📄 audio_fw.c
字号:
chan = special_file_ptr->read_chan; 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); return; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; 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); return; } } if(m_ptr->COUNT != sub_dev_ptr->FragSize) { reply(TASK_REPLY, 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); 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; sub_dev_ptr->NotifyProcNr = m_ptr->m_source; if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ get_started(sub_dev_ptr); sub_dev_ptr->DmaMode = DEV_READ_S; /* Dma mode is reading */ return; /* no need to get data from DMA buffer at this point */ } /* check if data is available and possibly fill user's buffer */ data_to_user(sub_dev_ptr);}PRIVATE void msg_hardware(void) { u32_t i; int j = 0; dprint("%s: handling hardware message\n", drv.DriverName); /* while we have an interrupt */ while ( drv_int_sum()) { /* loop over all sub devices */ for ( i = 0; i < drv.NrOfSubDevices; i++) { /* if interrupt from sub device and Dma transfer was actually busy, take care of business */ if( drv_int(i) && sub_dev[i].DmaBusy ) { if (sub_dev[i].DmaMode == DEV_WRITE_S) handle_int_write(i); if (sub_dev[i].DmaMode == DEV_READ_S) handle_int_read(i); } } } /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must * re-enable out interrupt after every interrupt. */ if ((sys_irqenable(&irq_hook_id)) != OK) { error("%s: msg_hardware: Couldn't enable IRQ\n", drv.DriverName); }}PRIVATE void msg_status(message *m_ptr){ int i; dprint("got a status message\n"); for (i = 0; i < drv.NrOfSubDevices; i++) { if(sub_dev[i].ReadyToRevive) { m_ptr->m_type = DEV_REVIVE; /* build message */ m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr; m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant; m_ptr->REP_STATUS = sub_dev[i].ReviveStatus; send(m_ptr->m_source, m_ptr); /* send the message */ /* reset variables */ sub_dev[i].ReadyToRevive = FALSE; sub_dev[i].RevivePending = 0; return; /* stop after one mess, file system will get back for other processes */ } } m_ptr->m_type = DEV_NO_STATUS; m_ptr->REP_STATUS = 0; send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */}PRIVATE void msg_sig_stop(void) { int i; char irq; for (i = 0; i < drv.NrOfSubDevices; i++) { drv_stop(i); /* stop all sub devices */ } if (irq_hook_set) { if (sys_irqdisable(&irq_hook_id) != OK) { error("Could not disable IRQ\n"); } /* get irq from device driver*/ if (drv_get_irq(&irq) != OK) { error("Msg SIG_STOP Couldn't get IRQ"); } /* remove the policy */ if (sys_irqrmpolicy(irq, &irq_hook_id) != OK) { error("%s: Could not disable IRQ\n",drv.DriverName); } }}/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/PRIVATE void handle_int_write(int sub_dev_nr) { sub_dev_t *sub_dev_ptr; int r; sub_dev_ptr = &sub_dev[sub_dev_nr]; dprint("Finished playing dma[%d] ", sub_dev_ptr->DmaReadNext); sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->DmaLength -= 1; if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ dprint(" buf[%d] -> dma[%d] ", sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext); memcpy(sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize, sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, sub_dev_ptr->FragSize); sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->BufLength -= 1; sub_dev_ptr->DmaLength += 1; } /* space became available, possibly copy new data from user */ data_from_user(sub_dev_ptr); if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ sub_dev_ptr->OutOfData = TRUE; /* we're out of data */ dprint("No more work...!\n"); if (!sub_dev_ptr->Opened) { close_sub_dev(sub_dev_ptr->Nr); dprint("Stopping sub device %d\n", sub_dev_ptr->Nr); return; } dprint("Pausing sub device %d\n",sub_dev_ptr->Nr); drv_pause(sub_dev_ptr->Nr); return; } dprint("\n"); /* confirm and reenable interrupt from this sub dev */ drv_reenable_int(sub_dev_nr);#if 0 /* reenable irq_hook*/ if ((r=sys_irqenable(&irq_hook_id)) != OK) { error("%s Couldn't enable IRQ\n", drv.DriverName); }#endif}/* handle interrupt for specified sub device; DmaMode == DEV_READ_S */PRIVATE void handle_int_read(int sub_dev_nr) { sub_dev_t *sub_dev_ptr; int r,i; sub_dev_ptr = &sub_dev[sub_dev_nr]; dprint("Device filled dma[%d]\n", sub_dev_ptr->DmaFillNext); sub_dev_ptr->DmaLength += 1; sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; /* possibly copy data to user (if it is waiting for us) */ data_to_user(sub_dev_ptr); if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { /* if dma buffer full */ if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) { error("All buffers full, we have a problem.\n"); drv_stop(sub_dev_nr); /* stop the sub device */ sub_dev_ptr->DmaBusy = FALSE; sub_dev_ptr->ReviveStatus = 0; /* no data for user, this is a sad story */ sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */ return; } else { /* dma full, still room in extra buf; copy from dma to extra buf */ dprint("dma full: going to copy buf[%d] <- dma[%d]\n", sub_dev_ptr->BufFillNext, sub_dev_ptr->DmaReadNext); memcpy(sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize, sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, sub_dev_ptr->FragSize); sub_dev_ptr->DmaLength -= 1; sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->BufFillNext = (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers; } } /* confirm interrupt, and reenable interrupt from this sub dev*/ drv_reenable_int(sub_dev_ptr->Nr);#if 0 /* reenable irq_hook*/ if ((r=sys_irqenable(&irq_hook_id)) != OK) { error("%s: Couldn't reenable IRQ", drv.DriverName); }#endif}PRIVATE int get_started(sub_dev_t *sub_dev_ptr) { u32_t i;char c; /* enable interrupt messages from MINIX */ if ((i=sys_irqenable(&irq_hook_id)) != OK) { error("%s: Couldn't enable IRQs",drv.DriverName); return EIO; } /* let the lower part of the driver start the device */ if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) { error("%s: Could not start device %d\n", drv.DriverName, sub_dev_ptr->Nr); } sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ sub_dev_ptr->DmaReadNext = 0; return OK;}PRIVATE void data_from_user(sub_dev_t *subdev){ if (subdev->DmaLength == subdev->NrOfDmaFragments && subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */ if (!subdev->RevivePending) return; /* no new data waiting to be copied */ if (subdev->RevivePending && subdev->ReadyToRevive) return; /* we already got this data */ if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ sys_safecopyfrom(subdev->ReviveProcNr, (vir_bytes)subdev->ReviveGrant, 0, (vir_bytes)subdev->DmaPtr + subdev->DmaFillNext * subdev->FragSize, (phys_bytes)subdev->FragSize, D); dprint(" user -> dma[%d]\n", subdev->DmaFillNext); subdev->DmaLength += 1; subdev->DmaFillNext = (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; } else { /* room in extra buf */ sys_safecopyfrom(subdev->ReviveProcNr, (vir_bytes)subdev->ReviveGrant, 0, (vir_bytes)subdev->ExtraBuf + subdev->BufFillNext * subdev->FragSize, (phys_bytes)subdev->FragSize, D); dprint(" user -> buf[%d]\n", subdev->BufFillNext); subdev->BufLength += 1; subdev->BufFillNext = (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; } if(subdev->OutOfData) { /* if device paused (because of lack of data) */ subdev->OutOfData = FALSE; drv_reenable_int(subdev->Nr); /* reenable irq_hook*/ if ((sys_irqenable(&irq_hook_id)) != OK) { error("%s: Couldn't enable IRQ", drv.DriverName); } drv_resume(subdev->Nr); /* resume resume the sub device */ } subdev->ReviveStatus = subdev->FragSize; subdev->ReadyToRevive = TRUE; notify(subdev->NotifyProcNr);}PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) { 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; /* no data for user */ if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ sys_safecopyto(sub_dev_ptr->ReviveProcNr, (vir_bytes)sub_dev_ptr->ReviveGrant, 0, (vir_bytes)sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, (phys_bytes)sub_dev_ptr->FragSize, D); dprint(" copied buf[%d] to user\n", sub_dev_ptr->BufReadNext); /* adjust the buffer status variables */ sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; sub_dev_ptr->BufLength -= 1; } else { /* extra buf empty, but data in dma buf*/ sys_safecopyto( sub_dev_ptr->ReviveProcNr, (vir_bytes)sub_dev_ptr->ReviveGrant, 0, (vir_bytes)sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, (phys_bytes)sub_dev_ptr->FragSize, D); dprint(" copied dma[%d] to user\n", sub_dev_ptr->DmaReadNext); /* adjust the buffer status variables */ sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->DmaLength -= 1; } 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*/} PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) {#if (CHIP == INTEL) 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; } 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;#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.REP_STATUS = status; /* result of device operation */ m.REP_ENDPT = process; /* which user made the request */ send(replyee, &m);}PRIVATE int io_ctl_length(int io_request) { io_request >>= 16; return io_request & _IOCPARM_MASK;}PRIVATE special_file_t* get_special_file(int minor_dev_nr) { int i; for(i = 0; i < drv.NrOfSpecialFiles; i++) { if(special_file[i].minor_dev_nr == minor_dev_nr) { return &special_file[i]; } } error("%s: No subdevice specified for minor device %d!\n", drv.DriverName, minor_dev_nr); return NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -