1 /* Best viewed with tabsize 4 2 * 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: 10 * 11 * main: main entry when driver is brought up 12 * 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 21 */ 22 23 24 #include <minix/audio_fw.h> 25 #include <minix/endpoint.h> 26 #include <minix/ds.h> 27 #include <sys/ioccom.h> 28 29 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 54 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; 58 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); 63 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 71 }; 72 73 int main(void) 74 { 75 76 /* SEF local startup. */ 77 sef_local_startup(); 78 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); 82 83 return 0; 84 } 85 86 /*===========================================================================* 87 * sef_local_startup * 88 *===========================================================================*/ 89 static void sef_local_startup(void) 90 { 91 /* Register init callbacks. */ 92 sef_setcb_init_fresh(sef_cb_init_fresh); 93 sef_setcb_init_restart(sef_cb_init_fresh); 94 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); 99 100 /* Register signal callbacks. */ 101 sef_setcb_signal_handler(sef_cb_signal_handler); 102 103 /* Let SEF perform startup. */ 104 sef_startup(); 105 } 106 107 /*===========================================================================* 108 * sef_cb_init_fresh * 109 *===========================================================================*/ 110 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 111 { 112 /* Initialize the audio driver framework. */ 113 int i; char irq; 114 static int executed = 0; 115 sub_dev_t* sub_dev_ptr; 116 117 /* initialize basic driver variables */ 118 if (drv_init() != OK) { 119 printf("libaudiodriver: Could not initialize driver\n"); 120 return EIO; 121 } 122 123 /* init variables, get dma buffers */ 124 for (i = 0; i < drv.NrOfSubDevices; i++) { 125 126 sub_dev_ptr = &sub_dev[i]; 127 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; 139 } 140 141 /* initialize hardware*/ 142 if (drv_init_hw() != OK) { 143 printf("%s: Could not initialize hardware\n", drv.DriverName); 144 return EIO; 145 } 146 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; 151 } 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; 156 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; 161 } 162 irq_hook_set = TRUE; /* now signal handler knows it must unregister policy*/ 163 164 /* Announce we are up! */ 165 chardriver_announce(); 166 167 return OK; 168 } 169 170 /*===========================================================================* 171 * sef_cb_signal_handler * 172 *===========================================================================*/ 173 static void sef_cb_signal_handler(int signo) 174 { 175 int i; 176 char irq; 177 178 /* Only check for termination signal, ignore anything else. */ 179 if (signo != SIGTERM) return; 180 181 for (i = 0; i < drv.NrOfSubDevices; i++) { 182 drv_stop(i); /* stop all sub devices */ 183 } 184 if (irq_hook_set) { 185 if (sys_irqdisable(&irq_hook_id) != OK) { 186 printf("Could not disable IRQ\n"); 187 } 188 /* get irq from device driver*/ 189 if (drv_get_irq(&irq) != OK) { 190 printf("Msg SIG_STOP Couldn't get IRQ"); 191 } 192 /* remove the policy */ 193 if (sys_irqrmpolicy(&irq_hook_id) != OK) { 194 printf("%s: Could not disable IRQ\n",drv.DriverName); 195 } 196 } 197 } 198 199 static int msg_open(devminor_t minor_dev_nr, int UNUSED(access), 200 endpoint_t UNUSED(user_endpt)) 201 { 202 int r, read_chan, write_chan, io_ctl; 203 special_file_t* special_file_ptr; 204 205 special_file_ptr = get_special_file(minor_dev_nr); 206 if(special_file_ptr == NULL) { 207 return EIO; 208 } 209 210 read_chan = special_file_ptr->read_chan; 211 write_chan = special_file_ptr->write_chan; 212 io_ctl = special_file_ptr->io_ctl; 213 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; 218 } 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; 223 } 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; 228 } 229 if (read_chan != NO_CHANNEL) { 230 if (open_sub_dev(read_chan, READ_DMA) != OK) return EIO; 231 } 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 */ 235 } 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; 239 } 240 return OK; 241 } 242 243 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]; 247 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; 253 } 254 if (sub_dev_ptr->DmaBusy) { 255 printf("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr); 256 return EBUSY; 257 } 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; 269 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; 275 } 276 return OK; 277 } 278 279 280 static int msg_close(devminor_t minor_dev_nr) 281 { 282 283 int r, read_chan, write_chan, io_ctl; 284 special_file_t* special_file_ptr; 285 286 special_file_ptr = get_special_file(minor_dev_nr); 287 if(special_file_ptr == NULL) { 288 return EIO; 289 } 290 291 read_chan = special_file_ptr->read_chan; 292 write_chan = special_file_ptr->write_chan; 293 io_ctl = special_file_ptr->io_ctl; 294 295 r= OK; 296 297 /* close all sub devices */ 298 if (write_chan != NO_CHANNEL) { 299 if (close_sub_dev(write_chan) != OK) r = EIO; 300 } 301 if (read_chan != NO_CHANNEL) { 302 if (close_sub_dev(read_chan) != OK) r = EIO; 303 } 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 */ 307 } 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 */ 311 } 312 return r; 313 } 314 315 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; 324 } 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; 329 } 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; 339 } 340 341 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) 344 { 345 int status, len, chan; 346 sub_dev_t *sub_dev_ptr; 347 special_file_t* special_file_ptr; 348 349 special_file_ptr = get_special_file(minor); 350 if(special_file_ptr == NULL) { 351 return EIO; 352 } 353 354 chan = special_file_ptr->io_ctl; 355 356 if (chan == NO_CHANNEL) { 357 printf("%s: No io control channel specified!\n", drv.DriverName); 358 return EIO; 359 } 360 /* get pointer to sub device data */ 361 sub_dev_ptr = &sub_dev[chan]; 362 363 if(!sub_dev_ptr->Opened) { 364 printf("%s: io control impossible - not opened!\n", drv.DriverName); 365 return EIO; 366 } 367 368 if (request & IOC_IN) { /* if there is data for us, copy it */ 369 len = io_ctl_length(request); 370 371 if (sys_safecopyfrom(endpt, grant, 0, (vir_bytes)io_ctl_buf, 372 len) != OK) { 373 printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__); 374 } 375 } 376 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); 379 380 /* IOC_OUT bit -> user expects data */ 381 if (status == OK && request & IOC_OUT) { 382 /* copy result back to user */ 383 384 if (sys_safecopyto(endpt, grant, 0, (vir_bytes)io_ctl_buf, 385 len) != OK) { 386 printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__); 387 } 388 389 } 390 return status; 391 } 392 393 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) 397 { 398 int chan; sub_dev_t *sub_dev_ptr; 399 special_file_t* special_file_ptr; 400 401 special_file_ptr = get_special_file(minor); 402 chan = special_file_ptr->write_chan; 403 404 if (chan == NO_CHANNEL) { 405 printf("%s: No write channel specified!\n", drv.DriverName); 406 return EIO; 407 } 408 /* get pointer to sub device data */ 409 sub_dev_ptr = &sub_dev[chan]; 410 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; 415 } 416 } 417 if(size != sub_dev_ptr->FragSize) { 418 printf("Fragment size does not match user's buffer length\n"); 419 return EINVAL; 420 } 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; 425 } 426 427 sub_dev_ptr->RevivePending = TRUE; 428 sub_dev_ptr->ReviveId = id; 429 sub_dev_ptr->ReviveGrant = grant; 430 sub_dev_ptr->SourceProcNr = endpt; 431 432 data_from_user(sub_dev_ptr); 433 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 */ 437 } 438 439 /* We may already have replied by now. In any case don't reply here. */ 440 return EDONTREPLY; 441 } 442 443 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) 447 { 448 int chan; sub_dev_t *sub_dev_ptr; 449 special_file_t* special_file_ptr; 450 451 special_file_ptr = get_special_file(minor); 452 chan = special_file_ptr->read_chan; 453 454 if (chan == NO_CHANNEL) { 455 printf("%s: No read channel specified!\n", drv.DriverName); 456 return EIO; 457 } 458 /* get pointer to sub device data */ 459 sub_dev_ptr = &sub_dev[chan]; 460 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; 465 } 466 } 467 if(size != sub_dev_ptr->FragSize) { 468 printf("fragment size does not match message size\n"); 469 return EINVAL; 470 } 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; 474 } 475 476 sub_dev_ptr->RevivePending = TRUE; 477 sub_dev_ptr->ReviveId = id; 478 sub_dev_ptr->ReviveGrant = grant; 479 sub_dev_ptr->SourceProcNr = endpt; 480 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; 486 } 487 /* check if data is available and possibly fill user's buffer */ 488 data_to_user(sub_dev_ptr); 489 490 /* We may already have replied by now. In any case don't reply here. */ 491 return EDONTREPLY; 492 } 493 494 495 static void msg_hardware(unsigned int UNUSED(mask)) 496 { 497 int i; 498 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); 510 } 511 } 512 } 513 514 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must 515 * re-enable out interrupt after every interrupt. 516 */ 517 if ((sys_irqenable(&irq_hook_id)) != OK) { 518 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv.DriverName); 519 } 520 } 521 522 523 /* handle interrupt for specified sub device; DmaMode == WRITE_DMA */ 524 static void handle_int_write(int sub_dev_nr) 525 { 526 sub_dev_t *sub_dev_ptr; 527 528 sub_dev_ptr = &sub_dev[sub_dev_nr]; 529 530 sub_dev_ptr->DmaReadNext = 531 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 532 sub_dev_ptr->DmaLength -= 1; 533 534 if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ 535 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); 541 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; 546 547 sub_dev_ptr->BufLength -= 1; 548 sub_dev_ptr->DmaLength += 1; 549 } 550 551 /* space became available, possibly copy new data from user */ 552 data_from_user(sub_dev_ptr); 553 554 if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ 555 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; 560 } 561 drv_pause(sub_dev_ptr->Nr); 562 return; 563 } 564 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); 571 } 572 #endif 573 } 574 575 576 /* handle interrupt for specified sub device; DmaMode == READ_DMA */ 577 static void handle_int_read(int sub_dev_nr) 578 { 579 sub_dev_t *sub_dev_ptr; 580 581 sub_dev_ptr = &sub_dev[sub_dev_nr]; 582 583 sub_dev_ptr->DmaLength += 1; 584 sub_dev_ptr->DmaFillNext = 585 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; 586 587 /* possibly copy data to user (if it is waiting for us) */ 588 data_to_user(sub_dev_ptr); 589 590 if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { 591 /* if dma buffer full */ 592 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; 601 } 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; 615 } 616 } 617 /* confirm interrupt, and reenable interrupt from this sub dev*/ 618 drv_reenable_int(sub_dev_ptr->Nr); 619 620 #if 0 621 /* reenable irq_hook*/ 622 if (sys_irqenable(&irq_hook_id) != OK) { 623 printf("%s: Couldn't reenable IRQ", drv.DriverName); 624 } 625 #endif 626 } 627 628 629 static int get_started(sub_dev_t *sub_dev_ptr) { 630 u32_t i; 631 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; 636 } 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); 641 } 642 643 sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ 644 sub_dev_ptr->DmaReadNext = 0; 645 return OK; 646 } 647 648 649 static void data_from_user(sub_dev_t *subdev) 650 { 651 int r; 652 653 if (subdev->DmaLength == subdev->NrOfDmaFragments && 654 subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */ 655 656 if (!subdev->RevivePending) return; /* no new data waiting to be copied */ 657 658 if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ 659 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__); 667 668 669 subdev->DmaLength += 1; 670 subdev->DmaFillNext = 671 (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; 672 673 } else { /* room in extra buf */ 674 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__); 682 683 subdev->BufLength += 1; 684 685 subdev->BufFillNext = 686 (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; 687 688 } 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); 695 } 696 drv_resume(subdev->Nr); /* resume resume the sub device */ 697 } 698 699 chardriver_reply_task(subdev->SourceProcNr, subdev->ReviveId, 700 subdev->FragSize); 701 702 /* reset variables */ 703 subdev->RevivePending = 0; 704 } 705 706 707 static void data_to_user(sub_dev_t *sub_dev_ptr) 708 { 709 int r; 710 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 */ 714 715 if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ 716 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__); 724 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; 729 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__); 739 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; 744 } 745 746 chardriver_reply_task(sub_dev_ptr->SourceProcNr, sub_dev_ptr->ReviveId, 747 sub_dev_ptr->FragSize); 748 749 /* reset variables */ 750 sub_dev_ptr->RevivePending = 0; 751 } 752 753 static int init_buffers(sub_dev_t *sub_dev_ptr) 754 { 755 #if defined(__i386__) 756 char *base; 757 size_t size; 758 unsigned left; 759 u32_t i; 760 phys_bytes ph; 761 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; 769 } 770 sub_dev_ptr->DmaBuf= base; 771 772 tell_dev((vir_bytes)base, size, 0, 0, 0); 773 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; 781 } 782 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)); 786 787 if (i != OK) { 788 return EIO; 789 } 790 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; 797 } 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; 802 803 #else /* !defined(__i386__) */ 804 printf("%s: init_buffers() failed, CHIP != INTEL", drv.DriverName); 805 return EIO; 806 #endif /* defined(__i386__) */ 807 } 808 809 810 static int io_ctl_length(int io_request) { 811 io_request >>= 16; 812 return io_request & IOCPARM_MASK; 813 } 814 815 816 static special_file_t* get_special_file(int minor_dev_nr) { 817 int i; 818 819 for(i = 0; i < drv.NrOfSpecialFiles; i++) { 820 if(special_file[i].minor_dev_nr == minor_dev_nr) { 821 return &special_file[i]; 822 } 823 } 824 825 printf("%s: No subdevice specified for minor device %d!\n", 826 drv.DriverName, minor_dev_nr); 827 828 return NULL; 829 } 830 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) 834 { 835 int r; 836 endpoint_t dev_e; 837 message m; 838 839 r= ds_retrieve_label_endpt("amddev", &dev_e); 840 if (r != OK) 841 { 842 #if 0 843 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", 844 r); 845 #endif 846 return; 847 } 848 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; 855 856 r= ipc_sendrec(dev_e, &m); 857 if (r != OK) 858 { 859 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e, r); 860 return; 861 } 862 if (m.m_type != OK) 863 { 864 printf("tell_dev: dma map request failed: %d\n", m.m_type); 865 return; 866 } 867 } 868 #endif 869