i2c驱动理解

I2C驱动全面解析

Linux I2C驱动框架(超详细)

I2C驱动之i2c总线设备及驱动

 

 

 

 

 

 

 https://zhuanlan.zhihu.com/p/166124369

i2cdev_ioctl函数:

static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	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:      //
		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:     //十位还是七位地址flag
		if (arg)
			client->flags |= I2C_M_TEN;
		else
			client->flags &= ~I2C_M_TEN;
		return 0;
	case I2C_PEC:       //   //设置传输后增加校验标志
		/*
		 * 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)
			client->flags |= I2C_CLIENT_PEC;
		else
			client->flags &= ~I2C_CLIENT_PEC;
		return 0;
	case I2C_FUNCS:               
		funcs = i2c_get_functionality(client->adapter);     //获取适配器支持的功能 :获取访问总线的协议,i2c协议还是smbus协议
		return put_user(funcs, (unsigned long __user *)arg);

	case I2C_RDWR:      //i2c数据传输
		return i2cdev_ioctl_rdwr(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;
}

memdup_user()函数:

用户态到内核态的拷贝,都会涉及到两个必要的步骤:
 *    void *memdup_user(const void __user *src, size_t len)
 *    {
 *        void *p;
 *    
 *        p = kmalloc_track_caller(len, GFP_KERNEL);    //内核态分配个空间
 *        if (!p)
 *            return ERR_PTR(-ENOMEM);
 *    
 *        if (copy_from_user(p, src, len)) {        //从用户态拷过来
 *            kfree(p);
 *            return ERR_PTR(-EFAULT);
 *        }
 *    
 *        return p;
 *    }

 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 = 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 %zu bytes.\n",
		iminor(file_inode(file)), count);

	ret = i2c_master_recv(client, tmp, count);    //主机接收数据
	if (ret >= 0)
		ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;   //将数据从内核空间拷贝到用户空间
 	kfree(tmp);
	return ret;
}

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_inode(file)), count);

	ret = i2c_master_send(client, tmp, count);  //发数据
	kfree(tmp);
	return ret;
}

  

 

 

 

https://www.cnblogs.com/embInn/p/13289367.html

posted @ 2021-06-22 15:06  轻轻的吻  阅读(485)  评论(0编辑  收藏  举报