中断上下文之work queue

linux kernel version:4.4.38

硬件平台:exynos4412-tiny4412

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

基于之前按键点灯程序,我引入了中断下文workqueue机制。

在中断处理程序中处理对紧急事务,使用workqueue来处理触发中断后需要处理得事务中不紧急的事情

  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 struct my_keys_priv {
 19     struct work_struct my_keys_work;
 20     int num;
 21 };
 22 
 23 static struct gpio_desc    *gpiod;
 24 
 25 static ssize_t myled_status_show(struct device *dev,
 26                      struct device_attribute *attr, char *buf)
 27 {
 28     int level = gpiod_get_value(gpiod);
 29     printk(KERN_ALERT "%s %d level=%d\n", __FUNCTION__, __LINE__, level);
 30     return 0;
 31 
 32 }
 33 
 34 static ssize_t myled_status_store(struct device *dev,
 35                    struct device_attribute *attr,
 36                    const char *buf, size_t len)
 37 {
 38     printk(KERN_ALERT "%s %d buf=%s len=%d\n", __FUNCTION__, __LINE__, buf, len);
 39     int level = 1;
 40     if(len >= 2){
 41         if(buf[0] == '0'){
 42             level = 0;
 43         } 
 44     }
 45     gpiod_set_value(gpiod, level);
 46     return len;
 47 }
 48 
 49 static DEVICE_ATTR_RW(myled_status);
 50 
 51 static struct attribute* myled_status_attrs[] = {
 52     &dev_attr_myled_status.attr,
 53     NULL
 54 };
 55 
 56 static const struct attribute_group myled_group = {
 57     .attrs        = myled_status_attrs,
 58 };
 59 
 60 static irqreturn_t my_irq(int irqno, void *dev_id)
 61 {
 62     int level = gpiod_get_value(gpiod);
 63     struct my_keys_priv *priv = dev_id;
 64 
 65     schedule_work(&priv->my_keys_work);
 66     printk(KERN_ALERT "%s %d irqno=%d level=%d\n", __FUNCTION__, __LINE__, irqno, level);
 67     gpiod_set_value(gpiod, !level);
 68     return IRQ_HANDLED;
 69 }
 70 
 71 static void my_key_work_handler(struct work_struct *work)
 72 {
 73 
 74     struct my_keys_priv *priv = container_of(work, struct my_keys_priv, my_keys_work);
 75     printk(KERN_ALERT "my_key_work_handler done. num=%d\n", priv->num);
 76     return;
 77 }
 78 
 79 
 80 static int hello_probe(struct platform_device *pdev)
 81 {
 82     int error = 0;
 83     unsigned int irq;
 84     int ret;
 85     struct device_node* np = pdev->dev.of_node;
 86 
 87     struct my_keys_priv *priv = NULL;
 88 
 89 
 90     priv = devm_kzalloc(&pdev->dev, sizeof(struct my_keys_priv), GFP_KERNEL);
 91     if (!priv){
 92         printk(KERN_ALERT "%s %d devm_kzalloc fail\n", __FUNCTION__, __LINE__);
 93         return -ENOMEM;
 94     }
 95 
 96     priv->num = 100;
 97 
 98     INIT_WORK(&priv->my_keys_work, my_key_work_handler);
 99     platform_set_drvdata(pdev, priv);
100 
101 
102     if(np == NULL){
103         printk(KERN_ALERT "%s %d of_node is NULL\n", __FUNCTION__, __LINE__);
104         goto NO_DEV_OF_NODE;
105     }
106 
107 
108     irq = platform_get_irq(pdev, 0);
109     if(irq < 0){
110         printk(KERN_ALERT "platform_get_irq fail!!! irq = %d\n", irq);
111         goto PLATFORM_GET_IRQ_FAIL;
112     }
113     
114     ret = devm_request_irq(&pdev->dev, irq, my_irq, 0, dev_name(&pdev->dev), priv);
115     if(ret){
116         printk(KERN_ALERT "devm_request_irq fail!!! ret = %d\n", ret);
117         goto REQUEST_IRQ_FAIL;
118     }
119     
120     gpiod = devm_gpiod_get_optional(&pdev->dev, "key1", GPIOD_OUT_LOW);
121     if(gpiod == NULL){
122         printk(KERN_ALERT "devm_gpiod_get_optional fail!!!\n");
123         goto GPIOD_GET_FAIL;
124     }
125  
126     ret = sysfs_create_group(&pdev->dev.kobj, &myled_group);
127     if(ret){
128         printk(KERN_ALERT "sysfs_create_group fail!!! ret=%d\n", ret);
129         goto SYS_CREATE_GTOUP_FAIL;
130     }
131 
132 NO_DEV_OF_NODE:
133 PLATFORM_GET_IRQ_FAIL:
134 REQUEST_IRQ_FAIL:
135 GPIOD_GET_FAIL:
136 SYS_CREATE_GTOUP_FAIL:
137     ;
138 
139     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
140     return error;
141 }
142 
143 static int hello_remove(struct platform_device *pdev)
144 {
145     sysfs_remove_group(&pdev->dev.kobj,&myled_group);
146     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
147     return 0;
148 
149 }
150 
151 static void hello_shutdown(struct platform_device *pdev)
152 {
153     printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__);
154 }
155 
156 static struct of_device_id of_platform_hello_match[] = {
157     { .compatible = "interrupt-keys",},
158     { },
159 };
160 MODULE_DEVICE_TABLE(of, of_platform_hello_match);
161 
162 static struct platform_driver platform_hello_driver = {
163     .probe        = hello_probe,
164     .remove        = hello_remove,
165     .shutdown    = hello_shutdown,
166     .driver        = {
167         .name    = "my_keys",
168         //.owner  = THIS_MODULE,
169         .of_match_table = of_platform_hello_match,
170     },
171 };
172 
173 module_platform_driver(platform_hello_driver);
174 MODULE_AUTHOR("EthanDL");
175 MODULE_DESCRIPTION("platform hello");
176 MODULE_LICENSE("GPL");

18行:定义了一个包含 work_struct 的私有数据结构

90行:为18行的数据结构申请内存,并初始化num

98行:对work queue进行初始化,确认了work被触发以后执行 my_key_work_handler

114行:注册了中断,中断发生时my_irq会被触发

65行:按下按键就会触发中断,schedule_work被执行,对应的work被激活执行

74行:使用container_of获取包含work的结构体指针priv,就可以得到num的值,操作它。

按下按键后打印如下:

可以看到先执行schedule_work,但是还是先打印中断处理函数中的printk,schedule_work激活work,但是会延迟执行

 

posted @ 2021-06-04 09:58  王东力  阅读(177)  评论(0)    收藏  举报