字符设备驱动之按键驱动(中断)

单片机下中断处理过程:

①按键按下

CPU发生中断,跳转到异常向量入口

③跳转到中断处理函数

a、保存被中断的现场

b、执行中断处理函数

c、恢复被中断现场

   

Linux下中断处理过程:

ARM架构CPU的异常向量地址可以是0x00000000,也可以是0xFFFF0000Linux内核使用的是0xFFFF00000xFFFF0000是一个虚拟地址)。因此,在建立虚拟地址映射之后,需要把异常向量复制到虚拟地址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

posted @ 2019-11-17 20:46  Lilto  阅读(339)  评论(0编辑  收藏  举报