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
);
51 static void tell_dev(vir_bytes buf
, size_t size
, int pci_bus
,
52 int pci_dev
, int pci_func
);
55 static char io_ctl_buf
[IOCPARM_MASK
];
56 static int irq_hook_id
= 0; /* id of irq hook at the kernel */
57 static int irq_hook_set
= FALSE
;
59 /* SEF functions and variables. */
60 static void sef_local_startup(void);
61 static int sef_cb_init_fresh(int type
, sef_init_info_t
*info
);
62 static void sef_cb_signal_handler(int signo
);
64 static struct chardriver audio_tab
= {
65 .cdr_open
= msg_open
, /* open the special file */
66 .cdr_close
= msg_close
, /* close the special file */
68 .cdr_write
= msg_write
,
69 .cdr_ioctl
= msg_ioctl
,
70 .cdr_intr
= msg_hardware
76 /* SEF local startup. */
79 /* Here is the main loop of the dma driver. It waits for a message,
80 carries it out, and sends a reply. */
81 chardriver_task(&audio_tab
);
86 /*===========================================================================*
88 *===========================================================================*/
89 static void sef_local_startup(void)
91 /* Register init callbacks. */
92 sef_setcb_init_fresh(sef_cb_init_fresh
);
93 sef_setcb_init_restart(sef_cb_init_fresh
);
95 /* Register live update callbacks. */
96 sef_setcb_lu_prepare(sef_cb_lu_prepare
);
97 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid
);
98 sef_setcb_lu_state_dump(sef_cb_lu_state_dump
);
100 /* Register signal callbacks. */
101 sef_setcb_signal_handler(sef_cb_signal_handler
);
103 /* Let SEF perform startup. */
107 /*===========================================================================*
108 * sef_cb_init_fresh *
109 *===========================================================================*/
110 static int sef_cb_init_fresh(int UNUSED(type
), sef_init_info_t
*UNUSED(info
))
112 /* Initialize the audio driver framework. */
114 static int executed
= 0;
115 sub_dev_t
* sub_dev_ptr
;
117 /* initialize basic driver variables */
118 if (drv_init() != OK
) {
119 printf("libaudiodriver: Could not initialize driver\n");
123 /* init variables, get dma buffers */
124 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
126 sub_dev_ptr
= &sub_dev
[i
];
128 sub_dev_ptr
->Opened
= FALSE
;
129 sub_dev_ptr
->DmaBusy
= FALSE
;
130 sub_dev_ptr
->DmaMode
= NO_DMA
;
131 sub_dev_ptr
->DmaReadNext
= 0;
132 sub_dev_ptr
->DmaFillNext
= 0;
133 sub_dev_ptr
->DmaLength
= 0;
134 sub_dev_ptr
->BufReadNext
= 0;
135 sub_dev_ptr
->BufFillNext
= 0;
136 sub_dev_ptr
->RevivePending
= FALSE
;
137 sub_dev_ptr
->OutOfData
= FALSE
;
141 /* initialize hardware*/
142 if (drv_init_hw() != OK
) {
143 printf("%s: Could not initialize hardware\n", drv
.DriverName
);
147 /* get irq from device driver...*/
148 if (drv_get_irq(&irq
) != OK
) {
149 printf("%s: init driver couldn't get IRQ", drv
.DriverName
);
152 /* TODO: execute the rest of this function only once
153 we don't want to set irq policy twice */
154 if (executed
) return OK
;
157 /* ...and register interrupt vector */
158 if ((i
=sys_irqsetpolicy(irq
, 0, &irq_hook_id
)) != OK
){
159 printf("%s: init driver couldn't set IRQ policy: %d", drv
.DriverName
, i
);
162 irq_hook_set
= TRUE
; /* now signal handler knows it must unregister policy*/
164 /* Announce we are up! */
165 chardriver_announce();
170 /*===========================================================================*
171 * sef_cb_signal_handler *
172 *===========================================================================*/
173 static void sef_cb_signal_handler(int signo
)
178 /* Only check for termination signal, ignore anything else. */
179 if (signo
!= SIGTERM
) return;
181 for (i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
182 drv_stop(i
); /* stop all sub devices */
185 if (sys_irqdisable(&irq_hook_id
) != OK
) {
186 printf("Could not disable IRQ\n");
188 /* get irq from device driver*/
189 if (drv_get_irq(&irq
) != OK
) {
190 printf("Msg SIG_STOP Couldn't get IRQ");
192 /* remove the policy */
193 if (sys_irqrmpolicy(&irq_hook_id
) != OK
) {
194 printf("%s: Could not disable IRQ\n",drv
.DriverName
);
199 static int msg_open(devminor_t minor_dev_nr
, int UNUSED(access
),
200 endpoint_t
UNUSED(user_endpt
))
202 int r
, read_chan
, write_chan
, io_ctl
;
203 special_file_t
* special_file_ptr
;
205 special_file_ptr
= get_special_file(minor_dev_nr
);
206 if(special_file_ptr
== NULL
) {
210 read_chan
= special_file_ptr
->read_chan
;
211 write_chan
= special_file_ptr
->write_chan
;
212 io_ctl
= special_file_ptr
->io_ctl
;
214 if (read_chan
==NO_CHANNEL
&& write_chan
==NO_CHANNEL
&& io_ctl
==NO_CHANNEL
) {
215 printf("%s: No channel specified for minor device %d!\n",
216 drv
.DriverName
, minor_dev_nr
);
219 if (read_chan
== write_chan
&& read_chan
!= NO_CHANNEL
) {
220 printf("%s: Read and write channels are equal: %d!\n",
221 drv
.DriverName
, minor_dev_nr
);
224 /* open the sub devices specified in the interface header file */
225 if (write_chan
!= NO_CHANNEL
) {
226 /* open sub device for writing */
227 if (open_sub_dev(write_chan
, WRITE_DMA
) != OK
) return EIO
;
229 if (read_chan
!= NO_CHANNEL
) {
230 if (open_sub_dev(read_chan
, READ_DMA
) != OK
) return EIO
;
232 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
233 /* io_ctl is already opened because it's the same as read or write */
234 return OK
; /* we're done */
236 if (io_ctl
!= NO_CHANNEL
) { /* Ioctl differs from read/write channels, */
237 r
= open_sub_dev(io_ctl
, NO_DMA
); /* open it explicitly */
238 if (r
!= OK
) return EIO
;
244 static int open_sub_dev(int sub_dev_nr
, int dma_mode
) {
245 sub_dev_t
* sub_dev_ptr
;
246 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
248 /* Only one open at a time per sub device */
249 if (sub_dev_ptr
->Opened
) {
250 printf("%s: Sub device %d is already opened\n",
251 drv
.DriverName
, sub_dev_nr
);
254 if (sub_dev_ptr
->DmaBusy
) {
255 printf("%s: Sub device %d is still busy\n", drv
.DriverName
, sub_dev_nr
);
258 /* Setup variables */
259 sub_dev_ptr
->Opened
= TRUE
;
260 sub_dev_ptr
->DmaReadNext
= 0;
261 sub_dev_ptr
->DmaFillNext
= 0;
262 sub_dev_ptr
->DmaLength
= 0;
263 sub_dev_ptr
->DmaMode
= dma_mode
;
264 sub_dev_ptr
->BufReadNext
= 0;
265 sub_dev_ptr
->BufFillNext
= 0;
266 sub_dev_ptr
->BufLength
= 0;
267 sub_dev_ptr
->RevivePending
= FALSE
;
268 sub_dev_ptr
->OutOfData
= TRUE
;
271 if (dma_mode
!= NO_DMA
) { /* sub device uses DMA */
272 /* allocate dma buffer and extra buffer space
273 and configure sub device for dma */
274 if (init_buffers(sub_dev_ptr
) != OK
) return EIO
;
280 static int msg_close(devminor_t minor_dev_nr
)
283 int r
, read_chan
, write_chan
, io_ctl
;
284 special_file_t
* special_file_ptr
;
286 special_file_ptr
= get_special_file(minor_dev_nr
);
287 if(special_file_ptr
== NULL
) {
291 read_chan
= special_file_ptr
->read_chan
;
292 write_chan
= special_file_ptr
->write_chan
;
293 io_ctl
= special_file_ptr
->io_ctl
;
297 /* close all sub devices */
298 if (write_chan
!= NO_CHANNEL
) {
299 if (close_sub_dev(write_chan
) != OK
) r
= EIO
;
301 if (read_chan
!= NO_CHANNEL
) {
302 if (close_sub_dev(read_chan
) != OK
) r
= EIO
;
304 if (read_chan
== io_ctl
|| write_chan
== io_ctl
) {
305 /* io_ctl is already closed because it's the same as read or write */
306 return r
; /* we're done */
308 /* ioctl differs from read/write channels... */
309 if (io_ctl
!= NO_CHANNEL
) {
310 if (close_sub_dev(io_ctl
) != OK
) r
= EIO
; /* ...close it explicitly */
316 static int close_sub_dev(int sub_dev_nr
) {
318 sub_dev_t
*sub_dev_ptr
;
319 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
320 if (sub_dev_ptr
->DmaMode
== WRITE_DMA
&& !sub_dev_ptr
->OutOfData
) {
321 /* do nothing, still data in buffers that has to be transferred */
322 sub_dev_ptr
->Opened
= FALSE
; /* keep DMA busy */
325 if (sub_dev_ptr
->DmaMode
== NO_DMA
) {
326 /* do nothing, there is no dma going on */
327 sub_dev_ptr
->Opened
= FALSE
;
330 sub_dev_ptr
->Opened
= FALSE
;
331 sub_dev_ptr
->DmaBusy
= FALSE
;
332 /* stop the device */
333 drv_stop(sub_dev_ptr
->Nr
);
334 /* free the buffers */
335 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
336 free_contig(sub_dev_ptr
->DmaBuf
, size
);
337 free(sub_dev_ptr
->ExtraBuf
);
342 static int msg_ioctl(devminor_t minor
, unsigned long request
, endpoint_t endpt
,
343 cp_grant_id_t grant
, int flags
, endpoint_t user_endpt
, cdev_id_t id
)
345 int status
, len
, chan
;
346 sub_dev_t
*sub_dev_ptr
;
347 special_file_t
* special_file_ptr
;
349 special_file_ptr
= get_special_file(minor
);
350 if(special_file_ptr
== NULL
) {
354 chan
= special_file_ptr
->io_ctl
;
356 if (chan
== NO_CHANNEL
) {
357 printf("%s: No io control channel specified!\n", drv
.DriverName
);
360 /* get pointer to sub device data */
361 sub_dev_ptr
= &sub_dev
[chan
];
363 if(!sub_dev_ptr
->Opened
) {
364 printf("%s: io control impossible - not opened!\n", drv
.DriverName
);
368 if (request
& IOC_IN
) { /* if there is data for us, copy it */
369 len
= io_ctl_length(request
);
371 if (sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
)io_ctl_buf
,
373 printf("%s:%d: safecopyfrom failed\n", __FILE__
, __LINE__
);
377 /* all ioctl's are passed to the device specific part of the driver */
378 status
= drv_io_ctl(request
, (void *)io_ctl_buf
, &len
, chan
);
380 /* IOC_OUT bit -> user expects data */
381 if (status
== OK
&& request
& IOC_OUT
) {
382 /* copy result back to user */
384 if (sys_safecopyto(endpt
, grant
, 0, (vir_bytes
)io_ctl_buf
,
386 printf("%s:%d: safecopyto failed\n", __FILE__
, __LINE__
);
394 static ssize_t
msg_write(devminor_t minor
, u64_t
UNUSED(position
),
395 endpoint_t endpt
, cp_grant_id_t grant
, size_t size
, int UNUSED(flags
),
398 int chan
; sub_dev_t
*sub_dev_ptr
;
399 special_file_t
* special_file_ptr
;
401 special_file_ptr
= get_special_file(minor
);
402 chan
= special_file_ptr
->write_chan
;
404 if (chan
== NO_CHANNEL
) {
405 printf("%s: No write channel specified!\n", drv
.DriverName
);
408 /* get pointer to sub device data */
409 sub_dev_ptr
= &sub_dev
[chan
];
411 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first write */
412 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
413 printf("%s; Failed to get fragment size!\n", drv
.DriverName
);
417 if(size
!= sub_dev_ptr
->FragSize
) {
418 printf("Fragment size does not match user's buffer length\n");
421 /* if we are busy with something else than writing, return EBUSY */
422 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= WRITE_DMA
) {
423 printf("Already busy with something else than writing\n");
427 sub_dev_ptr
->RevivePending
= TRUE
;
428 sub_dev_ptr
->ReviveId
= id
;
429 sub_dev_ptr
->ReviveGrant
= grant
;
430 sub_dev_ptr
->SourceProcNr
= endpt
;
432 data_from_user(sub_dev_ptr
);
434 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
435 get_started(sub_dev_ptr
);
436 sub_dev_ptr
->DmaMode
= WRITE_DMA
; /* Dma mode is writing */
439 /* We may already have replied by now. In any case don't reply here. */
444 static ssize_t
msg_read(devminor_t minor
, u64_t
UNUSED(position
),
445 endpoint_t endpt
, cp_grant_id_t grant
, size_t size
, int UNUSED(flags
),
448 int chan
; sub_dev_t
*sub_dev_ptr
;
449 special_file_t
* special_file_ptr
;
451 special_file_ptr
= get_special_file(minor
);
452 chan
= special_file_ptr
->read_chan
;
454 if (chan
== NO_CHANNEL
) {
455 printf("%s: No read channel specified!\n", drv
.DriverName
);
458 /* get pointer to sub device data */
459 sub_dev_ptr
= &sub_dev
[chan
];
461 if (!sub_dev_ptr
->DmaBusy
) { /* get fragment size on first read */
462 if (drv_get_frag_size(&(sub_dev_ptr
->FragSize
), sub_dev_ptr
->Nr
) != OK
){
463 printf("%s: Could not retrieve fragment size!\n", drv
.DriverName
);
467 if(size
!= sub_dev_ptr
->FragSize
) {
468 printf("fragment size does not match message size\n");
471 /* if we are busy with something else than reading, reply EBUSY */
472 if(sub_dev_ptr
->DmaBusy
&& sub_dev_ptr
->DmaMode
!= READ_DMA
) {
476 sub_dev_ptr
->RevivePending
= TRUE
;
477 sub_dev_ptr
->ReviveId
= id
;
478 sub_dev_ptr
->ReviveGrant
= grant
;
479 sub_dev_ptr
->SourceProcNr
= endpt
;
481 if(!sub_dev_ptr
->DmaBusy
) { /* Dma tranfer not yet started */
482 get_started(sub_dev_ptr
);
483 sub_dev_ptr
->DmaMode
= READ_DMA
; /* Dma mode is reading */
484 /* no need to get data from DMA buffer at this point */
487 /* check if data is available and possibly fill user's buffer */
488 data_to_user(sub_dev_ptr
);
490 /* We may already have replied by now. In any case don't reply here. */
495 static void msg_hardware(unsigned int UNUSED(mask
))
499 /* if we have an interrupt */
501 /* loop over all sub devices */
502 for ( i
= 0; i
< drv
.NrOfSubDevices
; i
++) {
503 /* if interrupt from sub device and Dma transfer
504 was actually busy, take care of business */
505 if( drv_int(i
) && sub_dev
[i
].DmaBusy
) {
506 if (sub_dev
[i
].DmaMode
== WRITE_DMA
)
508 if (sub_dev
[i
].DmaMode
== READ_DMA
)
514 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must
515 * re-enable out interrupt after every interrupt.
517 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
518 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv
.DriverName
);
523 /* handle interrupt for specified sub device; DmaMode == WRITE_DMA */
524 static void handle_int_write(int sub_dev_nr
)
526 sub_dev_t
*sub_dev_ptr
;
528 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
530 sub_dev_ptr
->DmaReadNext
=
531 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
532 sub_dev_ptr
->DmaLength
-= 1;
534 if (sub_dev_ptr
->BufLength
!= 0) { /* Data in extra buf, copy to Dma buf */
536 memcpy(sub_dev_ptr
->DmaPtr
+
537 sub_dev_ptr
->DmaFillNext
* sub_dev_ptr
->FragSize
,
538 sub_dev_ptr
->ExtraBuf
+
539 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
540 sub_dev_ptr
->FragSize
);
542 sub_dev_ptr
->BufReadNext
=
543 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
544 sub_dev_ptr
->DmaFillNext
=
545 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
547 sub_dev_ptr
->BufLength
-= 1;
548 sub_dev_ptr
->DmaLength
+= 1;
551 /* space became available, possibly copy new data from user */
552 data_from_user(sub_dev_ptr
);
554 if(sub_dev_ptr
->DmaLength
== 0) { /* Dma buffer empty, stop Dma transfer */
556 sub_dev_ptr
->OutOfData
= TRUE
; /* we're out of data */
557 if (!sub_dev_ptr
->Opened
) {
558 close_sub_dev(sub_dev_ptr
->Nr
);
561 drv_pause(sub_dev_ptr
->Nr
);
565 /* confirm and reenable interrupt from this sub dev */
566 drv_reenable_int(sub_dev_nr
);
568 /* reenable irq_hook*/
569 if (sys_irqenable(&irq_hook_id
!= OK
) {
570 printf("%s Couldn't enable IRQ\n", drv
.DriverName
);
576 /* handle interrupt for specified sub device; DmaMode == READ_DMA */
577 static void handle_int_read(int sub_dev_nr
)
579 sub_dev_t
*sub_dev_ptr
;
581 sub_dev_ptr
= &sub_dev
[sub_dev_nr
];
583 sub_dev_ptr
->DmaLength
+= 1;
584 sub_dev_ptr
->DmaFillNext
=
585 (sub_dev_ptr
->DmaFillNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
587 /* possibly copy data to user (if it is waiting for us) */
588 data_to_user(sub_dev_ptr
);
590 if (sub_dev_ptr
->DmaLength
== sub_dev_ptr
->NrOfDmaFragments
) {
591 /* if dma buffer full */
593 if (sub_dev_ptr
->BufLength
== sub_dev_ptr
->NrOfExtraBuffers
) {
594 printf("All buffers full, we have a problem.\n");
595 drv_stop(sub_dev_nr
); /* stop the sub device */
596 sub_dev_ptr
->DmaBusy
= FALSE
;
597 /* no data for user, this is a sad story */
598 chardriver_reply_task(sub_dev_ptr
->SourceProcNr
,
599 sub_dev_ptr
->ReviveId
, 0);
602 else { /* dma full, still room in extra buf;
603 copy from dma to extra buf */
604 memcpy(sub_dev_ptr
->ExtraBuf
+
605 sub_dev_ptr
->BufFillNext
* sub_dev_ptr
->FragSize
,
606 sub_dev_ptr
->DmaPtr
+
607 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
608 sub_dev_ptr
->FragSize
);
609 sub_dev_ptr
->DmaLength
-= 1;
610 sub_dev_ptr
->DmaReadNext
=
611 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
612 sub_dev_ptr
->BufLength
+= 1;
613 sub_dev_ptr
->BufFillNext
=
614 (sub_dev_ptr
->BufFillNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
617 /* confirm interrupt, and reenable interrupt from this sub dev*/
618 drv_reenable_int(sub_dev_ptr
->Nr
);
621 /* reenable irq_hook*/
622 if (sys_irqenable(&irq_hook_id
) != OK
) {
623 printf("%s: Couldn't reenable IRQ", drv
.DriverName
);
629 static int get_started(sub_dev_t
*sub_dev_ptr
) {
632 /* enable interrupt messages from MINIX */
633 if ((i
=sys_irqenable(&irq_hook_id
)) != OK
) {
634 printf("%s: Couldn't enable IRQs: error code %u",drv
.DriverName
, (unsigned int) i
);
637 /* let the lower part of the driver start the device */
638 if (drv_start(sub_dev_ptr
->Nr
, sub_dev_ptr
->DmaMode
) != OK
) {
639 printf("%s: Could not start device %d\n",
640 drv
.DriverName
, sub_dev_ptr
->Nr
);
643 sub_dev_ptr
->DmaBusy
= TRUE
; /* Dma is busy from now on */
644 sub_dev_ptr
->DmaReadNext
= 0;
649 static void data_from_user(sub_dev_t
*subdev
)
653 if (subdev
->DmaLength
== subdev
->NrOfDmaFragments
&&
654 subdev
->BufLength
== subdev
->NrOfExtraBuffers
) return;/* no space */
656 if (!subdev
->RevivePending
) return; /* no new data waiting to be copied */
658 if (subdev
->DmaLength
< subdev
->NrOfDmaFragments
) { /* room in dma buf */
660 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
661 (vir_bytes
)subdev
->ReviveGrant
, 0,
662 (vir_bytes
)subdev
->DmaPtr
+
663 subdev
->DmaFillNext
* subdev
->FragSize
,
664 (phys_bytes
)subdev
->FragSize
);
666 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
669 subdev
->DmaLength
+= 1;
670 subdev
->DmaFillNext
=
671 (subdev
->DmaFillNext
+ 1) % subdev
->NrOfDmaFragments
;
673 } else { /* room in extra buf */
675 r
= sys_safecopyfrom(subdev
->SourceProcNr
,
676 (vir_bytes
)subdev
->ReviveGrant
, 0,
677 (vir_bytes
)subdev
->ExtraBuf
+
678 subdev
->BufFillNext
* subdev
->FragSize
,
679 (phys_bytes
)subdev
->FragSize
);
681 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
683 subdev
->BufLength
+= 1;
685 subdev
->BufFillNext
=
686 (subdev
->BufFillNext
+ 1) % subdev
->NrOfExtraBuffers
;
689 if(subdev
->OutOfData
) { /* if device paused (because of lack of data) */
690 subdev
->OutOfData
= FALSE
;
691 drv_reenable_int(subdev
->Nr
);
692 /* reenable irq_hook*/
693 if ((sys_irqenable(&irq_hook_id
)) != OK
) {
694 printf("%s: Couldn't enable IRQ", drv
.DriverName
);
696 drv_resume(subdev
->Nr
); /* resume resume the sub device */
699 chardriver_reply_task(subdev
->SourceProcNr
, subdev
->ReviveId
,
702 /* reset variables */
703 subdev
->RevivePending
= 0;
707 static void data_to_user(sub_dev_t
*sub_dev_ptr
)
711 if (!sub_dev_ptr
->RevivePending
) return; /* nobody is wating for data */
712 if (sub_dev_ptr
->BufLength
== 0 && sub_dev_ptr
->DmaLength
== 0) return;
713 /* no data for user */
715 if(sub_dev_ptr
->BufLength
!= 0) { /* data in extra buffer available */
717 r
= sys_safecopyto(sub_dev_ptr
->SourceProcNr
,
718 (vir_bytes
)sub_dev_ptr
->ReviveGrant
,
719 0, (vir_bytes
)sub_dev_ptr
->ExtraBuf
+
720 sub_dev_ptr
->BufReadNext
* sub_dev_ptr
->FragSize
,
721 (phys_bytes
)sub_dev_ptr
->FragSize
);
723 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
725 /* adjust the buffer status variables */
726 sub_dev_ptr
->BufReadNext
=
727 (sub_dev_ptr
->BufReadNext
+ 1) % sub_dev_ptr
->NrOfExtraBuffers
;
728 sub_dev_ptr
->BufLength
-= 1;
730 } else { /* extra buf empty, but data in dma buf*/
732 sub_dev_ptr
->SourceProcNr
,
733 (vir_bytes
)sub_dev_ptr
->ReviveGrant
, 0,
734 (vir_bytes
)sub_dev_ptr
->DmaPtr
+
735 sub_dev_ptr
->DmaReadNext
* sub_dev_ptr
->FragSize
,
736 (phys_bytes
)sub_dev_ptr
->FragSize
);
738 printf("%s:%d: safecopy failed\n", __FILE__
, __LINE__
);
740 /* adjust the buffer status variables */
741 sub_dev_ptr
->DmaReadNext
=
742 (sub_dev_ptr
->DmaReadNext
+ 1) % sub_dev_ptr
->NrOfDmaFragments
;
743 sub_dev_ptr
->DmaLength
-= 1;
746 chardriver_reply_task(sub_dev_ptr
->SourceProcNr
, sub_dev_ptr
->ReviveId
,
747 sub_dev_ptr
->FragSize
);
749 /* reset variables */
750 sub_dev_ptr
->RevivePending
= 0;
753 static int init_buffers(sub_dev_t
*sub_dev_ptr
)
755 #if defined(__i386__)
762 /* allocate dma buffer space */
763 size
= sub_dev_ptr
->DmaSize
+ 64 * 1024;
764 base
= alloc_contig(size
, AC_ALIGN64K
|AC_LOWER16M
, &ph
);
766 printf("%s: failed to allocate dma buffer for a channel\n",
770 sub_dev_ptr
->DmaBuf
= base
;
772 tell_dev((vir_bytes
)base
, size
, 0, 0, 0);
774 /* allocate extra buffer space */
775 if (!(sub_dev_ptr
->ExtraBuf
= malloc(sub_dev_ptr
->NrOfExtraBuffers
*
776 sub_dev_ptr
->DmaSize
/
777 sub_dev_ptr
->NrOfDmaFragments
))) {
778 printf("%s failed to allocate extra buffer for a channel\n",
783 sub_dev_ptr
->DmaPtr
= sub_dev_ptr
->DmaBuf
;
784 i
= sys_umap(SELF
, VM_D
, (vir_bytes
) base
, (phys_bytes
) size
,
785 &(sub_dev_ptr
->DmaPhys
));
791 if ((left
= dma_bytes_left(sub_dev_ptr
->DmaPhys
)) <
792 (unsigned int)sub_dev_ptr
->DmaSize
) {
793 /* First half of buffer crosses a 64K boundary,
794 * can't DMA into that */
795 sub_dev_ptr
->DmaPtr
+= left
;
796 sub_dev_ptr
->DmaPhys
+= left
;
798 /* write the physical dma address and size to the device */
799 drv_set_dma(sub_dev_ptr
->DmaPhys
,
800 sub_dev_ptr
->DmaSize
, sub_dev_ptr
->Nr
);
803 #else /* !defined(__i386__) */
804 printf("%s: init_buffers() failed, CHIP != INTEL", drv
.DriverName
);
806 #endif /* defined(__i386__) */
810 static int io_ctl_length(int io_request
) {
812 return io_request
& IOCPARM_MASK
;
816 static special_file_t
* get_special_file(int minor_dev_nr
) {
819 for(i
= 0; i
< drv
.NrOfSpecialFiles
; i
++) {
820 if(special_file
[i
].minor_dev_nr
== minor_dev_nr
) {
821 return &special_file
[i
];
825 printf("%s: No subdevice specified for minor device %d!\n",
826 drv
.DriverName
, minor_dev_nr
);
831 #if defined(__i386__)
832 static void tell_dev(vir_bytes buf
, size_t size
, int pci_bus
,
833 int pci_dev
, int pci_func
)
839 r
= ds_retrieve_label_endpt("amddev", &dev_e
);
843 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
856 r
= ipc_sendrec(dev_e
, &m
);
859 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e
, r
);
864 printf("tell_dev: dma map request failed: %d\n", m
.m_type
);