1/* 2 * Focaltech TouchPad PS/2 mouse driver 3 * 4 * Copyright (c) 2014 Red Hat Inc. 5 * Copyright (c) 2014 Mathias Gottschlag <mgottschlag@gmail.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * Red Hat authors: 13 * 14 * Hans de Goede <hdegoede@redhat.com> 15 */ 16 17 18#include <linux/device.h> 19#include <linux/libps2.h> 20#include <linux/input/mt.h> 21#include <linux/serio.h> 22#include <linux/slab.h> 23#include "psmouse.h" 24#include "focaltech.h" 25 26static const char * const focaltech_pnp_ids[] = { 27 "FLT0101", 28 "FLT0102", 29 "FLT0103", 30 NULL 31}; 32 33/* 34 * Even if the kernel is built without support for Focaltech PS/2 touchpads (or 35 * when the real driver fails to recognize the device), we still have to detect 36 * them in order to avoid further detection attempts confusing the touchpad. 37 * This way it at least works in PS/2 mouse compatibility mode. 38 */ 39int focaltech_detect(struct psmouse *psmouse, bool set_properties) 40{ 41 if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) 42 return -ENODEV; 43 44 if (set_properties) { 45 psmouse->vendor = "FocalTech"; 46 psmouse->name = "FocalTech Touchpad"; 47 } 48 49 return 0; 50} 51 52static void focaltech_reset(struct psmouse *psmouse) 53{ 54 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); 55 psmouse_reset(psmouse); 56} 57 58#ifdef CONFIG_MOUSE_PS2_FOCALTECH 59 60/* 61 * Packet types - the numbers are not consecutive, so we might be missing 62 * something here. 63 */ 64#define FOC_TOUCH 0x3 /* bitmap of active fingers */ 65#define FOC_ABS 0x6 /* absolute position of one finger */ 66#define FOC_REL 0x9 /* relative position of 1-2 fingers */ 67 68#define FOC_MAX_FINGERS 5 69 70/* 71 * Current state of a single finger on the touchpad. 72 */ 73struct focaltech_finger_state { 74 /* The touchpad has generated a touch event for the finger */ 75 bool active; 76 77 /* 78 * The touchpad has sent position data for the finger. The 79 * flag is 0 when the finger is not active, and there is a 80 * time between the first touch event for the finger and the 81 * following absolute position packet for the finger where the 82 * touchpad has declared the finger to be valid, but we do not 83 * have any valid position yet. 84 */ 85 bool valid; 86 87 /* 88 * Absolute position (from the bottom left corner) of the 89 * finger. 90 */ 91 unsigned int x; 92 unsigned int y; 93}; 94 95/* 96 * Description of the current state of the touchpad hardware. 97 */ 98struct focaltech_hw_state { 99 /* 100 * The touchpad tracks the positions of the fingers for us, 101 * the array indices correspond to the finger indices returned 102 * in the report packages. 103 */ 104 struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; 105 106 /* 107 * Finger width 0-7 and 15 for a very big contact area. 108 * 15 value stays until the finger is released. 109 * Width is reported only in absolute packets. 110 * Since hardware reports width only for last touching finger, 111 * there is no need to store width for every specific finger, 112 * so we keep only last value reported. 113 */ 114 unsigned int width; 115 116 /* True if the clickpad has been pressed. */ 117 bool pressed; 118}; 119 120struct focaltech_data { 121 unsigned int x_max, y_max; 122 struct focaltech_hw_state state; 123}; 124 125static void focaltech_report_state(struct psmouse *psmouse) 126{ 127 struct focaltech_data *priv = psmouse->private; 128 struct focaltech_hw_state *state = &priv->state; 129 struct input_dev *dev = psmouse->dev; 130 int i; 131 132 for (i = 0; i < FOC_MAX_FINGERS; i++) { 133 struct focaltech_finger_state *finger = &state->fingers[i]; 134 bool active = finger->active && finger->valid; 135 136 input_mt_slot(dev, i); 137 input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 138 if (active) { 139 unsigned int clamped_x, clamped_y; 140 /* 141 * The touchpad might report invalid data, so we clamp 142 * the resulting values so that we do not confuse 143 * userspace. 144 */ 145 clamped_x = clamp(finger->x, 0U, priv->x_max); 146 clamped_y = clamp(finger->y, 0U, priv->y_max); 147 input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); 148 input_report_abs(dev, ABS_MT_POSITION_Y, 149 priv->y_max - clamped_y); 150 input_report_abs(dev, ABS_TOOL_WIDTH, state->width); 151 } 152 } 153 input_mt_report_pointer_emulation(dev, true); 154 155 input_report_key(psmouse->dev, BTN_LEFT, state->pressed); 156 input_sync(psmouse->dev); 157} 158 159static void focaltech_process_touch_packet(struct psmouse *psmouse, 160 unsigned char *packet) 161{ 162 struct focaltech_data *priv = psmouse->private; 163 struct focaltech_hw_state *state = &priv->state; 164 unsigned char fingers = packet[1]; 165 int i; 166 167 state->pressed = (packet[0] >> 4) & 1; 168 169 /* the second byte contains a bitmap of all fingers touching the pad */ 170 for (i = 0; i < FOC_MAX_FINGERS; i++) { 171 state->fingers[i].active = fingers & 0x1; 172 if (!state->fingers[i].active) { 173 /* 174 * Even when the finger becomes active again, we still 175 * will have to wait for the first valid position. 176 */ 177 state->fingers[i].valid = false; 178 } 179 fingers >>= 1; 180 } 181} 182 183static void focaltech_process_abs_packet(struct psmouse *psmouse, 184 unsigned char *packet) 185{ 186 struct focaltech_data *priv = psmouse->private; 187 struct focaltech_hw_state *state = &priv->state; 188 unsigned int finger; 189 190 finger = (packet[1] >> 4) - 1; 191 if (finger >= FOC_MAX_FINGERS) { 192 psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", 193 finger); 194 return; 195 } 196 197 state->pressed = (packet[0] >> 4) & 1; 198 199 state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; 200 state->fingers[finger].y = (packet[3] << 8) | packet[4]; 201 state->width = packet[5] >> 4; 202 state->fingers[finger].valid = true; 203} 204 205static void focaltech_process_rel_packet(struct psmouse *psmouse, 206 unsigned char *packet) 207{ 208 struct focaltech_data *priv = psmouse->private; 209 struct focaltech_hw_state *state = &priv->state; 210 int finger1, finger2; 211 212 state->pressed = packet[0] >> 7; 213 finger1 = ((packet[0] >> 4) & 0x7) - 1; 214 if (finger1 < FOC_MAX_FINGERS) { 215 state->fingers[finger1].x += (char)packet[1]; 216 state->fingers[finger1].y += (char)packet[2]; 217 } else { 218 psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", 219 finger1); 220 } 221 222 /* 223 * If there is an odd number of fingers, the last relative 224 * packet only contains one finger. In this case, the second 225 * finger index in the packet is 0 (we subtract 1 in the lines 226 * above to create array indices, so the finger will overflow 227 * and be above FOC_MAX_FINGERS). 228 */ 229 finger2 = ((packet[3] >> 4) & 0x7) - 1; 230 if (finger2 < FOC_MAX_FINGERS) { 231 state->fingers[finger2].x += (char)packet[4]; 232 state->fingers[finger2].y += (char)packet[5]; 233 } 234} 235 236static void focaltech_process_packet(struct psmouse *psmouse) 237{ 238 unsigned char *packet = psmouse->packet; 239 240 switch (packet[0] & 0xf) { 241 case FOC_TOUCH: 242 focaltech_process_touch_packet(psmouse, packet); 243 break; 244 245 case FOC_ABS: 246 focaltech_process_abs_packet(psmouse, packet); 247 break; 248 249 case FOC_REL: 250 focaltech_process_rel_packet(psmouse, packet); 251 break; 252 253 default: 254 psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); 255 break; 256 } 257 258 focaltech_report_state(psmouse); 259} 260 261static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) 262{ 263 if (psmouse->pktcnt >= 6) { /* Full packet received */ 264 focaltech_process_packet(psmouse); 265 return PSMOUSE_FULL_PACKET; 266 } 267 268 /* 269 * We might want to do some validation of the data here, but 270 * we do not know the protocol well enough 271 */ 272 return PSMOUSE_GOOD_DATA; 273} 274 275static int focaltech_switch_protocol(struct psmouse *psmouse) 276{ 277 struct ps2dev *ps2dev = &psmouse->ps2dev; 278 unsigned char param[3]; 279 280 param[0] = 0; 281 if (ps2_command(ps2dev, param, 0x10f8)) 282 return -EIO; 283 284 if (ps2_command(ps2dev, param, 0x10f8)) 285 return -EIO; 286 287 if (ps2_command(ps2dev, param, 0x10f8)) 288 return -EIO; 289 290 param[0] = 1; 291 if (ps2_command(ps2dev, param, 0x10f8)) 292 return -EIO; 293 294 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) 295 return -EIO; 296 297 if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) 298 return -EIO; 299 300 return 0; 301} 302 303static void focaltech_disconnect(struct psmouse *psmouse) 304{ 305 focaltech_reset(psmouse); 306 kfree(psmouse->private); 307 psmouse->private = NULL; 308} 309 310static int focaltech_reconnect(struct psmouse *psmouse) 311{ 312 int error; 313 314 focaltech_reset(psmouse); 315 316 error = focaltech_switch_protocol(psmouse); 317 if (error) { 318 psmouse_err(psmouse, "Unable to initialize the device\n"); 319 return error; 320 } 321 322 return 0; 323} 324 325static void focaltech_set_input_params(struct psmouse *psmouse) 326{ 327 struct input_dev *dev = psmouse->dev; 328 struct focaltech_data *priv = psmouse->private; 329 330 /* 331 * Undo part of setup done for us by psmouse core since touchpad 332 * is not a relative device. 333 */ 334 __clear_bit(EV_REL, dev->evbit); 335 __clear_bit(REL_X, dev->relbit); 336 __clear_bit(REL_Y, dev->relbit); 337 __clear_bit(BTN_RIGHT, dev->keybit); 338 __clear_bit(BTN_MIDDLE, dev->keybit); 339 340 /* 341 * Now set up our capabilities. 342 */ 343 __set_bit(EV_ABS, dev->evbit); 344 input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); 345 input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); 346 input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); 347 input_mt_init_slots(dev, 5, INPUT_MT_POINTER); 348 __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); 349} 350 351static int focaltech_read_register(struct ps2dev *ps2dev, int reg, 352 unsigned char *param) 353{ 354 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) 355 return -EIO; 356 357 param[0] = 0; 358 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 359 return -EIO; 360 361 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 362 return -EIO; 363 364 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 365 return -EIO; 366 367 param[0] = reg; 368 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 369 return -EIO; 370 371 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 372 return -EIO; 373 374 return 0; 375} 376 377static int focaltech_read_size(struct psmouse *psmouse) 378{ 379 struct ps2dev *ps2dev = &psmouse->ps2dev; 380 struct focaltech_data *priv = psmouse->private; 381 char param[3]; 382 383 if (focaltech_read_register(ps2dev, 2, param)) 384 return -EIO; 385 386 /* not sure whether this is 100% correct */ 387 priv->x_max = (unsigned char)param[1] * 128; 388 priv->y_max = (unsigned char)param[2] * 128; 389 390 return 0; 391} 392 393void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution) 394{ 395 /* not supported yet */ 396} 397 398static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate) 399{ 400 /* not supported yet */ 401} 402 403static void focaltech_set_scale(struct psmouse *psmouse, 404 enum psmouse_scale scale) 405{ 406 /* not supported yet */ 407} 408 409int focaltech_init(struct psmouse *psmouse) 410{ 411 struct focaltech_data *priv; 412 int error; 413 414 psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), 415 GFP_KERNEL); 416 if (!priv) 417 return -ENOMEM; 418 419 focaltech_reset(psmouse); 420 421 error = focaltech_read_size(psmouse); 422 if (error) { 423 psmouse_err(psmouse, 424 "Unable to read the size of the touchpad\n"); 425 goto fail; 426 } 427 428 error = focaltech_switch_protocol(psmouse); 429 if (error) { 430 psmouse_err(psmouse, "Unable to initialize the device\n"); 431 goto fail; 432 } 433 434 focaltech_set_input_params(psmouse); 435 436 psmouse->protocol_handler = focaltech_process_byte; 437 psmouse->pktsize = 6; 438 psmouse->disconnect = focaltech_disconnect; 439 psmouse->reconnect = focaltech_reconnect; 440 psmouse->cleanup = focaltech_reset; 441 /* resync is not supported yet */ 442 psmouse->resync_time = 0; 443 /* 444 * rate/resolution/scale changes are not supported yet, and 445 * the generic implementations of these functions seem to 446 * confuse some touchpads 447 */ 448 psmouse->set_resolution = focaltech_set_resolution; 449 psmouse->set_rate = focaltech_set_rate; 450 psmouse->set_scale = focaltech_set_scale; 451 452 return 0; 453 454fail: 455 focaltech_reset(psmouse); 456 kfree(priv); 457 return error; 458} 459 460#else /* CONFIG_MOUSE_PS2_FOCALTECH */ 461 462int focaltech_init(struct psmouse *psmouse) 463{ 464 focaltech_reset(psmouse); 465 466 return 0; 467} 468 469#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ 470