The Linux input subsystem (subsystem) is implemented from top to bottom by three layers: input subsystem Event processing layer (EventHandler), input subsystem core layer (Inputcore), and input subsystem device driver layer.
For the input subsystem device driver layer, the main implementation of the hardware device read and write access, interrupt settings, and the hardware-generated events into the core layer defined by the specification submitted to the event processing layer.
For the core layer, specifications and interfaces are provided for the device driver layer. As long as the device driver is concerned with how to drive the hardware and obtain the hardware data (such as the pressed key data), and then call the interface provided by the core layer, the core layer will automatically submit the data to the event processing layer.
For the event processing layer, it is the user-programmed interface (the device node) and handles the data processing of the drive-level submissions.
The framework structure for the Linux input subsystem is shown in 1:
previously our driver opened a specific device file "/dev/ Buttons "/dev/buttons". Usually open the original file, such as " dev/tty* " , but direct "scanf () Span class= "FONTSTYLE0" to get the key input. The
previously written drivers are only self-employed, not generic. To write a generic driver, let the other application
program "Seamless" use, that is, there is no need to modify the application of others. This requires the use of out-of-the-box drivers to put the drivers associated with the
device into the driver architecture in the kernel. This ready-made driver is "input subsystem --
Input subsystem".
The input subsystem not only makes the driver writer more comfortable, but also lets the application layer writer do not need specific changes, corresponding to the new or you write driver.
before we wrote some input devices (keyboards, mice, etc.) are driven by the use of character devices, mixed equipment processing. The problem is that the Linux open source community has seen this large number of input devices so fragmented, there is a mechanism for wood to implement a decentralized, different types of input devices can be unified driver, so the input subsystem appears
Using the input subsystem provided by the kernel, the code of the application layer will not be confused if the driver is invoked according to the interface of the input subsystem specification.
Drive Layer
Convert the underlying hardware input into a unified event form and report to the input core.
input Subsystem Core layer
It provides input device registration and operation interface for the driving layer, such as: Input_register_device; notifies event handlers to handle events, and generates corresponding device information under/proc.
Event Processing Layer
The main thing is to interact with the user space (in Linux, all devices are treated as files in the user space, because the FoPs interface is provided in the generic driver, and the corresponding device file nod is generated in/dev, which is done in the input subsystem by the event processing layer).
1. Core layer of the system
Key Features
- Registering a master device number
- For SWI Enter the Open function for the first layer processing, and through the secondary device number selection handler into the second layer open, that is, the real open file_operation, and return the file_opration of the FD
- The Input_register_device and Input_register_handler functions are provided for registering device and handler respectively.
2.handler Layer (Event processing layer)
Handler layer is a pure software layer, contains different solutions, such as keyboard, mouse, gamepad, etc., but there is no design to the hardware of the operation
For different solutions, there is a struct named Input_handler, which contains the following key members
. id_table a table that holds the device ID supported by the handler (in fact the Ev_xxx event is stored internally to determine if the device supports the event)
. FoPs the file_operation of the handler
. Connect connects the handler with the supported device functions
. Disconnect disconnecting the connection
The. Event event handler function, which lets device invoke
H_list is also a linked list that holds the handler to the intermediate stations of all supported device: pointers to handle structures
3.device layer (drive layer)
Device is a pure hardware operation layer, including different hardware interface processing, such as GPIO, etc.
For each of the different specific hardware operations, there are different input_dev structures
The structure also contains a h_list
With the layered design of the input subsystem, we write the driver only with the Tube drive layer, and the application layer only opens the corresponding input subsystem device with the tube. This will not have to drive the writer to tell the app writer which device to open.
Core Layer
Drivers/input.c So the code of the input subsystem is in this C file.
Look at a driver from the entry function to start viewing.
Here is the registration of a main device number "input_major" for the character device, the name "INPUT", its
The File_operations structure is "input_fops". There is only one ". Open" function in this structure. Obviously this open function is doing more of the other things.
Source analysis is not the time, and now is also the source of the reading, or all of these functions as STM32 library functions to use, first use up more in line with the reality of the need.
below we only know that using the input subsystem method, we only need to write the hardware driver layer code, then, in what way to write it?
entrance function: I believe that as long as the person who has learned the microcontroller should be able to imitate the other people's call way to achieve their own function
Export function:
In this way, more concise than the previous operation, the implementation of the input subsystem.
Experimental phenomena:
When the driver is not loaded as long as the event0, after loading the driver has Event1
cat Tty1 after the key (note here, the key press, you need to enter the ENTER key to display, corresponding to our key S4):
the standard input and standard output as well as standard errors here are our serial console/dev/console
Now redirect the tty1 to standard input:
As you can see, the first line of l^h^h is my keyboard input, at which point L (lowercase l) of the keyboard can be recognized, but I press the BACKSPACE key of the keyboard to print ^h.
At this point, we press 2440 on the top of the button followed by L then the last enter key, sure enough, we achieved the function of LS by the key, listing the current directory file information. We also have a S5 shift key, and when we hold down the SHIFT key, I press L and S to see the uppercase L and S. Prove that our drive experiment was successful.
Complete code:
/*Reference DRIVERS\INPUT\KEYBOARD\GPIO_KEYS.C*/#include<linux/module.h>#include<linux/version.h>#include<linux/init.h>#include<linux/fs.h>#include<linux/interrupt.h>#include<linux/irq.h>#include<linux/sched.h>#include<linux/pm.h>#include<linux/sysctl.h>#include<linux/proc_fs.h>#include<linux/delay.h>#include<linux/platform_device.h>#include<linux/input.h>#include<linux/irq.h>#include<asm/gpio.h>#include<asm/io.h>#include<asm/arch/regs-gpio.h>structpin_desc{intIRQ; Char*name; unsignedintpin; unsignedintKey_val;};structPin_desc pins_desc[4] ={{irq_eint0,"S2", s3c2410_gpf0, key_l}, {irq_eint2,"S3", S3C2410_GPF2, key_s}, {irq_eint11,"S4", S3C2410_GPG3, Key_enter}, {irq_eint19,"S5", S3c2410_gpg11, Key_leftshift},};Static structInput_dev *Buttons_dev;Static structPIN_DESC *irq_pd;Static structtimer_list Buttons_timer;StaticIrqreturn_t BUTTONS_IRQ (intIrqvoid*dev_id) { /*10ms after start timer*/IRQ_PD= (structPIN_DESC *) dev_id; Mod_timer (&buttons_timer, jiffies+hz/ -); returnIrq_retval (irq_handled);}Static voidButtons_timer_function (unsignedLongdata) { structPin_desc * Pindesc =IRQ_PD; unsignedintPinval; if(!Pindesc)return; Pinval= S3c2410_gpio_getpin (pindesc->pin); if(pinval) {/*release: Last parameter: 0-Release, 1-Press*/input_event (Buttons_dev, Ev_key, Pindesc->key_val,0);//report a new input eventInput_sync (Buttons_dev);//Synchronization Events } Else { /*Press the*/input_event (Buttons_dev, Ev_key, Pindesc->key_val,1); Input_sync (Buttons_dev); }}Static intButtons_init (void){ inti; /*1. Assigning a INPUT_DEV structure*/Buttons_dev=Input_allocate_device (); /*2. Settings*/ /*2.1 What kinds of events can be generated*/set_bit (Ev_key, Buttons_dev->evbit);//Key ClassSet_bit (Ev_rep, buttons_dev->evbit);//The key can be repeated, that is, when the press does not release, always keep this value /*2.2 What events in this type of operation can be generated: L,s,enter,leftshit*/set_bit (key_l, Buttons_dev-keybit); Set_bit (key_s, Buttons_dev-keybit); Set_bit (Key_enter, Buttons_dev-keybit); Set_bit (Key_leftshift, Buttons_dev-keybit); /*3. Registration*/Input_register_device (Buttons_dev); /*4. Hardware-related Operations*/Init_timer (&Buttons_timer); Buttons_timer.function=buttons_timer_function; Add_timer (&Buttons_timer); for(i =0; I <4; i++) {REQUEST_IRQ (PINS_DESC[I].IRQ, BUTTONS_IRQ, Irqt_bothedge, Pins_desc[i].name,&Pins_desc[i]); } return 0;}Static voidButtons_exit (void){ inti; for(i =0; I <4; i++) {FREE_IRQ (PINS_DESC[I].IRQ,&Pins_desc[i]); } del_timer (&Buttons_timer); Input_unregister_device (Buttons_dev); Input_free_device (Buttons_dev); }module_init (Buttons_init); Module_exit (Buttons_exit); Module_license ("GPL");View Code
Linux input Subsystem