Linux input子系统实例分析(一)
这是一个简单的输入设备驱动实例。这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理。该实例的代码如下:
1: #include <linux/module.h>
2: #include <linux/init.h>
3: #include <linux/fs.h>
4: #include <linux/interrupt.h>
5: #include <linux/irq.h>
6: #include <linux/sched.h>
7: #include <linux/spinlock.h>
8: #include <linux/pm.h>
9: #include <linux/slab.h>
10: #include <linux/sysctl.h>
11: #include <linux/proc_fs.h>
12: #include <linux/delay.h>
13: #include <linux/platform_device.h>
14: #include <linux/input.h>
15: #include <linux/workqueue.h>
16: #include <linux/gpio.h>
17:
18:
19: #define gpio_key 32*4+30 //PD(30) 即将使用的gpio
20: #define DEV_NAME "gpio_key"
21:
22: int g_irq = -1; //中断号
23: static struct input_dev *button_dev; //输入子系统设备结构
24:
25:
26: //中断处理函数
27: static irqreturn_t button_interrupt(int irq, void *p)
28: {
29: /*get pin value <down 0, up 1> */
30:
31: int val = gpio_get_value(gpio_key);
32:
33: input_report_key(button_dev, KEY_1, val);
34:
35: input_sync(button_dev);
36:
37: return IRQ_RETVAL(IRQ_HANDLED);
38: }
39:
40:
41:
42: static int __init button_init(void)
43: {
44: int irq = -1, err = -1;
45: unsigned long irqflags;
46: //申请gpio
47: err = gpio_request(gpio_key, "test_key");
48: if(err < 0){
49: printk("request gpio[%d] failed...\n", gpio_key);
50: goto end1;
51: }
52:
53: //gpio输入
54: err = gpio_direction_input(gpio_key);
55: if (err < 0) {
56: //dev_err(dev, "failed to configure"
57: // " direction for GPIO %d, error %d\n",
58: // gpio_key, error);
59: goto end2;
60: }
61: //申请gpio中断号
62: g_irq = (irq = gpio_to_irq(gpio_key));
63: if (irq < 0) {
64: err = irq;
65: //dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
66: // gpio_key, irq);
67: goto end2;
68: }
69: //中断类型
70: irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
71: /* 申请中断 */
72: if (request_irq(irq, button_interrupt, irqflags, DEV_NAME, NULL)) {
73:
74: printk(KERN_ERR"cannotallocate irq");
75: err= -EBUSY;
76: goto end2;
77: }
78:
79: /*分配input_dev */
80: button_dev = input_allocate_device();
81: if (button_dev == NULL) {
82: printk(KERN_ERR "notenough memory\n");
83: err= - ENOMEM;
84: goto end3;
85:
86: }
87: /*设置输入设备支持的事件类型和事件代码 */
88: button_dev->name = "key_gpio";
89: set_bit(EV_KEY, button_dev->evbit);
90: set_bit(KEY_1, button_dev->keybit);
91:
92: /*把输入设备注册进核心层 */
93: err = input_register_device(button_dev);
94: if(err) {
95: printk(KERN_ERR "failedto register device\n");
96: goto end4;
97: }
98:
99: printk("initialized\n");
100: return 0;
101:
102: end4:
103: input_free_device(button_dev);
104: end3:
105: free_irq(irq, NULL);
106: end2:
107: gpio_free(gpio_key);
108: end1:
109: return err;
110:
111: }
112:
113:
114:
115: static void __exit button_exit(void)
116: {
117: input_unregister_device(button_dev);
118: input_free_device(button_dev);
119:
120: gpio_free(gpio_key);
121: free_irq(g_irq, NULL);
122: }
123:
124:
125:
126: module_init(button_init);
127: module_exit(button_exit);
128:
129: MODULE_LICENSE("GPL");
130: MODULE_AUTHOR("xuyonghong@duotin.com>");
131:
132:
133:
134:
135:
136:
当编译进内核烧写板子后可以看到相应的设备文件:
root@CarRadio:/sys/devices# ls virtual/input/input2/
capabilities id name power subsystem uniq
event2 modalias phys properties uevent
root@CarRadio:/sys/devices# cat virtual/input/input2/name
key_gpio
root@CarRadio:/sys/devices#
这样就可以监控event2来捕捉按键
root@CarRadio:/# ls dev/input/event2
dev/input/event2
root@CarRadio:/#
驱动分析:
1.申请gpio
gpio_request(gpio_key, "test_key");
2.设置为gpio输入模式
gpio_direction_input(gpio_key);
3.申请gpio中断号,注册中断
//申请gpio中断号 g_irq = (irq = gpio_to_irq(gpio_key));
/* 申请中断 */
request_irq(irq, button_interrupt, irqflags, DEV_NAME, NULL);
4.分配input_dev设备
/*分配input_dev */
button_dev = input_allocate_device();
5.把输入设备注册进核心层
input_register_device(button_dev);