欧美亚洲一区二区三区,午夜欧美艳情视频免费看,欧美XXXXX又粗又大,国精品产露脸偷拍视频

技術文摘

Linux I2C驅動分析(三)——i2c_dev驅動和應用層分析












一、i2c-dev驅動分析

1.1、設備驅動注冊

分析這個驅動,還是從module_init()和module_exit()開始,程序如下:

1.       static int __init i2c_dev_init(void)

2.       {

3.           int res;

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

5.           res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);

6.           if (res)

7.               goto out;

8.           i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");

9.           if (IS_ERR(i2c_dev_class)) {

10.              res = PTR_ERR(i2c_dev_class);

11.              goto out_unreg_chrdev;

12.          }

13.          /* Keep track of adapters which will be added or removed later */

14.          res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);

15.          if (res)

16.              goto out_unreg_class;

17.          /* Bind to already existing adapters right away */

18.          i2c_for_each_dev(NULL, i2cdev_attach_adapter);

19.          return 0;

20.      out_unreg_class:

21.          class_destroy(i2c_dev_class);

22.      out_unreg_chrdev:

23.          unregister_chrdev(I2C_MAJOR, "i2c");

24.      out:

25.          printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);

26.          return res;

27.      }

28.      static void __exit i2c_dev_exit(void)

29.      {

30.          bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);

31.          i2c_for_each_dev(NULL, i2cdev_detach_adapter);

32.          class_destroy(i2c_dev_class);

33.          unregister_chrdev(I2C_MAJOR, "i2c");

34.      }

35.      module_init(i2c_dev_init);

36.      module_exit(i2c_dev_exit);


首先注冊了i2cdev_fops操作函數(shù)集,接著注冊了一個名為”i2c-dev”的class,然后又注冊了一個i2cdev_notifier,i2cdev_notifier如下

1.  static struct notifier_block i2cdev_notifier = {

2.      .notifier_call = i2cdev_notifier_call,

3.  };

4.  int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,

5.               void *data)

6.  {

7.      struct device *dev = data;

8.   

9.      switch (action) {

10.        case BUS_NOTIFY_ADD_DEVICE:

11.            return i2cdev_attach_adapter(dev, NULL);

12.        case BUS_NOTIFY_DEL_DEVICE:

13.            return i2cdev_detach_adapter(dev, NULL);

14.        }

15.     

16.        return 0;

17.    }


緊接著看下i2cdev_attach_adapter函數(shù):

1.  static int i2cdev_attach_adapter(struct device *dev, void *dummy)

2.  {

3.      struct i2c_adapter *adap;

4.      struct i2c_dev *i2c_dev;

5.      int res;

6.      if (dev->type != &i2c_adapter_type)

7.          return 0;

8.      adap = to_i2c_adapter(dev);

9.      i2c_dev = get_free_i2c_dev(adap);

10.          if (IS_ERR(i2c_dev))

11.              return PTR_ERR(i2c_dev);

12.          /* register this i2c device with the driver core */

13.          i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,

14.                       MKDEV(I2C_MAJOR, adap->nr), NULL,

15.                       "i2c-%d", adap->nr);

16.          if (IS_ERR(i2c_dev->dev)) {

17.              res = PTR_ERR(i2c_dev->dev);

18.              goto error;

19.          }

20.          res = device_create_file(i2c_dev->dev, &dev_attr_name);

21.          if (res)

22.              goto error_destroy;

23.          pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",

24.               adap->name, adap->nr);

25.          return 0;

26.      error_destroy:

27.          device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));

28.      error:

29.          return_i2c_dev(i2c_dev);

30.          return res;

31.      }


這個函數(shù)也很簡單,首先調用get_free_i2c_dev()分配并初始化了一個struct i2c_dev結構,使i2c_dev->adap指向操作的adapter.之后,該i2c_dev會被鏈入鏈表i2c_dev_list中。再分別以I2C_MAJOR,、adap->nr為主次設備號創(chuàng)建了一個device。如果此時系統(tǒng)配置了udev或者是hotplug,那么就在/dev下自動創(chuàng)建相關的設備節(jié)點了。

