Keywords: Android capacitive screen TP work queue interrupt multi-point touch Protocol
Platform information:
Kernel: linux2.6/linux3.0
System: Android/android4.0
Platform: s5pv310 (Samsung exynos 4210)
Author: xubin341719 (You are welcome to reprint it. Please note the author)
Reference: http://edsionte.com/techblog/archives/1582
For more information, see
Android capacitive screen (I): Basic Principles of Capacitive Screen
Android capacitive screen (2): basic concepts of driver debugging
Android capacitive screen (III): Driver debugging-Driver Analysis
Capacitor screen driver debugging:
Lower Part of the interrupt-work queue;
Input mechanism;
Linux and Android multi-touch protocols.
I. lower part of the interrupt-working queue
1. Interruption
Let's take a look at Mr. Song Baohua's "Linux device driver development details" about interruptions. I personally think this book is well written. from the beginning to the present, I have gained a lot of knowledge.
The interruption of the device will interrupt the normal scheduling and operation of processes in the kernel. The system's pursuit of higher throughput is bound to require the interruption of service programs to be as short and refined as possible. However, this good wish is often not consistent with reality. In most real systems, the work to be completed is often not short when the interruption arrives, and it may take a lot of time. For example, describes the interrupt handling mechanism of the Linux kernel. In order to find a balance between the interrupted execution time as short as possible and the large amount of work to be done, Linux splits the interrupt handler into two halves: the top half
Half) and bottom half (bottom half ). The top half completes as few urgent functions as possible. It usually simply reads the interrupt status in the register and clears the interrupt mark to "register the interrupt. "Registration interruption" means that the bottom half of the processing program is mounted to the bottom half of the device's execution queue. In this way, the execution speed in the top half is very fast, and more interrupt requests can be served. Now, the focus of interrupt handling is on the bottom half, which is used to complete most tasks of Interrupt events. The bottom half has almost done everything about the interrupt handler and can be interrupted by new interruptions. This is also the biggest difference between the bottom half and the top half, because the top half is often designed to be non-disruptive. The bottom half is not very urgent, and is relatively time-consuming and not executed in the hardware interrupt service program. Although the combination of the top half and the bottom half can improve the system's response capability, it is hard to say that the interrupt processing in the Linux device driver must be divided into two parts. If there are very few interrupted jobs to be processed, they can be completed directly in the top half.
In fact, the above section roughly describes a problem: the interruption should take as short as possible to restore the system to normal debugging as soon as possible, so the interruption triggering and interruption execution should be separated, that is to say, "The upper half (triggered by an interruption) and the lower half (interrupted execution)" are actually the interrupt context we will talk about later. Generally, the lower part includes tasklet and work queue implementation. The interrupt implementation in the touch screen is in the form of work queue, so we will focus on work queue today.
2. Why do I still need a work queue?
The work queue is another way to push the interrupted part of the work back. It can implement jobs that cannot be implemented by some tasklets, such as the work queue mechanism that can sleep. The essence of this difference is that in the working queue mechanism, the pushed work is handed over to a worker thread) (a single core is usually handed over to the default thread events/0 ). Therefore, in this mechanism, the kernel is in the process context (Process
Context. That is to say, the interrupted code executed by the work queue shows some features of the process. The most typical is that it can be rescheduled or even sleep.
For the tasklet mechanism (the same is true for interrupt handlers), the kernel is in the interrupt context during execution. The interrupt context is irrelevant to the process, so you cannot sleep in the interrupt context. Therefore, it is not difficult to select tasklet or work queue to complete the lower half. When the interrupted program needs to sleep, the work queue is undoubtedly your best choice; otherwise, use tasklet.
3. Interrupt Context
The above figure shows the upper and lower parts, that is, the context, which is better understood.
Let's take a look at others' professional explanations:
To understand the interrupt context, let's look back at another familiar concept: process context (this Chinese translation is really not very well understood, and it is much better to use the "Environment ). A general process runs in the user State. If the process is called by the system, the program in the user space enters the kernel space, and the kernel indicates that the process runs in the kernel space. Because the user space and kernel space have different address ing, and the user space processes need to pass many variables and parameters to the kernel, the kernel also needs to save some registers and variables of the user process, this allows the system to return to the user space for further execution after the call is completed. In this way, the process context is generated.
The process context is the value in all the registers of the CPU, the status of the process, and the content in the stack when a process is executed. When the kernel needs to switch to another process (context switch), it needs to save all the statuses of the current process, that is, the context of the current process, so that the process can be executed again, resume the status when switching. All the work done in the above-mentioned work queue is handled by the worker thread, so it can demonstrate some features of the process, such as sleeping. For interruptions, the hardware calls the interrupt handler through a trigger signal and enters the kernel space. In this process, some hardware variables and parameters must also be passed to the kernel. The kernel uses these parameters for interrupt processing, the interrupt context can be understood as the parameters passed by the hardware and the environment that the kernel needs to save, mainly the environment of the interrupted process. Therefore, tasklet In the interrupt context does not have the feature of sleep.
4. Working queue usage
In the kernel, the following struct is used to indicate a specific job:
Struct work_struct {unsigned long pending; // whether the job is waiting for processing struct list_head entry; // link the linked list of all jobs to form the work queue void (* func) (void *); // processing function void * data; // The Void * wq_data parameter passed to the processing function; // internally use the data struct timer_list timer; // The timer used by the delayed working queue };
The linked list of these jobs (struct) is the so-called work queue. When a worker thread is awakened, all jobs on the linked list are executed. When a job is completed, the corresponding work_struct struct is also deleted. When this work linked list does not work, the work thread will sleep.
(1) You can use the following macro to create a task to be pushed back:
DECLARE_WORK(name,void(*func)(void*),void*data);
(2) You can also dynamically create a job using the following macros:
INIT_WORK(struct work_struct*work,void(*func)(void*),void *data);
Similar to tasklet, each job has a specific work queue processing function. The prototype is as follows:
void work_handler(void *data)
The work queue mechanism is mapped to the specific interrupt program, that is, the pushed jobs will be executed in the work queue processing function pointed to by func.
(3) After the work queue processing function is implemented, the schedule_work function is required to schedule the work, as shown in the following figure:
schedule_work(&work);
In this way, the work will be scheduled immediately. Once the working thread is awakened, the work will be executed (because the Task Force column will be executed ).
Ii. Input subsystem overview this article is based on the mini2440 resistive touch screen (III): Linux input subsystem (inputsubsystem ):
Buttons, mouse, touch screen, battery information, etc. are all reported through the input subsystem.
Iii. multi-touch protocols for Linux and Android
To use a powerful multi-touch device, you need a solution to report the detailed finger touch data required by the user layer. The multi-touch protocol described in this document allows the kernel driver to report any multi-finger data information to the user layer.
1. Instructions for use
The single touch information is carried by ABS and sent in a certain order, such as btn_touch, abs_x, abs_y, and sync. The multi-point touch information is carried by abs_mt and sent in a certain order, such as abs_mt_position_x and abs_mt_position_y. Then, a syn_mt_report event is generated by calling input_mt_sync () to mark the end of a vertex, tell the recipient to receive the information of the current finger and prepare to receive the touch information of other fingers. Last call
The input_sync () function reports the start action of the Touch Information and tells the receiver to start receiving a series of multi-touch information.
The Protocol defines a series of abs_mt events. These events are divided into several categories and may only apply one of them. The smallest event set of multi-touch should include abs_mt_touch_major, abs_mt_position_x, and abs_mt_position_y, to achieve multi-point touch. If the device supports the abs_mt_width_major event, this event can provide the contact area for finger touch. The information such as the touch direction can be changed from abs_mt_touch_minor,
Abs_mt_width_minor and abs_mt_orientation are provided. Abs_mt_tool_type indicates the type of a touch device, such as a hand, pen, or other device. Finally, some devices may support abs_mt_tracking_id, which is used to support hardware tracking of Multi-Point information, that is, the line to which the point belongs.
The following is the minimum event set sequence supported by two-point touch: abs_mt_touch_majorabs_mt_position_xabs_mt_position_ysyn_mt_report // report the first vertex; // report the second vertex ............ // Complete multi-point reporting of syn_report // start action
2. Event primitive
The term "Contact" is used to describe the surface of an object directly hitting another object.
Abs_mt_touch_major describes the long axis of the main contact plane. It is in the same unit as X and Y. If the resolution of a plane is x * y, then, the maximum value of abs_mt_touch_major is SQRT (x ^ 2 + y ^ 2)
Abs_mt_touch_minor describes the short axis of the contact surface. If the contact surface is circular, it does not need to be used. Description: the long axis of the contact tool, abs_mt_width_minor. Description: = bool (x> Y)
The above four parameters can be used to generate additional touch information. The ratio of abs_mt_touch_major/abs_mt_width_major can be used to describe the pressure.
Abs_mt_orientation
Abs_mt_position_x coordinates of the contact center x
Abs_mt_position_y y coordinate of the center of the contact surface
Abs_mt_tool_type describes the contact tool type. Many kernel drivers cannot distinguish this parameter, such as finger and pen. If so, this parameter is not required. Currently, the protocol supports mt_tool_finger and mt_tool_pen.
Abs_mt_blob_id: ID of the Shape set, which contains several points to describe a shape. Many drivers do not have shape attributes. this parameter is optional. Abs_mt_tracking_id describes the entire process set from the beginning of contact to the release. If the device does not support this parameter, this parameter is not required.
3. Touch track
Only a few devices can clearly identify the real trackingid. In most cases, trackingid can only identify the process of one touch operation.
4. gestures
The application specified by multi-point touch is to create a gesture action. The touch and width parameters are often used to distinguish the pressure of the finger from the distance between the fingers, in addition, minor class parameters can be used to differentiate the contact surface size (point contact or surface contact) of a device, and orientation can generate rotation events.
5. Based on Linux Kernel support, Android adds the multi-touch feature to its 2.0 source code (the middle layer of android4.0 is different)
Thus, the touch screen is completely divided into two ways in the framework of Android: single-point touch screen single-point mode, multi-point touch screen single-point and multi-point mode.
In Linux input. H, the multi-touch function depends on the following main software bits:
…… #define SYN_REPORT0 #define SYN_CONFIG1 #define SYN_MT_REPORT2 …… #define ABS_MT_TOUCH_MAJOR0x30 #define ABS_MT_TOUCH_MINOR0x31 #define ABS_MT_WIDTH_MAJOR0x32 #define ABS_MT_WIDTH_MINOR0x33 #define ABS_MT_ORIENTATION0x34 #define ABS_MT_POSITION_X0x35 #define ABS_MT_POSITION_Y0x36 #define ABS_MT_TOOL_TYPE0x37 #define ABS_MT_BLOB_ID0x38 ……
The corresponding software bits in Android are defined in rawinputevent. Java:
…… public class RawInputEvent { …… public static final int CLASS_TOUCHSCREEN_MT = 0x00000010; …… public static final int ABS_MT_TOUCH_MAJOR = 0x30; public static final int ABS_MT_TOUCH_MINOR = 0x31; public static final int ABS_MT_WIDTH_MAJOR = 0x32; public static final int ABS_MT_WIDTH_MINOR = 0x33; public static final int ABS_MT_ORIENTATION = 0x34; public static final int ABS_MT_POSITION_X = 0x35; public static final int ABS_MT_POSITION_Y = 0x36; public static final int ABS_MT_TOOL_TYPE = 0x37; public static final int ABS_MT_BLOB_ID = 0x38; …… public static final int SYN_REPORT = 0; public static final int SYN_CONFIG = 1; public static final int SYN_MT_REPORT = 2; ……
In Android, the implementation of multi-point touch is completely separated from the single point in the specific code implementation. In eventhub. cpp of Android code, single screen and multi-screen are determined by the following code segment:
int EventHub::open_device(const char *deviceName) { …… if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask) && test_bit(ABS_MT_POSITION_X, abs_bitmask) && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT; //LOGI("It is a multi-touch screen!"); } //single-touch? else if (test_bit(BTN_TOUCH, key_bitmask) && test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask)) { device->classes |= CLASS_TOUCHSCREEN; //LOGI("It is a single-touch screen!"); } …… }
We know that in touch screen drivers, the probe function usually calls input_set_abs_params to initialize the input_dev struct to the device. These input_dev parameters will be read in eventhub. cpp of Android. As shown above, if our touch screen is to be processed as a multi-point screen, you only need to add the following parameters to input_dev in the driver:
Values (mcs_data.input, values, pdata-> abs_x_min, pdata-> abs_x_max, 0, 0); values (mcs_data.input, values, pdata-> abs_y_min, pdata-> abs_y_max, 0, 0); input_set_abs_params (mcs_data.input, cost, 0, 15, 0, 0); // equivalent to abx_pressure input_set_abs_params (mcs_data.input, cost, 0, 15, 0, 0) of a single screen ); // equivalent to abs_tool_width of a single screen
Because the multi-touch technology needs to collect multiple points and then process them together, the accuracy and integrity of each wave of points must be ensured in software implementation. Therefore, the Linux Kernel provides the input_mt_sync (struct input_dev * input) function. After each vertex of each wave is reported, an input_mt_sync () statement must be followed. When all vertices of this wave are reported, input_sync () is used for synchronization.
For example, a wave reports three points :...... Input_mt_sync (input );...... Input_mt_sync (input );...... Input_mt_sync (input); input_sync (input); Note: even if only one single point event is reported, one input_mt_sync is required.