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