int probe_for_sound_blaster(void) { unsigned int i; if (!init_sndsb()) return -1; #if !defined(TARGET_PC98) /* we want to know if certain emulation TSRs exist */ gravis_mega_em_detect(&megaem_info); gravis_sbos_detect(); #endif /* it's up to us now to tell it certain minor things */ sndsb_detect_virtualbox(); // whether or not we're running in VirtualBox /* sndsb now allows us to keep the EXE small by not referring to extra sound card support */ sndsb_enable_sb16_support(); // SB16 support sndsb_enable_sc400_support(); // SC400 support sndsb_enable_ess_audiodrive_support(); // ESS AudioDrive support #if !defined(TARGET_PC98) /* Plug & Play scan */ if (has_isa_pnp_bios()) { const unsigned int devnode_raw_sz = 4096U; unsigned char *devnode_raw = malloc(devnode_raw_sz); if (devnode_raw != NULL) { unsigned char csn,node=0,numnodes=0xFF,data[192]; unsigned int j,nodesize=0; const char *whatis = NULL; memset(data,0,sizeof(data)); if (isa_pnp_bios_get_pnp_isa_cfg(data) == 0) { struct isapnp_pnp_isa_cfg *nfo = (struct isapnp_pnp_isa_cfg*)data; isapnp_probe_next_csn = nfo->total_csn; isapnp_read_data = nfo->isa_pnp_port; } /* enumerate device nodes reported by the BIOS */ if (isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize) == 0 && numnodes != 0xFF && nodesize <= devnode_raw_sz) { for (node=0;node != 0xFF;) { struct isa_pnp_device_node far *devn; unsigned char this_node; /* apparently, start with 0. call updates node to * next node number, or 0xFF to signify end */ this_node = node; if (isa_pnp_bios_get_sysdev_node(&node,devnode_raw,ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW) != 0) break; devn = (struct isa_pnp_device_node far*)devnode_raw; if (isa_pnp_is_sound_blaster_compatible_id(devn->product_id,&whatis)) { if (sndsb_try_isa_pnp_bios(devn->product_id,this_node,devn,devnode_raw_sz) > 0) printf("PnP: Found %s\n",whatis); } } } /* enumerate the ISA bus directly */ if (isapnp_read_data != 0) { for (csn=1;csn < 255;csn++) { isa_pnp_init_key(); isa_pnp_wake_csn(csn); isa_pnp_write_address(0x06); /* CSN */ if (isa_pnp_read_data() == csn) { /* apparently doing this lets us read back the serial and vendor ID in addition to resource data */ /* if we don't, then we only read back the resource data */ isa_pnp_init_key(); isa_pnp_wake_csn(csn); for (j=0;j < 9;j++) data[j] = isa_pnp_read_config(); if (isa_pnp_is_sound_blaster_compatible_id(*((uint32_t*)data),&whatis)) { if (sndsb_try_isa_pnp(*((uint32_t*)data),csn) > 0) printf("PnP: Found %s\n",whatis); } } /* return back to "wait for key" state */ isa_pnp_write_data_register(0x02,0x02); /* bit 1: set -> return to Wait For Key state (or else a Pentium Pro system I own eventually locks up and hangs) */ } } free(devnode_raw); } } #endif /* Non-plug & play scan: BLASTER environment variable */ if (sndsb_try_blaster_var() != NULL) { if (!sndsb_init_card(sndsb_card_blaster)) sndsb_free_card(sndsb_card_blaster); } #if defined(TARGET_PC98) /* Non-plug & play scan: Most SB cards exist at xxD2h or xxD4h */ sndsb_try_base(0xD2); sndsb_try_base(0xD4); #else /* Non-plug & play scan: Most SB cards exist at 220h or 240h */ sndsb_try_base(0x220); sndsb_try_base(0x240); #endif /* further probing, for IRQ and DMA and other capabilities */ for (i=0;i < SNDSB_MAX_CARDS;i++) { struct sndsb_ctx *cx = sndsb_index_to_ctx(i); if (cx->baseio == 0) continue; if (cx->irq < 0) sndsb_probe_irq_F2(cx); if (cx->irq < 0) sndsb_probe_irq_80(cx); if (cx->dma8 < 0) sndsb_probe_dma8_E2(cx); if (cx->dma8 < 0) sndsb_probe_dma8_14(cx); // having IRQ and DMA changes the ideal playback method and capabilities sndsb_update_capabilities(cx); sndsb_determine_ideal_dsp_play_method(cx); } /* add detected cards to soundcard list */ { soundcard_t sc; unsigned int i; for (i=0;i < SNDSB_MAX_CARDS;i++) { struct sndsb_ctx *cx = sndsb_index_to_ctx(i); if (cx->baseio == 0) continue; sc = soundcardlist_new(&soundblaster_soundcard_template); if (sc == NULL) continue; sc->p.soundblaster.index = i; sc->requirements = soundcard_requirements_isa_dma; sc->capabilities = soundcard_caps_mmap_write | soundcard_caps_8bit | soundcard_caps_isa_dma; if (cx->irq >= 0) { sc->requirements |= soundcard_requirements_irq; sc->capabilities |= soundcard_caps_irq; } if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_4xx) sc->capabilities |= soundcard_caps_16bit; else if (cx->dsp_play_method >= SNDSB_DSPOUTMETHOD_3xx && cx->ess_extensions) sc->capabilities |= soundcard_caps_16bit; } } /* OK. done */ return 0; }
void isa_pnp_wake_csn(unsigned char id) { isa_pnp_write_address(3); /* Wake[CSN] */ isa_pnp_write_data(id); /* isolation state */ }
/* NTS: The caller is expected to pnp_wake_scn() then siphon off the device id */ int isa_pnp_sound_blaster_get_resources(uint32_t id,unsigned char csn,struct sndsb_ctx *cx) { cx->baseio = 0; cx->gameio = 0; cx->aweio = 0; cx->oplio = 0; cx->mpuio = 0; cx->dma16 = -1; cx->dma8 = -1; cx->irq = -1; if (ISAPNP_ID_FMATCH(id,'E','S','S')) { if (ISAPNP_ID_LMATCH(id,0x0100)) { /* ESS0100 ES688 Plug And Play AudioDrive */ /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */ } } else if (ISAPNP_ID_FMATCH(id,'C','P','Q')) { if (ISAPNP_ID_LMATCH(id,0xB040)) { /* CPQB040 ES1887 (Compaq) */ /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */ } } else if (ISAPNP_ID_FMATCH(id,'Y','M','H')) { if (ISAPNP_ID_LMATCH(id,0x0021)) { /* YMH0021 OPL3-SAx (TODO: Which one? SA2 or SA3) */ /* TODO: I don't have any ISA cards of this type, only one integrated into a laptop */ } } else if (ISAPNP_ID_FMATCH(id,'C','T','L')) { /* Creative SB PnP cards are fairly consistent on the resource layout. If you have one that this * code fails to match, feel free to add it here */ if ( ISAPNP_ID_LMATCH(id,0x0070) || /* CTL0070 Creative ViBRA16C PnP */ ISAPNP_ID_LMATCH(id,0x00B2) || /* CTL00B2 Creative AWE64 Gold PnP */ ISAPNP_ID_LMATCH(id,0x00C3) || /* CTL00C3 Creative AWE64 PnP */ ISAPNP_ID_LMATCH(id,0x00F0)) { /* CTL00F0 Creative ViBRA16X/XV PnP */ /* For ref (configuration regs): * IO[0] = Base I/O port * IO[1] = MPU I/O port * IO[2] = OPL3 I/O port * IRQ[0] = Interrupt request line * DMA[0] = 8-bit DMA channel * DMA[1] = 16-bit DMA channel */ isa_pnp_write_address(0x07); /* log device select */ isa_pnp_write_data(0x00); /* main device */ cx->baseio = isa_pnp_read_io_resource(0); if (cx->baseio == 0 || cx->baseio == 0xFFFF) cx->baseio = 0; cx->mpuio = isa_pnp_read_io_resource(1); if (cx->mpuio == 0 || cx->mpuio == 0xFFFF) cx->mpuio = 0; cx->oplio = isa_pnp_read_io_resource(2); if (cx->oplio == 0 || cx->oplio == 0xFFFF) cx->oplio = 0; cx->dma8 = isa_pnp_read_dma(0); if ((cx->dma8&7) == 4) cx->dma8 = -1; cx->dma16 = isa_pnp_read_dma(1); if ((cx->dma16&7) == 4) cx->dma16 = -1; cx->irq = isa_pnp_read_irq(0); if ((cx->irq&0xF) == 0) cx->irq = -1; /* logical device #1: gameport */ isa_pnp_write_address(0x07); /* log device select */ isa_pnp_write_data(0x01); /* main device */ cx->gameio = isa_pnp_read_io_resource(0); if (cx->gameio == cx->baseio || cx->gameio == 0 || cx->gameio == 0xFFFF) cx->gameio = 0; /* SB AWE: logical device #2: wavetable */ if (ISAPNP_ID_LMATCH(id,0x00C3) || ISAPNP_ID_LMATCH(id,0x00B2)) { isa_pnp_write_address(0x07); /* log device select */ isa_pnp_write_data(0x02); /* main device */ cx->aweio = isa_pnp_read_io_resource(0); if (cx->aweio == cx->baseio || cx->aweio == 0 || cx->aweio == 0xFFFF) cx->aweio = 0; } } } if (cx->baseio == 0) return ISAPNPSB_NO_RESOURCES; return 1; }