root/drivers/input/mouse/focaltech.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. focaltech_detect
  2. focaltech_report_state
  3. focaltech_process_touch_packet
  4. focaltech_process_abs_packet
  5. focaltech_process_rel_packet
  6. focaltech_process_packet
  7. focaltech_process_byte
  8. focaltech_switch_protocol
  9. focaltech_reset
  10. focaltech_disconnect
  11. focaltech_reconnect
  12. focaltech_set_input_params
  13. focaltech_read_register
  14. focaltech_read_size
  15. focaltech_set_resolution
  16. focaltech_set_rate
  17. focaltech_set_scale
  18. focaltech_init

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

/* [<][>][^][v][top][bottom][index][help] */