tools/llvm: Do not build with symbols
[minix3.git] / minix / lib / libaudiodriver / audio_fw.c
blobab45e5bb07c13b003e2bd757422d553507144bb8
1 /* Best viewed with tabsize 4
3 * This file contains a standard driver for audio devices.
4 * It supports double dma buffering and can be configured to use
5 * extra buffer space beside the dma buffer.
6 * This driver also support sub devices, which can be independently
7 * opened and closed.
8 *
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>
26 #include <minix/ds.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 */
68 .cdr_read = msg_read,
69 .cdr_write = msg_write,
70 .cdr_ioctl = msg_ioctl,
71 .cdr_intr = msg_hardware
74 int main(void)
76 int r, caller;
77 message mess, repl_mess;
78 int ipc_status;
80 /* SEF local startup. */
81 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);
87 return 0;
90 /*===========================================================================*
91 * sef_local_startup *
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. */
109 sef_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. */
118 u32_t i; char irq;
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");
125 return EIO;
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;
143 sub_dev_ptr->Nr = i;
146 /* initialize hardware*/
147 if (drv_init_hw() != OK) {
148 printf("%s: Could not initialize hardware\n", drv.DriverName);
149 return EIO;
152 /* get irq from device driver...*/
153 if (drv_get_irq(&irq) != OK) {
154 printf("%s: init driver couldn't get IRQ", drv.DriverName);
155 return EIO;
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;
160 executed = TRUE;
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);
165 return EIO;
167 irq_hook_set = TRUE; /* now signal handler knows it must unregister policy*/
169 /* Announce we are up! */
170 chardriver_announce();
172 return OK;
175 /*===========================================================================*
176 * sef_cb_signal_handler *
177 *===========================================================================*/
178 static void sef_cb_signal_handler(int signo)
180 int i;
181 char irq;
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 */
189 if (irq_hook_set) {
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) {
212 return EIO;
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);
222 return EIO;
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);
227 return EIO;
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;
245 return OK;
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);
257 return EBUSY;
259 if (sub_dev_ptr->DmaBusy) {
260 printf("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr);
261 return EBUSY;
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;
275 /* arrange DMA */
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;
281 return OK;
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) {
293 return EIO;
296 read_chan = special_file_ptr->read_chan;
297 write_chan = special_file_ptr->write_chan;
298 io_ctl = special_file_ptr->io_ctl;
300 r= OK;
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 */
317 return r;
321 static int close_sub_dev(int sub_dev_nr) {
322 size_t size;
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 */
328 return OK;
330 if (sub_dev_ptr->DmaMode == NO_DMA) {
331 /* do nothing, there is no dma going on */
332 sub_dev_ptr->Opened = FALSE;
333 return OK;
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);
343 return OK;
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) {
356 return EIO;
359 chan = special_file_ptr->io_ctl;
361 if (chan == NO_CHANNEL) {
362 printf("%s: No io control channel specified!\n", drv.DriverName);
363 return EIO;
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);
370 return EIO;
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,
377 len) != OK) {
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,
390 len) != OK) {
391 printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);
395 return status;
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),
401 cdev_id_t id)
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);
411 return EIO;
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);
419 return EIO;
422 if(size != sub_dev_ptr->FragSize) {
423 printf("Fragment size does not match user's buffer length\n");
424 return EINVAL;
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");
429 return EBUSY;
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. */
445 return EDONTREPLY;
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),
451 cdev_id_t id)
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);
461 return EIO;
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);
469 return EIO;
472 if(size != sub_dev_ptr->FragSize) {
473 printf("fragment size does not match message size\n");
474 return EINVAL;
476 /* if we are busy with something else than reading, reply EBUSY */
477 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != READ_DMA) {
478 return EBUSY;
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 */
490 return EDONTREPLY;
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. */
496 return EDONTREPLY;
500 static void msg_hardware(unsigned int UNUSED(mask))
502 u32_t i;
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)
510 handle_int_write(i);
511 if (sub_dev[i].DmaMode == READ_DMA)
512 handle_int_read(i);
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);
561 return;
563 drv_pause(sub_dev_ptr->Nr);
564 return;
567 /* confirm and reenable interrupt from this sub dev */
568 drv_reenable_int(sub_dev_nr);
569 #if 0
570 /* reenable irq_hook*/
571 if (sys_irqenable(&irq_hook_id != OK) {
572 printf("%s Couldn't enable IRQ\n", drv.DriverName);
574 #endif
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;
582 message m;
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);
603 return;
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);
622 #if 0
623 /* reenable irq_hook*/
624 if (sys_irqenable(&irq_hook_id) != OK) {
625 printf("%s: Couldn't reenable IRQ", drv.DriverName);
627 #endif
631 static int get_started(sub_dev_t *sub_dev_ptr) {
632 u32_t i;
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);
637 return EIO;
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;
647 return OK;
651 static void data_from_user(sub_dev_t *subdev)
653 int r;
654 message m;
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);
668 if (r != OK)
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);
683 if (r != OK)
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,
703 subdev->FragSize);
705 /* reset variables */
706 subdev->RevivePending = 0;
710 static void data_to_user(sub_dev_t *sub_dev_ptr)
712 int r;
713 message m;
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);
726 if (r != OK)
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*/
735 r = sys_safecopyto(
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);
741 if (r != OK)
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__)
760 char *base;
761 size_t size;
762 unsigned left;
763 u32_t i;
764 phys_bytes ph;
766 /* allocate dma buffer space */
767 size= sub_dev_ptr->DmaSize + 64 * 1024;
768 base= alloc_contig(size, AC_ALIGN64K|AC_LOWER16M, &ph);
769 if (!base) {
770 printf("%s: failed to allocate dma buffer for a channel\n",
771 drv.DriverName);
772 return EIO;
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",
783 drv.DriverName);
784 return EIO;
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));
791 if (i != OK) {
792 return EIO;
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);
805 return OK;
807 #else /* !defined(__i386__) */
808 printf("%s: init_buffers() failed, CHIP != INTEL", drv.DriverName);
809 return EIO;
810 #endif /* defined(__i386__) */
814 static int io_ctl_length(int io_request) {
815 io_request >>= 16;
816 return io_request & IOCPARM_MASK;
820 static special_file_t* get_special_file(int minor_dev_nr) {
821 int i;
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);
832 return NULL;
835 static void tell_dev(vir_bytes buf, size_t size, int pci_bus,
836 int pci_dev, int pci_func)
838 int r;
839 endpoint_t dev_e;
840 message m;
842 r= ds_retrieve_label_endpt("amddev", &dev_e);
843 if (r != OK)
845 #if 0
846 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
848 #endif
849 return;
852 m.m_type= IOMMU_MAP;
853 m.m2_i1= pci_bus;
854 m.m2_i2= pci_dev;
855 m.m2_i3= pci_func;
856 m.m2_l1= buf;
857 m.m2_l2= size;
859 r= ipc_sendrec(dev_e, &m);
860 if (r != OK)
862 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e, r);
863 return;
865 if (m.m_type != OK)
867 printf("tell_dev: dma map request failed: %d\n", m.m_type);
868 return;