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 26 static 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 */ 39 int 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 = "Touchpad"; 47 } 48 49 return 0; 50 } 51 52 #ifdef CONFIG_MOUSE_PS2_FOCALTECH 53 54 /* 55 * Packet types - the numbers are not consecutive, so we might be missing 56 * something here. 57 */ 58 #define FOC_TOUCH 0x3 /* bitmap of active fingers */ 59 #define FOC_ABS 0x6 /* absolute position of one finger */ 60 #define FOC_REL 0x9 /* relative position of 1-2 fingers */ 61 62 #define FOC_MAX_FINGERS 5 63 64 /* 65 * Current state of a single finger on the touchpad. 66 */ 67 struct focaltech_finger_state { 68 /* The touchpad has generated a touch event for the finger */ 69 bool active; 70 71 /* 72 * The touchpad has sent position data for the finger. The 73 * flag is 0 when the finger is not active, and there is a 74 * time between the first touch event for the finger and the 75 * following absolute position packet for the finger where the 76 * touchpad has declared the finger to be valid, but we do not 77 * have any valid position yet. 78 */ 79 bool valid; 80 81 /* 82 * Absolute position (from the bottom left corner) of the 83 * finger. 84 */ 85 unsigned int x; 86 unsigned int y; 87 }; 88 89 /* 90 * Description of the current state of the touchpad hardware. 91 */ 92 struct focaltech_hw_state { 93 /* 94 * The touchpad tracks the positions of the fingers for us, 95 * the array indices correspond to the finger indices returned 96 * in the report packages. 97 */ 98 struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; 99 100 /* 101 * Finger width 0-7 and 15 for a very big contact area. 102 * 15 value stays until the finger is released. 103 * Width is reported only in absolute packets. 104 * Since hardware reports width only for last touching finger, 105 * there is no need to store width for every specific finger, 106 * so we keep only last value reported. 107 */ 108 unsigned int width; 109 110 /* True if the clickpad has been pressed. */ 111 bool pressed; 112 }; 113 114 struct focaltech_data { 115 unsigned int x_max, y_max; 116 struct focaltech_hw_state state; 117 }; 118 119 static void focaltech_report_state(struct psmouse *psmouse) 120 { 121 struct focaltech_data *priv = psmouse->private; 122 struct focaltech_hw_state *state = &priv->state; 123 struct input_dev *dev = psmouse->dev; 124 int i; 125 126 for (i = 0; i < FOC_MAX_FINGERS; i++) { 127 struct focaltech_finger_state *finger = &state->fingers[i]; 128 bool active = finger->active && finger->valid; 129 130 input_mt_slot(dev, i); 131 input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 132 if (active) { 133 unsigned int clamped_x, clamped_y; 134 /* 135 * The touchpad might report invalid data, so we clamp 136 * the resulting values so that we do not confuse 137 * userspace. 138 */ 139 clamped_x = clamp(finger->x, 0U, priv->x_max); 140 clamped_y = clamp(finger->y, 0U, priv->y_max); 141 input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); 142 input_report_abs(dev, ABS_MT_POSITION_Y, 143 priv->y_max - clamped_y); 144 input_report_abs(dev, ABS_TOOL_WIDTH, state->width); 145 } 146 } 147 input_mt_report_pointer_emulation(dev, true); 148 149 input_report_key(dev, BTN_LEFT, state->pressed); 150 input_sync(dev); 151 } 152 153 static void focaltech_process_touch_packet(struct psmouse *psmouse, 154 unsigned char *packet) 155 { 156 struct focaltech_data *priv = psmouse->private; 157 struct focaltech_hw_state *state = &priv->state; 158 unsigned char fingers = packet[1]; 159 int i; 160 161 state->pressed = (packet[0] >> 4) & 1; 162 163 /* the second byte contains a bitmap of all fingers touching the pad */ 164 for (i = 0; i < FOC_MAX_FINGERS; i++) { 165 state->fingers[i].active = fingers & 0x1; 166 if (!state->fingers[i].active) { 167 /* 168 * Even when the finger becomes active again, we still 169 * will have to wait for the first valid position. 170 */ 171 state->fingers[i].valid = false; 172 } 173 fingers >>= 1; 174 } 175 } 176 177 static void focaltech_process_abs_packet(struct psmouse *psmouse, 178 unsigned char *packet) 179 { 180 struct focaltech_data *priv = psmouse->private; 181 struct focaltech_hw_state *state = &priv->state; 182 unsigned int finger; 183 184 finger = (packet[1] >> 4) - 1; 185 if (finger >= FOC_MAX_FINGERS) { 186 psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", 187 finger); 188 return; 189 } 190 191 state->pressed = (packet[0] >> 4) & 1; 192 193 state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; 194 state->fingers[finger].y = (packet[3] << 8) | packet[4]; 195 state->width = packet[5] >> 4; 196 state->fingers[finger].valid = true; 197 } 198 199 static void focaltech_process_rel_packet(struct psmouse *psmouse, 200 unsigned char *packet) 201 { 202 struct focaltech_data *priv = psmouse->private; 203 struct focaltech_hw_state *state = &priv->state; 204 int finger1, finger2; 205 206 state->pressed = packet[0] >> 7; 207 finger1 = ((packet[0] >> 4) & 0x7) - 1; 208 if (finger1 < FOC_MAX_FINGERS) { 209 state->fingers[finger1].x += (char)packet[1]; 210 state->fingers[finger1].y += (char)packet[2]; 211 } else { 212 psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", 213 finger1); 214 } 215 216 /* 217 * If there is an odd number of fingers, the last relative 218 * packet only contains one finger. In this case, the second 219 * finger index in the packet is 0 (we subtract 1 in the lines 220 * above to create array indices, so the finger will overflow 221 * and be above FOC_MAX_FINGERS). 222 */ 223 finger2 = ((packet[3] >> 4) & 0x7) - 1; 224 if (finger2 < FOC_MAX_FINGERS) { 225 state->fingers[finger2].x += (char)packet[4]; 226 state->fingers[finger2].y += (char)packet[5]; 227 } 228 } 229 230 static void focaltech_process_packet(struct psmouse *psmouse) 231 { 232 unsigned char *packet = psmouse->packet; 233 234 switch (packet[0] & 0xf) { 235 case FOC_TOUCH: 236 focaltech_process_touch_packet(psmouse, packet); 237 break; 238 239 case FOC_ABS: 240 focaltech_process_abs_packet(psmouse, packet); 241 break; 242 243 case FOC_REL: 244 focaltech_process_rel_packet(psmouse, packet); 245 break; 246 247 default: 248 psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); 249 break; 250 } 251 252 focaltech_report_state(psmouse); 253 } 254 255 static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) 256 { 257 if (psmouse->pktcnt >= 6) { /* Full packet received */ 258 focaltech_process_packet(psmouse); 259 return PSMOUSE_FULL_PACKET; 260 } 261 262 /* 263 * We might want to do some validation of the data here, but 264 * we do not know the protocol well enough 265 */ 266 return PSMOUSE_GOOD_DATA; 267 } 268 269 static int focaltech_switch_protocol(struct psmouse *psmouse) 270 { 271 struct ps2dev *ps2dev = &psmouse->ps2dev; 272 unsigned char param[3]; 273 274 param[0] = 0; 275 if (ps2_command(ps2dev, param, 0x10f8)) 276 return -EIO; 277 278 if (ps2_command(ps2dev, param, 0x10f8)) 279 return -EIO; 280 281 if (ps2_command(ps2dev, param, 0x10f8)) 282 return -EIO; 283 284 param[0] = 1; 285 if (ps2_command(ps2dev, param, 0x10f8)) 286 return -EIO; 287 288 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) 289 return -EIO; 290 291 if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) 292 return -EIO; 293 294 return 0; 295 } 296 297 static void focaltech_reset(struct psmouse *psmouse) 298 { 299 ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); 300 psmouse_reset(psmouse); 301 } 302 303 static void focaltech_disconnect(struct psmouse *psmouse) 304 { 305 focaltech_reset(psmouse); 306 kfree(psmouse->private); 307 psmouse->private = NULL; 308 } 309 310 static 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 325 static 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 351 static 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 377 static 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 393 static void focaltech_set_resolution(struct psmouse *psmouse, 394 unsigned int resolution) 395 { 396 /* not supported yet */ 397 } 398 399 static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate) 400 { 401 /* not supported yet */ 402 } 403 404 static void focaltech_set_scale(struct psmouse *psmouse, 405 enum psmouse_scale scale) 406 { 407 /* not supported yet */ 408 } 409 410 int focaltech_init(struct psmouse *psmouse) 411 { 412 struct focaltech_data *priv; 413 int error; 414 415 psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), 416 GFP_KERNEL); 417 if (!priv) 418 return -ENOMEM; 419 420 focaltech_reset(psmouse); 421 422 error = focaltech_read_size(psmouse); 423 if (error) { 424 psmouse_err(psmouse, 425 "Unable to read the size of the touchpad\n"); 426 goto fail; 427 } 428 429 error = focaltech_switch_protocol(psmouse); 430 if (error) { 431 psmouse_err(psmouse, "Unable to initialize the device\n"); 432 goto fail; 433 } 434 435 focaltech_set_input_params(psmouse); 436 437 psmouse->protocol_handler = focaltech_process_byte; 438 psmouse->pktsize = 6; 439 psmouse->disconnect = focaltech_disconnect; 440 psmouse->reconnect = focaltech_reconnect; 441 psmouse->cleanup = focaltech_reset; 442 /* resync is not supported yet */ 443 psmouse->resync_time = 0; 444 /* 445 * rate/resolution/scale changes are not supported yet, and 446 * the generic implementations of these functions seem to 447 * confuse some touchpads 448 */ 449 psmouse->set_resolution = focaltech_set_resolution; 450 psmouse->set_rate = focaltech_set_rate; 451 psmouse->set_scale = focaltech_set_scale; 452 453 return 0; 454 455 fail: 456 focaltech_reset(psmouse); 457 kfree(priv); 458 return error; 459 } 460 #endif /* CONFIG_MOUSE_PS2_FOCALTECH */ 461