Chinaunix首页 | 论坛 | 博客
  • 博客访问: 301083
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 715
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-20 20:38
文章分类
文章存档

2016年(20)

2015年(56)

分类: 嵌入式

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 能产生这类事件里的哪些小事件:LSENTERLEFTSHIFT */

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个同步事件,应用程序就知道,前面报告的xy这两个事件属于1个消息组,就会将两者联合起来形成一个(xy)坐标。


同理,在入口函数中申请注册的都需要在出口函数中释放。


实验结果如下:

这时候,发现,如果我按下按键s,屏幕上只会出现一次s,如果用键盘操作的话,按住不放,会一直出现很多s。这中现象称为可重复类事件,用下面的语句设置即可:

set_bit(EV_REP, button_dev->evbit);


既然我们在开发板上面已经实现了LSENTERLEFTSHIFT按键,如何用按键在开发板上面输入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个字节,code2个字节,value4个字节。

当第一次按键,按下松开L的时候,显示4行信息。

分析第一行:按键类EV_KEY在内核中定义为0x01,没有错误。KEY_L在内核中用宏定义为38,用十六进制表示为0x26,没有错误。value1,表示按下,没有错误。

第二行为同步类事件。第三行为松开时的信息,与第一行相比,只有value值不同。第四行也同样为同步类事件。


通过这4行信息,可以得出结论:我们按下松开了L键。

阅读(1060) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~