简体   繁体   English

是否需要像其他任何字符设备驱动程序一样实现i2c驱动程序?

[英]Does i2c driver need to be implemented just like any other character device driver?

I'm a noob to Linux device drivers so please bear with me. 我是Linux设备驱动程序的菜鸟,请耐心等待。 I'm trying to implement a i2c driver (client). 我正在尝试实现i2c驱动程序(客户端)。 It's at the point where I can insmod , .probe gets called (because of device-tree entries) and in the .probe I can read/write to the device. 在这里我可以insmod.probe被调用(由于设备树条目),并且在.probe中我可以读写设备。 Great. 大。

However I need to be able to initiate read/writes from userspace to the driver. 但是,我需要能够启动从用户空间到驱动程序的读取/写入。 In order to do this, should an i2c driver be shaped like any other char device driver? 为此,i2c驱动程序的形状是否应与其他任何char设备驱动程序一样? Meaning having a file_operations struct so userspace can open , close , read , write , and ioctls ? 意味着具有file_operations结构,以便用户空间可以openclosereadwriteioctls

I'm asking because in all the i2c client examples I've seen, nobody has implemented these things I've mentioned. 我之所以问是因为在我所看到的所有i2c客户端示例中,没有人实现我提到的这些东西。 I'm wondering how the heck they initiated calls from userspace without the file_operations struct set up. 我想知道他们如何在没有设置file_operations结构的情况下从用户空间发起调用。 Maybe it was so obvious that nobody mentioned it, I don't know... I'm wondering if it's because i2c is referred to as a platform device driver it doesn't need this? 也许是显而易见的,没有人提到它,我不知道...我想知道是否是因为i2c被称为平台设备驱动程序,所以不需要它吗? If someone can confirm that would help me second guessing myself. 如果有人可以确认那将帮助我第二次猜测自己。

If you understand what I'm asking please ignore the rest. 如果您了解我的要求,请忽略其余部分。 If you are confused about my question here is a more concrete explanation of what I'm asking: 如果您对我的问题感到困惑,这里是对我所问问题的更具体的解释:

What I have right now: 我现在所拥有的:

static int device_probe(struct i2c_client           *client,
                        const struct i2c_device_id  *id)
{
    struct device      *dev = &client->dev;
    struct device_data *data;

    /* Check the functionality of the i2c-adapter for smbus byte read/write */
    if (!i2c_check_functionality(client->adapter,
                                 I2C_FUNC_SMBUS_BYTE_DATA))
    {
        printk(KERN_ALERT "%s %d: device required i2c functionality is not supported\n", __func__, __LINE__);
        return -ENODEV;
    }

    /* Allocate memory to hold the device data
     * Using devm_kzalloc so do not have to worry about kfree */
    data = devm_kzalloc(dev, sizeof(struct device_data), GFP_KERNEL);
    if (dev == NULL)
    {
        printk(KERN_ALERT "%s %d: no memory\n", __func__, __LINE__);
        return -ENOMEM;
    }

    /* Record the pointer to current client */
    data->device_i2c_client = client;

    /* Set the client's data field to point to device-specific data struct */
    i2c_set_clientdata(client, data);

    /* Add the device-specific data struct to our collection of device client devices */
    device_data_tbl[id->driver_data] = data;

    /* Do a read, test the access */
    device_read();

    return 0;
}

static int device_remove(struct i2c_client *client)
{
    return 0;
}


int device_read(uint8_t             device_device_id,
                uint16_t const      dev_reg_addr,
                uint8_t *const      read_val)
{
    /* some read access */
}

static struct i2c_device_id device_idtable[] = {
    { "si5342",   0 },
    { },
};
MODULE_DEVICE_TABLE(i2c, device_idtable);

static struct i2c_driver device_driver = {
  .driver = {
    .name = device_DRIVER_NAME,
        .owner  = THIS_MODULE
  },
  .id_table = device_idtable,
    .probe      = device_probe,
    .remove     = device_remove,
};

static int __init device_driver_init(void)
{
    return i2c_add_driver(&device_driver);
}
module_init(device_driver_init);


