• 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
    ",
    		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.
    ",
    		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.
    ",
    		iminor(file_inode(file)), count);
    
    	ret = i2c_master_send(client, tmp, count);  //发数据
    	kfree(tmp);
    	return ret;
    }
    

      

     

     

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

  • 相关阅读:
    BAPI LIST
    如何设计折叠屏幕
    图形学习 Javascript 正则 regexper.com
    Javascript 的数据是什么数据类型?
    Javascript 严格模式下不允许删除一个不允许删除的属性
    Javascript 在严格模式下禁止指向 this
    指针自增学习
    Javascript 严格模式下几个禁忌
    笔记本设置 2K 显示屏 Intel HD Graphics 3000
    Javascript 在严格模式下不允许删除变量或对象
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/14918672.html
Copyright © 2020-2023  润新知