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 + -
显示快捷键?