从APP层----设备驱动层----核心层------
APP:fd = open("/dev/i2c-1", O_RDWR);
VFS: sys_open
i2c-dev.c: i2c_dev_init()
执行i2cdev_fops的open操作即:i2cdev_open();
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;
/* This creates an anonymous i2c_client, which may later be
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
*
* This client is ** NEVER REGISTERED ** with the driver model
* or I2C core It just holds private copies of addressing
* information and maybe a PEC flag.
*/
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->adapter = adap; //指定client属于哪个适配器
file->private_data = client;
return 0;
}
=========================================================================
APP: ioctl(fd, I2C_SLAVE, device_addr)
VFS: sys_ioctl
i2c-dev.c:执行i2cdev_fops的unlocked_ioctl操作即:i2cdev_ioctl();
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
// 获取client属性
struct i2c_client *client = file->private_data;
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:
/* NOTE: devices set up to work with "new style" drivers
* can't use I2C_SLAVE, even when the device node is not
* bound to a driver. Only I2C_SLAVE_FORCE will work.
*
* Setting the PEC flag here won't affect kernel drivers,
* which will be using the i2c_client node registered with
* the driver model core. Likewise, when that client has
* the PEC flag already set, the i2c-dev driver won't see
* (or use) this setting.
*/
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
return -EBUSY;
/* REVISIT: address could become busy later */
client->addr = arg; //指定设备地址
return 0;
case I2C_TENBIT:
//设置10 bit地址模式
if (arg)
client->flags |= I2C_M_TEN;
else
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
//设置传输后增加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:
//读取和接收数据,后面讲述
return i2cdev_ioctl_rdrw(client, arg);
case I2C_SMBUS:
//smbus协议数据传输,后面讲述
return i2cdev_ioctl_smbus(client, arg);
case I2C_RETRIES:
//设置重试次数
client->adapter->retries = arg;
break;
case I2C_TIMEOUT:
/* For historical reasons, user-space sets the timeout
* value in units of 10 ms.
*/
//设置超时时间
client->adapter->timeout = msecs_to_jiffies(arg * 10);
break;
default:
/* NOTE: returning a fault code here could cause trouble
* in buggy userspace code. Some old kernel bugs returned
* zero in this case, and userspace code might accidentally
* have depended on that bug.
*/
return -ENOTTY;
}
return 0;
}
=========================================================================
APP:write(fd ,wbuf, 2)
VFS: sys_write
i2c-dev.c:执行i2cdev_fops的write操作即: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 = file->private_data;
if (count > 8192)
count = 8192;
tmp = memdup_user(buf, count);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
pr_debug("i2c-dev: i2c-%d writing %zu 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核心层的函数,即代表到i2c-core层
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
int ret;
struct i2c_adapter *adap=client->adapter; // 获取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 (eg: 1 msg transmitted), return bytes number transmitted, else error code.
return (ret == 1) ? count : ret; // 如果发送成功就返回字节数
}
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
if (in_atomic() || irqs_disabled()) {
ret = mutex_trylock(&adap->bus_lock);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
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;
}
}
通过i2c_transfer的adap->algo->master_xfer(adap,msgs,num);调用到i2c-s3c2410.c文件的函数,进而调用到总线驱动层。