IIC驱动---系统流程分析(4)

从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文件的函数,进而调用到总线驱动层。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值