⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 es1938.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * initialize the chip - used by resume callback, too */static void snd_es1938_chip_init(struct es1938 *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(struct pci_dev *pci, pm_message_t state){	struct snd_card *card = pci_get_drvdata(pci);	struct es1938 *chip = card->private_data;	unsigned char *s, *d;	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);	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 */	if (chip->irq >= 0) {		synchronize_irq(chip->irq);		free_irq(chip->irq, chip);		chip->irq = -1;	}	pci_disable_device(pci);	pci_save_state(pci);	pci_set_power_state(pci, pci_choose_state(pci, state));	return 0;}static int es1938_resume(struct pci_dev *pci){	struct snd_card *card = pci_get_drvdata(pci);	struct es1938 *chip = card->private_data;	unsigned char *s, *d;	pci_set_power_state(pci, PCI_D0);	pci_restore_state(pci);	if (pci_enable_device(pci) < 0) {		printk(KERN_ERR "es1938: pci_enable_device failed, "		       "disabling device\n");		snd_card_disconnect(card);		return -EIO;	}	if (request_irq(pci->irq, snd_es1938_interrupt,			IRQF_SHARED, "ES1938", chip)) {		printk(KERN_ERR "es1938: unable to grab IRQ %d, "		       "disabling device\n", pci->irq);		snd_card_disconnect(card);		return -EIO;	}	chip->irq = pci->irq;	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 */#ifdef SUPPORT_JOYSTICKstatic int __devinit snd_es1938_create_gameport(struct es1938 *chip){	struct gameport *gp;	chip->gameport = gp = gameport_allocate_port();	if (!gp) {		printk(KERN_ERR "es1938: cannot allocate memory for gameport\n");		return -ENOMEM;	}	gameport_set_name(gp, "ES1938");	gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));	gameport_set_dev_parent(gp, &chip->pci->dev);	gp->io = chip->game_port;	gameport_register_port(gp);	return 0;}static void snd_es1938_free_gameport(struct es1938 *chip){	if (chip->gameport) {		gameport_unregister_port(chip->gameport);		chip->gameport = NULL;	}}#elsestatic inline int snd_es1938_create_gameport(struct es1938 *chip) { return -ENOSYS; }static inline void snd_es1938_free_gameport(struct es1938 *chip) { }#endif /* SUPPORT_JOYSTICK */static int snd_es1938_free(struct es1938 *chip){	/* disable irqs */	outb(0x00, SLIO_REG(chip, IRQCONTROL));	if (chip->rmidi)		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0);	snd_es1938_free_gameport(chip);	if (chip->irq >= 0) {		synchronize_irq(chip->irq);		free_irq(chip->irq, chip);	}	pci_release_regions(chip->pci);	pci_disable_device(chip->pci);	kfree(chip);	return 0;}static int snd_es1938_dev_free(struct snd_device *device){	struct es1938 *chip = device->device_data;	return snd_es1938_free(chip);}static int __devinit snd_es1938_create(struct snd_card *card,				    struct pci_dev * pci,				    struct es1938 ** rchip){	struct es1938 *chip;	int err;	static struct snd_device_ops 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, 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;        }	chip = kzalloc(sizeof(*chip), GFP_KERNEL);	if (chip == NULL) {		pci_disable_device(pci);		return -ENOMEM;	}	spin_lock_init(&chip->reg_lock);	spin_lock_init(&chip->mixer_lock);	chip->card = card;	chip->pci = pci;	chip->irq = -1;	if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) {		kfree(chip);		pci_disable_device(pci);		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, IRQF_SHARED,			"ES1938", chip)) {		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);		snd_es1938_free(chip);		return -EBUSY;	}	chip->irq = pci->irq;#ifdef ES1938_DDEBUG	snd_printk(KERN_DEBUG "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);	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 es1938 *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) {		// the following line is evil! It switches off MIDI interrupt handling after the first interrupt received.		// replacing the last 0 by 0x40 works for ESS-Solo1, but just doing nothing works as well!		// andreas@flying-snail.de		// 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);		}	}	return IRQ_RETVAL(handled);}#define ES1938_DMA_SIZE 64static int __devinit snd_es1938_mixer(struct es1938 *chip){	struct snd_card *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++) {		struct snd_kcontrol *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;	struct snd_card *card;	struct es1938 *chip;	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_es1938_create(card, pci, &chip)) < 0) {		snd_card_free(card);		return err;	}	card->private_data = chip;	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, MPU401_INFO_INTEGRATED,				chip->irq, 0, &chip->rmidi) < 0) {		printk(KERN_ERR "es1938: unable to initialize MPU-401\n");	} else {		// this line is vital for MIDI interrupt handling on ess-solo1		// andreas@flying-snail.de		snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0x40);	}	snd_es1938_create_gameport(chip);	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),#ifdef CONFIG_PM	.suspend = es1938_suspend,	.resume = es1938_resume,#endif};static int __init alsa_card_es1938_init(void){	return pci_register_driver(&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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -