本文部分参考华清远见文档

中断上半部要求执行时间间隔段,所以往往将处理时间较长的代码放在中断下半部来处理

中断下半部的应用:网卡驱动上半部初始化网卡驱动等短时间的事件,下半部收发数据

中断下半部:

    a, 下半部产生的原因:

        1,中断上下文中不能阻塞,这也限制了中断上下文中能干的事

        2,中断处理函数执行过程中仍有可能被其他中断打断,都希望中断处理函数执行得越快越好

        基于上面的原因,内核将整个的中断处理流程分为了上半部和下半部。上半部就是之前所说的中断处理函数,它能最快的响应中断,并且做一些必须在中断响应之后马上要做的事情。而一些需要在中断处理函数后继续执行的操作,内核建议把它放在下半部执行。

比如:在linux内核中,当网卡一旦接受到数据,网卡会通过中断告诉内核处理数据,内核会在网卡中断处理函数(上半部)执行一些网卡硬件的必要设置,因为这是在中断响应后急切要干的事情。接着,内核调用对应的下半部函数来处理网卡接收到的数据,因为数据处理没必要在中断处理函数里面马上执行,可以将中断让出来做更紧迫的事情

    b,中断下半部实现的机制分类

    tasklet:          

    workqueue:工作队列

    timer:定时器

其实还有一种,叫softirq,但要写代码的话,就必须修改原来的内核框架代码,在实际开发中用的比较少,tasklet内部实现就是用softeirq

c, 中断下半部实现方法

    1, tasklet的编程方式

         1.1 : 定义并初始化结构体tasklet_struct(一般在哪里初始化:是在模块卸载方法中)

              struct tasklet_struct

{

struct tasklet_struct *next; // l链表

unsigned long state;

atomic_t count;

void (*func)(unsigned long); // 下半部处理方法的实现

unsigned long data;//给处理函数的传参

};

           初始化方式:

           静态:DECLARE_TASKLET(name, func, data);

              DCLARE_TASKLET_DISABLED初始化后的处于禁止状态,暂时不能被使用(不是中断),除非被激活           

参数1:tasklet_struct 的变量名字,自定义

参数2:中断下半部执行的处理函数.类型为函数指针

参数3:处理函数带的参数

            动态:void tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data);

         参数1:tasklet_struct 对象

         参数2:中断下半部执行的处理函数

         参数3:处理函数带的参数

   1.2: 在中断上半部中调度下半部

        void tasklet_schedule(struct tasklet_struct * t);

   1.3: 在模块卸载时,销毁这个tasklet_struct 对象

        void tasklet_kill(struct tasklet_struct *t) 

   1.4:原理:初始化好struct tasklet_struct对象后,tasklet_schedule()会将tasklet对象加到链表中,内核稍后会去调度这个tasklet对象

   1.5: 特点:优先级高,调度快,运行在中断上下文中,所以在处理方法中,不能执行阻塞/睡眠的操作

            

       2,workqueque编程方式:

            2.1 :定义并初始化workqueue_struct(一个队列)和work_struct(队列中的一项工作)对象

                  work_struct对象的初始化

                  struct work_struct {

atomic_long_t data;  // 传递给work的参数

struct list_head entry; // 所在队列的链表

work_func_t func; // work对应的处理方法

};

静态:DECLARE_WORK(n, f)

     参数1: 变量名,自定义

     参数2:work对应的处理方法,类型为函数指针     

动态:INIT_WORK(_work, _func)

    参数1: 指针,先声明一个struct work_struct变量,将变量地址填入

    参数2:work对应的处理方法,类型为函数指针 

    返回值: 返回值为void   

                workqueue_struct对象的初始化:(其实就是一个内核线程)

                 1, 重新创建一个队列

                     create_workqueue(name)//这个本身就是一个宏

                      参数:名字,自定义,用于识别

返回值:struct workqueue_struct *                    

                 2, 系统在开机的时候自动创建一个队列  

           2.2  将工作对象加入工作队列中,并参与调度(注意不是马上调度,该步骤也是中断上半部中调用)

               int queue_work(struct workqueue_struct *wq, struct work_struct *work)

               参数1:工作队列

参数2: 工作对象

               返回值: 0表示已经放到队列上了(也即时说本次属于重复操作),其实一般我们都不会去做出错处理


           2.3  在模块注销的时候,销毁工作队列和工作对象

                  void flush_workqueue(struct workqueue_struct * wq)

                 该函数会一直等待,知道指定的等待队列中所有的任务都执行完毕并从等待队列中移除。

                 void destroy_workqueue(struct workqueue_struct * wq);

                该函数是是创建等待队列的反操作,注销掉指定的等待队列。


           2.4: 对于使用内核自带的工作队列events, 操作步骤如下:

                 2.4.1 初始化工作对象,无需创建队列了

                       静态:DECLARE_WORK(n, f)   

                       动态:INIT_WORK(_work, _func)

                 2.4.2将工作加入队列并调度(在中断上半部中调度)

                        int schedule_work(struct work_struct * work)

              只要两步骤就完成,也不需要刷新,也不要销毁,因为这个工作队列是系统管理的,我们不用管

           2.5:原理梳理:在工作队列中,有专门的工作者线程来处理加入到工作对列中的任务。工作对列对应的工作者线程可能不止一个,每个处理器有且仅有一个工作队列 对应的工作者线程,在内核中有一个默认的工作队列events,对于单处理器只有一个对应的工作者线程

                                      

      3, 定时器timer编程方式:(以上两个下半部处理都是内核在一个特定的时候进行调度,时间不定,而timer可以指定某个时间点执行)

            3.1, jiffies,表示从系统启动到当前的时间值,一般做加法(+5HZ(5s),)

            3.2, 定义并初始化 timer_list对象

                  struct timer_list {

struct list_head entry;  // 链表

unsigned long expires; // 过期时间。也及时在什么时候执行处理方法

struct tvec_base *base; 

void (*function)(unsigned long); // 处理方法

unsigned long data; // 处理方法可以传递的参数

int slack;

};

 静态初始化:TIMER_INITIALIZER(_function, _expires, _data)

   

 动态初始化:void init_timer(timer)

       参数:为一个指针,需要传递一个struct timer_list对象的地址

       该函数只是初始化了timer_list对象的部分成员,还有以下成员是需要编程的:

       struct timer_list mytimer;

       init_timer(&mytimer);

       mytimer.expires = jiffies + 2HZ

       mytimer.fuction = my_timer_func;  // 自己去实现

       mytimer.data = (unsigned long)99;  // 可以传递参数


                    3.3, 激活timer,开始计时   (一般也是放在中断上半部完成)

                                       void add_timer(&mytimer);

                    3.4   计时结束是,也就是要执行处理函数时,执行函数中要下一次计时的话,必须修改timer

                                      mod_timer(&my_timer, jiffies + 2*HZ);  

                  // 2s之后再来,相当于如下:

                  my_timer.expires = jiffies + 2*HZ; //重新设定时间,在两秒后再执行

                   add_timer(&my_timer); //再次激活定时器

          3.5 定时器的销毁

                    int del_timer(struct timer_list *timer) // 该函数用来删除还没超时的定时器

    


timer定时器的中断上下半部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <linux/kernel.h> 
#include <linux/device.h> 
#include <linux/cdev.h> 
#include <linux/fs.h> 
#include <linux/err.h> 
#include <linux/irq.h> 
#include <linux/input.h> 
#include <linux/interrupt.h> 
#include <linux/timer.h> 
  
#include <asm-arm/param.h> 
#include <asm/arch/regs-gpio.h> 
#include <asm/gpio.h> 
#define VIRTUAL_MAJOR 250 
int  major = VIRTUAL_MAJOR; 
  
struct  myirq_desc{ 
     int  irq_id; 
     char  *irq_name; 
     int  irq_code; 
}; 
  
struct  myirq_desc myirq_descs[3]= { 
         {S3C2410_GPF0,  "s2" , KEY_A}, 
         {S3C2410_GPF2,  "s3" , KEY_K}, 
         {S3C2410_GPG3,  "s4" , KEY_Z}, 
}; 
struct  VirtualDisk{ 
     struct  class  *mycdevclass; //在/sys/class创建类 
     struct  class_device *mycdevclassdevice; //在/dev下创建设备 
     struct  cdev mycdev; //给设备添加相关的fileoption 
     struct  timer_list mytimer; 
}; 
struct  VirtualDisk *myvirtualdisk; 
  
