[Beijing Xunwei] i.MX6ULL Terminator Linux INPUT subsystem experiment Input subsystem

1 Introduction to the input subsystem

The input subsystem is the subsystem that manages the input. Like the pinctrl and gpio subsystems, it is a framework created by the Linux kernel for a certain type of device. The input subsystem processes input transactions. Any input device driver can register to the kernel through the interface provided by the input input subsystem, and interact with the user space using the functions provided by the subsystem. Input devices generally include keyboards, mice, touch screens, etc., which appear as input devices in the kernel.
The input subsystem has a hierarchical structure, divided into three layers in total: hardware driver layer, subsystem core layer, and event processing layer.
(1) The hardware driver layer is responsible for operating specific hardware devices. The code of this layer is for specific drivers and needs to be written by the author of the driver.
(2) The core layer of the subsystem is the link and bridge between the other two layers, providing the interface of the driver layer downwards and the interface of the event processing layer upwards.
(3) The event processing layer is responsible for dealing with the user program, and reporting events from the hardware driver layer to the user program.
Insert picture description here

Figure 1.1

The basic unit of communication between the various layers is the event. The actions of any input device can be abstracted into an event, such as pressing the keyboard, pressing the touch screen, and moving the mouse. Events have three attributes: type, code, and value. All events supported by the input subsystem are defined in input.h, including all supported types and codes supported by the type. The direction of event transmission is hardware driver layer -> subsystem core -> event processing layer -> user space.

2 Input driver writing process

First, let's take a look at what functions are implemented in the input core layer. The input core layer file is input.c, the path: drivers/input/input.c, and some of the contents are as follows:

1767 struct class input_class = {
    
     
1768       .name = "input",
1769       .devnode = input_devnode, 
1770 }; 
...... 
2414 static int __init input_init(void) 
2415 {
    
     
2416       int err;
2417 
2418       err = class_register(&input_class); 
2419       if (err) {
    
     
2420               pr_err("unable to register input_dev class\n"); 
2421               return err; 
2422       } 
2423 
2424       err = input_proc_init(); 
2425       if (err) 
2426           goto fail1; 
2427 
2428       err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), 
2429                   INPUT_MAX_CHAR_DEVICES, "input"); 
2430       if (err) {
    
     
2431           pr_err("unable to register char major %d", INPUT_MAJOR); 
2432           goto fail2; 
2433       } 
2434 
2435   return 0; 
2436 
2437   fail2: input_proc_exit(); 
2438   fail1: class_unregister(&input_class); 
2439       return err; 
2440 } 

On line 2418, an input class is registered. After the system starts, a subdirectory of the input class will be generated in the /sys/class directory, as shown in Figure 2.1:
Insert picture description here

Figure 2.1

On lines 2428 and 2489, a character device is registered, so the input subsystem is essentially a character device driver. The major device number is INPUT_MAJOR, and INPUT_MAJOR is defined in the include/uapi/linux/major.h file, which is defined as follows:
#define INPUT_MAJOR 13
so the input sub The major device number of all devices in the system is 13, and there is no need to register character devices when using the input subsystem to process input devices. We only need to register an input_device with the system.
1. Input_dev structure
input_dev structure is the basic device structure of input devices. Each input driver must be allocated and initialized such a structure. The structure is defined in the include/linux/input.h file and is defined as follows:

121 struct input_dev {
    
     
122        const char *name; 
123        const char *phys; 
124        const char *uniq; 
125        struct input_id id; 
126 
127        unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; 
128 
129        unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; /* 事件类型的位图 */ 
130        unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; /* 按键值的位图 */ 
131        unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; /* 相对坐标的位图 */ 
132        unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; /* 绝对坐标的位图 */ 
133        unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; /* 杂项事件的位图 */ 
134        unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; /*LED 相关的位图 */ 
135        unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];/* sound 有关的位图 */ 
136        unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; /* 压力反馈的位图 */ 
137        unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; /*开关状态的位图 */ 
...... 
189        bool devres_managed; 
190 };

In line 129, evbit represents the input event type. The optional event types are defined in the include/uapi/linux/input.h file. The event types are as follows:

#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 	/* LED */ 
#define 	EV_SND 			0x12 	/* sound(声音) */ 
#define 	EV_REP 			0x14 	/* 重复事件 */ 
#define 	EV_FF 			0x15 	/* 压力事件 */ 
#define 	EV_PWR 			0x16 	/* 电源事件 */ 
#define 	EV_FF_STATUS 	0x17 	/* 压力状态事件 */

