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