i2cdev_detach_adapter函數(shù)完成相反的操作,在此省略。

所有主設備號為I2C_MAJOR的設備節(jié)點的操作函數(shù)是i2cdev_fops,它的定義如下所示:

1.  static const struct file_operations i2cdev_fops = {

2.      .owner        = THIS_MODULE,

3.      .llseek        = no_llseek,

4.      .read        = i2cdev_read,

5.      .write        = i2cdev_write,

6.      .unlocked_ioctl    = i2cdev_ioctl,

7.      .open        = i2cdev_open,

8.      .release    = i2cdev_release,

9.  };


接下來一一分析i2cdev_fops結構體的成員。







1.2、設備打開函數(shù)--i2cdev_open

1.  static int i2cdev_open(struct inode *inode, struct file *file)

2.  {

3.      unsigned int minor = iminor(inode);

4.      struct i2c_client *client;

5.      struct i2c_adapter *adap;

6.      struct i2c_dev *i2c_dev;

7.      i2c_dev = i2c_dev_get_by_minor(minor);     //以次設備號從i2c_dev_list鏈表中取得i2c_dev

8.      if (!i2c_dev)

9.          return -ENODEV;

10.          adap = i2c_get_adapter(i2c_dev->adap->nr);    //以apapter的總線號從i2c_adapter_idr中找到adapter

11.          if (!adap)

12.              return -ENODEV;

13.          /* This creates an anonymous i2c_client, which may later be

14.           * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.

15.           *

16.           * This client is ** NEVER REGISTERED ** with the driver model

17.           * or I2C core It just holds private copies of addressing

18.           * information and maybe a PEC flag.

19.           */

20.          client = kzalloc(sizeof(*client), GFP_KERNEL);    //分配并初始化一個i2c_client結構

21.          if (!client) {

22.              i2c_put_adapter(adap);

23.              return -ENOMEM;

24.          }

25.          snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);

26.          client->adapter = adap;    //clinet->adapter指向操作的adapter

27.          file->private_data = client;     //關聯(lián)到file

28.          return 0;

29.      }


注意這里分配并初始化了一個struct i2c_client結構,但是沒有注冊這個clinet。此外,這個函數(shù)中還有一個比較奇怪的操作,不是在前面已經將i2c_dev->adap 指向要操作的adapter么?為什么還要以adapter->nr為關鍵字從i2c_adapter_idr去找這個操作的adapter呢?因為調用i2c_get_adapter()從總線號nr找到操作的adapter的時候,還會增加module的引用計數(shù),這樣可以防止模塊意外被釋放掉,那i2c_dev->adap->nr操作,如果i2c_dev->adap被釋放掉的話,不是會引起系統(tǒng)崩潰么?這里因為在i2cdev_attach_adapter()間接的增加了一次adapter的一次引用計數(shù).如下:

1.  static int i2cdev_attach_adapter(struct i2c_adapter *adap)

2.  {

3.  ......

4.  i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,

5.                      MKDEV(I2C_MAJOR, adap->nr),

6.                      "i2c-%d", adap->nr);

7.  ......

8.  }


i2c_dev內嵌的device是以adap->dev為父結點,在device_create()中會增次adap->dev的一次引用計數(shù)。




1.3、read操作

Read操作對應的操作函數(shù)如下示:
1.   static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,

2.                               loff_t *offset)

3.   {

4.       char *tmp;

5.       int ret;

6.       struct i2c_client *client = (struct i2c_client *)file->private_data;

7.       if (count > 8192)

8.           count = 8192;

9.       tmp = kmalloc(count,GFP_KERNEL);

10.      if (tmp==NULL)

11.          return -ENOMEM;

12.      pr_debug("i2c-dev: i2c-%d reading %zd bytes./n",

13.          iminor(file->f_path.dentry->d_inode), count);

14.      ret = i2c_master_recv(client,tmp,count);

15.      if (ret >= 0)

16.          ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;

17.      kfree(tmp);

18.      return ret;

19.  }


