Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / lib / libaudiodriver / audio_fw.c
blob56a91c99c59be5473bfbd51737374b1b4996e3b3
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 #if defined(__i386__)
51 static void tell_dev(vir_bytes buf, size_t size, int pci_bus,
52 int pci_dev, int pci_func);
53 #endif
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 */
67 .cdr_read = msg_read,
68 .cdr_write = msg_write,
69 .cdr_ioctl = msg_ioctl,
70 .cdr_intr = msg_hardware
73 int main(void)
76 /* SEF local startup. */
77 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);
83 return 0;
86 /*===========================================================================*
87 * sef_local_startup *
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. */
104 sef_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. */
113 int i; char irq;
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");
120 return EIO;
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;
138 sub_dev_ptr->Nr = i;
141 /* initialize hardware*/
142 if (drv_init_hw() != OK) {
143 printf("%s: Could not initialize hardware\n", drv.DriverName);
144 return EIO;
147 /* get irq from device driver...*/
148 if (drv_get_irq(&irq) != OK) {
149 printf("%s: init driver couldn't get IRQ", drv.DriverName);
150 return EIO;
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;
155 executed = TRUE;
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);
160 return EIO;
162 irq_hook_set = TRUE; /* now signal handler knows it must unregister policy*/
164 /* Announce we are up! */
165 chardriver_announce();
167 return OK;
170 /*===========================================================================*
171 * sef_cb_signal_handler *
172 *===========================================================================*/
173 static void sef_cb_signal_handler(int signo)
175 int i;
176 char irq;
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 */
184 if (irq_hook_set) {
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) {
207 return EIO;
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);
217 return EIO;
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);
222 return EIO;
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;
240 return OK;
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);
252 return EBUSY;
254 if (sub_dev_ptr->DmaBusy) {
255 printf("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr);
256 return EBUSY;
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;
270 /* arrange DMA */
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;
276 return OK;
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) {
288 return EIO;
291 read_chan = special_file_ptr->read_chan;
292 write_chan = special_file_ptr->write_chan;
293 io_ctl = special_file_ptr->io_ctl;
295 r= OK;
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 */
312 return r;
316 static int close_sub_dev(int sub_dev_nr) {
317 size_t size;
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 */
323 return OK;
325 if (sub_dev_ptr->DmaMode == NO_DMA) {
326 /* do nothing, there is no dma going on */
327 sub_dev_ptr->Opened = FALSE;
328 return OK;
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);
338 return OK;
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) {
351 return EIO;
354 chan = special_file_ptr->io_ctl;
356 if (chan == NO_CHANNEL) {
357 printf("%s: No io control channel specified!\n", drv.DriverName);
358 return EIO;
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);
365 return EIO;
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,
372 len) != OK) {
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,
385 len) != OK) {
386 printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);
390 return status;
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),
396 cdev_id_t id)
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);
406 return EIO;
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);
414 return EIO;
417 if(size != sub_dev_ptr->FragSize) {
418 printf("Fragment size does not match user's buffer length\n");
419 return EINVAL;
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");
424 return EBUSY;
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. */
440 return EDONTREPLY;
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),
446 cdev_id_t id)
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);
456 return EIO;
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);
464 return EIO;
467 if(size != sub_dev_ptr->FragSize) {
468 printf("fragment size does not match message size\n");
469 return EINVAL;
471 /* if we are busy with something else than reading, reply EBUSY */
472 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != READ_DMA) {
473 return EBUSY;
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 */
485 return EDONTREPLY;
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. */
491 return EDONTREPLY;
495 static void msg_hardware(unsigned int UNUSED(mask))
497 int i;
499 /* if we have an interrupt */
500 if (drv_int_sum()) {
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)
507 handle_int_write(i);
508 if (sub_dev[i].DmaMode == READ_DMA)
509 handle_int_read(i);
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);
559 return;
561 drv_pause(sub_dev_ptr->Nr);
562 return;
565 /* confirm and reenable interrupt from this sub dev */
566 drv_reenable_int(sub_dev_nr);
567 #if 0
568 /* reenable irq_hook*/
569 if (sys_irqenable(&irq_hook_id != OK) {
570 printf("%s Couldn't enable IRQ\n", drv.DriverName);
572 #endif
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);
600 return;
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);
620 #if 0
621 /* reenable irq_hook*/
622 if (sys_irqenable(&irq_hook_id) != OK) {
623 printf("%s: Couldn't reenable IRQ", drv.DriverName);
625 #endif
629 static int get_started(sub_dev_t *sub_dev_ptr) {
630 u32_t i;
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);
635 return EIO;
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;
645 return OK;
649 static void data_from_user(sub_dev_t *subdev)
651 int r;
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);
665 if (r != OK)
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);
680 if (r != OK)
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,
700 subdev->FragSize);
702 /* reset variables */
703 subdev->RevivePending = 0;
707 static void data_to_user(sub_dev_t *sub_dev_ptr)
709 int r;
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);
722 if (r != OK)
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*/
731 r = sys_safecopyto(
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);
737 if (r != OK)
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__)
756 char *base;
757 size_t size;
758 unsigned left;
759 u32_t i;
760 phys_bytes ph;
762 /* allocate dma buffer space */
763 size= sub_dev_ptr->DmaSize + 64 * 1024;
764 base= alloc_contig(size, AC_ALIGN64K|AC_LOWER16M, &ph);
765 if (!base) {
766 printf("%s: failed to allocate dma buffer for a channel\n",
767 drv.DriverName);
768 return EIO;
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",
779 drv.DriverName);
780 return EIO;
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));
787 if (i != OK) {
788 return EIO;
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);
801 return OK;
803 #else /* !defined(__i386__) */
804 printf("%s: init_buffers() failed, CHIP != INTEL", drv.DriverName);
805 return EIO;
806 #endif /* defined(__i386__) */
810 static int io_ctl_length(int io_request) {
811 io_request >>= 16;
812 return io_request & IOCPARM_MASK;
816 static special_file_t* get_special_file(int minor_dev_nr) {
817 int i;
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);
828 return NULL;
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)
835 int r;
836 endpoint_t dev_e;
837 message m;
839 r= ds_retrieve_label_endpt("amddev", &dev_e);
840 if (r != OK)
842 #if 0
843 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n",
845 #endif
846 return;
849 m.m_type= IOMMU_MAP;
850 m.m2_i1= pci_bus;
851 m.m2_i2= pci_dev;
852 m.m2_i3= pci_func;
853 m.m2_l1= buf;
854 m.m2_l2= size;
856 r= ipc_sendrec(dev_e, &m);
857 if (r != OK)
859 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e, r);
860 return;
862 if (m.m_type != OK)
864 printf("tell_dev: dma map request failed: %d\n", m.m_type);
865 return;
868 #endif