字符设备驱动之按键驱动(中断)
单片机下中断处理过程:
①按键按下
②CPU发生中断,跳转到异常向量入口
③跳转到中断处理函数
a、保存被中断的现场
b、执行中断处理函数
c、恢复被中断现场
Linux下中断处理过程:
ARM架构CPU的异常向量地址可以是0x00000000,也可以是0xFFFF0000。Linux内核使用的是0xFFFF0000(0xFFFF0000是一个虚拟地址)。因此,在建立虚拟地址映射之后,需要把异常向量复制到虚拟地址0xFFFF0000上去,Linux使用trap_init函数。
函数接口:
注册中断:
1 int request_irq(unsigned int irq, irq_handler_t handler,
2 unsigned long irqflags, const char *devname, void *dev_id)
参数说明:
irq: 中断号
handle: 处理函数
irqflag: 触发方式
devname: 中断名字
dev_id: 设备号(用户自定义)
①分配了一个irqaction结构
②setup_irq(irq, action);
卸载中断:
1 void free_irq(unsigned int irq, void *dev_id)
参数说明:
irq: 中断号
dev_id: 设备号
①根据dev_id,删除用户注册的中断处理函数(释放irqaction结构)
②当当前中断号下无irqaction结构时,禁止中断
一些常用的命令:
cat /proc/devices //查看设备
cat /proc/interrupts //查看中断
exec 5</dev/myKey //打开设备
exec 5<&- //关闭设备
实例:
driver.c
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/irq.h>
7 #include <asm/uaccess.h>
8 #include <asm/irq.h>
9 #include <asm/io.h>
10 #include <asm/arch/regs-gpio.h>
11 #include <asm/hardware.h>
12
13
14 static int major;
15
16 static struct class *myKey_class;
17 static struct class_device *myKey_class_dev;
18
19 volatile unsigned long *gpfcon;
20 volatile unsigned long *gpfdat;
21
22 volatile unsigned long *gpgcon;
23 volatile unsigned long *gpgdat;
24
25 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
26 static volatile int ev_press = 0;
27
28
29 static unsigned char keyVal = 0;
30
31 struct pin_desc {
32 unsigned int pin;
33 unsigned int key_val;
34 };
35
36 /*
37 * 按键按下键值为0x01,...; 松开键值为0x81,...
38 */
39 struct pin_desc pins_desc[3] = {
40 {S3C2410_GPF0, 0x01},
41 {S3C2410_GPF2, 0x02},
42 {S3C2410_GPG11, 0x03},
43 };
44
45
46 static int myKey_open(struct inode *inode, struct file *file);
47 static int myKey_close(struct inode *, struct file *);
48 static ssize_t myKey_read(struct file *file, char __user *buf, size_t size, loff_t *ppos);
49
50
51 static struct file_operations myKey_fops = {
52 .open = myKey_open,
53 .read = myKey_read,
54 .owner = THIS_MODULE,
55 .release = myKey_close,
56 };
57
58
59 static irqreturn_t handle_buttons(int irq, void *dev)
60 {
61 unsigned int kval;
62 struct pin_desc *pinDesc = dev;
63
64 kval = s3c2410_gpio_getpin(pinDesc->pin);
65 if (kval) //松开
66 {
67 keyVal = 0x80 | pinDesc->key_val;
68 }
69 else { //按下
70 keyVal = pinDesc->key_val;
71 }
72
73 //唤醒休眠进程
74 ev_press = 1; //中断发生标志
75 wake_up_interruptible(&button_waitq);
76
77 return IRQ_RETVAL(IRQ_HANDLED);
78 }
79
80
81 static int myKey_open(struct inode *inode, struct file *file)
82 {
83 request_irq(IRQ_EINT0, handle_buttons, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
84 request_irq(IRQ_EINT2, handle_buttons, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
85 request_irq(IRQ_EINT19, handle_buttons, IRQT_BOTHEDGE, "S5", &pins_desc[2]);
86
87 return 0;
88 }
89
90
91 static int myKey_close(struct inode *inode, struct file *file)
92 {
93 free_irq(IRQ_EINT0, &pins_desc[0]);
94 free_irq(IRQ_EINT2, &pins_desc[1]);
95 free_irq(IRQ_EINT19, &pins_desc[2]);
96
97 return 0;
98 }
99
100
101 static ssize_t myKey_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
102 {
103 //无中断进入休眠
104 wait_event_interruptible(button_waitq, ev_press);
105
106 ev_press = 0; //清除中断发生标志
107 copy_to_user(buf, &keyVal, 1);
108 return 0;
109 }
110
111 static int __init myKey_init(void)
112 {
113 /* 物理地址映射成虚拟地址 */
114 gpfcon = (volatile unsigned long*)ioremap(0x56000050, 16);
115 gpfdat = gpfcon + 1;
116
117 gpgcon = (volatile unsigned long*)ioremap(0x56000060, 16);
118 gpgdat = gpgcon + 1;
119
120 major = register_chrdev(0, "myKey", &myKey_fops);
121
122 myKey_class = class_create(THIS_MODULE, "myKeyclass");
123 myKey_class_dev = class_device_create(myKey_class, NULL, MKDEV(major, 0), NULL, "myKey");
124
125 return 0;
126 }
127
128 static void __exit myKey_exit(void)
129 {
130 /* 释放虚拟地址映射 */
131 iounmap(0x56000050);
132 iounmap(0x56000060);
133
134 unregister_chrdev(major, "myKey");
135
136 class_device_unregister(myKey_class_dev);
137 class_destroy(myKey_class);
138 return;
139 }
140
141 module_init(myKey_init);
142 module_exit(myKey_exit);
143
144 MODULE_LICENSE("GPL");
app.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 int main (void)
7 {
8 int fd;
9 unsigned char keyVal;
10 ssize_t rst;
11
12 printf("test app!\n");
13
14 fd = open("/dev/myKey", O_RDWR);
15 if(fd < 0)
16 {
17 printf("open failed! %d\n", fd);
18 return -1;
19 }
20
21 while(1)
22 {
23 rst = read(fd, &keyVal, 1);
24 if (rst < 0)
25 {
26 printf("read failed!\n");
27 continue;
28 }
29 printf("keyVal: 0x%x\n", keyVal);
30 }
31 return 0;
32 }
Makefile
1 KERN_DIR = /work/system/linux-2.6.22.6
2
3 all:
4 make -C $(KERN_DIR) M=`pwd` modules
5
6 clean:
7 make -C $(KERN_DIR) M=`pwd` modules clean
8 rm -rf modules.order
9
10 obj-m += myKey_irq.o