Choose different event types according to the different devices used. In the experiments in this chapter, we will use key devices, so we need to select the EV_KEY event type.

Look at the evbit, keybit and other member variables in lines 129 to 137 in the input_dev structure, which are the values ​​of the corresponding different event types. For example, the keybit member corresponding to the key event. The keybit is the bitmap used by the key event. The Linux kernel defines many key values. These key values ​​are defined in the include/uapi/linux/input.h file. The key values ​​are as follows:

215 #define 	KEY_RESERVED 	0 
216 #define 	KEY_ESC 			1 
217 #define 	KEY_1	 		2 
218 #define 	KEY_2 			3 
219 #define 	KEY_3 			4 
220 #define 	KEY_4 			5 
221 #define 	KEY_5 			6 
222 #define 	KEY_6 			7 
223 #define 	KEY_7 			8 
224 #define 	KEY_8 			9 
225 #define 	KEY_9 			10 
226 #define 	KEY_0 			11 
...... 
794 #define 	BTN_TRIGGER_HAPPY39 	0x2e6 
795 #define 	BTN_TRIGGER_HAPPY40 	0x2e7

When we write the input device driver, we need to create an input_dev structure variable first, but we don't need to create it manually. The input subsystem provides the following two functions to create and unregister the input_dev structure variable.

struct input_dev *input_allocate_device(void)	//申请input_dev结构体
void input_free_device(struct input_dev *dev) 	//注销input_dev结构体
input_allocate_device函数不需要参数,直接返回申请到的input_dev结构体。
input_free_device函数用来释放掉前面申请到的input_dev结构体。

After applying for the input_dev structure, you need to initialize and specify the event type and event value according to your own device. For example, the event type of a key device is evbit and the event value is keybit.
After the input_dev structure is initialized, use the input_register_device function to register the input_dev device with the Linux kernel. The function prototype is as follows:
int input_register_device(struct input_dev *dev)
dev: input_dev to be registered.
Return value: 0, input_dev registration succeeded; negative value, input_dev registration failed.
Similarly, when unregistering the input driver, you need to use the input_unregister_device function to unregister the previously registered input_dev. The input_unregister_device function prototype is as follows:
void input_unregister_device(struct input_dev *dev)
To summarize the above content, the input_dev registration process is divided into the following steps:
① First use the input_allocate_device function to apply for an input_dev.
② Initialize the event type and event value of input_dev.
③ The input_register_device() function is a function provided by the input core. This function registers the input_dev structure into the input subsystem core.
④ If the input_register_device() function fails to register, you must call the input_free_device() function to release the allocated space. If the function is successfully registered, the input_unregister_device() function should be called in the uninstall function to unregister the input device structure.
The input_dev registration process example code is as follows:

1 struct input_dev *inputdev; /* input 结构体变量 */ 
2 
3 /* 驱动入口函数 */ 
4 static int __init xxx_init(void) 
5 {
    
     
6  ...... 
7    inputdev = input_allocate_device(); /* 申请 input_dev */ 
8  inputdev->name = "test_inputdev"; /* 设置 input_dev 名字 */ 
9 
10     /*********第一种设置事件和事件值的方法***********/ 
11     __set_bit(EV_KEY, inputdev->evbit); /* 设置产生按键事件 */ 
12     __set_bit(EV_REP, inputdev->repbit); /* 重复事件 */ 
13     __set_bit(KEY_0, inputdev->keybit); /*设置产生哪些按键值 */ 
14     /************************************************/ 
15 
16     /*********第二种设置事件和事件值的方法***********/ 
17     keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
18     keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0); 
19     /************************************************/ 
20 
21     /*********第三种设置事件和事件值的方法***********/ 
22     keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
23     input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0); 
24     /************************************************/ 
25 
26     /* 注册 input_dev */ 
27     input_register_device(inputdev); 
28     ...... 
29     return 0; 
30 } 
31 
32 /* 驱动出口函数 */ 
33 static void __exit xxx_exit(void)
34 {
    
     
35     input_unregister_device(inputdev); /* 注销 input_dev */ 
36     input_free_device(inputdev); /* 删除 input_dev */ 
37 }

