Input: psmouse - add support for Elantech touchpads

This is version 5 of the driver. Relative mode support has been
dropped (users wishing to use touchpad in relative mode can use
standard PS/2 protocol emulation done in hardware). The driver
supports both original version of Elantech protocol and the newer
one used by touchpads installed in EeePC.

Signed-off-by: Arjan Opmeer <arjan@opmeer.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by Arjan Opmeer and committed by Dmitry Torokhov 2a0bd75e 2c6f2cb8

+1251 -2
+405
Documentation/input/elantech.txt
··· 1 + Elantech Touchpad Driver 2 + ======================== 3 + 4 + Copyright (C) 2007-2008 Arjan Opmeer <arjan@opmeer.net> 5 + 6 + Extra information for hardware version 1 found and 7 + provided by Steve Havelka 8 + 9 + Version 2 (EeePC) hardware support based on patches 10 + received from Woody at Xandros and forwarded to me 11 + by user StewieGriffin at the eeeuser.com forum 12 + 13 + 14 + Contents 15 + ~~~~~~~~ 16 + 17 + 1. Introduction 18 + 2. Extra knobs 19 + 3. Hardware version 1 20 + 3.1 Registers 21 + 3.2 Native relative mode 4 byte packet format 22 + 3.3 Native absolute mode 4 byte packet format 23 + 4. Hardware version 2 24 + 4.1 Registers 25 + 4.2 Native absolute mode 6 byte packet format 26 + 4.2.1 One finger touch 27 + 4.2.2 Two finger touch 28 + 29 + 30 + 31 + 1. Introduction 32 + ~~~~~~~~~~~~ 33 + 34 + Currently the Linux Elantech touchpad driver is aware of two different 35 + hardware versions unimaginatively called version 1 and version 2. Version 1 36 + is found in "older" laptops and uses 4 bytes per packet. Version 2 seems to 37 + be introduced with the EeePC and uses 6 bytes per packet. 38 + 39 + The driver tries to support both hardware versions and should be compatible 40 + with the Xorg Synaptics touchpad driver and its graphical configuration 41 + utilities. 42 + 43 + Additionally the operation of the touchpad can be altered by adjusting the 44 + contents of some of its internal registers. These registers are represented 45 + by the driver as sysfs entries under /sys/bus/serio/drivers/psmouse/serio? 46 + that can be read from and written to. 47 + 48 + Currently only the registers for hardware version 1 are somewhat understood. 49 + Hardware version 2 seems to use some of the same registers but it is not 50 + known whether the bits in the registers represent the same thing or might 51 + have changed their meaning. 52 + 53 + On top of that, some register settings have effect only when the touchpad is 54 + in relative mode and not in absolute mode. As the Linux Elantech touchpad 55 + driver always puts the hardware into absolute mode not all information 56 + mentioned below can be used immediately. But because there is no freely 57 + available Elantech documentation the information is provided here anyway for 58 + completeness sake. 59 + 60 + 61 + ///////////////////////////////////////////////////////////////////////////// 62 + 63 + 64 + 2. Extra knobs 65 + ~~~~~~~~~~~ 66 + 67 + Currently the Linux Elantech touchpad driver provides two extra knobs under 68 + /sys/bus/serio/drivers/psmouse/serio? for the user. 69 + 70 + * debug 71 + 72 + Turn different levels of debugging ON or OFF. 73 + 74 + By echoing "0" to this file all debugging will be turned OFF. 75 + 76 + Currently a value of "1" will turn on some basic debugging and a value of 77 + "2" will turn on packet debugging. For hardware version 1 the default is 78 + OFF. For version 2 the default is "1". 79 + 80 + Turning packet debugging on will make the driver dump every packet 81 + received to the syslog before processing it. Be warned that this can 82 + generate quite a lot of data! 83 + 84 + * paritycheck 85 + 86 + Turns parity checking ON or OFF. 87 + 88 + By echoing "0" to this file parity checking will be turned OFF. Any 89 + non-zero value will turn it ON. For hardware version 1 the default is ON. 90 + For version 2 the default it is OFF. 91 + 92 + Hardware version 1 provides basic data integrity verification by 93 + calculating a parity bit for the last 3 bytes of each packet. The driver 94 + can check these bits and reject any packet that appears corrupted. Using 95 + this knob you can bypass that check. 96 + 97 + It is not known yet whether hardware version 2 provides the same parity 98 + bits. Hence checking is disabled by default. Currently even turning it on 99 + will do nothing. 100 + 101 + 102 + ///////////////////////////////////////////////////////////////////////////// 103 + 104 + 105 + 3. Hardware version 1 106 + ================== 107 + 108 + 3.1 Registers 109 + ~~~~~~~~~ 110 + 111 + By echoing a hexadecimal value to a register it contents can be altered. 112 + 113 + For example: 114 + 115 + echo -n 0x16 > reg_10 116 + 117 + * reg_10 118 + 119 + bit 7 6 5 4 3 2 1 0 120 + B C T D L A S E 121 + 122 + E: 1 = enable smart edges unconditionally 123 + S: 1 = enable smart edges only when dragging 124 + A: 1 = absolute mode (needs 4 byte packets, see reg_11) 125 + L: 1 = enable drag lock (see reg_22) 126 + D: 1 = disable dynamic resolution 127 + T: 1 = disable tapping 128 + C: 1 = enable corner tap 129 + B: 1 = swap left and right button 130 + 131 + * reg_11 132 + 133 + bit 7 6 5 4 3 2 1 0 134 + 1 0 0 H V 1 F P 135 + 136 + P: 1 = enable parity checking for relative mode 137 + F: 1 = enable native 4 byte packet mode 138 + V: 1 = enable vertical scroll area 139 + H: 1 = enable horizontal scroll area 140 + 141 + * reg_20 142 + 143 + single finger width? 144 + 145 + * reg_21 146 + 147 + scroll area width (small: 0x40 ... wide: 0xff) 148 + 149 + * reg_22 150 + 151 + drag lock time out (short: 0x14 ... long: 0xfe; 152 + 0xff = tap again to release) 153 + 154 + * reg_23 155 + 156 + tap make timeout? 157 + 158 + * reg_24 159 + 160 + tap release timeout? 161 + 162 + * reg_25 163 + 164 + smart edge cursor speed (0x02 = slow, 0x03 = medium, 0x04 = fast) 165 + 166 + * reg_26 167 + 168 + smart edge activation area width? 169 + 170 + 171 + 3.2 Native relative mode 4 byte packet format 172 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 173 + 174 + byte 0: 175 + bit 7 6 5 4 3 2 1 0 176 + c c p2 p1 1 M R L 177 + 178 + L, R, M = 1 when Left, Right, Middle mouse button pressed 179 + some models have M as byte 3 odd parity bit 180 + when parity checking is enabled (reg_11, P = 1): 181 + p1..p2 = byte 1 and 2 odd parity bit 182 + c = 1 when corner tap detected 183 + 184 + byte 1: 185 + bit 7 6 5 4 3 2 1 0 186 + dx7 dx6 dx5 dx4 dx3 dx2 dx1 dx0 187 + 188 + dx7..dx0 = x movement; positive = right, negative = left 189 + byte 1 = 0xf0 when corner tap detected 190 + 191 + byte 2: 192 + bit 7 6 5 4 3 2 1 0 193 + dy7 dy6 dy5 dy4 dy3 dy2 dy1 dy0 194 + 195 + dy7..dy0 = y movement; positive = up, negative = down 196 + 197 + byte 3: 198 + parity checking enabled (reg_11, P = 1): 199 + 200 + bit 7 6 5 4 3 2 1 0 201 + w h n1 n0 ds3 ds2 ds1 ds0 202 + 203 + normally: 204 + ds3..ds0 = scroll wheel amount and direction 205 + positive = down or left 206 + negative = up or right 207 + when corner tap detected: 208 + ds0 = 1 when top right corner tapped 209 + ds1 = 1 when bottom right corner tapped 210 + ds2 = 1 when bottom left corner tapped 211 + ds3 = 1 when top left corner tapped 212 + n1..n0 = number of fingers on touchpad 213 + only models with firmware 2.x report this, models with 214 + firmware 1.x seem to map one, two and three finger taps 215 + directly to L, M and R mouse buttons 216 + h = 1 when horizontal scroll action 217 + w = 1 when wide finger touch? 218 + 219 + otherwise (reg_11, P = 0): 220 + 221 + bit 7 6 5 4 3 2 1 0 222 + ds7 ds6 ds5 ds4 ds3 ds2 ds1 ds0 223 + 224 + ds7..ds0 = vertical scroll amount and direction 225 + negative = up 226 + positive = down 227 + 228 + 229 + 3.3 Native absolute mode 4 byte packet format 230 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 231 + 232 + byte 0: 233 + firmware version 1.x: 234 + 235 + bit 7 6 5 4 3 2 1 0 236 + D U p1 p2 1 p3 R L 237 + 238 + L, R = 1 when Left, Right mouse button pressed 239 + p1..p3 = byte 1..3 odd parity bit 240 + D, U = 1 when rocker switch pressed Up, Down 241 + 242 + firmware version 2.x: 243 + 244 + bit 7 6 5 4 3 2 1 0 245 + n1 n0 p2 p1 1 p3 R L 246 + 247 + L, R = 1 when Left, Right mouse button pressed 248 + p1..p3 = byte 1..3 odd parity bit 249 + n1..n0 = number of fingers on touchpad 250 + 251 + byte 1: 252 + firmware version 1.x: 253 + 254 + bit 7 6 5 4 3 2 1 0 255 + f 0 th tw x9 x8 y9 y8 256 + 257 + tw = 1 when two finger touch 258 + th = 1 when three finger touch 259 + f = 1 when finger touch 260 + 261 + firmware version 2.x: 262 + 263 + bit 7 6 5 4 3 2 1 0 264 + . . . . x9 x8 y9 y8 265 + 266 + byte 2: 267 + bit 7 6 5 4 3 2 1 0 268 + x7 x6 x5 x4 x3 x2 x1 x0 269 + 270 + x9..x0 = absolute x value (horizontal) 271 + 272 + byte 3: 273 + bit 7 6 5 4 3 2 1 0 274 + y7 y6 y5 y4 y3 y2 y1 y0 275 + 276 + y9..y0 = absolute y value (vertical) 277 + 278 + 279 + ///////////////////////////////////////////////////////////////////////////// 280 + 281 + 282 + 4. Hardware version 2 283 + ================== 284 + 285 + 286 + 4.1 Registers 287 + ~~~~~~~~~ 288 + 289 + By echoing a hexadecimal value to a register it contents can be altered. 290 + 291 + For example: 292 + 293 + echo -n 0x56 > reg_10 294 + 295 + * reg_10 296 + 297 + bit 7 6 5 4 3 2 1 0 298 + 0 1 0 1 0 1 D 0 299 + 300 + D: 1 = enable drag and drop 301 + 302 + * reg_11 303 + 304 + bit 7 6 5 4 3 2 1 0 305 + 1 0 0 0 S 0 1 0 306 + 307 + S: 1 = enable vertical scroll 308 + 309 + * reg_21 310 + 311 + unknown (0x00) 312 + 313 + * reg_22 314 + 315 + drag and drop release time out (short: 0x70 ... long 0x7e; 316 + 0x7f = never i.e. tap again to release) 317 + 318 + 319 + 4.2 Native absolute mode 6 byte packet format 320 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 321 + 322 + 4.2.1 One finger touch 323 + ~~~~~~~~~~~~~~~~ 324 + 325 + byte 0: 326 + 327 + bit 7 6 5 4 3 2 1 0 328 + n1 n0 . . . . R L 329 + 330 + L, R = 1 when Left, Right mouse button pressed 331 + n1..n0 = numbers of fingers on touchpad 332 + 333 + byte 1: 334 + 335 + bit 7 6 5 4 3 2 1 0 336 + x15 x14 x13 x12 x11 x10 x9 x8 337 + 338 + byte 2: 339 + 340 + bit 7 6 5 4 3 2 1 0 341 + x7 x6 x5 x4 x4 x2 x1 x0 342 + 343 + x15..x0 = absolute x value (horizontal) 344 + 345 + byte 3: 346 + 347 + bit 7 6 5 4 3 2 1 0 348 + . . . . . . . . 349 + 350 + byte 4: 351 + 352 + bit 7 6 5 4 3 2 1 0 353 + y15 y14 y13 y12 y11 y10 y8 y8 354 + 355 + byte 5: 356 + 357 + bit 7 6 5 4 3 2 1 0 358 + y7 y6 y5 y4 y3 y2 y1 y0 359 + 360 + y15..y0 = absolute y value (vertical) 361 + 362 + 363 + 4.2.2 Two finger touch 364 + ~~~~~~~~~~~~~~~~ 365 + 366 + byte 0: 367 + 368 + bit 7 6 5 4 3 2 1 0 369 + n1 n0 ay8 ax8 . . R L 370 + 371 + L, R = 1 when Left, Right mouse button pressed 372 + n1..n0 = numbers of fingers on touchpad 373 + 374 + byte 1: 375 + 376 + bit 7 6 5 4 3 2 1 0 377 + ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 378 + 379 + ax8..ax0 = first finger absolute x value 380 + 381 + byte 2: 382 + 383 + bit 7 6 5 4 3 2 1 0 384 + ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 385 + 386 + ay8..ay0 = first finger absolute y value 387 + 388 + byte 3: 389 + 390 + bit 7 6 5 4 3 2 1 0 391 + . . by8 bx8 . . . . 392 + 393 + byte 4: 394 + 395 + bit 7 6 5 4 3 2 1 0 396 + bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 397 + 398 + bx8..bx0 = second finger absolute x value 399 + 400 + byte 5: 401 + 402 + bit 7 6 5 4 3 2 1 0 403 + by7 by8 by5 by4 by3 by2 by1 by0 404 + 405 + by8..by0 = second finger absolute y value
+23 -2
drivers/input/mouse/Kconfig
··· 25 25 mice with wheels and extra buttons, Microsoft, Logitech or Genius 26 26 compatible. 27 27 28 - Synaptics TouchPad users might be interested in a specialized 29 - XFree86 driver at: 28 + Synaptics, ALPS or Elantech TouchPad users might be interested 29 + in a specialized Xorg/XFree86 driver at: 30 30 <http://w1.894.telia.com/~u89404340/touchpad/index.html> 31 31 and a new version of GPM at: 32 32 <http://www.geocities.com/dt_or/gpm/gpm.html> ··· 86 86 to your system. 87 87 88 88 If unsure, say Y. 89 + 90 + config MOUSE_PS2_ELANTECH 91 + bool "Elantech PS/2 protocol extension" 92 + depends on MOUSE_PS2 93 + help 94 + Say Y here if you have an Elantech PS/2 touchpad connected 95 + to your system. 96 + 97 + Note that if you enable this driver you will need an updated 98 + X.org Synaptics driver that does not require ABS_PRESSURE 99 + reports from the touchpad (i.e. post 1.5.0 version). You can 100 + grab a patch for the driver here: 101 + 102 + http://userweb.kernel.org/~dtor/synaptics-no-abspressure.patch 103 + 104 + If unsure, say N. 105 + 106 + This driver exposes some configuration registers via sysfs 107 + entries. For further information, 108 + see <file:Documentation/input/elantech.txt>. 109 + 89 110 90 111 config MOUSE_PS2_TOUCHKIT 91 112 bool "eGalax TouchKit PS/2 protocol extension"
+1
drivers/input/mouse/Makefile
··· 21 21 psmouse-objs := psmouse-base.o synaptics.o 22 22 23 23 psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o 24 + psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o 24 25 psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o 25 26 psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o 26 27 psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
+674
drivers/input/mouse/elantech.c
··· 1 + /* 2 + * Elantech Touchpad driver (v5) 3 + * 4 + * Copyright (C) 2007-2008 Arjan Opmeer <arjan@opmeer.net> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published 8 + * by the Free Software Foundation. 9 + * 10 + * Trademarks are the property of their respective owners. 11 + */ 12 + 13 + #include <linux/delay.h> 14 + #include <linux/module.h> 15 + #include <linux/input.h> 16 + #include <linux/serio.h> 17 + #include <linux/libps2.h> 18 + #include "psmouse.h" 19 + #include "elantech.h" 20 + 21 + #define elantech_debug(format, arg...) \ 22 + do { \ 23 + if (etd->debug) \ 24 + printk(KERN_DEBUG format, ##arg); \ 25 + } while (0) 26 + 27 + /* 28 + * Send a Synaptics style sliced query command 29 + */ 30 + static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, 31 + unsigned char *param) 32 + { 33 + if (psmouse_sliced_command(psmouse, c) || 34 + ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { 35 + pr_err("elantech.c: synaptics_send_cmd query 0x%02x failed.\n", c); 36 + return -1; 37 + } 38 + 39 + return 0; 40 + } 41 + 42 + /* 43 + * A retrying version of ps2_command 44 + */ 45 + static int elantech_ps2_command(struct psmouse *psmouse, 46 + unsigned char *param, int command) 47 + { 48 + struct ps2dev *ps2dev = &psmouse->ps2dev; 49 + struct elantech_data *etd = psmouse->private; 50 + int rc; 51 + int tries = ETP_PS2_COMMAND_TRIES; 52 + 53 + do { 54 + rc = ps2_command(ps2dev, param, command); 55 + if (rc == 0) 56 + break; 57 + tries--; 58 + elantech_debug("elantech.c: retrying ps2 command 0x%02x (%d).\n", 59 + command, tries); 60 + msleep(ETP_PS2_COMMAND_DELAY); 61 + } while (tries > 0); 62 + 63 + if (rc) 64 + pr_err("elantech.c: ps2 command 0x%02x failed.\n", command); 65 + 66 + return rc; 67 + } 68 + 69 + /* 70 + * Send an Elantech style special command to read a value from a register 71 + */ 72 + static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, 73 + unsigned char *val) 74 + { 75 + struct elantech_data *etd = psmouse->private; 76 + unsigned char param[3]; 77 + int rc = 0; 78 + 79 + if (reg < 0x10 || reg > 0x26) 80 + return -1; 81 + 82 + if (reg > 0x11 && reg < 0x20) 83 + return -1; 84 + 85 + switch (etd->hw_version) { 86 + case 1: 87 + if (psmouse_sliced_command(psmouse, ETP_REGISTER_READ) || 88 + psmouse_sliced_command(psmouse, reg) || 89 + ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { 90 + rc = -1; 91 + } 92 + break; 93 + 94 + case 2: 95 + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || 96 + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_READ) || 97 + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || 98 + elantech_ps2_command(psmouse, NULL, reg) || 99 + elantech_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO)) { 100 + rc = -1; 101 + } 102 + break; 103 + } 104 + 105 + if (rc) 106 + pr_err("elantech.c: failed to read register 0x%02x.\n", reg); 107 + else 108 + *val = param[0]; 109 + 110 + return rc; 111 + } 112 + 113 + /* 114 + * Send an Elantech style special command to write a register with a value 115 + */ 116 + static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, 117 + unsigned char val) 118 + { 119 + struct elantech_data *etd = psmouse->private; 120 + int rc = 0; 121 + 122 + if (reg < 0x10 || reg > 0x26) 123 + return -1; 124 + 125 + if (reg > 0x11 && reg < 0x20) 126 + return -1; 127 + 128 + switch (etd->hw_version) { 129 + case 1: 130 + if (psmouse_sliced_command(psmouse, ETP_REGISTER_WRITE) || 131 + psmouse_sliced_command(psmouse, reg) || 132 + psmouse_sliced_command(psmouse, val) || 133 + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) { 134 + rc = -1; 135 + } 136 + break; 137 + 138 + case 2: 139 + if (elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || 140 + elantech_ps2_command(psmouse, NULL, ETP_REGISTER_WRITE) || 141 + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || 142 + elantech_ps2_command(psmouse, NULL, reg) || 143 + elantech_ps2_command(psmouse, NULL, ETP_PS2_CUSTOM_COMMAND) || 144 + elantech_ps2_command(psmouse, NULL, val) || 145 + elantech_ps2_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) { 146 + rc = -1; 147 + } 148 + break; 149 + } 150 + 151 + if (rc) 152 + pr_err("elantech.c: failed to write register 0x%02x with value 0x%02x.\n", 153 + reg, val); 154 + 155 + return rc; 156 + } 157 + 158 + /* 159 + * Dump a complete mouse movement packet to the syslog 160 + */ 161 + static void elantech_packet_dump(unsigned char *packet, int size) 162 + { 163 + int i; 164 + 165 + printk(KERN_DEBUG "elantech.c: PS/2 packet ["); 166 + for (i = 0; i < size; i++) 167 + printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); 168 + printk("]\n"); 169 + } 170 + 171 + /* 172 + * Interpret complete data packets and report absolute mode input events for 173 + * hardware version 1. (4 byte packets) 174 + */ 175 + static void elantech_report_absolute_v1(struct psmouse *psmouse) 176 + { 177 + struct input_dev *dev = psmouse->dev; 178 + struct elantech_data *etd = psmouse->private; 179 + unsigned char *packet = psmouse->packet; 180 + int fingers; 181 + 182 + if (etd->fw_version_maj == 0x01) { 183 + /* byte 0: D U p1 p2 1 p3 R L 184 + byte 1: f 0 th tw x9 x8 y9 y8 */ 185 + fingers = ((packet[1] & 0x80) >> 7) + 186 + ((packet[1] & 0x30) >> 4); 187 + } else { 188 + /* byte 0: n1 n0 p2 p1 1 p3 R L 189 + byte 1: 0 0 0 0 x9 x8 y9 y8 */ 190 + fingers = (packet[0] & 0xc0) >> 6; 191 + } 192 + 193 + input_report_key(dev, BTN_TOUCH, fingers != 0); 194 + 195 + /* byte 2: x7 x6 x5 x4 x3 x2 x1 x0 196 + byte 3: y7 y6 y5 y4 y3 y2 y1 y0 */ 197 + if (fingers) { 198 + input_report_abs(dev, ABS_X, 199 + ((packet[1] & 0x0c) << 6) | packet[2]); 200 + input_report_abs(dev, ABS_Y, ETP_YMAX_V1 - 201 + (((packet[1] & 0x03) << 8) | packet[3])); 202 + } 203 + 204 + input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); 205 + input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); 206 + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); 207 + input_report_key(dev, BTN_LEFT, packet[0] & 0x01); 208 + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); 209 + 210 + if ((etd->fw_version_maj == 0x01) && 211 + (etd->capabilities & ETP_CAP_HAS_ROCKER)) { 212 + /* rocker up */ 213 + input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); 214 + /* rocker down */ 215 + input_report_key(dev, BTN_BACK, packet[0] & 0x80); 216 + } 217 + 218 + input_sync(dev); 219 + } 220 + 221 + /* 222 + * Interpret complete data packets and report absolute mode input events for 223 + * hardware version 2. (6 byte packets) 224 + */ 225 + static void elantech_report_absolute_v2(struct psmouse *psmouse) 226 + { 227 + struct input_dev *dev = psmouse->dev; 228 + unsigned char *packet = psmouse->packet; 229 + int fingers, x1, y1, x2, y2; 230 + 231 + /* byte 0: n1 n0 . . . . R L */ 232 + fingers = (packet[0] & 0xc0) >> 6; 233 + input_report_key(dev, BTN_TOUCH, fingers != 0); 234 + 235 + switch (fingers) { 236 + case 1: 237 + /* byte 1: x15 x14 x13 x12 x11 x10 x9 x8 238 + byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */ 239 + input_report_abs(dev, ABS_X, (packet[1] << 8) | packet[2]); 240 + /* byte 4: y15 y14 y13 y12 y11 y10 y8 y8 241 + byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ 242 + input_report_abs(dev, ABS_Y, ETP_YMAX_V2 - 243 + ((packet[4] << 8) | packet[5])); 244 + break; 245 + 246 + case 2: 247 + /* The coordinate of each finger is reported separately with 248 + a lower resolution for two finger touches */ 249 + /* byte 0: . . ay8 ax8 . . . . 250 + byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */ 251 + x1 = ((packet[0] & 0x10) << 4) | packet[1]; 252 + /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ 253 + y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]); 254 + /* byte 3: . . by8 bx8 . . . . 255 + byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */ 256 + x2 = ((packet[3] & 0x10) << 4) | packet[4]; 257 + /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ 258 + y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]); 259 + /* For compatibility with the X Synaptics driver scale up one 260 + coordinate and report as ordinary mouse movent */ 261 + input_report_abs(dev, ABS_X, x1 << 2); 262 + input_report_abs(dev, ABS_Y, y1 << 2); 263 + /* For compatibility with the proprietary X Elantech driver 264 + report both coordinates as hat coordinates */ 265 + input_report_abs(dev, ABS_HAT0X, x1); 266 + input_report_abs(dev, ABS_HAT0Y, y1); 267 + input_report_abs(dev, ABS_HAT1X, x2); 268 + input_report_abs(dev, ABS_HAT1Y, y2); 269 + break; 270 + } 271 + 272 + input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); 273 + input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); 274 + input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); 275 + input_report_key(dev, BTN_LEFT, packet[0] & 0x01); 276 + input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); 277 + 278 + input_sync(dev); 279 + } 280 + 281 + static int elantech_check_parity_v1(struct psmouse *psmouse) 282 + { 283 + struct elantech_data *etd = psmouse->private; 284 + unsigned char *packet = psmouse->packet; 285 + unsigned char p1, p2, p3; 286 + 287 + /* Parity bits are placed differently */ 288 + if (etd->fw_version_maj == 0x01) { 289 + /* byte 0: D U p1 p2 1 p3 R L */ 290 + p1 = (packet[0] & 0x20) >> 5; 291 + p2 = (packet[0] & 0x10) >> 4; 292 + } else { 293 + /* byte 0: n1 n0 p2 p1 1 p3 R L */ 294 + p1 = (packet[0] & 0x10) >> 4; 295 + p2 = (packet[0] & 0x20) >> 5; 296 + } 297 + 298 + p3 = (packet[0] & 0x04) >> 2; 299 + 300 + return etd->parity[packet[1]] == p1 && 301 + etd->parity[packet[2]] == p2 && 302 + etd->parity[packet[3]] == p3; 303 + } 304 + 305 + /* 306 + * Process byte stream from mouse and handle complete packets 307 + */ 308 + static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) 309 + { 310 + struct elantech_data *etd = psmouse->private; 311 + 312 + if (psmouse->pktcnt < psmouse->pktsize) 313 + return PSMOUSE_GOOD_DATA; 314 + 315 + if (etd->debug > 1) 316 + elantech_packet_dump(psmouse->packet, psmouse->pktsize); 317 + 318 + switch (etd->hw_version) { 319 + case 1: 320 + if (etd->paritycheck && !elantech_check_parity_v1(psmouse)) 321 + return PSMOUSE_BAD_DATA; 322 + 323 + elantech_report_absolute_v1(psmouse); 324 + break; 325 + 326 + case 2: 327 + /* We don't know how to check parity in protocol v2 */ 328 + elantech_report_absolute_v2(psmouse); 329 + break; 330 + } 331 + 332 + return PSMOUSE_FULL_PACKET; 333 + } 334 + 335 + /* 336 + * Put the touchpad into absolute mode 337 + */ 338 + static int elantech_set_absolute_mode(struct psmouse *psmouse) 339 + { 340 + struct elantech_data *etd = psmouse->private; 341 + unsigned char val; 342 + int tries = ETP_READ_BACK_TRIES; 343 + int rc = 0; 344 + 345 + switch (etd->hw_version) { 346 + case 1: 347 + etd->reg_10 = 0x16; 348 + etd->reg_11 = 0x8f; 349 + if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || 350 + elantech_write_reg(psmouse, 0x11, etd->reg_11)) { 351 + rc = -1; 352 + } 353 + break; 354 + 355 + case 2: 356 + /* Windows driver values */ 357 + etd->reg_10 = 0x54; 358 + etd->reg_11 = 0x88; /* 0x8a */ 359 + etd->reg_21 = 0x60; /* 0x00 */ 360 + if (elantech_write_reg(psmouse, 0x10, etd->reg_10) || 361 + elantech_write_reg(psmouse, 0x11, etd->reg_11) || 362 + elantech_write_reg(psmouse, 0x21, etd->reg_21)) { 363 + rc = -1; 364 + break; 365 + } 366 + /* 367 + * Read back reg 0x10. The touchpad is probably initalising 368 + * and not ready until we read back the value we just wrote. 369 + */ 370 + do { 371 + rc = elantech_read_reg(psmouse, 0x10, &val); 372 + if (rc == 0) 373 + break; 374 + tries--; 375 + elantech_debug("elantech.c: retrying read (%d).\n", 376 + tries); 377 + msleep(ETP_READ_BACK_DELAY); 378 + } while (tries > 0); 379 + if (rc) 380 + pr_err("elantech.c: failed to read back register 0x10.\n"); 381 + break; 382 + } 383 + 384 + if (rc) 385 + pr_err("elantech.c: failed to initialise registers.\n"); 386 + 387 + return rc; 388 + } 389 + 390 + /* 391 + * Set the appropriate event bits for the input subsystem 392 + */ 393 + static void elantech_set_input_params(struct psmouse *psmouse) 394 + { 395 + struct input_dev *dev = psmouse->dev; 396 + struct elantech_data *etd = psmouse->private; 397 + 398 + __set_bit(EV_KEY, dev->evbit); 399 + __set_bit(EV_ABS, dev->evbit); 400 + 401 + __set_bit(BTN_LEFT, dev->keybit); 402 + __set_bit(BTN_RIGHT, dev->keybit); 403 + 404 + __set_bit(BTN_TOUCH, dev->keybit); 405 + __set_bit(BTN_TOOL_FINGER, dev->keybit); 406 + __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); 407 + __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); 408 + 409 + switch (etd->hw_version) { 410 + case 1: 411 + /* Rocker button */ 412 + if ((etd->fw_version_maj == 0x01) && 413 + (etd->capabilities & ETP_CAP_HAS_ROCKER)) { 414 + __set_bit(BTN_FORWARD, dev->keybit); 415 + __set_bit(BTN_BACK, dev->keybit); 416 + } 417 + input_set_abs_params(dev, ABS_X, ETP_XMIN_V1, ETP_XMAX_V1, 0, 0); 418 + input_set_abs_params(dev, ABS_Y, ETP_YMIN_V1, ETP_YMAX_V1, 0, 0); 419 + break; 420 + 421 + case 2: 422 + input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); 423 + input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); 424 + input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); 425 + input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); 426 + input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); 427 + input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0); 428 + break; 429 + } 430 + } 431 + 432 + struct elantech_attr_data { 433 + size_t field_offset; 434 + unsigned char reg; 435 + }; 436 + 437 + /* 438 + * Display a register value by reading a sysfs entry 439 + */ 440 + static ssize_t elantech_show_int_attr(struct psmouse *psmouse, void *data, 441 + char *buf) 442 + { 443 + struct elantech_data *etd = psmouse->private; 444 + struct elantech_attr_data *attr = data; 445 + unsigned char *reg = (unsigned char *) etd + attr->field_offset; 446 + int rc = 0; 447 + 448 + if (attr->reg) 449 + rc = elantech_read_reg(psmouse, attr->reg, reg); 450 + 451 + return sprintf(buf, "0x%02x\n", (attr->reg && rc) ? -1 : *reg); 452 + } 453 + 454 + /* 455 + * Write a register value by writing a sysfs entry 456 + */ 457 + static ssize_t elantech_set_int_attr(struct psmouse *psmouse, 458 + void *data, const char *buf, size_t count) 459 + { 460 + struct elantech_data *etd = psmouse->private; 461 + struct elantech_attr_data *attr = data; 462 + unsigned char *reg = (unsigned char *) etd + attr->field_offset; 463 + unsigned long value; 464 + int err; 465 + 466 + err = strict_strtoul(buf, 16, &value); 467 + if (err) 468 + return err; 469 + 470 + if (value > 0xff) 471 + return -EINVAL; 472 + 473 + /* Do we need to preserve some bits for version 2 hardware too? */ 474 + if (etd->hw_version == 1) { 475 + if (attr->reg == 0x10) 476 + /* Force absolute mode always on */ 477 + value |= ETP_R10_ABSOLUTE_MODE; 478 + else if (attr->reg == 0x11) 479 + /* Force 4 byte mode always on */ 480 + value |= ETP_R11_4_BYTE_MODE; 481 + } 482 + 483 + if (!attr->reg || elantech_write_reg(psmouse, attr->reg, value) == 0) 484 + *reg = value; 485 + 486 + return count; 487 + } 488 + 489 + #define ELANTECH_INT_ATTR(_name, _register) \ 490 + static struct elantech_attr_data elantech_attr_##_name = { \ 491 + .field_offset = offsetof(struct elantech_data, _name), \ 492 + .reg = _register, \ 493 + }; \ 494 + PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ 495 + &elantech_attr_##_name, \ 496 + elantech_show_int_attr, \ 497 + elantech_set_int_attr) 498 + 499 + ELANTECH_INT_ATTR(reg_10, 0x10); 500 + ELANTECH_INT_ATTR(reg_11, 0x11); 501 + ELANTECH_INT_ATTR(reg_20, 0x20); 502 + ELANTECH_INT_ATTR(reg_21, 0x21); 503 + ELANTECH_INT_ATTR(reg_22, 0x22); 504 + ELANTECH_INT_ATTR(reg_23, 0x23); 505 + ELANTECH_INT_ATTR(reg_24, 0x24); 506 + ELANTECH_INT_ATTR(reg_25, 0x25); 507 + ELANTECH_INT_ATTR(reg_26, 0x26); 508 + ELANTECH_INT_ATTR(debug, 0); 509 + ELANTECH_INT_ATTR(paritycheck, 0); 510 + 511 + static struct attribute *elantech_attrs[] = { 512 + &psmouse_attr_reg_10.dattr.attr, 513 + &psmouse_attr_reg_11.dattr.attr, 514 + &psmouse_attr_reg_20.dattr.attr, 515 + &psmouse_attr_reg_21.dattr.attr, 516 + &psmouse_attr_reg_22.dattr.attr, 517 + &psmouse_attr_reg_23.dattr.attr, 518 + &psmouse_attr_reg_24.dattr.attr, 519 + &psmouse_attr_reg_25.dattr.attr, 520 + &psmouse_attr_reg_26.dattr.attr, 521 + &psmouse_attr_debug.dattr.attr, 522 + &psmouse_attr_paritycheck.dattr.attr, 523 + NULL 524 + }; 525 + 526 + static struct attribute_group elantech_attr_group = { 527 + .attrs = elantech_attrs, 528 + }; 529 + 530 + /* 531 + * Use magic knock to detect Elantech touchpad 532 + */ 533 + int elantech_detect(struct psmouse *psmouse, int set_properties) 534 + { 535 + struct ps2dev *ps2dev = &psmouse->ps2dev; 536 + unsigned char param[3]; 537 + 538 + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); 539 + 540 + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || 541 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 542 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 543 + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || 544 + ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { 545 + pr_err("elantech.c: sending Elantech magic knock failed.\n"); 546 + return -1; 547 + } 548 + 549 + /* 550 + * Report this in case there are Elantech models that use a different 551 + * set of magic numbers 552 + */ 553 + if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { 554 + pr_info("elantech.c: unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", 555 + param[0], param[1], param[2]); 556 + return -1; 557 + } 558 + 559 + if (set_properties) { 560 + psmouse->vendor = "Elantech"; 561 + psmouse->name = "Touchpad"; 562 + } 563 + 564 + return 0; 565 + } 566 + 567 + /* 568 + * Clean up sysfs entries when disconnecting 569 + */ 570 + static void elantech_disconnect(struct psmouse *psmouse) 571 + { 572 + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, 573 + &elantech_attr_group); 574 + kfree(psmouse->private); 575 + psmouse->private = NULL; 576 + } 577 + 578 + /* 579 + * Put the touchpad back into absolute mode when reconnecting 580 + */ 581 + static int elantech_reconnect(struct psmouse *psmouse) 582 + { 583 + if (elantech_detect(psmouse, 0)) 584 + return -1; 585 + 586 + if (elantech_set_absolute_mode(psmouse)) { 587 + pr_err("elantech.c: failed to put touchpad back into absolute mode.\n"); 588 + return -1; 589 + } 590 + 591 + return 0; 592 + } 593 + 594 + /* 595 + * Initialize the touchpad and create sysfs entries 596 + */ 597 + int elantech_init(struct psmouse *psmouse) 598 + { 599 + struct elantech_data *etd; 600 + int i, error; 601 + unsigned char param[3]; 602 + 603 + etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); 604 + psmouse->private = etd; 605 + if (!etd) 606 + return -1; 607 + 608 + etd->parity[0] = 1; 609 + for (i = 1; i < 256; i++) 610 + etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; 611 + 612 + /* 613 + * Find out what version hardware this is 614 + */ 615 + if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { 616 + pr_err("elantech.c: failed to query firmware version.\n"); 617 + goto init_fail; 618 + } 619 + pr_info("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", 620 + param[0], param[1], param[2]); 621 + etd->fw_version_maj = param[0]; 622 + etd->fw_version_min = param[2]; 623 + 624 + /* 625 + * Assume every version greater than this is new EeePC style 626 + * hardware with 6 byte packets 627 + */ 628 + if (etd->fw_version_maj >= 0x02 && etd->fw_version_min >= 0x30) { 629 + etd->hw_version = 2; 630 + /* For now show extra debug information */ 631 + etd->debug = 1; 632 + /* Don't know how to do parity checking for version 2 */ 633 + etd->paritycheck = 0; 634 + } else { 635 + etd->hw_version = 1; 636 + etd->paritycheck = 1; 637 + } 638 + pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d\n", 639 + etd->hw_version, etd->fw_version_maj, etd->fw_version_min); 640 + 641 + if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { 642 + pr_err("elantech.c: failed to query capabilities.\n"); 643 + goto init_fail; 644 + } 645 + pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", 646 + param[0], param[1], param[2]); 647 + etd->capabilities = param[0]; 648 + 649 + if (elantech_set_absolute_mode(psmouse)) { 650 + pr_err("elantech.c: failed to put touchpad into absolute mode.\n"); 651 + goto init_fail; 652 + } 653 + 654 + elantech_set_input_params(psmouse); 655 + 656 + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, 657 + &elantech_attr_group); 658 + if (error) { 659 + pr_err("elantech.c: failed to create sysfs attributes, error: %d.\n", 660 + error); 661 + goto init_fail; 662 + } 663 + 664 + psmouse->protocol_handler = elantech_process_byte; 665 + psmouse->disconnect = elantech_disconnect; 666 + psmouse->reconnect = elantech_reconnect; 667 + psmouse->pktsize = etd->hw_version == 2 ? 6 : 4; 668 + 669 + return 0; 670 + 671 + init_fail: 672 + kfree(etd); 673 + return -1; 674 + }
+124
drivers/input/mouse/elantech.h
··· 1 + /* 2 + * Elantech Touchpad driver (v5) 3 + * 4 + * Copyright (C) 2007-2008 Arjan Opmeer <arjan@opmeer.net> 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms of the GNU General Public License version 2 as published 8 + * by the Free Software Foundation. 9 + * 10 + * Trademarks are the property of their respective owners. 11 + */ 12 + 13 + #ifndef _ELANTECH_H 14 + #define _ELANTECH_H 15 + 16 + /* 17 + * Command values for Synaptics style queries 18 + */ 19 + #define ETP_FW_VERSION_QUERY 0x01 20 + #define ETP_CAPABILITIES_QUERY 0x02 21 + 22 + /* 23 + * Command values for register reading or writing 24 + */ 25 + #define ETP_REGISTER_READ 0x10 26 + #define ETP_REGISTER_WRITE 0x11 27 + 28 + /* 29 + * Hardware version 2 custom PS/2 command value 30 + */ 31 + #define ETP_PS2_CUSTOM_COMMAND 0xf8 32 + 33 + /* 34 + * Times to retry a ps2_command and millisecond delay between tries 35 + */ 36 + #define ETP_PS2_COMMAND_TRIES 3 37 + #define ETP_PS2_COMMAND_DELAY 500 38 + 39 + /* 40 + * Times to try to read back a register and millisecond delay between tries 41 + */ 42 + #define ETP_READ_BACK_TRIES 5 43 + #define ETP_READ_BACK_DELAY 2000 44 + 45 + /* 46 + * Register bitmasks for hardware version 1 47 + */ 48 + #define ETP_R10_ABSOLUTE_MODE 0x04 49 + #define ETP_R11_4_BYTE_MODE 0x02 50 + 51 + /* 52 + * Capability bitmasks 53 + */ 54 + #define ETP_CAP_HAS_ROCKER 0x04 55 + 56 + /* 57 + * One hard to find application note states that X axis range is 0 to 576 58 + * and Y axis range is 0 to 384 for harware version 1. 59 + * Edge fuzz might be necessary because of bezel around the touchpad 60 + */ 61 + #define ETP_EDGE_FUZZ_V1 32 62 + 63 + #define ETP_XMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) 64 + #define ETP_XMAX_V1 (576 - ETP_EDGE_FUZZ_V1) 65 + #define ETP_YMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) 66 + #define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) 67 + 68 + /* 69 + * It seems the resolution for hardware version 2 doubled. 70 + * Hence the X and Y ranges are doubled too. 71 + * The bezel around the pad also appears to be smaller 72 + */ 73 + #define ETP_EDGE_FUZZ_V2 8 74 + 75 + #define ETP_XMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) 76 + #define ETP_XMAX_V2 (1152 - ETP_EDGE_FUZZ_V2) 77 + #define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2) 78 + #define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2) 79 + 80 + /* 81 + * For two finger touches the coordinate of each finger gets reported 82 + * separately but with reduced resolution. 83 + */ 84 + #define ETP_2FT_FUZZ 4 85 + 86 + #define ETP_2FT_XMIN ( 0 + ETP_2FT_FUZZ) 87 + #define ETP_2FT_XMAX (288 - ETP_2FT_FUZZ) 88 + #define ETP_2FT_YMIN ( 0 + ETP_2FT_FUZZ) 89 + #define ETP_2FT_YMAX (192 - ETP_2FT_FUZZ) 90 + 91 + struct elantech_data { 92 + unsigned char reg_10; 93 + unsigned char reg_11; 94 + unsigned char reg_20; 95 + unsigned char reg_21; 96 + unsigned char reg_22; 97 + unsigned char reg_23; 98 + unsigned char reg_24; 99 + unsigned char reg_25; 100 + unsigned char reg_26; 101 + unsigned char debug; 102 + unsigned char capabilities; 103 + unsigned char fw_version_maj; 104 + unsigned char fw_version_min; 105 + unsigned char hw_version; 106 + unsigned char paritycheck; 107 + unsigned char parity[256]; 108 + }; 109 + 110 + #ifdef CONFIG_MOUSE_PS2_ELANTECH 111 + int elantech_detect(struct psmouse *psmouse, int set_properties); 112 + int elantech_init(struct psmouse *psmouse); 113 + #else 114 + static inline int elantech_detect(struct psmouse *psmouse, int set_properties) 115 + { 116 + return -ENOSYS; 117 + } 118 + static inline int elantech_init(struct psmouse *psmouse) 119 + { 120 + return -ENOSYS; 121 + } 122 + #endif /* CONFIG_MOUSE_PS2_ELANTECH */ 123 + 124 + #endif
+23
drivers/input/mouse/psmouse-base.c
··· 29 29 #include "lifebook.h" 30 30 #include "trackpoint.h" 31 31 #include "touchkit_ps2.h" 32 + #include "elantech.h" 32 33 33 34 #define DRIVER_DESC "PS/2 mouse driver" 34 35 ··· 651 650 max_proto = PSMOUSE_IMEX; 652 651 } 653 652 653 + /* 654 + * Try Elantech touchpad. 655 + */ 656 + if (max_proto > PSMOUSE_IMEX && 657 + elantech_detect(psmouse, set_properties) == 0) { 658 + if (!set_properties || elantech_init(psmouse) == 0) 659 + return PSMOUSE_ELANTECH; 660 + /* 661 + * Init failed, try basic relative protocols 662 + */ 663 + max_proto = PSMOUSE_IMEX; 664 + } 665 + 654 666 if (max_proto > PSMOUSE_IMEX) { 655 667 if (genius_detect(psmouse, set_properties) == 0) 656 668 return PSMOUSE_GENPS; ··· 803 789 .detect = hgpk_detect, 804 790 }, 805 791 #endif 792 + #ifdef CONFIG_MOUSE_PS2_ELANTECH 793 + { 794 + .type = PSMOUSE_ELANTECH, 795 + .name = "ETPS/2", 796 + .alias = "elantech", 797 + .detect = elantech_detect, 798 + .init = elantech_init, 799 + }, 800 + #endif 806 801 { 807 802 .type = PSMOUSE_CORTRON, 808 803 .name = "CortronPS/2",
+1
drivers/input/mouse/psmouse.h
··· 90 90 PSMOUSE_TOUCHKIT_PS2, 91 91 PSMOUSE_CORTRON, 92 92 PSMOUSE_HGPK, 93 + PSMOUSE_ELANTECH, 93 94 PSMOUSE_AUTO /* This one should always be last */ 94 95 }; 95 96