1 //------------------------------------------------------------------------------ 2 // 3 // EchoGals/Echo24 BeOS Driver for Echo audio cards 4 // 5 // Copyright (c) 2003, Jérôme Duval 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a 8 // copy of this software and associated documentation files (the "Software"), 9 // to deal in the Software without restriction, including without limitation 10 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 // and/or sell copies of the Software, and to permit persons to whom the 12 // Software is furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 // DEALINGS IN THE SOFTWARE. 24 25 #include <KernelExport.h> 26 #include <Drivers.h> 27 #include <malloc.h> 28 #include <unistd.h> 29 #include "OsSupportBeOS.h" 30 #include "EchoGalsXface.h" 31 #include "C3g.h" 32 #include "CDarla24.h" 33 #include "CDarla.h" 34 #include "CGina.h" 35 #include "CGina24.h" 36 #include "CIndigo.h" 37 #include "CIndigoDJ.h" 38 #include "CIndigoIO.h" 39 #include "CLayla.h" 40 #include "CLayla24.h" 41 #include "CMia.h" 42 #include "CMona.h" 43 #include "echo.h" 44 #include "debug.h" 45 #include "util.h" 46 47 static char pci_name[] = B_PCI_MODULE_NAME; 48 static pci_module_info *pci; 49 int32 num_cards; 50 echo_dev cards[NUM_CARDS]; 51 int32 num_names; 52 char * names[NUM_CARDS*20+1]; 53 54 extern device_hooks multi_hooks; 55 #ifdef MIDI_SUPPORT 56 extern device_hooks midi_hooks; 57 #endif 58 59 int32 echo_int(void *arg); 60 status_t init_hardware(void); 61 status_t init_driver(void); 62 static void make_device_names(echo_dev * card); 63 64 static status_t echo_setup(echo_dev * card); 65 static void echo_shutdown(echo_dev *card); 66 67 void uninit_driver(void); 68 const char ** publish_devices(void); 69 device_hooks * find_device(const char * name); 70 71 72 /* Echo Memory management */ 73 74 echo_mem * 75 echo_mem_new(echo_dev *card, size_t size) 76 { 77 echo_mem *mem; 78 79 if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL) 80 return (NULL); 81 82 mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer"); 83 mem->size = size; 84 if (mem->area < B_OK) { 85 free(mem); 86 return NULL; 87 } 88 return mem; 89 } 90 91 void 92 echo_mem_delete(echo_mem *mem) 93 { 94 if(mem->area > B_OK) 95 delete_area(mem->area); 96 free(mem); 97 } 98 99 echo_mem * 100 echo_mem_alloc(echo_dev *card, size_t size) 101 { 102 echo_mem *mem; 103 104 mem = echo_mem_new(card, size); 105 if (mem == NULL) 106 return (NULL); 107 108 LIST_INSERT_HEAD(&(card->mems), mem, next); 109 110 return mem; 111 } 112 113 void 114 echo_mem_free(echo_dev *card, void *ptr) 115 { 116 echo_mem *mem; 117 118 LIST_FOREACH(mem, &card->mems, next) { 119 if (mem->log_base != ptr) 120 continue; 121 LIST_REMOVE(mem, next); 122 123 echo_mem_delete(mem); 124 break; 125 } 126 } 127 128 /* Echo stream functions */ 129 130 extern char * pStatusStrs[ECHOSTATUS_LAST]; 131 132 status_t 133 echo_stream_set_audioparms(echo_stream *stream, uint8 channels, 134 uint8 bitsPerSample, uint32 sample_rate, uint8 index) 135 { 136 int32 i; 137 uint8 sample_size, frame_size; 138 ECHOGALS_OPENAUDIOPARAMETERS open_params; 139 ECHOGALS_CLOSEAUDIOPARAMETERS close_params; 140 ECHOGALS_AUDIOFORMAT format_params; 141 ECHOSTATUS status; 142 143 LOG(("echo_stream_set_audioparms\n")); 144 145 close_params.wPipeIndex = stream->pipe; 146 status = stream->card->pEG->CloseAudio(&close_params); 147 if(status!=ECHOSTATUS_OK && status!=ECHOSTATUS_CHANNEL_NOT_OPEN) { 148 PRINT(("echo_stream_set_audioparms : CloseAudio failed\n")); 149 PRINT((" status: %s \n", pStatusStrs[status])); 150 return B_ERROR; 151 } 152 153 open_params.bIsCyclic = TRUE; 154 open_params.Pipe.nPipe = index; 155 open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE; 156 open_params.Pipe.wInterleave = channels; 157 open_params.ProcessId = NULL; 158 159 status = stream->card->pEG->OpenAudio(&open_params, &stream->pipe); 160 if(status!=ECHOSTATUS_OK) { 161 PRINT(("echo_stream_set_audioparms : OpenAudio failed\n")); 162 PRINT((" status: %s \n", pStatusStrs[status])); 163 return B_ERROR; 164 } 165 166 //PRINT(("VerifyAudioOpen\n")); 167 status = stream->card->pEG->VerifyAudioOpen(stream->pipe); 168 if(status!=ECHOSTATUS_OK) { 169 PRINT(("echo_stream_set_audioparms : VerifyAudioOpen failed\n")); 170 PRINT((" status: %s \n", pStatusStrs[status])); 171 return B_ERROR; 172 } 173 174 if ((stream->channels == channels) && 175 (stream->bitsPerSample == bitsPerSample) && 176 (stream->sample_rate == sample_rate)) 177 return B_OK; 178 179 format_params.wBitsPerSample = bitsPerSample; 180 format_params.byDataAreBigEndian = 0; 181 format_params.byMonoToStereo = 0; 182 format_params.wDataInterleave = channels == 1 ? 1 : 2; 183 184 status = stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params); 185 if(status!=ECHOSTATUS_OK) { 186 PRINT(("echo_stream_set_audioparms : bad format when querying\n")); 187 PRINT((" status: %s \n", pStatusStrs[status])); 188 return B_ERROR; 189 } 190 191 status = stream->card->pEG->SetAudioFormat(stream->pipe, &format_params); 192 if(status!=ECHOSTATUS_OK) { 193 PRINT(("echo_stream_set_audioparms : bad format when setting\n")); 194 PRINT((" status: %s \n", pStatusStrs[status])); 195 return B_ERROR; 196 } 197 198 /* XXXX : setting sample rate is global in this driver */ 199 status = stream->card->pEG->QueryAudioSampleRate(sample_rate); 200 if(status!=ECHOSTATUS_OK) { 201 PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n")); 202 PRINT((" status: %s \n", pStatusStrs[status])); 203 return B_ERROR; 204 } 205 206 /* XXXX : setting sample rate is global in this driver */ 207 status = stream->card->pEG->SetAudioSampleRate(sample_rate); 208 if(status!=ECHOSTATUS_OK) { 209 PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n")); 210 PRINT((" status: %s \n", pStatusStrs[status])); 211 return B_ERROR; 212 } 213 214 if(stream->buffer) 215 echo_mem_free(stream->card, stream->buffer->log_base); 216 217 stream->bitsPerSample = bitsPerSample; 218 stream->sample_rate = sample_rate; 219 stream->channels = channels; 220 221 sample_size = stream->bitsPerSample / 8; 222 frame_size = sample_size * stream->channels; 223 224 stream->buffer = echo_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); 225 226 stream->trigblk = 1; 227 stream->blkmod = stream->bufcount; 228 stream->blksize = stream->bufframes * frame_size; 229 230 CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe); 231 if(duck == NULL) { 232 PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n")); 233 return B_ERROR; 234 } 235 236 uint32 dwNumFreeEntries = 0; 237 238 for(i=0; i<stream->bufcount; i++) { 239 duck->AddMapping(((uint32)stream->buffer->phy_base) + 240 i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries); 241 } 242 243 duck->Wrap(); 244 245 if(stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) { 246 PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n")); 247 return B_ERROR; 248 } 249 250 return B_OK; 251 } 252 253 254 status_t 255 echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf, 256 char** buffer, size_t *stride) 257 { 258 uint8 sample_size, frame_size; 259 LOG(("echo_stream_get_nth_buffer\n")); 260 261 sample_size = stream->bitsPerSample / 8; 262 frame_size = sample_size * stream->channels; 263 264 *buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size) 265 + chan * sample_size; 266 *stride = frame_size; 267 268 return B_OK; 269 } 270 271 272 static uint32 273 echo_stream_curaddr(echo_stream *stream) 274 { 275 uint32 addr = B_LENDIAN_TO_HOST_INT32(*stream->position); 276 // TRACE(("stream_curaddr %p, phy_base %p\n", addr)); 277 return (addr / stream->blksize) % stream->blkmod; 278 } 279 280 281 void 282 echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam) 283 { 284 LOG(("echo_stream_start\n")); 285 ECHOSTATUS status; 286 287 stream->inth = inth; 288 stream->inthparam = inthparam; 289 290 stream->state |= ECHO_STATE_STARTED; 291 292 status = stream->card->pEG->Start(stream->pipe); 293 if (status!=ECHOSTATUS_OK) { 294 PRINT(("echo_stream_start : Could not start the pipe %s\n", pStatusStrs[status])); 295 } 296 } 297 298 void 299 echo_stream_halt(echo_stream *stream) 300 { 301 LOG(("echo_stream_halt\n")); 302 ECHOSTATUS status; 303 304 stream->state &= ~ECHO_STATE_STARTED; 305 306 status = stream->card->pEG->Stop(stream->pipe); 307 if (status!=ECHOSTATUS_OK) { 308 PRINT(("echo_stream_halt : Could not stop the pipe %s\n", pStatusStrs[status])); 309 } 310 } 311 312 echo_stream * 313 echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount) 314 { 315 echo_stream *stream; 316 cpu_status status; 317 LOG(("echo_stream_new\n")); 318 319 stream = (echo_stream *) malloc(sizeof(echo_stream)); 320 if (stream == NULL) 321 return (NULL); 322 stream->card = card; 323 stream->use = use; 324 stream->state = !ECHO_STATE_STARTED; 325 stream->bitsPerSample = 0; 326 stream->sample_rate = 0; 327 stream->channels = 0; 328 stream->bufframes = bufframes; 329 stream->bufcount = bufcount; 330 stream->inth = NULL; 331 stream->inthparam = NULL; 332 stream->buffer = NULL; 333 stream->blksize = 0; 334 stream->trigblk = 0; 335 stream->blkmod = 0; 336 337 stream->pipe = -1; 338 339 stream->frames_count = 0; 340 stream->real_time = 0; 341 stream->update_needed = false; 342 343 status = lock(); 344 LIST_INSERT_HEAD((&card->streams), stream, next); 345 unlock(status); 346 347 return stream; 348 } 349 350 void 351 echo_stream_delete(echo_stream *stream) 352 { 353 cpu_status status; 354 LOG(("echo_stream_delete\n")); 355 356 echo_stream_halt(stream); 357 358 if(stream->buffer) 359 echo_mem_free(stream->card, stream->buffer->log_base); 360 361 status = lock(); 362 LIST_REMOVE(stream, next); 363 unlock(status); 364 365 free(stream); 366 } 367 368 369 /* Echo interrupt */ 370 371 int32 echo_int(void *arg) 372 { 373 echo_dev *card = (echo_dev*)arg; 374 BOOL midiReceived; 375 ECHOSTATUS err; 376 377 echo_stream *stream; 378 uint32 curblk; 379 380 err = card->pEG->ServiceIrq(midiReceived); 381 382 if(err != ECHOSTATUS_OK) { 383 return B_UNHANDLED_INTERRUPT; 384 } 385 386 #ifdef MIDI_SUPPORT 387 if (midiReceived) 388 release_sem(card->midi.midi_ready_sem); 389 #endif 390 391 LIST_FOREACH(stream, &card->streams, next) { 392 if ((stream->state & ECHO_STATE_STARTED) == 0 || 393 (stream->inth == NULL)) 394 continue; 395 396 curblk = echo_stream_curaddr(stream); 397 //TRACE(("echo_int stream %p at trigblk %lu at stream->trigblk %lu\n", 398 // stream, curblk, stream->trigblk)); 399 if (curblk == stream->trigblk) { 400 if(stream->inth) 401 stream->inth(stream->inthparam); 402 403 stream->trigblk++; 404 stream->trigblk %= stream->blkmod; 405 } 406 } 407 408 return B_INVOKE_SCHEDULER; 409 } 410 411 /* dumps card capabilities */ 412 void 413 echo_dump_caps(echo_dev *card) 414 { 415 PECHOGALS_CAPS caps = &card->caps; 416 PRINT(("name: %s\n", caps->szName)); 417 PRINT(("out pipes: %d, in pipes: %d, out busses: %d, in busses: %d, out midi: %d, in midi: %d\n", 418 caps->wNumPipesOut, caps->wNumPipesIn, caps->wNumBussesOut, caps->wNumBussesIn, caps->wNumMidiOut, caps->wNumMidiIn)); 419 420 } 421 422 423 /* detect presence of our hardware */ 424 status_t 425 init_hardware(void) 426 { 427 int ix=0; 428 pci_info info; 429 status_t err = ENODEV; 430 431 LOG_CREATE(); 432 433 PRINT(("init_hardware()\n")); 434 435 if (get_module(pci_name, (module_info **)&pci)) 436 return ENOSYS; 437 438 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 439 440 ushort card_type = info.u.h0.subsystem_id & 0xfff0; 441 442 if (info.vendor_id == VENDOR_ID && 443 ((info.device_id == DEVICE_ID_56301) 444 || (info.device_id == DEVICE_ID_56361)) && 445 (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && 446 ( 447 #ifdef ECHOGALS_FAMILY 448 (card_type == DARLA) 449 || (card_type == GINA) 450 || (card_type == LAYLA) 451 || (card_type == DARLA24) 452 #endif 453 #ifdef ECHO24_FAMILY 454 (card_type == GINA24) 455 || (card_type == LAYLA24) 456 || (card_type == MONA) 457 || (card_type == MIA) 458 #endif 459 #ifdef INDIGO_FAMILY 460 (card_type == INDIGO) 461 || (card_type == INDIGO_IO) 462 || (card_type == INDIGO_DJ) 463 #endif 464 #ifdef ECHO3G_FAMILY 465 (card_type == ECHO3G) 466 #endif 467 )) { 468 err = B_OK; 469 } 470 ix++; 471 } 472 473 put_module(pci_name); 474 475 if(err!=B_OK) { 476 PRINT(("no card found\n")); 477 } 478 479 return err; 480 } 481 482 483 status_t 484 init_driver(void) 485 { 486 int ix=0; 487 488 pci_info info; 489 num_cards = 0; 490 491 PRINT(("init_driver()\n")); 492 load_driver_symbols(DRIVER_NAME); 493 494 if (get_module(pci_name, (module_info **) &pci)) 495 return ENOSYS; 496 497 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 498 ushort card_type = info.u.h0.subsystem_id & 0xfff0; 499 500 if (info.vendor_id == VENDOR_ID && 501 ((info.device_id == DEVICE_ID_56301) 502 || (info.device_id == DEVICE_ID_56361)) && 503 (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && 504 ( 505 #ifdef ECHOGALS_FAMILY 506 (card_type == DARLA) 507 || (card_type == GINA) 508 || (card_type == LAYLA) 509 || (card_type == DARLA24) 510 #endif 511 #ifdef ECHO24_FAMILY 512 (card_type == GINA24) 513 || (card_type == LAYLA24) 514 || (card_type == MONA) 515 || (card_type == MIA) 516 #endif 517 #ifdef INDIGO_FAMILY 518 (card_type == INDIGO) 519 || (card_type == INDIGO_IO) 520 || (card_type == INDIGO_DJ) 521 #endif 522 #ifdef ECHO3G_FAMILY 523 (card_type == ECHO3G) 524 #endif 525 )) { 526 527 if (num_cards == NUM_CARDS) { 528 PRINT(("Too many "DRIVER_NAME" cards installed!\n")); 529 break; 530 } 531 memset(&cards[num_cards], 0, sizeof(echo_dev)); 532 cards[num_cards].info = info; 533 cards[num_cards].type = card_type; 534 if (echo_setup(&cards[num_cards])) { 535 PRINT(("Setup of "DRIVER_NAME" %ld failed\n", num_cards+1)); 536 } 537 else { 538 num_cards++; 539 } 540 } 541 ix++; 542 } 543 if (!num_cards) { 544 PRINT(("no cards\n")); 545 put_module(pci_name); 546 PRINT(("no suitable cards found\n")); 547 return ENODEV; 548 } 549 550 return B_OK; 551 } 552 553 554 static void 555 make_device_names( 556 echo_dev * card) 557 { 558 559 #ifdef MIDI_SUPPORT 560 sprintf(card->midi.name, "midi/"DRIVER_NAME"/%ld", card-cards+1); 561 names[num_names++] = card->midi.name; 562 #endif 563 sprintf(card->name, "audio/multi/"DRIVER_NAME"/%ld", card-cards+1); 564 names[num_names++] = card->name; 565 566 names[num_names] = NULL; 567 } 568 569 570 static status_t 571 echo_setup(echo_dev * card) 572 { 573 status_t err = B_OK; 574 unsigned char cmd; 575 char *name; 576 577 PRINT(("echo_setup(%p)\n", card)); 578 579 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, 580 PCI_latency, 1, 0xc0 ); 581 582 make_device_names(card); 583 584 card->bmbar = card->info.u.h0.base_registers[0]; 585 card->irq = card->info.u.h0.interrupt_line; 586 587 card->pOSS = new COsSupport(card->info.device_id, card->info.revision); 588 if(card->pOSS == NULL) 589 return B_ERROR; 590 591 switch (card->type) { 592 #ifdef ECHOGALS_FAMILY 593 case DARLA: 594 card->pEG = new CDarla(card->pOSS); 595 name = "Echo Darla"; 596 break; 597 case GINA: 598 card->pEG = new CGina(card->pOSS); 599 name = "Echo Gina"; 600 break; 601 case LAYLA: 602 card->pEG = new CLayla(card->pOSS); 603 name = "Echo Layla"; 604 break; 605 case DARLA24: 606 card->pEG = new CDarla24(card->pOSS); 607 name = "Echo Darla24"; 608 break; 609 #endif 610 #ifdef ECHO24_FAMILY 611 case GINA24: 612 card->pEG = new CGina24(card->pOSS); 613 name = "Echo Gina24"; 614 break; 615 case LAYLA24: 616 card->pEG = new CLayla24(card->pOSS); 617 name = "Echo Gina24"; 618 break; 619 case MONA: 620 card->pEG = new CMona(card->pOSS); 621 name = "Echo Mona"; 622 break; 623 case MIA: 624 card->pEG = new CMia(card->pOSS); 625 name = "Echo Mia"; 626 break; 627 #endif 628 #ifdef INDIGO_FAMILY 629 case INDIGO: 630 card->pEG = new CIndigo(card->pOSS); 631 name = "Echo Mia"; 632 break; 633 case INDIGO_IO: 634 card->pEG = new CIndigoIO(card->pOSS); 635 name = "Echo Mia"; 636 break; 637 case INDIGO_DJ: 638 card->pEG = new CIndigoDJ(card->pOSS); 639 name = "Echo Mia"; 640 break; 641 #endif 642 #ifdef ECHO3G_FAMILY 643 case ECHO3G: 644 card->pEG = new C3g(card->pOSS); 645 name = "Echo 3g"; 646 break; 647 #endif 648 default: 649 PRINT(("card type 0x%x not supported by "DRIVER_NAME"\n", card->type)); 650 delete card->pOSS; 651 return B_ERROR; 652 } 653 654 if (card->pEG == NULL) 655 return B_ERROR; 656 657 card->area_bmbar = map_mem(&card->log_bmbar, (void *)card->bmbar, 658 card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io"); 659 if (card->area_bmbar <= B_OK) { 660 LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar)); 661 return B_ERROR; 662 } 663 LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar, card->bmbar, card->log_bmbar)); 664 665 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 666 PRINT(("PCI command before: %x\n", cmd)); 667 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io); 668 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 669 PRINT(("PCI command after: %x\n", cmd)); 670 671 card->pEG->AssignResources(card->log_bmbar, name); 672 673 ECHOSTATUS status; 674 status = card->pEG->InitHw(); 675 if(status != ECHOSTATUS_OK) 676 return B_ERROR; 677 678 card->pEG->GetCapabilities(&card->caps); 679 680 /* Init streams list */ 681 LIST_INIT(&(card->streams)); 682 683 /* Init mems list */ 684 LIST_INIT(&(card->mems)); 685 686 #ifdef MIDI_SUPPORT 687 card->midi.midi_ready_sem = create_sem(0, "midi sem"); 688 #endif 689 690 PRINT(("installing interrupt : %x\n", card->irq)); 691 install_io_interrupt_handler(card->irq, echo_int, card, 0); 692 693 PRINT(("echo_setup done\n")); 694 695 echo_dump_caps(card); 696 697 #ifdef ECHO3G_FAMILY 698 if (card->type == ECHO3G) { 699 strncpy(card->caps.szName, ((C3g*)card->pEG)->Get3gBoxName(), ECHO_MAXNAMELEN); 700 } 701 #endif 702 703 status = card->pEG->OpenMixer(card->mixer); 704 if (status != ECHOSTATUS_OK) 705 return B_ERROR; 706 707 return err; 708 } 709 710 static void 711 echo_shutdown(echo_dev *card) 712 { 713 ECHOSTATUS status; 714 715 PRINT(("shutdown(%p)\n", card)); 716 status = card->pEG->CloseMixer(card->mixer); 717 if (status != ECHOSTATUS_OK) 718 PRINT(("echo_shutdown: error when CloseMixer\n")); 719 720 remove_io_interrupt_handler(card->irq, echo_int, card); 721 722 #ifdef MIDI_SUPPORT 723 delete_sem(card->midi.midi_ready_sem); 724 #endif 725 726 delete card->pEG; 727 delete card->pOSS; 728 729 delete_area(card->area_bmbar); 730 } 731 732 733 734 void 735 uninit_driver(void) 736 { 737 int ix, cnt = num_cards; 738 num_cards = 0; 739 740 PRINT(("uninit_driver()\n")); 741 742 for (ix=0; ix<cnt; ix++) { 743 echo_shutdown(&cards[ix]); 744 } 745 memset(&cards, 0, sizeof(cards)); 746 put_module(pci_name); 747 } 748 749 750 const char ** 751 publish_devices(void) 752 { 753 int ix = 0; 754 PRINT(("publish_devices()\n")); 755 756 for (ix=0; names[ix]; ix++) { 757 PRINT(("publish %s\n", names[ix])); 758 } 759 return (const char **)names; 760 } 761 762 763 device_hooks * 764 find_device(const char * name) 765 { 766 int ix; 767 768 PRINT(("find_device(%s)\n", name)); 769 770 for (ix=0; ix<num_cards; ix++) { 771 #ifdef MIDI_SUPPORT 772 if (!strcmp(cards[ix].midi.name, name)) { 773 return &midi_hooks; 774 } 775 #endif 776 if (!strcmp(cards[ix].name, name)) { 777 return &multi_hooks; 778 } 779 } 780 PRINT(("find_device(%s) failed\n", name)); 781 return NULL; 782 } 783 784 int32 api_version = B_CUR_DRIVER_API_VERSION; 785