📄 sonicvibes.c
字号:
snd_iprintf(buffer, "Ext. Rx to synth : %s\n", tmp & 0x02 ? "on" : "off"); snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off");}static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic){ struct snd_info_entry *entry; if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read);}/* */#ifdef SUPPORT_JOYSTICKstatic struct snd_kcontrol_new snd_sonicvibes_game_control __devinitdata =SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0);static int __devinit snd_sonicvibes_create_gameport(struct sonicvibes *sonic){ struct gameport *gp; sonic->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n"); return -ENOMEM; } gameport_set_name(gp, "SonicVibes Gameport"); gameport_set_phys(gp, "pci%s/gameport0", pci_name(sonic->pci)); gameport_set_dev_parent(gp, &sonic->pci->dev); gp->io = sonic->game_port; gameport_register_port(gp); snd_ctl_add(sonic->card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic)); return 0;}static void snd_sonicvibes_free_gameport(struct sonicvibes *sonic){ if (sonic->gameport) { gameport_unregister_port(sonic->gameport); sonic->gameport = NULL; }}#elsestatic inline int snd_sonicvibes_create_gameport(struct sonicvibes *sonic) { return -ENOSYS; }static inline void snd_sonicvibes_free_gameport(struct sonicvibes *sonic) { }#endifstatic int snd_sonicvibes_free(struct sonicvibes *sonic){ snd_sonicvibes_free_gameport(sonic); pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port); pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port); if (sonic->irq >= 0) free_irq(sonic->irq, sonic); release_and_free_resource(sonic->res_dmaa); release_and_free_resource(sonic->res_dmac); pci_release_regions(sonic->pci); pci_disable_device(sonic->pci); kfree(sonic); return 0;}static int snd_sonicvibes_dev_free(struct snd_device *device){ struct sonicvibes *sonic = device->device_data; return snd_sonicvibes_free(sonic);}static int __devinit snd_sonicvibes_create(struct snd_card *card, struct pci_dev *pci, int reverb, int mge, struct sonicvibes ** rsonic){ struct sonicvibes *sonic; unsigned int dmaa, dmac; int err; static struct snd_device_ops ops = { .dev_free = snd_sonicvibes_dev_free, }; *rsonic = NULL; /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } sonic = kzalloc(sizeof(*sonic), GFP_KERNEL); if (sonic == NULL) { pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&sonic->reg_lock); sonic->card = card; sonic->pci = pci; sonic->irq = -1; if ((err = pci_request_regions(pci, "S3 SonicVibes")) < 0) { kfree(sonic); pci_disable_device(pci); return err; } sonic->sb_port = pci_resource_start(pci, 0); sonic->enh_port = pci_resource_start(pci, 1); sonic->synth_port = pci_resource_start(pci, 2); sonic->midi_port = pci_resource_start(pci, 3); sonic->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED, "S3 SonicVibes", sonic)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_sonicvibes_free(sonic); return -EBUSY; } sonic->irq = pci->irq; pci_read_config_dword(pci, 0x40, &dmaa); pci_read_config_dword(pci, 0x48, &dmac); dmaio &= ~0x0f; dmaa &= ~0x0f; dmac &= ~0x0f; if (!dmaa) { dmaa = dmaio; dmaio += 0x10; snd_printk(KERN_INFO "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa); } if (!dmac) { dmac = dmaio; dmaio += 0x10; snd_printk(KERN_INFO "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac); } pci_write_config_dword(pci, 0x40, dmaa); pci_write_config_dword(pci, 0x48, dmac); if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) { snd_sonicvibes_free(sonic); snd_printk(KERN_ERR "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1); return -EBUSY; } if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) { snd_sonicvibes_free(sonic); snd_printk(KERN_ERR "unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1); return -EBUSY; } pci_read_config_dword(pci, 0x40, &sonic->dmaa_port); pci_read_config_dword(pci, 0x48, &sonic->dmac_port); sonic->dmaa_port &= ~0x0f; sonic->dmac_port &= ~0x0f; pci_write_config_dword(pci, 0x40, sonic->dmaa_port | 9); /* enable + enhanced */ pci_write_config_dword(pci, 0x48, sonic->dmac_port | 9); /* enable */ /* ok.. initialize S3 SonicVibes chip */ outb(SV_RESET, SV_REG(sonic, CONTROL)); /* reset chip */ udelay(100); outb(0, SV_REG(sonic, CONTROL)); /* release reset */ udelay(100); outb(SV_ENHANCED | SV_INTA | (reverb ? SV_REVERB : 0), SV_REG(sonic, CONTROL)); inb(SV_REG(sonic, STATUS)); /* clear IRQs */#if 1 snd_sonicvibes_out(sonic, SV_IREG_DRIVE_CTRL, 0); /* drive current 16mA */#else snd_sonicvibes_out(sonic, SV_IREG_DRIVE_CTRL, 0x40); /* drive current 8mA */#endif snd_sonicvibes_out(sonic, SV_IREG_PC_ENABLE, sonic->enable = 0); /* disable playback & capture */ outb(sonic->irqmask = ~(SV_DMAA_MASK | SV_DMAC_MASK | SV_UD_MASK), SV_REG(sonic, IRQMASK)); inb(SV_REG(sonic, STATUS)); /* clear IRQs */ snd_sonicvibes_out(sonic, SV_IREG_ADC_CLOCK, 0); /* use PLL as clock source */ snd_sonicvibes_out(sonic, SV_IREG_ANALOG_POWER, 0); /* power up analog parts */ snd_sonicvibes_out(sonic, SV_IREG_DIGITAL_POWER, 0); /* power up digital parts */ snd_sonicvibes_setpll(sonic, SV_IREG_ADC_PLL, 8000); snd_sonicvibes_out(sonic, SV_IREG_SRS_SPACE, sonic->srs_space = 0x80); /* SRS space off */ snd_sonicvibes_out(sonic, SV_IREG_SRS_CENTER, sonic->srs_center = 0x00);/* SRS center off */ snd_sonicvibes_out(sonic, SV_IREG_MPU401, sonic->mpu_switch = 0x05); /* MPU-401 switch */ snd_sonicvibes_out(sonic, SV_IREG_WAVE_SOURCE, sonic->wave_source = 0x00); /* onboard ROM */ snd_sonicvibes_out(sonic, SV_IREG_PCM_RATE_LOW, (8000 * 65536 / SV_FULLRATE) & 0xff); snd_sonicvibes_out(sonic, SV_IREG_PCM_RATE_HIGH, ((8000 * 65536 / SV_FULLRATE) >> 8) & 0xff); snd_sonicvibes_out(sonic, SV_IREG_LEFT_ADC, mge ? 0xd0 : 0xc0); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_ADC, 0xc0); snd_sonicvibes_out(sonic, SV_IREG_LEFT_AUX1, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_AUX1, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_CD, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_CD, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_LINE, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_LINE, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_MIC, 0x8f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_SYNTH, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_SYNTH, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_AUX2, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_AUX2, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_ANALOG, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_ANALOG, 0x9f); snd_sonicvibes_out(sonic, SV_IREG_LEFT_PCM, 0xbf); snd_sonicvibes_out(sonic, SV_IREG_RIGHT_PCM, 0xbf); snd_sonicvibes_out(sonic, SV_IREG_ADC_OUTPUT_CTRL, 0xfc);#if 0 snd_sonicvibes_debug(sonic);#endif sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) { snd_sonicvibes_free(sonic); return err; } snd_sonicvibes_proc_init(sonic); snd_card_set_dev(card, &pci->dev); *rsonic = sonic; return 0;}/* * MIDI section */static struct snd_kcontrol_new snd_sonicvibes_midi_controls[] __devinitdata = {SONICVIBES_SINGLE("SonicVibes Wave Source RAM", 0, SV_IREG_WAVE_SOURCE, 0, 1, 0),SONICVIBES_SINGLE("SonicVibes Wave Source RAM+ROM", 0, SV_IREG_WAVE_SOURCE, 1, 1, 0),SONICVIBES_SINGLE("SonicVibes Onboard Synth", 0, SV_IREG_MPU401, 0, 1, 0),SONICVIBES_SINGLE("SonicVibes External Rx to Synth", 0, SV_IREG_MPU401, 1, 1, 0),SONICVIBES_SINGLE("SonicVibes External Tx", 0, SV_IREG_MPU401, 2, 1, 0)};static int snd_sonicvibes_midi_input_open(struct snd_mpu401 * mpu){ struct sonicvibes *sonic = mpu->private_data; outb(sonic->irqmask &= ~SV_MIDI_MASK, SV_REG(sonic, IRQMASK)); return 0;}static void snd_sonicvibes_midi_input_close(struct snd_mpu401 * mpu){ struct sonicvibes *sonic = mpu->private_data; outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK));}static int __devinit snd_sonicvibes_midi(struct sonicvibes * sonic, struct snd_rawmidi *rmidi){ struct snd_mpu401 * mpu = rmidi->private_data; struct snd_card *card = sonic->card; struct snd_rawmidi_str *dir; unsigned int idx; int err; mpu->private_data = sonic; mpu->open_input = snd_sonicvibes_midi_input_open; mpu->close_input = snd_sonicvibes_midi_input_close; dir = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_midi_controls); idx++) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_midi_controls[idx], sonic))) < 0) return err; return 0;}static int __devinit snd_sonic_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; struct snd_card *card; struct sonicvibes *sonic; struct snd_rawmidi *midi_uart; struct snd_opl3 *opl3; int idx, err; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; for (idx = 0; idx < 5; idx++) { if (pci_resource_start(pci, idx) == 0 || !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) { snd_card_free(card); return -ENODEV; } } if ((err = snd_sonicvibes_create(card, pci, reverb[dev] ? 1 : 0, mge[dev] ? 1 : 0, &sonic)) < 0) { snd_card_free(card); return err; } strcpy(card->driver, "SonicVibes"); strcpy(card->shortname, "S3 SonicVibes"); sprintf(card->longname, "%s rev %i at 0x%llx, irq %i", card->shortname, sonic->revision, (unsigned long long)pci_resource_start(pci, 1), sonic->irq); if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) { snd_card_free(card); return err; } if ((err = snd_sonicvibes_mixer(sonic)) < 0) { snd_card_free(card); return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, sonic->midi_port, MPU401_INFO_INTEGRATED, sonic->irq, 0, &midi_uart)) < 0) { snd_card_free(card); return err; } snd_sonicvibes_midi(sonic, midi_uart); if ((err = snd_opl3_create(card, sonic->synth_port, sonic->synth_port + 2, OPL3_HW_OPL3_SV, 1, &opl3)) < 0) { snd_card_free(card); return err; } if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); return err; } snd_sonicvibes_create_gameport(sonic); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, card); dev++; return 0;}static void __devexit snd_sonic_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { .name = "S3 SonicVibes", .id_table = snd_sonic_ids, .probe = snd_sonic_probe, .remove = __devexit_p(snd_sonic_remove),};static int __init alsa_card_sonicvibes_init(void){ return pci_register_driver(&driver);}static void __exit alsa_card_sonicvibes_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_sonicvibes_init)module_exit(alsa_card_sonicvibes_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -