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