分类: 嵌入式
2015-06-01 19:11:22
输入子系统
15年5月14日13:53:55
代码如下:
1
#include
2
#include
3
4
#include
5
#include
6
#include
7
#include
8
#include
9
#include
10
#include
11
#include
12
#include
13
#include
14
#include
15
#include
16
#include
17
18
#include
19
#include
20
#include
21
22 static struct input_dev *button_dev;
23 static struct pin_desc *irq_pd;
24 static struct timer_list buttons_timer;
25
26 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
27 static volatile int ev_press = 0;
28
29 static struct fasync_struct *button_async;
30
31 struct pin_desc{
32 int irq;
33 char *name;
34 unsigned int pin;
35 unsigned int key_val;
36 };
37
38 struct pin_desc pin_desc[4] = {
39 {IRQ_EINT0, "S2", S3C2410_GPF0, KEY_L},
40 {IRQ_EINT2, "S3", S3C2410_GPF2, KEY_S},
41 {IRQ_EINT11, "S4", S3C2410_GPG3, KEY_ENTER},
42 {IRQ_EINT19, "S5", S3C2410_GPG11, KEY_LEFTSHIFT},
43 };
44
45 static irqreturn_t buttons_irq(int irq, void *dev_id)
46 {
47 irq_pd = (struct pin_desc *)dev_id;
48 mod_timer(&buttons_timer, jiffies + HZ/100);
49 return IRQ_RETVAL(IRQ_HANDLED);
50 }
51
52 void buttons_timer_function(unsigned long data)
53 {
54 struct pin_desc * pindesc = irq_pd;
55 unsigned int pinval;
56
57 if(!pindesc)
58 return;
59
60 pinval = s3c2410_gpio_getpin(pindesc->pin);
61
62 if (pinval)
63 {
64 input_event(button_dev, EV_KEY, pindesc->key_val, 0);
65 input_sync(button_dev);
66 }
67 else
68 {
69 input_event(button_dev, EV_KEY, pindesc->key_val, 1);
70 input_sync(button_dev);
71 }
72
73 ev_press = 1;
74 wake_up_interruptible(&button_waitq);
75
76 kill_fasync (&button_async, SIGIO, POLL_IN);
77 }
78
79 static int buttons_init(void)
80 {
81 int i;
82 /* 1.分配input_dev结构体 */
83 button_dev = input_allocate_device();
84
85 /* 2.设置 */
/* 2.1 能产生哪一类事件 */
86 set_bit(EV_KEY, button_dev->evbit); //按键类事件
87 set_bit(EV_REP, button_dev->evbit); //可重复类事件
88
/* 2.2 能产生这类事件里的哪些小事件:L,S,ENTER,LEFTSHIFT */
89 set_bit(KEY_L, button_dev->keybit);
90 set_bit(KEY_S, button_dev->keybit);
91 set_bit(KEY_ENTER, button_dev->keybit);
92 set_bit(KEY_LEFTSHIFT, button_dev->keybit);
93
94 /* 3.注册 */
95 input_register_device(button_dev);
96
97 /* 4.硬件相关操作 */
98 init_timer(&buttons_timer);
99 buttons_timer.function = buttons_timer_function;
100 add_timer(&buttons_timer);
101
102 for(i = 0; i < 4; i++)
103 {
104 request_irq(pin_desc[i].irq, buttons_irq, IRQT_BOTHEDGE, pin_desc[i].name, &pin_desc[i]);
105 }
106 return 0;
107 }
108
109 static void buttons_exit(void)
110 {
111 int i;
112 for(i = 0; i < 4; i++)
113 {
114 free_irq(pin_desc[i].irq, &pin_desc[i]);
115 }
116
117 del_timer(&buttons_timer);
118 input_unregister_device(button_dev);
119 input_free_device(button_dev);
120
121 return 0;
122 }
123
124 module_init(buttons_init);
125 module_exit(buttons_exit);
126
127 MODULE_LICENSE("GPL");
怎么写符合输入子系统框架的驱动程序?
(1)首先分配一个input_dev结构体,用
static struct input_dev *button_dev;
button_dev = input_allocate_device(void); 来分配。
注销的话用 void input_free_device(struct input_dev *dev); 来释放。
input_dev结构体如下所示,其中包含了能产生哪一类事件(大事件)等信息。
struct input_dev {
void *private;
const char *name;
const char *phys;
const char *uniq;
struct input_id id;
unsigned long evbit[NBITS(EV_MAX)]; //表示能产生哪一类事件(大事件)
unsigned long keybit[NBITS(KEY_MAX)]; //表示能产生哪些按键
unsigned long relbit[NBITS(REL_MAX)]; //表示能产生哪些相对位移事件(x y 滑轮等)
unsigned long absbit[NBITS(ABS_MAX)]; //表示能产生哪些绝对位移事件
unsigned long mscbit[NBITS(MSC_MAX)];
unsigned long ledbit[NBITS(LED_MAX)];
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
unsigned int repeat_key;
struct timer_list timer;
int state;
int sync;
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
unsigned long key[NBITS(KEY_MAX)];
unsigned long led[NBITS(LED_MAX)];
unsigned long snd[NBITS(SND_MAX)];
unsigned long sw[NBITS(SW_MAX)];
int absmax[ABS_MAX + 1];
int absmin[ABS_MAX + 1];
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
struct input_handle *grab;
struct mutex mutex; /* serializes open and close operations */
unsigned int users;
struct class_device cdev;
union { /* temporarily so while we switching to struct device */
struct device *parent;
} dev;
struct list_head h_list;
struct list_head node;
};
(2)设置。
设置能产生哪一类事件(大事件), 并且能产生这类事件里的哪些事件(小事件)。
比如本例中,首先设置能产生按键类事件(大事件),然后设置在按键类事件(大事件)里面能产生哪些小事件,比如说“L” “S”“ENTER”“LEFTSHIFT”等小事件。
其中,大事件包含在第一步的input_dev中,有按键类事件,相对位移类事件,绝对位移类事件等。
用 set_bit(EV_KEY, button_dev->evbit);
来设置。
小事件用 set_bit(KEY_L, button_dev->keybit);
set_bit(KEY_S, button_dev->keybit);
set_bit(KEY_ENTER, button_dev->keybit);
set_bit(KEY_LEFTSHIFT, button_dev->keybit);
来设置。
下面列出evbit包含哪些大事件:
unsigned long evbit[NBITS(EV_MAX)]; 包含下面几个事件:
/*
* Event types
*/
#define EV_SYN 0x00 //同步类
#define EV_KEY 0x01 //按键类
#define EV_REL 0x02//相对位移类(鼠标)
#define EV_ABS 0x03//绝对位移类(触摸屏)
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
下面列出keybit包含哪些小事件:
unsigned long keybit[NBITS(KEY_MAX)]; //表示能产生哪些按键
/*
* Keys and buttons
*/
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
#define KEY_5 6
#define KEY_6 7
#define KEY_7 8
#define KEY_8 9
#define KEY_9 10
#define KEY_0 11
#define KEY_TAB 15
#define KEY_Q 16
#define KEY_W 17
#define KEY_E 18
#define KEY_R 19
#define KEY_SPACE 57
#define KEY_CAPSLOCK 58
#define KEY_F1 59
#define KEY_F2 60
#define KEY_F3 61
#define KEY_F4 62 。。。。。。。。。。。。
键盘上面的按键全部包括了,我只是截取一部分演示一下。
(3)注册。把申请分配的input_dev结构体注册到内核中,用下面的语句:
input_register_device(button_dev);
(4)硬件相关的操作:定时器,申请中断,在中断服务程序里面上报事件(有数据产生时,调用input_event来上报)。代码如下:
input_event(button_dev, EV_KEY, pindesc->key_val, 0);
input_sync(button_dev);
第二行为报告一个同步事件,它表示前面报告的消息属于1个消息组,例如,用户在报告完x坐标后,又报告y坐标,之后报告1个同步事件,应用程序就知道,前面报告的x,y这两个事件属于1个消息组,就会将两者联合起来形成一个(x,y)坐标。
同理,在入口函数中申请注册的都需要在出口函数中释放。
实验结果如下:
这时候,发现,如果我按下按键s,屏幕上只会出现一次s,如果用键盘操作的话,按住不放,会一直出现很多s。这中现象称为可重复类事件,用下面的语句设置即可:
set_bit(EV_REP, button_dev->evbit);
既然我们在开发板上面已经实现了L,S,ENTER,LEFTSHIFT按键,如何用按键在开发板上面输入ls等命令?
用ps查看进程,开发板接受命令的是-sh文件,查看-sh文件打开了哪些文件:
可以看到,打开了0标准输入1标准输出2标准错误三个文件。通过exec 0,把shell程序的的0号文件(通用输入文件)改为从/dev/tty1输入。这样就可以用开发板的按键输入ls命令了。结果如下:
如果出现问题,下面给出了一种调试手段:
# hexdump /dev/event1
秒 微秒 类 code value
0000000 006d 0000 00fc 0009 0001 0026 0001 0000 //按下
0000010 006d 0000 0108 0009 0000 0000 0000 0000 //同步类事件
0000020 006d 0000 98f7 000b 0001 0026 0000 0000 //松开
0000030 006d 0000 98ff 000b 0000 0000 0000 0000 //同步类事件
上面显示的是input_event结构体,秒为4个字节,微秒为4个字节,类为2个字节,code为2个字节,value为4个字节。
当第一次按键,按下松开L的时候,显示4行信息。
分析第一行:按键类EV_KEY在内核中定义为0x01,没有错误。KEY_L在内核中用宏定义为38,用十六进制表示为0x26,没有错误。value为1,表示按下,没有错误。
第二行为同步类事件。第三行为松开时的信息,与第一行相比,只有value值不同。第四行也同样为同步类事件。
通过这4行信息,可以得出结论:我们按下松开了L键。