电容屏/电阻屏Android虚拟按键实现的两种方法

(一) 虚拟按键的描述可以见 韩超和梁泉的 《Android系统级深入开发——移植与调试》的第八章:

      虚拟按键(Virtual Key)是Eclair版本开始增加的新特性。Virtual Key的功能是利用触摸屏,模拟按键发生的事件,这样就可以利用触摸屏的边缘,实现一些可以自定义的按键效果。

虚拟按键的实现效果如图8-5所示。

图8-5  虚拟按键的实现效果

在Android系统中,触摸屏设备发送的是RawInputEvent(原始输入事件),而按键发送的是KeyEvent(按键事件)。KeyEvent直接发送给应用程序层,RawInputEvent在Android的Java框架中被转换成MotionEvent发送给应用程序层。

在Android系统中虚拟按键的实现方法是:在某种情况下,将RawInputEvent转换成KeyEvent。

frameworks/base/services/Java/com/android/server目录中的InputDevice.Java文件负责处理虚拟按键的主要文件。

虚拟按键的处理相对简单,需要根据以下文件对虚拟按键的内容进行配置:

/sys/board_properties/virtualkeys.{devicename}

在InputDevice.Java文件中通过readVirtualKeys,对进行消息的转化。根据配置文件将RawInputEvent转换成按键相关的内容。

virtualkeys.{devicename}是虚拟按键的适配文件,需要在目标文件系统的/sys/board_ properties/目录中。

虚拟按键配置文件的格式如下所示:

0x1:扫描码:X:Y:W:H:0x1: ……

例如,在MSM的mahimahi平台上查看虚拟按键的配置文件如下所示:

# cat /sys/board_properties/virtualkeys.synaptics-rmi-touchscreen

0x01:158:55:835:90:55:0x01:139:172:835:125:55:0x01:102:298:835:115:55:0x01:217:412:835:95:55

由此可见,其中定义了4个区域的虚拟按键,它们的Y坐标相同,可见4个按键的矩形区域位于水平的一排。其转换的扫描码分别为158,139,102,217,分别对应于BACK(返回),MENU(菜单),HOME(主界面),SEARCH(搜索)这4个按键。

另外一个系统的虚拟按键的配置文件如下所示:

$ cat /sys/board_properties/virtualkeys.qtouch-touchscreen

0x01:139:90:936:116:104:0x01:102:252:936:116:104:0x01:158:402:936:116:104

其转换的扫描码分别为:139,102,158,分别对应于MENU(菜单),HOME(主界面),BACK(返回)这3个按键。

提示:使用虚拟按键转换成为的是按键的扫描码,不是按键码,因此依然需要经过按键布局文件的转化才能得到按键码。

(二)如果按照韩超和梁泉的《Android系统级深入开发——移植与调试》的第八章描述虚拟按键的实现过程如下:

1.硬件分析
我所使用的触摸屏分辨率是1158*768,可视区域大小是1024*768(这也是LCD屏的大小),在触摸屏两侧总有5个按键。
 
2.触摸屏按键驱动的修改
既然可视区域在触摸屏中间部位,因此需要在触摸屏驱动中修改input_set_abs_params()函数中的参数
  1. input_set_abs_params(input_dev, ABS_MT_POSITION_X, 61, 1085, 0, 0);
  2. input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);

其中61是可视区域左侧x轴左边坐标,1085是右侧的。

3.Android框架层

Android上层通过读取触摸屏坐标并经过转算后来识别定义好的虚拟按键,代码位于frameworks/base/services/java/com/android/server/KeyInputQueue.java中:

static class Virtualkey{}是负责按键定位的方法;

private void readVirtualKeys(String deviceName)负责读取sys文件,这是最重要的代码,也是与底层sys文件系统沟通的桥梁,它会读取/sys/board_properties/virtualkeys.{deviceName}文件,deviceName一定要与触摸屏设备名称一致,不然会找不到指定的sys文件。

4.sys文件系统

