dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / audio / framework / audio_fw.c
blob818383ab369224816d499d61651d25eac47da77d
1 /* Best viewed with tabsize 4
3 * This file contains a standard driver for audio devices.
4 * It supports double dma buffering and can be configured to use
5 * extra buffer space beside the dma buffer.
6 * This driver also support sub devices, which can be independently
7 * opened and closed.
9 * The driver supports the following operations:
11 * m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS
12 * -----------------------------------------------------------------
13 * | DEV_OPEN | device | proc nr | | | |
14 * |-------------+---------+---------+---------+---------+---------|
15 * | DEV_CLOSE | device | proc nr | | | |
16 * |-------------+---------+---------+---------+---------+---------|
17 * | DEV_READ_S | device | proc nr | bytes | | buf ptr |
18 * |-------------+---------+---------+---------+---------+---------|
19 * | DEV_WRITE_S | device | proc nr | bytes | | buf ptr |
20 * |-------------+---------+---------+---------+---------+---------|
21 * | DEV_IOCTL_S | device | proc nr |func code| | buf ptr |
22 * |-------------+---------+---------+---------+---------+---------|
23 * | DEV_STATUS | | | | | |
24 * |-------------+---------+---------+---------+---------+---------|
25 * | HARD_INT | | | | | |
26 * |-------------+---------+---------+---------+---------+---------|
27 * | SIG_STOP | | | | | |
28 * -----------------------------------------------------------------
30 * The file contains one entry point:
32 * main: main entry when driver is brought up
34 * October 2007 Updated audio framework to work with mplayer, added
35 * savecopies (Pieter Hijma)
36 * February 2006 Updated audio framework,
37 * changed driver-framework relation (Peter Boonstoppel)
38 * November 2005 Created generic DMA driver framework (Laurens Bronwasser)
39 * August 24 2005 Ported audio driver to user space
40 * (only audio playback) (Peter Boonstoppel)
41 * May 20 1995 SB16 Driver: Michel R. Prevenier
45 #include "audio_fw.h"
46 #include <sys/vm.h>
47 #include <minix/endpoint.h>
48 #include <minix/ds.h>
49 #include <sys/vm_i386.h>
52 FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) );
53 FORWARD _PROTOTYPE( int msg_close, (int minor_dev_nr) );
54 FORWARD _PROTOTYPE( int msg_ioctl, (message *m_ptr) );
55 FORWARD _PROTOTYPE( void msg_write, (message *m_ptr) );
56 FORWARD _PROTOTYPE( void msg_read, (message *m_ptr) );
57 FORWARD _PROTOTYPE( void msg_hardware, (void) );
58 FORWARD _PROTOTYPE( void msg_sig_stop, (void) );
59 FORWARD _PROTOTYPE( void msg_status, (message *m_ptr) );
60 FORWARD _PROTOTYPE( int init_driver, (void) );
61 FORWARD _PROTOTYPE( int open_sub_dev, (int sub_dev_nr, int operation) );
62 FORWARD _PROTOTYPE( int close_sub_dev, (int sub_dev_nr) );
63 FORWARD _PROTOTYPE( void handle_int_write,(int sub_dev_nr) );
64 FORWARD _PROTOTYPE( void handle_int_read,(int sub_dev_nr) );
65 FORWARD _PROTOTYPE( void data_to_user, (sub_dev_t *sub_dev_ptr) );
66 FORWARD _PROTOTYPE( void data_from_user, (sub_dev_t *sub_dev_ptr) );
67 FORWARD _PROTOTYPE( int init_buffers, (sub_dev_t *sub_dev_ptr) );
68 FORWARD _PROTOTYPE( int get_started, (sub_dev_t *sub_dev_ptr) );
69 FORWARD _PROTOTYPE( void reply,(int code, int replyee, int process,int status));
70 FORWARD _PROTOTYPE( int io_ctl_length, (int io_request) );
71 FORWARD _PROTOTYPE( special_file_t* get_special_file, (int minor_dev_nr) );
72 FORWARD _PROTOTYPE( void tell_dev, (vir_bytes buf, size_t size, int pci_bus,
73 int pci_dev, int pci_func) );
75 PRIVATE char io_ctl_buf[_IOCPARM_MASK];
76 PRIVATE int irq_hook_id = 0; /* id of irq hook at the kernel */
77 PRIVATE int irq_hook_set = FALSE;
78 PRIVATE device_available = 0;/*todo*/
80 /* SEF functions and variables. */
81 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
82 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
83 EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
84 EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
85 EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
86 PUBLIC int is_status_msg_expected = FALSE;
88 PUBLIC void main(void)
90 int r, caller, proc_nr;
91 message mess, repl_mess;
93 /* SEF local startup. */
94 sef_local_startup();
96 /* Here is the main loop of the dma driver. It waits for a message,
97 carries it out, and sends a reply. */
99 while(1) {
100 sef_receive(ANY, &mess);
101 caller = mess.m_source;
102 proc_nr = mess.IO_ENDPT;
104 /* Now carry out the work. First check for notifications. */
105 if (is_notify(mess.m_type)) {
106 switch (_ENDPOINT_P(mess.m_source)) {
107 case HARDWARE:
108 msg_hardware();
109 break;
110 case PM_PROC_NR:
111 msg_sig_stop();
112 break;
113 default:
114 dprint("%s: %d uncaught notify!\n",
115 drv.DriverName, mess.m_type);
118 /* get next message */
119 continue;
122 /* Normal messages. */
123 switch(mess.m_type) {
124 case DEV_OPEN:
125 /* open the special file ( = parameter) */
126 r = msg_open(mess.DEVICE);
127 repl_mess.m_type = DEV_REVIVE;
128 repl_mess.REP_ENDPT = mess.IO_ENDPT;
129 repl_mess.REP_STATUS = r;
130 send(caller, &repl_mess);
132 continue;
134 case DEV_CLOSE:
135 /* close the special file ( = parameter) */
136 r = msg_close(mess.DEVICE);
137 repl_mess.m_type = DEV_CLOSE_REPL;
138 repl_mess.REP_ENDPT = mess.IO_ENDPT;
139 repl_mess.REP_STATUS = r;
140 send(caller, &repl_mess);
142 continue;
144 case DEV_IOCTL_S:
145 r = msg_ioctl(&mess);
147 if (r != SUSPEND)
149 repl_mess.m_type = DEV_REVIVE;
150 repl_mess.REP_ENDPT = mess.IO_ENDPT;
151 repl_mess.REP_IO_GRANT =
152 (unsigned)mess.IO_GRANT;
153 repl_mess.REP_STATUS = r;
154 send(caller, &repl_mess);
156 continue;
158 case DEV_READ_S:
159 msg_read(&mess); continue; /* don't reply */
160 case DEV_WRITE_S:
161 msg_write(&mess); continue; /* don't reply */
162 case DEV_STATUS:
163 msg_status(&mess);continue; /* don't reply */
164 case DEV_REOPEN:
165 /* reopen the special file ( = parameter) */
166 r = msg_open(mess.DEVICE);
167 repl_mess.m_type = DEV_REOPEN_REPL;
168 repl_mess.REP_ENDPT = mess.IO_ENDPT;
169 repl_mess.REP_STATUS = r;
170 send(caller, &repl_mess);
171 continue;
172 default:
173 dprint("%s: %d uncaught msg!\n",
174 drv.DriverName, mess.m_type);
175 continue;
178 /* Should not be here. Just continue. */
182 /*===========================================================================*
183 * sef_local_startup *
184 *===========================================================================*/
185 PRIVATE void sef_local_startup()
187 /* Register init callbacks. */
188 sef_setcb_init_fresh(sef_cb_init_fresh);
189 sef_setcb_init_lu(sef_cb_init_fresh);
190 sef_setcb_init_restart(sef_cb_init_fresh);
192 /* Register live update callbacks. */
193 sef_setcb_lu_prepare(sef_cb_lu_prepare);
194 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
195 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
197 /* Let SEF perform startup. */
198 sef_startup();
201 /*===========================================================================*
202 * sef_cb_init_fresh *
203 *===========================================================================*/
204 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
206 /* Initialize the audio driver framework. */
207 return init_driver();
210 PRIVATE int init_driver(void) {
211 u32_t i; char irq;
212 static int executed = 0;
213 sub_dev_t* sub_dev_ptr;
215 /* init variables, get dma buffers */
216 for (i = 0; i < drv.NrOfSubDevices; i++) {
218 sub_dev_ptr = &sub_dev[i];
220 sub_dev_ptr->Opened = FALSE;
221 sub_dev_ptr->DmaBusy = FALSE;
222 sub_dev_ptr->DmaMode = NO_DMA;
223 sub_dev_ptr->DmaReadNext = 0;
224 sub_dev_ptr->DmaFillNext = 0;
225 sub_dev_ptr->DmaLength = 0;
226 sub_dev_ptr->BufReadNext = 0;
227 sub_dev_ptr->BufFillNext = 0;
228 sub_dev_ptr->RevivePending = FALSE;
229 sub_dev_ptr->OutOfData = FALSE;
230 sub_dev_ptr->Nr = i;
233 /* initialize hardware*/
234 if (drv_init_hw() != OK) {
235 error("%s: Could not initialize hardware\n", drv.DriverName, 0);
236 return EIO;
239 /* get irq from device driver...*/
240 if (drv_get_irq(&irq) != OK) {
241 error("%s: init driver couldn't get IRQ", drv.DriverName, i);
242 return EIO;
244 /* todo: execute the rest of this function only once
245 we don't want to set irq policy twice */
246 if (executed) return OK;
247 executed = TRUE;
249 /* ...and register interrupt vector */
250 if ((i=sys_irqsetpolicy(irq, 0, &irq_hook_id )) != OK){
251 error("%s: init driver couldn't set IRQ policy", drv.DriverName, i);
252 return EIO;
254 irq_hook_set = TRUE; /* now msg_sig_stop knows it must unregister policy*/
255 return OK;
259 PRIVATE int msg_open (int minor_dev_nr) {
260 int r, read_chan, write_chan, io_ctl;
261 special_file_t* special_file_ptr;
263 dprint("%s: msg_open() special file %d\n", drv.DriverName, minor_dev_nr);
265 special_file_ptr = get_special_file(minor_dev_nr);
266 if(special_file_ptr == NULL) {
267 return EIO;
270 read_chan = special_file_ptr->read_chan;
271 write_chan = special_file_ptr->write_chan;
272 io_ctl = special_file_ptr->io_ctl;
274 if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) {
275 error("%s: No channel specified for minor device!\n",
276 drv.DriverName, minor_dev_nr);
277 return EIO;
279 if (read_chan == write_chan && read_chan != NO_CHANNEL) {
280 error("%s: Read and write channels are equal!\n",
281 drv.DriverName, minor_dev_nr);
282 return EIO;
284 /* init driver */
285 if (!device_available) {
286 if (init_driver() != OK) {
287 error("%s: Couldn't init driver!\n", drv.DriverName, minor_dev_nr);
288 return EIO;
289 } else {
290 device_available = TRUE;
293 /* open the sub devices specified in the interface header file */
294 if (write_chan != NO_CHANNEL) {
295 /* open sub device for writing */
296 if (open_sub_dev(write_chan, DEV_WRITE_S) != OK) return EIO;
298 if (read_chan != NO_CHANNEL) {
299 if (open_sub_dev(read_chan, DEV_READ_S) != OK) return EIO;
301 if (read_chan == io_ctl || write_chan == io_ctl) {
302 /* io_ctl is already opened because it's the same as read or write */
303 return OK; /* we're done */
305 if (io_ctl != NO_CHANNEL) { /* Ioctl differs from read/write channels, */
306 r = open_sub_dev(io_ctl, NO_DMA); /* open it explicitly */
307 if (r != OK) return EIO;
309 return OK;
313 PRIVATE int open_sub_dev(int sub_dev_nr, int dma_mode) {
314 sub_dev_t* sub_dev_ptr;
315 sub_dev_ptr = &sub_dev[sub_dev_nr];
317 /* Only one open at a time per sub device */
318 if (sub_dev_ptr->Opened) {
319 error("%s: Sub device %d is already opened\n",
320 drv.DriverName, sub_dev_nr);
321 return EBUSY;
323 if (sub_dev_ptr->DmaBusy) {
324 error("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr);
325 return EBUSY;
327 /* Setup variables */
328 sub_dev_ptr->Opened = TRUE;
329 sub_dev_ptr->DmaReadNext = 0;
330 sub_dev_ptr->DmaFillNext = 0;
331 sub_dev_ptr->DmaLength = 0;
332 sub_dev_ptr->DmaMode = dma_mode;
333 sub_dev_ptr->BufReadNext = 0;
334 sub_dev_ptr->BufFillNext = 0;
335 sub_dev_ptr->BufLength = 0;
336 sub_dev_ptr->RevivePending = FALSE;
337 sub_dev_ptr->OutOfData = TRUE;
339 /* arrange DMA */
340 if (dma_mode != NO_DMA) { /* sub device uses DMA */
341 /* allocate dma buffer and extra buffer space
342 and configure sub device for dma */
343 if (init_buffers(sub_dev_ptr) != OK ) return EIO;
345 return OK;
349 PRIVATE int msg_close(int minor_dev_nr) {
351 int r, read_chan, write_chan, io_ctl;
352 special_file_t* special_file_ptr;
354 dprint("%s: msg_close() minor device %d\n", drv.DriverName, minor_dev_nr);
356 special_file_ptr = get_special_file(minor_dev_nr);
357 if(special_file_ptr == NULL) {
358 return EIO;
361 read_chan = special_file_ptr->read_chan;
362 write_chan = special_file_ptr->write_chan;
363 io_ctl = special_file_ptr->io_ctl;
365 r= OK;
367 /* close all sub devices */
368 if (write_chan != NO_CHANNEL) {
369 if (close_sub_dev(write_chan) != OK) r = EIO;
371 if (read_chan != NO_CHANNEL) {
372 if (close_sub_dev(read_chan) != OK) r = EIO;
374 if (read_chan == io_ctl || write_chan == io_ctl) {
375 /* io_ctl is already closed because it's the same as read or write */
376 return r; /* we're done */
378 /* ioctl differs from read/write channels... */
379 if (io_ctl != NO_CHANNEL) {
380 if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */
382 return r;
386 PRIVATE int close_sub_dev(int sub_dev_nr) {
387 sub_dev_t *sub_dev_ptr;
388 sub_dev_ptr = &sub_dev[sub_dev_nr];
389 if (sub_dev_ptr->DmaMode == DEV_WRITE_S && !sub_dev_ptr->OutOfData) {
390 /* do nothing, still data in buffers that has to be transferred */
391 sub_dev_ptr->Opened = FALSE; /* keep DMA busy */
392 return OK;
394 if (sub_dev_ptr->DmaMode == NO_DMA) {
395 /* do nothing, there is no dma going on */
396 sub_dev_ptr->Opened = FALSE;
397 return OK;
399 sub_dev_ptr->Opened = FALSE;
400 sub_dev_ptr->DmaBusy = FALSE;
401 /* stop the device */
402 drv_stop(sub_dev_ptr->Nr);
403 /* free the buffers */
404 free(sub_dev_ptr->DmaBuf);
405 free(sub_dev_ptr->ExtraBuf);
406 return OK;
410 PRIVATE int msg_ioctl(message *m_ptr)
412 int status, len, chan;
413 sub_dev_t *sub_dev_ptr;
414 special_file_t* special_file_ptr;
416 dprint("%s: msg_ioctl() device %d\n", drv.DriverName, m_ptr->DEVICE);
418 special_file_ptr = get_special_file(m_ptr->DEVICE);
419 if(special_file_ptr == NULL) {
420 return EIO;
423 chan = special_file_ptr->io_ctl;
425 if (chan == NO_CHANNEL) {
426 error("%s: No io control channel specified!\n", drv.DriverName);
427 return EIO;
429 /* get pointer to sub device data */
430 sub_dev_ptr = &sub_dev[chan];
432 if(!sub_dev_ptr->Opened) {
433 error("%s: io control impossible - not opened!\n", drv.DriverName);
434 return EIO;
438 /* this is a hack...todo: may we intercept reset calls? */
440 if(m_ptr->REQUEST == DSPIORESET) {
441 device_available = FALSE;
446 if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */
447 len = io_ctl_length(m_ptr->REQUEST);
449 if(sys_safecopyfrom(m_ptr->IO_ENDPT,
450 (vir_bytes)m_ptr->ADDRESS, 0,
451 (vir_bytes)io_ctl_buf, len, D) != OK) {
452 printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__);
456 /* all ioctl's are passed to the device specific part of the driver */
457 status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan);
459 /* _IOC_OUT bit -> user expects data */
460 if (status == OK && m_ptr->REQUEST & _IOC_OUT) {
461 /* copy result back to user */
463 if(sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, 0,
464 (vir_bytes)io_ctl_buf, len, D) != OK) {
465 printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);
469 return status;
473 PRIVATE void msg_write(message *m_ptr)
475 int chan; sub_dev_t *sub_dev_ptr;
476 special_file_t* special_file_ptr;
478 dprint("%s: msg_write() device %d\n", drv.DriverName, m_ptr->DEVICE);
480 special_file_ptr = get_special_file(m_ptr->DEVICE);
481 chan = special_file_ptr->write_chan;
483 if (chan == NO_CHANNEL) {
484 error("%s: No write channel specified!\n", drv.DriverName);
485 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
486 return;
488 /* get pointer to sub device data */
489 sub_dev_ptr = &sub_dev[chan];
491 if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */
492 if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){
493 error("%s; Failed to get fragment size!\n", drv.DriverName, 0);
494 return;
497 if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
498 error("Fragment size does not match user's buffer length\n");
499 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
500 return;
502 /* if we are busy with something else than writing, return EBUSY */
503 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) {
504 error("Already busy with something else then writing\n");
505 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
506 return;
509 sub_dev_ptr->RevivePending = TRUE;
510 sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
511 sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
512 sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
514 data_from_user(sub_dev_ptr);
516 if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */
517 dprint("starting audio device\n");
518 get_started(sub_dev_ptr);
519 sub_dev_ptr->DmaMode = DEV_WRITE_S; /* Dma mode is writing */
524 PRIVATE void msg_read(message *m_ptr)
526 int chan; sub_dev_t *sub_dev_ptr;
527 special_file_t* special_file_ptr;
529 dprint("%s: msg_read() device %d\n", drv.DriverName, m_ptr->DEVICE);
531 special_file_ptr = get_special_file(m_ptr->DEVICE);
532 chan = special_file_ptr->read_chan;
534 if (chan == NO_CHANNEL) {
535 error("%s: No read channel specified!\n", drv.DriverName);
536 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
537 return;
539 /* get pointer to sub device data */
540 sub_dev_ptr = &sub_dev[chan];
542 if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */
543 if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){
544 error("%s: Could not retrieve fragment size!\n", drv.DriverName);
545 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
546 return;
549 if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
550 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
551 error("fragment size does not match message size\n");
552 return;
554 /* if we are busy with something else than reading, reply EBUSY */
555 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) {
556 reply(DEV_REVIVE, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
557 return;
560 sub_dev_ptr->RevivePending = TRUE;
561 sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
562 sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
563 sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
565 if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */
566 get_started(sub_dev_ptr);
567 sub_dev_ptr->DmaMode = DEV_READ_S; /* Dma mode is reading */
568 return; /* no need to get data from DMA buffer at this point */
570 /* check if data is available and possibly fill user's buffer */
571 data_to_user(sub_dev_ptr);
575 PRIVATE void msg_hardware(void) {
577 u32_t i;
579 dprint("%s: handling hardware message\n", drv.DriverName);
581 /* while we have an interrupt */
582 while ( drv_int_sum()) {
583 /* loop over all sub devices */
584 for ( i = 0; i < drv.NrOfSubDevices; i++) {
585 /* if interrupt from sub device and Dma transfer
586 was actually busy, take care of business */
587 if( drv_int(i) && sub_dev[i].DmaBusy ) {
588 if (sub_dev[i].DmaMode == DEV_WRITE_S) handle_int_write(i);
589 if (sub_dev[i].DmaMode == DEV_READ_S) handle_int_read(i);
594 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must
595 * re-enable out interrupt after every interrupt.
597 if ((sys_irqenable(&irq_hook_id)) != OK) {
598 error("%s: msg_hardware: Couldn't enable IRQ\n", drv.DriverName);
603 PRIVATE void msg_status(message *m_ptr)
605 int i;
607 dprint("got a status message\n");
608 for (i = 0; i < drv.NrOfSubDevices; i++) {
610 if(sub_dev[i].ReadyToRevive)
612 m_ptr->m_type = DEV_REVIVE; /* build message */
613 m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr;
614 m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant;
615 m_ptr->REP_STATUS = sub_dev[i].ReviveStatus;
616 send(m_ptr->m_source, m_ptr); /* send the message */
618 /* reset variables */
619 sub_dev[i].ReadyToRevive = FALSE;
620 sub_dev[i].RevivePending = 0;
622 is_status_msg_expected = TRUE;
623 return; /* stop after one mess,
624 file system will get back for other processes */
627 m_ptr->m_type = DEV_NO_STATUS;
628 m_ptr->REP_STATUS = 0;
629 send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */
630 is_status_msg_expected = FALSE;
634 PRIVATE void msg_sig_stop(void)
636 int i; char irq;
637 for (i = 0; i < drv.NrOfSubDevices; i++) {
638 drv_stop(i); /* stop all sub devices */
640 if (irq_hook_set) {
641 if (sys_irqdisable(&irq_hook_id) != OK) {
642 error("Could not disable IRQ\n");
644 /* get irq from device driver*/
645 if (drv_get_irq(&irq) != OK) {
646 error("Msg SIG_STOP Couldn't get IRQ");
648 /* remove the policy */
649 if (sys_irqrmpolicy(&irq_hook_id) != OK) {
650 error("%s: Could not disable IRQ\n",drv.DriverName);
656 /* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/
657 PRIVATE void handle_int_write(int sub_dev_nr)
659 sub_dev_t *sub_dev_ptr;
661 sub_dev_ptr = &sub_dev[sub_dev_nr];
663 dprint("Finished playing dma[%d] ", sub_dev_ptr->DmaReadNext);
664 sub_dev_ptr->DmaReadNext =
665 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
666 sub_dev_ptr->DmaLength -= 1;
668 if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */
670 dprint(" buf[%d] -> dma[%d] ",
671 sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext);
672 memcpy(sub_dev_ptr->DmaPtr +
673 sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize,
674 sub_dev_ptr->ExtraBuf +
675 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
676 sub_dev_ptr->FragSize);
678 sub_dev_ptr->BufReadNext =
679 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
680 sub_dev_ptr->DmaFillNext =
681 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
683 sub_dev_ptr->BufLength -= 1;
684 sub_dev_ptr->DmaLength += 1;
687 /* space became available, possibly copy new data from user */
688 data_from_user(sub_dev_ptr);
690 if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */
692 sub_dev_ptr->OutOfData = TRUE; /* we're out of data */
693 dprint("No more work...!\n");
694 if (!sub_dev_ptr->Opened) {
695 close_sub_dev(sub_dev_ptr->Nr);
696 dprint("Stopping sub device %d\n", sub_dev_ptr->Nr);
697 return;
699 dprint("Pausing sub device %d\n",sub_dev_ptr->Nr);
700 drv_pause(sub_dev_ptr->Nr);
701 return;
704 dprint("\n");
706 /* confirm and reenable interrupt from this sub dev */
707 drv_reenable_int(sub_dev_nr);
708 #if 0
709 /* reenable irq_hook*/
710 if (sys_irqenable(&irq_hook_id != OK) {
711 error("%s Couldn't enable IRQ\n", drv.DriverName);
713 #endif
717 /* handle interrupt for specified sub device; DmaMode == DEV_READ_S */
718 PRIVATE void handle_int_read(int sub_dev_nr)
720 sub_dev_t *sub_dev_ptr;
722 sub_dev_ptr = &sub_dev[sub_dev_nr];
724 dprint("Device filled dma[%d]\n", sub_dev_ptr->DmaFillNext);
725 sub_dev_ptr->DmaLength += 1;
726 sub_dev_ptr->DmaFillNext =
727 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
729 /* possibly copy data to user (if it is waiting for us) */
730 data_to_user(sub_dev_ptr);
732 if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) {
733 /* if dma buffer full */
735 if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) {
736 error("All buffers full, we have a problem.\n");
737 drv_stop(sub_dev_nr); /* stop the sub device */
738 sub_dev_ptr->DmaBusy = FALSE;
739 sub_dev_ptr->ReviveStatus = 0; /* no data for user,
740 this is a sad story */
741 sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */
742 return;
744 else { /* dma full, still room in extra buf;
745 copy from dma to extra buf */
746 dprint("dma full: going to copy buf[%d] <- dma[%d]\n",
747 sub_dev_ptr->BufFillNext, sub_dev_ptr->DmaReadNext);
748 memcpy(sub_dev_ptr->ExtraBuf +
749 sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize,
750 sub_dev_ptr->DmaPtr +
751 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
752 sub_dev_ptr->FragSize);
753 sub_dev_ptr->DmaLength -= 1;
754 sub_dev_ptr->DmaReadNext =
755 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
756 sub_dev_ptr->BufFillNext =
757 (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
760 /* confirm interrupt, and reenable interrupt from this sub dev*/
761 drv_reenable_int(sub_dev_ptr->Nr);
763 #if 0
764 /* reenable irq_hook*/
765 if (sys_irqenable(&irq_hook_id) != OK) {
766 error("%s: Couldn't reenable IRQ", drv.DriverName);
768 #endif
772 PRIVATE int get_started(sub_dev_t *sub_dev_ptr) {
773 u32_t i;
775 /* enable interrupt messages from MINIX */
776 if ((i=sys_irqenable(&irq_hook_id)) != OK) {
777 error("%s: Couldn't enable IRQs",drv.DriverName);
778 return EIO;
780 /* let the lower part of the driver start the device */
781 if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) {
782 error("%s: Could not start device %d\n",
783 drv.DriverName, sub_dev_ptr->Nr);
786 sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */
787 sub_dev_ptr->DmaReadNext = 0;
788 return OK;
792 PRIVATE void data_from_user(sub_dev_t *subdev)
794 int r;
795 message m;
797 if (subdev->DmaLength == subdev->NrOfDmaFragments &&
798 subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */
800 if (!subdev->RevivePending) return; /* no new data waiting to be copied */
802 if (subdev->RevivePending &&
803 subdev->ReadyToRevive) return; /* we already got this data */
805 if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */
807 sys_safecopyfrom(subdev->ReviveProcNr,
808 (vir_bytes)subdev->ReviveGrant, 0,
809 (vir_bytes)subdev->DmaPtr +
810 subdev->DmaFillNext * subdev->FragSize,
811 (phys_bytes)subdev->FragSize, D);
814 dprint(" user -> dma[%d]\n", subdev->DmaFillNext);
815 subdev->DmaLength += 1;
816 subdev->DmaFillNext =
817 (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments;
819 } else { /* room in extra buf */
821 sys_safecopyfrom(subdev->ReviveProcNr,
822 (vir_bytes)subdev->ReviveGrant, 0,
823 (vir_bytes)subdev->ExtraBuf +
824 subdev->BufFillNext * subdev->FragSize,
825 (phys_bytes)subdev->FragSize, D);
827 dprint(" user -> buf[%d]\n", subdev->BufFillNext);
828 subdev->BufLength += 1;
830 subdev->BufFillNext =
831 (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers;
834 if(subdev->OutOfData) { /* if device paused (because of lack of data) */
835 subdev->OutOfData = FALSE;
836 drv_reenable_int(subdev->Nr);
837 /* reenable irq_hook*/
838 if ((sys_irqenable(&irq_hook_id)) != OK) {
839 error("%s: Couldn't enable IRQ", drv.DriverName);
841 drv_resume(subdev->Nr); /* resume resume the sub device */
844 subdev->ReviveStatus = subdev->FragSize;
845 subdev->ReadyToRevive = TRUE;
847 m.m_type = DEV_REVIVE; /* build message */
848 m.REP_ENDPT = subdev->ReviveProcNr;
849 m.REP_IO_GRANT = subdev->ReviveGrant;
850 m.REP_STATUS = subdev->ReviveStatus;
851 r= send(subdev->NotifyProcNr, &m); /* send the message */
852 if (r != OK)
854 printf("audio_fw: send to %d failed: %d\n",
855 subdev->NotifyProcNr, r);
858 /* reset variables */
859 subdev->ReadyToRevive = FALSE;
860 subdev->RevivePending = 0;
864 PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
866 int r;
867 message m;
869 if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */
870 if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */
871 if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return;
872 /* no data for user */
874 if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */
876 sys_safecopyto(sub_dev_ptr->ReviveProcNr,
877 (vir_bytes)sub_dev_ptr->ReviveGrant,
878 0, (vir_bytes)sub_dev_ptr->ExtraBuf +
879 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
880 (phys_bytes)sub_dev_ptr->FragSize, D);
882 dprint(" copied buf[%d] to user\n", sub_dev_ptr->BufReadNext);
884 /* adjust the buffer status variables */
885 sub_dev_ptr->BufReadNext =
886 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
887 sub_dev_ptr->BufLength -= 1;
889 } else { /* extra buf empty, but data in dma buf*/
890 sys_safecopyto(
891 sub_dev_ptr->ReviveProcNr,
892 (vir_bytes)sub_dev_ptr->ReviveGrant, 0,
893 (vir_bytes)sub_dev_ptr->DmaPtr +
894 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
895 (phys_bytes)sub_dev_ptr->FragSize, D);
897 dprint(" copied dma[%d] to user\n", sub_dev_ptr->DmaReadNext);
899 /* adjust the buffer status variables */
900 sub_dev_ptr->DmaReadNext =
901 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
902 sub_dev_ptr->DmaLength -= 1;
905 sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize;
906 sub_dev_ptr->ReadyToRevive = TRUE;
907 /* drv_status will send REVIVE mess to FS*/
909 m.m_type = DEV_REVIVE; /* build message */
910 m.REP_ENDPT = sub_dev_ptr->ReviveProcNr;
911 m.REP_IO_GRANT = sub_dev_ptr->ReviveGrant;
912 m.REP_STATUS = sub_dev_ptr->ReviveStatus;
913 r= send(sub_dev_ptr->NotifyProcNr, &m); /* send the message */
914 if (r != OK)
916 printf("audio_fw: send to %d failed: %d\n",
917 sub_dev_ptr->NotifyProcNr, r);
920 /* reset variables */
921 sub_dev_ptr->ReadyToRevive = FALSE;
922 sub_dev_ptr->RevivePending = 0;
925 PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr)
927 #if (CHIP == INTEL)
928 char *base;
929 size_t size;
930 unsigned left;
931 u32_t i;
932 phys_bytes ph;
934 /* allocate dma buffer space */
935 size= sub_dev_ptr->DmaSize + 64 * 1024;
936 base= alloc_contig(size, AC_ALIGN4K, &ph);
937 if (!base) {
938 error("%s: failed to allocate dma buffer for a channel\n",
939 drv.DriverName);
940 return EIO;
942 sub_dev_ptr->DmaBuf= base;
944 tell_dev((vir_bytes)base, size, 0, 0, 0);
946 /* allocate extra buffer space */
947 if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers *
948 sub_dev_ptr->DmaSize /
949 sub_dev_ptr->NrOfDmaFragments))) {
950 error("%s failed to allocate extra buffer for channel %d\n",
951 drv.DriverName,i);
952 return EIO;
955 sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf;
956 i = sys_umap(SELF, D,
957 (vir_bytes) sub_dev_ptr->DmaBuf,
958 (phys_bytes) sizeof(sub_dev_ptr->DmaBuf),
959 &(sub_dev_ptr->DmaPhys));
961 if (i != OK) {
962 return EIO;
965 if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) <
966 sub_dev_ptr->DmaSize) {
967 /* First half of buffer crosses a 64K boundary,
968 * can't DMA into that */
969 sub_dev_ptr->DmaPtr += left;
970 sub_dev_ptr->DmaPhys += left;
972 /* write the physical dma address and size to the device */
973 drv_set_dma(sub_dev_ptr->DmaPhys,
974 sub_dev_ptr->DmaSize, sub_dev_ptr->Nr);
975 return OK;
977 #else /* CHIP != INTEL */
978 error("%s: init_buffer() failed, CHIP != INTEL", drv.DriverName);
979 return EIO;
980 #endif /* CHIP == INTEL */
984 PRIVATE void reply(int code, int replyee, int process, int status) {
985 message m;
987 m.m_type = code; /* DEV_REVIVE */
988 m.REP_STATUS = status; /* result of device operation */
989 m.REP_ENDPT = process; /* which user made the request */
990 send(replyee, &m);
994 PRIVATE int io_ctl_length(int io_request) {
995 io_request >>= 16;
996 return io_request & _IOCPARM_MASK;
1000 PRIVATE special_file_t* get_special_file(int minor_dev_nr) {
1001 int i;
1003 for(i = 0; i < drv.NrOfSpecialFiles; i++) {
1004 if(special_file[i].minor_dev_nr == minor_dev_nr) {
1005 return &special_file[i];
1009 error("%s: No subdevice specified for minor device %d!\n",
1010 drv.DriverName, minor_dev_nr);
1012 return NULL;
1015 PRIVATE void tell_dev(buf, size, pci_bus, pci_dev, pci_func)
1016 vir_bytes buf;
1017 size_t size;
1018 int pci_bus;
1019 int pci_dev;
1020 int pci_func;
1022 int r;
1023 endpoint_t dev_e;
1024 u32_t u32;
1025 message m;
1027 r= ds_retrieve_label_num("amddev", &u32);
1028 if (r != OK)
1030 #if 0
1031 printf("tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
1033 #endif
1034 return;
1037 dev_e= u32;
1039 m.m_type= IOMMU_MAP;
1040 m.m2_i1= pci_bus;
1041 m.m2_i2= pci_dev;
1042 m.m2_i3= pci_func;
1043 m.m2_l1= buf;
1044 m.m2_l2= size;
1046 r= sendrec(dev_e, &m);
1047 if (r != OK)
1049 printf("tell_dev: sendrec to %d failed: %d\n", dev_e, r);
1050 return;
1052 if (m.m_type != OK)
1054 printf("tell_dev: dma map request failed: %d\n", m.m_type);
1055 return;