es18xx.c
来自「linux 内核源代码」· C语言 代码 · 共 2,181 行 · 第 1/5 页
C
2,181 行
return 0;}static int snd_es18xx_resume(struct snd_card *card){ struct snd_audiodrive *acard = card->private_data; struct snd_es18xx *chip = acard->chip; /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); return 0;}#endif /* CONFIG_PM */static int snd_es18xx_free(struct snd_es18xx *chip){ release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_ctrl_port); release_and_free_resource(chip->res_mpu_port); if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); } if (chip->dma2 >= 0 && chip->dma1 != chip->dma2) { disable_dma(chip->dma2); free_dma(chip->dma2); } kfree(chip); return 0;}static int snd_es18xx_dev_free(struct snd_device *device){ struct snd_es18xx *chip = device->device_data; return snd_es18xx_free(chip);}static int __devinit snd_es18xx_new_device(struct snd_card *card, unsigned long port, unsigned long mpu_port, unsigned long fm_port, int irq, int dma1, int dma2, struct snd_es18xx ** rchip){ struct snd_es18xx *chip; static struct snd_device_ops ops = { .dev_free = snd_es18xx_dev_free, }; int err; *rchip = NULL; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); spin_lock_init(&chip->ctrl_lock); chip->card = card; chip->port = port; chip->mpu_port = mpu_port; chip->fm_port = fm_port; chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; chip->audio2_vol = 0x00; chip->active = 0; if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) { snd_es18xx_free(chip); snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) { snd_es18xx_free(chip); snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "ES18xx DMA 1")) { snd_es18xx_free(chip); snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) { snd_es18xx_free(chip); snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; if (snd_es18xx_probe(chip) < 0) { snd_es18xx_free(chip); return -ENODEV; } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_es18xx_free(chip); return err; } *rchip = chip; return 0;}static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip){ struct snd_card *card; int err; unsigned int idx; card = chip->card; strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(&snd_es18xx_base_controls[idx], chip); if (chip->caps & ES18XX_HWV) { switch (idx) { case 0: chip->master_volume = kctl; kctl->private_free = snd_es18xx_hwv_free; break; case 1: chip->master_switch = kctl; kctl->private_free = snd_es18xx_hwv_free; break; } } if ((err = snd_ctl_add(card, kctl)) < 0) return err; } if (chip->caps & ES18XX_PCM2) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_pcm2_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm2_controls[idx], chip))) < 0) return err; } } else { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_pcm1_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_pcm1_controls[idx], chip))) < 0) return err; } } if (chip->caps & ES18XX_RECMIX) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_recmix_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip))) < 0) return err; } } switch (chip->version) { default: if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre1_control, chip))) < 0) return err; break; case 0x1869: case 0x1879: if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_micpre2_control, chip))) < 0) return err; break; } if (chip->caps & ES18XX_SPATIALIZER) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_spatializer_controls); idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_spatializer_controls[idx], chip))) < 0) return err; } } if (chip->caps & ES18XX_HWV) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_hw_volume_controls); idx++) { struct snd_kcontrol *kctl; kctl = snd_ctl_new1(&snd_es18xx_hw_volume_controls[idx], chip); if (idx == 0) chip->hw_volume = kctl; else chip->hw_switch = kctl; kctl->private_free = snd_es18xx_hwv_free; if ((err = snd_ctl_add(card, kctl)) < 0) return err; } } /* finish initializing other chipset specific controls */ if (chip->version != 0x1868) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_speaker, chip)); if (err < 0) return err; } if (chip->version == 0x1869) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1869); idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1869[idx], chip)); if (err < 0) return err; } } else if (chip->version == 0x1878) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1878, chip)); if (err < 0) return err; } else if (chip->version == 0x1879) { for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1879); idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1879[idx], chip)); if (err < 0) return err; } } return 0;} /* Card level */MODULE_AUTHOR("Christian Fischbach <fishbach@pool.informatik.rwth-aachen.de>, Abramo Bagnara <abramo@alsa-project.org>"); MODULE_DESCRIPTION("ESS ES18xx AudioDrive");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{ESS,ES1868 PnP AudioDrive}," "{ESS,ES1869 PnP AudioDrive}," "{ESS,ES1878 PnP AudioDrive}," "{ESS,ES1879 PnP AudioDrive}," "{ESS,ES1887 PnP AudioDrive}," "{ESS,ES1888 PnP AudioDrive}," "{ESS,ES1887 AudioDrive}," "{ESS,ES1888 AudioDrive}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */#ifdef CONFIG_PNPstatic int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};#endifstatic long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */#ifndef CONFIG_PNPstatic long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};#elsestatic long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;#endifstatic long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for ES18xx soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for ES18xx soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable ES18xx soundcard.");#ifdef CONFIG_PNPmodule_param_array(isapnp, bool, NULL, 0444);MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");#endifmodule_param_array(port, long, NULL, 0444);MODULE_PARM_DESC(port, "Port # for ES18xx driver.");module_param_array(mpu_port, long, NULL, 0444);MODULE_PARM_DESC(mpu_port, "MPU-401 port # for ES18xx driver.");module_param_array(fm_port, long, NULL, 0444);MODULE_PARM_DESC(fm_port, "FM port # for ES18xx driver.");module_param_array(irq, int, NULL, 0444);MODULE_PARM_DESC(irq, "IRQ # for ES18xx driver.");module_param_array(dma1, int, NULL, 0444);MODULE_PARM_DESC(dma1, "DMA 1 # for ES18xx driver.");module_param_array(dma2, int, NULL, 0444);MODULE_PARM_DESC(dma2, "DMA 2 # for ES18xx driver.");#ifdef CONFIG_PNPstatic int isa_registered;static int pnp_registered;static int pnpc_registered;static struct pnp_device_id snd_audiodrive_pnpbiosids[] = { { .id = "ESS1869" }, { .id = "ESS1879" }, { .id = "" } /* end */};MODULE_DEVICE_TABLE(pnp, snd_audiodrive_pnpbiosids);/* PnP main device initialization */static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev, struct pnp_resource_table *cfg){ int err; pnp_init_resource_table(cfg); if (port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], port[dev], 16); if (fm_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); if (mpu_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[2], mpu_port[dev], 2); if (dma1[dev] != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); if (dma2[dev] != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); if (irq[dev] != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); if (pnp_device_is_isapnp(pdev)) { err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0) snd_printk(KERN_ERR PFX "PnP manual resources are invalid, using auto config\n"); } err = pnp_activate_dev(pdev); if (err < 0) { snd_printk(KERN_ERR PFX "PnP configure failure (out of resources?)\n"); return -EBUSY; } /* ok. hack using Vendor-Defined Card-Level registers */ /* skip csn and logdev initialization - already done in isapnp_configure */ if (pnp_device_is_isapnp(pdev)) { isapnp_cfg_begin(isapnp_card_number(pdev), isapnp_csn_number(pdev)); isapnp_write_byte(0x27, pnp_irq(pdev, 0)); /* Hardware Volume IRQ Number */ if (mpu_port[dev] != SNDRV_AUTO_PORT) isapnp_write_byte(0x28, pnp_irq(pdev, 0)); /* MPU-401 IRQ Number */ isapnp_write_byte(0x72, pnp_irq(pdev, 0)); /* second IRQ */ isapnp_cfg_end(); } port[dev] = pnp_port_start(pdev, 0); fm_port[dev] = pnp_port_start(pdev, 1); mpu_port[dev] = pnp_port_start(pdev, 2); dma1[dev] = pnp_dma(pdev, 0); dma2[dev] = pnp_dma(pdev, 1); irq[dev] = pnp_irq(pdev, 0); snd_printdd("PnP ES18xx: port=0x%lx, fm port=0x%lx, mpu port=0x%lx\n", port[dev], fm_port[dev], mpu_port[dev]); snd_printdd("PnP ES18xx: dma1=%i, dma2=%i, irq=%i\n", dma1[dev], dma2[dev], irq[dev]); return 0;}static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, struct pnp_dev *pdev){ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); if (!cfg) return -ENOMEM; acard->dev = pdev; if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { kfree(cfg); return -EBUSY; } kfree(cfg); return 0;}static struct pnp_card_device_id snd_audiodrive_pnpids[] = { /* ESS 1868 (integrated on Compaq dual P-Pro motherboard and Genius 18PnP 3D) */ { .id = "ESS1868", .devs = { { "ESS1868" }, { "ESS0000" } } }, /* ESS 1868 (integrated on Maxisound Cards) */ { .id = "ESS1868", .devs = { { "ESS8601" }, { "ESS8600" } } }, /* ESS 1868 (integrated on Maxisound Cards) */ { .id = "ESS1868", .devs = { { "ESS8611" }, { "ESS8610" } } }, /* ESS ES1869 Plug and Play AudioDrive */ { .id = "ESS0003", .devs = { { "ESS1869" }, { "ESS0006" } } }, /* ESS 1869 */ { .id = "ESS1869", .devs = { { "ESS1869" }, { "ESS0006" } } }, /* ESS 1878 */ { .id = "ESS1878", .devs = { { "ESS1878" }, { "ESS0004" } } }, /* ESS 1879 */ { .id = "ESS1879", .devs = { { "ESS1879" }, { "ESS0009" } } }, /* --- */ { .id = "" } /* end */};MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids);static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, struct pnp_card_link *card, const struct pnp_card_device_id *id){ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); if (!cfg) return -ENOMEM; acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); if (acard->dev == NULL) { kfree(cfg); return -EBUSY; } acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); if (acard->devc == NULL) { kfree(cfg); return -EBUSY; } /* Control port initialization */ if (pnp_activate_dev(acard->devc) < 0) { kfree(cfg); snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); return -EAGAIN; } snd_printdd("pnp: port=0x%llx\n", (unsigned long long)pnp_port_start(acard->devc, 0)); if (snd_audiodrive_pnp_init_main(dev, acard->dev, cfg) < 0) { kfree(cfg); return -EBUSY; } kfree(cfg); return 0;}#endif /* CONFIG_PNP */#ifdef CONFIG_PNP#define is_isapnp_selected(dev) isapnp[dev]#else#define is_isapnp_selected(dev) 0#endifstatic struct snd_card *snd_es18xx_card_new(int dev){ return snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_audiodrive));}static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev){ struct snd_audiodrive *acard = card->private_data; struct snd_es18xx *chip; struct snd_opl3 *opl3; int err; if ((err = snd_es18xx_new_device(card, port[dev], mpu_port[dev], f
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?