i2c 驱动四:sysfs文件系统

来源:互联网 发布:单片机系统可靠性 编辑:程序博客网 时间:2024/06/08 08:36


1. 用 sysfs 实现 i2c,其实质是将 i2c 和 sysfs 结合起来,那首先来看看什么是 sysfs:

【1】sysfs简介:sysfs 是基于内存的虚拟的文件系统,他的作用于 proc 相似,他的设计是吸取的 proc 中的很多教训,使之导出内核或其他的数据的方式更为统一

【2】此部分,有一个博客写的很好,在这里,暂时不做整理,直接点击跳转

【3】借助于 sysfs ,我们可以把要呈现的参数/数据以文件夹的形式呈现给用户,最直接的好处是你能够用命令行来读(cat)写(echo)参数/数据

【4】对sysfs中的函数,有一篇文章写的很好,直接点击跳转


2. 说的再多,不如一个例子:

由于手头上有个 mpu6050,所以,就以mpu6050为例,采用的传感器的小板子是 GY-521

目录结构:

.
├── dev
│   ├── Makefile
│   └── mpu6050_dev.c
└── dri
    ├── Makefile
    └── mpu6050_dri.c


mpu6050_dev.c 

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/i2c.h>  
  4. #include <linux/delay.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. static struct i2c_client *mpu6050_clientp;  
  9.   
  10. static struct i2c_board_info mpu6050_i2c_devs = {  
  11.         .type = "mpu6050",  
  12.         .addr = 0x68,  
  13.         /*I2C_BOARD_INFO("mpu6050", 0x50), //这个宏是上边两个变量赋值的替换*/  
  14. };  
  15.   
  16. static int mpu6050_dev_init(void)  
  17. {  
  18.     struct i2c_adapter *i2c_adap;    //分配一个适配器的指针  
  19.   
  20.     printk("mpu6050_dev_init.\n");  
  21.   
  22.     i2c_adap = i2c_get_adapter(0);   //0 是 i2c 总线编号  
  23.   
  24.     mpu6050_clientp = i2c_new_device(i2c_adap, &mpu6050_i2c_devs); //只能添加一个  
  25.     if (!mpu6050_clientp)  
  26.         printk("register i2c error!\n");  
  27.   
  28.     i2c_put_adapter(i2c_adap);       //释放 adapter  
  29.   
  30.     return 0;  
  31. }  
  32.   
  33. static void mpu6050_dev_exit(void)  
  34. {  
  35.     printk("mpu6050_dev_exit.\n");  
  36.     i2c_unregister_device(mpu6050_clientp);  
  37. }  
  38.   
  39. module_init(mpu6050_dev_init);  
  40. module_exit(mpu6050_dev_exit);  

Makefile

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. ifeq ($(KERNELRELEASE),)  
  2.   
  3. #KERNELDIR ?= /lib/modules/$(shell uname -r)/build   
  4. KERNELDIR ?= ~/wor_lip/linux-3.4.112  
  5. PWD := $(shell pwd)  
  6.   
  7. modules:  
  8.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules  
  9.   
  10. modules_install:  
  11.     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install  
  12.   
  13. clean:  
  14.     rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions modules* Module*  
  15.   
  16. .PHONY: modules modules_install clean  
  17.   
  18. else  
  19.     obj-m := mpu6050_dev.o  
  20. endif  

mpu6050_dri.c

