Input devices have common features: interrupt driver + character IO. Based on the hierarchical idea, Linux kernel extracts the public parts of these devices. Based on the interface provided by cdev, an input subsystem is designed. All devices constructed by the input subsystem use the main device number 13. At the same time, the input subsystem also supports the automatic creation of device files. These files use blocked IO reader and writer. Form, created under "/dev/input/". As shown in the figure below. The input subsystem in the kernel is divided into device driver layer, input core layer and event processing layer from bottom to top. Because the events reported by each input device are different, in order for the application layer to recognize the reported events well, the kernel also encapsulates a standard interface for the application layer to describe an event, which is in "/include/upai/linux/input".
- Device driver layer is a hardware-related implementation and the main part of driver development.
- The input core layer mainly provides some APIs for device driver layer to call. The data reported by these API device driver layer can be transferred to event processing layer.
- Event processing layer is responsible for creating device files and delivering reported events to user space.
The Use of input
The input object describes an input device, including the events it may report. These events are described by bitmaps. The corresponding tools provided by the kernel help us build an input object. You can refer to the kernel document "Documentation/input/input-programming.txt", which describes the use of the input subsystem in detail.
//input device object 121 struct input_dev { 122 const char *name; 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)]; 135 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; 136 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; 137 unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; 155 162 unsigned long key[BITS_TO_LONGS(KEY_CNT)]; 163 unsigned long led[BITS_TO_LONGS(LED_CNT)]; 164 unsigned long snd[BITS_TO_LONGS(SND_CNT)]; 165 unsigned long sw[BITS_TO_LONGS(SW_CNT)]; 166 172 struct input_handle __rcu *grab; 179 180 struct device dev; 181 182 struct list_head h_list; 183 struct list_head node; 190 };
struct input_dev
--122--> this name Not the device name. input The device name of the subsystem is specified in the subsystem source code, not here.
--129--> Device-supported input event bitmaps, EV_KEY,EV_REL, etc
--130--> For keystroke events, device-supported input sub-event bitmaps
--132--> For relative coordinate events, device-supported relative coordinate sub-event bitmaps
--133--> For absolute coordinate events, device-supported absolute coordinate sub-event bitmaps
--134--> Subevent Bitmaps Supported by Hybrid Devices
--180-->It means that this is a device.
--182-->h_list Is used to link correlation handle Linked list
--183-->node Used to link to others input_dev Linked list
Distribution/Release
//drivers/input/input.c //Create an input object struct input_dev *input_allocate_device(void); //Release an input object void input_free_device(struct input_dev *dev);
Initialization
Initialization of an input object is the main task of writing drivers using the input subsystem. The kernel specifies some common input events of common input devices in the header file "include/uapi/linux/input.h". These macros and arrays are our tools for initializing input objects. These macros are used for event parsing and event registration in user space at the same time. They can be regarded as communication protocols between driver and user space. Therefore, it is very important to understand the significance of these macros. In the input subsystem, the occurrence of each event is described by event (type) - > sub-event (code) - > value (value). For example, key event - > key F1 sub-event - > key F1 sub-event triggered value is high level 1. Note that events and sub-events and values are mutually reinforcing. Only when event EV_KEY is registered can sub-event BTN_0 be registered, which is meaningful.
Here is the event type agreed upon by the kernel, which corresponds to the type field of the event object in the application layer
Here are the types of keystroke events, and you can see the definition of PC keys.
In addition to describing common events, the kernel also provides tools to properly populate these events into bitmaps describing events in input objects.
//First kind //This is a great way to register multiple events when a contract is in place. button_dev->evbit[0] = BIT_MASK(EV_KEY); button_dev->keybit[BIT_WORD(BTN_0|BTN_1)] = BIT_MASK(BTN_0|BTN_1);
//Second kinds //Usually used to register only one event set_bit(EV_KEY,button_dev.evbit); set_bit(BTN_0,button_dev.keybit);
Registration/cancellation
After initializing an input object, you need to register it with the kernel
//Register input objects to the kernel int input_register_device(struct input_dev *dev); //Log off an input object from the kernel void input_unregister_device(struct input_dev *dev);
Driver layer reports events
At the right time (because the input is eventually represented by interrupts, so it is usually in the driver's interrupt handler) the driver can report registered events and multiple events at the same time. Here is the API provided by the kernel.
//Report the specified event + sub-event + value void input_event(struct input_dev *dev,unsigned int type,unsigned int code,int value); //Report key value void input_report_key(struct input_dev *dev,unsigned int code,int value); //Report absolute coordinates void input_report_abs(struct input_dev *dev,unsigned int code,int value); //Reporting synchronization events void input_report_rel(struct input_dev *dev,unsigned int code,int value); //Synchronize all reports void input_sync(struct input_dev *dev);
There are two points to note in reporting incidents:
- The report functions don't really report, but just prepare to report, sync will really report the event just reported to the input core.
- The input core will decide and then report the event processing layer, so for key events, we must first report 1 and then report 0 (or vice versa), not only report 1 or 0, so the core will think that an event has been triggered many times and reported only once, although we really pressed many times.
Application Layer Analysis
Event processing layer will eventually organize all report-driven events into a struct input_value[] and report them to the application layer. When the application layer retrieves the reported events from the corresponding device files, it should pay attention to:
- The number of elements received from the array is one more empty element than the underlying one, similar to the last empty element when writing of_device_id[], which the application layer should pay attention to when parsing.
- Event processing layer does not cache received events. If new events come, even if the old events are not read, they will be overwritten, so the application needs to read them in time.
As mentioned earlier, the macro in "include/uapi/linux/input.h" is a communication protocol shared by application layer and driver layer, so when the application layer parses the received struct input_value object, it only needs "include < linux/input.h>" to use the macro.
/* * The event structure itself */ struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; };
Template
The following template first uses the input subsystem to report key events, and then reads them at the application level.
input key device driver
/{
key@26{
compatible = "xj4412,key";
interrupt-parent = <&gpx1>;
interrupts = <2 2>;
};
};
static struct input_dev *button_dev; static int button_irq; static int irqflags; static irqreturn_t button_interrupt(int irq, void *dummy) { input_report_key(button_dev, BTN_0, 0); input_report_key(button_dev, BTN_0, 1); input_sync(button_dev); return IRQ_HANDLED; } static int button_init(void) { request_irq(button_irq, button_interrupt,irqflags, "button", NULL)) ; button_dev = input_allocate_device(); button_dev->name = "button"; button_dev->evbit[0] = BIT_MASK(EV_KEY); button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); input_register_device(button_dev); return 0; } static int button_exit(void) { input_free_device(button_dev); free_irq(button_irq, button_interrupt); return 0; } static int key_probe(struct platform_device *pdev) { struct resource *irq_res; irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if(irq_res){ button_irq = irq_res->start; irqflags = irq_res->flags & IRQF_TRIGGER_MASK; }else{ return -EINVAL; } return button_init(); } static int key_remove(struct platform_device *dev) { return button_exit(); } struct of_device_id of_tbl[] = { {.compatible = "xj4412,key",}, {}, }; MODULE_DEVICE_TABLE(of, of_tbl); struct platform_driver key_drv = { .probe = key_probe, .remove = key_remove, .driver.name = "keydrv", .driver.of_match_table = of_tbl, }; module_platform_driver_register(key_drv); MODULE_LICENSE("GPL");
Application Layer Gets Key Values
#include <linux/input.h> struct input_event { struct timeval time; unsigned short type; unsigned short code; int value; }; int main(int argc, char * const argv[]) { int fd = 0; struct input_event event[3] = {0}; //3!!! The driver uploads two events, and the third is used to empty the element int ret = 0; fd = open(argv[1],O_RDONLY); while(1){ ret = read(fd,&event,sizeof(event)); printf("ret:%d,val0:%d,val1:%d,val12:%d\n",ret,event[0].value,event[1].value,event[2].value); //2!!! The last one is empty sleep(1); } return 0; }