📄 i2c-core.c
字号:
return i2c_smbus_pec(pec, msg->buf, msg->len);}/* Used for write only transactions */static inline void i2c_smbus_add_pec(struct i2c_msg *msg){ msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg); msg->len++;}/* Return <0 on CRC error If there was a write before this read (most cases) we need to take the partial CRC from the write part into account. Note that this function does modify the message (we need to decrease the message length to hide the CRC byte from the caller). */int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg){ u8 rpec = msg->buf[--msg->len]; cpec = i2c_smbus_msg_pec(cpec, msg); if(rpec != cpec) { DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec)); return -1; } return 0; }extern 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);}extern 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;}extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value){ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);}extern 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;}extern 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);}extern 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;}extern 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);}extern 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 */extern 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]; }}extern 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 */extern 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 */extern 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]; }}extern 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[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; 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, len; u8 partial_pec = 0; 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: if (read_write == I2C_SMBUS_READ) { /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_READ_BLOCK_DATA */ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA)) { printk(KERN_ERR "i2c-core.o: Block read not supported " "under I2C emulation!\n"); return -1; } /* set send message */ msg[0].len = 1; /* set recv message */ msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = I2C_SMBUS_BLOCK_MAX + 1; if (flags & I2C_CLIENT_PEC) msg[1].flags |= I2C_M_RECV_PEC; } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", data->block[0]); return -1; } for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; case I2C_SMBUS_BLOCK_PROC_CALL: /* I2C_FUNC_SMBUS_EMUL doesn't include I2C_FUNC_SMBUS_BLOCK_PROC_CALL */ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BLOCK_PROC_CALL)) { printk(KERN_ERR "i2c-core.o: adapter doesn't support block process call!\n"); return -1; } /* Another special case */ num = 2; read_write = I2C_SMBUS_READ; /* set send message */ msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", data->block[0]); return -1; } for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; /* set recv message */ msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = I2C_SMBUS_BLOCK_MAX + 1; if (flags & I2C_CLIENT_PEC) msg[1].flags |= I2C_M_RECV_PEC; break; 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) { printk("i2c-core.o: 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: printk(KERN_ERR "i2c-core.o: smbus_access called with invalid size (%d)\n", size); return -1; } i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA); if (i) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { if (num == 1) /* Write only */ i2c_smbus_add_pec(&msg[0]); else /* Write followed by read */ partial_pec = i2c_smbus_msg_pec(0, &msg[0]); } /* Ask for PEC if last message is a read */ if (msg[num-1].flags & I2C_M_RD) msg[num-1].len++; } if (i2c_transfer(adapter, msg, num) < 0) return -1; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 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; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: len = msgbuf1[0] + 1; for (i = 0; i < len; i++) data->block[i] = msgbuf1[i]; break; } return 0;}s32 i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data * data){ s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adap->algo->smbus_xfer) { down(&adap->bus); res = adap->algo->smbus_xfer(adap,addr,flags,read_write, command,size,data); up(&adap->bus); } else res = i2c_smbus_xfer_emulated(adap,addr,flags,read_write, command,size,data); 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;}static int __init i2c_init(void){ printk(KERN_INFO "i2c-core.o: i2c core module version %s (%s)\n", I2C_VERSION, I2C_DATE); memset(adapters,0,sizeof(adapters)); memset(drivers,0,sizeof(drivers));#ifdef CONFIG_PROC_FS return i2cproc_init();#else return 0;#endif}static void __exit i2c_exit(void) {#ifdef CONFIG_PROC_FS i2cproc_cleanup();#endif}/* leave this in for now simply to make patching easier so we don't have to remove the call in drivers/char/mem.c */int __init i2c_init_all(void){ return 0;}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_get_client);EXPORT_SYMBOL(i2c_use_client);EXPORT_SYMBOL(i2c_release_client);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_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");MODULE_PARM(i2c_debug, "i");MODULE_PARM_DESC(i2c_debug,"debug level");module_init(i2c_init);module_exit(i2c_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -