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

📄 io.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (c) by Jaroslav Kysela <perex@perex.cz> *                   Creative Labs, Inc. *  Routines for control of EMU10K1 chips * *  BUGS: *    -- * *  TODO: *    -- * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * */#include <sound/driver.h>#include <linux/time.h>#include <sound/core.h>#include <sound/emu10k1.h>#include <linux/delay.h>#include "p17v.h"unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn){	unsigned long flags;	unsigned int regptr, val;	unsigned int mask;	mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;	regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);	if (reg & 0xff000000) {		unsigned char size, offset;				size = (reg >> 24) & 0x3f;		offset = (reg >> 16) & 0x1f;		mask = ((1 << size) - 1) << offset;				spin_lock_irqsave(&emu->emu_lock, flags);		outl(regptr, emu->port + PTR);		val = inl(emu->port + DATA);		spin_unlock_irqrestore(&emu->emu_lock, flags);				return (val & mask) >> offset;	} else {		spin_lock_irqsave(&emu->emu_lock, flags);		outl(regptr, emu->port + PTR);		val = inl(emu->port + DATA);		spin_unlock_irqrestore(&emu->emu_lock, flags);		return val;	}}EXPORT_SYMBOL(snd_emu10k1_ptr_read);void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data){	unsigned int regptr;	unsigned long flags;	unsigned int mask;	mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;	regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);	if (reg & 0xff000000) {		unsigned char size, offset;		size = (reg >> 24) & 0x3f;		offset = (reg >> 16) & 0x1f;		mask = ((1 << size) - 1) << offset;		data = (data << offset) & mask;		spin_lock_irqsave(&emu->emu_lock, flags);		outl(regptr, emu->port + PTR);		data |= inl(emu->port + DATA) & ~mask;		outl(data, emu->port + DATA);		spin_unlock_irqrestore(&emu->emu_lock, flags);			} else {		spin_lock_irqsave(&emu->emu_lock, flags);		outl(regptr, emu->port + PTR);		outl(data, emu->port + DATA);		spin_unlock_irqrestore(&emu->emu_lock, flags);	}}EXPORT_SYMBOL(snd_emu10k1_ptr_write);unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 					  unsigned int reg, 					  unsigned int chn){	unsigned long flags;	unsigned int regptr, val;  	regptr = (reg << 16) | chn;	spin_lock_irqsave(&emu->emu_lock, flags);	outl(regptr, emu->port + 0x20 + PTR);	val = inl(emu->port + 0x20 + DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);	return val;}void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 				   unsigned int reg, 				   unsigned int chn, 				   unsigned int data){	unsigned int regptr;	unsigned long flags;	regptr = (reg << 16) | chn;	spin_lock_irqsave(&emu->emu_lock, flags);	outl(regptr, emu->port + 0x20 + PTR);	outl(data, emu->port + 0x20 + DATA);	spin_unlock_irqrestore(&emu->emu_lock, flags);}int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,				   unsigned int data){	unsigned int reset, set;	unsigned int reg, tmp;	int n, result;	if (emu->card_capabilities->ca0108_chip)		reg = 0x3c; /* PTR20, reg 0x3c */	else {		/* For other chip types the SPI register		 * is currently unknown. */		return 1;	}	if (data > 0xffff) /* Only 16bit values allowed */		return 1;	tmp = snd_emu10k1_ptr20_read(emu, reg, 0);	reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */	set = reset | 0x10000; /* Set xxx1xxxx */	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */	snd_emu10k1_ptr20_write(emu, reg, 0, set | data);	result = 1;	/* Wait for status bit to return to 0 */	for (n = 0; n < 100; n++) {		udelay(10);		tmp = snd_emu10k1_ptr20_read(emu, reg, 0);		if (!(tmp & 0x10000)) {			result = 0;			break;		}	}	if (result) /* Timed out */		return 1;	snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);	tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */	return 0;}/* The ADC does not support i2c read, so only write is implemented */int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,				u32 reg,				u32 value){	u32 tmp;	int timeout = 0;	int status;	int retry;	if ((reg > 0x7f) || (value > 0x1ff)) {		snd_printk(KERN_ERR "i2c_write: invalid values.\n");		return -EINVAL;	}	tmp = reg << 25 | value << 16;	// snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);	/* Not sure what this I2C channel controls. */	/* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */	/* This controls the I2C connected to the WM8775 ADC Codec */	snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);	tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */	for (retry = 0; retry < 10; retry++) {		/* Send the data to i2c */		//tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);		//tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);		tmp = 0;		tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);		snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);		/* Wait till the transaction ends */		while (1) {			udelay(10);			status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);                	// snd_printk("I2C:status=0x%x\n", status);			timeout++;			if ((status & I2C_A_ADC_START) == 0)				break;			if (timeout > 1000) {                		snd_printk("emu10k1:I2C:timeout status=0x%x\n", status);				break;			}		}		//Read back and see if the transaction is successful		if ((status & I2C_A_ADC_ABORT) == 0)			break;	}	if (retry == 10) {		snd_printk(KERN_ERR "Writing to ADC failed!\n");		return -EINVAL;	}        	return 0;}int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value){	if (reg > 0x3f)		return 1;	reg += 0x40; /* 0x40 upwards are registers. */	if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */		return 1;	outl(reg, emu->port + A_IOCFG);	udelay(10);	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */	udelay(10);	outl(value, emu->port + A_IOCFG);	udelay(10);	outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */	return 0;}int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value){	if (reg > 0x3f)		return 1;	reg += 0x40; /* 0x40 upwards are registers. */	outl(reg, emu->port + A_IOCFG);	udelay(10);	outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */	udelay(10);	*value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);	return 0;}/* Each Destination has one and only one Source, * but one Source can feed any number of Destinations simultaneously. */int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src){	snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );	snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );	snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );	snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );	return 0;}void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb){	unsigned long flags;	unsigned int enable;

⌨️ 快捷键说明

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