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
9 * The driver supports the following operations:
11 * m_type DEVICE USER_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 <minix/audio_fw.h>
46 #include <minix/endpoint.h>
50 static int msg_open(int minor_dev_nr
);
51 static int msg_close(int minor_dev_nr
);
52 static int msg_ioctl(const message
*m_ptr
);
53 static void msg_write(const message
*m_ptr
);
54 static void msg_read(message
*m_ptr
);
55 static void msg_hardware(void);
56 static void msg_status(message
*m_ptr
);
57 static int init_driver(void);
58 static int open_sub_dev(int sub_dev_nr
, int operation
);
59 static int close_sub_dev(int sub_dev_nr
);
60 static void handle_int_write(int sub_dev_nr
);
61 static void handle_int_read(int sub_dev_nr
);
62 static void data_to_user(sub_dev_t
*sub_dev_ptr
);
63 static void data_from_user(sub_dev_t
*sub_dev_ptr
);
64 static int init_buffers(sub_dev_t
*sub_dev_ptr
);
65 static int get_started(sub_dev_t
*sub_dev_ptr
);
66 static void reply(int code
, int replyee
, int process
,int status
);
67 static int io_ctl_length(int io_request
);
68 static special_file_t
* get_special_file(int minor_dev_nr
);
69 static void tell_dev(vir_bytes buf
, size_t size
, int pci_bus
, int
70 pci_dev
, int pci_func
);
72 static char io_ctl_buf
[_IOCPARM_MASK
];
73 static int irq_hook_id
= 0; /* id of irq hook at the kernel */
74 static int irq_hook_set
= FALSE
;
75 static int device_available
= 0;/*todo*/
77 /* SEF functions and variables. */
78 static void sef_local_startup(void);
79 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
80 static void sef_cb_signal_handler(int signo
);
81 EXTERN
int sef_cb_lu_prepare(int state
);
82 EXTERN
int sef_cb_lu_state_isvalid(int state
);
83 EXTERN
void sef_cb_lu_state_dump(int state
);
84 int is_status_msg_expected
= FALSE
;
89 message mess
, repl_mess
;
92 /* SEF local startup. */
95 /* Here is the main loop of the dma driver. It waits for a message,
96 carries it out, and sends a reply. */
99 if(driver_receive(ANY
, &mess
, &ipc_status
) != OK
) {
100 panic("driver_receive failed");
102 caller
= mess
.m_source
;
104 /* Now carry out the work. First check for notifications. */
105 if (is_ipc_notify(ipc_status
)) {
106 switch (_ENDPOINT_P(mess
.m_source
)) {
111 printf("%s: %d uncaught notify!\n",
112 drv
.DriverName
, mess
.m_type
);
115 /* get next message */
119 /* Normal messages. */
120 switch(mess
.m_type
) {
122 /* open the special file ( = parameter) */
123 r
= msg_open(mess
.DEVICE
);
124 repl_mess
.m_type
= DEV_REVIVE
;
125 repl_mess
.REP_ENDPT
= mess
.USER_ENDPT
;
126 repl_mess
.REP_STATUS
= r
;
127 send(caller
, &repl_mess
);
132 /* close the special file ( = parameter) */
133 r
= msg_close(mess
.DEVICE
);
134 repl_mess
.m_type
= DEV_CLOSE_REPL
;
135 repl_mess
.REP_ENDPT
= mess
.USER_ENDPT
;
136 repl_mess
.REP_STATUS
= r
;
137 send(caller
, &repl_mess
);
142 r
= msg_ioctl(&mess
);
146 repl_mess
.m_type
= DEV_REVIVE
;
147 repl_mess
.REP_ENDPT
= mess
.USER_ENDPT
;
148 repl_mess
.REP_IO_GRANT
=
149 (unsigned)mess
.IO_GRANT
;
150 repl_mess
.REP_STATUS
= r
;
151 send(caller
, &repl_mess
);
156 msg_read(&mess
); continue; /* don't reply */
158 msg_write(&mess
); continue; /* don't reply */
160 msg_status(&mess
);continue; /* don't reply */
162 /* reopen the special file ( = parameter) */
163 r
= msg_open(mess
.DEVICE
);
164 repl_mess
.m_type
= DEV_REOPEN_REPL
;
165 repl_mess
.REP_ENDPT
= mess
.USER_ENDPT
;
166 repl_mess
.REP_STATUS
= r
;
167 send(caller
, &repl_mess
);
170 printf("%s: %d uncaught msg!\n",
171 drv
.DriverName
, mess
.m_type
);
175 /* Should not be here. Just continue. */
180 /*===========================================================================*
181 * sef_local_startup *
182 *===========================================================================*/
183 static void sef_local_startup()
185 /* Register init callbacks. */
186 sef_setcb_init_fresh(sef_cb_init_fresh
);
187 sef_setcb_init_lu(sef_cb_init_fresh
);
188 sef_setcb_init_restart(sef_cb_init_fresh
);
190 /* Register live update callbacks. */
191 sef_setcb_lu_prepare(sef_cb_lu_prepare
);
192 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid
);
193 sef_setcb_lu_state_dump(sef_cb_lu_state_dump
);
195 /* Register signal callbacks. */
196 sef_setcb_signal_handler(sef_cb_signal_handler
);
198 /* Let SEF perform startup. */
202 /*===========================================================================*
203 * sef_cb_init_fresh *
204 *===========================================================================*/
205 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
207 /* Initialize the audio driver framework. */
208 return init_driver();
211 static int init_driver(void) {
213 static int executed
= 0;
214 sub_dev_t
* sub_dev_ptr
;
216 /* initialize basic driver variables */
217 if (drv_init() != OK
) {
218 printf("libaudiodriver: Could not initialize driver\n");
222 /* init variables, get dma buffers */
223 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
225 sub_dev_ptr
= &sub_dev
[i
];
227 sub_dev_ptr
->Opened
= FALSE
;
228 sub_dev_ptr
->DmaBusy
= FALSE
;
229 sub_dev_ptr
->DmaMode
= NO_DMA
;
230 sub_dev_ptr
->DmaReadNext
= 0;
231 sub_dev_ptr
->DmaFillNext
= 0;
232 sub_dev_ptr
->DmaLength
= 0;
233 sub_dev_ptr
->BufReadNext
= 0;
234 sub_dev_ptr
->BufFillNext
= 0;
235 sub_dev_ptr
->RevivePending
= FALSE
;
236 sub_dev_ptr
->OutOfData
= FALSE
;
240 /* initialize hardware*/
241 if (drv_init_hw() != OK
) {
242 printf("%s: Could not initialize hardware\n", drv
.DriverName
);
246 /* get irq from device driver...*/
247 if (drv_get_irq(&irq
) != OK
) {
248 printf("%s: init driver couldn't get IRQ", drv
.DriverName
);
251 /* TODO: execute the rest of this function only once
252 we don't want to set irq policy twice */
253 if (executed
) return OK
;
256 /* ...and register interrupt vector */
257 if ((i
=sys_irqsetpolicy(irq
, 0, &irq_hook_id
)) != OK
){
258 printf("%s: init driver couldn't set IRQ policy: %d", drv
.DriverName
, i
);
261 irq_hook_set
= TRUE
; /* now signal handler knows it must unregister policy*/
263 /* Announce we are up! */
264 chardriver_announce();
269 /*===========================================================================*
270 * sef_cb_signal_handler *
271 *===========================================================================*/
272 static void sef_cb_signal_handler(int signo
)
277 /* Only check for termination signal, ignore anything else. */
278 if (signo
!= SIGTERM
) return;
280 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
281 drv_stop(i
); /* stop all sub devices */
284 if (sys_irqdisable(&irq_hook_id
) != OK
) {
285 printf("Could not disable IRQ\n");
287 /* get irq from device driver*/
288 if (drv_get_irq(&irq
) != OK
) {
289 printf("Msg SIG_STOP Couldn't get IRQ");
291 /* remove the policy */
292 if (sys_irqrmpolicy(&irq_hook_id
) != OK
) {
293 printf("%s: Could not disable IRQ\n",drv
.DriverName
);
298 static int msg_open (int minor_dev_nr
) {
299 int r
, read_chan
, write_chan
, io_ctl
;
300 special_file_t
* special_file_ptr
;
302 special_file_ptr
= get_special_file(minor_dev_nr
);
303 if(special_file_ptr
== NULL
) {
307 read_chan
= special_file_ptr
->read_chan
;
308 write_chan
= special_file_ptr
->write_chan
;
309 io_ctl
= special_file_ptr
->io_ctl
;
311 if (read_chan
==NO_CHANNEL
&& write_chan
==NO_CHANNEL
&& io_ctl
==NO_CHANNEL
) {
312 printf("%s: No channel specified for minor device %d!\n",
313 drv
.DriverName
, minor_dev_nr
);
316 if (read_chan
== write_chan
&& read_chan
!= NO_CHANNEL
) {
317 printf("%s: Read and write channels are equal: %d!\n",
318 drv
.DriverName
, minor_dev_nr
);
322 if (!device_available
) {
323 if (init_driver() != OK
) {
324 printf("%s: Couldn't init driver!\n", drv
.DriverName
);
327 device_available
= TRUE
;
330 /* open the sub devices specified in the interface header file */
331 if (write_chan
!= NO_CHANNEL
) {
332 /* open sub device for writing */
333 if (open_sub_dev(write_chan
, DEV_WRITE_S
) != OK
) return EIO
;
335 if (read_chan
!= NO_CHANNEL
) {
336 if (open_sub_dev(read_chan
, DEV_READ_S
) != OK
) return EIO
;
338 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
339 /* io_ctl is already opened because it's the same as read or write */
340 return OK
; /* we're done */
342 if (io_ctl
!= NO_CHANNEL
) { /* Ioctl differs from read/write channels, */
343 r
= open_sub_dev(io_ctl
, NO_DMA
); /* open it explicitly */
344 if (r
!= OK
) return EIO
;
350 static int open_sub_dev(int sub_dev_nr
, int dma_mode
) {
351 sub_dev_t
* sub_dev_ptr
;
352 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
354 /* Only one open at a time per sub device */
355 if (sub_dev_ptr
->Opened
) {
356 printf("%s: Sub device %d is already opened\n",
357 drv
.DriverName
, sub_dev_nr
);
360 if (sub_dev_ptr
->DmaBusy
) {
361 printf("%s: Sub device %d is still busy\n", drv
.DriverName
, sub_dev_nr
);
364 /* Setup variables */
365 sub_dev_ptr
->Opened
= TRUE
;
366 sub_dev_ptr
->DmaReadNext
= 0;
367 sub_dev_ptr
->DmaFillNext
= 0;
368 sub_dev_ptr
->DmaLength
= 0;
369 sub_dev_ptr
->DmaMode
= dma_mode
;
370 sub_dev_ptr
->BufReadNext
= 0;
371 sub_dev_ptr
->BufFillNext
= 0;
372 sub_dev_ptr
->BufLength
= 0;
373 sub_dev_ptr
->RevivePending
= FALSE
;
374 sub_dev_ptr
->OutOfData
= TRUE
;
377 if (dma_mode
!= NO_DMA
) { /* sub device uses DMA */
378 /* allocate dma buffer and extra buffer space
379 and configure sub device for dma */
380 if (init_buffers(sub_dev_ptr
) != OK
) return EIO
;
386 static int msg_close(int minor_dev_nr
) {
388 int r
, read_chan
, write_chan
, io_ctl
;
389 special_file_t
* special_file_ptr
;
391 special_file_ptr
= get_special_file(minor_dev_nr
);
392 if(special_file_ptr
== NULL
) {
396 read_chan
= special_file_ptr
->read_chan
;
397 write_chan
= special_file_ptr
->write_chan
;
398 io_ctl
= special_file_ptr
->io_ctl
;
402 /* close all sub devices */
403 if (write_chan
!= NO_CHANNEL
) {
404 if (close_sub_dev(write_chan
) != OK
) r
= EIO
;
406 if (read_chan
!= NO_CHANNEL
) {
407 if (close_sub_dev(read_chan
) != OK
) r
= EIO
;
409 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
410 /* io_ctl is already closed because it's the same as read or write */
411 return r
; /* we're done */
413 /* ioctl differs from read/write channels... */
414 if (io_ctl
!= NO_CHANNEL
) {
415 if (close_sub_dev(io_ctl
) != OK
) r
= EIO
; /* ...close it explicitly */
421 static int close_sub_dev(int sub_dev_nr
) {
423 sub_dev_t
*sub_dev_ptr
;
424 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
425 if (sub_dev_ptr
->DmaMode
== DEV_WRITE_S
&& !sub_dev_ptr
->OutOfData
) {
426 /* do nothing, still data in buffers that has to be transferred */
427 sub_dev_ptr
->Opened
= FALSE
; /* keep DMA busy */
430 if (sub_dev_ptr
->DmaMode
== NO_DMA
) {
431 /* do nothing, there is no dma going on */
432 sub_dev_ptr
->Opened
= FALSE
;
435 sub_dev_ptr
->Opened
= FALSE
;
436 sub_dev_ptr
->DmaBusy
= FALSE
;
437 /* stop the device */
438 drv_stop(sub_dev_ptr
->Nr
);
439 /* free the buffers */
440 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
441 free_contig(sub_dev_ptr
->DmaBuf
, size
);
442 free(sub_dev_ptr
->ExtraBuf
);
447 static int msg_ioctl(const message
*m_ptr
)
449 int status
, len
, chan
;
450 sub_dev_t
*sub_dev_ptr
;
451 special_file_t
* special_file_ptr
;
453 special_file_ptr
= get_special_file(m_ptr
->DEVICE
);
454 if(special_file_ptr
== NULL
) {
458 chan
= special_file_ptr
->io_ctl
;
460 if (chan
== NO_CHANNEL
) {
461 printf("%s: No io control channel specified!\n", drv
.DriverName
);
464 /* get pointer to sub device data */
465 sub_dev_ptr
= &sub_dev
[chan
];
467 if(!sub_dev_ptr
->Opened
) {
468 printf("%s: io control impossible - not opened!\n", drv
.DriverName
);
473 /* this is a hack...todo: may we intercept reset calls? */
475 if(m_ptr->REQUEST == DSPIORESET) {
476 device_available = FALSE;
481 if (m_ptr
->REQUEST
& _IOC_IN
) { /* if there is data for us, copy it */
482 len
= io_ctl_length(m_ptr
->REQUEST
);
484 if(sys_safecopyfrom(m_ptr
->m_source
,
485 (vir_bytes
)m_ptr
->ADDRESS
, 0,
486 (vir_bytes
)io_ctl_buf
, len
) != OK
) {
487 printf("%s:%d: safecopyfrom failed\n", __FILE__
, __LINE__
);
491 /* all ioctl's are passed to the device specific part of the driver */
492 status
= drv_io_ctl(m_ptr
->REQUEST
, (void *)io_ctl_buf
, &len
, chan
);
494 /* _IOC_OUT bit -> user expects data */
495 if (status
== OK
&& m_ptr
->REQUEST
& _IOC_OUT
) {
496 /* copy result back to user */
498 if(sys_safecopyto(m_ptr
->m_source
, (vir_bytes
)m_ptr
->ADDRESS
, 0,
499 (vir_bytes
)io_ctl_buf
, len
) != OK
) {
500 printf("%s:%d: safecopyto failed\n", __FILE__
, __LINE__
);
508 static void msg_write(const message
*m_ptr
)
510 int chan
; sub_dev_t
*sub_dev_ptr
;
511 special_file_t
* special_file_ptr
;
513 special_file_ptr
= get_special_file(m_ptr
->DEVICE
);
514 chan
= special_file_ptr
->write_chan
;
516 if (chan
== NO_CHANNEL
) {
517 printf("%s: No write channel specified!\n", drv
.DriverName
);
518 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EIO
);
521 /* get pointer to sub device data */
522 sub_dev_ptr
= &sub_dev
[chan
];
524 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first write */
525 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
526 printf("%s; Failed to get fragment size!\n", drv
.DriverName
);
530 if(m_ptr
->COUNT
!= sub_dev_ptr
->FragSize
) {
531 printf("Fragment size does not match user's buffer length\n");
532 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EINVAL
);
535 /* if we are busy with something else than writing, return EBUSY */
536 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= DEV_WRITE_S
) {
537 printf("Already busy with something else then writing\n");
538 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EBUSY
);
542 sub_dev_ptr
->RevivePending
= TRUE
;
543 sub_dev_ptr
->ReviveProcNr
= m_ptr
->USER_ENDPT
;
544 sub_dev_ptr
->ReviveGrant
= (cp_grant_id_t
) m_ptr
->ADDRESS
;
545 sub_dev_ptr
->SourceProcNr
= m_ptr
->m_source
;
547 data_from_user(sub_dev_ptr
);
549 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
550 get_started(sub_dev_ptr
);
551 sub_dev_ptr
->DmaMode
= DEV_WRITE_S
; /* Dma mode is writing */
556 static void msg_read(message
*m_ptr
)
558 int chan
; sub_dev_t
*sub_dev_ptr
;
559 special_file_t
* special_file_ptr
;
561 special_file_ptr
= get_special_file(m_ptr
->DEVICE
);
562 chan
= special_file_ptr
->read_chan
;
564 if (chan
== NO_CHANNEL
) {
565 printf("%s: No read channel specified!\n", drv
.DriverName
);
566 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EIO
);
569 /* get pointer to sub device data */
570 sub_dev_ptr
= &sub_dev
[chan
];
572 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first read */
573 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
574 printf("%s: Could not retrieve fragment size!\n", drv
.DriverName
);
575 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
,
580 if(m_ptr
->COUNT
!= sub_dev_ptr
->FragSize
) {
581 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EINVAL
);
582 printf("fragment size does not match message size\n");
585 /* if we are busy with something else than reading, reply EBUSY */
586 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= DEV_READ_S
) {
587 reply(DEV_REVIVE
, m_ptr
->m_source
, m_ptr
->USER_ENDPT
, EBUSY
);
591 sub_dev_ptr
->RevivePending
= TRUE
;
592 sub_dev_ptr
->ReviveProcNr
= m_ptr
->USER_ENDPT
;
593 sub_dev_ptr
->ReviveGrant
= (cp_grant_id_t
) m_ptr
->ADDRESS
;
594 sub_dev_ptr
->SourceProcNr
= m_ptr
->m_source
;
596 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
597 get_started(sub_dev_ptr
);
598 sub_dev_ptr
->DmaMode
= DEV_READ_S
; /* Dma mode is reading */
599 return; /* no need to get data from DMA buffer at this point */
601 /* check if data is available and possibly fill user's buffer */
602 data_to_user(sub_dev_ptr
);
606 static void msg_hardware(void) {
610 /* while we have an interrupt */
611 while ( drv_int_sum()) {
612 /* loop over all sub devices */
613 for ( i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
614 /* if interrupt from sub device and Dma transfer
615 was actually busy, take care of business */
616 if( drv_int(i
) && sub_dev
[i
].DmaBusy
) {
617 if (sub_dev
[i
].DmaMode
== DEV_WRITE_S
) handle_int_write(i
);
618 if (sub_dev
[i
].DmaMode
== DEV_READ_S
) handle_int_read(i
);
623 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must
624 * re-enable out interrupt after every interrupt.
626 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
627 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv
.DriverName
);
632 static void msg_status(message
*m_ptr
)
636 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
638 if(sub_dev
[i
].ReadyToRevive
)
640 m_ptr
->m_type
= DEV_REVIVE
; /* build message */
641 m_ptr
->REP_ENDPT
= sub_dev
[i
].ReviveProcNr
;
642 m_ptr
->REP_IO_GRANT
= sub_dev
[i
].ReviveGrant
;
643 m_ptr
->REP_STATUS
= sub_dev
[i
].ReviveStatus
;
644 send(m_ptr
->m_source
, m_ptr
); /* send the message */
646 /* reset variables */
647 sub_dev
[i
].ReadyToRevive
= FALSE
;
648 sub_dev
[i
].RevivePending
= 0;
650 is_status_msg_expected
= TRUE
;
651 return; /* stop after one mess,
652 file system will get back for other processes */
655 m_ptr
->m_type
= DEV_NO_STATUS
;
656 m_ptr
->REP_STATUS
= 0;
657 send(m_ptr
->m_source
, m_ptr
); /* send DEV_NO_STATUS message */
658 is_status_msg_expected
= FALSE
;
661 /* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/
662 static void handle_int_write(int sub_dev_nr
)
664 sub_dev_t
*sub_dev_ptr
;
666 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
668 sub_dev_ptr
->DmaReadNext
=
669 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
670 sub_dev_ptr
->DmaLength
-= 1;
672 if (sub_dev_ptr
->BufLength
!= 0) { /* Data in extra buf, copy to Dma buf */
674 memcpy(sub_dev_ptr
->DmaPtr
+
675 sub_dev_ptr
->DmaFillNext
* sub_dev_ptr
->FragSize
,
676 sub_dev_ptr
->ExtraBuf
+
677 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
678 sub_dev_ptr
->FragSize
);
680 sub_dev_ptr
->BufReadNext
=
681 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
682 sub_dev_ptr
->DmaFillNext
=
683 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
685 sub_dev_ptr
->BufLength
-= 1;
686 sub_dev_ptr
->DmaLength
+= 1;
689 /* space became available, possibly copy new data from user */
690 data_from_user(sub_dev_ptr
);
692 if(sub_dev_ptr
->DmaLength
== 0) { /* Dma buffer empty, stop Dma transfer */
694 sub_dev_ptr
->OutOfData
= TRUE
; /* we're out of data */
695 if (!sub_dev_ptr
->Opened
) {
696 close_sub_dev(sub_dev_ptr
->Nr
);
699 drv_pause(sub_dev_ptr
->Nr
);
703 /* confirm and reenable interrupt from this sub dev */
704 drv_reenable_int(sub_dev_nr
);
706 /* reenable irq_hook*/
707 if (sys_irqenable(&irq_hook_id
!= OK
) {
708 printf("%s Couldn't enable IRQ\n", drv
.DriverName
);
714 /* handle interrupt for specified sub device; DmaMode == DEV_READ_S */
715 static void handle_int_read(int sub_dev_nr
)
717 sub_dev_t
*sub_dev_ptr
;
719 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
721 sub_dev_ptr
->DmaLength
+= 1;
722 sub_dev_ptr
->DmaFillNext
=
723 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
725 /* possibly copy data to user (if it is waiting for us) */
726 data_to_user(sub_dev_ptr
);
728 if (sub_dev_ptr
->DmaLength
== sub_dev_ptr
->NrOfDmaFragments
) {
729 /* if dma buffer full */
731 if (sub_dev_ptr
->BufLength
== sub_dev_ptr
->NrOfExtraBuffers
) {
732 printf("All buffers full, we have a problem.\n");
733 drv_stop(sub_dev_nr
); /* stop the sub device */
734 sub_dev_ptr
->DmaBusy
= FALSE
;
735 sub_dev_ptr
->ReviveStatus
= 0; /* no data for user,
736 this is a sad story */
737 sub_dev_ptr
->ReadyToRevive
= TRUE
; /* wake user up */
740 else { /* dma full, still room in extra buf;
741 copy from dma to extra buf */
742 memcpy(sub_dev_ptr
->ExtraBuf
+
743 sub_dev_ptr
->BufFillNext
* sub_dev_ptr
->FragSize
,
744 sub_dev_ptr
->DmaPtr
+
745 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
746 sub_dev_ptr
->FragSize
);
747 sub_dev_ptr
->DmaLength
-= 1;
748 sub_dev_ptr
->DmaReadNext
=
749 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
750 sub_dev_ptr
->BufFillNext
=
751 (sub_dev_ptr
->BufFillNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
754 /* confirm interrupt, and reenable interrupt from this sub dev*/
755 drv_reenable_int(sub_dev_ptr
->Nr
);
758 /* reenable irq_hook*/
759 if (sys_irqenable(&irq_hook_id
) != OK
) {
760 printf("%s: Couldn't reenable IRQ", drv
.DriverName
);
766 static int get_started(sub_dev_t
*sub_dev_ptr
) {
769 /* enable interrupt messages from MINIX */
770 if ((i
=sys_irqenable(&irq_hook_id
)) != OK
) {
771 printf("%s: Couldn't enable IRQs: error code %u",drv
.DriverName
, (unsigned int) i
);
774 /* let the lower part of the driver start the device */
775 if (drv_start(sub_dev_ptr
->Nr
, sub_dev_ptr
->DmaMode
) != OK
) {
776 printf("%s: Could not start device %d\n",
777 drv
.DriverName
, sub_dev_ptr
->Nr
);
780 sub_dev_ptr
->DmaBusy
= TRUE
; /* Dma is busy from now on */
781 sub_dev_ptr
->DmaReadNext
= 0;
786 static void data_from_user(sub_dev_t
*subdev
)
791 if (subdev
->DmaLength
== subdev
->NrOfDmaFragments
&&
792 subdev
->BufLength
== subdev
->NrOfExtraBuffers
) return;/* no space */
794 if (!subdev
->RevivePending
) return; /* no new data waiting to be copied */
796 if (subdev
->RevivePending
&&
797 subdev
->ReadyToRevive
) return; /* we already got this data */
799 if (subdev
->DmaLength
< subdev
->NrOfDmaFragments
) { /* room in dma buf */
801 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
802 (vir_bytes
)subdev
->ReviveGrant
, 0,
803 (vir_bytes
)subdev
->DmaPtr
+
804 subdev
->DmaFillNext
* subdev
->FragSize
,
805 (phys_bytes
)subdev
->FragSize
);
807 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
810 subdev
->DmaLength
+= 1;
811 subdev
->DmaFillNext
=
812 (subdev
->DmaFillNext
+ 1) % subdev
->NrOfDmaFragments
;
814 } else { /* room in extra buf */
816 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
817 (vir_bytes
)subdev
->ReviveGrant
, 0,
818 (vir_bytes
)subdev
->ExtraBuf
+
819 subdev
->BufFillNext
* subdev
->FragSize
,
820 (phys_bytes
)subdev
->FragSize
);
822 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
824 subdev
->BufLength
+= 1;
826 subdev
->BufFillNext
=
827 (subdev
->BufFillNext
+ 1) % subdev
->NrOfExtraBuffers
;
830 if(subdev
->OutOfData
) { /* if device paused (because of lack of data) */
831 subdev
->OutOfData
= FALSE
;
832 drv_reenable_int(subdev
->Nr
);
833 /* reenable irq_hook*/
834 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
835 printf("%s: Couldn't enable IRQ", drv
.DriverName
);
837 drv_resume(subdev
->Nr
); /* resume resume the sub device */
840 subdev
->ReviveStatus
= subdev
->FragSize
;
841 subdev
->ReadyToRevive
= TRUE
;
843 m
.m_type
= DEV_REVIVE
; /* build message */
844 m
.REP_ENDPT
= subdev
->ReviveProcNr
;
845 m
.REP_IO_GRANT
= subdev
->ReviveGrant
;
846 m
.REP_STATUS
= subdev
->ReviveStatus
;
847 r
= send(subdev
->SourceProcNr
, &m
); /* send the message */
850 printf("audio_fw: send to %d failed: %d\n",
851 subdev
->SourceProcNr
, r
);
854 /* reset variables */
855 subdev
->ReadyToRevive
= FALSE
;
856 subdev
->RevivePending
= 0;
860 static void data_to_user(sub_dev_t
*sub_dev_ptr
)
865 if (!sub_dev_ptr
->RevivePending
) return; /* nobody is wating for data */
866 if (sub_dev_ptr
->ReadyToRevive
) return;/* we already filled user's buffer */
867 if (sub_dev_ptr
->BufLength
== 0 && sub_dev_ptr
->DmaLength
== 0) return;
868 /* no data for user */
870 if(sub_dev_ptr
->BufLength
!= 0) { /* data in extra buffer available */
872 r
= sys_safecopyto(sub_dev_ptr
->SourceProcNr
,
873 (vir_bytes
)sub_dev_ptr
->ReviveGrant
,
874 0, (vir_bytes
)sub_dev_ptr
->ExtraBuf
+
875 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
876 (phys_bytes
)sub_dev_ptr
->FragSize
);
878 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
880 /* adjust the buffer status variables */
881 sub_dev_ptr
->BufReadNext
=
882 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
883 sub_dev_ptr
->BufLength
-= 1;
885 } else { /* extra buf empty, but data in dma buf*/
887 sub_dev_ptr
->SourceProcNr
,
888 (vir_bytes
)sub_dev_ptr
->ReviveGrant
, 0,
889 (vir_bytes
)sub_dev_ptr
->DmaPtr
+
890 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
891 (phys_bytes
)sub_dev_ptr
->FragSize
);
893 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
895 /* adjust the buffer status variables */
896 sub_dev_ptr
->DmaReadNext
=
897 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
898 sub_dev_ptr
->DmaLength
-= 1;
901 sub_dev_ptr
->ReviveStatus
= sub_dev_ptr
->FragSize
;
902 sub_dev_ptr
->ReadyToRevive
= TRUE
;
903 /* drv_status will send REVIVE mess to FS*/
905 m
.m_type
= DEV_REVIVE
; /* build message */
906 m
.REP_ENDPT
= sub_dev_ptr
->ReviveProcNr
;
907 m
.REP_IO_GRANT
= sub_dev_ptr
->ReviveGrant
;
908 m
.REP_STATUS
= sub_dev_ptr
->ReviveStatus
;
909 r
= send(sub_dev_ptr
->SourceProcNr
, &m
); /* send the message */
912 printf("audio_fw: send to %d failed: %d\n",
913 sub_dev_ptr
->SourceProcNr
, r
);
916 /* reset variables */
917 sub_dev_ptr
->ReadyToRevive
= FALSE
;
918 sub_dev_ptr
->RevivePending
= 0;
921 static int init_buffers(sub_dev_t
*sub_dev_ptr
)
923 #if defined(__i386__)
930 /* allocate dma buffer space */
931 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
932 base
= alloc_contig(size
, AC_ALIGN4K
, &ph
);
934 printf("%s: failed to allocate dma buffer for a channel\n",
938 sub_dev_ptr
->DmaBuf
= base
;
940 tell_dev((vir_bytes
)base
, size
, 0, 0, 0);
942 /* allocate extra buffer space */
943 if (!(sub_dev_ptr
->ExtraBuf
= malloc(sub_dev_ptr
->NrOfExtraBuffers
*
944 sub_dev_ptr
->DmaSize
/
945 sub_dev_ptr
->NrOfDmaFragments
))) {
946 printf("%s failed to allocate extra buffer for a channel\n",
951 sub_dev_ptr
->DmaPtr
= sub_dev_ptr
->DmaBuf
;
952 i
= sys_umap(SELF
, VM_D
, (vir_bytes
) base
, (phys_bytes
) size
,
953 &(sub_dev_ptr
->DmaPhys
));
959 if ((left
= dma_bytes_left(sub_dev_ptr
->DmaPhys
)) <
960 sub_dev_ptr
->DmaSize
) {
961 /* First half of buffer crosses a 64K boundary,
962 * can't DMA into that */
963 sub_dev_ptr
->DmaPtr
+= left
;
964 sub_dev_ptr
->DmaPhys
+= left
;
966 /* write the physical dma address and size to the device */
967 drv_set_dma(sub_dev_ptr
->DmaPhys
,
968 sub_dev_ptr
->DmaSize
, sub_dev_ptr
->Nr
);
971 #else /* !defined(__i386__) */
972 printf("%s: init_buffers() failed, CHIP != INTEL", drv
.DriverName
);
974 #endif /* defined(__i386__) */
978 static void reply(int code
, int replyee
, int process
, int status
) {
981 m
.m_type
= code
; /* DEV_REVIVE */
982 m
.REP_STATUS
= status
; /* result of device operation */
983 m
.REP_ENDPT
= process
; /* which user made the request */
988 static int io_ctl_length(int io_request
) {
990 return io_request
& _IOCPARM_MASK
;
994 static special_file_t
* get_special_file(int minor_dev_nr
) {
997 for(i
= 0; i
< drv
.NrOfSpecialFiles
; i
++) {
998 if(special_file
[i
].minor_dev_nr
== minor_dev_nr
) {
999 return &special_file
[i
];
1003 printf("%s: No subdevice specified for minor device %d!\n",
1004 drv
.DriverName
, minor_dev_nr
);
1009 static void tell_dev(buf
, size
, pci_bus
, pci_dev
, pci_func
)
1020 r
= ds_retrieve_label_endpt("amddev", &dev_e
);
1024 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
1030 m
.m_type
= IOMMU_MAP
;
1037 r
= sendrec(dev_e
, &m
);
1040 printf("tell_dev: sendrec to %d failed: %d\n", dev_e
, r
);
1045 printf("tell_dev: dma map request failed: %d\n", m
.m_type
);