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

📄 es1968.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */static void es1968_update_hw_volume(unsigned long private_data){	struct es1968 *chip = (struct es1968 *) private_data;	int x, val;	unsigned long flags;	/* Figure out which volume control button was pushed,	   based on differences from the default register	   values. */	x = inb(chip->io_port + 0x1c) & 0xee;	/* Reset the volume control registers. */	outb(0x88, chip->io_port + 0x1c);	outb(0x88, chip->io_port + 0x1d);	outb(0x88, chip->io_port + 0x1e);	outb(0x88, chip->io_port + 0x1f);	if (chip->in_suspend)		return;	if (! chip->master_switch || ! chip->master_volume)		return;	/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */	spin_lock_irqsave(&chip->ac97_lock, flags);	val = chip->ac97->regs[AC97_MASTER];	switch (x) {	case 0x88:		/* mute */		val ^= 0x8000;		chip->ac97->regs[AC97_MASTER] = val;		outw(val, chip->io_port + ESM_AC97_DATA);		outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       &chip->master_switch->id);		break;	case 0xaa:		/* volume up */		if ((val & 0x7f) > 0)			val--;		if ((val & 0x7f00) > 0)			val -= 0x0100;		chip->ac97->regs[AC97_MASTER] = val;		outw(val, chip->io_port + ESM_AC97_DATA);		outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       &chip->master_volume->id);		break;	case 0x66:		/* volume down */		if ((val & 0x7f) < 0x1f)			val++;		if ((val & 0x7f00) < 0x1f00)			val += 0x0100;		chip->ac97->regs[AC97_MASTER] = val;		outw(val, chip->io_port + ESM_AC97_DATA);		outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,			       &chip->master_volume->id);		break;	}	spin_unlock_irqrestore(&chip->ac97_lock, flags);}/* * interrupt handler */static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id){	struct es1968 *chip = dev_id;	u32 event;	if (!(event = inb(chip->io_port + 0x1A)))		return IRQ_NONE;	outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);	if (event & ESM_HWVOL_IRQ)		tasklet_hi_schedule(&chip->hwvol_tq); /* we'll do this later */	/* else ack 'em all, i imagine */	outb(0xFF, chip->io_port + 0x1A);	if ((event & ESM_MPU401_IRQ) && chip->rmidi) {		snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);	}	if (event & ESM_SOUND_IRQ) {		struct esschan *es;		spin_lock(&chip->substream_lock);		list_for_each_entry(es, &chip->substream_list, list) {			if (es->running)				snd_es1968_update_pcm(chip, es);		}		spin_unlock(&chip->substream_lock);		if (chip->in_measurement) {			unsigned int curp = __apu_get_register(chip, chip->measure_apu, 5);			if (curp < chip->measure_lastpos)				chip->measure_count++;			chip->measure_lastpos = curp;		}	}	return IRQ_HANDLED;}/* *  Mixer stuff */static int __devinitsnd_es1968_mixer(struct es1968 *chip){	struct snd_ac97_bus *pbus;	struct snd_ac97_template ac97;	struct snd_ctl_elem_id id;	int err;	static struct snd_ac97_bus_ops ops = {		.write = snd_es1968_ac97_write,		.read = snd_es1968_ac97_read,	};	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)		return err;	pbus->no_vra = 1; /* ES1968 doesn't need VRA */	memset(&ac97, 0, sizeof(ac97));	ac97.private_data = chip;	if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0)		return err;	/* attach master switch / volumes for h/w volume control */	memset(&id, 0, sizeof(id));	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;	strcpy(id.name, "Master Playback Switch");	chip->master_switch = snd_ctl_find_id(chip->card, &id);	memset(&id, 0, sizeof(id));	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;	strcpy(id.name, "Master Playback Volume");	chip->master_volume = snd_ctl_find_id(chip->card, &id);	return 0;}/* * reset ac97 codec */static void snd_es1968_ac97_reset(struct es1968 *chip){	unsigned long ioaddr = chip->io_port;	unsigned short save_ringbus_a;	unsigned short save_68;	unsigned short w;	unsigned int vend;	/* save configuration */	save_ringbus_a = inw(ioaddr + 0x36);	//outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38); /* clear second codec id? */	/* set command/status address i/o to 1st codec */	outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);	outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);	/* disable ac link */	outw(0x0000, ioaddr + 0x36);	save_68 = inw(ioaddr + 0x68);	pci_read_config_word(chip->pci, 0x58, &w);	/* something magical with gpio and bus arb. */	pci_read_config_dword(chip->pci, PCI_SUBSYSTEM_VENDOR_ID, &vend);	if (w & 1)		save_68 |= 0x10;	outw(0xfffe, ioaddr + 0x64);	/* unmask gpio 0 */	outw(0x0001, ioaddr + 0x68);	/* gpio write */	outw(0x0000, ioaddr + 0x60);	/* write 0 to gpio 0 */	udelay(20);	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio 1 */	msleep(20);	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */	outw((inw(ioaddr + 0x38) & 0xfffc) | 0x1, ioaddr + 0x38);	outw((inw(ioaddr + 0x3a) & 0xfffc) | 0x1, ioaddr + 0x3a);	outw((inw(ioaddr + 0x3c) & 0xfffc) | 0x1, ioaddr + 0x3c);	/* now the second codec */	/* disable ac link */	outw(0x0000, ioaddr + 0x36);	outw(0xfff7, ioaddr + 0x64);	/* unmask gpio 3 */	save_68 = inw(ioaddr + 0x68);	outw(0x0009, ioaddr + 0x68);	/* gpio write 0 & 3 ?? */	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio */	udelay(20);	outw(0x0009, ioaddr + 0x60);	/* write 9 to gpio */	msleep(500);	//outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);	outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);	outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);#if 0				/* the loop here needs to be much better if we want it.. */	snd_printk(KERN_INFO "trying software reset\n");	/* try and do a software reset */	outb(0x80 | 0x7c, ioaddr + 0x30);	for (w = 0;; w++) {		if ((inw(ioaddr + 0x30) & 1) == 0) {			if (inb(ioaddr + 0x32) != 0)				break;			outb(0x80 | 0x7d, ioaddr + 0x30);			if (((inw(ioaddr + 0x30) & 1) == 0)			    && (inb(ioaddr + 0x32) != 0))				break;			outb(0x80 | 0x7f, ioaddr + 0x30);			if (((inw(ioaddr + 0x30) & 1) == 0)			    && (inb(ioaddr + 0x32) != 0))				break;		}		if (w > 10000) {			outb(inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);	/* do a software reset */			msleep(500);	/* oh my.. */			outb(inb(ioaddr + 0x37) & ~0x08,				ioaddr + 0x37);			udelay(1);			outw(0x80, ioaddr + 0x30);			for (w = 0; w < 10000; w++) {				if ((inw(ioaddr + 0x30) & 1) == 0)					break;			}		}	}#endif	if (vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {		/* turn on external amp? */		outw(0xf9ff, ioaddr + 0x64);		outw(inw(ioaddr + 0x68) | 0x600, ioaddr + 0x68);		outw(0x0209, ioaddr + 0x60);	}	/* restore.. */	outw(save_ringbus_a, ioaddr + 0x36);	/* Turn on the 978 docking chip.	   First frob the "master output enable" bit,	   then set most of the playback volume control registers to max. */	outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);	outb(0xff, ioaddr+0xc3);	outb(0xff, ioaddr+0xc4);	outb(0xff, ioaddr+0xc6);	outb(0xff, ioaddr+0xc8);	outb(0x3f, ioaddr+0xcf);	outb(0x3f, ioaddr+0xd0);}static void snd_es1968_reset(struct es1968 *chip){	/* Reset */	outw(ESM_RESET_MAESTRO | ESM_RESET_DIRECTSOUND,	     chip->io_port + ESM_PORT_HOST_IRQ);	udelay(10);	outw(0x0000, chip->io_port + ESM_PORT_HOST_IRQ);	udelay(10);}/* * initialize maestro chip */static void snd_es1968_chip_init(struct es1968 *chip){	struct pci_dev *pci = chip->pci;	int i;	unsigned long iobase  = chip->io_port;	u16 w;	u32 n;	/* We used to muck around with pci config space that	 * we had no business messing with.  We don't know enough	 * about the machine to know which DMA mode is appropriate, 	 * etc.  We were guessing wrong on some machines and making	 * them unhappy.  We now trust in the BIOS to do things right,	 * which almost certainly means a new host of problems will	 * arise with broken BIOS implementations.  screw 'em. 	 * We're already intolerant of machines that don't assign	 * IRQs.	 */		/* Config Reg A */	pci_read_config_word(pci, ESM_CONFIG_A, &w);	w &= ~DMA_CLEAR;	/* Clear DMA bits */	w &= ~(PIC_SNOOP1 | PIC_SNOOP2);	/* Clear Pic Snoop Mode Bits */	w &= ~SAFEGUARD;	/* Safeguard off */	w |= POST_WRITE;	/* Posted write */	w |= PCI_TIMING;	/* PCI timing on */	/* XXX huh?  claims to be reserved.. */	w &= ~SWAP_LR;		/* swap left/right 				   seems to only have effect on SB				   Emulation */	w &= ~SUBTR_DECODE;	/* Subtractive decode off */	pci_write_config_word(pci, ESM_CONFIG_A, w);	/* Config Reg B */	pci_read_config_word(pci, ESM_CONFIG_B, &w);	w &= ~(1 << 15);	/* Turn off internal clock multiplier */	/* XXX how do we know which to use? */	w &= ~(1 << 14);	/* External clock */	w &= ~SPDIF_CONFB;	/* disable S/PDIF output */	w |= HWV_CONFB;		/* HWV on */	w |= DEBOUNCE;		/* Debounce off: easier to push the HW buttons */	w &= ~GPIO_CONFB;	/* GPIO 4:5 */	w |= CHI_CONFB;		/* Disconnect from the CHI.  Enabling this made a dell 7500 work. */	w &= ~IDMA_CONFB;	/* IDMA off (undocumented) */	w &= ~MIDI_FIX;		/* MIDI fix off (undoc) */	w &= ~(1 << 1);		/* reserved, always write 0 */	w &= ~IRQ_TO_ISA;	/* IRQ to ISA off (undoc) */	pci_write_config_word(pci, ESM_CONFIG_B, w);	/* DDMA off */	pci_read_config_word(pci, ESM_DDMA, &w);	w &= ~(1 << 0);	pci_write_config_word(pci, ESM_DDMA, w);	/*	 *	Legacy mode	 */	pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &w);	w |= ESS_DISABLE_AUDIO;	/* Disable Legacy Audio */	w &= ~ESS_ENABLE_SERIAL_IRQ;	/* Disable SIRQ */	w &= ~(0x1f);		/* disable mpu irq/io, game port, fm, SB */	pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, w);	/* Set up 978 docking control chip. */	pci_read_config_word(pci, 0x58, &w);	w|=1<<2;	/* Enable 978. */	w|=1<<3;	/* Turn on 978 hardware volume control. */	w&=~(1<<11);	/* Turn on 978 mixer volume control. */	pci_write_config_word(pci, 0x58, w);		/* Sound Reset */	snd_es1968_reset(chip);	/*	 *	Ring Bus Setup	 */	/* setup usual 0x34 stuff.. 0x36 may be chip specific */	outw(0xC090, iobase + ESM_RING_BUS_DEST); /* direct sound, stereo */	udelay(20);	outw(0x3000, iobase + ESM_RING_BUS_CONTR_A); /* enable ringbus/serial */	udelay(20);	/*	 *	Reset the CODEC	 */	 	snd_es1968_ac97_reset(chip);	/* Ring Bus Control B */	n = inl(iobase + ESM_RING_BUS_CONTR_B);	n &= ~RINGB_EN_SPDIF;	/* SPDIF off */	//w |= RINGB_EN_2CODEC;	/* enable 2nd codec */	outl(n, iobase + ESM_RING_BUS_CONTR_B);	/* Set hardware volume control registers to midpoints.	   We can tell which button was pushed based on how they change. */	outb(0x88, iobase+0x1c);	outb(0x88, iobase+0x1d);	outb(0x88, iobase+0x1e);	outb(0x88, iobase+0x1f);	/* it appears some maestros (dell 7500) only work if these are set,	   regardless of wether we use the assp or not. */	outb(0, iobase + ASSP_CONTROL_B);	outb(3, iobase + ASSP_CONTROL_A);	/* M: Reserved bits... */	outb(0, iobase + ASSP_CONTROL_C);	/* M: Disable ASSP, ASSP IRQ's and FM Port */	/*	 * set up wavecache	 */	for (i = 0; i < 16; i++) {		/* Write 0 into the buffer area 0x1E0->1EF */		outw(0x01E0 + i, iobase + WC_INDEX);		outw(0x0000, iobase + WC_DATA);		/* The 1.10 test program seem to write 0 into the buffer area		 * 0x1D0-0x1DF too.*/		outw(0x01D0 + i, iobase + WC_INDEX);		outw(0x0000, iobase + WC_DATA);	}	wave_set_register(chip, IDR7_WAVE_ROMRAM,			  (wave_get_register(chip, IDR7_WAVE_ROMRAM) & 0xFF00));	wave_set_register(chip, IDR7_WAVE_ROMRAM,			  wave_get_register(chip, IDR7_WAVE_ROMRAM) | 0x100);	wave_set_register(chip, IDR7_WAVE_ROMRAM,			  wave_get_register(chip, IDR7_WAVE_ROMRAM) & ~0x200);	wave_set_register(chip, IDR7_WAVE_ROMRAM,			  wave_get_register(chip, IDR7_WAVE_ROMRAM) | ~0x400);	maestro_write(chip, IDR2_CRAM_DATA, 0x0000);	/* Now back to the DirectSound stuff */	/* audio serial configuration.. ? */	maestro_write(chip, 0x08, 0xB004);	maestro_write(chip, 0x09, 0x001B);	maestro_write(chip, 0x0A, 0x8000);	maestro_write(chip, 0x0B, 0x3F37);	maestro_write(chip, 0x0C, 0x0098);	/* parallel in, has something to do with recording :) */	maestro_write(chip, 0x0C,		      (maestro_read(chip, 0x0C) & ~0xF000) | 0x8000);	/* parallel out */	maestro_write(chip, 0x0C,		      (maestro_read(chip, 0x0C) & ~0x0F00) | 0x0500);	maestro_write(chip, 0x0D, 0x7632);	/* Wave cache control on - test off, sg off, 	   enable, enable extra chans 1Mb */	w = inw(iobase + WC_CONTROL);	w &= ~0xFA00;		/* Seems to be reserved? I don't know */	w |= 0xA000;		/* reserved... I don't know */	w &= ~0x0200;		/* Channels 56,57,58,59 as Extra Play,Rec Channel enable				   Seems to crash the Computer if enabled... */	w |= 0x0100;		/* Wave Cache Operation Enabled */	w |= 0x0080;		/* Channels 60/61 as Placback/Record enabled */	w &= ~0x0060;		/* Clear Wavtable Size */	w |= 0x0020;		/* Wavetable Size : 1MB */	/* Bit 4 is reserved */	w &= ~0x000C;		/* DMA Stuff? I don't understand what the datasheet means */	/* Bit 1 is reserved */	w &= ~0x0001;		/* Test Mode off */	outw(w, iobase + WC_CONTROL);	/* Now clear the APU control ram */	for (i = 0; i < NR_APUS; i++) {		for (w = 0; w < NR_APU_REGS; w++)			apu_set_register(chip, i, w, 0);	}}/* Enable IRQ's */static void snd_es1968_start_irq(struct es1968 

⌨️ 快捷键说明

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