📄 interwave.c
字号:
if (inb(iwcard->gus_status_reg)) { snd_gus_interrupt(irq, iwcard->gus, regs); loop++; } if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */ snd_cs4231_interrupt(irq, iwcard->cs4231, regs); loop++; } } while (loop && --max > 0);}static void __init snd_interwave_reset(snd_gus_card_t * gus){ snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x00); udelay(160); snd_gf1_write8(gus, SNDRV_GF1_GB_RESET, 0x01); udelay(160);}static void __init snd_interwave_bank_sizes(snd_gus_card_t * gus, int *sizes){ unsigned int idx; unsigned int local; unsigned char d; for (idx = 0; idx < 4; idx++) { sizes[idx] = 0; d = 0x55; for (local = idx << 22; local < (idx << 22) + 0x400000; local += 0x40000, d++) { snd_gf1_poke(gus, local, d); snd_gf1_poke(gus, local + 1, d + 1);#if 0 printk("d = 0x%x, local = 0x%x, local + 1 = 0x%x, idx << 22 = 0x%x\n", d, snd_gf1_peek(gus, local), snd_gf1_peek(gus, local + 1), snd_gf1_peek(gus, idx << 22));#endif if (snd_gf1_peek(gus, local) != d || snd_gf1_peek(gus, local + 1) != d + 1 || snd_gf1_peek(gus, idx << 22) != 0x55) break; sizes[idx]++; } }#if 0 printk("sizes: %i %i %i %i\n", sizes[0], sizes[1], sizes[2], sizes[3]);#endif}struct rom_hdr { /* 000 */ unsigned char iwave[8]; /* 008 */ unsigned char rom_hdr_revision; /* 009 */ unsigned char series_number; /* 010 */ unsigned char series_name[16]; /* 026 */ unsigned char date[10]; /* 036 */ unsigned short vendor_revision_major; /* 038 */ unsigned short vendor_revision_minor; /* 040 */ unsigned int rom_size; /* 044 */ unsigned char copyright[128]; /* 172 */ unsigned char vendor_name[64]; /* 236 */ unsigned char rom_description[128]; /* 364 */ unsigned char pad[147]; /* 511 */ unsigned char csum;};static void __init snd_interwave_detect_memory(snd_gus_card_t * gus){ static unsigned int lmc[13] = { 0x00000001, 0x00000101, 0x01010101, 0x00000401, 0x04040401, 0x00040101, 0x04040101, 0x00000004, 0x00000404, 0x04040404, 0x00000010, 0x00001010, 0x10101010 }; int bank_pos, pages; unsigned int i, lmct; int psizes[4]; unsigned char csum; struct rom_hdr romh; snd_interwave_reset(gus); snd_gf1_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_read8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01); /* enhanced mode */ snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01); /* DRAM I/O cycles selected */ snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff10) | 0x004c); /* ok.. simple test of memory size */ pages = 0; snd_gf1_poke(gus, 0, 0x55); snd_gf1_poke(gus, 1, 0xaa);#if 1 if (snd_gf1_peek(gus, 0) == 0x55 && snd_gf1_peek(gus, 1) == 0xaa)#else if (0) /* ok.. for testing of 0k RAM */#endif { snd_interwave_bank_sizes(gus, psizes); lmct = (psizes[3] << 24) | (psizes[2] << 16) | (psizes[1] << 8) | psizes[0];#if 0 printk("lmct = 0x%08x\n", lmct);#endif for (i = 0; i < sizeof(lmc) / sizeof(unsigned int); i++) if (lmct == lmc[i]) {#if 0 printk("found !!! %i\n", i);#endif snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | i); snd_interwave_bank_sizes(gus, psizes); break; } if (i >= sizeof(lmc) / sizeof(unsigned int) && !gus->gf1.enh_mode) snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xfff0) | 2); for (i = 0; i < 4; i++) { gus->gf1.mem_alloc.banks_8[i].address = gus->gf1.mem_alloc.banks_16[i].address = i << 22; gus->gf1.mem_alloc.banks_8[i].size = gus->gf1.mem_alloc.banks_16[i].size = psizes[i] << 18; pages += psizes[i]; } } pages <<= 18; gus->gf1.memory = pages; snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x03); /* select ROM */ snd_gf1_write16(gus, SNDRV_GF1_GW_MEMORY_CONFIG, (snd_gf1_look16(gus, SNDRV_GF1_GW_MEMORY_CONFIG) & 0xff1f) | (4 << 5)); gus->gf1.rom_banks = 0; gus->gf1.rom_memory = 0; for (bank_pos = 0; bank_pos < 16L * 1024L * 1024L; bank_pos += 4L * 1024L * 1024L) { for (i = 0; i < sizeof(struct rom_hdr); i++) *(((unsigned char *) &romh) + i) = snd_gf1_peek(gus, i + bank_pos);#ifdef CONFIG_SND_DEBUG_ROM printk("ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos, romh.iwave[0], romh.iwave[1], romh.iwave[2], romh.iwave[3], romh.iwave[4], romh.iwave[5], romh.iwave[6], romh.iwave[7]);#endif if (strncmp(romh.iwave, "INTRWAVE", 8)) continue; /* first check */ csum = 0; for (i = 0; i < sizeof(struct rom_hdr) - 1; i++) csum += *(((unsigned char *) &romh) + i);#ifdef CONFIG_SND_DEBUG_ROM printk("ROM checksum = 0x%x == 0x%x (computed)\n", romh.csum, (unsigned char) (256 - csum));#endif if (256 - csum != romh.csum) continue; /* not valid rom */ gus->gf1.rom_banks++; gus->gf1.rom_present |= 1 << (bank_pos >> 22);#ifdef SNDRV_LITTLE_ENDIAN gus->gf1.rom_memory = romh.rom_size;#else gus->gf1.rom_memory = ((romh.rom_size >> 24) & 0x000000ff) | ((romh.rom_size >> 8) & 0x0000ff00) | ((romh.rom_size << 8) & 0x00ff0000) | ((romh.rom_size << 24) & 0xff000000);#endif }#if 0 if (gus->gf1.rom_memory > 0) { if (gus->gf1.rom_banks == 1 && gus->gf1.rom_present == 8) gus->card->type = SNDRV_CARD_TYPE_IW_DYNASONIC; }#endif snd_gf1_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x00); /* select RAM */ if (!gus->gf1.enh_mode) snd_interwave_reset(gus);}static void __init snd_interwave_init(int dev, snd_gus_card_t * gus){ unsigned long flags; /* ok.. some InterWave specific initialization */ spin_lock_irqsave(&gus->reg_lock, flags); snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0x00); snd_gf1_write8(gus, SNDRV_GF1_GB_COMPATIBILITY, 0x1f); snd_gf1_write8(gus, SNDRV_GF1_GB_DECODE_CONTROL, 0x49); snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, 0x11); snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_A, 0x00); snd_gf1_write8(gus, SNDRV_GF1_GB_MPU401_CONTROL_B, 0x30); snd_gf1_write8(gus, SNDRV_GF1_GB_EMULATION_IRQ, 0x00); spin_unlock_irqrestore(&gus->reg_lock, flags); gus->equal_irq = 1; gus->codec_flag = 1; gus->interwave = 1; gus->max_flag = 1; gus->joystick_dac = snd_joystick_dac[dev];}#define INTERWAVE_CONTROLS (sizeof(snd_interwave_controls)/sizeof(snd_kcontrol_new_t))static snd_kcontrol_new_t snd_interwave_controls[] = {CS4231_DOUBLE("Master Playback Switch", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 7, 7, 1, 1),CS4231_DOUBLE("Master Playback Volume", 0, CS4231_LINE_LEFT_OUTPUT, CS4231_LINE_RIGHT_OUTPUT, 0, 0, 31, 1),CS4231_DOUBLE("Mic Playback Switch", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 7, 7, 1, 1),CS4231_DOUBLE("Mic Playback Volume", 0, CS4231_LEFT_MIC_INPUT, CS4231_RIGHT_MIC_INPUT, 0, 0, 31, 1)};static int __init snd_interwave_mixer(cs4231_t *chip){ snd_card_t *card = chip->card; snd_ctl_elem_id_t id1, id2; int idx, err; memset(&id1, 0, sizeof(id1)); memset(&id2, 0, sizeof(id2)); id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;#if 0 /* remove mono microphone controls */ strcpy(id1.name, "Mic Playback Switch"); if ((err = snd_ctl_remove_id(card, &id1)) < 0) return err; strcpy(id1.name, "Mic Playback Volume"); if ((err = snd_ctl_remove_id(card, &id1)) < 0) return err;#endif /* add new master and mic controls */ for (idx = 0; idx < INTERWAVE_CONTROLS; idx++) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_interwave_controls[idx], chip))) < 0) return err; snd_cs4231_out(chip, CS4231_LINE_LEFT_OUTPUT, 0x9f); snd_cs4231_out(chip, CS4231_LINE_RIGHT_OUTPUT, 0x9f); snd_cs4231_out(chip, CS4231_LEFT_MIC_INPUT, 0x9f); snd_cs4231_out(chip, CS4231_RIGHT_MIC_INPUT, 0x9f); /* reassign AUXA to SYNTHESIZER */ strcpy(id1.name, "Aux Playback Switch"); strcpy(id2.name, "Synth Playback Switch"); if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "Synth Playback Volume"); if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) return err; /* reassign AUXB to CD */ strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; strcpy(id2.name, "CD Playback Switch"); if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) return err; strcpy(id1.name, "Aux Playback Volume"); strcpy(id2.name, "CD Playback Volume"); if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) return err; return 0;}#ifdef __ISAPNP__static int __init snd_interwave_isapnp(int dev, struct snd_interwave *iwcard){ const struct isapnp_card_id *id = snd_interwave_isapnp_id[dev]; struct isapnp_card *card = snd_interwave_isapnp_cards[dev]; struct isapnp_dev *pdev; iwcard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL); if (iwcard->dev->active) { iwcard->dev = NULL; return -EBUSY; }#ifdef SNDRV_STB iwcard->devtc = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL); if (iwcard->devtc->active) { iwcard->dev = iwcard->devtc = NULL; return -EBUSY; }#endif /* Synth & Codec initialization */ pdev = iwcard->dev; if (pdev->prepare(pdev)<0) return -EAGAIN; if (snd_port[dev] != SNDRV_AUTO_PORT) { isapnp_resource_change(&pdev->resource[0], snd_port[dev], 16); isapnp_resource_change(&pdev->resource[1], snd_port[dev] + 0x100, 12); isapnp_resource_change(&pdev->resource[2], snd_port[dev] + 0x10c, 4); } if (snd_dma1[dev] != SNDRV_AUTO_DMA) isapnp_resource_change(&pdev->dma_resource[0], snd_dma1[dev], 1); if (snd_dma2[dev] != SNDRV_AUTO_DMA) isapnp_resource_change(&pdev->dma_resource[1], snd_dma2[dev], 1); if (snd_dma2[dev] < 0) isapnp_resource_change(&pdev->dma_resource[1], 4, 1); if (snd_irq[dev] != SNDRV_AUTO_IRQ) isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1); if (pdev->activate(pdev)<0) { snd_printk("isapnp configure failure (out of resources?)\n"); return -EBUSY; } if (pdev->resource[0].start + 0x100 != pdev->resource[1].start || pdev->resource[0].start + 0x10c != pdev->resource[2].start) { snd_printk("isapnp configure failure (wrong ports)\n"); pdev->deactivate(pdev); return -ENOENT; } snd_port[dev] = pdev->resource[0].start; snd_dma1[dev] = pdev->dma_resource[0].start; if (snd_dma2[dev] >= 0) snd_dma2[dev] = pdev->dma_resource[1].start; snd_irq[dev] = pdev->irq_resource[0].start; snd_printdd("isapnp IW: sb port=0x%lx, gf1 port=0x%lx, codec port=0x%lx\n", pdev->resource[0].start, pdev->resource[1].start, pdev->resource[2].start); snd_printdd("isapnp IW: dma1=%i, dma2=%i, irq=%i\n", snd_dma1[dev], snd_dma2[dev], snd_irq[dev]);#ifdef SNDRV_STB /* Tone Control initialization */ pdev = iwcard->devtc; if (pdev->prepare(pdev)<0) { iwcard->dev->deactivate(iwcard->dev); return -EAGAIN; } if (snd_port_tc[dev] != SNDRV_AUTO_PORT) isapnp_resource_change(&pdev->resource[0], snd_port_tc[dev], 1); if (pdev->activate(pdev)<0) { snd_printk("Tone Control isapnp configure failure (out of resources?)\n"); iwcard->dev->deactivate(iwcard->dev); return -EBUSY; } snd_port_tc[dev] = pdev->resource[0].start; snd_printdd("isapnp IW: tone control port=0x%lx\n", snd_port_tc[dev]);#endif return 0;}static void snd_interwave_deactivate(struct snd_interwave *iwcard){ if (iwcard->dev) { iwcard->dev->deactivate(iwcard->dev); iwcard->dev = NULL; }#ifdef SNDRV_STB if (iwcard->devtc) { iwcard->devtc->deactivate(iwcard->devtc); iwcard->devtc = NULL; }#endif}#endif /* __ISAPNP__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -