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

📄 cs46xx_lib.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);	/*	 *  Wait until we've sampled input slots 3 and 4 as valid, meaning that	 *  the codec is pumping ADC data across the AC-link.	 */	timeout = 150;	while (timeout-- > 0) {		/*		 *  Read the input slot valid register and see if input slots 3 and		 *  4 are valid yet.		 */		if ((snd_cs46xx_peekBA0(chip, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))			goto ok2;		if (busywait)			mdelay(10);		else {			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout((HZ+99)/100);		}	}	snd_printk("create - never read ISV3 & ISV4 from AC'97\n");	snd_cs46xx_free(chip);	return -EIO; ok2:	/*	 *  Now, assert valid frame and the slot 3 and 4 valid bits.  This will	 *  commense the transfer of digital audio data to the AC97 codec.	 */	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);	/*	 *  Power down the DAC and ADC.  We will power them up (if) when we need	 *  them.	 */	/* snd_cs46xx_pokeBA0(chip, BA0_AC97_POWERDOWN, 0x300); */	/*	 *  Turn off the Processor by turning off the software clock enable flag in 	 *  the clock control register.	 */	/* tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1) & ~CLKCR1_SWCE; */	/* snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); */	/*         *  Reset the processor.         */	snd_cs46xx_reset(chip);	/*         *  Download the image to the processor.	 */	if (snd_cs46xx_download_image(chip) < 0) {		snd_printk("image download error\n");		snd_cs46xx_free(chip);		return -EIO;	}	/*         *  Stop playback DMA.	 */	tmp = snd_cs46xx_peek(chip, BA1_PCTL);	chip->play.ctl = tmp & 0xffff0000;	snd_cs46xx_poke(chip, BA1_PCTL, tmp & 0x0000ffff);	/*         *  Stop capture DMA.	 */	tmp = snd_cs46xx_peek(chip, BA1_CCTL);	chip->capt.ctl = tmp & 0x0000ffff;	snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000);	snd_cs46xx_set_play_sample_rate(chip, 8000);	snd_cs46xx_set_capture_sample_rate(chip, 8000);	snd_cs46xx_proc_start(chip);	/*	 *  Enable interrupts on the part.	 */	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);	tmp = snd_cs46xx_peek(chip, BA1_PFIE);	tmp &= ~0x0000f03f;	snd_cs46xx_poke(chip, BA1_PFIE, tmp);	/* playback interrupt enable */	tmp = snd_cs46xx_peek(chip, BA1_CIE);	tmp &= ~0x0000003f;	tmp |=  0x00000001;	snd_cs46xx_poke(chip, BA1_CIE, tmp);	/* capture interrupt enable */		/* set the attenuation to 0dB */ 	snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);	snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);	return 0;}/* *	AMP control - null AMP */ static void amp_none(cs46xx_t *chip, int change){	}/* *	Crystal EAPD mode */ static void amp_voyetra(cs46xx_t *chip, int change){	/* Manage the EAPD bit on the Crystal 4297 	   and the Analog AD1885 */	   	int old = chip->amplifier;	int oval, val;		chip->amplifier += change;	oval = snd_cs46xx_codec_read(chip, AC97_POWERDOWN);	val = oval;	if (chip->amplifier && !old) {		/* Turn the EAPD amp on */		val |= 0x8000;	} else if (old && !chip->amplifier) {		/* Turn the EAPD amp off */		val &= ~0x8000;	}	if (val != oval) {		snd_cs46xx_codec_write(chip, AC97_POWERDOWN, val);		if (chip->eapd_switch)			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,				       &chip->eapd_switch->id);	}}/* *	Game Theatre XP card - EGPIO[2] is used to enable the external amp. */ static void amp_hercules(cs46xx_t *chip, int change){	int old = chip->amplifier;	chip->amplifier += change;	if (chip->amplifier && !old) {		snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, 				   EGPIODR_GPOE2);     /* enable EGPIO2 output */		snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, 				   EGPIOPTR_GPPT2);   /* open-drain on output */	} else if (old && !chip->amplifier) {		snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, 0); /* disable */		snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, 0); /* disable */	}}#if 0/* *	Untested */ static void amp_voyetra_4294(cs46xx_t *chip, int change){	chip->amplifier += change;	if (chip->amplifier) {		/* Switch the GPIO pins 7 and 8 to open drain */		snd_cs46xx_codec_write(chip, 0x4C,				       snd_cs46xx_codec_read(chip, 0x4C) & 0xFE7F);		snd_cs46xx_codec_write(chip, 0x4E,				       snd_cs46xx_codec_read(chip, 0x4E) | 0x0180);		/* Now wake the AMP (this might be backwards) */		snd_cs46xx_codec_write(chip, 0x54,				       snd_cs46xx_codec_read(chip, 0x54) & ~0x0180);	} else {		snd_cs46xx_codec_write(chip, 0x54,				       snd_cs46xx_codec_read(chip, 0x54) | 0x0180);	}}#endif/* * piix4 pci ids */#ifndef PCI_VENDOR_ID_INTEL#define PCI_VENDOR_ID_INTEL 0x8086#endif /* PCI_VENDOR_ID_INTEL */#ifndef PCI_DEVICE_ID_INTEL_82371AB_3#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113#endif /* PCI_DEVICE_ID_INTEL_82371AB_3 *//* *	Handle the CLKRUN on a thinkpad. We must disable CLKRUN support *	whenever we need to beat on the chip. * *	The original idea and code for this hack comes from David Kaiser at *	Linuxcare. Perhaps one day Crystal will document their chips well *	enough to make them useful. */ static void clkrun_hack(cs46xx_t *chip, int change){	u16 control;	int old;		if (chip->acpi_dev == NULL)		return;	old = chip->amplifier;	chip->amplifier += change;		/* Read ACPI port */		control = inw(chip->acpi_port + 0x10);	/* Flip CLKRUN off while running */	if (! chip->amplifier && old)		outw(control | 0x2000, chip->acpi_port + 0x10);	else if (chip->amplifier && ! old)		outw(control & ~0x2000, chip->acpi_port + 0x10);}	/* * detect intel piix4 */static void clkrun_init(cs46xx_t *chip){	u8 pp;	chip->acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);	if (chip->acpi_dev == NULL)		return;		/* Not a thinkpad thats for sure */	/* Find the control port */			pci_read_config_byte(chip->acpi_dev, 0x41, &pp);	chip->acpi_port = pp << 8;}/* * Card subid table */ struct cs_card_type{	u16 vendor;	u16 id;	char *name;	void (*init)(cs46xx_t *);	void (*amp)(cs46xx_t *, int);	void (*active)(cs46xx_t *, int);};static struct cs_card_type __initdata cards[] = {	{0x1489, 0x7001, "Genius Soundmaker 128 value", NULL, amp_none, NULL},	{0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL},	{0x1071, 0x6003, "Mitac MI6020/21", NULL, amp_voyetra, NULL},	{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	{0x1681, 0x0051, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	{0x1681, 0x0052, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	{0x1681, 0x0053, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	{0x1681, 0x0054, "Hercules Game Theatre XP", NULL, amp_hercules, NULL},	/* Not sure if the 570 needs the clkrun hack */	{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", clkrun_init, NULL, clkrun_hack},	{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", clkrun_init, NULL, clkrun_hack},	{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL},	{0, 0, "Card without SSID set", NULL, NULL, NULL },	{0, 0, NULL, NULL, NULL, NULL}};/* * APM support */#ifdef CONFIG_PMvoid snd_cs46xx_suspend(cs46xx_t *chip){	snd_card_t *card = chip->card;	snd_power_lock(card);	if (card->power_state == SNDRV_CTL_POWER_D3hot)		goto __skip;	snd_pcm_suspend_all(chip->pcm);	// chip->ac97_powerdown = snd_cs46xx_codec_read(chip, AC97_POWER_CONTROL);	// chip->ac97_general_purpose = snd_cs46xx_codec_read(chip, BA0_AC97_GENERAL_PURPOSE);	snd_cs46xx_hw_stop(chip);	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);      __skip:      	snd_power_unlock(card);}void snd_cs46xx_resume(cs46xx_t *chip){	snd_card_t *card = chip->card;	int amp_saved;	snd_power_lock(card);	if (card->power_state == SNDRV_CTL_POWER_D0)		goto __skip;	pci_enable_device(chip->pci);	amp_saved = chip->amplifier;	chip->amplifier = 0;	chip->active_ctrl(chip, 1); /* force to on */	snd_cs46xx_chip_init(chip, 1);#if 0	snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 			       chip->ac97_general_purpose);	snd_cs46xx_codec_write(chip, AC97_POWER_CONTROL, 			       chip->ac97_powerdown);	mdelay(10);	snd_cs46xx_codec_write(chip, BA0_AC97_POWERDOWN,			       chip->ac97_powerdown);	mdelay(5);#endif	snd_ac97_resume(chip->ac97);	if (amp_saved)		chip->amplifier_ctrl(chip, 1); /* try to turn on */	if (! amp_saved) {		chip->amplifier = 1;		chip->active_ctrl(chip, -1);	}	snd_power_change_state(card, SNDRV_CTL_POWER_D0);      __skip:      	snd_power_unlock(card);}static int snd_cs46xx_set_power_state(snd_card_t *card, unsigned int power_state){	cs46xx_t *chip = snd_magic_cast(cs46xx_t, card->power_state_private_data, return -ENXIO);	switch (power_state) {	case SNDRV_CTL_POWER_D0:	case SNDRV_CTL_POWER_D1:	case SNDRV_CTL_POWER_D2:		snd_cs46xx_resume(chip);		break;	case SNDRV_CTL_POWER_D3hot:	case SNDRV_CTL_POWER_D3cold:		snd_cs46xx_suspend(chip);		break;	default:		return -EINVAL;	}	return 0;}#endif /* CONFIG_PM *//* */int __devinit snd_cs46xx_create(snd_card_t * card,		      struct pci_dev * pci,		      int external_amp, int thinkpad,		      cs46xx_t ** rchip){	cs46xx_t *chip;	int err, idx;	snd_cs46xx_region_t *region;	struct cs_card_type *cp;	u16 ss_card, ss_vendor;	static snd_device_ops_t ops = {		dev_free:	snd_cs46xx_dev_free,	};		*rchip = NULL;	/* enable PCI device */	if ((err = pci_enable_device(pci)) < 0)		return err;	chip = snd_magic_kcalloc(cs46xx_t, 0, GFP_KERNEL);	if (chip == NULL)		return -ENOMEM;	spin_lock_init(&chip->reg_lock);	chip->card = card;	chip->pci = pci;	chip->play.hw_size = PAGE_SIZE;	chip->capt.hw_size = PAGE_SIZE;	chip->irq = -1;	chip->ba0_addr = pci_resource_start(pci, 0);	chip->ba1_addr = pci_resource_start(pci, 1);	if (chip->ba0_addr == 0 || chip->ba0_addr == ~0 ||	    chip->ba1_addr == 0 || chip->ba1_addr == ~0) {	    	snd_cs46xx_free(chip);	    	snd_printk("wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n", chip->ba0_addr, chip->ba1_addr);	    	return -ENOMEM;	}	region = &chip->region.name.ba0;	strcpy(region->name, "CS46xx_BA0");	region->base = chip->ba0_addr;	region->size = CS46XX_BA0_SIZE;	region = &chip->region.name.data0;	strcpy(region->name, "CS46xx_BA1_data0");	region->base = chip->ba1_addr + BA1_SP_DMEM0;	region->size = CS46XX_BA1_DATA0_SIZE;	region = &chip->region.name.data1;	strcpy(region->name, "CS46xx_BA1_data1");	region->base = chip->ba1_addr + BA1_SP_DMEM1;	region->size = CS46XX_BA1_DATA1_SIZE;	region = &chip->region.name.pmem;	strcpy(region->name, "CS46xx_BA1_pmem");	region->base = chip->ba1_addr + BA1_SP_PMEM;	region->size = CS46XX_BA1_PRG_SIZE;	region = &chip->region.name.reg;	strcpy(region->name, "CS46xx_BA1_reg");	region->base = chip->ba1_addr + BA1_SP_REG;	region->size = CS46XX_BA1_REG_SIZE;	/* set up amp and clkrun hack */	pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);	pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &ss_card);	for (cp = &cards[0]; cp->name; cp++) {		if (cp->vendor == ss_vendor && cp->id == ss_card) {			snd_printd("hack for %s enabled\n", cp->name);			if (cp->init)				cp->init(chip);			chip->amplifier_ctrl = cp->amp;			chip->active_ctrl = cp->active;			break;		}	}	if (external_amp) {		snd_printk("Crystal EAPD support forced on.\n");		chip->amplifier_ctrl = amp_voyetra;	}	if (thinkpad) {		snd_printk("Activating CLKRUN hack for Thinkpad.\n");		chip->active_ctrl = clkrun_hack;		clkrun_init(chip);	}		if (chip->amplifier_ctrl == NULL)		chip->amplifier_ctrl = amp_none;	if (chip->active_ctrl == NULL)		chip->active_ctrl = amp_none;	chip->active_ctrl(chip, 1);	pci_set_master(pci);	for (idx = 0; idx < 5; idx++) {		region = &chip->region.idx[idx];		if ((region->resource = request_mem_region(region->base, region->size, region->name)) == NULL) {			snd_cs46xx_free(chip);			snd_printk("unable to request memory region 0x%lx-0x%lx\n", region->base, region->base + region->size - 1);			return -EBUSY;		}		region->remap_addr = (unsigned long) ioremap_nocache(region->base, region->size);		i

⌨️ 快捷键说明

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