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