static  struct  file_operations  mydev_fops = { 
     .owner = THIS_MODULE, 
}; 
static  void  mytimer_func(unsigned  long  fundata){ 
     printk( "*******%s********\n" , __FUNCTION__); 
     struct  VirtualDisk *myvirtualdisk_fun = ( struct  VirtualDisk *)(fundata); 
     myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ; 
     add_timer(&myvirtualdisk_fun->mytimer); 
     printk( "timer func happened!\n" ); 
static  irqreturn_t myirq_handle( int  irq,  void  *dev_id){ 
     struct  myirq_desc *myirq_descone = ( struct  myirq_desc *)dev_id; 
     printk( "*******%s********\n" , __FUNCTION__); 
     printk( "irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n" , irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code); 
     mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ); 
     return  IRQ_RETVAL(IRQ_HANDLED); 
  
static  int  __init cdevtest_init( void ){ 
     dev_t mydev = MKDEV(major, 0); 
     int  ret; 
     int  i = 0; 
     printk( "*******%s********\n" , __FUNCTION__); 
     if (major){ //注册proc/devices 
     ret = register_chrdev_region(mydev, 1,  "mynewdriver" ); 
     } else
     ret = alloc_chrdev_region(&mydev, 0, 1,  "mynewdriver" ); 
     major =  MAJOR(mydev); 
    
     if (ret < 0){ 
     printk(KERN_ERR  "register_chrdev_region failed!\n" ); 
     ret = -EINVAL; 
     return  ret; 
    
     myvirtualdisk = kmalloc( sizeof ( struct  VirtualDisk), GFP_KERNEL); 
     if (!myvirtualdisk){ 
     ret = -ENOMEM; 
     printk(KERN_ERR  "kmalloc myvirtualdisk failed!\n" ); 
     goto  release_chrdev; 
    
     myvirtualdisk->mycdevclass = class_create(THIS_MODULE,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclass)){ 
     ret =  PTR_ERR(myvirtualdisk->mycdevclass); 
     printk(KERN_ERR  "class_create failed!\n" ); 
     goto  release_mem_malloc; 
      
    
     myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclassdevice)){ 
         ret = PTR_ERR(myvirtualdisk->mycdevclassdevice); 
         printk(KERN_ERR  "class_device_create failed!\n" ); 
         goto  release_class_create; 
    
      
     cdev_init(&(myvirtualdisk->mycdev), &mydev_fops); 
     myvirtualdisk->mycdev.owner = THIS_MODULE; 
     ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1); 
  
     //这里把timer相关的放在irq前面,不然会有bug出现(当在insmod时候按下按钮就会出错) 
     init_timer(&myvirtualdisk->mytimer); 
     myvirtualdisk->mytimer.function = mytimer_func; 
     myvirtualdisk->mytimer.data = (unsigned  long )myvirtualdisk; 
      
     if (ret < 0){ 
     goto  release_device_class_create; 
    
     for (i = 0; i < 3; i++) 
    
         ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]); 
         if (ret < 0){ 
         printk(KERN_ERR  "request irq failed!\n" ); 
         ret =-EFAULT; 
         goto  release_cdevandtimer; 
        
    
  
      
      
     return  0; 
     release_cdevandtimer: 
         del_timer(&myvirtualdisk->mytimer); 
         cdev_del(&myvirtualdisk->mycdev); 
     release_device_class_create: 
         class_device_unregister(myvirtualdisk->mycdevclassdevice); 
     release_class_create: 
         class_destroy(myvirtualdisk->mycdevclass); 
     release_mem_malloc: 
         kfree(myvirtualdisk); 
     release_chrdev: 
         unregister_chrdev_region(MKDEV(major, 0), 1); 
     return  ret; 
  
static  void  __exit cdevtest_exit( void ){ 
     int  i = 0; 
     printk( "*******%s****1****\n" , __FUNCTION__); 
     del_timer(&myvirtualdisk->mytimer); 
         printk( "*******%s*****2***\n" , __FUNCTION__); 
     for (i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]); 
         printk( "*******%s*****3***\n" , __FUNCTION__); 
     cdev_del(&myvirtualdisk->mycdev); 
         printk( "*******%s*****4***\n" , __FUNCTION__); 
     class_device_unregister(myvirtualdisk->mycdevclassdevice); 
         printk( "*******%s*****5***\n" , __FUNCTION__); 
     class_destroy(myvirtualdisk->mycdevclass); 
         printk( "*******%s*****6***\n" , __FUNCTION__); 
     kfree(myvirtualdisk); 
         printk( "*******%s********\n" , __FUNCTION__); 
     unregister_chrdev_region(MKDEV(major, 0), 1); 
         printk( "*******%s*****7***\n" , __FUNCTION__); 
  
  
module_init(cdevtest_init); 
module_exit(cdevtest_exit); 
MODULE_LICENSE( "GPL" );

完整的tasklet任务中断下半部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <linux/kernel.h> 
#include <linux/device.h> 
#include <linux/cdev.h> 
#include <linux/fs.h> 
#include <linux/err.h> 
#include <linux/irq.h> 
#include <linux/input.h> 
#include <linux/interrupt.h> 
#include <linux/timer.h> 
  
#include <asm-arm/param.h> 
#include <asm/arch/regs-gpio.h> 
#include <asm/gpio.h> 
#define VIRTUAL_MAJOR 250 
int  major = VIRTUAL_MAJOR; 
  
struct  myirq_desc{ 
     int  irq_id; 
     char  *irq_name; 
     int  irq_code; 
}; 
  
struct  myirq_desc myirq_descs[3]= { 
         {S3C2410_GPF0,  "s2" , KEY_J}, 
         {S3C2410_GPF2,  "s3" , KEY_K}, 
         {S3C2410_GPG3,  "s4" , KEY_Z}, 
}; 
struct  VirtualDisk{ 
     struct  class  *mycdevclass; //在/sys/class创建类 
     struct  class_device *mycdevclassdevice; //在/dev下创建设备 
     struct  cdev mycdev; //给设备添加相关的fileoption 
     struct  timer_list mytimer; 
     struct  tasklet_struct mytasklet; 
}; 
struct  VirtualDisk *myvirtualdisk; 
  
static  struct  file_operations  mydev_fops = { 
     .owner = THIS_MODULE, 
}; 
static  void  mytasklet_func(unsigned  long  fundata){ 
     printk( "*****%s******,date = %ld\n" , __FUNCTION__, fundata); 
static  void  mytimer_func(unsigned  long  fundata){ 
     printk( "*******%s********\n" , __FUNCTION__); 
     struct  VirtualDisk *myvirtualdisk_fun = ( struct  VirtualDisk *)(fundata); 
     //myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ; 
     //add_timer(&myvirtualdisk_fun->mytimer); 
     printk( "timer func happened!\n" ); 
static  irqreturn_t myirq_handle( int  irq,  void  *dev_id){ 
     struct  myirq_desc *myirq_descone = ( struct  myirq_desc *)dev_id; 
     printk( "*******%s********\n" , __FUNCTION__); 
     printk( "irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n" , irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code); 
     tasklet_schedule(&myvirtualdisk->mytasklet); //激发任务,将mytasklet_func加入系统任务 
     mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ); 
     return  IRQ_RETVAL(IRQ_HANDLED); 
  
static  int  __init cdevtest_init( void ){ 
     dev_t mydev = MKDEV(major, 0); 
     int  ret; 
     int  i = 0; 
     printk( "*******%s********\n" , __FUNCTION__); 
     if (major){ //注册proc/devices 
     ret = register_chrdev_region(mydev, 1,  "mynewdriver" ); 
     } else
     ret = alloc_chrdev_region(&mydev, 0, 1,  "mynewdriver" ); 
     major =  MAJOR(mydev); 
    
     if (ret < 0){ 
     printk(KERN_ERR  "register_chrdev_region failed!\n" ); 
     ret = -EINVAL; 
     return  ret; 
    
     myvirtualdisk = kmalloc( sizeof ( struct  VirtualDisk), GFP_KERNEL); 
     if (!myvirtualdisk){ 
     ret = -ENOMEM; 
     printk(KERN_ERR  "kmalloc myvirtualdisk failed!\n" ); 
     goto  release_chrdev; 
    
     myvirtualdisk->mycdevclass = class_create(THIS_MODULE,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclass)){ 
     ret =  PTR_ERR(myvirtualdisk->mycdevclass); 
     printk(KERN_ERR  "class_create failed!\n" ); 
     goto  release_mem_malloc; 
      
    
     myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclassdevice)){ 
         ret = PTR_ERR(myvirtualdisk->mycdevclassdevice); 
         printk(KERN_ERR  "class_device_create failed!\n" ); 
         goto  release_class_create; 
    
      
     cdev_init(&(myvirtualdisk->mycdev), &mydev_fops); 
     myvirtualdisk->mycdev.owner = THIS_MODULE; 
     ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1); 
  
     //tasklet 任务调度 
     tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned  long ) 90); 
      
     //这里把timer相关的放在irq前面,不然会有bug出现(当在insmod时候按下按钮就会出错) 
     init_timer(&myvirtualdisk->mytimer); 
     myvirtualdisk->mytimer.function = mytimer_func; 
     myvirtualdisk->mytimer.data = (unsigned  long )myvirtualdisk; 
      
     if (ret < 0){ 
     goto  release_device_class_create; 
    
     for (i = 0; i < 3; i++) 
    
         ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]); 
         if (ret < 0){ 
         printk(KERN_ERR  "request irq failed!\n" ); 
         ret =-EFAULT; 
         goto  release_cdevandtimer; 
        
    
  
      
      
     return  0; 
     release_cdevandtimer: 
         tasklet_kill(&myvirtualdisk->mytasklet); //删除任务 
         del_timer(&myvirtualdisk->mytimer); 
         cdev_del(&myvirtualdisk->mycdev); 
     release_device_class_create: 
         class_device_unregister(myvirtualdisk->mycdevclassdevice); 
     release_class_create: 
         class_destroy(myvirtualdisk->mycdevclass); 
     release_mem_malloc: 
         kfree(myvirtualdisk); 
     release_chrdev: 
         unregister_chrdev_region(MKDEV(major, 0), 1); 
     return  ret; 
  
static  void  __exit cdevtest_exit( void ){ 
     int  i = 0; 
     printk( "*******%s****1****\n" , __FUNCTION__); 
     tasklet_kill(&myvirtualdisk->mytasklet); //删除任务 
     del_timer(&myvirtualdisk->mytimer); 
         printk( "*******%s*****2***\n" , __FUNCTION__); 
     for (i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]); 
         printk( "*******%s*****3***\n" , __FUNCTION__); 
     cdev_del(&myvirtualdisk->mycdev); 
         printk( "*******%s*****4***\n" , __FUNCTION__); 
     class_device_unregister(myvirtualdisk->mycdevclassdevice); 
         printk( "*******%s*****5***\n" , __FUNCTION__); 
     class_destroy(myvirtualdisk->mycdevclass); 
         printk( "*******%s*****6***\n" , __FUNCTION__); 
     kfree(myvirtualdisk); 
         printk( "*******%s********\n" , __FUNCTION__); 
     unregister_chrdev_region(MKDEV(major, 0), 1); 
         printk( "*******%s*****7***\n" , __FUNCTION__); 
  
  
module_init(cdevtest_init); 
module_exit(cdevtest_exit); 
MODULE_LICENSE( "GPL" );

完整的workqueue工作队列中断下半部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <linux/kernel.h> 
#include <linux/device.h> 
#include <linux/cdev.h> 
#include <linux/fs.h> 
#include <linux/err.h> 
#include <linux/irq.h> 
#include <linux/input.h> 
#include <linux/interrupt.h> 
#include <linux/timer.h> 
#include <linux/workqueue.h> 
  
#include <asm-arm/param.h> 
#include <asm/arch/regs-gpio.h> 
#include <asm/gpio.h> 
#define VIRTUAL_MAJOR 250 
int  major = VIRTUAL_MAJOR; 
  
struct  myirq_desc{ 
     int  irq_id; 
     char  *irq_name; 
     int  irq_code; 
}; 
  
struct  myirq_desc myirq_descs[3]= { 
         {S3C2410_GPF0,  "s2" , KEY_J}, 
         {S3C2410_GPF2,  "s3" , KEY_K}, 
         {S3C2410_GPG3,  "s4" , KEY_Z}, 
}; 
struct  VirtualDisk{ 
     struct  class  *mycdevclass; //在/sys/class创建类 
     struct  class_device *mycdevclassdevice; //在/dev下创建设备 
     struct  cdev mycdev; //给设备添加相关的fileoption 
     struct  timer_list mytimer; 
     struct  tasklet_struct mytasklet; 
     struct  workqueue_struct *myworkqueue; //工作队列 
     struct  work_struct mywork; //工作;工作队列中的一项工作 
}; 
struct  VirtualDisk *myvirtualdisk; 
  
static  struct  file_operations  mydev_fops = { 
     .owner = THIS_MODULE, 
}; 
  
static  void  mywork_func( struct  work_struct *work){ 
     printk( "*******%s********\n" , __FUNCTION__); 
static  void  mytasklet_func(unsigned  long  fundata){ 
     printk( "*****%s******,date = %ld\n" , __FUNCTION__, fundata); 
static  void  mytimer_func(unsigned  long  fundata){ 
     printk( "*******%s********\n" , __FUNCTION__); 
     //struct VirtualDisk *myvirtualdisk_fun = (struct VirtualDisk *)(fundata); 
     //myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ; 
     //add_timer(&myvirtualdisk_fun->mytimer); 
     printk( "timer func happened!\n" ); 
static  irqreturn_t myirq_handle( int  irq,  void  *dev_id){ 
     struct  myirq_desc *myirq_descone = ( struct  myirq_desc *)dev_id; 
     printk( "*******%s********\n" , __FUNCTION__); 
     printk( "irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n" , irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code); 
     queue_work(myvirtualdisk->myworkqueue, &myvirtualdisk->mywork); 
     tasklet_schedule(&myvirtualdisk->mytasklet); //激发任务,将mytasklet_func加入系统任务 
     mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ); 
     return  IRQ_RETVAL(IRQ_HANDLED); 
  
static  int  __init cdevtest_init( void ){ 
     dev_t mydev = MKDEV(major, 0); 
     int  ret; 
     int  i = 0; 
     printk( "*******%s********\n" , __FUNCTION__); 
     if (major){ //注册proc/devices 
     ret = register_chrdev_region(mydev, 1,  "mynewdriver" ); 
     } else
     ret = alloc_chrdev_region(&mydev, 0, 1,  "mynewdriver" ); 
     major =  MAJOR(mydev); 
    
     if (ret < 0){ 
     printk(KERN_ERR  "register_chrdev_region failed!\n" ); 
     ret = -EINVAL; 
     return  ret; 
    
     myvirtualdisk = kmalloc( sizeof ( struct  VirtualDisk), GFP_KERNEL); 
     if (!myvirtualdisk){ 
     ret = -ENOMEM; 
     printk(KERN_ERR  "kmalloc myvirtualdisk failed!\n" ); 
     goto  release_chrdev; 
    
     myvirtualdisk->mycdevclass = class_create(THIS_MODULE,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclass)){ 
     ret =  PTR_ERR(myvirtualdisk->mycdevclass); 
     printk(KERN_ERR  "class_create failed!\n" ); 
     goto  release_mem_malloc; 
      
    
     myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL,  "mynewdriver" ); 
     if (IS_ERR(myvirtualdisk->mycdevclassdevice)){ 
         ret = PTR_ERR(myvirtualdisk->mycdevclassdevice); 
         printk(KERN_ERR  "class_device_create failed!\n" ); 
         goto  release_class_create; 
    
  
     //工作和工作队列 
     INIT_WORK(&myvirtualdisk->mywork, mywork_func); 
     myvirtualdisk->myworkqueue = create_workqueue( "myworkqueue" ); 
     if  (!myvirtualdisk->myworkqueue) { 
         ret = -ENOMEM; 
         goto  release_class_create; 
    
      
     cdev_init(&(myvirtualdisk->mycdev), &mydev_fops); 
     myvirtualdisk->mycdev.owner = THIS_MODULE; 
     ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1); 
  
      
     //tasklet 任务调度 
     tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned  long ) 90); 
      
     //这里把timer相关的放在irq前面,不然会有bug出现(当在insmod时候按下按钮就会出错) 
     init_timer(&myvirtualdisk->mytimer); 
     myvirtualdisk->mytimer.function = mytimer_func; 
     myvirtualdisk->mytimer.data = (unsigned  long )myvirtualdisk; 
      
     if (ret < 0){ 
     goto  release_device_class_create; 
    
     for (i = 0; i < 3; i++) 
    
         ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]); 
         if (ret < 0){ 
         printk(KERN_ERR  "request irq failed!\n" ); 
         ret =-EFAULT; 
         goto  release_cdevandtimer; 
        
    
  
             /*在模块注销的时候,销毁工作队列和工作对象 
                   void flush_workqueue(struct workqueue_struct * wq) 
                  该函数会一直等待,知道指定的等待队列中所有的任务都执行完毕并从等待队列中移除。 
                  void destroy_workqueue(struct workqueue_struct * wq); 
                 该函数是是创建等待队列的反操作,注销掉指定的等待队列。*/ 
      
     return  0; 
     release_cdevandtimer: 
         tasklet_kill(&myvirtualdisk->mytasklet); //删除任务 
         del_timer(&myvirtualdisk->mytimer); 
         cdev_del(&myvirtualdisk->mycdev); 
         /*在模块注销的时候,销毁工作队列和工作对象 
                   void flush_workqueue(struct workqueue_struct * wq) 
                  该函数会一直等待,知道指定的等待队列中所有的任务都执行完毕并从等待队列中移除。 
                  void destroy_workqueue(struct workqueue_struct * wq); 
                 该函数是是创建等待队列的反操作,注销掉指定的等待队列。*/ 
                 flush_workqueue(myvirtualdisk->myworkqueue); 
         destroy_workqueue(myvirtualdisk->myworkqueue); 
     release_device_class_create: 
         class_device_unregister(myvirtualdisk->mycdevclassdevice); 
     release_class_create: 
         class_destroy(myvirtualdisk->mycdevclass); 
     release_mem_malloc: 
         kfree(myvirtualdisk); 
     release_chrdev: 
         unregister_chrdev_region(MKDEV(major, 0), 1); 
     return  ret; 
  
static  void  __exit cdevtest_exit( void ){ 
     int  i = 0; 
     printk( "*******%s****1****\n" , __FUNCTION__); 
     tasklet_kill(&myvirtualdisk->mytasklet); //删除任务 
     del_timer(&myvirtualdisk->mytimer); 
         printk( "*******%s*****2***\n" , __FUNCTION__); 
     for (i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]); 
         printk( "*******%s*****3***\n" , __FUNCTION__); 
     cdev_del(&myvirtualdisk->mycdev); 
  
     //删除工作和工作队列 
        flush_workqueue(myvirtualdisk->myworkqueue); 
     destroy_workqueue(myvirtualdisk->myworkqueue); 
      
         printk( "*******%s*****4***\n" , __FUNCTION__); 
     class_device_unregister(myvirtualdisk->mycdevclassdevice); 
         printk( "*******%s*****5***\n" , __FUNCTION__); 
     class_destroy(myvirtualdisk->mycdevclass); 
         printk( "*******%s*****6***\n" , __FUNCTION__); 
     kfree(myvirtualdisk); 
         printk( "*******%s********\n" , __FUNCTION__); 
     unregister_chrdev_region(MKDEV(major, 0), 1); 
         printk( "*******%s*****7***\n" , __FUNCTION__); 
  
  
module_init(cdevtest_init); 
module_exit(cdevtest_exit); 
MODULE_LICENSE( "GPL" );

本文转自lilin9105 51CTO博客,原文链接:http://blog.51cto.com/7071976/1419036,如需转载请自行联系原作者