首先從file結構中取得struct i2c_clinet,然后在kernel分配相同長度的緩存區(qū),隨之調用i2c_master_recv()從設備中讀取數(shù)據(jù).再將讀取出來的數(shù)據(jù)copy到用戶空間中。I2c_master_recv()在Linux I2C驅動分析(二)----I2C板級設備掃描和數(shù)據(jù)傳輸已經講述。







1.4、write操作

1.  static ssize_t i2cdev_write(struct file *file, const char __user *buf,

2.          size_t count, loff_t *offset)

3.  {

4.      int ret;

5.      char *tmp;

6.      struct i2c_client *client = file->private_data;

7.   

8.      if (count > 8192)

9.          count = 8192;

10.     

11.        tmp = memdup_user(buf, count);

12.        if (IS_ERR(tmp))

13.            return PTR_ERR(tmp);

14.     

15.        pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",

16.            iminor(file->f_path.dentry->d_inode), count);

17.     

18.        ret = i2c_master_send(client, tmp, count);

19.        kfree(tmp);

20.        return ret;

21.    }


該操作比較簡單,就是將用戶空間的數(shù)據(jù)通過使用函數(shù)i2c_master_send發(fā)送到i2c 設備。i2c_master_send函數(shù)在《Linux I2C驅動分析(二)----I2C板級設備掃描和數(shù)據(jù)傳輸》已經講述。

memdup_user函數(shù)完成分配存儲區(qū),把應用層的數(shù)據(jù)復制到剛分配的存儲區(qū)中,具體程序如下:
1.     void *memdup_user(const void __user *src, size_t len)

2.     {

3.         void *p;

4.         /*

5.          * Always use GFP_KERNEL, since copy_from_user() can sleep and

6.          * cause pagefault, which makes it pointless to use GFP_NOFS

7.          * or GFP_ATOMIC.

8.          */

9.         p = kmalloc_track_caller(len, GFP_KERNEL);

10.        if (!p)

11.            return ERR_PTR(-ENOMEM);

12.        if (copy_from_user(p, src, len)) {

13.            kfree(p);

14.            return ERR_PTR(-EFAULT);

15.        }

16.        return p;

17.    }




1.5、ioctl函數(shù)

有人可能看出了一個問題,clinet->addr是從哪來的呢?對,在read之前應該還要有一步操作來設置clinet->addr的值。這個過程是ioctl的操作,ioctl可以設置PEC標志,重試次數(shù),超時時間和發(fā)送接收數(shù)據(jù)等。具體程序如下:
1.  static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

2.  {

3.      struct i2c_client *client = file->private_data;

4.      unsigned long funcs;

5.      dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",

6.          cmd, arg);

7.      switch (cmd) {

8.      case I2C_SLAVE:

9.      case I2C_SLAVE_FORCE:

10.          /* NOTE: devices set up to work with "new style" drivers

11.           * can't use I2C_SLAVE, even when the device node is not

12.           * bound to a driver. Only I2C_SLAVE_FORCE will work.

13.           *

14.           * Setting the PEC flag here won't affect kernel drivers,

15.           * which will be using the i2c_client node registered with

16.           * the driver model core. Likewise, when that client has

17.           * the PEC flag already set, the i2c-dev driver won't see

18.           * (or use) this setting.

19.           */

20.          if ((arg > 0x3ff) ||

21.           (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))

22.              return -EINVAL;

23.          if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))

24.              return -EBUSY;

25.          /* REVISIT: address could become busy later */

26.          client->addr = arg;    //設置addr

27.          return 0;

28.      case I2C_TENBIT:

29.          //設置10 bit地址模式

