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 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
47 #include <minix/endpoint.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. */
96 /* Here is the main loop of the dma driver. It waits for a message,
97 carries it out, and sends a reply. */
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
)) {
114 dprint("%s: %d uncaught notify!\n",
115 drv
.DriverName
, mess
.m_type
);
118 /* get next message */
122 /* Normal messages. */
123 switch(mess
.m_type
) {
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
);
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
);
145 r
= msg_ioctl(&mess
);
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
);
159 msg_read(&mess
); continue; /* don't reply */
161 msg_write(&mess
); continue; /* don't reply */
163 msg_status(&mess
);continue; /* don't reply */
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
);
173 dprint("%s: %d uncaught msg!\n",
174 drv
.DriverName
, mess
.m_type
);
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. */
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) {
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
;
233 /* initialize hardware*/
234 if (drv_init_hw() != OK
) {
235 error("%s: Could not initialize hardware\n", drv
.DriverName
, 0);
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
);
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
;
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
);
254 irq_hook_set
= TRUE
; /* now msg_sig_stop knows it must unregister policy*/
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
) {
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
);
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
);
285 if (!device_available
) {
286 if (init_driver() != OK
) {
287 error("%s: Couldn't init driver!\n", drv
.DriverName
, minor_dev_nr
);
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
;
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
);
323 if (sub_dev_ptr
->DmaBusy
) {
324 error("%s: Sub device %d is still busy\n", drv
.DriverName
, sub_dev_nr
);
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
;
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
;
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
) {
361 read_chan
= special_file_ptr
->read_chan
;
362 write_chan
= special_file_ptr
->write_chan
;
363 io_ctl
= special_file_ptr
->io_ctl
;
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 */
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 */
394 if (sub_dev_ptr
->DmaMode
== NO_DMA
) {
395 /* do nothing, there is no dma going on */
396 sub_dev_ptr
->Opened
= FALSE
;
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
);
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
) {
423 chan
= special_file_ptr
->io_ctl
;
425 if (chan
== NO_CHANNEL
) {
426 error("%s: No io control channel specified!\n", drv
.DriverName
);
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
);
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__
);
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
);
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);
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
);
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
);
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
);
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
);
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");
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
);
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) {
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
)
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)
637 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
638 drv_stop(i
); /* stop all sub devices */
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
);
699 dprint("Pausing sub device %d\n",sub_dev_ptr
->Nr
);
700 drv_pause(sub_dev_ptr
->Nr
);
706 /* confirm and reenable interrupt from this sub dev */
707 drv_reenable_int(sub_dev_nr
);
709 /* reenable irq_hook*/
710 if (sys_irqenable(&irq_hook_id
!= OK
) {
711 error("%s Couldn't enable IRQ\n", drv
.DriverName
);
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 */
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
);
764 /* reenable irq_hook*/
765 if (sys_irqenable(&irq_hook_id
) != OK
) {
766 error("%s: Couldn't reenable IRQ", drv
.DriverName
);
772 PRIVATE
int get_started(sub_dev_t
*sub_dev_ptr
) {
775 /* enable interrupt messages from MINIX */
776 if ((i
=sys_irqenable(&irq_hook_id
)) != OK
) {
777 error("%s: Couldn't enable IRQs",drv
.DriverName
);
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;
792 PRIVATE
void data_from_user(sub_dev_t
*subdev
)
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 */
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
)
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*/
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 */
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
)
934 /* allocate dma buffer space */
935 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
936 base
= alloc_contig(size
, AC_ALIGN4K
, &ph
);
938 error("%s: failed to allocate dma buffer for a channel\n",
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",
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
));
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
);
977 #else /* CHIP != INTEL */
978 error("%s: init_buffer() failed, CHIP != INTEL", drv
.DriverName
);
980 #endif /* CHIP == INTEL */
984 PRIVATE
void reply(int code
, int replyee
, int process
, int status
) {
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 */
994 PRIVATE
int io_ctl_length(int io_request
) {
996 return io_request
& _IOCPARM_MASK
;
1000 PRIVATE special_file_t
* get_special_file(int minor_dev_nr
) {
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
);
1015 PRIVATE
void tell_dev(buf
, size
, pci_bus
, pci_dev
, pci_func
)
1027 r
= ds_retrieve_label_num("amddev", &u32
);
1031 printf("tell_dev: ds_retrieve_label_num failed for 'amddev': %d\n",
1039 m
.m_type
= IOMMU_MAP
;
1046 r
= sendrec(dev_e
, &m
);
1049 printf("tell_dev: sendrec to %d failed: %d\n", dev_e
, r
);
1054 printf("tell_dev: dma map request failed: %d\n", m
.m_type
);