Linux input subsystem analysis

  
 


The input subsystem of Linux provides the drive framework for input devices, such as mouse, keyboard, touch screen, etc., which are input devices. The documentation for the input subsystem in Linux is in the Documentation/input directory, and the core code for input is in input.c and input.h.
This article does not cover some of the details of input, such as input_dev->grab, and the timing of keystrokes.
1. input_handle, input_handler, input_dev
input_handle, input_handler, input_dev are the three most important data structures in the input subsystem.
l input_handler is used by the upper application to get input events. The upper application opens the device node of the input device, and then reads and writes the node to obtain mouse movement information, or keyboard information, and the like. The file manipulation function for the device node is provided by input_handler.
l input_dev represents a specific device, such as a mouse, keyboard, and so on.
l For a Linux computer
, there may be multiple mice and multiple keyboards. Each mouse can control the movement of the cursor, and each keyboard can be used normally. This is reflected in the input subsystem as an input_handle associated with multiple input_dev, which can get input messages from multiple input_dev at the same time. At the same time, there may be multiple device nodes in Linux associated with an input device at the same time, so that the application can obtain input information of specific devices such as a mouse and a keyboard through any device node. Therefore, there is a many-to-many relationship between input_dev and input_handler, and these associations are represented by input_handle.
1.1 The establishment of the association between handler and dev
input_handle contains a pointer to input_dev, and a pointer to input_handler, so it can establish a one-to-one association between handler and dev. In the input_handler, there is a linked list h_list that points to all the input_handles associated with the handler. Through these handles, you can find all the devs associated with the handler. Similarly, in input_dev, there is also a linked list h_list that points to all input_handles associated with dev, through which all handlers associated with dev can be found. A complex mesh structure is established between the two linked lists and the input_handle, input_handler and input_dev.
So, what is the rule for establishing association between input_handler and input_dev? That is, under what circumstances do you need to establish an association and when do you need to establish an association? This requires a matching mechanism between the handler and the dev.
Input_handler has two pointers, id_table and blacklist, where blacklist is blacklist, and any matching dev will be forced to filter; and dev matching any one of id_table can be associated with the handler.
const struct input_device_id * id_table;
const struct input_device_id * blacklist;
struct input_device_id {
kernel_ulong_t flags;
__u16 bustype;
__u16 vendor;
__u16 product;
__ u16 version;
kernel_ulong_t evbit [INPUT_DEVICE_ID_EV_MAX /BITS_PER_LONG + 1];
kernel_ulong_t keybit [INPUT_DEVICE_ID_KEY_MAX /BITS_PER_LONG + 1];
kernel_ulong_t relbit [INPUT_DEVICE_ID_REL_MAX /BITS_PER_LONG + 1];
kernel_ulong_t absbit [INPUT_DEVICE_ID_ABS_MAX /BITS_PER_LONG + 1];
kernel_ulong_t mscbit [INPUT_DEVICE_ID_MSC_MAX /BITS_PER_LONG + 1];
kernel_ulong_t ledbit [INPUT_DEVICE_ID_LED_MAX /BITS_PER_LONG + 1];
kernel_ulong_t sndbit [INPUT_DEVICE_ID_SND_MAX /BITS_PER_LONG + 1];
kernel_ulong_t ffbit [INPUT_DEVICE_ID_FF_MAX /BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX /BITS_PER_LONG + 1];
kernel_ulong_t driver_info;
};
In this struct, flags contain some masks:
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVIC E_ID_MATCH_VENDOR 2
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
#define INPUT_DEVICE_ID_MATCH_VERSION 8
These masks are used to match the bus type, vendor, product number, version number, etc. If the selection does not match this information, then driver_info needs to be set to skip the matching process of flags.
The supported event mask is included in evbit[INPUT_DEVICE_ID_EV_MAX /BITS_PER_LONG + 1]. input subsystem supports the following events:
#define EV_SYN 0x00 //EV_SYN for the relative displacement of the end
#define EV_KEY mark a series of 0x01 //input keyboard input
#define EV_REL 0x02 //mouse
absolute coordinate
#define EV_ABS 0x03 //touchscreen #define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11 //such as a keyboard LED control
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
If the handler supports an event, the corresponding bit of evbit will be set. If a certain position of evbit is set, the mask array corresponding to the specific event in the structure will be valid. For example, if EV_KEY is set, then the corresponding keybit array is valid. The array defines the type of the specific key supported by the handler. If the handler and dev need to match, then dev must be able to support all handler-supported events; however, the handler does not have to deal with all the events that dev can provide.
#define MATCH_BIT (bit, max) \\
for (i = 0; i & lt; BITS_TO_LONGS (max); i ++) \\
if ((id- & gt; bit [i] & dev- >bit[i]) != id->bit[i]) \\
break; \\
if (i != BITS_TO_LONGS(max)) \\
continue;
About matching For the specific process, you can refer to the function input_match_device.
2. input_dev
All input_dev are virtual devices whose class name is ”input”, class registration function:
class_register(&input_class);
So, you need to register one first A physical device that has registered input_dev for the parent device.
2.1 Registration of input_dev
The registration of input_dev is done by the input_register_device function.
int input_register_device(struct input_dev *dev)
__set_bit(EV_SYN, dev->evbit); //Force setting EV_SYN bit
//Initialize timer, REP_DELAY is the timeout value of the first delay , REP_PERIOD is the timeout value after the first delay //
init_timer(&dev->timer);
if (!dev->rep[REP_DELAY] && !dev-> ;rep[REP_PERIOD]) {
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
dev->rep[REP_DELAY] = 250;
dev->rep[REP_PERIOD] = 33;
}
//Set the default get key and set key functions
if (!dev->getkeycode) dev->getkeycode = Input_default_getkeycode;
if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode;
//Set the device name, then register the device
snprintf(dev->dev.bus_id, sizeof(dev ->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
device_add(&dev->dev);
list_add_tail (&dev->node, &input_dev_list); //Add the device to the input_dev_list chain Table
//For each registered handler, call input_attach_handler
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler); //See the next section
//proc Related operations
input_wakeup_procfs_readers();

Copyright © Windows knowledge All Rights Reserved