i2c 应用层与驱动层沟通的结构体就是下面这个, 定义在i2c-dev.c中:
static const struct file_operations i2cdev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
1. 应用层的open和close
应用层的打开和关闭设备函数:
fd = open(“/dev/i2c-0”, O_RDWR );
close(fd);
这两个系统调用分别会调用到i2c-dev.c 中的 .open, 和.release 函数
也就是:
static int i2cdev_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct i2c_client *client;
struct i2c_adapter *adap;
struct i2c_dev *i2c_dev;
i2c_dev = i2c_dev_get_by_minor(minor);
if (!i2c_dev)
return -ENODEV;
adap = i2c_get_adapter(i2c_dev->adap->nr);
if (!adap)
return -ENODEV;
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
/* registered with adapter, passed as client to user */
client->adapter = adap;
file->private_data = client;
return 0;
}
static int i2cdev_release(struct inode *inode, struct file *file)
{
struct i2c_client *client = file->private_data;
i2c_put_adapter(client->adapter);
kfree(client);
file->private_data = NULL;
return 0;
}
i2cdev_open() 中先通过次设备号,获得该i2c设备,也就是/dev/i2c-*
i2c_dev = i2c_dev_get_by_minor(minor);
然后通过i2c_dev->adap->nr, 获得与该设备匹配的i2c_adapter。
adap = i2c_get_adapter(i2c_dev->adap->nr);
然后申请一个i2c_client , 每次打开一个i2c设备,都会建立一个i2c_client结构体,用来表示被打开的一个i2c设备。
并给i2c_client赋值, 主要是复制client->driver, 和client->adapter.
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
/* registered with adapter, passed as client to user */
client->adapter = adap;
client->driver, 该i2c设备的驱动程序。
client->adapter, 该i2c设备依附的i2c_adapter.
2. 应用层的ioctl():
ioctl(fd, request, Addr);
fd 就是打开的i2c设备号。
request,是ioctl 传递给驱动层的commd, 有如下一些定义:
/* ----- commands for the ioctl like i2c_command call:
* note that additional calls are defined in the algorithm and hw
* dependent layers - these can be listed here, or see the
* corresponding header files.
*/
/* -> bit-adapter specific ioctls */
#define I2C_RETRIES 0x0701 /* number of times a device address */
/* should be polled when not */
/* acknowledging */
#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */
/* this is for i2c-dev.c */
#define I2C_SLAVE 0x0703 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */
/* Attn.: Slave address is 7 or 10 bits */
/* This changes the address, even if it */
/* is already taken! */
#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */
#define I2C_FUNCS 0x0705 /* Get the adapter functionality */
#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/
#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */
#define I2C_SMBUS 0x0720 /* SMBus-level access */
Addr,就是传给驱动层的程序要访问I2C设备的地址,一般只有高7位,LSB用来设置读还是写。
应用层ioctl() 会调用到驱动层的ioctl().
static int i2cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = (struct i2c_client *)file->private_data;
struct i2c_rdwr_ioctl_data rdwr_arg;
struct i2c_smbus_ioctl_data data_arg;
union i2c_smbus_data temp;
struct i2c_msg *rdwr_pa;
u8 __user **data_ptrs;
int i,datasize,res;
unsigned long funcs;
dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
cmd, arg);
switch ( cmd ) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
return -EBUSY;
client->addr = arg;
return 0;
case I2C_TENBIT:
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
client->flags &= ~I2C_CLIENT_PEC;
return 0;
case I2C_FUNCS:
funcs = i2c_get_functionality(client->adapter);
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR:
if (copy_from_user(&rdwr_arg,
(struct i2c_rdwr_ioctl_data __user *)arg,
sizeof(rdwr_arg)))
return -EFAULT;
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
rdwr_pa = (struct i2c_msg *)
kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
GFP_KERNEL);
if (rdwr_pa == NULL) return -ENOMEM;
if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
kfree(rdwr_pa);
return -EFAULT;
}
data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
if (data_ptrs == NULL) {
kfree(rdwr_pa);
return -ENOMEM;
}
res = 0;
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
/* Limit the size of the message to a sane amount */
if (rdwr_pa[i].len > 8192) {
res = -EINVAL;
break;
}
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
if(rdwr_pa[i].buf == NULL) {
res = -ENOMEM;
break;
}
if(copy_from_user(rdwr_pa[i].buf,
data_ptrs[i],
rdwr_pa[i].len)) {
++i; /* Needs to be kfreed too */
res = -EFAULT;
break;
}
}
if (res < 0) {
int j;
for (j = 0; j < i; ++j)
kfree(rdwr_pa[j].buf);
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
}
res = i2c_transfer(client->adapter,
rdwr_pa,
rdwr_arg.nmsgs);
while(i-- > 0) {
if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
if(copy_to_user(
data_ptrs[i],
rdwr_pa[i].buf,
rdwr_pa[i].len)) {
res = -EFAULT;
}
}
kfree(rdwr_pa[i].buf);
}
kfree(data_ptrs);
kfree(rdwr_pa);
return res;
case I2C_SMBUS:
if (copy_from_user(&data_arg,
(struct i2c_smbus_ioctl_data __user *) arg,
sizeof(struct i2c_smbus_ioctl_data)))
return -EFAULT;
if ((data_arg.size != I2C_SMBUS_BYTE) &&
(data_arg.size != I2C_SMBUS_QUICK) &&
(data_arg.size != I2C_SMBUS_BYTE_DATA) &&
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
(data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
dev_dbg(&client->adapter->dev,
"size out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.size);
return -EINVAL;
}
/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
so the check is valid if size==I2C_SMBUS_QUICK too. */
if ((data_arg.read_write != I2C_SMBUS_READ) &&
(data_arg.read_write != I2C_SMBUS_WRITE)) {
dev_dbg(&client->adapter->dev,
"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.read_write);
return -EINVAL;
}
/* Note that command values are always valid! */
if ((data_arg.size == I2C_SMBUS_QUICK) ||
((data_arg.size == I2C_SMBUS_BYTE) &&
(data_arg.read_write == I2C_SMBUS_WRITE)))
/* These are special: we do not use data */
return i2c_smbus_xfer(client->adapter, client->addr,
client->flags,
data_arg.read_write,
data_arg.command,
data_arg.size, NULL);
if (data_arg.data == NULL) {
dev_dbg(&client->adapter->dev,
"data is NULL pointer in ioctl I2C_SMBUS.\n");
return -EINVAL;
}
if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
(data_arg.size == I2C_SMBUS_BYTE))
datasize = sizeof(data_arg.data->byte);
else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
(data_arg.size == I2C_SMBUS_PROC_CALL))
datasize = sizeof(data_arg.data->word);
else /* size == smbus block, i2c block, or block proc. call */
datasize = sizeof(data_arg.data->block);
if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.read_write == I2C_SMBUS_WRITE)) {
if (copy_from_user(&temp, data_arg.data, datasize))
return -EFAULT;
}
res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
data_arg.read_write,
data_arg.command,data_arg.size,&temp);
if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
(data_arg.read_write == I2C_SMBUS_READ))) {
if (copy_to_user(data_arg.data, &temp, datasize))
return -EFAULT;
}
return res;
default:
return i2c_control(client,cmd,arg);
}
return 0;
}
驱动层的ioctl(), 根据不同的command执行不同的操作。
应用层和驱动层之间数据传输用copy_from_user() 和copy_to_user(). 也可以put_user().
驱动层中核心的通信函数就是i2c_transfer().
这里如果i2c command是 I2C_RDWR, 则会用到i2c_transfer(), 这函数定义在 i2c-core.c 中:
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
int ret;
if (adap->algo->master_xfer) {
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
mutex_lock_nested(&adap->bus_lock, adap->level);
ret = adap->algo->master_xfer(adap,msgs,num);
mutex_unlock(&adap->bus_lock);
return ret;
} else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -ENOSYS;
}
}
EXPORT_SYMBOL(i2c_transfer);
这函数的核心,其实也就是
ret = adap->algo->master_xfer(adap,msgs,num);
这个函数指针其实就是在algo中赋值的,如这里用drivers/i2c/algos/i2c-algo-bit.c 的话,就是
static const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
也就是bit_xfer()函数:
static int bit_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct i2c_msg *pmsg;
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
int i,ret;
unsigned short nak_ok;
#ifdef BUGGY_SLM
unsigned long flags;
#endif
#ifdef BUGGY_SLM
local_irq_save(flags);
local_irq_disable();
#endif
bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
for (i=0;i<num;i++) {
pmsg = &msgs[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (!(pmsg->flags & I2C_M_NOSTART)) {
if (i) {
bit_dbg(3, &i2c_adap->dev, "emitting "
"repeated start condition\n");
i2c_repstart(adap);
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
bit_dbg(1, &i2c_adap->dev, "NAK from "
"device addr 0x%02x msg #%d\n",
msgs[i].addr, i);
goto bailout;
}
}
if (pmsg->flags & I2C_M_RD ) {
/* read bytes into buffer*/
ret = readbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EREMOTEIO;
goto bailout;
}
} else {
/* write bytes from buffer */
ret = sendbytes(i2c_adap, pmsg);
if (ret >= 1)
bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
ret, ret == 1 ? "" : "s");
if (ret < pmsg->len) {
if (ret >= 0)
ret = -EREMOTEIO;
goto bailout;
}
}
}
ret = i;
bailout:
bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
#ifdef BUGGY_SLM
local_irq_restore(flags);
local_irq_enable();
#endif
return ret;
}
这个函数中,其实就包含了一次I2C通讯了:
从i2c_start(adap) --- 发送start信号
到bit_doAddress(i2c_adap, pmsg); -- 发送地址+读写信号
再到 readbytes(i2c_adap, pmsg); --- 读i2c设备数据
或者 sendbytes(i2c_adap, pmsg); ---写i2c设备
最后 i2c_stop(adap); --- 发送一个stop信号
这就是一次完整的i2c通信协议了。
3. 应用层的i2c_read()
read(fd, pBuf, nDataLen)
pBuf --- 读取数据的buffer
nDataLen --- 需要读取的数据字节数,
这个会系统调用到驱动层的i2cdev_read()
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
char *tmp;
int ret;
struct i2c_client *client = (struct i2c_client *)file->private_data;
if (count > 8192)
count = 8192;
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
pr_debug("i2c-dev: i2c-%d reading %zd bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_recv(client,tmp,count);
if (ret >= 0)
ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
kfree(tmp);
return ret;
}
i2c_master_recv() 定义在 i2c-core.c 中:
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
{
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
int ret;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.flags |= I2C_M_RD;
msg.len = count;
msg.buf = buf;
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_recv);
其实还是用到了i2c_transfer().
4. 应用层的 write() 函数:
write(fd, pBuf, nDataLen)
pBuf --- 要写入数据的buffer
nDataLen --- 要写入i2c设备的数据的字节数
这个会系统调用到i2c-dev.c 的 i2cdev_write() 函数:
static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t count,
loff_t *offset)
{
int ret;
char *tmp;
struct i2c_client *client = (struct i2c_client *)file->private_data;
if (count > 8192)
count = 8192;
tmp = kmalloc(count,GFP_KERNEL);
if (tmp==NULL)
return -ENOMEM;
if (copy_from_user(tmp,buf,count)) {
kfree(tmp);
return -EFAULT;
}
pr_debug("i2c-dev: i2c-%d writing %zd bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
ret = i2c_master_send(client,tmp,count);
kfree(tmp);
return ret;
}
其实就是 i2c_master_send() 函数,这个定义在i2c-core.c 中
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
int ret;
struct i2c_adapter *adap=client->adapter;
struct i2c_msg msg;
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN;
msg.len = count;
msg.buf = (char *)buf;
ret = i2c_transfer(adap, &msg, 1);
/* If everything went ok (i.e. 1 msg transmitted), return #bytes
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
EXPORT_SYMBOL(i2c_master_send);
也还是i2c_transfer() 函数,所以这个函数绝对是I2C通信的核心了。