linux kernel version:4.4.38
硬件平台:exynos4412-tiny4412
参考链接:https://www.cnblogs.com/ethandlwang/p/14759735.html
基于之前按键点灯程序,我引入了中断下文tasklet机制。
在中断处理程序中处理对紧急事务,使用tasklet来处理触发中断后需要处理得事务中不紧急的事情
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 void my_task_handle(unsigned long data); 19 static struct gpio_desc *gpiod; 20 static DECLARE_TASKLET(my_task, my_task_handle, 0); 21 22 static void my_task_handle(unsigned long data) 23 { 24 printk(KERN_ALERT "my_task_handle data=%d\n", data); 25 return; 26 } 27 28 static ssize_t myled_status_show(struct device *dev, 29 struct device_attribute *attr, char *buf) 30 { 31 int level = gpiod_get_value(gpiod); 32 printk(KERN_ALERT "%s %d level=%d\n", __FUNCTION__, __LINE__, level); 33 return 0; 34 35 } 36 37 static ssize_t myled_status_store(struct device *dev, 38 struct device_attribute *attr, 39 const char *buf, size_t len) 40 { 41 printk(KERN_ALERT "%s %d buf=%s len=%d\n", __FUNCTION__, __LINE__, buf, len); 42 int level = 1; 43 if(len >= 2){ 44 if(buf[0] == ‘0‘){ 45 level = 0; 46 } 47 } 48 gpiod_set_value(gpiod, level); 49 return len; 50 } 51 52 static DEVICE_ATTR_RW(myled_status); 53 54 static struct attribute* myled_status_attrs[] = { 55 &dev_attr_myled_status.attr, 56 NULL 57 }; 58 59 static const struct attribute_group myled_group = { 60 .attrs = myled_status_attrs, 61 }; 62 63 static irqreturn_t my_irq(int irqno, void *dev_id) 64 { 65 int level = gpiod_get_value(gpiod); 66 tasklet_schedule(&my_task); 67 printk(KERN_ALERT "%s %d irqno=%d level=%d\n", __FUNCTION__, __LINE__, irqno, level); 68 gpiod_set_value(gpiod, !level); 69 return IRQ_HANDLED; 70 } 71 72 static int hello_probe(struct platform_device *pdev) 73 { 74 int error = 0; 75 unsigned int irq; 76 int ret; 77 struct device_node* np = pdev->dev.of_node; 78 79 if(np == NULL){ 80 printk(KERN_ALERT "%s %d of_node is NULL\n", __FUNCTION__, __LINE__); 81 goto NO_DEV_OF_NODE; 82 } 83 84 85 irq = platform_get_irq(pdev, 0); 86 if(irq < 0){ 87 printk(KERN_ALERT "platform_get_irq fail!!! irq = %d\n", irq); 88 goto PLATFORM_GET_IRQ_FAIL; 89 } 90 91 ret = devm_request_irq(&pdev->dev, irq, my_irq, 0, dev_name(&pdev->dev), NULL); 92 if(ret){ 93 printk(KERN_ALERT "devm_request_irq fail!!! ret = %d\n", ret); 94 goto REQUEST_IRQ_FAIL; 95 } 96 97 gpiod = devm_gpiod_get_optional(&pdev->dev, "key1", GPIOD_OUT_LOW); 98 if(gpiod == NULL){ 99 printk(KERN_ALERT "devm_gpiod_get_optional fail!!!\n"); 100 goto GPIOD_GET_FAIL; 101 } 102 103 ret = sysfs_create_group(&pdev->dev.kobj, &myled_group); 104 if(ret){ 105 printk(KERN_ALERT "sysfs_create_group fail!!! ret=%d\n", ret); 106 goto SYS_CREATE_GTOUP_FAIL; 107 } 108 109 NO_DEV_OF_NODE: 110 PLATFORM_GET_IRQ_FAIL: 111 REQUEST_IRQ_FAIL: 112 GPIOD_GET_FAIL: 113 SYS_CREATE_GTOUP_FAIL: 114 tasklet_kill(&my_task); 115 116 printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__); 117 return error; 118 } 119 120 static int hello_remove(struct platform_device *pdev) 121 { 122 sysfs_remove_group(&pdev->dev.kobj,&myled_group); 123 tasklet_kill(&my_task); 124 printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__); 125 return 0; 126 127 } 128 129 static void hello_shutdown(struct platform_device *pdev) 130 { 131 printk(KERN_ALERT "%s %d success===\n", __FUNCTION__, __LINE__); 132 } 133 134 static struct of_device_id of_platform_hello_match[] = { 135 { .compatible = "interrupt-keys",}, 136 { }, 137 }; 138 MODULE_DEVICE_TABLE(of, of_platform_hello_match); 139 140 static struct platform_driver platform_hello_driver = { 141 .probe = hello_probe, 142 .remove = hello_remove, 143 .shutdown = hello_shutdown, 144 .driver = { 145 .name = "my_keys", 146 //.owner = THIS_MODULE, 147 .of_match_table = of_platform_hello_match, 148 }, 149 }; 150 151 module_platform_driver(platform_hello_driver); 152 MODULE_AUTHOR("EthanDL"); 153 MODULE_DESCRIPTION("platform hello"); 154 MODULE_LICENSE("GPL");
20行:以静态的方式申请和初始化tasklet,my_task_handle为处理函数,0为my_task_handle参数
66行:在中断处理函数中调用tasklet_schedule,在触发中断后调用,在中断处理函数执行完毕后的一个很小的时间间隔,执行my_task_handle,使中断处理函数迅速返回。my_task_handle随后参与调度被cpu执行。
123行:在确定不使用tasklet时,将其注销。
实验结果:
在按下按键后,触发中断,执行中断处理函数,67行被先打印,虽然tasklet_schedule先被调用,但是my_task_handle中的打印会在最后打印,这就是中断下文的效果。
原文:https://www.cnblogs.com/ethandlwang/p/14767801.html