Lines 10~23 are all initializing input device events and key values. Three methods are used to set events and key values.
2. The input event is reported
. After the input_dev structure is applied and registered in the input device driver, the input subsystem cannot be used normally because the input device inputs some information, but the Linux kernel still does not know what the input information means and what it means Function, so we need to drive to obtain specific input values, or input events, and then report the input events to the Linux kernel. For example, for a button device, we need to report the button value to the Linux kernel after the button is generated, and the Linux kernel will execute the corresponding function after obtaining the specific button value. Different events report different functions. Let's take a look at the commonly used API functions.
input_event function: used to report the specified event and the corresponding value. The function prototype is as follows:

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

The meanings of function parameters and return values ​​are as follows:
dev: input_dev to be reported.
type: The type of event reported, such as EV_KEY.
code: Event code, which is the key value we registered, such as KEY_0, KEY_1, etc.
value: event value, for example, 1 means the key is pressed, 0 means the key is released.
Return value: None.
The input_event function can be used to report all event types and event values.

input_report_key function: report key events. The specific function content is as follows:

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) 
{
    
     
input_event(dev, EV_KEY, code, !!value); 
} 

It can be seen that the essence of the input_report_key function is the input_event function. Of course, there is no problem with which function is used. It is more appropriate to use the corresponding function for different devices.
There are also some reporting functions corresponding to other events:

void input_report_rel(struct input_dev *dev, unsigned int code, int value) 
void input_report_abs(struct input_dev *dev, unsigned int code, int value)
void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) 
void input_report_switch(struct input_dev *dev, unsigned int code, int value) 
void input_mt_sync(struct input_dev *dev)

input_sync function: used to tell the Linux kernel input subsystem to report the end. The input_sync function essentially reports a synchronization event. The function prototype is as follows:
void input_sync(struct input_dev *dev)
Several functions are listed. Take the key device as an example, let’s see how to use it:

1 /* 用于按键消抖的定时器服务函数 */ 
2 void timer_function(unsigned long arg) 
3 {
    
     
4      unsigned char value;
5 
6      value = gpio_get_value(keydesc->gpio); /* 读取 IO 值 */ 
7      if(value == 0){
    
     /* 按下按键 */ 
8           /* 上报按键值 */ 
9          input_report_key(inputdev, KEY_0, 1); /* 最后一个参数 1,按下 */ 
10             input_sync(inputdev); /* 同步事件 */ 
11         } else {
    
     /* 按键松开 */ 
12             input_report_key(inputdev, KEY_0, 0); /* 最后一个参数 0,松开 */ 
13             input_sync(inputdev); /* 同步事件 */ 
14         } 
15 }

Get the value of the key, and then determine whether the key is pressed, and report the value of the key through the input_report_key function, and the input_sync function indicates the end of the report.

3 input_event structure

The Linux kernel uses the input_event structure to represent all input events. The input_envent structure is defined in the include/uapi/linux/input.h file. The structure content is as follows:

24 struct input_event {
    
     
25         struct timeval time; 
26         __u16 type; 
27       __u16 code; 
28         __s32 value; 
29 };

Let's take a look at each member variable in the input_event structure in turn:
time: time, which is the time when this event occurs, is the timeval structure type, and the timeval structure is defined as follows:

1 typedef long __kernel_long_t; 
2 typedef __kernel_long_t __kernel_time_t; 
3 typedef __kernel_long_t __kernel_suseconds_t; 
4
5 struct timeval {
    
     
6  __kernel_time_t tv_sec; /* 秒 */ 
7  __kernel_suseconds_t tv_usec; /* 微秒 */ 
8 };

The two member variables tv_sec and tv_usec are of long type, which is 32 bits. This must be remembered, and we will use it when we analyze the event report data later.
type: Event type, such as EV_KEY, indicating that this event is a key event, and this member variable is 16 bits.
code: Event code. For example, in the EV_KEY event, code represents the specific key code, such as KEY_0, KEY_1, and so on. This member variable is 16 bits.
value: value. For example, in the EV_KEY event, value is the key value, indicating whether the key has been pressed, if it is 1, it means the key is pressed, if it is 0, it means the key is not pressed or the key is released.
The input_envent structure is very important, because all input devices are finally presented to the user according to the input_event structure, and user applications can obtain specific input events or related values, such as key values, through input_event.

Insert picture description here

Guess you like

Origin blog.csdn.net/BeiJingXunWei/article/details/112171281