linux/drivers/input/mouse/focaltech.c
<<
>>
Prefs
   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
  22static 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 */
  35int 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 */
  63struct 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 */
  88struct 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
 110struct focaltech_data {
 111        unsigned int x_max, y_max;
 112        struct focaltech_hw_state state;
 113};
 114
 115static 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
 149static 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
 173static 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
 195static 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
 226static 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
 251static 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
 265static 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
 293static void focaltech_reset(struct psmouse *psmouse)
 294{
 295        ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
 296        psmouse_reset(psmouse);
 297}
 298
 299static void focaltech_disconnect(struct psmouse *psmouse)
 300{
 301        focaltech_reset(psmouse);
 302        kfree(psmouse->private);
 303        psmouse->private = NULL;
 304}
 305
 306static 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
 321static 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
 347static 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
 373static 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
 389static void focaltech_set_resolution(struct psmouse *psmouse,
 390                                     unsigned int resolution)
 391{
 392        /* not supported yet */
 393}
 394
 395static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate)
 396{
 397        /* not supported yet */
 398}
 399
 400static void focaltech_set_scale(struct psmouse *psmouse,
 401                                enum psmouse_scale scale)
 402{
 403        /* not supported yet */
 404}
 405
 406int 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
 451fail:
 452        focaltech_reset(psmouse);
 453        kfree(priv);
 454        return error;
 455}
 456#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
 457