30.          if (arg)

31.              client->flags |= I2C_M_TEN;

32.          else

33.              client->flags &= ~I2C_M_TEN;

34.          return 0;

35.      case I2C_PEC:

36.          //設置傳輸后增加PEC標志

37.          if (arg)

38.              client->flags |= I2C_CLIENT_PEC;

39.          else

40.              client->flags &= ~I2C_CLIENT_PEC;

41.          return 0;

42.      case I2C_FUNCS:

43.          //獲取函數(shù)支持

44.          funcs = i2c_get_functionality(client->adapter);

45.          return put_user(funcs, (unsigned long __user *)arg);

46.      case I2C_RDWR:

47.          //讀取和接收數(shù)據(jù),后面講述

48.          return i2cdev_ioctl_rdrw(client, arg);

49.      case I2C_SMBUS:

50.          //smbus協(xié)議數(shù)據(jù)傳輸,后面講述

51.          return i2cdev_ioctl_smbus(client, arg);

52.      case I2C_RETRIES:

53.          //設置重試次數(shù)

54.          client->adapter->retries = arg;

55.          break;

56.      case I2C_TIMEOUT:

57.          /* For historical reasons, user-space sets the timeout

58.           * value in units of 10 ms.

59.           */

60.          //設置超時時間

61.          client->adapter->timeout = msecs_to_jiffies(arg * 10);

62.          break;

63.      default:

64.          /* NOTE: returning a fault code here could cause trouble

65.           * in buggy userspace code. Some old kernel bugs returned

66.           * zero in this case, and userspace code might accidentally

67.           * have depended on that bug.

68.           */

69.          return -ENOTTY;

70.      }

71.      return 0;

72.  }


讀取和接收數(shù)據(jù)函數(shù)i2cdev_ioctl_rdrw(client, arg);如下:

1.  static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,

2.          unsigned long arg)

3.  {

4.      struct i2c_rdwr_ioctl_data rdwr_arg;    //包括i2c_msg和它的個數(shù)

5.      struct i2c_msg *rdwr_pa;

6.      u8 __user **data_ptrs;

7.      int i, res;

8.      if (copy_from_user(&rdwr_arg,

9.               (struct i2c_rdwr_ioctl_data __user *)arg,

10.                 sizeof(rdwr_arg)))

11.            return -EFAULT;

12.        /* Put an arbitrary limit on the number of messages that can

13.         * be sent at once */

14.        if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)

15.            return -EINVAL;

16.        rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);    //創(chuàng)建存儲i2c_msg的內存

17.        if (!rdwr_pa)

18.            return -ENOMEM;

19.        if (copy_from_user(rdwr_pa, rdwr_arg.msgs,

20.                 rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {

21.            kfree(rdwr_pa);

22.            return -EFAULT;

23.        }

24.        data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);

25.        if (data_ptrs == NULL) {

26.            kfree(rdwr_pa);

27.            return -ENOMEM;

28.        }

29.        res = 0;

30.        for (i = 0; i < rdwr_arg.nmsgs; i++) {

31.            /* Limit the size of the message to a sane amount;

32.             * and don't let length change either. */

33.            if ((rdwr_pa[i].len > 8192) ||

34.             (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {

35.                res = -EINVAL;

36.                break;

37.            }

38.            data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;

39.            rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);

40.            if (IS_ERR(rdwr_pa[i].buf)) {

41.                res = PTR_ERR(rdwr_pa[i].buf);

42.                break;

43.            }

44.        }

45.        if (res < 0) {

46.            int j;

47.            for (j = 0; j < i; ++j)

48.                kfree(rdwr_pa[j].buf);

49.            kfree(data_ptrs);

50.            kfree(rdwr_pa);

51.            return res;

52.        }

53.        res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);    //傳輸數(shù)據(jù)

54.        while (i-- > 0) {

55.            if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {

56.                if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,

57.                         rdwr_pa[i].len))    //將接收到的數(shù)據(jù)發(fā)送到應用層

58.                    res = -EFAULT;

59.            }

