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 ((where.address & ~(phys_addr_t)0xffffff) != 0) { 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 %#" B_PRIxPHYSADDR " logical %p\n", 364 where.address, ainfo.address); 365 goto a_o_k; 366 } 367 368 allocate: 369 if (curarea >= 0) { 370 delete_area(curarea); /* area didn't work */ 371 curarea = -1; 372 } 373 ddprintf(("cmedia_pci: allocating new low area\n")); 374 375 curarea = create_area(name, &addr, B_ANY_KERNEL_ADDRESS, 376 trysize, B_LOMEM, B_READ_AREA | B_WRITE_AREA); 377 ddprintf(("cmedia_pci: create_area(%lx) returned %lx logical %p\n", 378 trysize, curarea, addr)); 379 if (curarea < 0) { 380 goto oops; 381 } 382 if (get_memory_map(addr, low_size, &where, 1) < 0) { 383 delete_area(curarea); 384 curarea = B_ERROR; 385 goto oops; 386 } 387 ddprintf(("cmedia_pci: physical %p\n", where.address)); 388 if ((where.address & ~(phys_addr_t)0xffffff) != 0) { 389 delete_area(curarea); 390 curarea = B_ERROR; 391 goto oops; 392 } 393 if (((where.address + low_size) & ~(phys_addr_t)0xffffff) != 0) { 394 delete_area(curarea); 395 curarea = B_ERROR; 396 goto oops; 397 } 398 /* hey, it worked! */ 399 if (trysize > low_size) { /* don't waste */ 400 resize_area(curarea, low_size); 401 } 402 403 oops: 404 if (curarea < 0) { 405 dprintf("cmedia_pci: failed to create low_mem area\n"); 406 return curarea; 407 } 408 a_o_k: 409 ddprintf(("cmedia_pci: successfully found or created low area!\n")); 410 card->low_size = low_size; 411 card->low_mem = addr; 412 card->low_phys = (vuchar *)(addr_t)where.address; 413 card->map_low = curarea; 414 return B_OK; 415 } 416 417 418 static status_t 419 setup_cmedia_pci( 420 cmedia_pci_dev * card) 421 { 422 status_t err = B_OK; 423 /* cpu_status cp; */ 424 425 ddprintf(("cmedia_pci: setup_cmedia_pci(%p)\n", card)); 426 427 if ((card->pcm.init_sem = create_sem(1, "cm pcm init")) < B_OK) 428 goto bail; 429 #if 1 430 if ((*mpu401->create_device)(0x330, &card->midi.driver, 431 #else 432 if ((*mpu401->create_device)(card->info.u.h0.base_registers[3], &card->midi.driver, 433 #endif 434 0, midi_interrupt_op, &card->midi) < B_OK) 435 goto bail3; 436 #if 1 437 if ((*gameport->create_device)(0x201, &card->joy.driver) < B_OK) 438 #else 439 if ((*gameport->create_device)(card->info.u.h0.base_registers[4], &card->joy.driver) < B_OK) 440 #endif 441 goto bail4; 442 ddprintf(("midi %p gameport %p\n", card->midi.driver, card->joy.driver)); 443 card->midi.card = card; 444 445 err = find_low_memory(card); 446 if (err < B_OK) { 447 goto bail5; 448 } 449 450 //cp = disable_interrupts(); 451 //acquire_spinlock(&card->hardware); 452 453 make_device_names(card); 454 card->enhanced = card->info.u.h0.base_registers[0]; 455 ddprintf(("cmedia_pci: %s enhanced at %x\n", card->name, card->enhanced)); 456 457 ddprintf(("cmedia_pci: revision %x\n", get_indirect(card, 0x15))); 458 459 disable_card_interrupts(card); 460 if (setup_dma(card) != B_OK) 461 { 462 dprintf("cmedia pci: can't setup DMA\n"); 463 goto bail6; 464 } 465 466 set_default_registers(card); 467 468 //release_spinlock(&card->hardware); 469 //restore_interrupts(cp); 470 471 return B_OK; 472 473 bail6: 474 // deallocate low memory 475 bail5: 476 (*gameport->delete_device)(card->joy.driver); 477 bail4: 478 (*mpu401->delete_device)(card->midi.driver); 479 bail3: 480 delete_sem(card->pcm.init_sem); 481 bail: 482 return err < B_OK ? err : B_ERROR; 483 } 484 485 486 static int 487 debug_cmedia( 488 int argc, 489 char * argv[]) 490 { 491 int ix = 0; 492 if (argc == 2) { 493 ix = parse_expression(argv[1])-1; 494 } 495 if (argc > 2 || ix < 0 || ix >= num_cards) { 496 dprintf("cmedia_pci: dude, you gotta watch your syntax!\n"); 497 return -1; 498 } 499 dprintf("%s: enhanced registers at 0x%x\n", cards[ix].name, 500 cards[ix].enhanced); 501 dprintf("%s: open %ld dma_a at 0x%x dma_c 0x%x\n", cards[ix].pcm.name, 502 cards[ix].pcm.open_count, cards[ix].pcm.dma_a, cards[ix].pcm.dma_c); 503 if (cards[ix].pcm.open_count) { 504 dprintf(" dma_a: 0x%lx+0x%lx dma_c: 0x%lx+0x%lx\n", 505 PCI_IO_RD_32((int)cards[ix].pcm.dma_a), PCI_IO_RD_32((int)cards[ix].pcm.dma_a+4), 506 PCI_IO_RD_32((int)cards[ix].pcm.dma_c), PCI_IO_RD_32((int)cards[ix].pcm.dma_c+4)); 507 } 508 return 0; 509 } 510 511 512 status_t 513 init_driver(void) 514 { 515 pci_info info; 516 int ix = 0; 517 518 num_cards = 0; 519 520 ddprintf(("cmedia_pci: init_driver()\n")); 521 522 if (get_module(pci_name, (module_info **)&pci)) 523 return ENOSYS; 524 525 if (get_module(gameport_name, (module_info **)&gameport)) { 526 put_module(pci_name); 527 return ENOSYS; 528 } 529 ddprintf(("MPU\n")); 530 if (get_module(mpu401_name, (module_info **) &mpu401)) { 531 put_module(gameport_name); 532 put_module(pci_name); 533 return ENOSYS; 534 } 535 536 ddprintf(("MPU: %p\n", mpu401)); 537 538 while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { 539 if (info.vendor_id == CMEDIA_PCI_VENDOR_ID && 540 (info.device_id == CMEDIA_8338A_DEVICE_ID || 541 info.device_id == CMEDIA_8338B_DEVICE_ID || 542 info.device_id == CMEDIA_8738A_DEVICE_ID || 543 info.device_id == CMEDIA_8738B_DEVICE_ID )) { 544 if (num_cards == NUM_CARDS) { 545 dprintf("Too many C-Media cards installed!\n"); 546 break; 547 } 548 memset(&cards[num_cards], 0, sizeof(cmedia_pci_dev)); 549 cards[num_cards].info = info; 550 if (setup_cmedia_pci(&cards[num_cards])) { 551 dprintf("Setup of C-Media %ld failed\n", num_cards+1); 552 } 553 else { 554 num_cards++; 555 } 556 } 557 ix++; 558 } 559 if (!num_cards) { 560 KPRINTF(("no cards\n")); 561 put_module(mpu401_name); 562 put_module(gameport_name); 563 put_module(pci_name); 564 ddprintf(("cmedia_pci: no suitable cards found\n")); 565 return ENODEV; 566 } 567 568 #if DEBUG 569 add_debugger_command("cmedia", debug_cmedia, "cmedia [card# (1-n)]"); 570 #endif 571 return B_OK; 572 } 573 574 575 static void 576 teardown_cmedia_pci( 577 cmedia_pci_dev * card) 578 { 579 static uchar regs[] = { 580 #ifdef DO_JOY 581 0x04, 0x00, 0x02, /* enable joystick */ 582 #endif 583 #ifdef DO_MIDI 584 0x04, 0x00, 0x04, /* enable MPU-401 */ 585 #endif 586 }; 587 uchar * ptr = regs; 588 cpu_status cp; 589 590 /* remove created devices */ 591 (*gameport->delete_device)(card->joy.driver); 592 (*mpu401->delete_device)(card->midi.driver); 593 594 cp = disable_interrupts(); 595 acquire_spinlock(&card->hardware); 596 597 while (ptr < regs+sizeof(regs)) { 598 set_direct(card, ptr[0], ptr[1], ptr[2]); 599 ptr += 3; 600 } 601 disable_card_interrupts(card); 602 603 release_spinlock(&card->hardware); 604 restore_interrupts(cp); 605 606 delete_sem(card->pcm.init_sem); 607 } 608 609 610 void 611 uninit_driver(void) 612 { 613 int ix, cnt = num_cards; 614 num_cards = 0; 615 616 ddprintf(("cmedia_pci: uninit_driver()\n")); 617 remove_debugger_command("cmedia", debug_cmedia); 618 619 for (ix=0; ix<cnt; ix++) { 620 teardown_cmedia_pci(&cards[ix]); 621 } 622 memset(&cards, 0, sizeof(cards)); 623 put_module(mpu401_name); 624 put_module(gameport_name); 625 put_module(pci_name); 626 } 627 628 629 const char ** 630 publish_devices(void) 631 { 632 int ix = 0; 633 ddprintf(("cmedia_pci: publish_devices()\n")); 634 635 for (ix=0; names[ix]; ix++) { 636 ddprintf(("cmedia_pci: publish %s\n", names[ix])); 637 } 638 return (const char **)names; 639 } 640 641 642 device_hooks * 643 find_device( 644 const char * name) 645 { 646 int ix; 647 648 ddprintf(("cmedia_pci: find_device(%s)\n", name)); 649 650 for (ix=0; ix<num_cards; ix++) { 651 #if DO_MIDI 652 if (!strcmp(cards[ix].midi.name, name)) { 653 return &midi_hooks; 654 } 655 #endif /* DO_MIDI */ 656 #if DO_JOY 657 if (!strcmp(cards[ix].joy.name1, name)) { 658 return &joy_hooks; 659 } 660 #endif /* DO_JOY */ 661 #if DO_PCM 662 if (!strcmp(cards[ix].pcm.name, name)) { 663 return &pcm_hooks; 664 } 665 if (!strcmp(cards[ix].pcm.oldname, name)) { 666 return &pcm_hooks; 667 } 668 #endif /* DO_PCM */ 669 #if DO_MUX 670 if (!strcmp(cards[ix].mux.name, name)) { 671 return &mux_hooks; 672 } 673 674 #endif /* DO_MUX */ 675 #if DO_MIXER 676 if (!strcmp(cards[ix].mixer.name, name)) { 677 return &mixer_hooks; 678 } 679 #endif /* DO_MIXER */ 680 } 681 ddprintf(("cmedia_pci: find_device(%s) failed\n", name)); 682 return NULL; 683 } 684 685 int32 api_version = B_CUR_DRIVER_API_VERSION; 686 687 static int32 688 cmedia_pci_interrupt( 689 void * data) 690 { 691 cpu_status cp = disable_interrupts(); 692 cmedia_pci_dev * card = (cmedia_pci_dev *)data; 693 uchar status; 694 int32 handled = B_UNHANDLED_INTERRUPT; 695 696 /* KTRACE(); / * */ 697 acquire_spinlock(&card->hardware); 698 699 status = get_direct(card, 0x10); 700 701 #if DEBUG 702 /* kprintf("%x\n", status); / * */ 703 #endif 704 #if DO_PCM 705 if (status & 0x02) { 706 if (dma_c_interrupt(card)) { 707 handled = B_INVOKE_SCHEDULER; 708 } 709 else { 710 handled = B_HANDLED_INTERRUPT; 711 } 712 /* acknowledge interrupt */ 713 set_direct(card, 0x0e, 0x00, 0x02); 714 set_direct(card, 0x0e, 0x02, 0x02); 715 } 716 if (status & 0x01) { 717 if (dma_a_interrupt(card)) { 718 handled = B_INVOKE_SCHEDULER; 719 } 720 else { 721 handled = B_HANDLED_INTERRUPT; 722 } 723 /* acknowledge interrupt */ 724 set_direct(card, 0x0e, 0x00, 0x01); 725 set_direct(card, 0x0e, 0x01, 0x01); 726 } 727 #endif 728 #if DO_MIDI 729 status = get_direct(card, 0x12); 730 if (status & 0x01) { 731 if (midi_interrupt(card)) { 732 handled = B_INVOKE_SCHEDULER; 733 } else { 734 handled = B_HANDLED_INTERRUPT; 735 } 736 } 737 #endif 738 739 /* Sometimes, the Sonic Vibes will receive a byte of Midi data... 740 ** And duly note it in the MPU401 status register... 741 ** And generate an interrupt... 742 ** But not bother setting the midi interrupt bit in the ISR. 743 ** Thanks a lot, S3. 744 */ 745 if(handled == B_UNHANDLED_INTERRUPT){ 746 if (midi_interrupt(card)) { 747 handled = B_INVOKE_SCHEDULER; 748 } 749 } 750 751 /* KTRACE(); / * */ 752 release_spinlock(&card->hardware); 753 restore_interrupts(cp); 754 755 return handled; 756 // return (handled == B_INVOKE_SCHEDULER) ? B_HANDLED_INTERRUPT : handled; 757 } 758 759 760 void 761 increment_interrupt_handler( 762 cmedia_pci_dev * card) 763 { 764 KPRINTF(("cmedia_pci: increment_interrupt_handler()\n")); 765 if (atomic_add(&card->inth_count, 1) == 0) { 766 // !!! 767 KPRINTF(("cmedia_pci: intline %d int %p\n", card->info.u.h0.interrupt_line, cmedia_pci_interrupt)); 768 install_io_interrupt_handler(card->info.u.h0.interrupt_line, 769 cmedia_pci_interrupt, card, 0); 770 } 771 } 772 773 774 void 775 decrement_interrupt_handler( 776 cmedia_pci_dev * card) 777 { 778 KPRINTF(("cmedia_pci: decrement_interrupt_handler()\n")); 779 if (atomic_add(&card->inth_count, -1) == 1) { 780 KPRINTF(("cmedia_pci: remove_io_interrupt_handler()\n")); 781 remove_io_interrupt_handler(card->info.u.h0.interrupt_line, cmedia_pci_interrupt, card); 782 } 783 } 784 785 786