es1938.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
ES1938_SINGLE("Hardware Volume Split", 0, 0x64, 7, 1, 0),ES1938_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),ES1938_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),ES1938_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),ES1938_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),ES1938_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),ES1938_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),ES1938_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0),ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = snd_es1938_info_mux, .get = snd_es1938_get_mux, .put = snd_es1938_put_mux,},ES1938_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),ES1938_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),ES1938_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),ES1938_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),ES1938_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),ES1938_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),ES1938_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),ES1938_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0),ES1938_DOUBLE("PCM Playback Volume", 0, 0x7c, 0x7c, 4, 0, 15, 0),ES1938_DOUBLE("PCM Playback Volume", 1, 0x14, 0x14, 4, 0, 15, 0),ES1938_SINGLE("3D Control - Level", 0, 0x52, 0, 63, 0),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "3D Control - Switch", .info = snd_es1938_info_spatializer_enable, .get = snd_es1938_get_spatializer_enable, .put = snd_es1938_put_spatializer_enable,},ES1938_SINGLE("Mic Boost (+26dB)", 0, 0x7d, 3, 1, 0)};/* ---------------------------------------------------------------------------- *//* ---------------------------------------------------------------------------- *//* * initialize the chip - used by resume callback, too */static void snd_es1938_chip_init(es1938_t *chip){ /* reset chip */ snd_es1938_reset(chip); /* configure native mode */ /* enable bus master */ pci_set_master(chip->pci); /* disable legacy audio */ pci_write_config_word(chip->pci, SL_PCI_LEGACYCONTROL, 0x805f); /* set DDMA base */ pci_write_config_word(chip->pci, SL_PCI_DDMACONTROL, chip->ddma_port | 1); /* set DMA/IRQ policy */ pci_write_config_dword(chip->pci, SL_PCI_CONFIG, 0); /* enable Audio 1, Audio 2, MPU401 IRQ and HW volume IRQ*/ outb(0xf0, SLIO_REG(chip, IRQCONTROL)); /* reset DMA */ outb(0, SLDM_REG(chip, DMACLEAR));}#ifdef CONFIG_PM/* * PM support */static unsigned char saved_regs[SAVED_REG_SIZE+1] = { 0x14, 0x1a, 0x1c, 0x3a, 0x3c, 0x3e, 0x36, 0x38, 0x50, 0x52, 0x60, 0x61, 0x62, 0x63, 0x64, 0x68, 0x69, 0x6a, 0x6b, 0x6d, 0x6e, 0x6f, 0x7c, 0x7d, 0xa8, 0xb4,};static int es1938_suspend(snd_card_t *card, unsigned int state){ es1938_t *chip = card->pm_private_data; unsigned char *s, *d; snd_pcm_suspend_all(chip->pcm); /* save mixer-related registers */ for (s = saved_regs, d = chip->saved_regs; *s; s++, d++) *d = snd_es1938_reg_read(chip, *s); outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */ snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0;}static int es1938_resume(snd_card_t *card, unsigned int state){ es1938_t *chip = card->pm_private_data; unsigned char *s, *d; pci_enable_device(chip->pci); snd_es1938_chip_init(chip); /* restore mixer-related registers */ for (s = saved_regs, d = chip->saved_regs; *s; s++, d++) { if (*s < 0xa0) snd_es1938_mixer_write(chip, *s, *d); else snd_es1938_write(chip, *s, *d); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endif /* CONFIG_PM */static int snd_es1938_free(es1938_t *chip){ /* disable irqs */ outb(0x00, SLIO_REG(chip, IRQCONTROL)); /*if (chip->rmidi) snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);*/#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) if (chip->gameport.io) gameport_unregister_port(&chip->gameport);#endif if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); pci_release_regions(chip->pci); kfree(chip); return 0;}static int snd_es1938_dev_free(snd_device_t *device){ es1938_t *chip = device->device_data; return snd_es1938_free(chip);}static int __devinit snd_es1938_create(snd_card_t * card, struct pci_dev * pci, es1938_t ** rchip){ es1938_t *chip; int err; static snd_device_ops_t ops = { .dev_free = snd_es1938_dev_free, }; *rchip = 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, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); chip->card = card; chip->pci = pci; if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) { kfree(chip); return err; } chip->io_port = pci_resource_start(pci, 0); chip->sb_port = pci_resource_start(pci, 1); chip->vc_port = pci_resource_start(pci, 2); chip->mpu_port = pci_resource_start(pci, 3); chip->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_es1938_interrupt, SA_INTERRUPT|SA_SHIRQ, "ES1938", (void *)chip)) { snd_printk("unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; } chip->irq = pci->irq;#ifdef ES1938_DDEBUG snd_printk("create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port);#endif chip->ddma_port = chip->vc_port + 0x00; /* fix from Thomas Sailer */ snd_es1938_chip_init(chip); snd_card_set_pm_callback(card, es1938_suspend, es1938_resume, chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_es1938_free(chip); return err; } snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0;}/* -------------------------------------------------------------------- * Interrupt handler * -------------------------------------------------------------------- */static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs){ es1938_t *chip = dev_id; unsigned char status, audiostatus; int handled = 0; status = inb(SLIO_REG(chip, IRQCONTROL));#if 0 printk("Es1938debug - interrupt status: =0x%x\n", status);#endif /* AUDIO 1 */ if (status & 0x10) {#if 0 printk("Es1938debug - AUDIO channel 1 interrupt\n"); printk("Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n", inw(SLDM_REG(chip, DMACOUNT))); printk("Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n", inl(SLDM_REG(chip, DMAADDR))); printk("Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n", inl(SLDM_REG(chip, DMASTATUS)));#endif /* clear irq */ handled = 1; audiostatus = inb(SLSB_REG(chip, STATUS)); if (chip->active & ADC1) snd_pcm_period_elapsed(chip->capture_substream); else if (chip->active & DAC1) snd_pcm_period_elapsed(chip->playback2_substream); } /* AUDIO 2 */ if (status & 0x20) {#if 0 printk("Es1938debug - AUDIO channel 2 interrupt\n"); printk("Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n", inw(SLIO_REG(chip, AUDIO2DMACOUNT))); printk("Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n", inl(SLIO_REG(chip, AUDIO2DMAADDR)));#endif /* clear irq */ handled = 1; snd_es1938_mixer_bits(chip, ESSSB_IREG_AUDIO2CONTROL2, 0x80, 0); if (chip->active & DAC2) snd_pcm_period_elapsed(chip->playback1_substream); } /* Hardware volume */ if (status & 0x40) { int split = snd_es1938_mixer_read(chip, 0x64) & 0x80; handled = 1; snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id); if (!split) { snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); } /* ack interrupt */ snd_es1938_mixer_write(chip, 0x66, 0x00); } /* MPU401 */ if (status & 0x80) { // snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */ if (chip->rmidi) { handled = 1; snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); } } return IRQ_RETVAL(handled);}#define ES1938_DMA_SIZE 64static int __devinit snd_es1938_mixer(es1938_t *chip){ snd_card_t *card; unsigned int idx; int err; card = chip->card; strcpy(card->mixername, "ESS Solo-1"); for (idx = 0; idx < ARRAY_SIZE(snd_es1938_controls); idx++) { snd_kcontrol_t *kctl; kctl = snd_ctl_new1(&snd_es1938_controls[idx], chip); switch (idx) { case 0: chip->master_volume = kctl; kctl->private_free = snd_es1938_hwv_free; break; case 1: chip->master_switch = kctl; kctl->private_free = snd_es1938_hwv_free; break; case 2: chip->hw_volume = kctl; kctl->private_free = snd_es1938_hwv_free; break; case 3: chip->hw_switch = kctl; kctl->private_free = snd_es1938_hwv_free; break; } if ((err = snd_ctl_add(card, kctl)) < 0) return err; } return 0;} static int __devinit snd_es1938_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; snd_card_t *card; es1938_t *chip; opl3_t *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_es1938_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; } strcpy(card->driver, "ES1938"); strcpy(card->shortname, "ESS ES1938 (Solo-1)"); sprintf(card->longname, "%s rev %i, irq %i", card->shortname, chip->revision, chip->irq); if ((err = snd_es1938_new_pcm(chip, 0)) < 0) { snd_card_free(card); return err; } if ((err = snd_es1938_mixer(chip)) < 0) { snd_card_free(card); return err; } if (snd_opl3_create(card, SLSB_REG(chip, FMLOWADDR), SLSB_REG(chip, FMHIGHADDR), OPL3_HW_OPL3, 1, &opl3) < 0) { printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { snd_card_free(card); return err; } if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); return err; } } if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); } /*else snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);*/#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) chip->gameport.io = chip->game_port; gameport_register_port(&chip->gameport);#endif 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_es1938_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { .name = "ESS ES1938 (Solo-1)", .id_table = snd_es1938_ids, .probe = snd_es1938_probe, .remove = __devexit_p(snd_es1938_remove), SND_PCI_PM_CALLBACKS};static int __init alsa_card_es1938_init(void){ return pci_module_init(&driver);}static void __exit alsa_card_es1938_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_es1938_init)module_exit(alsa_card_es1938_exit)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?