中断上下文之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,但是会延迟执行

浙公网安备 33010602011771号