ens1370.c

来自「linux 内核源代码」· C语言 代码 · 共 1,967 行 · 第 1/5 页

C
1,967
字号
	ensoniq->u.es1371.ac97 = NULL;}struct es1371_quirk {	unsigned short vid;		/* vendor ID */	unsigned short did;		/* device ID */	unsigned char rev;		/* revision */};static int es1371_quirk_lookup(struct ensoniq *ensoniq,				struct es1371_quirk *list){	while (list->vid != (unsigned short)PCI_ANY_ID) {		if (ensoniq->pci->vendor == list->vid &&		    ensoniq->pci->device == list->did &&		    ensoniq->rev == list->rev)			return 1;		list++;	}	return 0;}static struct es1371_quirk es1371_spdif_present[] __devinitdata = {	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_CT5880_A },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_ES1373_8 },	{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }};static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = {	SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */	SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */	{ } /* end */};static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq,					    int has_spdif, int has_line){	struct snd_card *card = ensoniq->card;	struct snd_ac97_bus *pbus;	struct snd_ac97_template ac97;	int err;	static struct snd_ac97_bus_ops ops = {		.write = snd_es1371_codec_write,		.read = snd_es1371_codec_read,		.wait = snd_es1371_codec_wait,	};	if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0)		return err;	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = ensoniq;	ac97.private_free = snd_ensoniq_mixer_free_ac97;	ac97.scaps = AC97_SCAP_AUDIO;	if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0)		return err;	if (has_spdif > 0 ||	    (!has_spdif && es1371_quirk_lookup(ensoniq, es1371_spdif_present))) {		struct snd_kcontrol *kctl;		int i, index = 0;		ensoniq->spdif_default = ensoniq->spdif_stream =			SNDRV_PCM_DEFAULT_CON_SPDIF;		outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));		if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)			index++;		for (i = 0; i < ARRAY_SIZE(snd_es1371_mixer_spdif); i++) {			kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq);			if (!kctl)				return -ENOMEM;			kctl->id.index = index;			err = snd_ctl_add(card, kctl);			if (err < 0)				return err;		}	}	if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) {		/* mirror rear to front speakers */		ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24);		ensoniq->cssr |= ES_1373_REAR_BIT26;		err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_rear, ensoniq));		if (err < 0)			return err;	}	if (has_line > 0 ||	    snd_pci_quirk_lookup(ensoniq->pci, ens1373_line_quirk)) {		 err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line,						      ensoniq));		 if (err < 0)			 return err;	}	return 0;}#endif /* CHIP1371 *//* generic control callbacks for ens1370 */#ifdef CHIP1370#define ENSONIQ_CONTROL(xname, mask) \{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \  .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \  .private_value = mask }#define snd_ensoniq_control_info	snd_ctl_boolean_mono_infostatic int snd_ensoniq_control_get(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);	int mask = kcontrol->private_value;		spin_lock_irq(&ensoniq->reg_lock);	ucontrol->value.integer.value[0] = ensoniq->ctrl & mask ? 1 : 0;	spin_unlock_irq(&ensoniq->reg_lock);	return 0;}static int snd_ensoniq_control_put(struct snd_kcontrol *kcontrol,				   struct snd_ctl_elem_value *ucontrol){	struct ensoniq *ensoniq = snd_kcontrol_chip(kcontrol);	int mask = kcontrol->private_value;	unsigned int nval;	int change;		nval = ucontrol->value.integer.value[0] ? mask : 0;	spin_lock_irq(&ensoniq->reg_lock);	change = (ensoniq->ctrl & mask) != nval;	ensoniq->ctrl &= ~mask;	ensoniq->ctrl |= nval;	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));	spin_unlock_irq(&ensoniq->reg_lock);	return change;}/* * ENS1370 mixer */static struct snd_kcontrol_new snd_es1370_controls[2] __devinitdata = {ENSONIQ_CONTROL("PCM 0 Output also on Line-In Jack", ES_1370_XCTL0),ENSONIQ_CONTROL("Mic +5V bias", ES_1370_XCTL1)};#define ES1370_CONTROLS ARRAY_SIZE(snd_es1370_controls)static void snd_ensoniq_mixer_free_ak4531(struct snd_ak4531 *ak4531){	struct ensoniq *ensoniq = ak4531->private_data;	ensoniq->u.es1370.ak4531 = NULL;}static int __devinit snd_ensoniq_1370_mixer(struct ensoniq * ensoniq){	struct snd_card *card = ensoniq->card;	struct snd_ak4531 ak4531;	unsigned int idx;	int err;	/* try reset AK4531 */	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC));	inw(ES_REG(ensoniq, 1370_CODEC));	udelay(100);	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC));	inw(ES_REG(ensoniq, 1370_CODEC));	udelay(100);	memset(&ak4531, 0, sizeof(ak4531));	ak4531.write = snd_es1370_codec_write;	ak4531.private_data = ensoniq;	ak4531.private_free = snd_ensoniq_mixer_free_ak4531;	if ((err = snd_ak4531_mixer(card, &ak4531, &ensoniq->u.es1370.ak4531)) < 0)		return err;	for (idx = 0; idx < ES1370_CONTROLS; idx++) {		err = snd_ctl_add(card, snd_ctl_new1(&snd_es1370_controls[idx], ensoniq));		if (err < 0)			return err;	}	return 0;}#endif /* CHIP1370 */#ifdef SUPPORT_JOYSTICK#ifdef CHIP1371static int __devinit snd_ensoniq_get_joystick_port(int dev){	switch (joystick_port[dev]) {	case 0: /* disabled */	case 1: /* auto-detect */	case 0x200:	case 0x208:	case 0x210:	case 0x218:		return joystick_port[dev];	default:		printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]);		return 0;	}}#elsestatic inline int snd_ensoniq_get_joystick_port(int dev){	return joystick[dev] ? 0x200 : 0;}#endifstatic int __devinit snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev){	struct gameport *gp;	int io_port;	io_port = snd_ensoniq_get_joystick_port(dev);	switch (io_port) {	case 0:		return -ENOSYS;	case 1: /* auto_detect */		for (io_port = 0x200; io_port <= 0x218; io_port += 8)			if (request_region(io_port, 8, "ens137x: gameport"))				break;		if (io_port > 0x218) {			printk(KERN_WARNING "ens137x: no gameport ports available\n");			return -EBUSY;		}		break;	default:		if (!request_region(io_port, 8, "ens137x: gameport")) {			printk(KERN_WARNING "ens137x: gameport io port 0x%#x in use\n",			       io_port);			return -EBUSY;		}		break;	}	ensoniq->gameport = gp = gameport_allocate_port();	if (!gp) {		printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n");		release_region(io_port, 8);		return -ENOMEM;	}	gameport_set_name(gp, "ES137x");	gameport_set_phys(gp, "pci%s/gameport0", pci_name(ensoniq->pci));	gameport_set_dev_parent(gp, &ensoniq->pci->dev);	gp->io = io_port;	ensoniq->ctrl |= ES_JYSTK_EN;#ifdef CHIP1371	ensoniq->ctrl &= ~ES_1371_JOY_ASELM;	ensoniq->ctrl |= ES_1371_JOY_ASEL((io_port - 0x200) / 8);#endif	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));	gameport_register_port(ensoniq->gameport);	return 0;}static void snd_ensoniq_free_gameport(struct ensoniq *ensoniq){	if (ensoniq->gameport) {		int port = ensoniq->gameport->io;		gameport_unregister_port(ensoniq->gameport);		ensoniq->gameport = NULL;		ensoniq->ctrl &= ~ES_JYSTK_EN;		outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));		release_region(port, 8);	}}#elsestatic inline int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, long port) { return -ENOSYS; }static inline void snd_ensoniq_free_gameport(struct ensoniq *ensoniq) { }#endif /* SUPPORT_JOYSTICK *//* */static void snd_ensoniq_proc_read(struct snd_info_entry *entry, 				  struct snd_info_buffer *buffer){	struct ensoniq *ensoniq = entry->private_data;#ifdef CHIP1370	snd_iprintf(buffer, "Ensoniq AudioPCI ES1370\n\n");#else	snd_iprintf(buffer, "Ensoniq AudioPCI ES1371\n\n");#endif	snd_iprintf(buffer, "Joystick enable  : %s\n",		    ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");#ifdef CHIP1370	snd_iprintf(buffer, "MIC +5V bias     : %s\n",		    ensoniq->ctrl & ES_1370_XCTL1 ? "on" : "off");	snd_iprintf(buffer, "Line In to AOUT  : %s\n",		    ensoniq->ctrl & ES_1370_XCTL0 ? "on" : "off");#else	snd_iprintf(buffer, "Joystick port    : 0x%x\n",		    (ES_1371_JOY_ASELI(ensoniq->ctrl) * 8) + 0x200);#endif}static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq){	struct snd_info_entry *entry;	if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry))		snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read);}/* */static int snd_ensoniq_free(struct ensoniq *ensoniq){	snd_ensoniq_free_gameport(ensoniq);	if (ensoniq->irq < 0)		goto __hw_end;#ifdef CHIP1370	outl(ES_1370_SERR_DISABLE, ES_REG(ensoniq, CONTROL));	/* switch everything off */	outl(0, ES_REG(ensoniq, SERIAL));	/* clear serial interface */#else	outl(0, ES_REG(ensoniq, CONTROL));	/* switch everything off */	outl(0, ES_REG(ensoniq, SERIAL));	/* clear serial interface */#endif	synchronize_irq(ensoniq->irq);	pci_set_power_state(ensoniq->pci, 3);      __hw_end:#ifdef CHIP1370	if (ensoniq->dma_bug.area)		snd_dma_free_pages(&ensoniq->dma_bug);#endif	if (ensoniq->irq >= 0)		free_irq(ensoniq->irq, ensoniq);	pci_release_regions(ensoniq->pci);	pci_disable_device(ensoniq->pci);	kfree(ensoniq);	return 0;}static int snd_ensoniq_dev_free(struct snd_device *device){	struct ensoniq *ensoniq = device->device_data;	return snd_ensoniq_free(ensoniq);}#ifdef CHIP1371static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = {	SND_PCI_QUIRK_ID(0x107b, 0x2150),	/* Gateway Solo 2150 */	SND_PCI_QUIRK_ID(0x13bd, 0x100c),	/* EV1938 on Mebius PC-MJ100V */	SND_PCI_QUIRK_ID(0x1102, 0x5938),	/* Targa Xtender300 */	SND_PCI_QUIRK_ID(0x1102, 0x8938),	/* IPC Topnote G notebook */	{ } /* end */};static struct es1371_quirk es1371_ac97_reset_hack[] = {	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_CT5880_A },	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_ES1373_8 },	{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }};#endifstatic void snd_ensoniq_chip_init(struct ensoniq *ensoniq){#ifdef CHIP1371	int idx;#endif	/* this code was part of snd_ensoniq_create before intruduction	  * of suspend/resume	  */#ifdef CHIP1370	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));	outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));	outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE));	outl(ensoniq->dma_bug.addr, ES_REG(ensoniq, PHANTOM_FRAME));	out

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?