一、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. }
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ù)如下示: 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. }
memdup_user函數(shù)完成分配存儲區(qū),把應用層的數(shù)據(jù)復制到剛分配的存儲區(qū)中,具體程序如下: 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ù)等。具體程序如下: 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。
1. ioctl(fd, I2C_TIMEOUT, m); //設置SMBus的超時時間為m,單位為jiffies。
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列表,所以不能防止其它線程使用同一地址,也不能防止驅動模塊占用同一地址。 這一行代碼可以使用I2C協(xié)議和設備進行通信。它進行連續(xù)的讀寫,中間沒有間歇。只有當適配器支持I2C_FUNC_I2C此命令才有效。參數(shù)是一個指針,指向一個結構體,它的定義如: msgs[] 數(shù)組成員包含了指向各自緩沖區(qū)的指針。這個函數(shù)會根據(jù)是否在消息中的flags置位I2C_M_RD來對緩沖區(qū)進行讀寫。從機的地址以及是否使用10比特地址模式記錄在每個消息中,忽略之前ioctl設置的結果。 如果select不等于0選擇SMBus PEC (packet error checking),等于零則關閉這個功能,默認是關閉的。 這個命令只對SMBus傳輸有效。這個請求只在適配器支持I2C_FUNC_SMBUS_PEC時有效;如果不支持這個命令也是安全的,它不做任何工作。 這個函數(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 | ||||