2. Touch Screen Driver Analysis
2.1 Overview
Touch screen drivers do not distinguish between resistance and tolerance, but between single-point touch and multi-point touch. A typical touch screen driver is based on the input subsystem. Here we will analyze the driver file s3c2410_ts.c (in the old kernel, it is a great change. If you are interested, you can check it out. This file is named S3C2410, but it also supports S3C2440 and cloud6410.
2.2 driver analysis (s3c2410_ts.c)
L initialization module
Staticstruct platform_driver initi_ts_driver = {
. Driver = {
. Name = "Samsung-ts ",
. Owner = this_module,
# Ifdefconfig_pm
. PM = & cloud_ts_pmops,
# Endif
},
. Id_table = s3cts_driver_ids,
. Probe = s3c2410ts_probe,
. Remove =__ devexit_p (s3c2410ts_remove ),
};
Staticint _ init s3c2410ts_init (void)
{
Returnplatform_driver_register (& initi_ts_driver );
}
It can be seen that the driver is mounted to the platform bus, constructs a platform_driver struct, and then registers
L probe function,
Static int _ devinit s3c2410ts_probe (struct platform_device * pdev)
{
/* Obtain the clock resource for the ADC */
TS. Clock = clk_get (Dev, "ADC ");
/* Obtain touch screen interrupt resources */
TS. irq_tc = ret = platform_get_irq (pdev, 0 );
/* Obtain Io memory resources */
Res = platform_get_resource (pdev, ioresource_mem, 0 );
TS. IO = ioremap (res-> Start, resource_size (RES ));
/*
* Construct an ADC customer to request data conversion from the ADC
* S3c24xx_ts_select: This is called when the ADC selects or unprocesses this client.
* S3c24xx_ts_conversion: called when the ADC conversion is complete
*/
TS. Client = maid (pdev, s3c24xx_ts_select,
S3c24xx_ts_conversion, 1 );
/* Allocate an input device struct */
Input_dev = input_allocate_device ();
TS. Input = input_dev;
/* Set the input device to support ev_key and ev_abs events */
TS. Input-> evbit [0] = bit_mask (ev_key) | bit_mask (ev_abs );
/* The btn_touch button is supported */
TS. Input-> keybit [bit_word (btn_touch)] = bit_mask (btn_touch );
/* Set the touch screen range (for the range value, refer to the Data Manual) to filter out error events when handling events */
Input_set_abs_params (TS. Input, abs_x, 0, 0x3ff, 0, 0 );
Input_set_abs_params (TS. Input, abs_y, 0, 0x3ff, 0, 0 );
/* Set some attributes */
TS. Input-> name = "s3c24xxtouchscreen ";
TS. Input-> ID. bustype = bus_host;
TS. Input-> ID. Vendor = 0 xdead;
TS. Input-> ID. Product = 0 xbeef;
TS. Input-> ID. Version = 0x0102;
/* Set the buffer size. If oversampling_shift = 2, the buffer size is 1 <2 */
TS. Shift = Info-> oversampling_shift;
TS. Features = platform_get_device_id (pdev)-> driver_data;
/* Apply for touch screen interruption */
Ret = request_irq (TS. irq_tc, stylus_irq, 0,
"S3c2410_ts_pen", ts. Input );
/* All went OK, so register to theinput system */
Ret = input_register_device (TS. Input );
Return 0;
}
2.3 interrupt Analysis
L The core of the touch screen driver is the interrupt program. When a touch pen is clicked or popped up, interruption occurs (int_tc)
Staticirqreturn_t stylus_irq (int irq, void * dev_id)
{
Data0 = readl (TS. Io + s3c2410_adcdat0);/* Get X value */
Data1 = readl (TS. Io + s3c2410_adcdat1);/* Get y value */
Down = get_down (data0, data1 );
If (down)/* determines whether to press and start ADC conversion */
Initi_adc_start (TS. Client, 0, 1 <ts. Shift );
Return irq_handled;
}
L start ADC Conversion
Intiniti_adc_start (struct initi_adc_client * client,
Unsigned int channel, unsigned intnr_samples)
{
Spin_lock_irqsave (& ADC-> lock, flags );
Client-> channel = channel;
Client-> nr_samples = nr_samples;
If (client-> is_ts)
ADC-> ts_pend = client;/* "blocking" the client for request conversion */
Else
List_add_tail (& client-> pend, & adc_pending );
If (! ADC-> cur)/* if the current request is complete, the ADC performs the next conversion Request */
Initi_adc_try (ADC );/**/
Spin_unlock_irqrestore (& ADC-> lock, flags );
Return 0;
}
There may be many customers who want to convert ADC requests, so the queue mechanism is used to accept the customer's conversion requests. However, for a touch screen request conversion, the request will be blocked in ts_pend. Touch screen request conversion takes precedence over others, which I personally think may be the reason for real-time performance.
Static void89c_adc_try (struct adc_device * ADC)
{
Struct initi_adc_client * Next = ADC-> ts_pend;
If (! Next &&! List_empty (& adc_pending )){
Next = list_first_entry (& adc_pending,
Structiniti_adc_client, pend );
List_del (& next-> pend );
} Else
ADC-> ts_pend = NULL;
If (next ){
Adc_dbg (ADC, "New clientis % P \ n", next );
ADC-> cur = next;
Initi_adc_select (ADC, next);/* select the customer requesting conversion */
Cloud_adc_convert (ADC);/* Start conversion */
Initi_adc_dbgshow (ADC );
}
}
L int_adc interruption occurs when the ADC is fully converted. The value of "initi_adc_irq ()-> (client-> select_cb) (client, 0)" indicates that the select_cb function is "initi_adc_register ()" in the touch screen driver () registered callback function: s3c24xx_ts_select ()
Static voids3c24xx_ts_select (struct initi_adc_client * client, unsigned select)
{
If (select) {/* select the ADC conversion request customer item */
Writel (s3c2410_adctsc_pull_up_disable | autopst,
TS. Io + s3c2410_adctsc );
} Else {/**/
Mod_timer (& touch_timer, jiffies + 1 );
Writel (wait4int | int_up, ts. Io + s3c2410_adctsc );
}
}
Touch_timer is a timer. When a time-out occurs, the touch_timer_fire () function is called to report the coordinates. After the event is reported, it is handled by the input subsystem.
Static voidtouch_timer_fire (unsigned long data)
{
Data0 = readl (TS. Io + s3c2410_adcdat0 );
Data1 = readl (TS. Io + s3c2410_adcdat1 );
Down = get_down (data0, data1 );
If (down) {/* determines whether to press or play? */
If (TS. Count = (1 <ts. Shift) {/* determine whether the buffer is full */
TS. XP >>=ts. shift;
TS. yp> = ts. shift;
/* Report event information */
Input_report_abs (TS. Input, abs_x, ts. XP );
Input_report_abs (TS. Input, abs_y, ts. YP );
Input_report_key (TS. Input, btn_touch, 1 );
Input_sync (TS. Input );
TS. XP = 0;
TS. Yp = 0;
TS. Count = 0;
}
Initi_adc_start (TS. Client, 0, 1 <ts. Shift );
} Else {
TS. XP = 0;
TS. Yp = 0;
TS. Count = 0;
Input_report_key (TS. Input, btn_touch, 0 );
Input_sync (TS. Input );
Writel (wait4int | int_down, ts. Io + s3c2410_adctsc );
}
}
First, we can analyze the key points of the analysis as long as we grasp the time when two interruptions occur, otherwise it will be difficult to analyze them.