LCOV - code coverage report
Current view: top level - drivers/input/mouse - cypress_ps2.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 289 0.0 %
Date: 2023-08-24 13:40:31 Functions: 0 19 0.0 %

          Line data    Source code
       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             : 
      29             : static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
      30             : {
      31           0 :         struct cytp_data *cytp = psmouse->private;
      32           0 :         cytp->pkt_size = n;
      33             : }
      34             : 
      35             : static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
      36             : static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
      37             : 
      38             : static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
      39             : {
      40           0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
      41             : 
      42           0 :         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           0 :                 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             : 
      60           0 : static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
      61             :                                unsigned char data)
      62             : {
      63           0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
      64           0 :         int tries = CYTP_PS2_CMD_TRIES;
      65             :         int rc;
      66             : 
      67           0 :         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           0 :                 rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
      76           0 :                 if (rc == CYTP_PS2_RETRY) {
      77           0 :                         rc = cypress_ps2_sendbyte(psmouse, 0x00);
      78           0 :                         if (rc == CYTP_PS2_RETRY)
      79             :                                 rc = cypress_ps2_sendbyte(psmouse, 0x0a);
      80             :                 }
      81           0 :                 if (rc == CYTP_PS2_ERROR)
      82           0 :                         continue;
      83             : 
      84           0 :                 rc = cypress_ps2_sendbyte(psmouse, data);
      85           0 :                 if (rc == CYTP_PS2_RETRY)
      86           0 :                         rc = cypress_ps2_sendbyte(psmouse, data);
      87           0 :                 if (rc == CYTP_PS2_ERROR)
      88           0 :                         continue;
      89             :                 else
      90             :                         break;
      91           0 :         } while (--tries > 0);
      92             : 
      93           0 :         ps2_end_command(ps2dev);
      94             : 
      95           0 :         return rc;
      96             : }
      97             : 
      98           0 : static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
      99             :                                        unsigned char cmd,
     100             :                                        unsigned char *param)
     101             : {
     102             :         int rc;
     103           0 :         struct ps2dev *ps2dev = &psmouse->ps2dev;
     104             :         enum psmouse_state old_state;
     105             :         int pktsize;
     106             : 
     107           0 :         ps2_begin_command(ps2dev);
     108             : 
     109           0 :         old_state = psmouse->state;
     110           0 :         psmouse->state = PSMOUSE_CMD_MODE;
     111           0 :         psmouse->pktcnt = 0;
     112             : 
     113           0 :         pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
     114           0 :         memset(param, 0, pktsize);
     115             : 
     116           0 :         rc = cypress_ps2_sendbyte(psmouse, 0xe9);
     117             :         if (rc < 0)
     118             :                 goto out;
     119             : 
     120           0 :         wait_event_timeout(ps2dev->wait,
     121             :                         (psmouse->pktcnt >= pktsize),
     122             :                         msecs_to_jiffies(CYTP_CMD_TIMEOUT));
     123             : 
     124           0 :         memcpy(param, psmouse->packet, pktsize);
     125             : 
     126             :         psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
     127             :                         cmd, pktsize, param);
     128             : 
     129             : out:
     130           0 :         psmouse->state = old_state;
     131           0 :         psmouse->pktcnt = 0;
     132             : 
     133           0 :         ps2_end_command(ps2dev);
     134             : 
     135           0 :         return rc;
     136             : }
     137             : 
     138           0 : static bool cypress_verify_cmd_state(struct psmouse *psmouse,
     139             :                                      unsigned char cmd, unsigned char *param)
     140             : {
     141           0 :         bool rate_match = false;
     142           0 :         bool resolution_match = false;
     143             :         int i;
     144             : 
     145             :         /* callers will do further checking. */
     146           0 :         if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
     147           0 :             cmd == CYTP_CMD_STANDARD_MODE ||
     148             :             cmd == CYTP_CMD_READ_TP_METRICS)
     149             :                 return true;
     150             : 
     151           0 :         if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
     152             :             (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
     153           0 :                 for (i = 0; i < sizeof(cytp_resolution); i++)
     154           0 :                         if (cytp_resolution[i] == param[1])
     155           0 :                                 resolution_match = true;
     156             : 
     157           0 :                 for (i = 0; i < sizeof(cytp_rate); i++)
     158           0 :                         if (cytp_rate[i] == param[2])
     159           0 :                                 rate_match = true;
     160             : 
     161           0 :                 if (resolution_match && rate_match)
     162             :                         return true;
     163             :         }
     164             : 
     165             :         psmouse_dbg(psmouse, "verify cmd state failed.\n");
     166           0 :         return false;
     167             : }
     168             : 
     169           0 : static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
     170             :                                 unsigned char *param)
     171             : {
     172           0 :         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           0 :                 cypress_ps2_ext_cmd(psmouse,
     181           0 :                                     PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
     182           0 :                 cypress_ps2_ext_cmd(psmouse,
     183           0 :                                     PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
     184           0 :                 cypress_ps2_ext_cmd(psmouse,
     185           0 :                                     PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
     186           0 :                 cypress_ps2_ext_cmd(psmouse,
     187             :                                     PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
     188             : 
     189           0 :                 rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
     190           0 :                 if (rc)
     191           0 :                         continue;
     192             : 
     193           0 :                 if (cypress_verify_cmd_state(psmouse, cmd, param))
     194             :                         return 0;
     195             : 
     196           0 :         } while (--tries > 0);
     197             : 
     198             :         return -EIO;
     199             : }
     200             : 
     201           0 : int cypress_detect(struct psmouse *psmouse, bool set_properties)
     202             : {
     203             :         unsigned char param[3];
     204             : 
     205           0 :         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           0 :         if (param[0] != 0x33 || param[1] != 0xCC)
     210             :                 return -ENODEV;
     211             : 
     212           0 :         if (set_properties) {
     213           0 :                 psmouse->vendor = "Cypress";
     214           0 :                 psmouse->name = "Trackpad";
     215             :         }
     216             : 
     217             :         return 0;
     218             : }
     219             : 
     220           0 : static int cypress_read_fw_version(struct psmouse *psmouse)
     221             : {
     222           0 :         struct cytp_data *cytp = psmouse->private;
     223             :         unsigned char param[3];
     224             : 
     225           0 :         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           0 :         if (param[0] != 0x33 || param[1] != 0xCC)
     230             :                 return -ENODEV;
     231             : 
     232           0 :         cytp->fw_version = param[2] & FW_VERSION_MASX;
     233           0 :         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           0 :         if (cytp->fw_version >= 11)
     240           0 :                 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             : 
     249           0 : static int cypress_read_tp_metrics(struct psmouse *psmouse)
     250             : {
     251           0 :         struct cytp_data *cytp = psmouse->private;
     252             :         unsigned char param[8];
     253             : 
     254             :         /* set default values for tp metrics. */
     255           0 :         cytp->tp_width = CYTP_DEFAULT_WIDTH;
     256           0 :         cytp->tp_high = CYTP_DEFAULT_HIGH;
     257           0 :         cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
     258           0 :         cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
     259           0 :         cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
     260           0 :         cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
     261           0 :         cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
     262           0 :         cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
     263             : 
     264           0 :         if (!cytp->tp_metrics_supported)
     265             :                 return 0;
     266             : 
     267           0 :         memset(param, 0, sizeof(param));
     268           0 :         if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
     269             :                 /* Update trackpad parameters. */
     270           0 :                 cytp->tp_max_abs_x = (param[1] << 8) | param[0];
     271           0 :                 cytp->tp_max_abs_y = (param[3] << 8) | param[2];
     272           0 :                 cytp->tp_min_pressure = param[4];
     273           0 :                 cytp->tp_max_pressure = param[5];
     274             :         }
     275             : 
     276           0 :         if (!cytp->tp_max_pressure ||
     277           0 :             cytp->tp_max_pressure < cytp->tp_min_pressure ||
     278           0 :             !cytp->tp_width || !cytp->tp_high ||
     279           0 :             !cytp->tp_max_abs_x ||
     280           0 :             cytp->tp_max_abs_x < cytp->tp_width ||
     281           0 :             !cytp->tp_max_abs_y ||
     282             :             cytp->tp_max_abs_y < cytp->tp_high)
     283             :                 return -EINVAL;
     284             : 
     285           0 :         cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
     286           0 :         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           0 :         return 0;
     320             : }
     321             : 
     322           0 : static int cypress_query_hardware(struct psmouse *psmouse)
     323             : {
     324             :         int ret;
     325             : 
     326           0 :         ret = cypress_read_fw_version(psmouse);
     327           0 :         if (ret)
     328             :                 return ret;
     329             : 
     330           0 :         ret = cypress_read_tp_metrics(psmouse);
     331           0 :         if (ret)
     332             :                 return ret;
     333             : 
     334           0 :         return 0;
     335             : }
     336             : 
     337           0 : static int cypress_set_absolute_mode(struct psmouse *psmouse)
     338             : {
     339           0 :         struct cytp_data *cytp = psmouse->private;
     340             :         unsigned char param[3];
     341             : 
     342           0 :         if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
     343             :                 return -1;
     344             : 
     345           0 :         cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
     346           0 :                         | CYTP_BIT_ABS_PRESSURE;
     347           0 :         cypress_set_packet_size(psmouse, 5);
     348             : 
     349           0 :         return 0;
     350             : }
     351             : 
     352             : /*
     353             :  * Reset trackpad device.
     354             :  * This is also the default mode when trackpad powered on.
     355             :  */
     356           0 : static void cypress_reset(struct psmouse *psmouse)
     357             : {
     358           0 :         struct cytp_data *cytp = psmouse->private;
     359             : 
     360           0 :         cytp->mode = 0;
     361             : 
     362           0 :         psmouse_reset(psmouse);
     363           0 : }
     364             : 
     365           0 : static int cypress_set_input_params(struct input_dev *input,
     366             :                                     struct cytp_data *cytp)
     367             : {
     368             :         int ret;
     369             : 
     370           0 :         if (!cytp->tp_res_x || !cytp->tp_res_y)
     371             :                 return -EINVAL;
     372             : 
     373           0 :         __set_bit(EV_ABS, input->evbit);
     374           0 :         input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
     375           0 :         input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
     376           0 :         input_set_abs_params(input, ABS_PRESSURE,
     377             :                              cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
     378           0 :         input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
     379             : 
     380             :         /* finger position */
     381           0 :         input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
     382           0 :         input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
     383           0 :         input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
     384             : 
     385           0 :         ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
     386             :                         INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
     387           0 :         if (ret < 0)
     388             :                 return ret;
     389             : 
     390           0 :         __set_bit(INPUT_PROP_SEMI_MT, input->propbit);
     391             : 
     392           0 :         input_abs_set_res(input, ABS_X, cytp->tp_res_x);
     393           0 :         input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
     394             : 
     395           0 :         input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
     396           0 :         input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
     397             : 
     398           0 :         __set_bit(BTN_TOUCH, input->keybit);
     399           0 :         __set_bit(BTN_TOOL_FINGER, input->keybit);
     400           0 :         __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
     401           0 :         __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
     402           0 :         __set_bit(BTN_TOOL_QUADTAP, input->keybit);
     403           0 :         __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
     404             : 
     405           0 :         __clear_bit(EV_REL, input->evbit);
     406           0 :         __clear_bit(REL_X, input->relbit);
     407           0 :         __clear_bit(REL_Y, input->relbit);
     408             : 
     409           0 :         __set_bit(EV_KEY, input->evbit);
     410           0 :         __set_bit(BTN_LEFT, input->keybit);
     411           0 :         __set_bit(BTN_RIGHT, input->keybit);
     412           0 :         __set_bit(BTN_MIDDLE, input->keybit);
     413             : 
     414             :         return 0;
     415             : }
     416             : 
     417             : static int cypress_get_finger_count(unsigned char header_byte)
     418             : {
     419             :         unsigned char bits6_7;
     420             :         int finger_count;
     421             : 
     422           0 :         bits6_7 = header_byte >> 6;
     423           0 :         finger_count = bits6_7 & 0x03;
     424             : 
     425           0 :         if (finger_count == 1)
     426             :                 return 1;
     427             : 
     428           0 :         if (header_byte & ABS_HSCROLL_BIT) {
     429             :                 /* HSCROLL gets added on to 0 finger count. */
     430           0 :                 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             : 
     443           0 : static int cypress_parse_packet(struct psmouse *psmouse,
     444             :                                 struct cytp_data *cytp, struct cytp_report_data *report_data)
     445             : {
     446           0 :         unsigned char *packet = psmouse->packet;
     447           0 :         unsigned char header_byte = packet[0];
     448             : 
     449           0 :         memset(report_data, 0, sizeof(struct cytp_report_data));
     450             : 
     451           0 :         report_data->contact_cnt = cypress_get_finger_count(header_byte);
     452           0 :         report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
     453             : 
     454           0 :         if (report_data->contact_cnt == 1) {
     455           0 :                 report_data->contacts[0].x =
     456           0 :                         ((packet[1] & 0x70) << 4) | packet[2];
     457           0 :                 report_data->contacts[0].y =
     458           0 :                         ((packet[1] & 0x07) << 8) | packet[3];
     459           0 :                 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
     460           0 :                         report_data->contacts[0].z = packet[4];
     461             : 
     462           0 :         } else if (report_data->contact_cnt >= 2) {
     463           0 :                 report_data->contacts[0].x =
     464           0 :                         ((packet[1] & 0x70) << 4) | packet[2];
     465           0 :                 report_data->contacts[0].y =
     466           0 :                         ((packet[1] & 0x07) << 8) | packet[3];
     467           0 :                 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
     468           0 :                         report_data->contacts[0].z = packet[4];
     469             : 
     470           0 :                 report_data->contacts[1].x =
     471           0 :                         ((packet[5] & 0xf0) << 4) | packet[6];
     472           0 :                 report_data->contacts[1].y =
     473           0 :                         ((packet[5] & 0x0f) << 8) | packet[7];
     474           0 :                 if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
     475           0 :                         report_data->contacts[1].z = report_data->contacts[0].z;
     476             :         }
     477             : 
     478           0 :         report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
     479           0 :         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           0 :         if (report_data->tap)
     488           0 :                 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           0 :         return 0;
     511             : }
     512             : 
     513           0 : static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
     514             : {
     515             :         int i;
     516           0 :         struct input_dev *input = psmouse->dev;
     517           0 :         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           0 :         cypress_parse_packet(psmouse, cytp, &report_data);
     525             : 
     526           0 :         n = report_data.contact_cnt;
     527           0 :         if (n > CYTP_MAX_MT_SLOTS)
     528           0 :                 n = CYTP_MAX_MT_SLOTS;
     529             : 
     530           0 :         for (i = 0; i < n; i++) {
     531           0 :                 contact = &report_data.contacts[i];
     532           0 :                 pos[i].x = contact->x;
     533           0 :                 pos[i].y = contact->y;
     534             :         }
     535             : 
     536           0 :         input_mt_assign_slots(input, slots, pos, n, 0);
     537             : 
     538           0 :         for (i = 0; i < n; i++) {
     539           0 :                 contact = &report_data.contacts[i];
     540           0 :                 input_mt_slot(input, slots[i]);
     541           0 :                 input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
     542           0 :                 input_report_abs(input, ABS_MT_POSITION_X, contact->x);
     543           0 :                 input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
     544           0 :                 input_report_abs(input, ABS_MT_PRESSURE, contact->z);
     545             :         }
     546             : 
     547           0 :         input_mt_sync_frame(input);
     548             : 
     549           0 :         input_mt_report_finger_count(input, report_data.contact_cnt);
     550             : 
     551           0 :         input_report_key(input, BTN_LEFT, report_data.left);
     552           0 :         input_report_key(input, BTN_RIGHT, report_data.right);
     553           0 :         input_report_key(input, BTN_MIDDLE, report_data.middle);
     554             : 
     555           0 :         input_sync(input);
     556           0 : }
     557             : 
     558           0 : static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
     559             : {
     560             :         int contact_cnt;
     561           0 :         int index = psmouse->pktcnt - 1;
     562           0 :         unsigned char *packet = psmouse->packet;
     563           0 :         struct cytp_data *cytp = psmouse->private;
     564             : 
     565           0 :         if (index < 0 || index > cytp->pkt_size)
     566             :                 return PSMOUSE_BAD_DATA;
     567             : 
     568           0 :         if (index == 0 && (packet[0] & 0xfc) == 0) {
     569             :                 /* call packet process for reporting finger leave. */
     570           0 :                 cypress_process_packet(psmouse, 1);
     571           0 :                 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           0 :         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           0 :         if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
     586             :                 return PSMOUSE_GOOD_DATA;
     587             : 
     588           0 :         if ((packet[0] & 0x08) == 0x08)
     589             :                 return PSMOUSE_BAD_DATA;
     590             : 
     591           0 :         contact_cnt = cypress_get_finger_count(packet[0]);
     592           0 :         if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
     593           0 :                 cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
     594             :         else
     595           0 :                 cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
     596             : 
     597             :         return PSMOUSE_GOOD_DATA;
     598             : }
     599             : 
     600           0 : static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
     601             : {
     602           0 :         struct cytp_data *cytp = psmouse->private;
     603             : 
     604           0 :         if (psmouse->pktcnt >= cytp->pkt_size) {
     605           0 :                 cypress_process_packet(psmouse, 0);
     606           0 :                 return PSMOUSE_FULL_PACKET;
     607             :         }
     608             : 
     609           0 :         return cypress_validate_byte(psmouse);
     610             : }
     611             : 
     612           0 : static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
     613             : {
     614           0 :         struct cytp_data *cytp = psmouse->private;
     615             : 
     616           0 :         if (rate >= 80) {
     617           0 :                 psmouse->rate = 80;
     618           0 :                 cytp->mode |= CYTP_BIT_HIGH_RATE;
     619             :         } else {
     620           0 :                 psmouse->rate = 40;
     621           0 :                 cytp->mode &= ~CYTP_BIT_HIGH_RATE;
     622             :         }
     623             : 
     624           0 :         ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
     625             :                     PSMOUSE_CMD_SETRATE);
     626           0 : }
     627             : 
     628           0 : static void cypress_disconnect(struct psmouse *psmouse)
     629             : {
     630           0 :         cypress_reset(psmouse);
     631           0 :         kfree(psmouse->private);
     632           0 :         psmouse->private = NULL;
     633           0 : }
     634             : 
     635           0 : static int cypress_reconnect(struct psmouse *psmouse)
     636             : {
     637           0 :         int tries = CYTP_PS2_CMD_TRIES;
     638             :         int rc;
     639             : 
     640             :         do {
     641           0 :                 cypress_reset(psmouse);
     642           0 :                 rc = cypress_detect(psmouse, false);
     643           0 :         } while (rc && (--tries > 0));
     644             : 
     645           0 :         if (rc) {
     646           0 :                 psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
     647           0 :                 return -1;
     648             :         }
     649             : 
     650           0 :         if (cypress_set_absolute_mode(psmouse)) {
     651           0 :                 psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
     652           0 :                 return -1;
     653             :         }
     654             : 
     655             :         return 0;
     656             : }
     657             : 
     658           0 : int cypress_init(struct psmouse *psmouse)
     659             : {
     660             :         struct cytp_data *cytp;
     661             : 
     662           0 :         cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
     663           0 :         if (!cytp)
     664             :                 return -ENOMEM;
     665             : 
     666           0 :         psmouse->private = cytp;
     667           0 :         psmouse->pktsize = 8;
     668             : 
     669           0 :         cypress_reset(psmouse);
     670             : 
     671           0 :         if (cypress_query_hardware(psmouse)) {
     672           0 :                 psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
     673           0 :                 goto err_exit;
     674             :         }
     675             : 
     676           0 :         if (cypress_set_absolute_mode(psmouse)) {
     677           0 :                 psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
     678           0 :                 goto err_exit;
     679             :         }
     680             : 
     681           0 :         if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
     682           0 :                 psmouse_err(psmouse, "init: Unable to set input params.\n");
     683           0 :                 goto err_exit;
     684             :         }
     685             : 
     686           0 :         psmouse->model = 1;
     687           0 :         psmouse->protocol_handler = cypress_protocol_handler;
     688           0 :         psmouse->set_rate = cypress_set_rate;
     689           0 :         psmouse->disconnect = cypress_disconnect;
     690           0 :         psmouse->reconnect = cypress_reconnect;
     691           0 :         psmouse->cleanup = cypress_reset;
     692           0 :         psmouse->resync_time = 0;
     693             : 
     694           0 :         return 0;
     695             : 
     696             : err_exit:
     697             :         /*
     698             :          * Reset Cypress Trackpad as a standard mouse. Then
     699             :          * let psmouse driver communicating with it as default PS2 mouse.
     700             :          */
     701           0 :         cypress_reset(psmouse);
     702             : 
     703           0 :         psmouse->private = NULL;
     704           0 :         kfree(cytp);
     705             : 
     706           0 :         return -1;
     707             : }

Generated by: LCOV version 1.14