给驱动添加sysfs设备模型(基于中断的按键程序)

linux kernel version:4.4.38

硬件平台:exynos4412-tiny4412

参考链接:https://www.cnblogs.com/ethandlwang/p/14759735.html

基于上一篇按键点灯程序,我给设备驱动添加了sysfs设备模型,demo级程序

添加了myled_status文件在用户空间获取灯的状态~

  1 #include <linux/err.h>
  2 #include <linux/gpio.h>
  3 #include <linux/fs.h>
  4 #include <linux/gpio/consumer.h>
  5 #include <linux/kernel.h>
  6 #include <linux/leds.h>
  7 #include <linux/module.h>
  8 #include <linux/of.h>
  9 #include <linux/of_gpio.h>
 10 #include <linux/of_irq.h>
 11 #include <linux/platform_device.h>
 12 #include <linux/property.h>
 13 #include <linux/slab.h>
 14 #include <linux/workqueue.h>
 15 #include <linux/interrupt.h>
 16 #include <linux/acpi.h>
 17 
 18 static struct gpio_desc    *gpiod;
 19 
 20 static ssize_t myled_status_show(struct device *dev,
 21                      struct device_attribute *attr, char *buf)
 22 {
 23     int level = gpiod_get_value(gpiod);
 24     printk(KERN_ALERT "%s %d level=%d\n", __FUNCTION__, __LINE__, level);
 25     return 0;
 26 
 27 }
 28 
 29 static ssize_t myled_status_store(struct device *dev,
 30                    struct device_attribute *attr,
 31                    const char *buf, size_t len)
 32 {
 33     printk(KERN_ALERT "%s %d buf=%s len=%d\n", __FUNCTION__, __LINE__, buf, len);
 34     int level = 1;
 35 
 36     if(len >= 2){
 37         if(buf[0] == '0'){
 38             level = 0;
 39         } 
 40     }
 41     gpiod_set_value(gpiod, level);
 42     return len;
 43 }
 44 
 45 static DEVICE_ATTR_RW(myled_status);
 46 
 47 static struct attribute* myled_status_attrs[] = {
 48     &dev_attr_myled_status.attr,
 49     NULL
 50 };
 51 
 52 static const struct attribute_group myled_group = {
 53     .attrs        = myled_status_attrs,
 54 };
 55 
 56 static irqreturn_t my_irq(int irqno, void *dev_id)
 57 {
 58     int level = gpiod_get_value(gpiod);
 59     printk(KERN_ALERT "%s %d irqno=%d level=%d\n", __FUNCTION__, __LINE__, irqno, level);
 60     gpiod_set_value(gpiod, !level);
 61     return IRQ_HANDLED;
 62 }
 63 
 64 static int hello_probe(struct platform_device *pdev)
 65 {
 66     int error = 0;
 67     struct fwnode_handle *fwhandle;
 68     const char *str;
 69     u32 val[3];
 70     u32 interrupts_val[2];
 71     unsigned int irq;
 72     int ret;
 73 
 74     struct device_node* np = pdev->dev.of_node;
 75     if(np == NULL)
 76     {
 77         printk(KERN_ALERT "%s %d of_node is NULL\n", __FUNCTION__, __LINE__);
 78         return 0;
 79     }
 80 
 81 
 82     irq = platform_get_irq(pdev, 0);
 83     printk(KERN_ALERT "%s %d irq = %d\n", __FUNCTION__, __LINE__, irq);
 84     ret = devm_request_irq(&pdev->dev, irq, my_irq, 0, dev_name(&pdev->dev), NULL);
 85     printk(KERN_ALERT "%s %d ret = %d\n", __FUNCTION__, __LINE__, ret);
 86 
 87     gpiod = devm_gpiod_get_optional(&pdev->dev, "key1", GPIOD_OUT_LOW);
 88     if(gpiod == NULL){
 89         printk(KERN_ALERT "%s %d devm_gpiod_get_optional fail!!!\n", __FUNCTION__, __LINE__);
 90     }
 91  
 92     ret = sysfs_create_group(&pdev->dev.kobj, &myled_group);
 93     if(ret)
 94     {
 95         printk(KERN_ALERT "%s %d sysfs_create_group fail!!!\n", __FUNCTION__, __LINE__);
 96         return 1;
 97     }
 98 
 99     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
100     return error;
101 }
102 
103 static int hello_remove(struct platform_device *pdev)
104 {
105     sysfs_remove_group(&pdev->dev.kobj,&myled_group);
106 
107     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
108 
109     return 0;
110 
111 }
112 
113 static void hello_shutdown(struct platform_device *pdev)
114 {
115     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
116 
117 }
118 
119 static struct of_device_id of_platform_hello_match[] = {
120     { .compatible = "interrupt-keys",},
121     { },
122 };
123 MODULE_DEVICE_TABLE(of, of_platform_hello_match);
124 
125 static struct platform_driver platform_hello_driver = {
126     .probe        = hello_probe,
127     .remove        = hello_remove,
128     .shutdown    = hello_shutdown,
129     .driver        = {
130         .name    = "my_keys",
131         //.owner  = THIS_MODULE,
132         .of_match_table = of_platform_hello_match,
133     },
134 };
135 
136 module_platform_driver(platform_hello_driver);
137 
138 MODULE_AUTHOR("EthanDL");
139 MODULE_DESCRIPTION("platform hello");
140 MODULE_LICENSE("GPL");

92行:向sysfs添加myled_status文件,所在目录/sys/devices/platform/my_keys/,因为my_keys是platform device,所以my_keys就会在/sys/devices/platform/下,sysfs_create_group的第一个参数kobj对应的正好是my_keys,所以myled_status是在my_keys下

20&29行:myled_status_show和myled_status_store,对应myled_status的读写,实现查看和控制led的亮灭~

上一篇:Selinux 快速上手


下一篇:第四十六讲 设备驱动kobject