Linux Kernel 设备驱动之I2C之i2c设备文件

    xiaoxiao2021-03-25  90

    当提供I2C设备文件时,用户空间可以通过设备文件直接操作设备。这里需要配置 CONFIG_I2C_CHARDEV。

    static int __init i2c_dev_init(void) {  int res;

     printk(KERN_INFO "i2c /dev entries driver\n");

     res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c");  if (res)   goto out;

     i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");  if (IS_ERR(i2c_dev_class)) {   res = PTR_ERR(i2c_dev_class);   goto out_unreg_chrdev;  }  i2c_dev_class->dev_groups = i2c_groups;

     /* Keep track of adapters which will be added or removed later */  res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);  if (res)   goto out_unreg_class;

     /* Bind to already existing adapters right away */  i2c_for_each_dev(NULL, i2cdev_attach_adapter);

     return 0;

    out_unreg_class:  class_destroy(i2c_dev_class); out_unreg_chrdev:  unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS); out:  printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);  return res; }

    static const struct file_operations i2cdev_fops = {  .owner  = THIS_MODULE,  .llseek  = no_llseek,  .read  = i2cdev_read,  .write  = i2cdev_write,  .unlocked_ioctl = i2cdev_ioctl,  .open  = i2cdev_open,  .release = i2cdev_release, };

    /* ------------------------------------------------------------------------- */

    static struct class *i2c_dev_class;

    static int i2cdev_attach_adapter(struct device *dev, void *dummy) {  struct i2c_adapter *adap;  struct i2c_dev *i2c_dev;  int res;

     if (dev->type != &i2c_adapter_type)   return 0;  adap = to_i2c_adapter(dev);

     i2c_dev = get_free_i2c_dev(adap);  if (IS_ERR(i2c_dev))   return PTR_ERR(i2c_dev);

     cdev_init(&i2c_dev->cdev, &i2cdev_fops);  i2c_dev->cdev.owner = THIS_MODULE;  res = cdev_add(&i2c_dev->cdev, MKDEV(I2C_MAJOR, adap->nr), 1);  if (res)   goto error_cdev;

     /* register this i2c device with the driver core */  i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,          MKDEV(I2C_MAJOR, adap->nr), NULL,          "i2c-%d", adap->nr);  if (IS_ERR(i2c_dev->dev)) {   res = PTR_ERR(i2c_dev->dev);   goto error;  }

     pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",    adap->name, adap->nr);  return 0; error:  cdev_del(&i2c_dev->cdev); error_cdev:  put_i2c_dev(i2c_dev);  return res; }

       

    static int i2cdev_detach_adapter(struct device *dev, void *dummy) {  struct i2c_adapter *adap;  struct i2c_dev *i2c_dev;

     if (dev->type != &i2c_adapter_type)   return 0;  adap = to_i2c_adapter(dev);

     i2c_dev = i2c_dev_get_by_minor(adap->nr);  if (!i2c_dev) /* attach_adapter must have failed */   return 0;

     cdev_del(&i2c_dev->cdev);  put_i2c_dev(i2c_dev);  device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));

     pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);  return 0; }

    static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,     void *data) {  struct device *dev = data;

     switch (action) {  case BUS_NOTIFY_ADD_DEVICE:   return i2cdev_attach_adapter(dev, NULL);  case BUS_NOTIFY_DEL_DEVICE:   return i2cdev_detach_adapter(dev, NULL);  }

     return 0; }

    static struct notifier_block i2cdev_notifier = {  .notifier_call = i2cdev_notifier_call, };

       
    转载请注明原文地址: https://ju.6miu.com/read-11799.html

    最新回复(0)