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 /* loop over all sub devices */ 500 for ( i = 0; i < drv.NrOfSubDevices; i++) { 501 /* if interrupt from sub device and Dma transfer 502 was actually busy, take care of business */ 503 if( drv_int(i) && sub_dev[i].DmaBusy ) { 504 if (sub_dev[i].DmaMode == WRITE_DMA) 505 handle_int_write(i); 506 if (sub_dev[i].DmaMode == READ_DMA) 507 handle_int_read(i); 508 } 509 } 510 511 /* As IRQ_REENABLE is not on in sys_irqsetpolicy, we must 512 * re-enable out interrupt after every interrupt. 513 */ 514 if ((sys_irqenable(&irq_hook_id)) != OK) { 515 printf("%s: msg_hardware: Couldn't enable IRQ\n", drv.DriverName); 516 } 517 } 518 519 520 /* handle interrupt for specified sub device; DmaMode == WRITE_DMA */ 521 static void handle_int_write(int sub_dev_nr) 522 { 523 sub_dev_t *sub_dev_ptr; 524 525 sub_dev_ptr = &sub_dev[sub_dev_nr]; 526 527 sub_dev_ptr->DmaReadNext = 528 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 529 sub_dev_ptr->DmaLength -= 1; 530 531 if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ 532 533 memcpy(sub_dev_ptr->DmaPtr + 534 sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize, 535 sub_dev_ptr->ExtraBuf + 536 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, 537 sub_dev_ptr->FragSize); 538 539 sub_dev_ptr->BufReadNext = 540 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 541 sub_dev_ptr->DmaFillNext = 542 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; 543 544 sub_dev_ptr->BufLength -= 1; 545 sub_dev_ptr->DmaLength += 1; 546 } 547 548 /* space became available, possibly copy new data from user */ 549 data_from_user(sub_dev_ptr); 550 551 if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ 552 553 sub_dev_ptr->OutOfData = TRUE; /* we're out of data */ 554 if (!sub_dev_ptr->Opened) { 555 close_sub_dev(sub_dev_ptr->Nr); 556 return; 557 } 558 drv_pause(sub_dev_ptr->Nr); 559 return; 560 } 561 562 /* confirm and reenable interrupt from this sub dev */ 563 drv_reenable_int(sub_dev_nr); 564 #if 0 565 /* reenable irq_hook*/ 566 if (sys_irqenable(&irq_hook_id != OK) { 567 printf("%s Couldn't enable IRQ\n", drv.DriverName); 568 } 569 #endif 570 } 571 572 573 /* handle interrupt for specified sub device; DmaMode == READ_DMA */ 574 static void handle_int_read(int sub_dev_nr) 575 { 576 sub_dev_t *sub_dev_ptr; 577 578 sub_dev_ptr = &sub_dev[sub_dev_nr]; 579 580 sub_dev_ptr->DmaLength += 1; 581 sub_dev_ptr->DmaFillNext = 582 (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; 583 584 /* possibly copy data to user (if it is waiting for us) */ 585 data_to_user(sub_dev_ptr); 586 587 if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { 588 /* if dma buffer full */ 589 590 if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) { 591 printf("All buffers full, we have a problem.\n"); 592 drv_stop(sub_dev_nr); /* stop the sub device */ 593 sub_dev_ptr->DmaBusy = FALSE; 594 /* no data for user, this is a sad story */ 595 chardriver_reply_task(sub_dev_ptr->SourceProcNr, 596 sub_dev_ptr->ReviveId, 0); 597 return; 598 } 599 else { /* dma full, still room in extra buf; 600 copy from dma to extra buf */ 601 memcpy(sub_dev_ptr->ExtraBuf + 602 sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize, 603 sub_dev_ptr->DmaPtr + 604 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, 605 sub_dev_ptr->FragSize); 606 sub_dev_ptr->DmaLength -= 1; 607 sub_dev_ptr->DmaReadNext = 608 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 609 sub_dev_ptr->BufFillNext = 610 (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 611 } 612 } 613 /* confirm interrupt, and reenable interrupt from this sub dev*/ 614 drv_reenable_int(sub_dev_ptr->Nr); 615 616 #if 0 617 /* reenable irq_hook*/ 618 if (sys_irqenable(&irq_hook_id) != OK) { 619 printf("%s: Couldn't reenable IRQ", drv.DriverName); 620 } 621 #endif 622 } 623 624 625 static int get_started(sub_dev_t *sub_dev_ptr) { 626 u32_t i; 627 628 /* enable interrupt messages from MINIX */ 629 if ((i=sys_irqenable(&irq_hook_id)) != OK) { 630 printf("%s: Couldn't enable IRQs: error code %u",drv.DriverName, (unsigned int) i); 631 return EIO; 632 } 633 /* let the lower part of the driver start the device */ 634 if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) { 635 printf("%s: Could not start device %d\n", 636 drv.DriverName, sub_dev_ptr->Nr); 637 } 638 639 sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ 640 sub_dev_ptr->DmaReadNext = 0; 641 return OK; 642 } 643 644 645 static void data_from_user(sub_dev_t *subdev) 646 { 647 int r; 648 649 if (subdev->DmaLength == subdev->NrOfDmaFragments && 650 subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */ 651 652 if (!subdev->RevivePending) return; /* no new data waiting to be copied */ 653 654 if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ 655 656 r = sys_safecopyfrom(subdev->SourceProcNr, 657 (vir_bytes)subdev->ReviveGrant, 0, 658 (vir_bytes)subdev->DmaPtr + 659 subdev->DmaFillNext * subdev->FragSize, 660 (phys_bytes)subdev->FragSize); 661 if (r != OK) 662 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 663 664 665 subdev->DmaLength += 1; 666 subdev->DmaFillNext = 667 (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; 668 669 } else { /* room in extra buf */ 670 671 r = sys_safecopyfrom(subdev->SourceProcNr, 672 (vir_bytes)subdev->ReviveGrant, 0, 673 (vir_bytes)subdev->ExtraBuf + 674 subdev->BufFillNext * subdev->FragSize, 675 (phys_bytes)subdev->FragSize); 676 if (r != OK) 677 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 678 679 subdev->BufLength += 1; 680 681 subdev->BufFillNext = 682 (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; 683 684 } 685 if(subdev->OutOfData) { /* if device paused (because of lack of data) */ 686 subdev->OutOfData = FALSE; 687 drv_reenable_int(subdev->Nr); 688 /* reenable irq_hook*/ 689 if ((sys_irqenable(&irq_hook_id)) != OK) { 690 printf("%s: Couldn't enable IRQ", drv.DriverName); 691 } 692 drv_resume(subdev->Nr); /* resume resume the sub device */ 693 } 694 695 chardriver_reply_task(subdev->SourceProcNr, subdev->ReviveId, 696 subdev->FragSize); 697 698 /* reset variables */ 699 subdev->RevivePending = 0; 700 } 701 702 703 static void data_to_user(sub_dev_t *sub_dev_ptr) 704 { 705 int r; 706 707 if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ 708 if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; 709 /* no data for user */ 710 711 if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ 712 713 r = sys_safecopyto(sub_dev_ptr->SourceProcNr, 714 (vir_bytes)sub_dev_ptr->ReviveGrant, 715 0, (vir_bytes)sub_dev_ptr->ExtraBuf + 716 sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, 717 (phys_bytes)sub_dev_ptr->FragSize); 718 if (r != OK) 719 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 720 721 /* adjust the buffer status variables */ 722 sub_dev_ptr->BufReadNext = 723 (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; 724 sub_dev_ptr->BufLength -= 1; 725 726 } else { /* extra buf empty, but data in dma buf*/ 727 r = sys_safecopyto( 728 sub_dev_ptr->SourceProcNr, 729 (vir_bytes)sub_dev_ptr->ReviveGrant, 0, 730 (vir_bytes)sub_dev_ptr->DmaPtr + 731 sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, 732 (phys_bytes)sub_dev_ptr->FragSize); 733 if (r != OK) 734 printf("%s:%d: safecopy failed\n", __FILE__, __LINE__); 735 736 /* adjust the buffer status variables */ 737 sub_dev_ptr->DmaReadNext = 738 (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; 739 sub_dev_ptr->DmaLength -= 1; 740 } 741 742 chardriver_reply_task(sub_dev_ptr->SourceProcNr, sub_dev_ptr->ReviveId, 743 sub_dev_ptr->FragSize); 744 745 /* reset variables */ 746 sub_dev_ptr->RevivePending = 0; 747 } 748 749 static int init_buffers(sub_dev_t *sub_dev_ptr) 750 { 751 #if defined(__i386__) 752 char *base; 753 size_t size; 754 unsigned left; 755 u32_t i; 756 phys_bytes ph; 757 758 /* allocate dma buffer space */ 759 size= sub_dev_ptr->DmaSize + 64 * 1024; 760 base= alloc_contig(size, AC_ALIGN64K|AC_LOWER16M, &ph); 761 if (!base) { 762 printf("%s: failed to allocate dma buffer for a channel\n", 763 drv.DriverName); 764 return EIO; 765 } 766 sub_dev_ptr->DmaBuf= base; 767 768 tell_dev((vir_bytes)base, size, 0, 0, 0); 769 770 /* allocate extra buffer space */ 771 if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers * 772 sub_dev_ptr->DmaSize / 773 sub_dev_ptr->NrOfDmaFragments))) { 774 printf("%s failed to allocate extra buffer for a channel\n", 775 drv.DriverName); 776 return EIO; 777 } 778 779 sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf; 780 i = sys_umap(SELF, VM_D, (vir_bytes) base, (phys_bytes) size, 781 &(sub_dev_ptr->DmaPhys)); 782 783 if (i != OK) { 784 return EIO; 785 } 786 787 if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) < 788 (unsigned int)sub_dev_ptr->DmaSize) { 789 /* First half of buffer crosses a 64K boundary, 790 * can't DMA into that */ 791 sub_dev_ptr->DmaPtr += left; 792 sub_dev_ptr->DmaPhys += left; 793 } 794 /* write the physical dma address and size to the device */ 795 drv_set_dma(sub_dev_ptr->DmaPhys, 796 sub_dev_ptr->DmaSize, sub_dev_ptr->Nr); 797 return OK; 798 799 #else /* !defined(__i386__) */ 800 printf("%s: init_buffers() failed, CHIP != INTEL", drv.DriverName); 801 return EIO; 802 #endif /* defined(__i386__) */ 803 } 804 805 806 static int io_ctl_length(int io_request) { 807 io_request >>= 16; 808 return io_request & IOCPARM_MASK; 809 } 810 811 812 static special_file_t* get_special_file(int minor_dev_nr) { 813 int i; 814 815 for(i = 0; i < drv.NrOfSpecialFiles; i++) { 816 if(special_file[i].minor_dev_nr == minor_dev_nr) { 817 return &special_file[i]; 818 } 819 } 820 821 printf("%s: No subdevice specified for minor device %d!\n", 822 drv.DriverName, minor_dev_nr); 823 824 return NULL; 825 } 826 827 #if defined(__i386__) 828 static void tell_dev(vir_bytes buf, size_t size, int pci_bus, 829 int pci_dev, int pci_func) 830 { 831 int r; 832 endpoint_t dev_e; 833 message m; 834 835 r= ds_retrieve_label_endpt("amddev", &dev_e); 836 if (r != OK) 837 { 838 #if 0 839 printf("tell_dev: ds_retrieve_label_endpt failed for 'amddev': %d\n", 840 r); 841 #endif 842 return; 843 } 844 845 m.m_type= IOMMU_MAP; 846 m.m2_i1= pci_bus; 847 m.m2_i2= pci_dev; 848 m.m2_i3= pci_func; 849 m.m2_l1= buf; 850 m.m2_l2= size; 851 852 r= ipc_sendrec(dev_e, &m); 853 if (r != OK) 854 { 855 printf("tell_dev: ipc_sendrec to %d failed: %d\n", dev_e, r); 856 return; 857 } 858 if (m.m_type != OK) 859 { 860 printf("tell_dev: dma map request failed: %d\n", m.m_type); 861 return; 862 } 863 } 864 #endif 865