引文网址:http://www.cnblogs.com/myblesh/articles/2918142.html
在linux2.6内核驱动中,为设备实现一套中断处理机制提供了如下两个步骤:
1.向内核注册中断处理;2.实现中断处理函数
int request_irq(unsigned int irq,void (*handler)(int, void*, struct pt_regs *),unsigned long flags,const char *devname,void *dev_id) //注册中断;返回0表示成功,或者返回一个错误码
参数含义
unsigned int irq 中断号
void (*handler)(int,void *,struct pt_regs *) 中断处理函数
unsigned long flags 与中断管理有关的各种选项;如IRQF_DISABLED,IRQF_SHARED
const char * devname 设备名
void *dev_id 共享中断时使用
注意1 共享设备就是将不同的设备挂接到同一个中断信号线上,liunx对共享的支持主要是用在PCI设备服务。且在共享中断时,dev_id必须唯一指定。
注意2 共享中断的处理程序中,不能使用 disable_irq(unsigned int irq) 因为如果使用了这个函数,共享中断信线的其它设备将同样无法使用中断,也就无法正常工作了。
handler中断处理程序
中断处理程序就是普通的C代码。特别之处在于中断处理程序是在中断上下文中运行的,它的行为受到某些限制
1. 不能向用户空间发送或接受数据 2. 不能使用可能引起阻塞的函数 3. 不能使用可能引起调度的函数
中断处理函数一个实例如下
1 void short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)
2 {
3 /* 判断是否是本设备产生了中断(为什么要做这样的检测? 共享中断) */
4 value = inb(short_base);
5 if (!(value & 0x80)) return;
6 /* 清除中断位(如果设备支持自动清除,则不需要这步) */
7 outb(value & 0x7F, short_base);
8 /* 中断处理,通常是数据接收*/
9 。。。。。。。。。
10 /* 唤醒等待数据的进程*/
11 wake_up_interruptible(&short_queue);
12 }
释放中断函数
void free_irq(unsigned int irq, void *dev_id) //当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们返还给系统
附s3c24xx按键中断驱动程序源码:
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/fs.h>
4 #include <linux/init.h>
5 #include <linux/delay.h>
6 #include <linux/poll.h>
7 #include <linux/irq.h>
8 #include <asm/irq.h>
9 #include <linux/interrupt.h>
10 #include <asm/uaccess.h>
11 #include <mach/regs-gpio.h>
12 #include <mach/hardware.h>
13 #include <linux/platform_device.h>
14 #include <linux/cdev.h>
15 #include <linux/miscdevice.h>
16 #include <linux/sched.h>
17 #include <linux/gpio.h>
18
19 #define DEVICE_NAME "buttons"
20
21 struct button_irq_desc {
22 int irq;
23 int pin;
24 int pin_setting;
25 int number;
26 char *name;
27 };
28
29 //#define DEBUG
30 #undef DEBUG
31 #define QIUSHI
32 #define START_BUTTON 8
33
34 #ifdef QIUSHI
35 static struct button_irq_desc button_irqs [] = {
36 {IRQ_EINT0, S3C2410_GPF(0), S3C2410_GPF0_EINT0, 0, "KEY0"},
37 {IRQ_EINT1, S3C2410_GPF(1), S3C2410_GPF1_EINT1, 1, "KEY1"},
38 {IRQ_EINT2, S3C2410_GPF(2), S3C2410_GPF2_EINT2, 2, "KEY2"},
39 {IRQ_EINT3, S3C2410_GPF(3), S3C2410_GPF3_EINT3, 3, "KEY3"},
40 {IRQ_EINT4, S3C2410_GPF(4), S3C2410_GPF4_EINT4, 4, "KEY4"},
41 {IRQ_EINT5, S3C2410_GPF(5), S3C2410_GPF5_EINT5, 5, "KEY5"},
42 {IRQ_EINT6, S3C2410_GPF(6), S3C2410_GPF6_EINT6, 6, "KEY6"},
43 {IRQ_EINT8, S3C2410_GPG(0), S3C2410_GPG0_EINT8, 7, "KEY7"},
44 {IRQ_EINT9, S3C2410_GPG(1), S3C2410_GPG1_EINT9, 8, "KEY8"},
45 };
46 #else
47 static struct button_irq_desc button_irqs [] = {
48 {IRQ_EINT8 , S3C2410_GPG(0) , S3C2410_GPG0_EINT8 , 0, "KEY0"},
49 {IRQ_EINT11, S3C2410_GPG(3) , S3C2410_GPG3_EINT11 , 1, "KEY1"},
50 {IRQ_EINT13, S3C2410_GPG(5) , S3C2410_GPG5_EINT13 , 2, "KEY2"},
51 {IRQ_EINT14, S3C2410_GPG(6) , S3C2410_GPG6_EINT14 , 3, "KEY3"},
52 {IRQ_EINT15, S3C2410_GPG(7) , S3C2410_GPG7_EINT15 , 4, "KEY4"},
53 {IRQ_EINT19, S3C2410_GPG(11), S3C2410_GPG11_EINT19, 5, "KEY5"},
54 };
55 #endif
56
57 static volatile char key_values [] = {'0', '0', '0', '0', '0', '0', '0', '0', '0'};
58
59 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
60
61 static volatile int ev_press = 0;
62
63
64 static irqreturn_t buttons_interrupt(int irq, void *dev_id)
65 {
66 struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
67 int down;
68
69 // udelay(0);
70 down = !s3c2410_gpio_getpin(button_irqs->pin);
71
72 #ifdef DEBUG
73 printk( "%s: new=%d, old=%d\n", __FUNCTION__ , down, (key_values[button_irqs->number] & 1));
74 #endif
75
76 if (down != (key_values[button_irqs->number] & 1)) { // Changed
77
78 key_values[button_irqs->number] = '0' + down;
79
80 ev_press = 1;
81 wake_up_interruptible(&button_waitq);
82 }
83 return IRQ_RETVAL(IRQ_HANDLED);
84 }
85
86
87 static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
88 {
89 int i;
90 int err = 0;
91
92 for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
93 if (button_irqs[i].irq < 0) {
94 continue;
95 }
96 err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,
97 button_irqs[i].name, (void *)&button_irqs[i]);
98 if (err)
99 {
100 printk( "%s: err=%d, but=%d\n", __FUNCTION__, err, i);
101 break;
102 }
103 }
104 /*错误处理*/
105 if (err) {
106 i--;
107 for (; i >= 0; i--) {
108 if (button_irqs[i].irq < 0) {
109 continue;
110 }
111 disable_irq(button_irqs[i].irq);
112 free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
113 }
114 return -EBUSY;
115 }
116
117 ev_press = 1;
118
119 return 0;
120 }
121
122
123 static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
124 {
125 int i;
126
127 for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
128 if (button_irqs[i].irq < 0) {
129 continue;
130 }
131 free_irq(button_irqs[i].irq, (void *)&button_irqs[i]);
132 }
133
134 return 0;
135 }
136
137
138 static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
139 {
140 unsigned long err;
141
142 if (!ev_press) {
143 if (filp->f_flags & O_NONBLOCK)
144 return -EAGAIN;
145 else
146 wait_event_interruptible(button_waitq, ev_press);
147 }
148
149 ev_press = 0;
150
151 err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
152
153 return err ? -EFAULT : min(sizeof(key_values), count);
154 }
155
156 /*poll做两件事?poll_wait指明使用的等待队列,返回掩码*/
157
158 static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
159 {
160 unsigned int mask = 0;
161 poll_wait(file, &poll_wait, wait);
162 if (ev_press) /*按下evpress为1,有数据刻可读*/
163 mask |= POLLIN | POLLRDNORM;
164 return mask;
165 }
166
167
168
169
170 static int s3c2410_buttons_ioctl(
171 struct inode *inode,
172 struct file *file,
173 unsigned int cmd,
174 unsigned long arg)
175 { int down;
176 down = s3c2410_gpio_getpin(button_irqs[START_BUTTON].pin);
177 return down;
178 }
179
180
181 static struct file_operations dev_fops = {
182 .owner = THIS_MODULE,
183 .open = s3c24xx_buttons_open,
184 .release = s3c24xx_buttons_close,
185 .read = s3c24xx_buttons_read,
186 .poll = s3c24xx_buttons_poll,
187 .ioctl = s3c2410_buttons_ioctl,
188 };
189
190
191 static struct miscdevice misc = {
192 .minor = MISC_DYNAMIC_MINOR,
193 .name = DEVICE_NAME,
194 .fops = &dev_fops,
195 };
196
197 static int __init dev_init(void)
198 {
199 int ret;
200
201 ret = misc_register(&misc);
202
203 printk (DEVICE_NAME"\tinitialized\n");
204
205 return ret;
206 }
207
208 static void __exit dev_exit(void)
209 {
210 misc_deregister(&misc);
211 }
212
213 module_init(dev_init);
214 module_exit(dev_exit);
215 MODULE_LICENSE("GPL");
216 MODULE_AUTHOR("QiuShi Inc.");
platform总线是linux2.6内核后加入的一条虚拟总线,由两部分组成:platform_device和platform_driver;优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口,提高可可移植性。
结构体平台设备 struct platform_device
1 struct platform_device {
2 const char * name;
3 int id;
4 struct device dev;
5 u32 num_resources;
6 struct resource * resource;
7
8 const struct platform_device_id *id_entry;
9
10 /* arch specific additions */
11 struct pdev_archdata archdata;
12 };
struct platform_device*platform_device_alloc(const char *name, int id) //平台设备分配函数
int platform_device_add(struct platform_device *pdev) 平台设备注册函数
平台设备资源 结构体 struct resource
按 Ctrl+C 复制代码
按 Ctrl+C 复制代码
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num) //获取资源分配函数
参数:
vdev: 资源所属的设备
vtype: 获取的资源类型
vnum: 获取的资源数
例:
platform_get_resource(pdev, IORESOURCE_IRQ, 0) //获取中断
结构体平台驱动 struct platform_driver
1 struct platform_driver {
2 int (*probe)(struct platform_device *);
3 int (*remove)(struct platform_device *);
4 void (*shutdown)(struct platform_device *);
5 int (*suspend)(struct platform_device *, pm_message_t state);
6 int (*resume)(struct platform_device *);
7 struct device_driver driver;
8 const struct platform_device_id *id_table;
9 };
int platform_driver_register(struct platform_driver *) //平台驱动注册使用函数
void platform_driver_unregister(struct platform_driver *); //平台驱动卸载使用函数
下例结合mini2440利用平台驱动模型来分析按键中断程序
plat_device.c
1 #include <linux/module.h>
2 #include <linux/types.h>
3 #include <linux/fs.h>
4 #include <linux/init.h>
5 #include <linux/platform_device.h>
6 #include <mach/regs-gpio.h>
7 #include <linux/interrupt.h>
8 #include <linux/device.h>
9 #include <linux/io.h>
10
11 /*平台资源的定义*/
12 static struct resource s3c_buttons_resource[] = {
13 [0]={
14 .start = S3C24XX_PA_GPIO,
15 .end = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1,
16 .flags = IORESOURCE_MEM,
17 },
18
19 [1]={
20 .start = IRQ_EINT8,
21 .end = IRQ_EINT8,
22 .flags = IORESOURCE_IRQ,
23 },
24 [2]={
25 .start = IRQ_EINT11,
26 .end = IRQ_EINT11,
27 .flags = IORESOURCE_IRQ,
28 },
29 [3]={
30 .start = IRQ_EINT13,
31 .end = IRQ_EINT13,
32 .flags = IORESOURCE_IRQ,
33 },
34 [4]={
35 .start = IRQ_EINT14,
36 .end = IRQ_EINT14,
37 .flags = IORESOURCE_IRQ,
38 },
39 [5]={
40 .start = IRQ_EINT15,
41 .end = IRQ_EINT15,
42 .flags = IORESOURCE_IRQ,
43 },
44 [6]={
45 .start = IRQ_EINT19,
46 .end = IRQ_EINT19,
47 .flags = IORESOURCE_IRQ,
48 }
49 };
50
51 static struct platform_device *s3c_buttons;
52
53
54 static int __init platform_init(void)
55 {
56
57 s3c_buttons = platform_device_alloc("mini2440-buttons",-1);
58
59 platform_device_add_resources(s3c_buttons,&s3c_buttons_resource,7);
60
61 /*平台设备的注册*/
62 platform_device_add(s3c_buttons);
63
64
65 }
66
67 static void __exit platform_exit(void)
68 {
69 platform_device_unregister(s3c_buttons);
70 }
71
72 module_init(platform_init);
73 module_exit(platform_exit);
74
75 MODULE_AUTHOR("David Xie");
76 MODULE_LICENSE("GPL");
77 MODULE_ALIAS("platform:mini2440buttons");
plat_buttons.c
1 #include <linux/module.h>
2 #include <linux/types.h>
3 #include <linux/miscdevice.h>
4 #include <linux/fs.h>
5 #include <linux/init.h>
6 #include <linux/platform_device.h>
7 #include <linux/interrupt.h>
8 #include <linux/clk.h>
9 #include <linux/uaccess.h>
10 #include <linux/io.h>
11 #include <mach/map.h>
12 #include <mach/regs-gpio.h>
13 #include <linux/poll.h>
14 #include <linux/irq.h>
15 #include <asm/unistd.h>
16 #include <linux/device.h>
17
18
19 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
20
21 static volatile int ev_press = 0;
22
23
24 static int key_value;
25 static struct device *buttons_dev; /* platform device attached to */
26 static struct resource *buttons_mem;
27 static struct resource *buttons_irq;
28 static void __iomem *buttons_base;
29
30
31 static int button_irqs[6];
32
33 static irqreturn_t buttons_interrupt(int irq, void *dev_id)
34 {
35 int i;
36 for(i=0; i<6; i++){
37 if(irq == button_irqs[i]){
38 //printk("==>interrput number:%d\n",irq);
39 key_value = i;
40 ev_press =1;
41 wake_up_interruptible(&button_waitq);
42 }
43 }
44
45 return IRQ_RETVAL(IRQ_HANDLED);
46
47 }
48
49 static int s3c24xx_buttons_open(struct inode *inode, struct file *file)
50 {
51 int i;
52 int err = 0;
53 /*注册中断*/
54 for(i=0; i<6; i++){
55 if (button_irqs[i] < 0)
56 continue;
57
58 /*中断触发方式:上升沿触发*/
59 err = request_irq(button_irqs[i],buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);
60 if(err)
61 break;
62 }
63
64 if (err) {
65 i--;
66 for (; i >= 0; i--) {
67 if (button_irqs[i] < 0) {
68 continue;
69 }
70 disable_irq(button_irqs[i]);
71 free_irq(button_irqs[i], NULL);
72 }
73 return -EBUSY;
74 }
75
76 ev_press = 0;
77 return 0;
78 }
79
80 static int s3c24xx_buttons_close(struct inode *inode, struct file *file)
81 {
82 int i;
83 for (i=0; i<6; i++) {
84 if (button_irqs[i] < 0) {
85 continue;
86 }
87 free_irq(button_irqs[i],NULL);
88 }
89 return 0;
90 }
91
92 static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
93 {
94 unsigned long err;
95 if (!ev_press) {
96 if (filp->f_flags & O_NONBLOCK)
97 return -EAGAIN;
98 else
99 wait_event_interruptible(button_waitq, ev_press);
100 }
101 ev_press = 0;
102 err = copy_to_user(buff, &key_value, sizeof(key_value));
103 return sizeof(key_value);
104 }
105 //轮询poll要做两件事:poll_wait指明使用的等待队列;返回掩码
106 static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait)
107 {
108 unsigned int mask = 0;
109 poll_wait(file, &button_waitq, wait);
110 if (ev_press){
111 mask |= POLLIN | POLLRDNORM; /*按下evpress为1,有数据刻可读*/
112 }
113 return mask;
114 }
115
116
117
118 static struct file_operations mini2440buttons_fops = {
119 .owner = THIS_MODULE,
120 .open = s3c24xx_buttons_open,
121 .release = s3c24xx_buttons_close,
122 .read = s3c24xx_buttons_read,
123 .poll = s3c24xx_buttons_poll,
124 };
125
126 static struct miscdevice mini2440_miscdev = {
127
128 .minor = MISC_DYNAMIC_MINOR,
129 .name ="buttons",
130 .fops = &mini2440buttons_fops,
131 };
132
133 /* device interface */
134 static int mini2440_buttons_probe(struct platform_device *pdev)
135 {
136 struct resource *res;
137 struct device *dev;
138 int ret;
139 int size;
140 int i;
141
142 printk("probe:%s\n", __func__);
143 dev = &pdev->dev;
144 buttons_dev = &pdev->dev;
145
146 /*平台资源获取*/
147 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
148 if (res == NULL) {
149 dev_err(dev, "no memory resource specified\n");
150 return -ENOENT;
151 }
152
153 size = (res->end - res->start) + 1;
154 buttons_mem = request_mem_region(res->start, size, pdev->name);
155 if (buttons_mem == NULL) {
156 dev_err(dev, "failed to get memory region\n");
157 ret = -ENOENT;
158 goto err_req;
159 }
160
161 buttons_base = ioremap(res->start, size);
162 if (buttons_base == NULL) {
163 dev_err(dev, "failed to ioremap() region\n");
164 ret = -EINVAL;
165 goto err_req;
166 }
167 printk(KERN_DEBUG"probe: mapped buttons_base=%p\n", buttons_base);
168
169 /*get irq number*/
170 for(i=0; i<6; i++){
171 buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i);
172 if(buttons_irq == NULL){
173 dev_err(dev,"no irq resource specified\n");
174 ret = -ENOENT;
175 goto err_map;
176 }
177 button_irqs[i] = buttons_irq->start;
178 //printk("button_irqs[%d]=%d\n",i,button_irqs[i]);
179 }
180 ret = misc_register(&mini2440_miscdev); //混杂设备注册
181
182 return 0;
183
184 err_map:
185 iounmap(buttons_base);
186
187 err_req:
188 release_resource(buttons_mem);
189 kfree(buttons_mem);
190
191 return ret;
192 }
193
194 static int mini2440_buttons_remove(struct platform_device *dev)
195 {
196 release_resource(buttons_mem);
197 kfree(buttons_mem);
198 buttons_mem = NULL;
199
200 iounmap(buttons_base);
201 misc_deregister(&mini2440_miscdev);
202 return 0;
203 }
204
205 /*平台驱动定义*/
206 static struct platform_driver mini2440buttons_driver = {
207 .probe = mini2440_buttons_probe,
208 .remove = mini2440_buttons_remove,
209 .driver = {
210 .owner = THIS_MODULE,
211 .name = "mini2440-buttons",
212 },
213 };
214
215 static char banner[] __initdata =
216 "Mini2440 Buttons Driver\n";
217 /*
218 宏 __init作用与 __initdata作用:
219 此宏定义可知标记后的函数或数据其实是放到了特定的(代码或数据)段中。
220 标记为初始化的函数,表明该函数供在初始化期间使用。在模块装载之后,
221 模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。
222 */
223 static int __init buttons_init(void)
224 {
225 printk(banner);
226 /*平台驱动注册*/
227 platform_driver_register(&mini2440buttons_driver);
228 return 0;
229 }
230
231 static void __exit buttons_exit(void)
232 {
233 platform_driver_unregister(&mini2440buttons_driver);
234 }
235
236 module_init(buttons_init);
237 module_exit(buttons_exit);
238
239 MODULE_AUTHOR("David Xie");
240 MODULE_DESCRIPTION("Mini2440 Buttons Driver");
241 MODULE_LICENSE("GPL");