linux/drivers/input/mouse/cypress_ps2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Cypress Trackpad PS/2 mouse driver
   4 *
   5 * Copyright (c) 2012 Cypress Semiconductor Corporation.
   6 *
   7 * Author:
   8 *   Dudley Du <dudl@cypress.com>
   9 *
  10 * Additional contributors include:
  11 *   Kamal Mostafa <kamal@canonical.com>
  12 *   Kyle Fazzari <git@status.e4ward.com>
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/kernel.h>
  17#include <linux/slab.h>
  18#include <linux/serio.h>
  19#include <linux/libps2.h>
  20#include <linux/input.h>
  21#include <linux/input/mt.h>
  22#include <linux/sched.h>
  23#include <linux/wait.h>
  24
  25#include "cypress_ps2.h"
  26
  27#undef CYTP_DEBUG_VERBOSE  /* define this and DEBUG for more verbose dump */
  28
  29static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
  30{
  31        struct cytp_data *cytp = psmouse->private;
  32        cytp->pkt_size = n;
  33}
  34
  35static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
  36static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
  37
  38static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
  39{
  40        struct ps2dev *ps2dev = &psmouse->ps2dev;
  41
  42        if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
  43                psmouse_dbg(psmouse,
  44                                "sending command 0x%02x failed, resp 0x%02x\n",
  45                                value & 0xff, ps2dev->nak);
  46                if (ps2dev->nak == CYTP_PS2_RETRY)
  47                        return CYTP_PS2_RETRY;
  48                else
  49                        return CYTP_PS2_ERROR;
  50        }
  51
  52#ifdef CYTP_DEBUG_VERBOSE
  53        psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
  54                        value & 0xff);
  55#endif
  56
  57        return 0;
  58}
  59
  60static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
  61                               unsigned char data)
  62{
  63        struct ps2dev *ps2dev = &psmouse->ps2dev;
  64        int tries = CYTP_PS2_CMD_TRIES;
  65        int rc;
  66
  67        ps2_begin_command(ps2dev);
  68
  69        do {
  70                /*
  71                 * Send extension command byte (0xE8 or 0xF3).
  72                 * If sending the command fails, send recovery command
  73                 * to make the device return to the ready state.
  74                 */
  75                rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
  76                if (rc == CYTP_PS2_RETRY) {
  77                        rc = cypress_ps2_sendbyte(psmouse, 0x00);
  78                        if (rc == CYTP_PS2_RETRY)
  79                                rc = cypress_ps2_sendbyte(psmouse, 0x0a);
  80                }
  81                if (rc == CYTP_PS2_ERROR)
  82                        continue;
  83
  84                rc = cypress_ps2_sendbyte(psmouse, data);
  85                if (rc == CYTP_PS2_RETRY)
  86                        rc = cypress_ps2_sendbyte(psmouse, data);
  87                if (rc == CYTP_PS2_ERROR)
  88                        continue;
  89                else
  90                        break;
  91        } while (--tries > 0);
  92
  93        ps2_end_command(ps2dev);
  94
  95        return rc;
  96}
  97
  98static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
  99                                       unsigned char cmd,
 100                                       unsigned char *param)
 101{
 102        int rc;
 103        struct ps2dev *ps2dev = &psmouse->ps2dev;
 104        enum psmouse_state old_state;
 105        int pktsize;
 106
 107        ps2_begin_command(ps2dev);
 108
 109        old_state = psmouse->state;
 110        psmouse->state = PSMOUSE_CMD_MODE;
 111        psmouse->pktcnt = 0;
 112
 113        pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
 114        memset(param, 0, pktsize);
 115
 116        rc = cypress_ps2_sendbyte(psmouse, 0xe9);
 117        if (rc < 0)
 118                goto out;
 119
 120        wait_event_timeout(ps2dev->wait,
 121                        (psmouse->pktcnt >= pktsize),
 122                        msecs_to_jiffies(CYTP_CMD_TIMEOUT));
 123
 124        memcpy(param, psmouse->packet, pktsize);
 125
 126        psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
 127                        cmd, pktsize, param);
 128
 129out:
 130        psmouse->state = old_state;
 131        psmouse->pktcnt = 0;
 132
 133        ps2_end_command(ps2dev);
 134
 135        return rc;
 136}
 137
 138static bool cypress_verify_cmd_state(struct psmouse *psmouse,
 139                                     unsigned char cmd, unsigned char *param)
 140{
 141        bool rate_match = false;
 142        bool resolution_match = false;
 143        int i;
 144
 145        /* callers will do further checking. */
 146        if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
 147            cmd == CYTP_CMD_STANDARD_MODE ||
 148            cmd == CYTP_CMD_READ_TP_METRICS)
 149                return true;
 150
 151        if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
 152            (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
 153                for (i = 0; i < sizeof(cytp_resolution); i++)
 154                        if (cytp_resolution[i] == param[1])
 155                                resolution_match = true;
 156
 157                for (i = 0; i < sizeof(cytp_rate); i++)
 158                        if (cytp_rate[i] == param[2])
 159                                rate_match = true;
 160
 161                if (resolution_match && rate_match)
 162                        return true;
 163        }
 164
 165        psmouse_dbg(psmouse, "verify cmd state failed.\n");
 166        return false;
 167}
 168
 169static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
 170                                unsigned char *param)
 171{
 172        int tries = CYTP_PS2_CMD_TRIES;
 173        int rc;
 174
 175        psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
 176                 cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
 177                 DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
 178
 179        do {
 180                cypress_ps2_ext_cmd(psmouse,
 181                                    PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
 182                cypress_ps2_ext_cmd(psmouse,
 183                                    PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
 184                cypress_ps2_ext_cmd(psmouse,
 185                                    PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
 186                cypress_ps2_ext_cmd(psmouse,
 187                                    PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
 188
 189                rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
 190                if (rc)
 191                        continue;
 192
 193                if (cypress_verify_cmd_state(psmouse, cmd, param))
 194                        return 0;
 195
 196        } while (--tries > 0);
 197
 198        return -EIO;
 199}
 200
 201int cypress_detect(struct psmouse *psmouse, bool set_properties)
 202{
 203        unsigned char param[3];
 204
 205        if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
 206                return -ENODEV;
 207
 208        /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
 209        if (param[0] != 0x33 || param[1] != 0xCC)
 210                return -ENODEV;
 211
 212        if (set_properties) {
 213                psmouse->vendor = "Cypress";
 214                psmouse->name = "Trackpad";
 215        }
 216
 217        return 0;
 218}
 219
 220static int cypress_read_fw_version(struct psmouse *psmouse)
 221{
 222        struct cytp_data *cytp = psmouse->private;
 223        unsigned char param[3];
 224
 225        if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
 226                return -ENODEV;
 227
 228        /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
 229        if (param[0] != 0x33 || param[1] != 0xCC)
 230                return -ENODEV;
 231
 232        cytp->fw_version = param[2] & FW_VERSION_MASX;
 233        cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
 234
 235        /*
 236         * Trackpad fw_version 11 (in Dell XPS12) yields a bogus response to
 237         * CYTP_CMD_READ_TP_METRICS so do not try to use it. LP: #1103594.
 238         */
 239        if (cytp->fw_version >= 11)
 240                cytp->tp_metrics_supported = 0;
 241
 242        psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
 243        psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
 244                 cytp->tp_metrics_supported);
 245
 246        return 0;
 247}
 248
 249static int cypress_read_tp_metrics(struct psmouse *psmouse)
 250{
 251        struct cytp_data *cytp = psmouse->private;
 252        unsigned char param[8];
 253
 254        /* set default values for tp metrics. */
 255        cytp->tp_width = CYTP_DEFAULT_WIDTH;
 256        cytp->tp_high = CYTP_DEFAULT_HIGH;
 257        cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
 258        cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
 259        cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
 260        cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
 261        cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
 262        cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
 263
 264        if (!cytp->tp_metrics_supported)
 265                return 0;
 266
 267        memset(param, 0, sizeof(param));
 268        if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
 269                /* Update trackpad parameters. */
 270                cytp->tp_max_abs_x = (param[1] << 8) | param[0];
 271                cytp->tp_max_abs_y = (param[3] << 8) | param[2];
 272                cytp->tp_min_pressure = param[4];
 273                cytp->tp_max_pressure = param[5];
 274        }
 275
 276        if (!cytp->tp_max_pressure ||
 277            cytp->tp_max_pressure < cytp->tp_min_pressure ||
 278            !cytp->tp_width || !cytp->tp_high ||
 279            !cytp->tp_max_abs_x ||
 280            cytp->tp_max_abs_x < cytp->tp_width ||
 281            !cytp->tp_max_abs_y ||
 282            cytp->tp_max_abs_y < cytp->tp_high)
 283                return -EINVAL;
 284
 285        cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
 286        cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
 287
 288#ifdef CYTP_DEBUG_VERBOSE
 289        psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
 290        psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
 291        psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
 292        psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
 293        psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
 294        psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
 295        psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
 296        psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
 297        psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
 298
 299        psmouse_dbg(psmouse, "tp_type_APA = %d\n",
 300                        (param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
 301        psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
 302                        (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
 303        psmouse_dbg(psmouse, "tp_palm = %d\n",
 304                        (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
 305        psmouse_dbg(psmouse, "tp_stubborn = %d\n",
 306                        (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
 307        psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
 308                        (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
 309        psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
 310                        (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
 311        psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
 312                        param[7] & TP_METRICS_BIT_1F_SPIKE);
 313        psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
 314                        (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
 315        psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
 316                        (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
 317#endif
 318
 319        return 0;
 320}
 321
 322static int cypress_query_hardware(struct psmouse *psmouse)
 323{
 324        int ret;
 325
 326        ret = cypress_read_fw_version(psmouse);
 327        if (ret)
 328                return ret;
 329
 330        ret = cypress_read_tp_metrics(psmouse);
 331        if (ret)
 332                return ret;
 333
 334        return 0;
 335}
 336
 337static int cypress_set_absolute_mode(struct psmouse *psmouse)
 338{
 339        struct cytp_data *cytp = psmouse->private;
 340        unsigned char param[3];
 341
 342        if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
 343                return -1;
 344
 345        cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
 346                        | CYTP_BIT_ABS_PRESSURE;
 347        cypress_set_packet_size(psmouse, 5);
 348
 349        return 0;
 350}
 351
 352/*
 353 * Reset trackpad device.
 354 * This is also the default mode when trackpad powered on.
 355 */
 356static void cypress_reset(struct psmouse *psmouse)
 357{
 358        struct cytp_data *cytp = psmouse->private;
 359
 360        cytp->mode = 0;
 361
 362        psmouse_reset(psmouse);
 363}
 364
 365static int cypress_set_input_params(struct input_dev *input,
 366                                    struct cytp_data *cytp)
 367{
 368        int ret;
 369
 370        if (!cytp->tp_res_x || !cytp->tp_res_y)
 371                return -EINVAL;
 372
 373        __set_bit(EV_ABS, input->evbit);
 374        input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
 375        input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
 376        input_set_abs_params(input, ABS_PRESSURE,
 377                             cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
 378        input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
 379
 380        /* finger position */
 381        input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
 382        input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
 383        input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
 384
 385        ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
 386                        INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
 387        if (ret < 0)
 388                return ret;
 389
 390        __set_bit(INPUT_PROP_SEMI_MT, input->propbit);
 391
 392        input_abs_set_res(input, ABS_X, cytp->tp_res_x);
 393        input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
 394
 395        input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
 396        input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
 397
 398        __set_bit(BTN_TOUCH, input->keybit);
 399        __set_bit(BTN_TOOL_FINGER, input->keybit);
 400        __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
 401        __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
 402        __set_bit(BTN_TOOL_QUADTAP, input->keybit);
 403        __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
 404
 405        __clear_bit(EV_REL, input->evbit);
 406        __clear_bit(REL_X, input->relbit);
 407        __clear_bit(REL_Y, input->relbit);
 408
 409        __set_bit(EV_KEY, input->evbit);
 410        __set_bit(BTN_LEFT, input->keybit);
 411        __set_bit(BTN_RIGHT, input->keybit);
 412        __set_bit(BTN_MIDDLE, input->keybit);
 413
 414        return 0;
 415}
 416
 417static int cypress_get_finger_count(unsigned char header_byte)
 418{
 419        unsigned char bits6_7;
 420        int finger_count;
 421
 422        bits6_7 = header_byte >> 6;
 423        finger_count = bits6_7 & 0x03;
 424
 425        if (finger_count == 1)
 426                return 1;
 427
 428        if (header_byte & ABS_HSCROLL_BIT) {
 429                /* HSCROLL gets added on to 0 finger count. */
 430                switch (finger_count) {
 431                        case 0: return 4;
 432                        case 2: return 5;
 433                        default:
 434                                /* Invalid contact (e.g. palm). Ignore it. */
 435                                return 0;
 436                }
 437        }
 438
 439        return finger_count;
 440}
 441
 442
 443static int cypress_parse_packet(struct psmouse *psmouse,
 444                                struct cytp_data *cytp, struct cytp_report_data *report_data)
 445{
 446        unsigned char *packet = psmouse->packet;
 447        unsigned char header_byte = packet[0];
 448
 449        memset(report_data, 0, sizeof(struct cytp_report_data));
 450
 451        report_data->contact_cnt = cypress_get_finger_count(header_byte);
 452        report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
 453
 454        if (report_data->contact_cnt == 1) {
 455                report_data->contacts[0].x =
 456                        ((packet[1] & 0x70) << 4) | packet[2];
 457                report_data->contacts[0].y =
 458                        ((packet[1] & 0x07) << 8) | packet[3];
 459                if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 460                        report_data->contacts[0].z = packet[4];
 461
 462        } else if (report_data->contact_cnt >= 2) {
 463                report_data->contacts[0].x =
 464                        ((packet[1] & 0x70) << 4) | packet[2];
 465                report_data->contacts[0].y =
 466                        ((packet[1] & 0x07) << 8) | packet[3];
 467                if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 468                        report_data->contacts[0].z = packet[4];
 469
 470                report_data->contacts[1].x =
 471                        ((packet[5] & 0xf0) << 4) | packet[6];
 472                report_data->contacts[1].y =
 473                        ((packet[5] & 0x0f) << 8) | packet[7];
 474                if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 475                        report_data->contacts[1].z = report_data->contacts[0].z;
 476        }
 477
 478        report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
 479        report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
 480
 481        /*
 482         * This is only true if one of the mouse buttons were tapped.  Make
 483         * sure it doesn't turn into a click. The regular tap-to-click
 484         * functionality will handle that on its own. If we don't do this,
 485         * disabling tap-to-click won't affect the mouse button zones.
 486         */
 487        if (report_data->tap)
 488                report_data->left = 0;
 489
 490#ifdef CYTP_DEBUG_VERBOSE
 491        {
 492                int i;
 493                int n = report_data->contact_cnt;
 494                psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
 495                psmouse_dbg(psmouse, "contact_cnt = %d\n",
 496                        report_data->contact_cnt);
 497                if (n > CYTP_MAX_MT_SLOTS)
 498                    n = CYTP_MAX_MT_SLOTS;
 499                for (i = 0; i < n; i++)
 500                        psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
 501                                        report_data->contacts[i].x,
 502                                        report_data->contacts[i].y,
 503                                        report_data->contacts[i].z);
 504                psmouse_dbg(psmouse, "left = %d\n", report_data->left);
 505                psmouse_dbg(psmouse, "right = %d\n", report_data->right);
 506                psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
 507        }
 508#endif
 509
 510        return 0;
 511}
 512
 513static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
 514{
 515        int i;
 516        struct input_dev *input = psmouse->dev;
 517        struct cytp_data *cytp = psmouse->private;
 518        struct cytp_report_data report_data;
 519        struct cytp_contact *contact;
 520        struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
 521        int slots[CYTP_MAX_MT_SLOTS];
 522        int n;
 523
 524        cypress_parse_packet(psmouse, cytp, &report_data);
 525
 526        n = report_data.contact_cnt;
 527        if (n > CYTP_MAX_MT_SLOTS)
 528                n = CYTP_MAX_MT_SLOTS;
 529
 530        for (i = 0; i < n; i++) {
 531                contact = &report_data.contacts[i];
 532                pos[i].x = contact->x;
 533                pos[i].y = contact->y;
 534        }
 535
 536        input_mt_assign_slots(input, slots, pos, n, 0);
 537
 538        for (i = 0; i < n; i++) {
 539                contact = &report_data.contacts[i];
 540                input_mt_slot(input, slots[i]);
 541                input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
 542                input_report_abs(input, ABS_MT_POSITION_X, contact->x);
 543                input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
 544                input_report_abs(input, ABS_MT_PRESSURE, contact->z);
 545        }
 546
 547        input_mt_sync_frame(input);
 548
 549        input_mt_report_finger_count(input, report_data.contact_cnt);
 550
 551        input_report_key(input, BTN_LEFT, report_data.left);
 552        input_report_key(input, BTN_RIGHT, report_data.right);
 553        input_report_key(input, BTN_MIDDLE, report_data.middle);
 554
 555        input_sync(input);
 556}
 557
 558static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
 559{
 560        int contact_cnt;
 561        int index = psmouse->pktcnt - 1;
 562        unsigned char *packet = psmouse->packet;
 563        struct cytp_data *cytp = psmouse->private;
 564
 565        if (index < 0 || index > cytp->pkt_size)
 566                return PSMOUSE_BAD_DATA;
 567
 568        if (index == 0 && (packet[0] & 0xfc) == 0) {
 569                /* call packet process for reporting finger leave. */
 570                cypress_process_packet(psmouse, 1);
 571                return PSMOUSE_FULL_PACKET;
 572        }
 573
 574        /*
 575         * Perform validation (and adjust packet size) based only on the
 576         * first byte; allow all further bytes through.
 577         */
 578        if (index != 0)
 579                return PSMOUSE_GOOD_DATA;
 580
 581        /*
 582         * If absolute/relative mode bit has not been set yet, just pass
 583         * the byte through.
 584         */
 585        if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
 586                return PSMOUSE_GOOD_DATA;
 587
 588        if ((packet[0] & 0x08) == 0x08)
 589                return PSMOUSE_BAD_DATA;
 590
 591        contact_cnt = cypress_get_finger_count(packet[0]);
 592        if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
 593                cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
 594        else
 595                cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
 596
 597        return PSMOUSE_GOOD_DATA;
 598}
 599
 600static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
 601{
 602        struct cytp_data *cytp = psmouse->private;
 603
 604        if (psmouse->pktcnt >= cytp->pkt_size) {
 605                cypress_process_packet(psmouse, 0);
 606                return PSMOUSE_FULL_PACKET;
 607        }
 608
 609        return cypress_validate_byte(psmouse);
 610}
 611
 612static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
 613{
 614        struct cytp_data *cytp = psmouse->private;
 615
 616        if (rate >= 80) {
 617                psmouse->rate = 80;
 618                cytp->mode |= CYTP_BIT_HIGH_RATE;
 619        } else {
 620                psmouse->rate = 40;
 621                cytp->mode &= ~CYTP_BIT_HIGH_RATE;
 622        }
 623
 624        ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
 625                    PSMOUSE_CMD_SETRATE);
 626}
 627
 628static void cypress_disconnect(struct psmouse *psmouse)
 629{
 630        cypress_reset(psmouse);
 631        kfree(psmouse->private);
 632        psmouse->private = NULL;
 633}
 634
 635static int cypress_reconnect(struct psmouse *psmouse)
 636{
 637        int tries = CYTP_PS2_CMD_TRIES;
 638        int rc;
 639
 640        do {
 641                cypress_reset(psmouse);
 642                rc = cypress_detect(psmouse, false);
 643        } while (rc && (--tries > 0));
 644
 645        if (rc) {
 646                psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
 647                return -1;
 648        }
 649
 650        if (cypress_set_absolute_mode(psmouse)) {
 651                psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
 652                return -1;
 653        }
 654
 655        return 0;
 656}
 657
 658int cypress_init(struct psmouse *psmouse)
 659{
 660        struct cytp_data *cytp;
 661
 662        cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
 663        if (!cytp)
 664                return -ENOMEM;
 665
 666        psmouse->private = cytp;
 667        psmouse->pktsize = 8;
 668
 669        cypress_reset(psmouse);
 670
 671        if (cypress_query_hardware(psmouse)) {
 672                psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
 673                goto err_exit;
 674        }
 675
 676        if (cypress_set_absolute_mode(psmouse)) {
 677                psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
 678                goto err_exit;
 679        }
 680
 681        if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
 682                psmouse_err(psmouse, "init: Unable to set input params.\n");
 683                goto err_exit;
 684        }
 685
 686        psmouse->model = 1;
 687        psmouse->protocol_handler = cypress_protocol_handler;
 688        psmouse->set_rate = cypress_set_rate;
 689        psmouse->disconnect = cypress_disconnect;
 690        psmouse->reconnect = cypress_reconnect;
 691        psmouse->cleanup = cypress_reset;
 692        psmouse->resync_time = 0;
 693
 694        return 0;
 695
 696err_exit:
 697        /*
 698         * Reset Cypress Trackpad as a standard mouse. Then
 699         * let psmouse driver commmunicating with it as default PS2 mouse.
 700         */
 701        cypress_reset(psmouse);
 702
 703        psmouse->private = NULL;
 704        kfree(cytp);
 705
 706        return -1;
 707}
 708