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 "CDarla24.h" 32 #include "CDarla.h" 33 #include "CGina.h" 34 #include "CGina24.h" 35 #include "CLayla.h" 36 #include "CLayla24.h" 37 #include "CMia.h" 38 #include "CMona.h" 39 #include "echo.h" 40 #include "debug.h" 41 #include "util.h" 42 43 static char pci_name[] = B_PCI_MODULE_NAME; 44 static pci_module_info *pci; 45 int32 num_cards; 46 echo_dev cards[NUM_CARDS]; 47 int32 num_names; 48 char * names[NUM_CARDS*20+1]; 49 50 extern device_hooks multi_hooks; 51 52 int32 echo_int(void *arg); 53 status_t init_hardware(void); 54 status_t init_driver(void); 55 static void make_device_names(echo_dev * card); 56 57 static status_t echo_setup(echo_dev * card); 58 static void echo_shutdown(echo_dev *card); 59 60 void uninit_driver(void); 61 const char ** publish_devices(void); 62 device_hooks * find_device(const char * name); 63 64 65 /* Echo Memory management */ 66 67 echo_mem * 68 echo_mem_new(echo_dev *card, size_t size) 69 { 70 echo_mem *mem; 71 72 if ((mem = (echo_mem *) malloc(sizeof(*mem))) == NULL) 73 return (NULL); 74 75 mem->area = alloc_mem(&mem->phy_base, &mem->log_base, size, "echo buffer"); 76 mem->size = size; 77 if (mem->area < B_OK) { 78 free(mem); 79 return NULL; 80 } 81 return mem; 82 } 83 84 void 85 echo_mem_delete(echo_mem *mem) 86 { 87 if(mem->area > B_OK) 88 delete_area(mem->area); 89 free(mem); 90 } 91 92 echo_mem * 93 echo_mem_alloc(echo_dev *card, size_t size) 94 { 95 echo_mem *mem; 96 97 mem = echo_mem_new(card, size); 98 if (mem == NULL) 99 return (NULL); 100 101 LIST_INSERT_HEAD(&(card->mems), mem, next); 102 103 return mem; 104 } 105 106 void 107 echo_mem_free(echo_dev *card, void *ptr) 108 { 109 echo_mem *mem; 110 111 LIST_FOREACH(mem, &card->mems, next) { 112 if (mem->log_base != ptr) 113 continue; 114 LIST_REMOVE(mem, next); 115 116 echo_mem_delete(mem); 117 break; 118 } 119 } 120 121 /* Echo stream functions */ 122 123 extern char * pStatusStrs[ECHOSTATUS_LAST]; 124 125 status_t 126 echo_stream_set_audioparms(echo_stream *stream, uint8 channels, 127 uint8 bitsPerSample, uint32 sample_rate) 128 { 129 int32 i; 130 uint8 sample_size, frame_size; 131 ECHOGALS_OPENAUDIOPARAMETERS open_params; 132 ECHOGALS_CLOSEAUDIOPARAMETERS close_params; 133 ECHOGALS_AUDIOFORMAT format_params; 134 ECHOSTATUS status; 135 136 LOG(("echo_stream_set_audioparms\n")); 137 138 close_params.wPipeIndex = stream->pipe; 139 status = stream->card->pEG->CloseAudio(&close_params); 140 if(status!=ECHOSTATUS_OK && status!=ECHOSTATUS_CHANNEL_NOT_OPEN) { 141 PRINT(("echo_stream_set_audioparms : CloseAudio failed\n")); 142 PRINT((" status: %s \n", pStatusStrs[status])); 143 return B_ERROR; 144 } 145 146 open_params.bIsCyclic = TRUE; 147 open_params.Pipe.nPipe = 0; 148 open_params.Pipe.bIsInput = stream->use == ECHO_USE_RECORD ? TRUE : FALSE; 149 open_params.Pipe.wInterleave = channels; 150 open_params.ProcessId = NULL; 151 152 status = stream->card->pEG->OpenAudio(&open_params, &stream->pipe); 153 if(status!=ECHOSTATUS_OK) { 154 PRINT(("echo_stream_set_audioparms : OpenAudio failed\n")); 155 PRINT((" status: %s \n", pStatusStrs[status])); 156 return B_ERROR; 157 } 158 159 //PRINT(("VerifyAudioOpen\n")); 160 status = stream->card->pEG->VerifyAudioOpen(stream->pipe); 161 if(status!=ECHOSTATUS_OK) { 162 PRINT(("echo_stream_set_audioparms : VerifyAudioOpen failed\n")); 163 PRINT((" status: %s \n", pStatusStrs[status])); 164 return B_ERROR; 165 } 166 167 if ((stream->channels == channels) && 168 (stream->bitsPerSample == bitsPerSample) && 169 (stream->sample_rate == sample_rate)) 170 return B_OK; 171 172 format_params.wBitsPerSample = bitsPerSample; 173 format_params.byDataAreBigEndian = 0; 174 format_params.byMonoToStereo = 0; 175 format_params.wDataInterleave = channels == 1 ? 1 : 2; 176 177 status = stream->card->pEG->QueryAudioFormat(stream->pipe, &format_params); 178 if(status!=ECHOSTATUS_OK) { 179 PRINT(("echo_stream_set_audioparms : bad format when querying\n")); 180 PRINT((" status: %s \n", pStatusStrs[status])); 181 return B_ERROR; 182 } 183 184 status = stream->card->pEG->SetAudioFormat(stream->pipe, &format_params); 185 if(status!=ECHOSTATUS_OK) { 186 PRINT(("echo_stream_set_audioparms : bad format when setting\n")); 187 PRINT((" status: %s \n", pStatusStrs[status])); 188 return B_ERROR; 189 } 190 191 /* XXXX : setting sample rate is global in this driver */ 192 status = stream->card->pEG->QueryAudioSampleRate(sample_rate); 193 if(status!=ECHOSTATUS_OK) { 194 PRINT(("echo_stream_set_audioparms : bad sample rate when querying\n")); 195 PRINT((" status: %s \n", pStatusStrs[status])); 196 return B_ERROR; 197 } 198 199 /* XXXX : setting sample rate is global in this driver */ 200 status = stream->card->pEG->SetAudioSampleRate(sample_rate); 201 if(status!=ECHOSTATUS_OK) { 202 PRINT(("echo_stream_set_audioparms : bad sample rate when setting\n")); 203 PRINT((" status: %s \n", pStatusStrs[status])); 204 return B_ERROR; 205 } 206 207 if(stream->buffer) 208 echo_mem_free(stream->card, stream->buffer->log_base); 209 210 stream->bitsPerSample = bitsPerSample; 211 stream->sample_rate = sample_rate; 212 stream->channels = channels; 213 214 sample_size = stream->bitsPerSample / 8; 215 frame_size = sample_size * stream->channels; 216 217 stream->buffer = echo_mem_alloc(stream->card, stream->bufframes * frame_size * stream->bufcount); 218 219 stream->trigblk = 1; 220 stream->blkmod = stream->bufcount; 221 stream->blksize = stream->bufframes * frame_size; 222 223 CDaffyDuck *duck = stream->card->pEG->GetDaffyDuck(stream->pipe); 224 if(duck == NULL) { 225 PRINT(("echo_stream_set_audioparms : Could not get daffy duck pointer\n")); 226 return B_ERROR; 227 } 228 229 uint32 dwNumFreeEntries = 0; 230 231 for(i=0; i<stream->bufcount; i++) { 232 duck->AddMapping(((uint32)stream->buffer->phy_base) + 233 i * stream->blksize, stream->blksize, 0, TRUE, dwNumFreeEntries); 234 } 235 236 duck->Wrap(); 237 238 if(stream->card->pEG->GetAudioPositionPtr(stream->pipe, stream->position)!=ECHOSTATUS_OK) { 239 PRINT(("echo_stream_set_audioparms : Could not get audio position ptr\n")); 240 return B_ERROR; 241 } 242 243 return B_OK; 244 } 245 246 247 status_t 248 echo_stream_get_nth_buffer(echo_stream *stream, uint8 chan, uint8 buf, 249 char** buffer, size_t *stride) 250 { 251 uint8 sample_size, frame_size; 252 LOG(("echo_stream_get_nth_buffer\n")); 253 254 sample_size = stream->bitsPerSample / 8; 255 frame_size = sample_size * stream->channels; 256 257 *buffer = (char*)stream->buffer->log_base + (buf * stream->bufframes * frame_size) 258 + chan * sample_size; 259 *stride = frame_size; 260 261 return B_OK; 262 } 263 264 265 static uint32 266 echo_stream_curaddr(echo_stream *stream) 267 { 268 uint32 addr = B_LENDIAN_TO_HOST_INT32(*stream->position); 269 // TRACE(("stream_curaddr %p, phy_base %p\n", addr)); 270 return (addr / stream->blksize) % stream->blkmod; 271 } 272 273 274 void 275 echo_stream_start(echo_stream *stream, void (*inth) (void *), void *inthparam) 276 { 277 LOG(("echo_stream_start\n")); 278 279 stream->inth = inth; 280 stream->inthparam = inthparam; 281 282 stream->state |= ECHO_STATE_STARTED; 283 284 if(stream->card->pEG->Start(stream->pipe)!=ECHOSTATUS_OK) { 285 PRINT(("echo_stream_start : Could not start the pipe\n")); 286 } 287 } 288 289 void 290 echo_stream_halt(echo_stream *stream) 291 { 292 LOG(("echo_stream_halt\n")); 293 294 stream->state &= ~ECHO_STATE_STARTED; 295 296 if(stream->card->pEG->Stop(stream->pipe)!=ECHOSTATUS_OK) { 297 PRINT(("echo_stream_halt : Could not stop the pipe\n")); 298 } 299 } 300 301 echo_stream * 302 echo_stream_new(echo_dev *card, uint8 use, uint32 bufframes, uint8 bufcount) 303 { 304 echo_stream *stream; 305 cpu_status status; 306 LOG(("echo_stream_new\n")); 307 308 stream = (echo_stream *) malloc(sizeof(echo_stream)); 309 if (stream == NULL) 310 return (NULL); 311 stream->card = card; 312 stream->use = use; 313 stream->state = !ECHO_STATE_STARTED; 314 stream->bitsPerSample = 0; 315 stream->sample_rate = 0; 316 stream->channels = 0; 317 stream->bufframes = bufframes; 318 stream->bufcount = bufcount; 319 stream->inth = NULL; 320 stream->inthparam = NULL; 321 stream->buffer = NULL; 322 stream->blksize = 0; 323 stream->trigblk = 0; 324 stream->blkmod = 0; 325 326 stream->pipe = card->pEG->MakePipeIndex(0, (use == ECHO_USE_RECORD)); 327 328 stream->frames_count = 0; 329 stream->real_time = 0; 330 stream->update_needed = false; 331 332 status = lock(); 333 LIST_INSERT_HEAD((&card->streams), stream, next); 334 unlock(status); 335 336 return stream; 337 } 338 339 void 340 echo_stream_delete(echo_stream *stream) 341 { 342 cpu_status status; 343 LOG(("echo_stream_delete\n")); 344 345 echo_stream_halt(stream); 346 347 if(stream->buffer) 348 echo_mem_free(stream->card, stream->buffer->log_base); 349 350 status = lock(); 351 LIST_REMOVE(stream, next); 352 unlock(status); 353 354 free(stream); 355 } 356 357 358 /* Echo interrupt */ 359 360 int32 echo_int(void *arg) 361 { 362 echo_dev *card = (echo_dev*)arg; 363 BOOL midiReceived; 364 ECHOSTATUS err; 365 366 echo_stream *stream; 367 uint32 curblk; 368 369 err = card->pEG->ServiceIrq(midiReceived); 370 371 if(err != ECHOSTATUS_OK) { 372 return B_UNHANDLED_INTERRUPT; 373 } 374 375 LIST_FOREACH(stream, &card->streams, next) { 376 if ((stream->state & ECHO_STATE_STARTED) == 0 || 377 (stream->inth == NULL)) 378 continue; 379 380 curblk = echo_stream_curaddr(stream); 381 //TRACE(("echo_int stream %p at trigblk %lu at stream->trigblk %lu\n", 382 // stream, curblk, stream->trigblk)); 383 if (curblk == stream->trigblk) { 384 if(stream->inth) 385 stream->inth(stream->inthparam); 386 387 stream->trigblk++; 388 stream->trigblk %= stream->blkmod; 389 } 390 } 391 392 return B_INVOKE_SCHEDULER; 393 } 394 395 /* detect presence of our hardware */ 396 status_t 397 init_hardware(void) 398 { 399 int ix=0; 400 pci_info info; 401 status_t err = ENODEV; 402 403 LOG_CREATE(); 404 405 PRINT(("init_hardware()\n")); 406 407 if (get_module(pci_name, (module_info **)&pci)) 408 return ENOSYS; 409 410 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 411 412 ushort card_type = info.u.h0.subsystem_id & 0xfff0; 413 414 if (info.vendor_id == VENDOR_ID && 415 ((info.device_id == DEVICE_ID_56301) 416 || (info.device_id == DEVICE_ID_56361)) && 417 (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && 418 ( 419 #ifdef ECHOGALS_FAMILY 420 (card_type == DARLA) 421 || (card_type == GINA) 422 || (card_type == LAYLA) 423 || (card_type == DARLA24) 424 #endif 425 #ifdef ECHO24_FAMILY 426 (card_type == GINA24) 427 || (card_type == LAYLA24) 428 || (card_type == MONA) 429 || (card_type == MIA) 430 || (card_type == INDIGO) 431 #endif 432 )) { 433 err = B_OK; 434 } 435 ix++; 436 } 437 438 put_module(pci_name); 439 440 if(err!=B_OK) { 441 PRINT(("no card found\n")); 442 } 443 444 return err; 445 } 446 447 448 status_t 449 init_driver(void) 450 { 451 int ix=0; 452 453 pci_info info; 454 num_cards = 0; 455 456 PRINT(("init_driver()\n")); 457 load_driver_symbols(DRIVER_NAME); 458 459 if (get_module(pci_name, (module_info **) &pci)) 460 return ENOSYS; 461 462 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 463 ushort card_type = info.u.h0.subsystem_id & 0xfff0; 464 465 if (info.vendor_id == VENDOR_ID && 466 ((info.device_id == DEVICE_ID_56301) 467 || (info.device_id == DEVICE_ID_56361)) && 468 (info.u.h0.subsystem_vendor_id == SUBVENDOR_ID) && 469 ( 470 #ifdef ECHOGALS_FAMILY 471 (card_type == DARLA) 472 || (card_type == GINA) 473 || (card_type == LAYLA) 474 || (card_type == DARLA24) 475 #endif 476 #ifdef ECHO24_FAMILY 477 (card_type == GINA24) 478 || (card_type == LAYLA24) 479 || (card_type == MONA) 480 || (card_type == MIA) 481 || (card_type == INDIGO) 482 #endif 483 )) { 484 485 if (num_cards == NUM_CARDS) { 486 PRINT(("Too many "DRIVER_NAME" cards installed!\n")); 487 break; 488 } 489 memset(&cards[num_cards], 0, sizeof(echo_dev)); 490 cards[num_cards].info = info; 491 cards[num_cards].type = card_type; 492 if (echo_setup(&cards[num_cards])) { 493 PRINT(("Setup of "DRIVER_NAME" %ld failed\n", num_cards+1)); 494 } 495 else { 496 num_cards++; 497 } 498 } 499 ix++; 500 } 501 if (!num_cards) { 502 PRINT(("no cards\n")); 503 put_module(pci_name); 504 PRINT(("no suitable cards found\n")); 505 return ENODEV; 506 } 507 508 return B_OK; 509 } 510 511 512 static void 513 make_device_names( 514 echo_dev * card) 515 { 516 sprintf(card->name, "audio/multi/"DRIVER_NAME"/%ld", card-cards+1); 517 names[num_names++] = card->name; 518 519 names[num_names] = NULL; 520 } 521 522 523 static status_t 524 echo_setup(echo_dev * card) 525 { 526 status_t err = B_OK; 527 unsigned char cmd; 528 529 PRINT(("echo_setup(%p)\n", card)); 530 531 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, 532 PCI_latency, 1, 0xc0 ); 533 534 make_device_names(card); 535 536 card->bmbar = card->info.u.h0.base_registers[0]; 537 card->irq = card->info.u.h0.interrupt_line; 538 539 card->pOSS = new COsSupport(card->info.device_id); 540 if(card->pOSS == NULL) 541 return B_ERROR; 542 543 switch (card->type) { 544 #ifdef ECHOGALS_FAMILY 545 case DARLA: 546 card->pEG = new CDarla(card->pOSS); 547 break; 548 case GINA: 549 card->pEG = new CGina(card->pOSS); 550 break; 551 case LAYLA: 552 card->pEG = new CLayla(card->pOSS); 553 break; 554 case DARLA24: 555 card->pEG = new CDarla24(card->pOSS); 556 break; 557 #endif 558 #ifdef ECHO24_FAMILY 559 case GINA24: 560 card->pEG = new CGina24(card->pOSS); 561 break; 562 case LAYLA24: 563 card->pEG = new CLayla24(card->pOSS); 564 break; 565 case MONA: 566 card->pEG = new CMona(card->pOSS); 567 break; 568 case MIA: 569 card->pEG = new CMia(card->pOSS); 570 break; 571 #endif 572 default: 573 PRINT(("card type 0x%x not supported by "DRIVER_NAME"\n", card->type)); 574 delete card->pOSS; 575 return B_ERROR; 576 } 577 578 if (card->pEG == NULL) 579 return B_ERROR; 580 581 card->area_bmbar = map_mem(&card->log_bmbar, (void *)card->bmbar, 582 card->info.u.h0.base_register_sizes[0], DRIVER_NAME" bmbar io"); 583 if (card->area_bmbar <= B_OK) { 584 LOG(("mapping of bmbar io failed, error = %#x\n",card->area_bmbar)); 585 return B_ERROR; 586 } 587 LOG(("mapping of bmbar: area %#x, phys %#x, log %#x\n", card->area_bmbar, card->bmbar, card->log_bmbar)); 588 589 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 590 PRINT(("PCI command before: %x\n", cmd)); 591 (*pci->write_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2, cmd | PCI_command_io); 592 cmd = (*pci->read_pci_config)(card->info.bus, card->info.device, card->info.function, PCI_command, 2); 593 PRINT(("PCI command after: %x\n", cmd)); 594 595 card->pEG->AssignResources(card->log_bmbar, "no name"); 596 597 ECHOSTATUS status; 598 status = card->pEG->InitHw(); 599 if(status != ECHOSTATUS_OK) 600 return B_ERROR; 601 602 /* Init streams list */ 603 LIST_INIT(&(card->streams)); 604 605 /* Init mems list */ 606 LIST_INIT(&(card->mems)); 607 608 PRINT(("installing interrupt : %x\n", card->irq)); 609 install_io_interrupt_handler(card->irq, echo_int, card, 0); 610 611 PRINT(("echo_setup done\n")); 612 613 return err; 614 } 615 616 static void 617 echo_shutdown(echo_dev *card) 618 { 619 PRINT(("shutdown(%p)\n", card)); 620 remove_io_interrupt_handler(card->irq, echo_int, card); 621 622 delete card->pEG; 623 delete card->pOSS; 624 625 delete_area(card->area_bmbar); 626 } 627 628 629 630 void 631 uninit_driver(void) 632 { 633 int ix, cnt = num_cards; 634 num_cards = 0; 635 636 PRINT(("uninit_driver()\n")); 637 638 for (ix=0; ix<cnt; ix++) { 639 echo_shutdown(&cards[ix]); 640 } 641 memset(&cards, 0, sizeof(cards)); 642 put_module(pci_name); 643 } 644 645 646 const char ** 647 publish_devices(void) 648 { 649 int ix = 0; 650 PRINT(("publish_devices()\n")); 651 652 for (ix=0; names[ix]; ix++) { 653 PRINT(("publish %s\n", names[ix])); 654 } 655 return (const char **)names; 656 } 657 658 659 device_hooks * 660 find_device(const char * name) 661 { 662 int ix; 663 664 PRINT(("find_device(%s)\n", name)); 665 666 for (ix=0; ix<num_cards; ix++) { 667 if (!strcmp(cards[ix].name, name)) { 668 return &multi_hooks; 669 } 670 } 671 PRINT(("find_device(%s) failed\n", name)); 672 return NULL; 673 } 674 675 int32 api_version = B_CUR_DRIVER_API_VERSION; 676