前面讲到了readVirtualKeys会读取sys文件,这个sys文件就是定义虚拟按键的坐标以及键值,它的协议格式是一段字符串,每个按键有六项分别用冒号分割,按键按键之间也是用冒号分割,标准格式是:

键类型:键值:按键区域中心x坐标:按键区域中心y坐标:按键区域宽:按键区域高

加载触摸屏以及创建sys文件的代码:

[cpp]  view plain copy
  1. <span style="font-size:13px;">#ifdef VIRTUAL_KEYS  
  2.   
  3. static ssize_t virtual_keys_show(struct kobject *kobj,  
  4.   
  5.              struct kobj_attribute *attr, char *buf)  
  6.   
  7. {  
  8.   
  9.     if (1) {  
  10.   
  11.           
  12.   
  13.         return sprintf(buf,  
  14.   
  15.          __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEUP) ":1030:370:30:30"  
  16.   
  17.          ":" __stringify(EV_KEY) ":" __stringify(KEY_VOLUMEDOWN) ":1030:470:30:30"  
  18.   
  19.          ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":1030:18:30:30"  
  20.   
  21.          ":" __stringify(EV_KEY) ":" __stringify(KEY_HOME) ":1030:136:30:30"  
  22.   
  23.          ":" __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":1030:236:30:30"  
  24.   
  25.          "\n");  
  26.   
  27.     } else {  
  28.   
  29.   
  30.   
  31.     }  
  32.   
  33. }  
  34.   
  35.   
  36.   
  37. static struct kobj_attribute virtual_keys_attr = {  
  38.   
  39.     .attr = {  
  40.   
  41.         .name = "virtualkeys.xxxx",  
  42.   
  43.         .mode = S_IRUGO,  
  44.   
  45.     },  
  46.   
  47.     .show = &virtual_keys_show,  
  48.   
  49. };  
  50.   
  51.   
  52.   
  53. static struct attribute *properties_attrs[] = {  
  54.   
  55.     &virtual_keys_attr.attr,  
  56.   
  57.     NULL  
  58.   
  59. };  
  60.   
  61.   
  62.   
  63. static struct attribute_group properties_attr_group = {  
  64.   
  65.     .attrs = properties_attrs,  
  66.   
  67. };  
  68.   
  69.   
  70.   
  71. static void virtual_keys_init(void)  
  72.   
  73. {  
  74.   
  75.     int ret;  
  76.   
  77.     struct kobject *properties_kobj;  
  78.   
  79.       
  80.   
  81.     properties_kobj = kobject_create_and_add("board_properties", NULL);  
  82.   
  83.     if (properties_kobj)  
  84.   
  85.         ret = sysfs_create_group(properties_kobj,  
  86.   
  87.                      &properties_attr_group);  
  88.   
  89.     if (!properties_kobj || ret)  
  90.   
  91.         pr_err("failed to create board_properties\n");      
  92.   
  93. }  
  94. #endif  
  95. </span>  


      其中.name = "virtualkeys.xxxx"的xxxx就是触摸屏设备名称,也就是前面说到的{deviceName},virtual_keys_init()函数可以在触摸屏probe函数中调用。另外,我将可视区域左侧的两侧按键移到了右侧实现,因此五个按键区域中心x坐标都是一样,这部分要在触摸屏驱动增加x轴坐标调整,这部分我就不再说明。以上步骤完成后可以使用 cat /sys/board_properties/virtualkeys.{deviceName}查看虚拟按键的配置文件,并试试按下触摸屏上按键是否有反应,如果坐标不正确还要进行耐心地校准。

  1.       具体的可以去HTC网站(http://htcdev.com/devcenter/downloads)上下载HTC手机的linux源码,HTC很多款手机的BACK,MENU,HOME,SEARCH电容屏虚拟按键都是采用这种方式实现的。
  1. (三)但是我用的是四线电阻触摸屏,用上面的方式好像没有任何反应,所以我采用最直接的方式用input_event发送按键消息,就是在触摸屏处理芯片TSC2007驱动中当读到一定范围内的触摸事件就发送按键消息:这种方式只要修改TSC2007驱动的几个地方:
  1. 1.定义全局局部变量用于记录是否有虚拟按键按下
    [cpp]  view plain copy
    1. static int backkeydown=0;  
    2. static int homekeydown=0;  
    3. static int menukeydown=0;  
    2..在prope函数中添加
    [cpp]  view plain copy
    1. set_bit(EV_SYN, input_dev->evbit);  
    2. set_bit(KEY_HOME, input_dev->keybit);  
    3. //set_bit(KEY_SEARCH, input_dev->keybit);  
    4. set_bit(KEY_BACK, input_dev->keybit);  
    5. set_bit(KEY_MENU, input_dev->keybit);  
    3.在中断处理work里面添加按键按下消息
    [cpp]  view plain copy
    1. if((tc.y>=81)&&(tc.y<=181))  
    2. {  
    3.     if((tc.x>=2711)&&(tc.x<=2832))  
    4.     {  
    5.         if(backkeydown==0)  
    6.         {  
    7.             input_event(input, EV_KEY,KEY_BACK, 1);  
    8.             backkeydown=1;  
    9.             //printk("back key down\n");  
    10.         }  
    11.     }  
    12.     else if((tc.x>=1891)&&(tc.x<=1933))  
    13.     {  
    14.         if(homekeydown==0)  
    15.         {  
    16.             input_event(input, EV_KEY,KEY_HOME, 1);  
    17.             homekeydown=1;  
    18.             //printk("home key down\n");  
    19.         }  
    20.     }  
    21.     else if((tc.x>=1088)&&(tc.x<=1143))  
    22.     {  
    23.         if(menukeydown==0)  
    24.         {  
    25.             input_event(input, EV_KEY,KEY_MENU, 1);  
    26.             menukeydown=1;  
    27.             //printk("menu key down\n");  
    28.         }  
    29.     }  
    30. }  

4.在tsc2007_send_up_event函数中添加按键释放消息
[cpp]  view plain copy
  1. if(backkeydown==1)  
  2. {  
  3.     backkeydown=0;  
  4.     input_event(input, EV_KEY, KEY_BACK, 0);  
  5.     //printk("back key up\n");  
  6. }  
  7. if(homekeydown==1)  
  8. {  
  9.     homekeydown=0;  
  10.     input_event(input, EV_KEY, KEY_HOME, 0);  
  11.     //printk("home key up\n");  
  12. }  
  13. if(menukeydown==1)  
  14. {  
  15.     menukeydown=0;  
  16.     input_event(input, EV_KEY, KEY_MENU, 0);  
  17.     //printk("menu key up\n");  
  18. }  

整个修改后的TSC2007驱动如下:
[cpp]  view plain copy
  1. /* 
  2.  * drivers/input/touchscreen/tsc2007.c 
  3.  * 
  4.  * Copyright (c) 2008 MtekVision Co., Ltd. 
  5.  *  Kwangwoo Lee <kwlee@mtekvision.com> 
  6.  * 
  7.  * Using code from: 
  8.  *  - ads7846.c 
  9.  *  Copyright (c) 2005 David Brownell 
  10.  *  Copyright (c) 2006 Nokia Corporation 
  11.  *  - corgi_ts.c 
  12.  *  Copyright (C) 2004-2005 Richard Purdie 
  13.  *  - omap_ts.[hc], ads7846.h, ts_osk.c 
  14.  *  Copyright (C) 2002 MontaVista Software 
  15.  *  Copyright (C) 2004 Texas Instruments 
  16.  *  Copyright (C) 2005 Dirk Behme 
  17.  * 
  18.  *  This program is free software; you can redistribute it and/or modify 
  19.  *  it under the terms of the GNU General Public License version 2 as 
  20.  *  published by the Free Software Foundation. 
  21.  */  
  22.   
  23. #include <linux/module.h>  
  24. #include <linux/slab.h>  
  25. #include <linux/input.h>  
  26. #include <linux/interrupt.h>  
  27. #include <linux/i2c.h>  
  28. #include <linux/i2c/tsc2007.h>  
  29.   
  30. #define TS_POLL_DELAY           1 /* ms delay between samples */  
  31. #define TS_POLL_PERIOD          1 /* ms delay between samples */  
  32.   
  33. #define TSC2007_MEASURE_TEMP0       (0x0 << 4)  
  34. #define TSC2007_MEASURE_AUX     (0x2 << 4)  
  35. #define TSC2007_MEASURE_TEMP1       (0x4 << 4)  
  36. #define TSC2007_ACTIVATE_XN     (0x8 << 4)  
  37. #define TSC2007_ACTIVATE_YN     (0x9 << 4)  
  38. #define TSC2007_ACTIVATE_YP_XN      (0xa << 4)  
  39. #define TSC2007_SETUP           (0xb << 4)  
  40. #define TSC2007_MEASURE_X       (0xc << 4)  
  41. #define TSC2007_MEASURE_Y       (0xd << 4)  
  42. #define TSC2007_MEASURE_Z1      (0xe << 4)  
  43. #define TSC2007_MEASURE_Z2      (0xf << 4)  
  44.   
  45. #define TSC2007_POWER_OFF_IRQ_EN    (0x0 << 2)  
  46. #define TSC2007_ADC_ON_IRQ_DIS0     (0x1 << 2)  
  47. #define TSC2007_ADC_OFF_IRQ_EN      (0x2 << 2)  
  48. #define TSC2007_ADC_ON_IRQ_DIS1     (0x3 << 2)  
  49.   
  50. #define TSC2007_12BIT           (0x0 << 1)  
  51. #define TSC2007_8BIT            (0x1 << 1)  
  52.   
  53. #define MAX_12BIT           ((1 << 12) - 1)  
  54.   
  55. #define ADC_ON_12BIT    (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)  
  56.   
  57. #define READ_Y      (ADC_ON_12BIT | TSC2007_MEASURE_Y)  
  58. #define READ_Z1     (ADC_ON_12BIT | TSC2007_MEASURE_Z1)  
  59. #define READ_Z2     (ADC_ON_12BIT | TSC2007_MEASURE_Z2)  
  60. #define READ_X      (ADC_ON_12BIT | TSC2007_MEASURE_X)  
  61. #define PWRDOWN     (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)  
  62.   
  63.   
  64. static int backkeydown=0;  
  65. static int homekeydown=0;  
  66. static int menukeydown=0;  
  67. struct ts_event {  
  68.     u16 x;  
  69.     u16 y;  
  70.     u16 z1, z2;  
  71. };  
  72.   
  73. struct tsc2007 {  
  74.     struct input_dev    *input;  
  75.     char            phys[32];  
  76.     struct delayed_work work;  
  77.   
  78.     struct i2c_client   *client;  
  79.   
  80.     u16         model;  
  81.     u16         x_plate_ohms;  
  82.   
  83.     bool            pendown;  
  84.     int         irq;  
  85.   
  86.     int         (*get_pendown_state)(void);  
  87.     void            (*clear_penirq)(void);  
  88. };  
  89.   
  90. static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)  
  91. {  
  92.     s32 data;  
  93.     u16 val;  
  94.   
  95.     data = i2c_smbus_read_word_data(tsc->client, cmd);  
  96.     if (data < 0) {  
  97.         dev_err(&tsc->client->dev, "i2c io error: %d\n", data);  
  98.         return data;  
  99.     }  
  100.   
  101.     /* The protocol and raw data format from i2c interface: 
  102.      * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P 
  103.      * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit]. 
  104.      */  
  105.     val = swab16(data) >> 4;  
  106.   
  107.     dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);  
  108.   
  109.     return val;  
  110. }  
  111.   
  112. static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)  
  113. {  
  114.     /* y- still on; turn on only y+ (and ADC) */  
  115.     tc->y = tsc2007_xfer(tsc, READ_Y);  
  116.   
  117.     /* turn y- off, x+ on, then leave in lowpower */  
  118.     tc->x = tsc2007_xfer(tsc, READ_X);  
  119.   
  120.     /* turn y+ off, x- on; we'll use formula #1 */  
  121.     tc->z1 = tsc2007_xfer(tsc, READ_Z1);  
  122.     tc->z2 = tsc2007_xfer(tsc, READ_Z2);  
  123.     //printk("x=%d,y=%d\n",tc->x,tc->y);  
  124.     /* Prepare for next touch reading - power down ADC, enable PENIRQ */  
  125.     tsc2007_xfer(tsc, PWRDOWN);  
  126. }  
  127.   
  128. static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)  
  129. {  
  130.     u32 rt = 0;  
  131.   
  132.     /* range filtering */  
  133.     if (tc->x == MAX_12BIT)  
  134.         tc->x = 0;  
  135.   
  136.     if (likely(tc->x && tc->z1)) {  
  137.         /* compute touch pressure resistance using equation #1 */  
  138.         rt = tc->z2 - tc->z1;  
  139.         rt *= tc->x;  
  140.         rt *= tsc->x_plate_ohms;  
  141.         rt /= tc->z1;  
  142.         rt = (rt + 2047) >> 12;  
  143.     }  
  144.   
  145.     return rt;  
  146. }  
  147.   
  148. static void tsc2007_send_up_event(struct tsc2007 *tsc)  
  149. {  
  150.     struct input_dev *input = tsc->input;  
  151.   
  152.     dev_dbg(&tsc->client->dev, "UP\n");  
  153.     if(backkeydown==1)  
  154.     {  
  155.         backkeydown=0;  
  156.         input_event(input, EV_KEY, KEY_BACK, 0);  
  157.         //printk("back key up\n");  
  158.     }  
  159.     if(homekeydown==1)  
  160.     {  
  161.         homekeydown=0;  
  162.         input_event(input, EV_KEY, KEY_HOME, 0);  
  163.         //printk("home key up\n");  
  164.     }  
  165.     if(menukeydown==1)  
  166.     {  
  167.         menukeydown=0;  
  168.         input_event(input, EV_KEY, KEY_MENU, 0);  
  169.         //printk("menu key up\n");  
  170.     }  
  171.     input_report_key(input, BTN_TOUCH, 0);  
  172.     input_report_abs(input, ABS_PRESSURE, 0);  
  173.     input_sync(input);  
  174. }  
  175.   
  176. static void tsc2007_work(struct work_struct *work)  
  177. {  
  178.     struct tsc2007 *ts =  
  179.         container_of(to_delayed_work(work), struct tsc2007, work);  
  180.     struct ts_event tc;  
  181.     u32 rt;  
  182.   
  183.     /* 
  184.      * NOTE: We can't rely on the pressure to determine the pen down 
  185.      * state, even though this controller has a pressure sensor. 
  186.      * The pressure value can fluctuate for quite a while after 
  187.      * lifting the pen and in some cases may not even settle at the 
  188.      * expected value. 
  189.      * 
  190.      * The only safe way to check for the pen up condition is in the 
  191.      * work function by reading the pen signal state (it's a GPIO 
  192.      * and IRQ). Unfortunately such callback is not always available, 
  193.      * in that case we have rely on the pressure anyway. 
  194.      */  
  195.     if (ts->get_pendown_state) {  
  196.         if (unlikely(!ts->get_pendown_state())) {  
  197.             tsc2007_send_up_event(ts);  
  198.             ts->pendown = false;  
  199.             goto out;  
  200.         }  
  201.   
  202.         dev_dbg(&ts->client->dev, "pen is still down\n");  
  203.     }  
  204.   
  205.     tsc2007_read_values(ts, &tc);  
  206.   
  207.     rt = tsc2007_calculate_pressure(ts, &tc);  
  208.     if (rt > MAX_12BIT) {  
  209.         /* 
  210.          * Sample found inconsistent by debouncing or pressure is 
  211.          * beyond the maximum. Don't report it to user space, 
  212.          * repeat at least once more the measurement. 
  213.          */  
  214.         dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);  
  215.         goto out;  
  216.   
  217.     }  
  218.   
  219.     if (rt) {  
  220.         struct input_dev *input = ts->input;  
  221.         if((tc.y>=81)&&(tc.y<=181))  
  222.         {  
  223.             if((tc.x>=2711)&&(tc.x<=2832))  
  224.             {  
  225.                 if(backkeydown==0)  
  226.                 {  
  227.                     input_event(input, EV_KEY,KEY_BACK, 1);  
  228.                     backkeydown=1;  
  229.                     //printk("back key down\n");  
  230.                 }  
  231.             }  
  232.             else if((tc.x>=1891)&&(tc.x<=1933))  
  233.             {  
  234.                 if(homekeydown==0)  
  235.                 {  
  236.                     input_event(input, EV_KEY,KEY_HOME, 1);  
  237.                     homekeydown=1;  
  238.                     //printk("home key down\n");  
  239.                 }  
  240.             }  
  241.             else if((tc.x>=1088)&&(tc.x<=1143))  
  242.             {  
  243.                 if(menukeydown==0)  
  244.                 {  
  245.                     input_event(input, EV_KEY,KEY_MENU, 1);  
  246.                     menukeydown=1;  
  247.                     //printk("menu key down\n");  
  248.                 }  
  249.             }  
  250.         }  
  251.         if (!ts->pendown) {  
  252.             dev_dbg(&ts->client->dev, "DOWN\n");  
  253.   
  254.             input_report_key(input, BTN_TOUCH, 1);  
  255.             ts->pendown = true;  
  256.         }  
  257.   
  258.         input_report_abs(input, ABS_X, tc.x);  
  259.         input_report_abs(input, ABS_Y, tc.y);  
  260.         input_report_abs(input, ABS_PRESSURE, rt);  
  261.   
  262.         input_sync(input);  
  263.   
  264.         dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",  
  265.             tc.x, tc.y, rt);  
  266.   
  267.     } else if (!ts->get_pendown_state && ts->pendown) {  
  268.         /* 
  269.          * We don't have callback to check pendown state, so we 
  270.          * have to assume that since pressure reported is 0 the 
  271.          * pen was lifted up. 
  272.          */  
  273.         tsc2007_send_up_event(ts);  
  274.         ts->pendown = false;  
  275.     }  
  276.   
  277.  out:  
  278.     if (ts->pendown)  
  279.         schedule_delayed_work(&ts->work,  
  280.                       msecs_to_jiffies(TS_POLL_PERIOD));  
  281.     else  
  282.         enable_irq(ts->irq);  
  283. }  
  284.   
  285. static irqreturn_t tsc2007_irq(int irq, void *handle)  
  286. {  
  287.     struct tsc2007 *ts = handle;  
  288.   
  289.     if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {  
  290.         disable_irq_nosync(ts->irq);  
  291.         schedule_delayed_work(&ts->work,  
  292.                       msecs_to_jiffies(TS_POLL_DELAY));  
  293.     }  
  294.   
  295.     if (ts->clear_penirq)  
  296.         ts->clear_penirq();  
  297.   
  298.     return IRQ_HANDLED;  
  299. }  
  300.   
  301. static void tsc2007_free_irq(struct tsc2007 *ts)  
  302. {  
  303.     free_irq(ts->irq, ts);  
  304.     if (cancel_delayed_work_sync(&ts->work)) {  
  305.         /* 
  306.          * Work was pending, therefore we need to enable 
  307.          * IRQ here to balance the disable_irq() done in the 
  308.          * interrupt handler. 
  309.          */  
  310.         enable_irq(ts->irq);  
  311.     }  
  312. }  
  313.   
  314. static int __devinit tsc2007_probe(struct i2c_client *client,  
  315.                    const struct i2c_device_id *id)  
  316. {  
  317.     struct tsc2007 *ts;  
  318.     struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;  
  319.     struct input_dev *input_dev;  
  320.     int err;  
  321.   
  322.     if (!pdata) {  
  323.         dev_err(&client->dev, "platform data is required!\n");  
  324.         return -EINVAL;  
  325.     }  
  326.   
  327.     if (!i2c_check_functionality(client->adapter,  
  328.                      I2C_FUNC_SMBUS_READ_WORD_DATA))  
  329.         return -EIO;  
  330.   
  331.     ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);  
  332.     input_dev = input_allocate_device();  
  333.     if (!ts || !input_dev) {  
  334.         err = -ENOMEM;  
  335.         goto err_free_mem;  
  336.     }  
  337.   
  338.     ts->client = client;  
  339.     ts->irq = client->irq;  
  340.     ts->input = input_dev;  
  341.     INIT_DELAYED_WORK(&ts->work, tsc2007_work);  
  342.   
  343.     ts->model             = pdata->model;  
  344.     ts->x_plate_ohms      = pdata->x_plate_ohms;  
  345.     ts->get_pendown_state = pdata->get_pendown_state;  
  346.     ts->clear_penirq      = pdata->clear_penirq;  
  347.   
  348.     snprintf(ts->phys, sizeof(ts->phys),  
  349.          "%s/input0", dev_name(&client->dev));  
  350.   
  351.     input_dev->name = "TSC2007";  
  352.     input_dev->phys = ts->phys;  
  353.     input_dev->id.vendor = 0x0001;  
  354.     input_dev->id.product = 0x0001;  
  355.     input_dev->id.version = 0x0100;  
  356.     input_dev->id.bustype = BUS_I2C;  
  357.   
  358.     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  
  359.     input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);  
  360.     set_bit(EV_SYN, input_dev->evbit);  
  361.     set_bit(KEY_HOME, input_dev->keybit);  
  362.     //set_bit(KEY_SEARCH, input_dev->keybit);  
  363.     set_bit(KEY_BACK, input_dev->keybit);  
  364.     set_bit(KEY_MENU, input_dev->keybit);  
  365.     input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);  
  366.     input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);  
  367.     input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);  
  368.   
  369.     if (pdata->init_platform_hw)  
  370.         pdata->init_platform_hw();  
  371.   
  372.     err = request_irq(ts->irq, tsc2007_irq, 0,  
  373.             client->dev.driver->name, ts);  
  374.     if (err < 0) {  
  375.         dev_err(&client->dev, "irq %d busy?\n", ts->irq);  
  376.         goto err_free_mem;  
  377.     }  
  378.   
  379.     /* Prepare for touch readings - power down ADC and enable PENIRQ */  
  380.     err = tsc2007_xfer(ts, PWRDOWN);  
  381.     if (err < 0)  
  382.         goto err_free_irq;  
  383.   
  384.     err = input_register_device(input_dev);  
  385.     if (err)  
  386.         goto err_free_irq;  
  387.   
  388.     i2c_set_clientdata(client, ts);  
  389.   
  390.     return 0;  
  391.   
  392.  err_free_irq:  
  393.     tsc2007_free_irq(ts);  
  394.     if (pdata->exit_platform_hw)  
  395.         pdata->exit_platform_hw();  
  396.  err_free_mem:  
  397.     input_free_device(input_dev);  
  398.     kfree(ts);  
  399.     return err;  
  400. }  
  401.   
  402. static int __devexit tsc2007_remove(struct i2c_client *client)  
  403. {  
  404.     struct tsc2007  *ts = i2c_get_clientdata(client);  
  405.     struct tsc2007_platform_data *pdata = client->dev.platform_data;  
  406.   
  407.     tsc2007_free_irq(ts);  
  408.   
  409.     if (pdata->exit_platform_hw)  
  410.         pdata->exit_platform_hw();  
  411.   
  412.     input_unregister_device(ts->input);  
  413.     kfree(ts);  
  414.   
  415.     return 0;  
  416. }  
  417.   
  418. static struct i2c_device_id tsc2007_idtable[] = {  
  419.     { "tsc2007", 0 },  
  420.     { }  
  421. };  
  422.   
  423. MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);  
  424.   
  425. static struct i2c_driver tsc2007_driver = {  
  426.     .driver = {  
  427.         .owner  = THIS_MODULE,  
  428.         .name   = "tsc2007"  
  429.     },  
  430.     .id_table   = tsc2007_idtable,  
  431.     .probe      = tsc2007_probe,  
  432.     .remove     = __devexit_p(tsc2007_remove),  
  433. };  
  434.   
  435. static int __init tsc2007_init(void)  
  436. {  
  437.     return i2c_add_driver(&tsc2007_driver);  
  438. }  
  439.   
  440. static void __exit tsc2007_exit(void)  
  441. {  
  442.     i2c_del_driver(&tsc2007_driver);  
  443. }  
  444.   
  445. module_init(tsc2007_init);  
  446. module_exit(tsc2007_exit);  
  447.   
  448. MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");  
  449. MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");  
  450. MODULE_LICENSE("GPL");  

