Respond to RS ping request, asynch interface, register with I/O MMU.

This commit is contained in:
Philip Homburg 2008-02-25 10:02:24 +00:00
parent 00ef93d6a2
commit 54f714e59e

View file

@ -43,6 +43,8 @@
#include "audio_fw.h"
#include <sys/vm.h>
#include <minix/ds.h>
FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) );
@ -65,7 +67,8 @@ FORWARD _PROTOTYPE( int get_started, (sub_dev_t *sub_dev_ptr) );
FORWARD _PROTOTYPE( void reply,(int code, int replyee, int process,int status));
FORWARD _PROTOTYPE( int io_ctl_length, (int io_request) );
FORWARD _PROTOTYPE( special_file_t* get_special_file, (int minor_dev_nr) );
FORWARD _PROTOTYPE( void tell_dev, (vir_bytes buf, size_t size, int pci_bus,
int pci_dev, int pci_func) );
PRIVATE char io_ctl_buf[_IOCPARM_MASK];
PRIVATE int irq_hook_id = 0; /* id of irq hook at the kernel */
@ -76,7 +79,7 @@ PRIVATE device_available = 0;/*todo*/
PUBLIC void main(void)
{
int r, caller, proc_nr, chan;
message mess;
message mess, repl_mess;
drv_init();
@ -89,32 +92,74 @@ PUBLIC void main(void)
caller = mess.m_source;
proc_nr = mess.IO_ENDPT;
if (caller == RS_PROC_NR && mess.m_type == DEV_PING)
{
/* Got ping from RS. Just notify RS */
notify(RS_PROC_NR);
continue;
}
/* Now carry out the work. */
switch(mess.m_type) {
case DEV_OPEN: /* open the special file ( = parameter) */
r = msg_open(mess.DEVICE);break;
case DEV_CLOSE: /* close the special file ( = parameter) */
r = msg_close(mess.DEVICE); break;
case DEV_OPEN:
/* open the special file ( = parameter) */
r = msg_open(mess.DEVICE);
repl_mess.m_type = DEV_REVIVE;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
continue;
case DEV_CLOSE:
/* close the special file ( = parameter) */
r = msg_close(mess.DEVICE);
repl_mess.m_type = DEV_CLOSE_REPL;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
continue;
case DEV_IOCTL_S:
r = msg_ioctl(&mess); break;
r = msg_ioctl(&mess);
if (r != SUSPEND)
{
repl_mess.m_type = DEV_REVIVE;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_IO_GRANT =
(unsigned)mess.IO_GRANT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
}
continue;
case DEV_READ_S:
msg_read(&mess); continue; /* don't reply */
case DEV_WRITE_S:
msg_write(&mess); continue; /* don't reply */
case DEV_STATUS:
msg_status(&mess);continue; /* don't reply */
case DEV_REOPEN:
/* reopen the special file ( = parameter) */
r = msg_open(mess.DEVICE);
repl_mess.m_type = DEV_REOPEN_REPL;
repl_mess.REP_ENDPT = mess.IO_ENDPT;
repl_mess.REP_STATUS = r;
send(caller, &repl_mess);
continue;
case HARD_INT:
msg_hardware();continue; /* don't reply */
case SYS_SIG:
msg_sig_stop(); continue; /* don't reply */
default:
r = EINVAL;
dprint("%s: %d uncaught msg!\n", drv.DriverName, mess.m_type);
break;
dprint("%s: %d uncaught msg!\n",
drv.DriverName, mess.m_type);
continue;
}
/* Finally, prepare and send the reply message. */
reply(TASK_REPLY, caller, proc_nr, r);
/* Should not be here. Just continue. */
}
}
@ -274,6 +319,8 @@ PRIVATE int msg_close(int minor_dev_nr) {
write_chan = special_file_ptr->write_chan;
io_ctl = special_file_ptr->io_ctl;
r= OK;
/* close all sub devices */
if (write_chan != NO_CHANNEL) {
if (close_sub_dev(write_chan) != OK) r = EIO;
@ -392,7 +439,7 @@ PRIVATE void msg_write(message *m_ptr)
if (chan == NO_CHANNEL) {
error("%s: No write channel specified!\n", drv.DriverName);
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
return;
}
/* get pointer to sub device data */
@ -406,17 +453,16 @@ PRIVATE void msg_write(message *m_ptr)
}
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
error("Fragment size does not match user's buffer length\n");
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
return;
}
/* if we are busy with something else than writing, return EBUSY */
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) {
error("Already busy with something else then writing\n");
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
return;
}
/* unblock the FileSystem, but keep user process blocked until REVIVE*/
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
sub_dev_ptr->RevivePending = TRUE;
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
@ -444,7 +490,7 @@ PRIVATE void msg_read(message *m_ptr)
if (chan == NO_CHANNEL) {
error("%s: No read channel specified!\n", drv.DriverName);
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
return;
}
/* get pointer to sub device data */
@ -453,22 +499,21 @@ PRIVATE void msg_read(message *m_ptr)
if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */
if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){
error("%s: Could not retrieve fragment size!\n", drv.DriverName);
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
return;
}
}
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
error("fragment size does not match message size\n");
return;
}
/* if we are busy with something else than reading, reply EBUSY */
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) {
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
return;
}
/* unblock the FileSystem, but keep user process blocked until REVIVE*/
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
sub_dev_ptr->RevivePending = TRUE;
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
@ -703,6 +748,8 @@ PRIVATE int get_started(sub_dev_t *sub_dev_ptr) {
PRIVATE void data_from_user(sub_dev_t *subdev)
{
int r;
message m;
if (subdev->DmaLength == subdev->NrOfDmaFragments &&
subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */
@ -753,11 +800,29 @@ PRIVATE void data_from_user(sub_dev_t *subdev)
subdev->ReviveStatus = subdev->FragSize;
subdev->ReadyToRevive = TRUE;
notify(subdev->NotifyProcNr);
m.m_type = DEV_REVIVE; /* build message */
m.REP_ENDPT = subdev->ReviveProcNr;
m.REP_IO_GRANT = subdev->ReviveGrant;
m.REP_STATUS = subdev->ReviveStatus;
r= send(subdev->NotifyProcNr, &m); /* send the message */
if (r != OK)
{
printf("audio_fw: send to %d failed: %d\n",
subdev->NotifyProcNr, r);
}
/* reset variables */
subdev->ReadyToRevive = FALSE;
subdev->RevivePending = 0;
}
PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) {
PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
{
int r;
message m;
if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */
if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */
if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return;
@ -797,63 +862,89 @@ PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) {
sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize;
sub_dev_ptr->ReadyToRevive = TRUE;
/* drv_status will send REVIVE mess to FS*/
notify(sub_dev_ptr->NotifyProcNr); /* notify the File Systam to make it
send DEV_STATUS messages*/
m.m_type = DEV_REVIVE; /* build message */
m.REP_ENDPT = sub_dev_ptr->ReviveProcNr;
m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant;
m.REP_STATUS = sub_dev_ptr->ReviveStatus;
r= send(sub_dev_ptr->NotifyProcNr, &m); /* send the message */
if (r != OK)
{
printf("audio_fw: send to %d failed: %d\n",
sub_dev_ptr->NotifyProcNr, r);
}
/* reset variables */
sub_dev_ptr->ReadyToRevive = FALSE;
sub_dev_ptr->RevivePending = 0;
}
PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) {
PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr)
{
#if (CHIP == INTEL)
unsigned left;
u32_t i;
char *base;
size_t size, off;
unsigned left;
u32_t i;
/* allocate dma buffer space */
if (!(sub_dev_ptr->DmaBuf = malloc(sub_dev_ptr->DmaSize + 64 * 1024))) {
error("%s: failed to allocate dma buffer for channel %d\n",
drv.DriverName,i);
return EIO;
}
/* allocate extra buffer space */
if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers *
sub_dev_ptr->DmaSize /
sub_dev_ptr->NrOfDmaFragments))) {
error("%s failed to allocate extra buffer for channel %d\n",
drv.DriverName,i);
return EIO;
}
/* allocate dma buffer space */
size= sub_dev_ptr->DmaSize + 64 * 1024;
base= malloc(size + PAGE_SIZE);
if (!base) {
error("%s: failed to allocate dma buffer for channel %d\n",
drv.DriverName,i);
return EIO;
}
/* Align base */
off= ((size_t)base % PAGE_SIZE);
if (off)
base += PAGE_SIZE-off;
sub_dev_ptr->DmaBuf= base;
sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf;
i = sys_umap(SELF, D,
(vir_bytes) sub_dev_ptr->DmaBuf,
(phys_bytes) sizeof(sub_dev_ptr->DmaBuf),
&(sub_dev_ptr->DmaPhys));
tell_dev((vir_bytes)base, size, 0, 0, 0);
if (i != OK) {
return EIO;
}
if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) <
sub_dev_ptr->DmaSize) {
/* First half of buffer crosses a 64K boundary,
* can't DMA into that */
sub_dev_ptr->DmaPtr += left;
sub_dev_ptr->DmaPhys += left;
}
/* write the physical dma address and size to the device */
drv_set_dma(sub_dev_ptr->DmaPhys,
sub_dev_ptr->DmaSize, sub_dev_ptr->Nr);
return OK;
/* allocate extra buffer space */
if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers *
sub_dev_ptr->DmaSize /
sub_dev_ptr->NrOfDmaFragments))) {
error("%s failed to allocate extra buffer for channel %d\n",
drv.DriverName,i);
return EIO;
}
sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf;
i = sys_umap(SELF, D,
(vir_bytes) sub_dev_ptr->DmaBuf,
(phys_bytes) sizeof(sub_dev_ptr->DmaBuf),
&(sub_dev_ptr->DmaPhys));
if (i != OK) {
return EIO;
}
if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) <
sub_dev_ptr->DmaSize) {
/* First half of buffer crosses a 64K boundary,
* can't DMA into that */
sub_dev_ptr->DmaPtr += left;
sub_dev_ptr->DmaPhys += left;
}
/* write the physical dma address and size to the device */
drv_set_dma(sub_dev_ptr->DmaPhys,
sub_dev_ptr->DmaSize, sub_dev_ptr->Nr);
return OK;
#else /* CHIP != INTEL */
error("%s: init_buffer() failed, CHIP != INTEL", drv.DriverName);
return EIO;
error("%s: init_buffer() failed, CHIP != INTEL", drv.DriverName);
return EIO;
#endif /* CHIP == INTEL */
}
}
PRIVATE void reply(int code, int replyee, int process, int status) {
message m;
m.m_type = code; /* TASK_REPLY or REVIVE */
m.m_type = code; /* DEV_REVIVE */
m.REP_STATUS = status; /* result of device operation */
m.REP_ENDPT = process; /* which user made the request */
send(replyee, &m);
@ -880,3 +971,45 @@ PRIVATE special_file_t* get_special_file(int minor_dev_nr) {
return NULL;
}
PRIVATE void tell_dev(buf, size, pci_bus, pci_dev, pci_func)
vir_bytes buf;
size_t size;
int pci_bus;
int pci_dev;
int pci_func;
{
int r;
endpoint_t dev_e;
u32_t u32;
message m;
r= ds_retrieve_u32("amddev", &u32);
if (r != OK)
{
printf("tell_dev: ds_retrieve_u32 failed for 'amddev': %d\n",
r);
return;
}
dev_e= u32;
m.m_type= IOMMU_MAP;
m.m2_i1= pci_bus;
m.m2_i2= pci_dev;
m.m2_i3= pci_func;
m.m2_l1= buf;
m.m2_l2= size;
r= sendrec(dev_e, &m);
if (r != OK)
{
printf("tell_dev: sendrec to %d failed: %d\n", dev_e, r);
return;
}
if (m.m_type != OK)
{
printf("tell_dev: dma map request failed: %d\n", m.m_type);
return;
}
}