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

📄 i2c-core.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial,                        union i2c_smbus_data *data){	u8 buf[3], rpec, cpec;	buf[1] = command;	switch(size) {		case I2C_SMBUS_BYTE_DATA:			buf[0] = (addr << 1) | 1;			cpec = i2c_smbus_pec(2, buf, NULL);			rpec = data->byte;			break;		case I2C_SMBUS_WORD_DATA:			buf[0] = (addr << 1) | 1;			buf[2] = data->word & 0xff;			cpec = i2c_smbus_pec(3, buf, NULL);			rpec = data->word >> 8;			break;		case I2C_SMBUS_WORD_DATA_PEC:			/* unsupported */			cpec = rpec = 0;			break;		case I2C_SMBUS_PROC_CALL_PEC:			/* unsupported */			cpec = rpec = 0;			break;		case I2C_SMBUS_BLOCK_DATA_PEC:			buf[0] = (addr << 1);			buf[2] = (addr << 1) | 1;			cpec = i2c_smbus_pec(3, buf, data->block);			rpec = data->block[data->block[0] + 1];			break;		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:			buf[0] = (addr << 1) | 1;			rpec = i2c_smbus_partial_pec(partial, 1,			                             buf, data->block);			cpec = data->block[data->block[0] + 1];			break;		default:			cpec = rpec = 0;			break;	}	if (rpec != cpec) {		pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",			rpec, cpec);		return -1;	}	return 0;	}s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value){	return i2c_smbus_xfer(client->adapter,client->addr,client->flags, 	                      value,0,I2C_SMBUS_QUICK,NULL);}s32 i2c_smbus_read_byte(struct i2c_client *client){	union i2c_smbus_data data;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                   I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))		return -1;	else		return 0x0FF & data.byte;}s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value){	union i2c_smbus_data data;	/* only for PEC */	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data);}s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command){	union i2c_smbus_data data;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                   I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))		return -1;	else		return 0x0FF & data.byte;}s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value){	union i2c_smbus_data data;	data.byte = value;	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_WRITE,command,	                      I2C_SMBUS_BYTE_DATA,&data);}s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command){	union i2c_smbus_data data;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                   I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))		return -1;	else		return 0x0FFFF & data.word;}s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value){	union i2c_smbus_data data;	data.word = value;	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_WRITE,command,	                      I2C_SMBUS_WORD_DATA,&data);}s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value){	union i2c_smbus_data data;	data.word = value;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                   I2C_SMBUS_WRITE,command,	                   I2C_SMBUS_PROC_CALL, &data))		return -1;	else		return 0x0FFFF & data.word;}/* Returns the number of read bytes */s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, u8 *values){	union i2c_smbus_data data;	int i;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                   I2C_SMBUS_READ,command,	                   I2C_SMBUS_BLOCK_DATA,&data))		return -1;	else {		for (i = 1; i <= data.block[0]; i++)			values[i-1] = data.block[i];		return data.block[0];	}}s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values){	union i2c_smbus_data data;	int i;	if (length > I2C_SMBUS_BLOCK_MAX)		length = I2C_SMBUS_BLOCK_MAX;	for (i = 1; i <= length; i++)		data.block[i] = values[i-1];	data.block[0] = length;	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_WRITE,command,	                      I2C_SMBUS_BLOCK_DATA,&data);}/* Returns the number of read bytes */s32 i2c_smbus_block_process_call(struct i2c_client *client, u8 command, u8 length, u8 *values){	union i2c_smbus_data data;	int i;	if (length > I2C_SMBUS_BLOCK_MAX - 1)		return -1;	data.block[0] = length;	for (i = 1; i <= length; i++)		data.block[i] = values[i-1];	if(i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                  I2C_SMBUS_WRITE, command,	                  I2C_SMBUS_BLOCK_PROC_CALL, &data))		return -1;	for (i = 1; i <= data.block[0]; i++)		values[i-1] = data.block[i];	return data.block[0];}/* Returns the number of read bytes */s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values){	union i2c_smbus_data data;	int i;	if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_READ,command,	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))		return -1;	else {		for (i = 1; i <= data.block[0]; i++)			values[i-1] = data.block[i];		return data.block[0];	}}s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, u8 *values){	union i2c_smbus_data data;	int i;	if (length > I2C_SMBUS_I2C_BLOCK_MAX)		length = I2C_SMBUS_I2C_BLOCK_MAX;	for (i = 1; i <= length; i++)		data.block[i] = values[i-1];	data.block[0] = length;	return i2c_smbus_xfer(client->adapter,client->addr,client->flags,	                      I2C_SMBUS_WRITE,command,	                      I2C_SMBUS_I2C_BLOCK_DATA,&data);}/* Simulate a SMBus command using the i2c protocol    No checking of parameters is done!  */static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,                                    unsigned short flags,                                   char read_write, u8 command, int size,                                    union i2c_smbus_data * data){	/* So we need to generate a series of msgs. In the case of writing, we	  need to use only one message; when reading, we need two. We initialize	  most things with sane defaults, to keep the code below somewhat	  simpler. */	unsigned char msgbuf0[34];	unsigned char msgbuf1[34];	int num = read_write == I2C_SMBUS_READ?2:1;	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, 	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }	                        };	int i;	msgbuf0[0] = command;	switch(size) {	case I2C_SMBUS_QUICK:		msg[0].len = 0;		/* Special case: The read/write field is used as data */		msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;		num = 1;		break;	case I2C_SMBUS_BYTE:		if (read_write == I2C_SMBUS_READ) {			/* Special case: only a read! */			msg[0].flags = I2C_M_RD | flags;			num = 1;		}		break;	case I2C_SMBUS_BYTE_DATA:		if (read_write == I2C_SMBUS_READ)			msg[1].len = 1;		else {			msg[0].len = 2;			msgbuf0[1] = data->byte;		}		break;	case I2C_SMBUS_WORD_DATA:		if (read_write == I2C_SMBUS_READ)			msg[1].len = 2;		else {			msg[0].len=3;			msgbuf0[1] = data->word & 0xff;			msgbuf0[2] = (data->word >> 8) & 0xff;		}		break;	case I2C_SMBUS_PROC_CALL:		num = 2; /* Special case */		read_write = I2C_SMBUS_READ;		msg[0].len = 3;		msg[1].len = 2;		msgbuf0[1] = data->word & 0xff;		msgbuf0[2] = (data->word >> 8) & 0xff;		break;	case I2C_SMBUS_BLOCK_DATA:	case I2C_SMBUS_BLOCK_DATA_PEC:		if (read_write == I2C_SMBUS_READ) {			dev_err(&adapter->dev, "Block read not supported "			       "under I2C emulation!\n");			return -1;		} else {			msg[0].len = data->block[0] + 2;			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {				dev_err(&adapter->dev, "smbus_access called with "				       "invalid block write size (%d)\n",				       data->block[0]);				return -1;			}			if(size == I2C_SMBUS_BLOCK_DATA_PEC)				(msg[0].len)++;			for (i = 1; i <= msg[0].len; i++)				msgbuf0[i] = data->block[i-1];		}		break;	case I2C_SMBUS_BLOCK_PROC_CALL:	case I2C_SMBUS_BLOCK_PROC_CALL_PEC:		dev_dbg(&adapter->dev, "Block process call not supported "		       "under I2C emulation!\n");		return -1;	case I2C_SMBUS_I2C_BLOCK_DATA:		if (read_write == I2C_SMBUS_READ) {			msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX;		} else {			msg[0].len = data->block[0] + 1;			if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 1) {				dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "				       "invalid block write size (%d)\n",				       data->block[0]);				return -1;			}			for (i = 1; i <= data->block[0]; i++)				msgbuf0[i] = data->block[i];		}		break;	default:		dev_err(&adapter->dev, "smbus_access called with invalid size (%d)\n",		       size);		return -1;	}	if (i2c_transfer(adapter, msg, num) < 0)		return -1;	if (read_write == I2C_SMBUS_READ)		switch(size) {			case I2C_SMBUS_BYTE:				data->byte = msgbuf0[0];				break;			case I2C_SMBUS_BYTE_DATA:				data->byte = msgbuf1[0];				break;			case I2C_SMBUS_WORD_DATA: 			case I2C_SMBUS_PROC_CALL:				data->word = msgbuf1[0] | (msgbuf1[1] << 8);				break;			case I2C_SMBUS_I2C_BLOCK_DATA:				/* fixed at 32 for now */				data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX;				for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++)					data->block[i+1] = msgbuf1[i];				break;		}	return 0;}s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,                   char read_write, u8 command, int size,                    union i2c_smbus_data * data){	s32 res;	int swpec = 0;	u8 partial = 0;	flags &= I2C_M_TEN | I2C_CLIENT_PEC;	if((flags & I2C_CLIENT_PEC) &&	   !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) {		swpec = 1;		if(read_write == I2C_SMBUS_READ &&		   size == I2C_SMBUS_BLOCK_DATA)			size = I2C_SMBUS_BLOCK_DATA_PEC;		else if(size == I2C_SMBUS_PROC_CALL)			size = I2C_SMBUS_PROC_CALL_PEC;		else if(size == I2C_SMBUS_BLOCK_PROC_CALL) {			i2c_smbus_add_pec(addr, command,		                          I2C_SMBUS_BLOCK_DATA, data);			partial = data->block[data->block[0] + 1];			size = I2C_SMBUS_BLOCK_PROC_CALL_PEC;		} else if(read_write == I2C_SMBUS_WRITE &&		          size != I2C_SMBUS_QUICK &&		          size != I2C_SMBUS_I2C_BLOCK_DATA)			size = i2c_smbus_add_pec(addr, command, size, data);	}	if (adapter->algo->smbus_xfer) {		down(&adapter->bus_lock);		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,		                                command,size,data);		up(&adapter->bus_lock);	} else		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,	                                      command,size,data);	if(res >= 0 && swpec &&	   size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA &&	   (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC ||	    size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) {		if(i2c_smbus_check_pec(addr, command, size, partial, data))			return -1;	}	return res;}/* You should always define `functionality'; the 'else' is just for   backward compatibility. */ u32 i2c_get_functionality (struct i2c_adapter *adap){	if (adap->algo->functionality)		return adap->algo->functionality(adap);	else		return 0xffffffff;}int i2c_check_functionality (struct i2c_adapter *adap, u32 func){	u32 adap_func = i2c_get_functionality (adap);	return (func & adap_func) == func;}EXPORT_SYMBOL(i2c_add_adapter);EXPORT_SYMBOL(i2c_del_adapter);EXPORT_SYMBOL(i2c_add_driver);EXPORT_SYMBOL(i2c_del_driver);EXPORT_SYMBOL(i2c_attach_client);EXPORT_SYMBOL(i2c_detach_client);EXPORT_SYMBOL(i2c_use_client);EXPORT_SYMBOL(i2c_release_client);EXPORT_SYMBOL(i2c_clients_command);EXPORT_SYMBOL(i2c_check_addr);EXPORT_SYMBOL(i2c_master_send);EXPORT_SYMBOL(i2c_master_recv);EXPORT_SYMBOL(i2c_control);EXPORT_SYMBOL(i2c_transfer);EXPORT_SYMBOL(i2c_adapter_id);EXPORT_SYMBOL(i2c_get_adapter);EXPORT_SYMBOL(i2c_put_adapter);EXPORT_SYMBOL(i2c_probe);EXPORT_SYMBOL(i2c_smbus_xfer);EXPORT_SYMBOL(i2c_smbus_write_quick);EXPORT_SYMBOL(i2c_smbus_read_byte);EXPORT_SYMBOL(i2c_smbus_write_byte);EXPORT_SYMBOL(i2c_smbus_read_byte_data);EXPORT_SYMBOL(i2c_smbus_write_byte_data);EXPORT_SYMBOL(i2c_smbus_read_word_data);EXPORT_SYMBOL(i2c_smbus_write_word_data);EXPORT_SYMBOL(i2c_smbus_process_call);EXPORT_SYMBOL(i2c_smbus_read_block_data);EXPORT_SYMBOL(i2c_smbus_write_block_data);EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);EXPORT_SYMBOL(i2c_get_functionality);EXPORT_SYMBOL(i2c_check_functionality);MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");MODULE_DESCRIPTION("I2C-Bus main module");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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