实践证明上述方式完全可行,这里我没有指定TSC2007的kl和kcm文件,android系统会自动选择默认的\android\sdk\emulator\keymaps\目录下的qwerty.kl和qwerty.kcm文件,如果你的系统不能正常收到按键消息,你首先可以用android的getevent看看驱动是否能正常发送按键消息给上层,如果能正常收到触摸屏驱动发送的按键消息,上层android系统不能收到的原因就是kl和kcm文件不对。
5.另外附上加载TSC2007驱动的代码
 
[cpp]  view plain copy
  1. /* TouchScreen */  
  2. #define IRQ1 1  
  3. unsigned int tsc2007_int;  
  4. unsigned int tsc2007_irq_no;  
  5. static int ts_get_pendown_state(void)  
  6. {  
  7.     int result=!(imapx_gpio_getpin(tsc2007_int, IG_NORMAL));  
  8.     //printk("%d\n",result);  
  9.     return result;  
  10. }  
  11. static int ts_init(void)  
  12. {  
  13.   
  14.     //printk("====ts_init===\n");  
  15.     tsc2007_int  = __imapx_name_to_gpio(CONFIG_TP_TSC2007_INT);  
  16.     if(tsc2007_int == IMAPX_GPIO_ERROR) {  
  17.         printk(KERN_ERR "failed to get tsc2007_int pin.\n");  
  18.         return -1;  
  19.     }  
  20.     tsc2007_irq_no = imapx_gpio_to_irq(tsc2007_int);  
  21.     imapx_gpio_setcfg(tsc2007_int, IG_INPUT, IG_NORMAL);  
  22.     imapx_gpio_setirq(tsc2007_int, FILTER_MAX, IG_FALL, 1);  
  23.     return 0;  
  24. }  
  25. struct tsc2007_platform_data tsc2007_info = {  
  26.     .model          = 2007,  
  27.     .x_plate_ohms       = 180,  
  28.     .get_pendown_state  = ts_get_pendown_state,  
  29.     .init_platform_hw   = ts_init,  
  30. };  
  31. static struct i2c_board_info ts_i2c_clients = {  
  32.     I2C_BOARD_INFO("tsc2007", 0x48),  
  33.     .type       = "tsc2007",  
  34.     .platform_data  = &tsc2007_info,  
  35.     .irq        = IRQ1,  
  36. };  
  37. static int __init imap_arch_init(void)  
  38. {  
  39.     int ret;  
  40.   
  41.     // do the correct init for cpu  
  42.   
  43.     if (cpu == NULL)  
  44.         panic("imap_arch_init: NULL cpu\n");  
  45.   
  46.     ret = (cpu->init)();  
  47.     if (ret != 0)  
  48.         return ret;  
  49.   
  50.     ret = platform_add_devices(imap_uart_devs, nr_uarts);  
  51.     if (ret != 0)  
  52.         return ret;  
  53.     /*瑙︽懜灞?/  
  54.     i2c_register_board_info(1, &ts_i2c_clients, 1);  
  55.     /*瑙︽懜灞忚櫄鎷熸寜閿?/  
  56.     //virtual_keys_init();  
  57.     printk(KERN_INFO "leaving imap_arch_init\n");  
  58.     return ret;  
  59. }  
----------------------------------------------------------------------------------------------------------------------------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值