1 /*
2 输入子系统:
3 把按键的驱动,添加到输入子系统中,可以通过按键来输入对应的字符
4
5 内核中 include/linux/input.h
6 驱动中主要填充 input_dev 这个结构体
7 name 名称 phys uniq input_id 设置对应的节点信息
8
9
10 */
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14
15 #include <linux/input.h>
16 #include <linux/bitops.h>
17 #include <linux/interrupt.h> //request_irq
18 #include <mach/irqs.h> //IRQ_EINT
19 #include <linux/gpio.h> //gpio_request
20 #include <mach/gpio.h> //EXYNOS4_GPX3
21 /*
22 用四个按键模拟键盘 把案件值 直接输出标准输出
23
24 可以将开发板上的系统当前终端输入重定向为标准输入
25
26 exec 0 < /dev/tty1
27 */
28
29
30 #define DEVNAME "ldm"
31
32 //
33 struct ldm_info
34 {
35 struct input_dev * pdev;
36 };
37
38 struct ldm_info ldm;
39
40 struct key_info
41 {
42 char * name;
43 int code;
44 int irqno;
45 int gpio_num;
46 };
47
48 //l s enter backspace
49 struct key_info keyinfo[] = {
50 {"KEY_L", KEY_L, IRQ_EINT(26), EXYNOS4_GPX3(2)},
51 {"KEY_S", KEY_S, IRQ_EINT(27), EXYNOS4_GPX3(3)},
52 {"KEY_ENTER", KEY_ENTER, IRQ_EINT(28), EXYNOS4_GPX3(4)},
53 {"KEY_BACKSPACE", KEY_BACKSPACE, IRQ_EINT(29), EXYNOS4_GPX3(5)},
54 };
55
56 //中断处理函数
57 static irqreturn_t key_handler(int irqno, void * arg)
58 {
59 struct key_info *key = (struct key_info *)arg;
60 //产生了中断,在合适时候,发送input_event事件
61
62 int key_stat = gpio_get_value(key->gpio_num);
63
64 //发送事件 发送按键的按键值 和 按键的状态
65 input_report_key(ldm.pdev, key->code, !key_stat);
66 //发送结束事件
67 input_sync(ldm.pdev);
68
69 return IRQ_HANDLED;
70 }
71
72 static int test_init(void)
73 {
74 int ret = 0;
75 int i = 0;
76 int j = 0;
77 printk("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
78
79 //1.创建input_dev 的对象 input_allocate_device();
80 //如果仅仅申请了空间,没有注册 即调用input_allocate_device
81 //那么需要调用input_free_device 函数来释放空间
82 //一旦注册成功,则不需要调用input_free_device来释放空间
83 ldm.pdev = input_allocate_device();
84 if(!ldm.pdev) {
85 printk("input_allocate_device failed\n");
86 ret = -ENOMEM;
87 goto err_input_allocate_device;
88 }
89
90 //2.填充input_dev 这个结构体
91 ////////////相关的信息/////////////////////////
92 ldm.pdev->name = "my test input device";
93 ldm.pdev->phys = "key";
94 ldm.pdev->uniq = "candle";
95 ldm.pdev->id.bustype = 0x1234;
96 ldm.pdev->id.vendor = 0x2222;
97 ldm.pdev->id.product = 0xabcd;
98 ldm.pdev->id.version = 0x3433;
99 ///////////////////////////////////////////////////////
100
101 //这个设备支持哪些事件?
102 //本设备支持的事件的类型,通过set_bit函数来指定位置
103 //所有的位置,都可以通过宏来设置
104 set_bit(EV_KEY, ldm.pdev->evbit); //支持按键类型的事件
105 set_bit(EV_REP, ldm.pdev->evbit);//支持连发
106
107 //针对不同的事件,处理什么样的数据?
108 //eint26~29 GPX3_2 ~5
109 //这个设备支持的按键的键值
110
111 for(i=0; i< ARRAY_SIZE(keyinfo);i++) {
112 set_bit(keyinfo[i].code, ldm.pdev->keybit);
113 }
114
115 //注册设备对象
116 ret = input_register_device(ldm.pdev);
117 if(ret < 0) {
118 printk("input_register_device failed\n");
119 goto err_input_register_device;
120 }
121
122 //注册中断,按下和抬起的时候都要去触发
123 for(i=0;i < ARRAY_SIZE(keyinfo);i++) {
124 ret = request_irq(keyinfo[i].irqno, key_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, DEVNAME, keyinfo + i );
125 if(ret < 0) {
126 printk("request_irq failed\n");
127 goto err_request_irq;
128 }
129 }
130
131 //注册GPIO管脚
132 //int j = 0;
133 for(j=0; j < ARRAY_SIZE(keyinfo);j++) {
134 ret = gpio_request(keyinfo[j].gpio_num, keyinfo[j].name);
135 if(ret < 0) {
136 printk("gpio_request failed\n");
137 goto err_gpio_request;
138 }
139 }
140
141
142 return 0;
143
144 err_gpio_request:
145 for(j = j - 1;j>=0;j--) {
146 gpio_free(keyinfo[j].gpio_num);
147 }
148 err_request_irq:
149 for(i=i-1;i>=0;i--) {
150 free_irq(keyinfo[i].irqno, keyinfo + i);
151 //把之前注册成功的中断号释放掉
152 }
153 input_unregister_device(ldm.pdev);
154 return ret;
155 err_input_register_device:
156 input_free_device(ldm.pdev);
157 err_input_allocate_device:
158 return ret;
159 }
160
161 static void test_exit(void)
162 {
163 int i = ARRAY_SIZE(keyinfo);
164 printk("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);
165
166
167 for(i=i-1; i>=0;i--) {
168 gpio_free(keyinfo[i].gpio_num);
169 free_irq(keyinfo[i].irqno, keyinfo + i);
170 }
171
172 input_unregister_device(ldm.pdev);
173 }
174
175
176 module_init(test_init);
177 module_exit(test_exit);
178 MODULE_LICENSE("GPL");