root/drivers/input/mouse/logips2pp.c

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

DEFINITIONS

This source file includes following definitions.
  1. ps2pp_process_byte
  2. ps2pp_cmd
  3. ps2pp_set_smartscroll
  4. ps2pp_attr_show_smartscroll
  5. ps2pp_attr_set_smartscroll
  6. ps2pp_set_resolution
  7. ps2pp_disconnect
  8. get_model_info
  9. ps2pp_set_model_properties
  10. ps2pp_setup_protocol
  11. ps2pp_detect

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Logitech PS/2++ mouse driver
   4  *
   5  * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
   6  * Copyright (c) 2003 Eric Wong <eric@yhbt.net>
   7  */
   8 
   9 #include <linux/bitops.h>
  10 #include <linux/input.h>
  11 #include <linux/serio.h>
  12 #include <linux/libps2.h>
  13 #include <linux/types.h>
  14 #include "psmouse.h"
  15 #include "logips2pp.h"
  16 
  17 /* Logitech mouse types */
  18 #define PS2PP_KIND_WHEEL        1
  19 #define PS2PP_KIND_MX           2
  20 #define PS2PP_KIND_TP3          3
  21 #define PS2PP_KIND_TRACKMAN     4
  22 
  23 /* Logitech mouse features */
  24 #define PS2PP_WHEEL             BIT(0)
  25 #define PS2PP_HWHEEL            BIT(1)
  26 #define PS2PP_SIDE_BTN          BIT(2)
  27 #define PS2PP_EXTRA_BTN         BIT(3)
  28 #define PS2PP_TASK_BTN          BIT(4)
  29 #define PS2PP_NAV_BTN           BIT(5)
  30 
  31 struct ps2pp_info {
  32         u8 model;
  33         u8 kind;
  34         u16 features;
  35 };
  36 
  37 /*
  38  * Process a PS2++ or PS2T++ packet.
  39  */
  40 
  41 static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
  42 {
  43         struct input_dev *dev = psmouse->dev;
  44         u8 *packet = psmouse->packet;
  45 
  46         if (psmouse->pktcnt < 3)
  47                 return PSMOUSE_GOOD_DATA;
  48 
  49 /*
  50  * Full packet accumulated, process it
  51  */
  52 
  53         if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
  54 
  55                 /* Logitech extended packet */
  56                 switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
  57 
  58                 case 0x0d: /* Mouse extra info */
  59 
  60                         input_report_rel(dev,
  61                                 packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
  62                                 -sign_extend32(packet[2], 3));
  63                         input_report_key(dev, BTN_SIDE,  packet[2] & BIT(4));
  64                         input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
  65 
  66                         break;
  67 
  68                 case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
  69 
  70                         input_report_key(dev, BTN_SIDE,    packet[2] & BIT(0));
  71                         input_report_key(dev, BTN_EXTRA,   packet[2] & BIT(1));
  72                         input_report_key(dev, BTN_TASK,    packet[2] & BIT(2));
  73                         input_report_key(dev, BTN_BACK,    packet[2] & BIT(3));
  74                         input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
  75 
  76                         break;
  77 
  78                 case 0x0f: /* TouchPad extra info */
  79 
  80                         input_report_rel(dev,
  81                                 packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
  82                                 -sign_extend32(packet[2] >> 4, 3));
  83                         packet[0] = packet[2] | BIT(3);
  84                         break;
  85 
  86                 default:
  87                         psmouse_dbg(psmouse,
  88                                     "Received PS2++ packet #%x, but don't know how to handle.\n",
  89                                     (packet[1] >> 4) | (packet[0] & 0x30));
  90                         break;
  91                 }
  92 
  93                 psmouse_report_standard_buttons(dev, packet[0]);
  94 
  95         } else {
  96                 /* Standard PS/2 motion data */
  97                 psmouse_report_standard_packet(dev, packet);
  98         }
  99 
 100         input_sync(dev);
 101 
 102         return PSMOUSE_FULL_PACKET;
 103 
 104 }
 105 
 106 /*
 107  * ps2pp_cmd() sends a PS2++ command, sliced into two bit
 108  * pieces through the SETRES command. This is needed to send extended
 109  * commands to mice on notebooks that try to understand the PS/2 protocol
 110  * Ugly.
 111  */
 112 
 113 static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
 114 {
 115         int error;
 116 
 117         error = ps2_sliced_command(&psmouse->ps2dev, command);
 118         if (error)
 119                 return error;
 120 
 121         error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
 122         if (error)
 123                 return error;
 124 
 125         return 0;
 126 }
 127 
 128 /*
 129  * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
 130  * enabled if we do nothing to it. Of course I put this in because I want it
 131  * disabled :P
 132  * 1 - enabled (if previously disabled, also default)
 133  * 0 - disabled
 134  */
 135 
 136 static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
 137 {
 138         struct ps2dev *ps2dev = &psmouse->ps2dev;
 139         u8 param[4];
 140 
 141         ps2pp_cmd(psmouse, param, 0x32);
 142 
 143         param[0] = 0;
 144         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 145         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 146         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 147 
 148         param[0] = smartscroll;
 149         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 150 }
 151 
 152 static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
 153                                            void *data, char *buf)
 154 {
 155         return sprintf(buf, "%d\n", psmouse->smartscroll);
 156 }
 157 
 158 static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
 159                                           const char *buf, size_t count)
 160 {
 161         unsigned int value;
 162         int err;
 163 
 164         err = kstrtouint(buf, 10, &value);
 165         if (err)
 166                 return err;
 167 
 168         if (value > 1)
 169                 return -EINVAL;
 170 
 171         ps2pp_set_smartscroll(psmouse, value);
 172         psmouse->smartscroll = value;
 173         return count;
 174 }
 175 
 176 PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
 177                     ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
 178 
 179 /*
 180  * Support 800 dpi resolution _only_ if the user wants it (there are good
 181  * reasons to not use it even if the mouse supports it, and of course there are
 182  * also good reasons to use it, let the user decide).
 183  */
 184 
 185 static void ps2pp_set_resolution(struct psmouse *psmouse,
 186                                  unsigned int resolution)
 187 {
 188         if (resolution > 400) {
 189                 struct ps2dev *ps2dev = &psmouse->ps2dev;
 190                 u8 param = 3;
 191 
 192                 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
 193                 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
 194                 ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
 195                 ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
 196                 psmouse->resolution = 800;
 197         } else
 198                 psmouse_set_resolution(psmouse, resolution);
 199 }
 200 
 201 static void ps2pp_disconnect(struct psmouse *psmouse)
 202 {
 203         device_remove_file(&psmouse->ps2dev.serio->dev,
 204                            &psmouse_attr_smartscroll.dattr);
 205 }
 206 
 207 static const struct ps2pp_info *get_model_info(unsigned char model)
 208 {
 209         static const struct ps2pp_info ps2pp_list[] = {
 210                 {  1,   0,                      0 },    /* Simple 2-button mouse */
 211                 { 12,   0,                      PS2PP_SIDE_BTN},
 212                 { 13,   0,                      0 },
 213                 { 15,   PS2PP_KIND_MX,                                  /* MX1000 */
 214                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
 215                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
 216                 { 40,   0,                      PS2PP_SIDE_BTN },
 217                 { 41,   0,                      PS2PP_SIDE_BTN },
 218                 { 42,   0,                      PS2PP_SIDE_BTN },
 219                 { 43,   0,                      PS2PP_SIDE_BTN },
 220                 { 50,   0,                      0 },
 221                 { 51,   0,                      0 },
 222                 { 52,   PS2PP_KIND_WHEEL,       PS2PP_SIDE_BTN | PS2PP_WHEEL },
 223                 { 53,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 224                 { 56,   PS2PP_KIND_WHEEL,       PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
 225                 { 61,   PS2PP_KIND_MX,                                  /* MX700 */
 226                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
 227                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
 228                 { 66,   PS2PP_KIND_MX,                                  /* MX3100 receiver */
 229                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
 230                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
 231                 { 72,   PS2PP_KIND_TRACKMAN,    0 },                    /* T-CH11: TrackMan Marble */
 232                 { 73,   PS2PP_KIND_TRACKMAN,    PS2PP_SIDE_BTN },       /* TrackMan FX */
 233                 { 75,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 234                 { 76,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 235                 { 79,   PS2PP_KIND_TRACKMAN,    PS2PP_WHEEL },          /* TrackMan with wheel */
 236                 { 80,   PS2PP_KIND_WHEEL,       PS2PP_SIDE_BTN | PS2PP_WHEEL },
 237                 { 81,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 238                 { 83,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 239                 { 85,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 240                 { 86,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 241                 { 87,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 242                 { 88,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 243                 { 96,   0,                      0 },
 244                 { 97,   PS2PP_KIND_TP3,         PS2PP_WHEEL | PS2PP_HWHEEL },
 245                 { 99,   PS2PP_KIND_WHEEL,       PS2PP_WHEEL },
 246                 { 100,  PS2PP_KIND_MX,                                  /* MX510 */
 247                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
 248                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
 249                 { 111,  PS2PP_KIND_MX,  PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
 250                 { 112,  PS2PP_KIND_MX,                                  /* MX500 */
 251                                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
 252                                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
 253                 { 114,  PS2PP_KIND_MX,                                  /* MX310 */
 254                                 PS2PP_WHEEL | PS2PP_SIDE_BTN |
 255                                 PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
 256         };
 257         int i;
 258 
 259         for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
 260                 if (model == ps2pp_list[i].model)
 261                         return &ps2pp_list[i];
 262 
 263         return NULL;
 264 }
 265 
 266 /*
 267  * Set up input device's properties based on the detected mouse model.
 268  */
 269 
 270 static void ps2pp_set_model_properties(struct psmouse *psmouse,
 271                                        const struct ps2pp_info *model_info,
 272                                        bool using_ps2pp)
 273 {
 274         struct input_dev *input_dev = psmouse->dev;
 275 
 276         if (model_info->features & PS2PP_SIDE_BTN)
 277                 input_set_capability(input_dev, EV_KEY, BTN_SIDE);
 278 
 279         if (model_info->features & PS2PP_EXTRA_BTN)
 280                 input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
 281 
 282         if (model_info->features & PS2PP_TASK_BTN)
 283                 input_set_capability(input_dev, EV_KEY, BTN_TASK);
 284 
 285         if (model_info->features & PS2PP_NAV_BTN) {
 286                 input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
 287                 input_set_capability(input_dev, EV_KEY, BTN_BACK);
 288         }
 289 
 290         if (model_info->features & PS2PP_WHEEL)
 291                 input_set_capability(input_dev, EV_REL, REL_WHEEL);
 292 
 293         if (model_info->features & PS2PP_HWHEEL)
 294                 input_set_capability(input_dev, EV_REL, REL_HWHEEL);
 295 
 296         switch (model_info->kind) {
 297 
 298         case PS2PP_KIND_WHEEL:
 299                 psmouse->name = "Wheel Mouse";
 300                 break;
 301 
 302         case PS2PP_KIND_MX:
 303                 psmouse->name = "MX Mouse";
 304                 break;
 305 
 306         case PS2PP_KIND_TP3:
 307                 psmouse->name = "TouchPad 3";
 308                 break;
 309 
 310         case PS2PP_KIND_TRACKMAN:
 311                 psmouse->name = "TrackMan";
 312                 break;
 313 
 314         default:
 315                 /*
 316                  * Set name to "Mouse" only when using PS2++,
 317                  * otherwise let other protocols define suitable
 318                  * name
 319                  */
 320                 if (using_ps2pp)
 321                         psmouse->name = "Mouse";
 322                 break;
 323         }
 324 }
 325 
 326 static int ps2pp_setup_protocol(struct psmouse *psmouse,
 327                                 const struct ps2pp_info *model_info)
 328 {
 329         int error;
 330 
 331         psmouse->protocol_handler = ps2pp_process_byte;
 332         psmouse->pktsize = 3;
 333 
 334         if (model_info->kind != PS2PP_KIND_TP3) {
 335                 psmouse->set_resolution = ps2pp_set_resolution;
 336                 psmouse->disconnect = ps2pp_disconnect;
 337 
 338                 error = device_create_file(&psmouse->ps2dev.serio->dev,
 339                                            &psmouse_attr_smartscroll.dattr);
 340                 if (error) {
 341                         psmouse_err(psmouse,
 342                                     "failed to create smartscroll sysfs attribute, error: %d\n",
 343                                     error);
 344                         return error;
 345                 }
 346         }
 347 
 348         return 0;
 349 }
 350 
 351 /*
 352  * Logitech magic init. Detect whether the mouse is a Logitech one
 353  * and its exact model and try turning on extended protocol for ones
 354  * that support it.
 355  */
 356 
 357 int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
 358 {
 359         struct ps2dev *ps2dev = &psmouse->ps2dev;
 360         const struct ps2pp_info *model_info;
 361         u8 param[4];
 362         u8 model, buttons;
 363         bool use_ps2pp = false;
 364         int error;
 365 
 366         param[0] = 0;
 367         ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
 368         ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
 369         ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
 370         ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
 371         param[1] = 0;
 372         ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
 373 
 374         model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
 375         buttons = param[1];
 376 
 377         if (!model || !buttons)
 378                 return -ENXIO;
 379 
 380         model_info = get_model_info(model);
 381         if (model_info) {
 382 
 383 /*
 384  * Do Logitech PS2++ / PS2T++ magic init.
 385  */
 386                 if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
 387 
 388                         /* Unprotect RAM */
 389                         param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
 390                         ps2_command(ps2dev, param, 0x30d1);
 391                         /* Enable features */
 392                         param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
 393                         ps2_command(ps2dev, param, 0x30d1);
 394                         /* Enable PS2++ */
 395                         param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
 396                         ps2_command(ps2dev, param, 0x30d1);
 397 
 398                         param[0] = 0;
 399                         if (!ps2_command(ps2dev, param, 0x13d1) &&
 400                             param[0] == 0x06 && param[1] == 0x00 &&
 401                             param[2] == 0x14) {
 402                                 use_ps2pp = true;
 403                         }
 404 
 405                 } else {
 406 
 407                         param[0] = param[1] = param[2] = 0;
 408                         ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
 409                         ps2pp_cmd(psmouse, param, 0xDB);
 410 
 411                         if ((param[0] & 0x78) == 0x48 &&
 412                             (param[1] & 0xf3) == 0xc2 &&
 413                             (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
 414                                 ps2pp_set_smartscroll(psmouse, false);
 415                                 use_ps2pp = true;
 416                         }
 417                 }
 418 
 419         } else {
 420                 psmouse_warn(psmouse,
 421                              "Detected unknown Logitech mouse model %d\n",
 422                              model);
 423         }
 424 
 425         if (set_properties) {
 426                 psmouse->vendor = "Logitech";
 427                 psmouse->model = model;
 428 
 429                 if (use_ps2pp) {
 430                         error = ps2pp_setup_protocol(psmouse, model_info);
 431                         if (error)
 432                                 return error;
 433                 }
 434 
 435                 if (buttons >= 3)
 436                         input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
 437 
 438                 if (model_info)
 439                         ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
 440         }
 441 
 442         return use_ps2pp ? 0 : -ENXIO;
 443 }
 444 

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