linux的输入子系统---按键事件

struct input_dev {
	const char *name;   // 设备名字
	const char *phys;
	const char *uniq;
	struct input_id id;    // 用于匹配事件处理层handler

	unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

	unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
	unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
	unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
	unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
	unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
	unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
	unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
	unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
	unsigned long swbit[BITS_TO_LONGS(SW_CNT)];

	unsigned int hint_events_per_packet;

	unsigned int keycodemax;
	unsigned int keycodesize;
	void *keycode;

	int (*setkeycode)(struct input_dev *dev,
			  const struct input_keymap_entry *ke,
			  unsigned int *old_keycode);
	int (*getkeycode)(struct input_dev *dev,
			  struct input_keymap_entry *ke);

	struct ff_device *ff;

	unsigned int repeat_key;
	struct timer_list timer;

	int rep[REP_CNT];

	struct input_mt_slot *mt;
	int mtsize;
	int slot;
	int trkid;

	struct input_absinfo *absinfo;

	unsigned long key[BITS_TO_LONGS(KEY_CNT)];
	unsigned long led[BITS_TO_LONGS(LED_CNT)];
	unsigned long snd[BITS_TO_LONGS(SND_CNT)];
	unsigned long sw[BITS_TO_LONGS(SW_CNT)];

	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 __rcu *grab;

	spinlock_t event_lock;
	struct mutex mutex;

	unsigned int users;
	bool going_away;

	bool sync;

	struct device dev;

	struct list_head	h_list;
	struct list_head	node;
};

这是输入设备很重要的结构体,我们在驱动程序中需要分配一个这个设备,然后填充它。

那么,名字叫输入设备,那么到底我们写哪些驱动的时候可以采用这种定义一个输入设备的方法来写驱动,网上有很多这种输入子系统的框架,基本都说了鼠标、键盘液晶屏使用这种方法来编写驱动,so,接下来就一步一步来熟悉这种方式:

1.看这个结构体的成员:

unsigned long evbit[BITS_TO_LONGS(EV_CNT)];

这是在结构体的一个成员,定义的一个数组,

/*
 * Event types
 */

#define EV_SYN			0x00       //同步事件     位0
#define EV_KEY			0x01       //按键事件     位1
#define EV_REL			0x02       //相对坐标     位2
#define EV_ABS			0x03       //绝对坐标     位3
#define EV_MSC			0x04       //其他         位4
#define EV_SW			0x05       //开关         位5
#define EV_LED			0x11       //按键/设备灯  位17
#define EV_SND			0x12       //声音/警报    位18
#define EV_REP			0x14       //重复         位20
#define EV_FF			0x15       //力反馈       位21
#define EV_PWR			0x16       //电源         位22
#define EV_FF_STATUS		0x17       //力反馈状态   位23
#define EV_MAX			0x1f       //支持31个事件             
#define EV_CNT			(EV_MAX+1)

一个设备可以支持多个事件类型,我们把成员evbit相应的位设置为1表示就支持上面的相应的功能。那位什么在input_dev里边定义evbit是一个数组:这里就比较神奇了:

可以理解为:     evbit[0]   ---------  表示位0-31

                             evbit[1]   ---------  表示位32-63

                             每一个数组成员代表的不同的位的分组,位什么这样玩,当然这样肯定有好处,后边的input_dev结构体成员keybit,  relbit,  absbit等等,都可以采用这种方法。

1.按键事件

            这里我们就实现一个简单的按键作为输入,使用输入子系统机制来编写按键驱动

   大致驱动框架就是,我们按一下键,产生一个中断,执行中断服务程序,在服务程序里边,我们使用

void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value)

使用这个函数上报一个输入事件,函数内容:

void input_event(struct input_dev *dev,
		 unsigned int type, unsigned int code, int value)
{
	unsigned long flags;

	if (is_event_supported(type, dev->evbit, EV_MAX)) {

		spin_lock_irqsave(&dev->event_lock, flags);
		add_input_randomness(type, code, value);
		input_handle_event(dev, type, code, value);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}
当然我们同时要使用 static inline void input_sync(struct input_dev *dev)
还有一个input_event结构体:
struct input_event {
	struct timeval time;
	__u16 type;
	__u16 code;
	__s32 value;
};

这个就结构体便是上报后,在应用层我们可以接收到的数据,下面贴上测试程序:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
  
  int main(void)
  {
          int buttons_fd;
          int key_value,i=0, count;
  
          struct input_event ev_key;
         buttons_fd = open("/dev/event0", O_RDWR);
          if (buttons_fd < 0) {
              printf("open device buttons error!!\n");
              exit(1);
          }
  
          for (;;) {
              count = read(buttons_fd, &ev_key, sizeof(struct input_event));
  
              for(i = 0; i < (int)count/sizeof(struct input_event); i++)
                  if(EV_KEY == ev_key.type)
                      printf("type:%d,code:%d,value:%d\n", ev_key.type, ev_key.code, ev_key.value);
  
              if(EV_SYN == ev_key.type)
                  printf("syn event\n\n");
  
          }
 	close(buttons_fd);
 	return 0;
 }
收到的数据打印如下:

type:1,code:38,value:1
syn event

type:1,code:38,value:0
syn event

type:1,code:42,value:1
syn event

type:1,code:42,value:0
syn event

type:1,code:38,value:1
syn event

type:1,code:38,value:0
syn event

type:1,code:31,value:1
syn event

type:1,code:31,value:0
syn event

type:1,code:28,value:1
syn event

type:1,code:28,value:0








你可能感兴趣的:(_linux的输入子系统)