1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 */ 5 6 #include "cmedia_pci.h" 7 #include "cm_private.h" 8 9 #include <string.h> 10 #include <stdio.h> 11 12 #if !defined(_KERNEL_EXPORT_H) 13 #include <KernelExport.h> 14 #endif 15 16 17 #if DEBUG 18 #define KPRINTF(x) kprintf x 19 #else 20 #define KPRINTF(x) 21 #endif 22 23 EXPORT status_t init_hardware(void); 24 EXPORT status_t init_driver(void); 25 EXPORT void uninit_driver(void); 26 EXPORT const char ** publish_devices(void); 27 EXPORT device_hooks * find_device(const char *); 28 29 30 static char pci_name[] = B_PCI_MODULE_NAME; 31 static pci_module_info *pci; 32 static char gameport_name[] = "generic/gameport/v1"; 33 generic_gameport_module * gameport; 34 static char mpu401_name[] = B_MPU_401_MODULE_NAME; 35 generic_mpu401_module * mpu401; 36 37 #define DO_JOY 1 38 #define DO_MIDI 1 39 #define DO_PCM 1 40 #define DO_MUX 0 41 #define DO_MIXER 0 42 43 #if DO_MIDI 44 extern device_hooks midi_hooks; 45 #endif /* DO_MIDI */ 46 #if DO_JOY 47 extern device_hooks joy_hooks; 48 #endif /* DO_JOY */ 49 #if DO_PCM 50 extern device_hooks pcm_hooks; 51 #endif /* DO_PCM */ 52 #if DO_MUX 53 extern device_hooks mux_hooks; 54 #endif /* DO_MUX */ 55 #if DO_MIXER 56 extern device_hooks mixer_hooks; 57 #endif /* DO_MIXER */ 58 59 60 int32 num_cards; 61 cmedia_pci_dev cards[NUM_CARDS]; 62 int num_names; 63 char * names[NUM_CARDS*7+1]; 64 /* vuchar *io_base; */ 65 66 67 /* ---------- 68 PCI_IO_RD - read a byte from pci i/o space 69 ----- */ 70 71 uint8 72 PCI_IO_RD (int offset) 73 { 74 return (*pci->read_io_8) (offset); 75 } 76 77 78 /* ---------- 79 PCI_IO_RD_32 - read a 32 bit value from pci i/o space 80 ----- */ 81 82 uint32 83 PCI_IO_RD_32 (int offset) 84 { 85 return (*pci->read_io_32) (offset); 86 } 87 /* ---------- 88 PCI_IO_WR - write a byte to pci i/o space 89 ----- */ 90 91 void 92 PCI_IO_WR (int offset, uint8 val) 93 { 94 (*pci->write_io_8) (offset, val); 95 } 96 97 98 /* detect presence of our hardware */ 99 status_t 100 init_hardware(void) 101 { 102 int ix=0; 103 pci_info info; 104 status_t err = ENODEV; 105 106 ddprintf(("cmedia_pci: init_hardware()\n")); 107 108 if (get_module(pci_name, (module_info **)&pci)) 109 return ENOSYS; 110 111 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 112 if (info.vendor_id == CMEDIA_PCI_VENDOR_ID && 113 (info.device_id == CMEDIA_8338A_DEVICE_ID || 114 info.device_id == CMEDIA_8338B_DEVICE_ID || 115 info.device_id == CMEDIA_8738A_DEVICE_ID || 116 info.device_id == CMEDIA_8738B_DEVICE_ID )) { 117 err = B_OK; 118 } 119 ix++; 120 } 121 #if defined(__POWERPC__) && 0 122 { 123 char area_name [32]; 124 area_info area; 125 area_id id; 126 127 sprintf (area_name, "pci_bus%d_isa_io", info.bus); 128 id = find_area (area_name); 129 if (id < 0) 130 err = id; 131 else if ((err = get_area_info (id, &area)) == B_OK) 132 io_base = area.address; 133 } 134 #endif 135 136 put_module(pci_name); 137 138 return err; 139 } 140 141 142 void set_direct( cmedia_pci_dev * card, int regno, uchar value, uchar mask) 143 { 144 if (mask == 0) 145 { 146 return; 147 } 148 if (mask != 0xff) 149 { 150 uchar old = PCI_IO_RD(card->enhanced+regno); 151 value = (value&mask)|(old&~mask); 152 } 153 PCI_IO_WR(card->enhanced+regno, value); 154 ddprintf(("cmedia_pci: CM%02x = %02x\n", regno, value)); 155 } 156 157 158 uchar get_direct(cmedia_pci_dev * card, int regno) 159 { 160 uchar ret = PCI_IO_RD(card->enhanced+regno); 161 return ret; 162 } 163 164 165 166 void set_indirect(cmedia_pci_dev * card, int regno, uchar value, uchar mask) 167 { 168 PCI_IO_WR(card->enhanced+0x23, regno); 169 EIEIO(); 170 if (mask == 0) 171 { 172 return; 173 } 174 if (mask != 0xff) 175 { 176 uchar old = PCI_IO_RD(card->enhanced+0x22); 177 value = (value&mask)|(old&~mask); 178 } 179 PCI_IO_WR(card->enhanced+0x22, value); 180 EIEIO(); 181 ddprintf(("cmedia_pci: CMX%02x = %02x\n", regno, value)); 182 } 183 184 185 186 uchar get_indirect(cmedia_pci_dev * card,int regno) 187 { 188 uchar ret; 189 PCI_IO_WR(card->enhanced+0x23, regno); 190 EIEIO(); 191 ret = PCI_IO_RD(card->enhanced+0x22); 192 return ret; 193 } 194 195 196 #if 0 197 void dump_card(cmedia_pci_dev * card) 198 { 199 int ix; 200 dprintf("\n"); 201 dprintf("CM: "); 202 for (ix=0; ix<6; ix++) { 203 if (ix == 2 || ix == 3) dprintf(" "); 204 else dprintf(" %02x", get_direct(card, ix)); 205 } 206 for (ix=0; ix<0x32; ix++) { 207 if (!(ix & 7)) { 208 dprintf("\nCMX%02x:", ix); 209 } 210 dprintf(" %02x", get_indirect(card, ix)); 211 } 212 dprintf("\n"); 213 dprintf("\n"); 214 } 215 #else 216 void dump_card(cmedia_pci_dev * card) 217 { 218 } 219 #endif 220 221 222 static void 223 disable_card_interrupts(cmedia_pci_dev * card) 224 { 225 set_direct(card, 0x0e, 0x00, 0x03); 226 } 227 228 229 static status_t 230 setup_dma(cmedia_pci_dev * card) 231 { 232 /* we're appropriating some ISA space here... */ 233 /* need kernel support to do it right */ 234 const uint16 base = card->enhanced+0x80; 235 ddprintf(("cmedia_pci: dma base is 0x%04x\n", base)); 236 if(0 == base) 237 return B_DEV_RESOURCE_CONFLICT; 238 card->dma_base = base; 239 return B_OK; 240 } 241 242 243 static void 244 set_default_registers( 245 cmedia_pci_dev * card) 246 { 247 static uchar values[] = { 248 #ifdef DO_JOY 249 0x04, 0x02, 0x02, /* enable joystick */ 250 #endif 251 252 0x0a, 0x01, 0x01, /* enable SPDIF inverse before SPDIF_LOOP */ 253 0x04, 0x80, 0x80, /* enable SPDIF_LOOP */ 254 255 0x1a, 0x00, 0x20, /* SPD32SEL disable */ 256 0x1a, 0x00, 0x10, /* SPDFLOOPI disable */ 257 258 0x1b, 0x04, 0x04, /* dual channel mode enable */ 259 0x1a, 0x00, 0x80, /* Double DAC structure disable */ 260 261 0x24, 0x00, 0x02, /* 3D surround disable */ 262 263 0x24, 0x00, 0x01, /* disable SPDIF_IN PCM to DAC */ 264 #ifdef DO_MIDI 265 0x04, 0x04, 0x04, /* enable MPU-401 */ 266 0x17, 0x00, 0x60, /* default at 0x330 */ 267 #endif 268 }; 269 uchar * ptr = values; 270 271 while (ptr < values+sizeof(values)) { 272 set_direct(card, ptr[0], ptr[1], ptr[2]); 273 ptr += 3; 274 } 275 } 276 277 278 static void 279 make_device_names( 280 cmedia_pci_dev * card) 281 { 282 char * name = card->name; 283 sprintf(name, "cmedia_pci/%ld", card-cards+1); 284 285 #if DO_MIDI 286 sprintf(card->midi.name, "midi/%s", name); 287 names[num_names++] = card->midi.name; 288 #endif /* DO_MIDI */ 289 #if DO_JOY 290 sprintf(card->joy.name1, "joystick/%s", name); 291 names[num_names++] = card->joy.name1; 292 #endif /* DO_JOY */ 293 #if DO_PCM 294 /* cmedia_pci DMA doesn't work when physical NULL isn't NULL from PCI */ 295 /* this is a hack to not export bad devices on BeBox hardware */ 296 if ((*pci->ram_address)(NULL) == NULL) { 297 sprintf(card->pcm.name, "audio/raw/%s", name); 298 names[num_names++] = card->pcm.name; 299 sprintf(card->pcm.oldname, "audio/old/%s", name); 300 names[num_names++] = card->pcm.oldname; 301 } 302 #endif /* DO_PCM */ 303 #if DO_MUX 304 sprintf(card->mux.name, "audio/mux/%s", name); 305 names[num_names++] = card->mux.name; 306 #endif /* DO_MUX */ 307 #if DO_MIXER 308 sprintf(card->mixer.name, "audio/mix/%s", name); 309 names[num_names++] = card->mixer.name; 310 #endif /* DO_MIXER */ 311 names[num_names] = NULL; 312 } 313 314 315 /* We use the SV chip in ISA DMA addressing mode, which is 24 bits */ 316 /* so we need to find suitable, locked, contiguous memory in that */ 317 /* physical address range. */ 318 319 static status_t 320 find_low_memory( 321 cmedia_pci_dev * card) 322 { 323 size_t low_size = (MIN_MEMORY_SIZE+(B_PAGE_SIZE-1))&~(B_PAGE_SIZE-1); 324 physical_entry where; 325 size_t trysize; 326 area_id curarea; 327 void * addr; 328 char name[DEVNAME]; 329 330 sprintf(name, "%s_low", card->name); 331 if (low_size < MIN_MEMORY_SIZE) { 332 low_size = MIN_MEMORY_SIZE; 333 } 334 trysize = low_size; 335 336 curarea = find_area(name); 337 if (curarea >= 0) { /* area there from previous run */ 338 area_info ainfo; 339 ddprintf(("cmedia_pci: testing likely candidate...\n")); 340 if (get_area_info(curarea, &ainfo)) { 341 ddprintf(("cmedia_pci: no info\n")); 342 goto allocate; 343 } 344 /* test area we found */ 345 trysize = ainfo.size; 346 addr = ainfo.address; 347 if (trysize < low_size) { 348 ddprintf(("cmedia_pci: too small (%lx)\n", trysize)); 349 goto allocate; 350 } 351 if (get_memory_map(addr, trysize, &where, 1) < B_OK) { 352 ddprintf(("cmedia_pci: no memory map\n")); 353 goto allocate; 354 } 355 if ((uint32)where.address & 0xff000000) { 356 ddprintf(("cmedia_pci: bad physical address\n")); 357 goto allocate; 358 } 359 if (ainfo.lock < B_FULL_LOCK || where.size < low_size) { 360 ddprintf(("cmedia_pci: lock not contiguous\n")); 361 goto allocate; 362 } 363 dprintf("cmedia_pci: physical %p logical %p\n", where.address, ainfo.address); 364 goto a_o_k; 365 } 366 367 allocate: 368 if (curarea >= 0) { 369 delete_area(curarea); /* area didn't work */ 370 curarea = -1; 371 } 372 ddprintf(("cmedia_pci: allocating new low area\n")); 373 374 curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS, 375 trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA); 376 ddprintf(("cmedia_pci: create_area(%lx) returned %lx logical %p\n", 377 trysize, curarea, addr)); 378 if (curarea < 0) { 379 goto oops; 380 } 381 if (get_memory_map(addr, low_size, &where, 1) < 0) { 382 delete_area(curarea); 383 curarea = B_ERROR; 384 goto oops; 385 } 386 ddprintf(("cmedia_pci: physical %p\n", where.address)); 387 if ((uint32)where.address & 0xff000000) { 388 delete_area(curarea); 389 curarea = B_ERROR; 390 goto oops; 391 } 392 if ((((uint32)where.address)+low_size) & 0xff000000) { 393 delete_area(curarea); 394 curarea = B_ERROR; 395 goto oops; 396 } 397 /* hey, it worked! */ 398 if (trysize > low_size) { /* don't waste */ 399 resize_area(curarea, low_size); 400 } 401 402 oops: 403 if (curarea < 0) { 404 dprintf("cmedia_pci: failed to create low_mem area\n"); 405 return curarea; 406 } 407 a_o_k: 408 ddprintf(("cmedia_pci: successfully found or created low area!\n")); 409 card->low_size = low_size; 410 card->low_mem = addr; 411 card->low_phys = (vuchar *)where.address; 412 card->map_low = curarea; 413 return B_OK; 414 } 415 416 417 static status_t 418 setup_cmedia_pci( 419 cmedia_pci_dev * card) 420 { 421 status_t err = B_OK; 422 /* cpu_status cp; */ 423 424 ddprintf(("cmedia_pci: setup_cmedia_pci(%p)\n", card)); 425 426 if ((card->pcm.init_sem = create_sem(1, "cm pcm init")) < B_OK) 427 goto bail; 428 #if 1 429 if ((*mpu401->create_device)(0x330, &card->midi.driver, 430 #else 431 if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver, 432 #endif 433 0, midi_interrupt_op, &card->midi) < B_OK) 434 goto bail3; 435 #if 1 436 if ((*gameport->create_device)(0x201, &card->joy.driver) < B_OK) 437 #else 438 if ((*gameport->create_device)(card->info.u.h0.base_registers[4], &card->joy.driver) < B_OK) 439 #endif 440 goto bail4; 441 ddprintf(("midi %p gameport %p\n", card->midi.driver, card->joy.driver)); 442 card->midi.card = card; 443 444 err = find_low_memory(card); 445 if (err < B_OK) { 446 goto bail5; 447 } 448 449 //cp = disable_interrupts(); 450 //acquire_spinlock(&card->hardware); 451 452 make_device_names(card); 453 card->enhanced = card->info.u.h0.base_registers[0]; 454 ddprintf(("cmedia_pci: %s enhanced at %x\n", card->name, card->enhanced)); 455 456 ddprintf(("cmedia_pci: revision %x\n", get_indirect(card, 0x15))); 457 458 disable_card_interrupts(card); 459 if (setup_dma(card) != B_OK) 460 { 461 dprintf("cmedia pci: can't setup DMA\n"); 462 goto bail6; 463 } 464 465 set_default_registers(card); 466 467 //release_spinlock(&card->hardware); 468 //restore_interrupts(cp); 469 470 return B_OK; 471 472 bail6: 473 // deallocate low memory 474 bail5: 475 (*gameport->delete_device)(card->joy.driver); 476 bail4: 477 (*mpu401->delete_device)(card->midi.driver); 478 bail3: 479 delete_sem(card->pcm.init_sem); 480 bail: 481 return err < B_OK ? err : B_ERROR; 482 } 483 484 485 static int 486 debug_cmedia( 487 int argc, 488 char * argv[]) 489 { 490 int ix = 0; 491 if (argc == 2) { 492 ix = parse_expression(argv[1])-1; 493 } 494 if (argc > 2 || ix < 0 || ix >= num_cards) { 495 dprintf("cmedia_pci: dude, you gotta watch your syntax!\n"); 496 return -1; 497 } 498 dprintf("%s: enhanced registers at 0x%x\n", cards[ix].name, 499 cards[ix].enhanced); 500 dprintf("%s: open %ld dma_a at 0x%x dma_c 0x%x\n", cards[ix].pcm.name, 501 cards[ix].pcm.open_count, cards[ix].pcm.dma_a, cards[ix].pcm.dma_c); 502 if (cards[ix].pcm.open_count) { 503 dprintf(" dma_a: 0x%lx+0x%lx dma_c: 0x%lx+0x%lx\n", 504 PCI_IO_RD_32((int)cards[ix].pcm.dma_a), PCI_IO_RD_32((int)cards[ix].pcm.dma_a+4), 505 PCI_IO_RD_32((int)cards[ix].pcm.dma_c), PCI_IO_RD_32((int)cards[ix].pcm.dma_c+4)); 506 } 507 return 0; 508 } 509 510 511 status_t 512 init_driver(void) 513 { 514 pci_info info; 515 int ix = 0; 516 517 num_cards = 0; 518 519 ddprintf(("cmedia_pci: init_driver()\n")); 520 521 if (get_module(pci_name, (module_info **)&pci)) 522 return ENOSYS; 523 524 if (get_module(gameport_name, (module_info **)&gameport)) { 525 put_module(pci_name); 526 return ENOSYS; 527 } 528 ddprintf(("MPU\n")); 529 if (get_module(mpu401_name, (module_info **) &mpu401)) { 530 put_module(gameport_name); 531 put_module(pci_name); 532 return ENOSYS; 533 } 534 535 ddprintf(("MPU: %p\n", mpu401)); 536 537 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 538 if (info.vendor_id == CMEDIA_PCI_VENDOR_ID && 539 (info.device_id == CMEDIA_8338A_DEVICE_ID || 540 info.device_id == CMEDIA_8338B_DEVICE_ID || 541 info.device_id == CMEDIA_8738A_DEVICE_ID || 542 info.device_id == CMEDIA_8738B_DEVICE_ID )) { 543 if (num_cards == NUM_CARDS) { 544 dprintf("Too many C-Media cards installed!\n"); 545 break; 546 } 547 memset(&cards[num_cards], 0, sizeof(cmedia_pci_dev)); 548 cards[num_cards].info = info; 549 if (setup_cmedia_pci(&cards[num_cards])) { 550 dprintf("Setup of C-Media %ld failed\n", num_cards+1); 551 } 552 else { 553 num_cards++; 554 } 555 } 556 ix++; 557 } 558 if (!num_cards) { 559 KPRINTF(("no cards\n")); 560 put_module(mpu401_name); 561 put_module(gameport_name); 562 put_module(pci_name); 563 ddprintf(("cmedia_pci: no suitable cards found\n")); 564 return ENODEV; 565 } 566 567 #if DEBUG 568 add_debugger_command("cmedia", debug_cmedia, "cmedia [card# (1-n)]"); 569 #endif 570 return B_OK; 571 } 572 573 574 static void 575 teardown_cmedia_pci( 576 cmedia_pci_dev * card) 577 { 578 static uchar regs[] = { 579 #ifdef DO_JOY 580 0x04, 0x00, 0x02, /* enable joystick */ 581 #endif 582 #ifdef DO_MIDI 583 0x04, 0x00, 0x04, /* enable MPU-401 */ 584 #endif 585 }; 586 uchar * ptr = regs; 587 cpu_status cp; 588 589 /* remove created devices */ 590 (*gameport->delete_device)(card->joy.driver); 591 (*mpu401->delete_device)(card->midi.driver); 592 593 cp = disable_interrupts(); 594 acquire_spinlock(&card->hardware); 595 596 while (ptr < regs+sizeof(regs)) { 597 set_direct(card, ptr[0], ptr[1], ptr[2]); 598 ptr += 3; 599 } 600 disable_card_interrupts(card); 601 602 release_spinlock(&card->hardware); 603 restore_interrupts(cp); 604 605 delete_sem(card->pcm.init_sem); 606 } 607 608 609 void 610 uninit_driver(void) 611 { 612 int ix, cnt = num_cards; 613 num_cards = 0; 614 615 ddprintf(("cmedia_pci: uninit_driver()\n")); 616 remove_debugger_command("cmedia", debug_cmedia); 617 618 for (ix=0; ix<cnt; ix++) { 619 teardown_cmedia_pci(&cards[ix]); 620 } 621 memset(&cards, 0, sizeof(cards)); 622 put_module(mpu401_name); 623 put_module(gameport_name); 624 put_module(pci_name); 625 } 626 627 628 const char ** 629 publish_devices(void) 630 { 631 int ix = 0; 632 ddprintf(("cmedia_pci: publish_devices()\n")); 633 634 for (ix=0; names[ix]; ix++) { 635 ddprintf(("cmedia_pci: publish %s\n", names[ix])); 636 } 637 return (const char **)names; 638 } 639 640 641 device_hooks * 642 find_device( 643 const char * name) 644 { 645 int ix; 646 647 ddprintf(("cmedia_pci: find_device(%s)\n", name)); 648 649 for (ix=0; ix<num_cards; ix++) { 650 #if DO_MIDI 651 if (!strcmp(cards[ix].midi.name, name)) { 652 return &midi_hooks; 653 } 654 #endif /* DO_MIDI */ 655 #if DO_JOY 656 if (!strcmp(cards[ix].joy.name1, name)) { 657 return &joy_hooks; 658 } 659 #endif /* DO_JOY */ 660 #if DO_PCM 661 if (!strcmp(cards[ix].pcm.name, name)) { 662 return &pcm_hooks; 663 } 664 if (!strcmp(cards[ix].pcm.oldname, name)) { 665 return &pcm_hooks; 666 } 667 #endif /* DO_PCM */ 668 #if DO_MUX 669 if (!strcmp(cards[ix].mux.name, name)) { 670 return &mux_hooks; 671 } 672 673 #endif /* DO_MUX */ 674 #if DO_MIXER 675 if (!strcmp(cards[ix].mixer.name, name)) { 676 return &mixer_hooks; 677 } 678 #endif /* DO_MIXER */ 679 } 680 ddprintf(("cmedia_pci: find_device(%s) failed\n", name)); 681 return NULL; 682 } 683 684 int32 api_version = B_CUR_DRIVER_API_VERSION; 685 686 static int32 687 cmedia_pci_interrupt( 688 void * data) 689 { 690 cpu_status cp = disable_interrupts(); 691 cmedia_pci_dev * card = (cmedia_pci_dev *)data; 692 uchar status; 693 int32 handled = B_UNHANDLED_INTERRUPT; 694 695 /* KTRACE(); / * */ 696 acquire_spinlock(&card->hardware); 697 698 status = get_direct(card, 0x10); 699 700 #if DEBUG 701 /* kprintf("%x\n", status); / * */ 702 #endif 703 #if DO_PCM 704 if (status & 0x02) { 705 if (dma_c_interrupt(card)) { 706 handled = B_INVOKE_SCHEDULER; 707 } 708 else { 709 handled = B_HANDLED_INTERRUPT; 710 } 711 /* acknowledge interrupt */ 712 set_direct(card, 0x0e, 0x00, 0x02); 713 set_direct(card, 0x0e, 0x02, 0x02); 714 } 715 if (status & 0x01) { 716 if (dma_a_interrupt(card)) { 717 handled = B_INVOKE_SCHEDULER; 718 } 719 else { 720 handled = B_HANDLED_INTERRUPT; 721 } 722 /* acknowledge interrupt */ 723 set_direct(card, 0x0e, 0x00, 0x01); 724 set_direct(card, 0x0e, 0x01, 0x01); 725 } 726 #endif 727 #if DO_MIDI 728 status = get_direct(card, 0x12); 729 if (status & 0x01) { 730 if (midi_interrupt(card)) { 731 handled = B_INVOKE_SCHEDULER; 732 } else { 733 handled = B_HANDLED_INTERRUPT; 734 } 735 } 736 #endif 737 738 /* Sometimes, the Sonic Vibes will receive a byte of Midi data... 739 ** And duly note it in the MPU401 status register... 740 ** And generate an interrupt... 741 ** But not bother setting the midi interrupt bit in the ISR. 742 ** Thanks a lot, S3. 743 */ 744 if(handled == B_UNHANDLED_INTERRUPT){ 745 if (midi_interrupt(card)) { 746 handled = B_INVOKE_SCHEDULER; 747 } 748 } 749 750 /* KTRACE(); / * */ 751 release_spinlock(&card->hardware); 752 restore_interrupts(cp); 753 754 return handled; 755 // return (handled == B_INVOKE_SCHEDULER) ? B_HANDLED_INTERRUPT : handled; 756 } 757 758 759 void 760 increment_interrupt_handler( 761 cmedia_pci_dev * card) 762 { 763 KPRINTF(("cmedia_pci: increment_interrupt_handler()\n")); 764 if (atomic_add(&card->inth_count, 1) == 0) { 765 // !!! 766 KPRINTF(("cmedia_pci: intline %d int %p\n", card->info.u.h0.interrupt_line, cmedia_pci_interrupt)); 767 install_io_interrupt_handler(card->info.u.h0.interrupt_line, 768 cmedia_pci_interrupt, card, 0); 769 } 770 } 771 772 773 void 774 decrement_interrupt_handler( 775 cmedia_pci_dev * card) 776 { 777 KPRINTF(("cmedia_pci: decrement_interrupt_handler()\n")); 778 if (atomic_add(&card->inth_count, -1) == 1) { 779 KPRINTF(("cmedia_pci: remove_io_interrupt_handler()\n")); 780 remove_io_interrupt_handler(card->info.u.h0.interrupt_line, cmedia_pci_interrupt, card); 781 } 782 } 783 784 785