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 = "FocalTech Touchpad"; 47 } 48 49 return 0; 50 } 51 52 static 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 */ 73 struct 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 */ 98 struct 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 /* True if the clickpad has been pressed. */ 107 bool pressed; 108 }; 109 110 struct focaltech_data { 111 unsigned int x_max, y_max; 112 struct focaltech_hw_state state; 113 }; 114 115 static void focaltech_report_state(struct psmouse *psmouse) 116 { 117 struct focaltech_data *priv = psmouse->private; 118 struct focaltech_hw_state *state = &priv->state; 119 struct input_dev *dev = psmouse->dev; 120 int i; 121 122 for (i = 0; i < FOC_MAX_FINGERS; i++) { 123 struct focaltech_finger_state *finger = &state->fingers[i]; 124 bool active = finger->active && finger->valid; 125 126 input_mt_slot(dev, i); 127 input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); 128 if (active) { 129 unsigned int clamped_x, clamped_y; 130 /* 131 * The touchpad might report invalid data, so we clamp 132 * the resulting values so that we do not confuse 133 * userspace. 134 */ 135 clamped_x = clamp(finger->x, 0U, priv->x_max); 136 clamped_y = clamp(finger->y, 0U, priv->y_max); 137 input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); 138 input_report_abs(dev, ABS_MT_POSITION_Y, 139 priv->y_max - clamped_y); 140 } 141 } 142 input_mt_report_pointer_emulation(dev, true); 143 144 input_report_key(psmouse->dev, BTN_LEFT, state->pressed); 145 input_sync(psmouse->dev); 146 } 147 148 static void focaltech_process_touch_packet(struct psmouse *psmouse, 149 unsigned char *packet) 150 { 151 struct focaltech_data *priv = psmouse->private; 152 struct focaltech_hw_state *state = &priv->state; 153 unsigned char fingers = packet[1]; 154 int i; 155 156 state->pressed = (packet[0] >> 4) & 1; 157 158 /* the second byte contains a bitmap of all fingers touching the pad */ 159 for (i = 0; i < FOC_MAX_FINGERS; i++) { 160 state->fingers[i].active = fingers & 0x1; 161 if (!state->fingers[i].active) { 162 /* 163 * Even when the finger becomes active again, we still 164 * will have to wait for the first valid position. 165 */ 166 state->fingers[i].valid = false; 167 } 168 fingers >>= 1; 169 } 170 } 171 172 static void focaltech_process_abs_packet(struct psmouse *psmouse, 173 unsigned char *packet) 174 { 175 struct focaltech_data *priv = psmouse->private; 176 struct focaltech_hw_state *state = &priv->state; 177 unsigned int finger; 178 179 finger = (packet[1] >> 4) - 1; 180 if (finger >= FOC_MAX_FINGERS) { 181 psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", 182 finger); 183 return; 184 } 185 186 state->pressed = (packet[0] >> 4) & 1; 187 188 state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; 189 state->fingers[finger].y = (packet[3] << 8) | packet[4]; 190 state->fingers[finger].valid = true; 191 } 192 193 static void focaltech_process_rel_packet(struct psmouse *psmouse, 194 unsigned char *packet) 195 { 196 struct focaltech_data *priv = psmouse->private; 197 struct focaltech_hw_state *state = &priv->state; 198 int finger1, finger2; 199 200 state->pressed = packet[0] >> 7; 201 finger1 = ((packet[0] >> 4) & 0x7) - 1; 202 if (finger1 < FOC_MAX_FINGERS) { 203 state->fingers[finger1].x += (char)packet[1]; 204 state->fingers[finger1].y += (char)packet[2]; 205 } else { 206 psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", 207 finger1); 208 } 209 210 /* 211 * If there is an odd number of fingers, the last relative 212 * packet only contains one finger. In this case, the second 213 * finger index in the packet is 0 (we subtract 1 in the lines 214 * above to create array indices, so the finger will overflow 215 * and be above FOC_MAX_FINGERS). 216 */ 217 finger2 = ((packet[3] >> 4) & 0x7) - 1; 218 if (finger2 < FOC_MAX_FINGERS) { 219 state->fingers[finger2].x += (char)packet[4]; 220 state->fingers[finger2].y += (char)packet[5]; 221 } 222 } 223 224 static void focaltech_process_packet(struct psmouse *psmouse) 225 { 226 unsigned char *packet = psmouse->packet; 227 228 switch (packet[0] & 0xf) { 229 case FOC_TOUCH: 230 focaltech_process_touch_packet(psmouse, packet); 231 break; 232 233 case FOC_ABS: 234 focaltech_process_abs_packet(psmouse, packet); 235 break; 236 237 case FOC_REL: 238 focaltech_process_rel_packet(psmouse, packet); 239 break; 240 241 default: 242 psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); 243 break; 244 } 245 246 focaltech_report_state(psmouse); 247 } 248 249 static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) 250 { 251 if (psmouse->pktcnt >= 6) { /* Full packet received */ 252 focaltech_process_packet(psmouse); 253 return PSMOUSE_FULL_PACKET; 254 } 255 256 /* 257 * We might want to do some validation of the data here, but 258 * we do not know the protocol well enough 259 */ 260 return PSMOUSE_GOOD_DATA; 261 } 262 263 static int focaltech_switch_protocol(struct psmouse *psmouse) 264 { 265 struct ps2dev *ps2dev = &psmouse->ps2dev; 266 unsigned char param[3]; 267 268 param[0] = 0; 269 if (ps2_command(ps2dev, param, 0x10f8)) 270 return -EIO; 271 272 if (ps2_command(ps2dev, param, 0x10f8)) 273 return -EIO; 274 275 if (ps2_command(ps2dev, param, 0x10f8)) 276 return -EIO; 277 278 param[0] = 1; 279 if (ps2_command(ps2dev, param, 0x10f8)) 280 return -EIO; 281 282 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) 283 return -EIO; 284 285 if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) 286 return -EIO; 287 288 return 0; 289 } 290 291 static void focaltech_disconnect(struct psmouse *psmouse) 292 { 293 focaltech_reset(psmouse); 294 kfree(psmouse->private); 295 psmouse->private = NULL; 296 } 297 298 static int focaltech_reconnect(struct psmouse *psmouse) 299 { 300 int error; 301 302 focaltech_reset(psmouse); 303 304 error = focaltech_switch_protocol(psmouse); 305 if (error) { 306 psmouse_err(psmouse, "Unable to initialize the device\n"); 307 return error; 308 } 309 310 return 0; 311 } 312 313 static void focaltech_set_input_params(struct psmouse *psmouse) 314 { 315 struct input_dev *dev = psmouse->dev; 316 struct focaltech_data *priv = psmouse->private; 317 318 /* 319 * Undo part of setup done for us by psmouse core since touchpad 320 * is not a relative device. 321 */ 322 __clear_bit(EV_REL, dev->evbit); 323 __clear_bit(REL_X, dev->relbit); 324 __clear_bit(REL_Y, dev->relbit); 325 __clear_bit(BTN_RIGHT, dev->keybit); 326 __clear_bit(BTN_MIDDLE, dev->keybit); 327 328 /* 329 * Now set up our capabilities. 330 */ 331 __set_bit(EV_ABS, dev->evbit); 332 input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); 333 input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); 334 input_mt_init_slots(dev, 5, INPUT_MT_POINTER); 335 __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); 336 } 337 338 static int focaltech_read_register(struct ps2dev *ps2dev, int reg, 339 unsigned char *param) 340 { 341 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) 342 return -EIO; 343 344 param[0] = 0; 345 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 346 return -EIO; 347 348 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 349 return -EIO; 350 351 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 352 return -EIO; 353 354 param[0] = reg; 355 if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) 356 return -EIO; 357 358 if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) 359 return -EIO; 360 361 return 0; 362 } 363 364 static int focaltech_read_size(struct psmouse *psmouse) 365 { 366 struct ps2dev *ps2dev = &psmouse->ps2dev; 367 struct focaltech_data *priv = psmouse->private; 368 char param[3]; 369 370 if (focaltech_read_register(ps2dev, 2, param)) 371 return -EIO; 372 373 /* not sure whether this is 100% correct */ 374 priv->x_max = (unsigned char)param[1] * 128; 375 priv->y_max = (unsigned char)param[2] * 128; 376 377 return 0; 378 } 379 380 void focaltech_set_resolution(struct psmouse *psmouse, unsigned int resolution) 381 { 382 /* not supported yet */ 383 } 384 385 static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate) 386 { 387 /* not supported yet */ 388 } 389 390 static void focaltech_set_scale(struct psmouse *psmouse, 391 enum psmouse_scale scale) 392 { 393 /* not supported yet */ 394 } 395 396 int focaltech_init(struct psmouse *psmouse) 397 { 398 struct focaltech_data *priv; 399 int error; 400 401 psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), 402 GFP_KERNEL); 403 if (!priv) 404 return -ENOMEM; 405 406 focaltech_reset(psmouse); 407 408 error = focaltech_read_size(psmouse); 409 if (error) { 410 psmouse_err(psmouse, 411 "Unable to read the size of the touchpad\n"); 412 goto fail; 413 } 414 415 error = focaltech_switch_protocol(psmouse); 416 if (error) { 417 psmouse_err(psmouse, "Unable to initialize the device\n"); 418 goto fail; 419 } 420 421 focaltech_set_input_params(psmouse); 422 423 psmouse->protocol_handler = focaltech_process_byte; 424 psmouse->pktsize = 6; 425 psmouse->disconnect = focaltech_disconnect; 426 psmouse->reconnect = focaltech_reconnect; 427 psmouse->cleanup = focaltech_reset; 428 /* resync is not supported yet */ 429 psmouse->resync_time = 0; 430 /* 431 * rate/resolution/scale changes are not supported yet, and 432 * the generic implementations of these functions seem to 433 * confuse some touchpads 434 */ 435 psmouse->set_resolution = focaltech_set_resolution; 436 psmouse->set_rate = focaltech_set_rate; 437 psmouse->set_scale = focaltech_set_scale; 438 439 return 0; 440 441 fail: 442 focaltech_reset(psmouse); 443 kfree(priv); 444 return error; 445 } 446 447 #else /* CONFIG_MOUSE_PS2_FOCALTECH */ 448 449 int focaltech_init(struct psmouse *psmouse) 450 { 451 focaltech_reset(psmouse); 452 453 return 0; 454 } 455 456 #endif /* CONFIG_MOUSE_PS2_FOCALTECH */ 457