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 static void tell_dev(vir_bytes buf, size_t size, int pci_bus, 51 int pci_dev, int pci_func); 52 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; 56 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 62 static struct chardriver audio_tab = { 63 .cdr_open = msg_open, /* open the special file */ 64 .cdr_close = msg_close, /* close the special file */ 65 .cdr_read = msg_read, 66 .cdr_write = msg_write, 67 .cdr_ioctl = msg_ioctl, 68 .cdr_intr = msg_hardware 69 }; 70 71 int main(void) 72 { 73 74 /* SEF local startup. */ 75 sef_local_startup(); 76 77 /* Here is the main loop of the dma driver. It waits for a message, 78 carries it out, and sends a reply. */ 79 chardriver_task(&audio_tab); 80 81 return 0; 82 } 83 84 /*===========================================================================* 85 * sef_local_startup * 86 *===========================================================================*/ 87 static void sef_local_startup(void) 88 { 89 /* Register init callbacks. */ 90 sef_setcb_init_fresh(sef_cb_init_fresh); 91 sef_setcb_init_lu(sef_cb_init_fresh); 92 sef_setcb_init_restart(sef_cb_init_fresh); 93 94 /* Register live update callbacks. */ 95 sef_setcb_lu_prepare(sef_cb_lu_prepare); 96 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid); 97 sef_setcb_lu_state_dump(sef_cb_lu_state_dump); 98 99 /* Register signal callbacks. */ 100 sef_setcb_signal_handler(sef_cb_signal_handler); 101 102 /* Let SEF perform startup. */ 103 sef_startup(); 104 } 105 106 /*===========================================================================* 107 * sef_cb_init_fresh * 108 *===========================================================================*/ 109 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 110 { 111 /* Initialize the audio driver framework. */ 112 int i; char irq; 113 static int executed = 0; 114 sub_dev_t* sub_dev_ptr; 115 116 /* initialize basic driver variables */ 117 if (drv_init() != OK) { 118 printf("libaudiodriver: Could not initialize driver\n"); 119 return EIO; 120 } 121 122 /* init variables, get dma buffers */ 123 for (i = 0; i < drv.NrOfSubDevices; i++) { 124 125 sub_dev_ptr = &sub_dev[i]; 126 127 sub_dev_ptr->Opened = FALSE; 128 sub_dev_ptr->DmaBusy = FALSE; 129 sub_dev_ptr->DmaMode = NO_DMA; 130 sub_dev_ptr->DmaReadNext = 0; 131 sub_dev_ptr->DmaFillNext = 0; 132 sub_dev_ptr->DmaLength = 0; 133 sub_dev_ptr->BufReadNext = 0; 134 sub_dev_ptr->BufFillNext = 0; 135 sub_dev_ptr->RevivePending = FALSE; 136 sub_dev_ptr->OutOfData = FALSE; 137 sub_dev_ptr->Nr = i; 138 } 139 140 /* initialize hardware*/ 141 if (drv_init_hw() != OK) { 142 printf("%s: Could not initialize hardware\n", drv.DriverName); 143 return EIO; 144 } 145 146 /* get irq from device driver...*/ 147 if (drv_get_irq(&irq) != OK) { 148 printf("%s: init driver couldn't get IRQ", drv.DriverName); 149 return EIO; 150 } 151 /* TODO: execute the rest of this function only once 152 we don't want to set irq policy twice */ 153 if (executed) return OK; 154 executed = TRUE; 155 156 /* ...and register interrupt vector */ 157 if ((i=sys_irqsetpolicy(irq, 0, &irq_hook_id )) != OK){ 158 printf("%s: init driver couldn't set IRQ policy: %d", drv.DriverName, i); 159 return EIO; 160 } 161 irq_hook_set = TRUE; /* now signal handler knows it must unregister policy*/ 162 163 /* Announce we are up! */ 164 chardriver_announce(); 165 166 return OK; 167 } 168 169 /*===========================================================================* 170 * sef_cb_signal_handler * 171 *===========================================================================*/ 172 static void sef_cb_signal_handler(int signo) 173 { 174 int i; 175 char irq; 176 177 /* Only check for termination signal, ignore anything else. */ 178 if (signo != SIGTERM) return; 179 180 for (i = 0; i < drv.NrOfSubDevices; i++) { 181 drv_stop(i); /* stop all sub devices */ 182 } 183 if (irq_hook_set) { 184 if (sys_irqdisable(&irq_hook_id) != OK) { 185 printf("Could not disable IRQ\n"); 186 } 187 /* get irq from device driver*/ 188 if (drv_get_irq(&irq) != OK) { 189 printf("Msg SIG_STOP Couldn't get IRQ"); 190 } 191 /* remove the policy */ 192 if (sys_irqrmpolicy(&irq_hook_id) != OK) { 193 printf("%s: Could not disable IRQ\n",drv.DriverName); 194 } 195 } 196 } 197 198 static int msg_open(devminor_t minor_dev_nr, int UNUSED(access), 199 endpoint_t UNUSED(user_endpt)) 200 { 201 int r, read_chan, write_chan, io_ctl; 202 special_file_t* special_file_ptr; 203 204 special_file_ptr = get_special_file(minor_dev_nr); 205 if(special_file_ptr == NULL) { 206 return EIO; 207 } 208 209 read_chan = special_file_ptr->read_chan; 210 write_chan = special_file_ptr->write_chan; 211 io_ctl = special_file_ptr->io_ctl; 212 213 if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) { 214 printf("%s: No channel specified for minor device %d!\n", 215 drv.DriverName, minor_dev_nr); 216 return EIO; 217 } 218 if (read_chan == write_chan && read_chan != NO_CHANNEL) { 219 printf("%s: Read and write channels are equal: %d!\n", 220 drv.DriverName, minor_dev_nr); 221 return EIO; 222 } 223 /* open the sub devices specified in the interface header file */ 224 if (write_chan != NO_CHANNEL) { 225 /* open sub device for writing */ 226 if (open_sub_dev(write_chan, WRITE_DMA) != OK) return EIO; 227 } 228 if (read_chan != NO_CHANNEL) { 229 if (open_sub_dev(read_chan, READ_DMA) != OK) return EIO; 230 } 231 if (read_chan == io_ctl || write_chan == io_ctl) { 232 /* io_ctl is already opened because it's the same as read or write */ 233 return OK; /* we're done */ 234 } 235 if (io_ctl != NO_CHANNEL) { /* Ioctl differs from read/write channels, */ 236 r = open_sub_dev(io_ctl, NO_DMA); /* open it explicitly */ 237 if (r != OK) return EIO; 238 } 239 return OK; 240 } 241 242 243 static int open_sub_dev(int sub_dev_nr, int dma_mode) { 244 sub_dev_t* sub_dev_ptr; 245 sub_dev_ptr = &sub_dev[sub_dev_nr]; 246 247 /* Only one open at a time per sub device */ 248 if (sub_dev_ptr->Opened) { 249 printf("%s: Sub device %d is already opened\n", 250 drv.DriverName, sub_dev_nr); 251 return EBUSY; 252 } 253 if (sub_dev_ptr->DmaBusy) { 254 printf("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr); 255 return EBUSY; 256 } 257 /* Setup variables */ 258 sub_dev_ptr->Opened = TRUE; 259 sub_dev_ptr->DmaReadNext = 0; 260 sub_dev_ptr->DmaFillNext = 0; 261 sub_dev_ptr->DmaLength = 0; 262 sub_dev_ptr->DmaMode = dma_mode; 263 sub_dev_ptr->BufReadNext = 0; 264 sub_dev_ptr->BufFillNext = 0; 265 sub_dev_ptr->BufLength = 0; 266 sub_dev_ptr->RevivePending = FALSE; 267 sub_dev_ptr->OutOfData = TRUE; 268 269 /* arrange DMA */ 270 if (dma_mode != NO_DMA) { /* sub device uses DMA */ 271 /* allocate dma buffer and extra buffer space 272 and configure sub device for dma */ 273 if (init_buffers(sub_dev_ptr) != OK ) return EIO; 274 } 275 return OK; 276 } 277 278 279 static int msg_close(devminor_t minor_dev_nr) 280 { 281 282 int r, read_chan, write_chan, io_ctl; 283 special_file_t* special_file_ptr; 284 285 special_file_ptr = get_special_file(minor_dev_nr); 286 if(special_file_ptr == NULL) { 287 return EIO; 288 } 289 290 read_chan = special_file_ptr->read_chan; 291 write_chan = special_file_ptr->write_chan; 292 io_ctl = special_file_ptr->io_ctl; 293 294 r= OK; 295 296 /* close all sub devices */ 297 if (write_chan != NO_CHANNEL) { 298 if (close_sub_dev(write_chan) != OK) r = EIO; 299 } 300 if (read_chan != NO_CHANNEL) { 301 if (close_sub_dev(read_chan) != OK) r = EIO; 302 } 303 if (read_chan == io_ctl || write_chan == io_ctl) { 304 /* io_ctl is already closed because it's the same as read or write */ 305 return r; /* we're done */ 306 } 307 /* ioctl differs from read/write channels... */ 308 if (io_ctl != NO_CHANNEL) { 309 if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */ 310 } 311 return r; 312 } 313 314 315 static int close_sub_dev(int sub_dev_nr) { 316 size_t size; 317 sub_dev_t *sub_dev_ptr; 318 sub_dev_ptr = &sub_dev[sub_dev_nr]; 319 if (sub_dev_ptr->DmaMode == WRITE_DMA && !sub_dev_ptr->OutOfData) { 320 /* do nothing, still data in buffers that has to be transferred */ 321 sub_dev_ptr->Opened = FALSE; /* keep DMA busy */ 322 return OK; 323 } 324 if (sub_dev_ptr->DmaMode == NO_DMA) { 325 /* do nothing, there is no dma going on */ 326 sub_dev_ptr->Opened = FALSE; 327 return OK; 328 } 329 sub_dev_ptr->Opened = FALSE; 330 sub_dev_ptr->DmaBusy = FALSE; 331 /* stop the device */ 332 drv_stop(sub_dev_ptr->Nr); 333 /* free the buffers */ 334 size= sub_dev_ptr->DmaSize + 64 * 1024; 335 free_contig(sub_dev_ptr->DmaBuf, size); 336 free(sub_dev_ptr->ExtraBuf); 337 return OK; 338 } 339 340 341 static int msg_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, 342 cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) 343 { 344 int status, len, chan; 345 sub_dev_t *sub_dev_ptr; 346 special_file_t* special_file_ptr; 347 348 special_file_ptr = get_special_file(minor); 349 if(special_file_ptr == NULL) { 350 return EIO; 351 } 352 353 chan = special_file_ptr->io_ctl; 354 355 if (chan == NO_CHANNEL) { 356 printf("%s: No io control channel specified!\n", drv.DriverName); 357 return EIO; 358 } 359 /* get pointer to sub device data */ 360 sub_dev_ptr = &sub_dev[chan]; 361 362 if(!sub_dev_ptr->Opened) { 363 printf("%s: io control impossible - not opened!\n", drv.DriverName); 364 return EIO; 365 } 366 367 if (request & IOC_IN) { /* if there is data for us, copy it */ 368 len = io_ctl_length(request); 369 370 if (sys_safecopyfrom(endpt, grant, 0, (vir_bytes)io_ctl_buf, 371 len) != OK) { 372 printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__); 373 } 374 } 375 376 /* all ioctl's are passed to the device specific part of the driver */ 377 status = drv_io_ctl(request, (void *)io_ctl_buf, &len, chan); 378 379 /* IOC_OUT bit -> user expects data */ 380 if (status == OK && request & IOC_OUT) { 381 /* copy result back to user */ 382 383 if (sys_safecopyto(endpt, grant, 0, (vir_bytes)io_ctl_buf, 384 len) != OK) { 385 printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__); 386 } 387 388 } 389 return status; 390 } 391 392 393 static ssize_t msg_write(devminor_t minor, u64_t UNUSED(position), 394 endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), 395 cdev_id_t id) 396 { 397 int chan; sub_dev_t *sub_dev_ptr; 398 special_file_t* special_file_ptr; 399 400 special_file_ptr = get_special_file(minor); 401 chan = special_file_ptr->write_chan; 402 403 if (chan == NO_CHANNEL) { 404 printf("%s: No write channel specified!\n", drv.DriverName); 405 return EIO; 406 } 407 /* get pointer to sub device data */ 408 sub_dev_ptr = &sub_dev[chan]; 409 410 if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */ 411 if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ 412 printf("%s; Failed to get fragment size!\n", drv.DriverName); 413 return EIO; 414 } 415 } 416 if(size != sub_dev_ptr->FragSize) { 417 printf("Fragment size does not match user's buffer length\n"); 418 return EINVAL; 419 } 420 /* if we are busy with something else than writing, return EBUSY */ 421 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != WRITE_DMA) { 422 printf("Already busy with something else than writing\n"); 423 return EBUSY; 424 } 425 426 sub_dev_ptr->RevivePending = TRUE; 427 sub_dev_ptr->ReviveId = id; 428 sub_dev_ptr->ReviveGrant = grant; 429 sub_dev_ptr->SourceProcNr = endpt; 430 431 data_from_user(sub_dev_ptr); 432 433 if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ 434 get_started(sub_dev_ptr); 435 sub_dev_ptr->DmaMode = WRITE_DMA; /* Dma mode is writing */ 436 } 437 438 /* We may already have replied by now. In any case don't reply here. */ 439 return EDONTREPLY; 440 } 441 442 443 static ssize_t msg_read(devminor_t minor, u64_t UNUSED(position), 444 endpoint_t endpt, cp_grant_id_t grant, size_t size, int UNUSED(flags), 445 cdev_id_t id) 446 { 447 int chan; sub_dev_t *sub_dev_ptr; 448 special_file_t* special_file_ptr; 449 450 special_file_ptr = get_special_file(minor); 451 chan = special_file_ptr->read_chan; 452 453 if (chan == NO_CHANNEL) { 454 printf("%s: No read channel specified!\n", drv.DriverName); 455 return EIO; 456 } 457 /* get pointer to sub device data */ 458 sub_dev_ptr = &sub_dev[chan]; 459 460 if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */ 461 if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ 462 printf("%s: Could not retrieve fragment size!\n", drv.DriverName); 463 return EIO; 464 } 465 } 466 if(size != sub_dev_ptr->FragSize) { 467 printf("fragment size does not match message size\n"); 468 return EINVAL; 469 } 470 /* if we are busy with something else than reading, reply EBUSY */ 471 if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != READ_DMA) { 472 return EBUSY; 473 } 474 475 sub_dev_ptr->RevivePending = TRUE; 476 sub_dev_ptr->ReviveId = id; 477 sub_dev_ptr->ReviveGrant = grant; 478 sub_dev_ptr->SourceProcNr = endpt; 479 480 if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ 481 get_started(sub_dev_ptr); 482 sub_dev_ptr->DmaMode = READ_DMA; /* Dma mode is reading */ 483 /* no need to get data from DMA buffer at this point */ 484 return EDONTREPLY; 485 } 486 /* check if data is available and possibly fill user's buffer */ 487 data_to_user(sub_dev_ptr); 488 489 /* We may already have replied by now. In any case don't reply here. */ 490 return EDONTREPLY; 491 } 492 493 494 static void msg_hardware(unsigned int UNUSED(mask)) 495 { 496 int i; 497 498 /* loop over all sub devices */ 499 for ( i = 0; i < drv.NrOfSubDevices; i++) { 500 /* if interrupt from sub device and Dma transfer 501 was actually busy, take care of business */ 502 if( drv_int(i) && sub_dev[i].DmaBusy ) { 503 if (sub_dev[i].DmaMode == WRITE_DMA) 504 handle_int_write(i); 505 if (sub_dev[i].DmaMode == READ_DMA) 506 handle_int_read(i); 507 } 508 } 509 510 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must 511 * re-enable out interrupt after every interrupt. 512 */ 513 if ((sys_irqenable(&irq_hook_id)) != OK) { 514 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv.DriverName); 515 } 516 } 517 518 519 /* handle interrupt for specified sub device; DmaMode == WRITE_DMA */ 520 static void handle_int_write(int sub_dev_nr) 521 { 522 sub_dev_t *sub_dev_ptr; 523 524 sub_dev_ptr = &sub_dev[sub_dev_nr]; 525 526 sub_dev_ptr->DmaReadNext = 527 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 528 sub_dev_ptr->DmaLength -= 1; 529 530 if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ 531 532 memcpy(sub_dev_ptr->DmaPtr + 533 sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize, 534 sub_dev_ptr->ExtraBuf + 535 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, 536 sub_dev_ptr->FragSize); 537 538 sub_dev_ptr->BufReadNext = 539 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 540 sub_dev_ptr->DmaFillNext = 541 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; 542 543 sub_dev_ptr->BufLength -= 1; 544 sub_dev_ptr->DmaLength += 1; 545 } 546 547 /* space became available, possibly copy new data from user */ 548 data_from_user(sub_dev_ptr); 549 550 if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ 551 552 sub_dev_ptr->OutOfData = TRUE; /* we're out of data */ 553 if (!sub_dev_ptr->Opened) { 554 close_sub_dev(sub_dev_ptr->Nr); 555 return; 556 } 557 drv_pause(sub_dev_ptr->Nr); 558 return; 559 } 560 561 /* confirm and reenable interrupt from this sub dev */ 562 drv_reenable_int(sub_dev_nr); 563 #if 0 564 /* reenable irq_hook*/ 565 if (sys_irqenable(&irq_hook_id != OK) { 566 printf("%s Couldn't enable IRQ\n", drv.DriverName); 567 } 568 #endif 569 } 570 571 572 /* handle interrupt for specified sub device; DmaMode == READ_DMA */ 573 static void handle_int_read(int sub_dev_nr) 574 { 575 sub_dev_t *sub_dev_ptr; 576 577 sub_dev_ptr = &sub_dev[sub_dev_nr]; 578 579 sub_dev_ptr->DmaLength += 1; 580 sub_dev_ptr->DmaFillNext = 581 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; 582 583 /* possibly copy data to user (if it is waiting for us) */ 584 data_to_user(sub_dev_ptr); 585 586 if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { 587 /* if dma buffer full */ 588 589 if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) { 590 printf("All buffers full, we have a problem.\n"); 591 drv_stop(sub_dev_nr); /* stop the sub device */ 592 sub_dev_ptr->DmaBusy = FALSE; 593 /* no data for user, this is a sad story */ 594 chardriver_reply_task(sub_dev_ptr->SourceProcNr, 595 sub_dev_ptr->ReviveId, 0); 596 return; 597 } 598 else { /* dma full, still room in extra buf; 599 copy from dma to extra buf */ 600 memcpy(sub_dev_ptr->ExtraBuf + 601 sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize, 602 sub_dev_ptr->DmaPtr + 603 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, 604 sub_dev_ptr->FragSize); 605 sub_dev_ptr->DmaLength -= 1; 606 sub_dev_ptr->DmaReadNext = 607 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 608 sub_dev_ptr->BufFillNext = 609 (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 610 } 611 } 612 /* confirm interrupt, and reenable interrupt from this sub dev*/ 613 drv_reenable_int(sub_dev_ptr->Nr); 614 615 #if 0 616 /* reenable irq_hook*/ 617 if (sys_irqenable(&irq_hook_id) != OK) { 618 printf("%s: Couldn't reenable IRQ", drv.DriverName); 619 } 620 #endif 621 } 622 623 624 static int get_started(sub_dev_t *sub_dev_ptr) { 625 u32_t i; 626 627 /* enable interrupt messages from MINIX */ 628 if ((i=sys_irqenable(&irq_hook_id)) != OK) { 629 printf("%s: Couldn't enable IRQs: error code %u",drv.DriverName, (unsigned int) i); 630 return EIO; 631 } 632 /* let the lower part of the driver start the device */ 633 if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) { 634 printf("%s: Could not start device %d\n", 635 drv.DriverName, sub_dev_ptr->Nr); 636 } 637 638 sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ 639 sub_dev_ptr->DmaReadNext = 0; 640 return OK; 641 } 642 643 644 static void data_from_user(sub_dev_t *subdev) 645 { 646 int r; 647 648 if (subdev->DmaLength == subdev->NrOfDmaFragments && 649 subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */ 650 651 if (!subdev->RevivePending) return; /* no new data waiting to be copied */ 652 653 if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ 654 655 r = sys_safecopyfrom(subdev->SourceProcNr, 656 (vir_bytes)subdev->ReviveGrant, 0, 657 (vir_bytes)subdev->DmaPtr + 658 subdev->DmaFillNext * subdev->FragSize, 659 (phys_bytes)subdev->FragSize); 660 if (r != OK) 661 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 662 663 664 subdev->DmaLength += 1; 665 subdev->DmaFillNext = 666 (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; 667 668 } else { /* room in extra buf */ 669 670 r = sys_safecopyfrom(subdev->SourceProcNr, 671 (vir_bytes)subdev->ReviveGrant, 0, 672 (vir_bytes)subdev->ExtraBuf + 673 subdev->BufFillNext * subdev->FragSize, 674 (phys_bytes)subdev->FragSize); 675 if (r != OK) 676 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 677 678 subdev->BufLength += 1; 679 680 subdev->BufFillNext = 681 (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; 682 683 } 684 if(subdev->OutOfData) { /* if device paused (because of lack of data) */ 685 subdev->OutOfData = FALSE; 686 drv_reenable_int(subdev->Nr); 687 /* reenable irq_hook*/ 688 if ((sys_irqenable(&irq_hook_id)) != OK) { 689 printf("%s: Couldn't enable IRQ", drv.DriverName); 690 } 691 drv_resume(subdev->Nr); /* resume resume the sub device */ 692 } 693 694 chardriver_reply_task(subdev->SourceProcNr, subdev->ReviveId, 695 subdev->FragSize); 696 697 /* reset variables */ 698 subdev->RevivePending = 0; 699 } 700 701 702 static void data_to_user(sub_dev_t *sub_dev_ptr) 703 { 704 int r; 705 706 if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ 707 if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; 708 /* no data for user */ 709 710 if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ 711 712 r = sys_safecopyto(sub_dev_ptr->SourceProcNr, 713 (vir_bytes)sub_dev_ptr->ReviveGrant, 714 0, (vir_bytes)sub_dev_ptr->ExtraBuf + 715 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, 716 (phys_bytes)sub_dev_ptr->FragSize); 717 if (r != OK) 718 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 719 720 /* adjust the buffer status variables */ 721 sub_dev_ptr->BufReadNext = 722 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 723 sub_dev_ptr->BufLength -= 1; 724 725 } else { /* extra buf empty, but data in dma buf*/ 726 r = sys_safecopyto( 727 sub_dev_ptr->SourceProcNr, 728 (vir_bytes)sub_dev_ptr->ReviveGrant, 0, 729 (vir_bytes)sub_dev_ptr->DmaPtr + 730 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, 731 (phys_bytes)sub_dev_ptr->FragSize); 732 if (r != OK) 733 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 734 735 /* adjust the buffer status variables */ 736 sub_dev_ptr->DmaReadNext = 737 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 738 sub_dev_ptr->DmaLength -= 1; 739 } 740 741 chardriver_reply_task(sub_dev_ptr->SourceProcNr, sub_dev_ptr->ReviveId, 742 sub_dev_ptr->FragSize); 743 744 /* reset variables */ 745 sub_dev_ptr->RevivePending = 0; 746 } 747 748 static int init_buffers(sub_dev_t *sub_dev_ptr) 749 { 750 #if defined(__i386__) 751 char *base; 752 size_t size; 753 unsigned left; 754 u32_t i; 755 phys_bytes ph; 756 757 /* allocate dma buffer space */ 758 size= sub_dev_ptr->DmaSize + 64 * 1024; 759 base= alloc_contig(size, AC_ALIGN64K|AC_LOWER16M, &ph); 760 if (!base) { 761 printf("%s: failed to allocate dma buffer for a channel\n", 762 drv.DriverName); 763 return EIO; 764 } 765 sub_dev_ptr->DmaBuf= base; 766 767 tell_dev((vir_bytes)base, size, 0, 0, 0); 768 769 /* allocate extra buffer space */ 770 if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers * 771 sub_dev_ptr->DmaSize / 772 sub_dev_ptr->NrOfDmaFragments))) { 773 printf("%s failed to allocate extra buffer for a channel\n", 774 drv.DriverName); 775 return EIO; 776 } 777 778 sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf; 779 i = sys_umap(SELF, VM_D, (vir_bytes) base, (phys_bytes) size, 780 &(sub_dev_ptr->DmaPhys)); 781 782 if (i != OK) { 783 return EIO; 784 } 785 786 if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) < 787 (unsigned int)sub_dev_ptr->DmaSize) { 788 /* First half of buffer crosses a 64K boundary, 789 * can't DMA into that */ 790 sub_dev_ptr->DmaPtr += left; 791 sub_dev_ptr->DmaPhys += left; 792 } 793 /* write the physical dma address and size to the device */ 794 drv_set_dma(sub_dev_ptr->DmaPhys, 795 sub_dev_ptr->DmaSize, sub_dev_ptr->Nr); 796 return OK; 797 798 #else /* !defined(__i386__) */ 799 printf("%s: init_buffers() failed, CHIP != INTEL", drv.DriverName); 800 return EIO; 801 #endif /* defined(__i386__) */ 802 } 803 804 805 static int io_ctl_length(int io_request) { 806 io_request >>= 16; 807 return io_request & IOCPARM_MASK; 808 } 809 810 811 static special_file_t* get_special_file(int minor_dev_nr) { 812 int i; 813 814 for(i = 0; i < drv.NrOfSpecialFiles; i++) { 815 if(special_file[i].minor_dev_nr == minor_dev_nr) { 816 return &special_file[i]; 817 } 818 } 819 820 printf("%s: No subdevice specified for minor device %d!\n", 821 drv.DriverName, minor_dev_nr); 822 823 return NULL; 824 } 825 826 static void tell_dev(vir_bytes buf, size_t size, int pci_bus, 827 int pci_dev, int pci_func) 828 { 829 int r; 830 endpoint_t dev_e; 831 message m; 832 833 r= ds_retrieve_label_endpt("amddev", &dev_e); 834 if (r != OK) 835 { 836 #if 0 837 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", 838 r); 839 #endif 840 return; 841 } 842 843 m.m_type= IOMMU_MAP; 844 m.m2_i1= pci_bus; 845 m.m2_i2= pci_dev; 846 m.m2_i3= pci_func; 847 m.m2_l1= buf; 848 m.m2_l2= size; 849 850 r= ipc_sendrec(dev_e, &m); 851 if (r != OK) 852 { 853 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e, r); 854 return; 855 } 856 if (m.m_type != OK) 857 { 858 printf("tell_dev: dma map request failed: %d\n", m.m_type); 859 return; 860 } 861 } 862