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

📄 i2c-i801.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
				/* if die in middle of block transaction, fail */				result = -1;				goto END;			}		}		if (i == 1)			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);		/* We will always wait for a fraction of a second! */		timeout = 0;		do {			temp = inb_p(SMBHSTSTS);			msleep(1);		}		    while ((!(temp & 0x80))			   && (timeout++ < MAX_TIMEOUT));		/* If the SMBus is still busy, we give up */		if (timeout >= MAX_TIMEOUT) {			result = -1;			dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");		}		if (temp & 0x10) {			result = -1;			dev_dbg(&I801_dev->dev,				"Error: Failed bus transaction\n");		} else if (temp & 0x08) {			result = -1;			dev_err(&I801_dev->dev, "Bus collision!\n");		} else if (temp & 0x04) {			result = -1;			dev_dbg(&I801_dev->dev, "Error: no response!\n");		}		if (i == 1 && read_write == I2C_SMBUS_READ) {			len = inb_p(SMBHSTDAT0);			if (len < 1)				len = 1;			if (len > 32)				len = 32;			data->block[0] = len;		}		/* Retrieve/store value in SMBBLKDAT */		if (read_write == I2C_SMBUS_READ)			data->block[i] = inb_p(SMBBLKDAT);		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)			outb_p(data->block[i+1], SMBBLKDAT);		if ((temp & 0x9e) != 0x00)			outb_p(temp, SMBHSTSTS);  /* signals SMBBLKDAT ready */		if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {			dev_dbg(&I801_dev->dev,				"Bad status (%02x) at end of transaction\n",				temp);		}		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));		if (result < 0)			goto END;	}#ifdef HAVE_PEC	if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {		/* wait for INTR bit as advised by Intel */		timeout = 0;		do {			temp = inb_p(SMBHSTSTS);			msleep(1);		} while ((!(temp & 0x02))			   && (timeout++ < MAX_TIMEOUT));		if (timeout >= MAX_TIMEOUT) {			dev_dbg(&I801_dev->dev, "PEC Timeout!\n");		}		outb_p(temp, SMBHSTSTS); 	}#endif	result = 0;END:	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {		/* restore saved configuration register value */		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);	}	return result;}/* Return -1 on error. */static s32 i801_access(struct i2c_adapter * adap, u16 addr,		       unsigned short flags, char read_write, u8 command,		       int size, union i2c_smbus_data * data){	int hwpec = 0;	int block = 0;	int ret, xact = 0;#ifdef HAVE_PEC	if(isich4)		hwpec = (flags & I2C_CLIENT_PEC) != 0;#endif	switch (size) {	case I2C_SMBUS_QUICK:		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),		       SMBHSTADD);		xact = I801_QUICK;		break;	case I2C_SMBUS_BYTE:		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),		       SMBHSTADD);		if (read_write == I2C_SMBUS_WRITE)			outb_p(command, SMBHSTCMD);		xact = I801_BYTE;		break;	case I2C_SMBUS_BYTE_DATA:		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),		       SMBHSTADD);		outb_p(command, SMBHSTCMD);		if (read_write == I2C_SMBUS_WRITE)			outb_p(data->byte, SMBHSTDAT0);		xact = I801_BYTE_DATA;		break;	case I2C_SMBUS_WORD_DATA:		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),		       SMBHSTADD);		outb_p(command, SMBHSTCMD);		if (read_write == I2C_SMBUS_WRITE) {			outb_p(data->word & 0xff, SMBHSTDAT0);			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);		}		xact = I801_WORD_DATA;		break;	case I2C_SMBUS_BLOCK_DATA:	case I2C_SMBUS_I2C_BLOCK_DATA:#ifdef HAVE_PEC	case I2C_SMBUS_BLOCK_DATA_PEC:		if(hwpec && size == I2C_SMBUS_BLOCK_DATA)			size = I2C_SMBUS_BLOCK_DATA_PEC;#endif		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),		       SMBHSTADD);		outb_p(command, SMBHSTCMD);		block = 1;		break;	case I2C_SMBUS_PROC_CALL:	default:		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);		return -1;	}#ifdef HAVE_PEC	if(isich4 && hwpec) {		if(size != I2C_SMBUS_QUICK &&		   size != I2C_SMBUS_I2C_BLOCK_DATA)			outb_p(1, SMBAUXCTL);	/* enable HW PEC */	}#endif	if(block)		ret = i801_block_transaction(data, read_write, size);	else {		outb_p(xact | ENABLE_INT9, SMBHSTCNT);		ret = i801_transaction();	}#ifdef HAVE_PEC	if(isich4 && hwpec) {		if(size != I2C_SMBUS_QUICK &&		   size != I2C_SMBUS_I2C_BLOCK_DATA)			outb_p(0, SMBAUXCTL);	}#endif	if(block)		return ret;	if(ret)		return -1;	if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))		return 0;	switch (xact & 0x7f) {	case I801_BYTE:	/* Result put in SMBHSTDAT0 */	case I801_BYTE_DATA:		data->byte = inb_p(SMBHSTDAT0);		break;	case I801_WORD_DATA:		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);		break;	}	return 0;}static u32 i801_func(struct i2c_adapter *adapter){	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK#ifdef HAVE_PEC	     | (isich4 ? I2C_FUNC_SMBUS_BLOCK_DATA_PEC |	                 I2C_FUNC_SMBUS_HWPEC_CALC	               : 0)#endif	    ;}static struct i2c_algorithm smbus_algorithm = {	.name		= "Non-I2C SMBus adapter",	.id		= I2C_ALGO_SMBUS,	.smbus_xfer	= i801_access,	.functionality	= i801_func,};static struct i2c_adapter i801_adapter = {	.owner		= THIS_MODULE,	.class		= I2C_CLASS_HWMON,	.algo		= &smbus_algorithm,	.name		= "unset",};static struct pci_device_id i801_ids[] = {	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801AA_3,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801AB_3,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801BA_2,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801CA_3,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801DB_3,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_82801EB_3,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_ESB_4,		.subvendor =	PCI_ANY_ID,		.subdevice = 	PCI_ANY_ID,	},	{		.vendor =	PCI_VENDOR_ID_INTEL,		.device =	PCI_DEVICE_ID_INTEL_ICH6_16,		.subvendor =	PCI_ANY_ID,		.subdevice =	PCI_ANY_ID,	},	{ 0, }};static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id){	if (i801_setup(dev)) {		dev_warn(&dev->dev,			"I801 not detected, module not inserted.\n");		return -ENODEV;	}	/* set up the driverfs linkage to our parent device */	i801_adapter.dev.parent = &dev->dev;	snprintf(i801_adapter.name, I2C_NAME_SIZE,		"SMBus I801 adapter at %04x", i801_smba);	return i2c_add_adapter(&i801_adapter);}static void __devexit i801_remove(struct pci_dev *dev){	i2c_del_adapter(&i801_adapter);	release_region(i801_smba, (isich4 ? 16 : 8));}static struct pci_driver i801_driver = {	.name		= "i801 smbus",	.id_table	= i801_ids,	.probe		= i801_probe,	.remove		= __devexit_p(i801_remove),};static int __init i2c_i801_init(void){	return pci_module_init(&i801_driver);}static void __exit i2c_i801_exit(void){	pci_unregister_driver(&i801_driver);}MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "		"Philip Edelbrock <phil@netroedge.com>, "		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("I801 SMBus driver");MODULE_LICENSE("GPL");module_init(i2c_i801_init);module_exit(i2c_i801_exit);

⌨️ 快捷键说明

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