Linux touch screen (4)-multi-touch

Source: Internet
Author: User
Linux touch screen (4)-multi-touch

4.1 Overview

The driver supports the it7260 touch screen controller, which supports up to three touch points and has been tested on CPU: s5pc110, linux-2.6.32.9, Android-2.2. I thought it could be done in three days, but it took a week to finish it. Level limited, there may be some bugs, please feedback to me (cjok.liao@gmail.com) in time ).

The Touch Screen driver consists of two parts:

I2C DRIVER: connects devices to the I2C bus for data transmission;

Input subsystem: reports the obtained data to the user space.

The lower part of the interrupt uses a delayed working queue to complete data parsing and reporting.

For more information, see the Controller Data Manual, such as data packet parsing and data transmission protocol (Standard I2C protocol ).

4.2 Driver Analysis

/** Multi touch screen driver for it7260 * base on multi-touch protocol a */# include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/input. h> # include <Linux/interrupt. h> # include <Linux/PM. h> # include <Linux/slab. h> # include <ASM/Io. h> # include <Linux/I2C. h> # include <Linux/Timer. h>/* buffer address */# define pai_buf0x20/* command buffer (write only) */# define sys_assist_buf0x40/* systerm command Bu Ffer (write only) */# define query_buf0x80/* Query Buffer (read only) */# define prepare _rsp_buf0xa0/* command response buffer (read only) */# define sys_assist_rsp_buf0xc0/* systerm command response buffer (read only) */# define point_info_buf0xe0/* Point Information buffer (read only) * // * construct a touch screen device struct */struct it7260_ts_priv {struct i2c_client * client;/* I2C device */struct input_dev * input;/* input device struct */Str UCT delayed_work work;/* delayed work queue */struct mutex;/* mutex */int irq;/* interrupt */};/*** sending and receiving functions, although i2c_master_recv and i2c_master_send are provided in the kernel, * these two functions are only suitable for a single MSG * // *** i2c_master_read_it7260-issue two I2C message in master receive mode * @ client: handler to slave device * @ buf_index: buffer address * @ buf_data: Where to store data read from slave * @ len_data: The bytes of buf_data to read ** returns ne Gative errno, or else the number of bytes read */static int i2c_master_read_it7260 (struct i2c_client * client, unsigned char buf_index, unsigned char * buf_data, unsigned short len_data) {int ret; struct i2c_msg msgs [2] = {{. ADDR = client-> ADDR ,. flags = i2c_m_nostart ,. len = 1 ,. buf = & buf_index ,},{. ADDR = client-> ADDR ,. flags = i2c_m_rd ,. len = len_data ,. buf = buf_data, }}; ret = i2c_transfer (client-> adapte R, msgs, 2); Return (ret = 2 )? Len_data: ret;}/*** i2c_master_write_it7260-issue a single I2C message in master transmit mode * @ client: Handler to slave device * @ buf_index: buffer address * @ buf_data: data that wile be write to the slave * @ len_data: The bytes of buf_data to write ** returns negative errno, or else the number of bytes written */static int i2c_master_write_it7260 (struct i2c_client * client, unsigned char buf_index, Unsigned char const * buf_data, unsigned short len_data) {unsigned char Buf [2]; int ret; struct i2c_msg msgs [1] = {{. ADDR = client-> ADDR ,. flags = 0,/* default write flag */. len = len_data + 1 ,. buf = Buf, }}; Buf [0] = buf_index; memcpy (& Buf [1], buf_data, len_data); ret = i2c_transfer (client-> adapter, msgs, 1); Return (ret = 1 )? Sizeof (BUF): ret;}/*** delayed operation. When an interrupt occurs, call it to read data from the I2C bus and parse the data according to the Data Manual, then, report it. */Static void it7260_ts_poscheck (struct work_struct * Work) {struct it7260_ts_priv * priv = container_of (work, struct it7260_ts_priv, work. work); unsigned char Buf [14]; unsigned short xpos [3] = {0}, ypos [3] = {0 }; unsigned char event [3] = {0}; unsigned char query = 0; int ret, I; mutex_lock (& priv-> mutex); i2c_master_read_it7260 (priv-> client, query_buf, & query, 1); If (! (Query & 0x80) {dev_err (& priv-> client-> Dev, "No finger touch \ n"); goto out;} memset (& Buf, 0, sizeof (BUF); ret = i2c_master_read_it7260 (priv-> client, point_info_buf, Buf, 14); If (Ret! = 14) {dev_err (& priv-> client-> Dev, "failed to read Point Info buffer \ n"); goto out ;} /* touch key */If (BUF [0] = 0x41) {dev_info (& priv-> client-> Dev, "the key Number % d \ n ", buf [1]); If (BUF [1] = 0x04) input_report_key (priv-> input, key_home ,!! Buf [2]); else if (BUF [1] = 0x03) input_report_key (priv-> input, key_menu ,!! Buf [2]); else if (BUF [1] = 0x02) input_report_key (priv-> input, key_back ,!! Buf [2]); else if (BUF [1] = 0x01) input_report_key (priv-> input, key_power ,!! Buf [2]); elsegoto out; input_sync (priv-> input); goto out;}/* finger 0 */If (BUF [0] & 0x01) {xpos [0] = (BUF [3] & 0x0f) <8) | Buf [2]; ypos [0] = (BUF [3] & 0xf0) <4) | Buf [4]; event [0] = Buf [5] & 0x0f;}/* finger 1 */If (BUF [0] & 0x02) {xpos [1] = (BUF [7] & 0x0f) <8) | Buf [6]; ypos [1] = (BUF [7] & 0xf0) <4) | Buf [8]; event [1] = Buf [9] & 0x0f;}/* finger 2 */If (BUF [0] & 0x04) {xpos [2] = (BUF [11] & 0x 0f) <8) | Buf [10]; ypos [2] = (BUF [11] & 0xf0) <4) | Buf [12]; event [2] = Buf [13] & 0x0f;} for (I = 0; I <3; I ++) {input_report_abs (priv-> input, abs_mt_position_x, ypos [I]); input_report_abs (priv-> input, abs_mt_position_y, xpos [I]); input_report_abs (priv-> input, abs_mt_touch_major ,!! Event [I]); input_report_abs (priv-> input, abs_mt_width_major, 0); input_mt_sync (priv-> input); dev_info (& priv-> client-> Dev, "Finger % d> xpos = % d, \ ypos = % d, event = % d \ n", I, ypos [I], xpos [I], event [I]);} input_sync (priv-> input); Out: mutex_unlock (& priv-> mutex); enable_irq (priv-> IRQ );} /* interrupt service subprogram. After interruption is generated, the task is scheduled after a delay of (Hz/20) Tick. */static irqreturn_t it7260_ts_isr (int irq, void * dev_id) {struct it7260_ts_priv * Pri V = dev_id; disable_irq_nosync (IRQ); schedule_delayed_work (& priv-> Work, Hz/20); Return irq_handled ;} /*** handle-identify capacitance sensor model *** Returns Error-1, or else suc 0 */static int it7260_identify_capsensor (struct i2c_client * client) {unsigned char Buf [10]; unsigned char query = 0; do {i2c_master_read_it7260 (client, query_buf, & query, 1) ;}while (query & 0x01);/* 0x00: The command of identify cap sensor */Buf [0] = 0x00; i2c_master_write_it7260 (client, pai_buf, Buf, 1); do {i2c_master_read_it7260 (client, query_buf, & query, 1) ;}while (query & 0x01); memset (& Buf, 0, sizeof (BUF); i2c_master_read_it7260 (client, pai_rsp_buf, Buf, 10 ); dev_err (& client-> Dev, "Len = % d, % C \ n", Buf [0], Buf [1], Buf [2], buf [3]); If (BUF [1]! = 'I' | Buf [2]! = 'T' | Buf [3]! = 'E') Return-1; return 0;}/* probe function, this function is called when the I2C device matches the I2C driver */static int it7260_ts_probe (struct i2c_client * client, const struct i2c_device_id * IDP) {struct it7260_ts_priv * priv; struct input_dev * input; int error;/* identify whether the device model is it7260 */error = it7260_identify_capsensor (client); If (error) {dev_err (& client-> Dev, "Cannot identify the touch screen \ n"); goto err0;} priv = kzarloc (sizeof (* priv), gfp_k Ernel); If (! Priv) {dev_err (& client-> Dev, "failed to allocate driver data \ n"); error =-enomem; goto err0 ;} /* initialize mutex */mutex_init (& priv-> mutex); dev_set_drvdata (& client-> Dev, priv);/* allocate an input device */input = input_allocate_device (); if (! Input) {dev_err (& client-> Dev, "failed to allocate input device \ n"); error =-enomem; goto err1 ;} /* set the event types supported by the input device */input-> evbit [0] = bit_mask (ev_key) | bit_mask (ev_abs); input_set_capability (input, ev_key, key_menu ); input_set_capability (input, ev_key, key_back); input_set_capability (input, ev_key, key_home); input_set_capability (input, ev_key, key_power); percentage (input, percentage, 0,600, 0, 0 ); input_set_abs_params (input, abs_mt_position_y, 0, 1024, 0); input_set_abs_params (input, callback, 0, 15, 0, 0); callback (input, callback, 0, 2, 0, 0); input-> name = "it7260 touch screen"; input-> phys = "I2C"; input-> ID. bustype = bus_i2c; input_set_drvdata (input, priv); priv-> client = client; priv-> input = input; /* initialize the delayed working queue */init_delayed_work (& priv-> Work, it7260_ts_poscheck); priv-> IRQ = client-> IRQ; /* register the input device with the input subsystem */error = input_register_device (input); If (error) {dev_err (& client-> Dev, "failed to register input device \ n"); goto err1;}/* Registration interrupted, low-level trigger */error = request_irq (priv-> IRQ, it7260_ts_isr, ir1__trigger_low, client-> name, priv); If (error) {dev_err (& client-> Dev, "unable to request touchscreen IRQ \ n"); goto err2 ;} device_init_wakeup (& client-> Dev, 1); Return 0; err2: input_unregister_device (input); input = NULL; err1: input_free_device (input); kfree (priv); err0: dev_set_drvdata (& client-> Dev, null); Return Error ;} /* call the remove function to log out when the device is not used */static int _ devexit it7260_ts_remove (struct i2c_client * client) {struct it7260_ts_priv * priv = dev_get_drvdata (& client> Dev); free_irq (priv-> IRQ, priv); input_unregister_device (priv-> input); kfree (priv ); dev_set_drvdata (& client-> Dev, null); Return 0;}/* power management function */static int it7260_ts_suspend (struct i2c_client * client, pm_message_t mesg) {int ret =-1; u8 suspend_cmd [] = {0x04, 0x00, 0x02}; struct it7260_ts_priv * priv = i2c_get_clientdata (client ); if (device_may_wakeup (& client-> Dev) {enable_irq_wake (priv-> IRQ); If (sizeof (suspend_cmd) = clients (client, inclu_buf, suspend_cmd, 3 )) ret = 0;} return ret;} static int it7260_ts_resume (struct i2c_client * client) {int ret =-1; unsigned char query; struct it7260_ts_priv * priv = i2c_get_clientdata (client ); if (device_may_wakeup (& client-> Dev) {i2c_master_read_it7260 (client, query_buf, & query, 1); disable_irq_wake (priv-> IRQ); ret = 0 ;} return ret;}/* List of devices supported by the driver, used to match */static const struct i2c_device_id it7260_ts_id [] ={{ "it7260", 0 }, {}/* shocould not omitted */}; module_device_table (I2C, it7260_ts_id); static struct i2c_driver it7260_ts_driver = {. driver = {. name = "IT7260-ts ",},. probe = it7260_ts_probe ,. remove = _ devexit_p (it7260_ts_remove ),. suspend = it7260_ts_suspend ,. resume = it7260_ts_resume ,. id_table = it7260_ts_id,};/* module Loading Function */static int _ init it7260_ts_init (void) {return i2c_add_driver (& it7260_ts_driver );} /* module unmount function */static void _ exit functions (void) {i2c_del_driver (& it7260_ts_driver);} module_init (it7260_ts_init); module_exit (it7260_ts_exit ); module_license ("GPL"); module_author ("cjok <cjok.liao@gmail.com>"); module_description ("it7260 touchscreen driver ");

Complete source code can be downloaded through git: git clone git: // github.com/cjok/it7260.git

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.