60.            kfree(rdwr_pa[i].buf);

61.        }

62.        kfree(data_ptrs);

63.        kfree(rdwr_pa);

64.        return res;

65.    }


smbus協(xié)議數(shù)據(jù)傳輸函數(shù)i2cdev_ioctl_smbus(client, arg);如下:

1.  static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,

2.          unsigned long arg)

3.  {

4.      struct i2c_smbus_ioctl_data data_arg;

5.      union i2c_smbus_data temp;

6.      int datasize, res;

7.      //從應用層復制數(shù)據(jù)

8.      if (copy_from_user(&data_arg,

9.               (struct i2c_smbus_ioctl_data __user *) arg,

10.                 sizeof(struct i2c_smbus_ioctl_data)))

11.            return -EFAULT;

12.        if ((data_arg.size != I2C_SMBUS_BYTE) &&

13.         (data_arg.size != I2C_SMBUS_QUICK) &&

14.         (data_arg.size != I2C_SMBUS_BYTE_DATA) &&

15.         (data_arg.size != I2C_SMBUS_WORD_DATA) &&

16.         (data_arg.size != I2C_SMBUS_PROC_CALL) &&

17.         (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&

18.         (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&

19.         (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&

20.         (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {

21.            dev_dbg(&client->adapter->dev,

22.                "size out of range (%x) in ioctl I2C_SMBUS.\n",

23.                data_arg.size);

24.            return -EINVAL;    //不符合協(xié)議,直接退出

25.        }

26.        /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,

27.         so the check is valid if size==I2C_SMBUS_QUICK too. */

28.        if ((data_arg.read_write != I2C_SMBUS_READ) &&

29.         (data_arg.read_write != I2C_SMBUS_WRITE)) {

30.            dev_dbg(&client->adapter->dev,

31.                "read_write out of range (%x) in ioctl I2C_SMBUS.\n",

32.                data_arg.read_write);

33.            return -EINVAL;    //既不是讀,也不是寫

34.        }

35.        /* Note that command values are always */

36.        if ((data_arg.size == I2C_SMBUS_QUICK) ||

37.         ((data_arg.size == I2C_SMBUS_BYTE) &&

38.         (data_arg.read_write == I2C_SMBUS_WRITE)))

39.            /* These are special: we do not use data */

40.            return i2c_smbus_xfer(client->adapter, client->addr,

41.                     client->flags, data_arg.read_write,

42.                     data_arg.command, data_arg.size, NULL);     //不需要讀

43.        if (data_arg.data == NULL) {

44.            dev_dbg(&client->adapter->dev,

45.                "data is NULL pointer in ioctl I2C_SMBUS.\n");

46.            return -EINVAL;

47.        }

48.        //判斷數(shù)據(jù)大小

49.        if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||

50.         (data_arg.size == I2C_SMBUS_BYTE))

51.            datasize = sizeof(data_arg.data->byte);

52.        else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||

53.             (data_arg.size == I2C_SMBUS_PROC_CALL))

54.            datasize = sizeof(data_arg.data->word);

55.        else /* size == smbus block, i2c block, or block proc. call */

56.            datasize = sizeof(data_arg.data->block);

57.        if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||

58.         (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||

59.         (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||

60.         (data_arg.read_write == I2C_SMBUS_WRITE)) {

61.            if (copy_from_user(&temp, data_arg.data, datasize))

62.                return -EFAULT;

63.        }

64.        if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {

65.            /* Convert old I2C block commands to the new

66.             convention. This preserves binary compatibility. */

67.            data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;

68.            if (data_arg.read_write == I2C_SMBUS_READ)

69.                temp.block[0] = I2C_SMBUS_BLOCK_MAX;

70.        }

71.        //smbus數(shù)據(jù)傳輸,2中已經講述

72.        res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,

73.         data_arg.read_write, data_arg.command, data_arg.size, &temp);

74.        if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||

75.             (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||

76.             (data_arg.read_write == I2C_SMBUS_READ))) {

77.            if (copy_to_user(data_arg.data, &temp, datasize))

78.                return -EFAULT;

79.        }

80.        return res;

81.    }







二、用戶空間使用i2c_dev

對于注冊的i2c適配器,用戶空間可以使用它們。上面的驅動對每個適配器生成一個主設備號為89的設備節(jié)點,實現(xiàn)了文件操作接口,用戶空間可以通過i2c設備節(jié)點訪問i2c適配器。適配器的編號從0開始,和適配器的設備節(jié)點的次設備號相同。i2c適配器的設備節(jié)點是/dev/i2c-x,其中x是數(shù)字,代表適配器的編號。由于適配器編號是動態(tài)分配的(和注冊次序有關),所以想了解哪一個適配器對應什么編號,可以查看/sys/class/i2c-dev/目錄下的文件內容。







2.1 前期準備

為了在用戶空間的程序當中操作i2c適配器,必須在程序中包含以下兩句:

1.  #include<linux/i2c-dev.h>

2.  #include<linux/i2c.h>

這兩個頭文件中定義了之后需要用到的結構體和宏。然后就可以打開設備節(jié)點了。但是打開哪一個呢?因為適配器的編號并不固定。為此我們在終端中運行以下命令:

[root@hdw /]# cat /sys/class/i2c-dev/i2c-0/name

BLX GSC3280 I2C adapter

如果我們想打開第二個適配器,剛好它的編號是1,對應的設備節(jié)點是/dev/i2c-1。那么可以用下面的方法打開它:

1.  int fd;

2.  if ((fd = open("/dev/i2c-1",O_RDWR))< 0)

3.  {

4.      /* 錯誤處理 */        

5.      exit(1);

6.  }

打開適配器對應的設備節(jié)點,i2c-dev為打開的線程建立一個i2c_client,但是這個i2c_client并不加到i2c_adapter的client鏈表當中。當用戶關閉設備節(jié)點時,它自動被釋放。







2.2 IOCTL控制

查看include/linux/i2c-dev.h文件,可以看到i2c-dev支持的IOCTL命令。如下:

1.  #define I2C_RETRIES 0x0701 /* 設置收不到ACK時的重試次數(shù) */

2.  #define I2C_TIMEOUT 0x0702 /* 設置超時時限的jiffies */

3.  #define I2C_SLAVE 0x0703 /* 設置從機地址 */

4.  #define I2C_SLAVE_FORCE 0x0706 /* 強制設置從機地址 */

5.  #define I2C_TENBIT 0x0704 /* 選擇地址位長:=0 for 7bit , != 0 for 10 bit */

6.  #define I2C_FUNCS 0x0705 /* 獲取適配器支持的功能 */

7.  #define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */

8.  #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */

9.  #define I2C_SMBUS 0x0720 /* SMBus transfer */


下面進行一一解釋。

1.設置重試次數(shù)      

      1.   ioctl(fd, I2C_RETRIES, m); //這句話設置適配器收不到ACK時重試的次數(shù)為m。默認的重試次數(shù)為1。


2.設置超時

      1.   ioctl(fd, I2C_TIMEOUT, m); //設置SMBus的超時時間為m,單位為jiffies。


3.設置從機地址

      1.   ioctl(fd, I2C_SLAVE,addr);

      2.   ioctl(fd, I2C_SLAVE_FORCE, addr);


在調用read()和write()函數(shù)之前必須設置從機地址。這兩行都可以設置從機的地址,區(qū)別是第二行無論內核中是否已有驅動在使用這個地址都會成功, 第一行則只在該地址空閑的情況下成功。由于i2c-dev創(chuàng)建的i2c_client不加入i2c_adapter的client列表,所以不能防止其它線程使用同一地址,也不能防止驅動模塊占用同一地址。

4.設置地址模式
      1.   ioctl(file, I2C_TENBIT, select); //如果select不等于0選擇10比特地址模式,如果等于0選擇7比特模式,默認7比特。只有適配器支持I2C_FUNC_10BIT_ADDR,這個請求才是有效的。

5.獲取適配器功能
      1.     ioctl(file, I2C_FUNCS, (unsignedlong *)funcs); //獲取的適配器功能保存在funcs中。各比特的含義如:
      2.     /* include/linux/i2c.h */
      3.     #define I2C_FUNC_I2C 0x00000001
      4.     #define I2C_FUNC_10BIT_ADDR 0x00000002
      5.     #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
      6.     #define I2C_FUNC_SMBUS_PEC 0x00000008
      7.     #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
      8.     #define I2C_FUNC_SMBUS_QUICK 0x00010000
      9.     #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
     10.    #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
     11.    #define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
     12.    #define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
     13.    #define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
     14.    #define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
     15.    #define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
     16.    #define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
     17.    #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
     18.    #define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
     19.    #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
     20.    #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */
     21.    #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */

6.I2C層通信
      1.     ioctl(file, I2C_RDWR, (structi2c_rdwr_ioctl_data *)msgset);

這一行代碼可以使用I2C協(xié)議和設備進行通信。它進行連續(xù)的讀寫,中間沒有間歇。只有當適配器支持I2C_FUNC_I2C此命令才有效。參數(shù)是一個指針,指向一個結構體,它的定義如:
      1.     struct i2c_rdwr_ioctl_data {
      2.         struct i2c_msg __user *msgs; /* 指向i2c_msgs數(shù)組 */
      3.         __u32nmsgs; /* 消息的個數(shù) */
      4.     };

msgs[] 數(shù)組成員包含了指向各自緩沖區(qū)的指針。這個函數(shù)會根據(jù)是否在消息中的flags置位I2C_M_RD來對緩沖區(qū)進行讀寫。從機的地址以及是否使用10比特地址模式記錄在每個消息中,忽略之前ioctl設置的結果。

7.設置SMBus PEC 
      1.     ioctl(file, I2C_PEC, (long )select);

如果select不等于0選擇SMBus PEC (packet error checking),等于零則關閉這個功能,默認是關閉的。

這個命令只對SMBus傳輸有效。這個請求只在適配器支持I2C_FUNC_SMBUS_PEC時有效;如果不支持這個命令也是安全的,它不做任何工作。

8.SMBus通信
      1.   ioctl(file, I2C_SMBUS, (i2c_smbus_ioctl_data*)msgset);

這個函數(shù)和I2C_RDWR類似,參數(shù)的指針指向i2c_smbus_ioctl_data類型的變量,它的定義如:

      1.   struct i2c_smbus_ioctl_data {

      2.       __u8read_write;

      3.       __u8command;

      4.       __u32size;

      5.       unioni2c_smbus_data __user *data;

      6.   };







2.3 i2c_dev使用例程

要想在用戶空間使用i2c適配器,首先要選擇某個適配器的設備節(jié)點打開,然后才能進行通信。

2.3.1 read()/write()

通信的方式有兩種,一種是使用操作普通文件的接口read()和write()。這兩個函數(shù)間接調用了i2c_master_recv和i2c_master_send。但是在使用之前需要使用I2C_SLAVE設置從機地址,設置可能失敗,需要檢查返回值。這種通信過程進行I2C層的通信,一次只能進行一個方向的傳輸。

下面的程序是ARM與E2PROM芯片通信的例子,使用read()/write()與i2c設備通信:

1.       #include <stdio.h>

2.       #include <sys/ioctl.h>

3.       #include <fcntl.h>

4.       #include <linux/i2c-dev.h>

5.       #include <linux/i2c.h>

6.        

7.       #define CHIP "/dev/i2c-0"

#define CHIP_ADDR 0x50

8.        

9.        

10.      int main()

11.       

12.      {

13.          printf("this is i2c test/n");

14.          int fd =open(CHIP, O_RDWR);

15.          if (fd< 0) {

16.              printf("open"CHIP"failed/n");        

17.              gotoexit;

18.       

19.          }

20.          if (ioctl(fd, I2C_SLAVE_FORCE, CHIP_ADDR) < 0) { 

21.              /* 設置芯片地址 */

22.              printf("oictl:setslave address failed/n");

23.              goto close;

24.       

25.          }

26.          struct i2c_msg msg;    

27.          unsigned char rddata;

28.          unsigned char rdaddr[2] = {0, 0}; /* 將要讀取的數(shù)據(jù)在芯片中的偏移量 */

29.          unsigned char wrbuf[3] = {0, 0, 0x3c}; /* 要寫的數(shù)據(jù),頭兩字節(jié)為偏移量 */

30.          printf("inputa char you want to write to E2PROM/n");

31.          wrbuf[2]= getchar();

32.          printf("writereturn:%d, write data:%x/n", write(fd, wrbuf, 3), wrbuf[2]);

33.          sleep(1);

34.          printf("writeaddress return: %d/n",write(fd, rdaddr, 2)); /* 讀取之前首先設置讀取的偏移量 */

35.          printf("readdata return:%d/n", read(fd, &rddata, 1));

36.          printf("rddata:%c/n", rddata);

37.      close:

38.          close(fd);

39.      exit:  

40.          return0;

41.      }







2.3.2  I2C_RDWR

還可以使用I2C_RDWR實現(xiàn)同樣的功能,使用I2C_RDWR與I2C設備通信

1.     #include <stdio.h>

2.     #include <sys/ioctl.h>

3.     #include <fcntl.h>

4.     #include <linux/i2c-dev.h>

5.     #include <linux/i2c.h>

1.     #define CHIP "/dev/i2c-0"

2.     #define CHIP_ADDR 0x50

3.     int main()

4.     {

5.         printf("hello,this is i2c tester/n");

6.         int fd =open(CHIP, O_RDWR);

7.         if (fd< 0) {

8.             printf("open"CHIP"failed/n");

9.             gotoexit;

10.        }

11.        struct i2c_msg msg;

12.        unsigned char rddata;

13.        unsigned char rdaddr[2] = {0, 0}; 

14.        unsigned char wrbuf[3] = {0, 0, 0x3c};

15.        printf("inputa char you want to write to E2PROM/n");

16.        wrbuf[2]= getchar();

17.        struct i2c_rdwr_ioctl_data ioctl_data;

18.        struct i2c_msg msgs[2];

19.        msgs[0].addr= CHIP_ADDR;

20.        msgs[0].len= 3;

21.        msgs[0].buf= wrbuf;

22.        ioctl_data.nmsgs= 1;

23.        ioctl_data.msgs= &msgs[0];

24.        printf("ioctlwrite,return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data));

25.        sleep(1);

26.        msgs[0].addr= CHIP_ADDR;  

27.        msgs[0].len= 2;

28.        msgs[0].buf= rdaddr;

29.        msgs[1].addr= CHIP_ADDR;

30.        msgs[1].flags|= I2C_M_RD;

31.        msgs[1].len= 1;

32.        msgs[1].buf= &rddata;

33.        ioctl_data.nmsgs= 1;

34.        ioctl_data.msgs= msgs;

35.        printf("ioctlwrite address, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data));

36.        ioctl_data.msgs= &msgs[1];

37.        printf("ioctlread, return :%d/n", ioctl(fd, I2C_RDWR, &ioctl_data));

38.        printf("rddata:%c/n", rddata);

39.        close:

40.        close(fd);

41.     exit:

42.        return0;

43.          }







原文請參見:http://blog.chinaunix.net/uid-25445243-id-3862576.html