[cpp] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/i2c.h>  
  4. #include <linux/delay.h>  
  5.   
  6. MODULE_LICENSE("GPL");  
  7.   
  8. #define SMPLRT_DIV      0x19  
  9. #define CONFIG          0x1A  
  10. #define GYRO_CONFIG     0x1B  
  11. #define ACCEL_CONFIG    0x1C  
  12. #define ACCEL_XOUT_H    0x3B  
  13. #define ACCEL_XOUT_L    0x3C  
  14. #define ACCEL_YOUT_H    0x3D  
  15. #define ACCEL_YOUT_L    0x3E  
  16. #define ACCEL_ZOUT_H    0x3F  
  17. #define ACCEL_ZOUT_L    0x40  
  18. #define TEMP_OUT_H      0x41  
  19. #define TEMP_OUT_L      0x42  
  20. #define GYRO_XOUT_H     0x43  
  21. #define GYRO_XOUT_L     0x44  
  22. #define GYRO_YOUT_H     0x45  
  23. #define GYRO_YOUT_L     0x46  
  24. #define GYRO_ZOUT_H     0x47  
  25. #define GYRO_ZOUT_L     0x48  
  26. #define PWR_MGMT_1      0x6B  
  27.   
  28. static struct kobject *example_kobj;  
  29. struct i2c_client *glb_client;  
  30.   
  31. static int mpu6050_read_byte(struct i2c_client *client, unsigned char reg)  
  32. {  
  33.     int ret;  
  34.   
  35.     char txbuf[1] = { reg  };  
  36.     char rxbuf[1];  
  37.   
  38.     struct i2c_msg msg[] = {  
  39.         {client->addr, 0, 1, txbuf},  
  40.         {client->addr, I2C_M_RD, 1, rxbuf}  
  41.   
  42.     };  
  43.   
  44.     ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  45.     if (ret < 0) {  
  46.         printk("ret = %d\n", ret);  
  47.         return ret;  
  48.   
  49.     }  
  50.   
  51.     return rxbuf[0];  
  52. }  
  53.   
  54. static int mpu6050_write_byte(struct i2c_client *client, unsigned char reg, unsigned char val)  
  55. {  
  56.     char txbuf[2] = {reg, val};  
  57.   
  58.     struct i2c_msg msg[] = {  
  59.         {client->addr, 0, 2, txbuf},  
  60.   
  61.     };  
  62.   
  63.     i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));  
  64.   
  65.     return 0;  
  66. }  
  67.   
  68. /* 读/sys/kernel/mpu6050_i2c文件下的文件时调用 */  
  69. static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,  
  70.         char *buf) /* buf是返回给用户空间的值 */  
  71. {  
  72.     unsigned short accel_x = 0, accel_y = 0, accel_z = 0;    
  73.     unsigned short gyro_x = 0, gyro_y = 0, gyro_z = 0;    
  74.     unsigned short temp = 0;    
  75.   
  76.     mpu6050_write_byte(glb_client, PWR_MGMT_1, 0x00);  
  77.     mpu6050_write_byte(glb_client, SMPLRT_DIV, 0x07);  
  78.     mpu6050_write_byte(glb_client, CONFIG, 0x06);  
  79.     mpu6050_write_byte(glb_client, GYRO_CONFIG, 0x18);  
  80.     mpu6050_write_byte(glb_client, ACCEL_CONFIG, 0x01);  
  81.     mdelay(10);  
  82.   
  83.     accel_x = mpu6050_read_byte(glb_client, ACCEL_XOUT_L);  
  84.     accel_x |= mpu6050_read_byte(glb_client, ACCEL_XOUT_H) << 8;  
  85.   
  86.     accel_y =  mpu6050_read_byte(glb_client, ACCEL_YOUT_L);  
  87.     accel_y |= mpu6050_read_byte(glb_client, ACCEL_YOUT_H) << 8;  
  88.   
  89.     accel_z = mpu6050_read_byte(glb_client, ACCEL_ZOUT_L);  
  90.     accel_z |= mpu6050_read_byte(glb_client, ACCEL_ZOUT_H) << 8;  
  91.   
  92.     printk("acceleration data: x = %04x, y = %04x, z = %04x\n", accel_x, accel_y, accel_z);  
  93.   
  94.     gyro_x = mpu6050_read_byte(glb_client, GYRO_XOUT_L);  
  95.     gyro_x |= mpu6050_read_byte(glb_client, GYRO_XOUT_H) << 8;  
  96.   
  97.     gyro_y = mpu6050_read_byte(glb_client, GYRO_YOUT_L);  
  98.     gyro_y |= mpu6050_read_byte(glb_client, GYRO_YOUT_H) << 8;  
  99.   
  100.     gyro_z = mpu6050_read_byte(glb_client, GYRO_ZOUT_L);  
  101.     gyro_z |= mpu6050_read_byte(glb_client, GYRO_ZOUT_H) << 8;  
  102.   
  103.     printk("gyroscope data: x = %04x, y = %04x, z = %04x\n", gyro_x, gyro_y, gyro_z);   
  104.   
  105.     temp = mpu6050_read_byte(glb_client, TEMP_OUT_L);   
  106.     temp |= mpu6050_read_byte(glb_client, TEMP_OUT_H) << 8;   
  107.   
  108.     printk("temperature data: %x\n", temp);  
  109.   
  110.   
  111.     return sprintf(buf, "%x\n", temp);  
  112. }  
  113.   
  114. /* 写/sys/kernel/mpu6050_i2c文件下的文件时调用 */  
  115. static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,  
  116.         const char *buf, size_t count)  
  117. {  
  118.     return 0;  
  119. }  
  120.   
  121. static struct kobj_attribute foo_attribute =  
  122. __ATTR(mpu6050_accelerationd, 0666, foo_show, foo_store);  
  123. /* (文件名, 文件权限, 读这个文件时调用的函数, 写文件时调用时的函数) 
  124.  * 在/sys/kernel/mpu6050_i2c/下的文件 
  125.  */  
  126.   
  127. static struct kobj_attribute foo_attribute2 =  
  128. __ATTR(mpu6050_gyroscope, 0666, foo_show, foo_store);  
  129.   
  130. static struct kobj_attribute foo_attribute3 =  
  131. __ATTR(mpu6050_temperature, 0666, foo_show, foo_store);  
  132.   
  133. /* 
  134.  * 创建一个属性组,方便我们一次性的创建和删除 
  135.  */  
  136. static struct attribute *attrs[] = {  
  137.     &foo_attribute.attr,  
  138.     &foo_attribute2.attr,  
  139.     &foo_attribute3.attr,  
  140.     NULL,  /* 需要用NULL来表示属性列表的结束 */  
  141.   
  142. };  
  143.   
  144. /* 
  145.  * An unnamed attribute group will put all of the attributes directly in 
  146.  * the kobject directory.  If we specify a name, a subdirectory will be 
  147.  * created for the attributes with the directory being the name of the 
  148.  * attribute group. 
  149.  */  
  150. static struct attribute_group attr_group = {  
  151.     .attrs = attrs,  
  152.   
  153. };  
  154.   
  155.   
  156. static int mpu6050_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  157. {  
  158.     int retval;  
  159.     glb_client = client;  
  160.   
  161.     /* 
  162.      * 创建目录 /sys/kernel/mpu6050_i2c 
  163.      */  
  164.     example_kobj = kobject_create_and_add("mpu6050_i2c", kernel_kobj); /* (kernel_kobj这个父文件夹下的叫mpu6050_i2c的文件夹) */  
  165.     if (!example_kobj)  
  166.         return -ENOMEM;  
  167.   
  168.     /* Create the files associated with this kobject */  
  169.     retval = sysfs_create_group(example_kobj, &attr_group);  
  170.     if (retval)  
  171.         kobject_put(example_kobj);  
  172.   
  173.     return 0;  
  174. }  
  175.   
  176. static int mpu6050_remove(struct i2c_client *client)  
  177. {  
  178.     /*struct bin_attribute *binp;*/  
  179.   
  180.     /*binp = i2c_get_clientdata(client);*/  
  181.   
  182.     /*sysfs_remove_bin_file(&client->dev.kobj, binp);*/  
  183.   
  184.     kobject_put(example_kobj);  
  185.   
  186.     printk("driver removed.\n");  
  187.   
  188.     return 0;  
  189. }  
  190.   
  191. static const struct i2c_device_id mpu6050_id[] = {  
  192.     { "mpu6050", 0 },  
  193. };   
  194.   
  195. /*MODULE_DEVICE_TABLE(i2c, mpu6050_id);*/  
  196.   
  197. static struct i2c_driver mpu6050_driver = {  
  198.     .driver = {  
  199.         .name           = "xx",    //供模块匹配用  
  200.         .owner          = THIS_MODULE,  
  201.     },  
  202.     .probe      = mpu6050_probe,  
  203.     .remove     = mpu6050_remove,  
  204.     .id_table   = mpu6050_id,     /* 用于I2C driver的probe函数调用 */  
  205. };  
  206.   
  207. /*i2c_add_driver();*/  
  208.   
  209. module_i2c_driver(mpu6050_driver);//简单方式,内核中是个宏,完成了模块的初始化和卸载  

【1】当设备 和 驱动 匹配成功后,会在 /sys/kernel/ 下创建一个mpu6050_i2c 目录,里边有3个文件,如下图


【2】读传感器的值


【3】很明显,程序中3个参数以文件夹的方式呈现给了用户,用户可以像操作文件的形式读写相应文件,在本程序中,我偷了个懒,读这3个参数执行了相同的函数,没有实现写的函数

【4】可以想到的是,程序中可以实现不同的读函数,实现单独的参数读取

0 0
原创粉丝点击