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