static void __exit device_driver_exit(void)
{
    return i2c_del_driver(&device_driver);
}
module_exit(device_driver_exit);

Wondering if the following elements needs to be added in 想知道是否需要添加以下元素

static struct file_operations oxdrv_fops =
{
    .owner   = THIS_MODULE,
    .release = device_release,
    .open    = device_open,
    .unlocked_ioctl = device_ioctl
};

/* Associated function definitions: device_open, device_ioctl, etc */

alloc_chrdev_region();
cdev_init();

I think I understand the device driver model better now with @Alexandre Belloni's comment and reading this set of presentation slides: http://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf . 我想我现在可以通过@Alexandre Belloni的评论并阅读以下演示幻灯片来更好地了解设备驱动程序模型: http ://free-electrons.com/doc/training/linux-kernel/linux-kernel-slides.pdf。 The relevant slides are from page 221 to 236. 相关幻灯片从第221页到第236页。

There are 3 types of device drivers: 有3种类型的设备驱动程序:

  1. Character 字符
  2. Network 网络
  3. Block

However, there are specific "frameworks" that exist as a subclass of character device drivers which implements the common parts of drivers for the same type of devices. 但是,有一些特定的“框架”作为字符设备驱动程序的子类存在,它们为同一类型的设备实现了驱动程序的公共部分。

For example a temperature sensor on the motherboard used for hardware monitoring would be registered under the hwmon framework ( https://www.kernel.org/doc/Documentation/hwmon/hwmon-kernel-api.txt ). 例如,用于硬件监视的主板上的温度传感器将在hwmon框架下注册( https://www.kernel.org/doc/Documentation/hwmon/hwmon-kernel-api.txt )。 You would implement the i2c probe , read , write functionality but instead of shaping it into a character device with file_operations struct , you just need to register it as a hwmon device: hwmon_device_register_with_groups() . 您将实现i2c probereadwrite功能,但无需将其塑造为具有file_operations struct的字符设备,只需将其注册为hwmon设备: hwmon_device_register_with_groups() To expose to userspace you need to build up your /sys/class/hwmon/hwmon* directory using attributes with the list of exposed read/write commands you want (ex: read temp from channel 1, write to limit temp register). 要暴露给用户空间,您需要使用attributes和所需的暴露的读/写命令列表来构建/sys/class/hwmon/hwmon*目录(例如:从通道1读取温度,写入限制温度寄存器)。

When you build the kernel, select your device in make menuconfig in order for it to be built with the kernel. 当您构建内核时,请在make menuconfig中选择设备,以make menuconfig与内核一起构建。 With this, once you bootup the kernel, the device will appear under /sys/class/hwmon/hwmon* , and userspace can then open and read from the device through the sysfs interface. 这样,一旦启动内核,该设备将出现在/sys/class/hwmon/hwmon* ,然后用户空间可以通过sysfs接口open并从该设备read See a good example here: http://lxr.free-electrons.com/source/drivers/hwmon/tmp421.c . 在此处查看一个很好的示例: http : //lxr.free-electrons.com/source/drivers/hwmon/tmp421.c Or any device in the hwmon directory. 或hwmon目录中的任何设备。

So that's where my confusion was. 这就是我的困惑所在。 As @Alexandre Belloni pointed out, these devices are registered under a framework so the explicit character device driver code is not necessary. 正如@Alexandre Belloni指出的那样,这些设备是在框架下注册的,因此不需要显式字符设备驱动程序代码。 For me this is not the case, I don't think there is a suitable framework for the device I'm doing (clocking PLL). 对我而言,情况并非如此,我认为没有适用于我正在做的设备的合适框架(时钟PLL)。 Thus I will need to go the general route and implement as a character device. 因此,我将需要走一般路线并将其实现为字符设备。 This will also allow me to load/unload as a module rather than it automatically being loaded during kernel bootup. 这也将允许我以模块的形式加载/卸载,而不是在内核启动过程中自动加载/卸载。

Please feel free to correct any mistakes I made. 请随时纠正我犯的任何错误。 I hope this is helpful for anyone else confused about writing i2c-clients. 我希望这对其他对编写i2c客户端感到困惑的人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM