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 file contains one entry point:
11 * main: main entry when driver is brought up
13 * October 2007 Updated audio framework to work with mplayer, added
14 * savecopies (Pieter Hijma)
15 * February 2006 Updated audio framework,
16 * changed driver-framework relation (Peter Boonstoppel)
17 * November 2005 Created generic DMA driver framework (Laurens Bronwasser)
18 * August 24 2005 Ported audio driver to user space
19 * (only audio playback) (Peter Boonstoppel)
20 * May 20 1995 SB16 Driver: Michel R. Prevenier
24 #include <minix/audio_fw.h>
25 #include <minix/endpoint.h>
27 #include <sys/ioccom.h>
30 static int msg_open(devminor_t minor_dev_nr
, int access
,
31 endpoint_t user_endpt
);
32 static int msg_close(int minor_dev_nr
);
33 static ssize_t
msg_read(devminor_t minor
, u64_t position
, endpoint_t endpt
,
34 cp_grant_id_t grant
, size_t size
, int flags
, cdev_id_t id
);
35 static ssize_t
msg_write(devminor_t minor
, u64_t position
, endpoint_t endpt
,
36 cp_grant_id_t grant
, size_t size
, int flags
, cdev_id_t id
);
37 static int msg_ioctl(devminor_t minor
, unsigned long request
, endpoint_t endpt
,
38 cp_grant_id_t grant
, int flags
, endpoint_t user_endpt
, cdev_id_t id
);
39 static void msg_hardware(unsigned int mask
);
40 static int open_sub_dev(int sub_dev_nr
, int operation
);
41 static int close_sub_dev(int sub_dev_nr
);
42 static void handle_int_write(int sub_dev_nr
);
43 static void handle_int_read(int sub_dev_nr
);
44 static void data_to_user(sub_dev_t
*sub_dev_ptr
);
45 static void data_from_user(sub_dev_t
*sub_dev_ptr
);
46 static int init_buffers(sub_dev_t
*sub_dev_ptr
);
47 static int get_started(sub_dev_t
*sub_dev_ptr
);
48 static int io_ctl_length(int io_request
);
49 static special_file_t
* get_special_file(int minor_dev_nr
);
50 static void tell_dev(vir_bytes buf
, size_t size
, int pci_bus
,
51 int pci_dev
, int pci_func
);
53 static char io_ctl_buf
[IOCPARM_MASK
];
54 static int irq_hook_id
= 0; /* id of irq hook at the kernel */
55 static int irq_hook_set
= FALSE
;
57 /* SEF functions and variables. */
58 static void sef_local_startup(void);
59 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
60 static void sef_cb_signal_handler(int signo
);
61 EXTERN
int sef_cb_lu_prepare(int state
);
62 EXTERN
int sef_cb_lu_state_isvalid(int state
);
63 EXTERN
void sef_cb_lu_state_dump(int state
);
65 static struct chardriver audio_tab
= {
66 .cdr_open
= msg_open
, /* open the special file */
67 .cdr_close
= msg_close
, /* close the special file */
69 .cdr_write
= msg_write
,
70 .cdr_ioctl
= msg_ioctl
,
71 .cdr_intr
= msg_hardware
77 message mess
, repl_mess
;
80 /* SEF local startup. */
83 /* Here is the main loop of the dma driver. It waits for a message,
84 carries it out, and sends a reply. */
85 chardriver_task(&audio_tab
);
90 /*===========================================================================*
92 *===========================================================================*/
93 static void sef_local_startup(void)
95 /* Register init callbacks. */
96 sef_setcb_init_fresh(sef_cb_init_fresh
);
97 sef_setcb_init_lu(sef_cb_init_fresh
);
98 sef_setcb_init_restart(sef_cb_init_fresh
);
100 /* Register live update callbacks. */
101 sef_setcb_lu_prepare(sef_cb_lu_prepare
);
102 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid
);
103 sef_setcb_lu_state_dump(sef_cb_lu_state_dump
);
105 /* Register signal callbacks. */
106 sef_setcb_signal_handler(sef_cb_signal_handler
);
108 /* Let SEF perform startup. */
112 /*===========================================================================*
113 * sef_cb_init_fresh *
114 *===========================================================================*/
115 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
117 /* Initialize the audio driver framework. */
119 static int executed
= 0;
120 sub_dev_t
* sub_dev_ptr
;
122 /* initialize basic driver variables */
123 if (drv_init() != OK
) {
124 printf("libaudiodriver: Could not initialize driver\n");
128 /* init variables, get dma buffers */
129 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
131 sub_dev_ptr
= &sub_dev
[i
];
133 sub_dev_ptr
->Opened
= FALSE
;
134 sub_dev_ptr
->DmaBusy
= FALSE
;
135 sub_dev_ptr
->DmaMode
= NO_DMA
;
136 sub_dev_ptr
->DmaReadNext
= 0;
137 sub_dev_ptr
->DmaFillNext
= 0;
138 sub_dev_ptr
->DmaLength
= 0;
139 sub_dev_ptr
->BufReadNext
= 0;
140 sub_dev_ptr
->BufFillNext
= 0;
141 sub_dev_ptr
->RevivePending
= FALSE
;
142 sub_dev_ptr
->OutOfData
= FALSE
;
146 /* initialize hardware*/
147 if (drv_init_hw() != OK
) {
148 printf("%s: Could not initialize hardware\n", drv
.DriverName
);
152 /* get irq from device driver...*/
153 if (drv_get_irq(&irq
) != OK
) {
154 printf("%s: init driver couldn't get IRQ", drv
.DriverName
);
157 /* TODO: execute the rest of this function only once
158 we don't want to set irq policy twice */
159 if (executed
) return OK
;
162 /* ...and register interrupt vector */
163 if ((i
=sys_irqsetpolicy(irq
, 0, &irq_hook_id
)) != OK
){
164 printf("%s: init driver couldn't set IRQ policy: %d", drv
.DriverName
, i
);
167 irq_hook_set
= TRUE
; /* now signal handler knows it must unregister policy*/
169 /* Announce we are up! */
170 chardriver_announce();
175 /*===========================================================================*
176 * sef_cb_signal_handler *
177 *===========================================================================*/
178 static void sef_cb_signal_handler(int signo
)
183 /* Only check for termination signal, ignore anything else. */
184 if (signo
!= SIGTERM
) return;
186 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
187 drv_stop(i
); /* stop all sub devices */
190 if (sys_irqdisable(&irq_hook_id
) != OK
) {
191 printf("Could not disable IRQ\n");
193 /* get irq from device driver*/
194 if (drv_get_irq(&irq
) != OK
) {
195 printf("Msg SIG_STOP Couldn't get IRQ");
197 /* remove the policy */
198 if (sys_irqrmpolicy(&irq_hook_id
) != OK
) {
199 printf("%s: Could not disable IRQ\n",drv
.DriverName
);
204 static int msg_open(devminor_t minor_dev_nr
, int UNUSED(access
),
205 endpoint_t
UNUSED(user_endpt
))
207 int r
, read_chan
, write_chan
, io_ctl
;
208 special_file_t
* special_file_ptr
;
210 special_file_ptr
= get_special_file(minor_dev_nr
);
211 if(special_file_ptr
== NULL
) {
215 read_chan
= special_file_ptr
->read_chan
;
216 write_chan
= special_file_ptr
->write_chan
;
217 io_ctl
= special_file_ptr
->io_ctl
;
219 if (read_chan
==NO_CHANNEL
&& write_chan
==NO_CHANNEL
&& io_ctl
==NO_CHANNEL
) {
220 printf("%s: No channel specified for minor device %d!\n",
221 drv
.DriverName
, minor_dev_nr
);
224 if (read_chan
== write_chan
&& read_chan
!= NO_CHANNEL
) {
225 printf("%s: Read and write channels are equal: %d!\n",
226 drv
.DriverName
, minor_dev_nr
);
229 /* open the sub devices specified in the interface header file */
230 if (write_chan
!= NO_CHANNEL
) {
231 /* open sub device for writing */
232 if (open_sub_dev(write_chan
, WRITE_DMA
) != OK
) return EIO
;
234 if (read_chan
!= NO_CHANNEL
) {
235 if (open_sub_dev(read_chan
, READ_DMA
) != OK
) return EIO
;
237 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
238 /* io_ctl is already opened because it's the same as read or write */
239 return OK
; /* we're done */
241 if (io_ctl
!= NO_CHANNEL
) { /* Ioctl differs from read/write channels, */
242 r
= open_sub_dev(io_ctl
, NO_DMA
); /* open it explicitly */
243 if (r
!= OK
) return EIO
;
249 static int open_sub_dev(int sub_dev_nr
, int dma_mode
) {
250 sub_dev_t
* sub_dev_ptr
;
251 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
253 /* Only one open at a time per sub device */
254 if (sub_dev_ptr
->Opened
) {
255 printf("%s: Sub device %d is already opened\n",
256 drv
.DriverName
, sub_dev_nr
);
259 if (sub_dev_ptr
->DmaBusy
) {
260 printf("%s: Sub device %d is still busy\n", drv
.DriverName
, sub_dev_nr
);
263 /* Setup variables */
264 sub_dev_ptr
->Opened
= TRUE
;
265 sub_dev_ptr
->DmaReadNext
= 0;
266 sub_dev_ptr
->DmaFillNext
= 0;
267 sub_dev_ptr
->DmaLength
= 0;
268 sub_dev_ptr
->DmaMode
= dma_mode
;
269 sub_dev_ptr
->BufReadNext
= 0;
270 sub_dev_ptr
->BufFillNext
= 0;
271 sub_dev_ptr
->BufLength
= 0;
272 sub_dev_ptr
->RevivePending
= FALSE
;
273 sub_dev_ptr
->OutOfData
= TRUE
;
276 if (dma_mode
!= NO_DMA
) { /* sub device uses DMA */
277 /* allocate dma buffer and extra buffer space
278 and configure sub device for dma */
279 if (init_buffers(sub_dev_ptr
) != OK
) return EIO
;
285 static int msg_close(devminor_t minor_dev_nr
)
288 int r
, read_chan
, write_chan
, io_ctl
;
289 special_file_t
* special_file_ptr
;
291 special_file_ptr
= get_special_file(minor_dev_nr
);
292 if(special_file_ptr
== NULL
) {
296 read_chan
= special_file_ptr
->read_chan
;
297 write_chan
= special_file_ptr
->write_chan
;
298 io_ctl
= special_file_ptr
->io_ctl
;
302 /* close all sub devices */
303 if (write_chan
!= NO_CHANNEL
) {
304 if (close_sub_dev(write_chan
) != OK
) r
= EIO
;
306 if (read_chan
!= NO_CHANNEL
) {
307 if (close_sub_dev(read_chan
) != OK
) r
= EIO
;
309 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
310 /* io_ctl is already closed because it's the same as read or write */
311 return r
; /* we're done */
313 /* ioctl differs from read/write channels... */
314 if (io_ctl
!= NO_CHANNEL
) {
315 if (close_sub_dev(io_ctl
) != OK
) r
= EIO
; /* ...close it explicitly */
321 static int close_sub_dev(int sub_dev_nr
) {
323 sub_dev_t
*sub_dev_ptr
;
324 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
325 if (sub_dev_ptr
->DmaMode
== WRITE_DMA
&& !sub_dev_ptr
->OutOfData
) {
326 /* do nothing, still data in buffers that has to be transferred */
327 sub_dev_ptr
->Opened
= FALSE
; /* keep DMA busy */
330 if (sub_dev_ptr
->DmaMode
== NO_DMA
) {
331 /* do nothing, there is no dma going on */
332 sub_dev_ptr
->Opened
= FALSE
;
335 sub_dev_ptr
->Opened
= FALSE
;
336 sub_dev_ptr
->DmaBusy
= FALSE
;
337 /* stop the device */
338 drv_stop(sub_dev_ptr
->Nr
);
339 /* free the buffers */
340 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
341 free_contig(sub_dev_ptr
->DmaBuf
, size
);
342 free(sub_dev_ptr
->ExtraBuf
);
347 static int msg_ioctl(devminor_t minor
, unsigned long request
, endpoint_t endpt
,
348 cp_grant_id_t grant
, int flags
, endpoint_t user_endpt
, cdev_id_t id
)
350 int status
, len
, chan
;
351 sub_dev_t
*sub_dev_ptr
;
352 special_file_t
* special_file_ptr
;
354 special_file_ptr
= get_special_file(minor
);
355 if(special_file_ptr
== NULL
) {
359 chan
= special_file_ptr
->io_ctl
;
361 if (chan
== NO_CHANNEL
) {
362 printf("%s: No io control channel specified!\n", drv
.DriverName
);
365 /* get pointer to sub device data */
366 sub_dev_ptr
= &sub_dev
[chan
];
368 if(!sub_dev_ptr
->Opened
) {
369 printf("%s: io control impossible - not opened!\n", drv
.DriverName
);
373 if (request
& IOC_IN
) { /* if there is data for us, copy it */
374 len
= io_ctl_length(request
);
376 if (sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
)io_ctl_buf
,
378 printf("%s:%d: safecopyfrom failed\n", __FILE__
, __LINE__
);
382 /* all ioctl's are passed to the device specific part of the driver */
383 status
= drv_io_ctl(request
, (void *)io_ctl_buf
, &len
, chan
);
385 /* IOC_OUT bit -> user expects data */
386 if (status
== OK
&& request
& IOC_OUT
) {
387 /* copy result back to user */
389 if (sys_safecopyto(endpt
, grant
, 0, (vir_bytes
)io_ctl_buf
,
391 printf("%s:%d: safecopyto failed\n", __FILE__
, __LINE__
);
399 static ssize_t
msg_write(devminor_t minor
, u64_t
UNUSED(position
),
400 endpoint_t endpt
, cp_grant_id_t grant
, size_t size
, int UNUSED(flags
),
403 int chan
; sub_dev_t
*sub_dev_ptr
;
404 special_file_t
* special_file_ptr
;
406 special_file_ptr
= get_special_file(minor
);
407 chan
= special_file_ptr
->write_chan
;
409 if (chan
== NO_CHANNEL
) {
410 printf("%s: No write channel specified!\n", drv
.DriverName
);
413 /* get pointer to sub device data */
414 sub_dev_ptr
= &sub_dev
[chan
];
416 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first write */
417 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
418 printf("%s; Failed to get fragment size!\n", drv
.DriverName
);
422 if(size
!= sub_dev_ptr
->FragSize
) {
423 printf("Fragment size does not match user's buffer length\n");
426 /* if we are busy with something else than writing, return EBUSY */
427 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= WRITE_DMA
) {
428 printf("Already busy with something else than writing\n");
432 sub_dev_ptr
->RevivePending
= TRUE
;
433 sub_dev_ptr
->ReviveId
= id
;
434 sub_dev_ptr
->ReviveGrant
= grant
;
435 sub_dev_ptr
->SourceProcNr
= endpt
;
437 data_from_user(sub_dev_ptr
);
439 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
440 get_started(sub_dev_ptr
);
441 sub_dev_ptr
->DmaMode
= WRITE_DMA
; /* Dma mode is writing */
444 /* We may already have replied by now. In any case don't reply here. */
449 static ssize_t
msg_read(devminor_t minor
, u64_t
UNUSED(position
),
450 endpoint_t endpt
, cp_grant_id_t grant
, size_t size
, int UNUSED(flags
),
453 int chan
; sub_dev_t
*sub_dev_ptr
;
454 special_file_t
* special_file_ptr
;
456 special_file_ptr
= get_special_file(minor
);
457 chan
= special_file_ptr
->read_chan
;
459 if (chan
== NO_CHANNEL
) {
460 printf("%s: No read channel specified!\n", drv
.DriverName
);
463 /* get pointer to sub device data */
464 sub_dev_ptr
= &sub_dev
[chan
];
466 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first read */
467 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
468 printf("%s: Could not retrieve fragment size!\n", drv
.DriverName
);
472 if(size
!= sub_dev_ptr
->FragSize
) {
473 printf("fragment size does not match message size\n");
476 /* if we are busy with something else than reading, reply EBUSY */
477 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= READ_DMA
) {
481 sub_dev_ptr
->RevivePending
= TRUE
;
482 sub_dev_ptr
->ReviveId
= id
;
483 sub_dev_ptr
->ReviveGrant
= grant
;
484 sub_dev_ptr
->SourceProcNr
= endpt
;
486 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
487 get_started(sub_dev_ptr
);
488 sub_dev_ptr
->DmaMode
= READ_DMA
; /* Dma mode is reading */
489 /* no need to get data from DMA buffer at this point */
492 /* check if data is available and possibly fill user's buffer */
493 data_to_user(sub_dev_ptr
);
495 /* We may already have replied by now. In any case don't reply here. */
500 static void msg_hardware(unsigned int UNUSED(mask
))
504 /* loop over all sub devices */
505 for ( i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
506 /* if interrupt from sub device and Dma transfer
507 was actually busy, take care of business */
508 if( drv_int(i
) && sub_dev
[i
].DmaBusy
) {
509 if (sub_dev
[i
].DmaMode
== WRITE_DMA
)
511 if (sub_dev
[i
].DmaMode
== READ_DMA
)
516 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must
517 * re-enable out interrupt after every interrupt.
519 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
520 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv
.DriverName
);
525 /* handle interrupt for specified sub device; DmaMode == WRITE_DMA */
526 static void handle_int_write(int sub_dev_nr
)
528 sub_dev_t
*sub_dev_ptr
;
530 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
532 sub_dev_ptr
->DmaReadNext
=
533 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
534 sub_dev_ptr
->DmaLength
-= 1;
536 if (sub_dev_ptr
->BufLength
!= 0) { /* Data in extra buf, copy to Dma buf */
538 memcpy(sub_dev_ptr
->DmaPtr
+
539 sub_dev_ptr
->DmaFillNext
* sub_dev_ptr
->FragSize
,
540 sub_dev_ptr
->ExtraBuf
+
541 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
542 sub_dev_ptr
->FragSize
);
544 sub_dev_ptr
->BufReadNext
=
545 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
546 sub_dev_ptr
->DmaFillNext
=
547 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
549 sub_dev_ptr
->BufLength
-= 1;
550 sub_dev_ptr
->DmaLength
+= 1;
553 /* space became available, possibly copy new data from user */
554 data_from_user(sub_dev_ptr
);
556 if(sub_dev_ptr
->DmaLength
== 0) { /* Dma buffer empty, stop Dma transfer */
558 sub_dev_ptr
->OutOfData
= TRUE
; /* we're out of data */
559 if (!sub_dev_ptr
->Opened
) {
560 close_sub_dev(sub_dev_ptr
->Nr
);
563 drv_pause(sub_dev_ptr
->Nr
);
567 /* confirm and reenable interrupt from this sub dev */
568 drv_reenable_int(sub_dev_nr
);
570 /* reenable irq_hook*/
571 if (sys_irqenable(&irq_hook_id
!= OK
) {
572 printf("%s Couldn't enable IRQ\n", drv
.DriverName
);
578 /* handle interrupt for specified sub device; DmaMode == READ_DMA */
579 static void handle_int_read(int sub_dev_nr
)
581 sub_dev_t
*sub_dev_ptr
;
584 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
586 sub_dev_ptr
->DmaLength
+= 1;
587 sub_dev_ptr
->DmaFillNext
=
588 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
590 /* possibly copy data to user (if it is waiting for us) */
591 data_to_user(sub_dev_ptr
);
593 if (sub_dev_ptr
->DmaLength
== sub_dev_ptr
->NrOfDmaFragments
) {
594 /* if dma buffer full */
596 if (sub_dev_ptr
->BufLength
== sub_dev_ptr
->NrOfExtraBuffers
) {
597 printf("All buffers full, we have a problem.\n");
598 drv_stop(sub_dev_nr
); /* stop the sub device */
599 sub_dev_ptr
->DmaBusy
= FALSE
;
600 /* no data for user, this is a sad story */
601 chardriver_reply_task(sub_dev_ptr
->SourceProcNr
,
602 sub_dev_ptr
->ReviveId
, 0);
605 else { /* dma full, still room in extra buf;
606 copy from dma to extra buf */
607 memcpy(sub_dev_ptr
->ExtraBuf
+
608 sub_dev_ptr
->BufFillNext
* sub_dev_ptr
->FragSize
,
609 sub_dev_ptr
->DmaPtr
+
610 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
611 sub_dev_ptr
->FragSize
);
612 sub_dev_ptr
->DmaLength
-= 1;
613 sub_dev_ptr
->DmaReadNext
=
614 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
615 sub_dev_ptr
->BufFillNext
=
616 (sub_dev_ptr
->BufFillNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
619 /* confirm interrupt, and reenable interrupt from this sub dev*/
620 drv_reenable_int(sub_dev_ptr
->Nr
);
623 /* reenable irq_hook*/
624 if (sys_irqenable(&irq_hook_id
) != OK
) {
625 printf("%s: Couldn't reenable IRQ", drv
.DriverName
);
631 static int get_started(sub_dev_t
*sub_dev_ptr
) {
634 /* enable interrupt messages from MINIX */
635 if ((i
=sys_irqenable(&irq_hook_id
)) != OK
) {
636 printf("%s: Couldn't enable IRQs: error code %u",drv
.DriverName
, (unsigned int) i
);
639 /* let the lower part of the driver start the device */
640 if (drv_start(sub_dev_ptr
->Nr
, sub_dev_ptr
->DmaMode
) != OK
) {
641 printf("%s: Could not start device %d\n",
642 drv
.DriverName
, sub_dev_ptr
->Nr
);
645 sub_dev_ptr
->DmaBusy
= TRUE
; /* Dma is busy from now on */
646 sub_dev_ptr
->DmaReadNext
= 0;
651 static void data_from_user(sub_dev_t
*subdev
)
656 if (subdev
->DmaLength
== subdev
->NrOfDmaFragments
&&
657 subdev
->BufLength
== subdev
->NrOfExtraBuffers
) return;/* no space */
659 if (!subdev
->RevivePending
) return; /* no new data waiting to be copied */
661 if (subdev
->DmaLength
< subdev
->NrOfDmaFragments
) { /* room in dma buf */
663 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
664 (vir_bytes
)subdev
->ReviveGrant
, 0,
665 (vir_bytes
)subdev
->DmaPtr
+
666 subdev
->DmaFillNext
* subdev
->FragSize
,
667 (phys_bytes
)subdev
->FragSize
);
669 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
672 subdev
->DmaLength
+= 1;
673 subdev
->DmaFillNext
=
674 (subdev
->DmaFillNext
+ 1) % subdev
->NrOfDmaFragments
;
676 } else { /* room in extra buf */
678 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
679 (vir_bytes
)subdev
->ReviveGrant
, 0,
680 (vir_bytes
)subdev
->ExtraBuf
+
681 subdev
->BufFillNext
* subdev
->FragSize
,
682 (phys_bytes
)subdev
->FragSize
);
684 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
686 subdev
->BufLength
+= 1;
688 subdev
->BufFillNext
=
689 (subdev
->BufFillNext
+ 1) % subdev
->NrOfExtraBuffers
;
692 if(subdev
->OutOfData
) { /* if device paused (because of lack of data) */
693 subdev
->OutOfData
= FALSE
;
694 drv_reenable_int(subdev
->Nr
);
695 /* reenable irq_hook*/
696 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
697 printf("%s: Couldn't enable IRQ", drv
.DriverName
);
699 drv_resume(subdev
->Nr
); /* resume resume the sub device */
702 chardriver_reply_task(subdev
->SourceProcNr
, subdev
->ReviveId
,
705 /* reset variables */
706 subdev
->RevivePending
= 0;
710 static void data_to_user(sub_dev_t
*sub_dev_ptr
)
715 if (!sub_dev_ptr
->RevivePending
) return; /* nobody is wating for data */
716 if (sub_dev_ptr
->BufLength
== 0 && sub_dev_ptr
->DmaLength
== 0) return;
717 /* no data for user */
719 if(sub_dev_ptr
->BufLength
!= 0) { /* data in extra buffer available */
721 r
= sys_safecopyto(sub_dev_ptr
->SourceProcNr
,
722 (vir_bytes
)sub_dev_ptr
->ReviveGrant
,
723 0, (vir_bytes
)sub_dev_ptr
->ExtraBuf
+
724 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
725 (phys_bytes
)sub_dev_ptr
->FragSize
);
727 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
729 /* adjust the buffer status variables */
730 sub_dev_ptr
->BufReadNext
=
731 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
732 sub_dev_ptr
->BufLength
-= 1;
734 } else { /* extra buf empty, but data in dma buf*/
736 sub_dev_ptr
->SourceProcNr
,
737 (vir_bytes
)sub_dev_ptr
->ReviveGrant
, 0,
738 (vir_bytes
)sub_dev_ptr
->DmaPtr
+
739 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
740 (phys_bytes
)sub_dev_ptr
->FragSize
);
742 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
744 /* adjust the buffer status variables */
745 sub_dev_ptr
->DmaReadNext
=
746 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
747 sub_dev_ptr
->DmaLength
-= 1;
750 chardriver_reply_task(sub_dev_ptr
->SourceProcNr
, sub_dev_ptr
->ReviveId
,
751 sub_dev_ptr
->FragSize
);
753 /* reset variables */
754 sub_dev_ptr
->RevivePending
= 0;
757 static int init_buffers(sub_dev_t
*sub_dev_ptr
)
759 #if defined(__i386__)
766 /* allocate dma buffer space */
767 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
768 base
= alloc_contig(size
, AC_ALIGN64K
|AC_LOWER16M
, &ph
);
770 printf("%s: failed to allocate dma buffer for a channel\n",
774 sub_dev_ptr
->DmaBuf
= base
;
776 tell_dev((vir_bytes
)base
, size
, 0, 0, 0);
778 /* allocate extra buffer space */
779 if (!(sub_dev_ptr
->ExtraBuf
= malloc(sub_dev_ptr
->NrOfExtraBuffers
*
780 sub_dev_ptr
->DmaSize
/
781 sub_dev_ptr
->NrOfDmaFragments
))) {
782 printf("%s failed to allocate extra buffer for a channel\n",
787 sub_dev_ptr
->DmaPtr
= sub_dev_ptr
->DmaBuf
;
788 i
= sys_umap(SELF
, VM_D
, (vir_bytes
) base
, (phys_bytes
) size
,
789 &(sub_dev_ptr
->DmaPhys
));
795 if ((left
= dma_bytes_left(sub_dev_ptr
->DmaPhys
)) <
796 sub_dev_ptr
->DmaSize
) {
797 /* First half of buffer crosses a 64K boundary,
798 * can't DMA into that */
799 sub_dev_ptr
->DmaPtr
+= left
;
800 sub_dev_ptr
->DmaPhys
+= left
;
802 /* write the physical dma address and size to the device */
803 drv_set_dma(sub_dev_ptr
->DmaPhys
,
804 sub_dev_ptr
->DmaSize
, sub_dev_ptr
->Nr
);
807 #else /* !defined(__i386__) */
808 printf("%s: init_buffers() failed, CHIP != INTEL", drv
.DriverName
);
810 #endif /* defined(__i386__) */
814 static int io_ctl_length(int io_request
) {
816 return io_request
& IOCPARM_MASK
;
820 static special_file_t
* get_special_file(int minor_dev_nr
) {
823 for(i
= 0; i
< drv
.NrOfSpecialFiles
; i
++) {
824 if(special_file
[i
].minor_dev_nr
== minor_dev_nr
) {
825 return &special_file
[i
];
829 printf("%s: No subdevice specified for minor device %d!\n",
830 drv
.DriverName
, minor_dev_nr
);
835 static void tell_dev(vir_bytes buf
, size_t size
, int pci_bus
,
836 int pci_dev
, int pci_func
)
842 r
= ds_retrieve_label_endpt("amddev", &dev_e
);
846 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
859 r
= ipc_sendrec(dev_e
, &m
);
862 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e
, r
);
867 printf("tell_dev: dma map request failed: %d\n", m
.m_type
);