Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Logitech PS/2++ mouse driver
0004  *
0005  * Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
0006  * Copyright (c) 2003 Eric Wong <eric@yhbt.net>
0007  */
0008 
0009 #include <linux/bitops.h>
0010 #include <linux/input.h>
0011 #include <linux/serio.h>
0012 #include <linux/libps2.h>
0013 #include <linux/types.h>
0014 #include "psmouse.h"
0015 #include "logips2pp.h"
0016 
0017 /* Logitech mouse types */
0018 #define PS2PP_KIND_WHEEL    1
0019 #define PS2PP_KIND_MX       2
0020 #define PS2PP_KIND_TP3      3
0021 #define PS2PP_KIND_TRACKMAN 4
0022 
0023 /* Logitech mouse features */
0024 #define PS2PP_WHEEL     BIT(0)
0025 #define PS2PP_HWHEEL        BIT(1)
0026 #define PS2PP_SIDE_BTN      BIT(2)
0027 #define PS2PP_EXTRA_BTN     BIT(3)
0028 #define PS2PP_TASK_BTN      BIT(4)
0029 #define PS2PP_NAV_BTN       BIT(5)
0030 
0031 struct ps2pp_info {
0032     u8 model;
0033     u8 kind;
0034     u16 features;
0035 };
0036 
0037 /*
0038  * Process a PS2++ or PS2T++ packet.
0039  */
0040 
0041 static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
0042 {
0043     struct input_dev *dev = psmouse->dev;
0044     u8 *packet = psmouse->packet;
0045 
0046     if (psmouse->pktcnt < 3)
0047         return PSMOUSE_GOOD_DATA;
0048 
0049 /*
0050  * Full packet accumulated, process it
0051  */
0052 
0053     if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
0054 
0055         /* Logitech extended packet */
0056         switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
0057 
0058         case 0x0d: /* Mouse extra info */
0059 
0060             input_report_rel(dev,
0061                 packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
0062                 -sign_extend32(packet[2], 3));
0063             input_report_key(dev, BTN_SIDE,  packet[2] & BIT(4));
0064             input_report_key(dev, BTN_EXTRA, packet[2] & BIT(5));
0065 
0066             break;
0067 
0068         case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
0069 
0070             input_report_key(dev, BTN_SIDE,    packet[2] & BIT(0));
0071             input_report_key(dev, BTN_EXTRA,   packet[2] & BIT(1));
0072             input_report_key(dev, BTN_TASK,    packet[2] & BIT(2));
0073             input_report_key(dev, BTN_BACK,    packet[2] & BIT(3));
0074             input_report_key(dev, BTN_FORWARD, packet[2] & BIT(4));
0075 
0076             break;
0077 
0078         case 0x0f: /* TouchPad extra info */
0079 
0080             input_report_rel(dev,
0081                 packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
0082                 -sign_extend32(packet[2] >> 4, 3));
0083             packet[0] = packet[2] | BIT(3);
0084             break;
0085 
0086         default:
0087             psmouse_dbg(psmouse,
0088                     "Received PS2++ packet #%x, but don't know how to handle.\n",
0089                     (packet[1] >> 4) | (packet[0] & 0x30));
0090             break;
0091         }
0092 
0093         psmouse_report_standard_buttons(dev, packet[0]);
0094 
0095     } else {
0096         /* Standard PS/2 motion data */
0097         psmouse_report_standard_packet(dev, packet);
0098     }
0099 
0100     input_sync(dev);
0101 
0102     return PSMOUSE_FULL_PACKET;
0103 
0104 }
0105 
0106 /*
0107  * ps2pp_cmd() sends a PS2++ command, sliced into two bit
0108  * pieces through the SETRES command. This is needed to send extended
0109  * commands to mice on notebooks that try to understand the PS/2 protocol
0110  * Ugly.
0111  */
0112 
0113 static int ps2pp_cmd(struct psmouse *psmouse, u8 *param, u8 command)
0114 {
0115     int error;
0116 
0117     error = ps2_sliced_command(&psmouse->ps2dev, command);
0118     if (error)
0119         return error;
0120 
0121     error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300);
0122     if (error)
0123         return error;
0124 
0125     return 0;
0126 }
0127 
0128 /*
0129  * SmartScroll / CruiseControl for some newer Logitech mice Defaults to
0130  * enabled if we do nothing to it. Of course I put this in because I want it
0131  * disabled :P
0132  * 1 - enabled (if previously disabled, also default)
0133  * 0 - disabled
0134  */
0135 
0136 static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll)
0137 {
0138     struct ps2dev *ps2dev = &psmouse->ps2dev;
0139     u8 param[4];
0140 
0141     ps2pp_cmd(psmouse, param, 0x32);
0142 
0143     param[0] = 0;
0144     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
0145     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
0146     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
0147 
0148     param[0] = smartscroll;
0149     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
0150 }
0151 
0152 static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse,
0153                        void *data, char *buf)
0154 {
0155     return sprintf(buf, "%d\n", psmouse->smartscroll);
0156 }
0157 
0158 static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data,
0159                       const char *buf, size_t count)
0160 {
0161     unsigned int value;
0162     int err;
0163 
0164     err = kstrtouint(buf, 10, &value);
0165     if (err)
0166         return err;
0167 
0168     if (value > 1)
0169         return -EINVAL;
0170 
0171     ps2pp_set_smartscroll(psmouse, value);
0172     psmouse->smartscroll = value;
0173     return count;
0174 }
0175 
0176 PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL,
0177             ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll);
0178 
0179 /*
0180  * Support 800 dpi resolution _only_ if the user wants it (there are good
0181  * reasons to not use it even if the mouse supports it, and of course there are
0182  * also good reasons to use it, let the user decide).
0183  */
0184 
0185 static void ps2pp_set_resolution(struct psmouse *psmouse,
0186                  unsigned int resolution)
0187 {
0188     if (resolution > 400) {
0189         struct ps2dev *ps2dev = &psmouse->ps2dev;
0190         u8 param = 3;
0191 
0192         ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
0193         ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
0194         ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
0195         ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
0196         psmouse->resolution = 800;
0197     } else
0198         psmouse_set_resolution(psmouse, resolution);
0199 }
0200 
0201 static void ps2pp_disconnect(struct psmouse *psmouse)
0202 {
0203     device_remove_file(&psmouse->ps2dev.serio->dev,
0204                &psmouse_attr_smartscroll.dattr);
0205 }
0206 
0207 static const struct ps2pp_info *get_model_info(unsigned char model)
0208 {
0209     static const struct ps2pp_info ps2pp_list[] = {
0210         {  1,   0,          0 },    /* Simple 2-button mouse */
0211         { 12,   0,          PS2PP_SIDE_BTN},
0212         { 13,   0,          0 },
0213         { 15,   PS2PP_KIND_MX,                  /* MX1000 */
0214                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
0215                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
0216         { 40,   0,          PS2PP_SIDE_BTN },
0217         { 41,   0,          PS2PP_SIDE_BTN },
0218         { 42,   0,          PS2PP_SIDE_BTN },
0219         { 43,   0,          PS2PP_SIDE_BTN },
0220         { 50,   0,          0 },
0221         { 51,   0,          0 },
0222         { 52,   PS2PP_KIND_WHEEL,   PS2PP_SIDE_BTN | PS2PP_WHEEL },
0223         { 53,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0224         { 56,   PS2PP_KIND_WHEEL,   PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
0225         { 61,   PS2PP_KIND_MX,                  /* MX700 */
0226                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
0227                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
0228         { 66,   PS2PP_KIND_MX,                  /* MX3100 receiver */
0229                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
0230                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL },
0231         { 72,   PS2PP_KIND_TRACKMAN,    0 },            /* T-CH11: TrackMan Marble */
0232         { 73,   PS2PP_KIND_TRACKMAN,    PS2PP_SIDE_BTN },   /* TrackMan FX */
0233         { 75,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0234         { 76,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0235         { 79,   PS2PP_KIND_TRACKMAN,    PS2PP_WHEEL },      /* TrackMan with wheel */
0236         { 80,   PS2PP_KIND_WHEEL,   PS2PP_SIDE_BTN | PS2PP_WHEEL },
0237         { 81,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0238         { 83,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0239         { 85,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0240         { 86,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0241         { 87,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0242         { 88,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0243         { 96,   0,          0 },
0244         { 97,   PS2PP_KIND_TP3,     PS2PP_WHEEL | PS2PP_HWHEEL },
0245         { 99,   PS2PP_KIND_WHEEL,   PS2PP_WHEEL },
0246         { 100,  PS2PP_KIND_MX,                  /* MX510 */
0247                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
0248                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
0249         { 111,  PS2PP_KIND_MX,  PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
0250         { 112,  PS2PP_KIND_MX,                  /* MX500 */
0251                 PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
0252                 PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
0253         { 114,  PS2PP_KIND_MX,                  /* MX310 */
0254                 PS2PP_WHEEL | PS2PP_SIDE_BTN |
0255                 PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
0256     };
0257     int i;
0258 
0259     for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
0260         if (model == ps2pp_list[i].model)
0261             return &ps2pp_list[i];
0262 
0263     return NULL;
0264 }
0265 
0266 /*
0267  * Set up input device's properties based on the detected mouse model.
0268  */
0269 
0270 static void ps2pp_set_model_properties(struct psmouse *psmouse,
0271                        const struct ps2pp_info *model_info,
0272                        bool using_ps2pp)
0273 {
0274     struct input_dev *input_dev = psmouse->dev;
0275 
0276     if (model_info->features & PS2PP_SIDE_BTN)
0277         input_set_capability(input_dev, EV_KEY, BTN_SIDE);
0278 
0279     if (model_info->features & PS2PP_EXTRA_BTN)
0280         input_set_capability(input_dev, EV_KEY, BTN_EXTRA);
0281 
0282     if (model_info->features & PS2PP_TASK_BTN)
0283         input_set_capability(input_dev, EV_KEY, BTN_TASK);
0284 
0285     if (model_info->features & PS2PP_NAV_BTN) {
0286         input_set_capability(input_dev, EV_KEY, BTN_FORWARD);
0287         input_set_capability(input_dev, EV_KEY, BTN_BACK);
0288     }
0289 
0290     if (model_info->features & PS2PP_WHEEL)
0291         input_set_capability(input_dev, EV_REL, REL_WHEEL);
0292 
0293     if (model_info->features & PS2PP_HWHEEL)
0294         input_set_capability(input_dev, EV_REL, REL_HWHEEL);
0295 
0296     switch (model_info->kind) {
0297 
0298     case PS2PP_KIND_WHEEL:
0299         psmouse->name = "Wheel Mouse";
0300         break;
0301 
0302     case PS2PP_KIND_MX:
0303         psmouse->name = "MX Mouse";
0304         break;
0305 
0306     case PS2PP_KIND_TP3:
0307         psmouse->name = "TouchPad 3";
0308         break;
0309 
0310     case PS2PP_KIND_TRACKMAN:
0311         psmouse->name = "TrackMan";
0312         break;
0313 
0314     default:
0315         /*
0316          * Set name to "Mouse" only when using PS2++,
0317          * otherwise let other protocols define suitable
0318          * name
0319          */
0320         if (using_ps2pp)
0321             psmouse->name = "Mouse";
0322         break;
0323     }
0324 }
0325 
0326 static int ps2pp_setup_protocol(struct psmouse *psmouse,
0327                 const struct ps2pp_info *model_info)
0328 {
0329     int error;
0330 
0331     psmouse->protocol_handler = ps2pp_process_byte;
0332     psmouse->pktsize = 3;
0333 
0334     if (model_info->kind != PS2PP_KIND_TP3) {
0335         psmouse->set_resolution = ps2pp_set_resolution;
0336         psmouse->disconnect = ps2pp_disconnect;
0337 
0338         error = device_create_file(&psmouse->ps2dev.serio->dev,
0339                        &psmouse_attr_smartscroll.dattr);
0340         if (error) {
0341             psmouse_err(psmouse,
0342                     "failed to create smartscroll sysfs attribute, error: %d\n",
0343                     error);
0344             return error;
0345         }
0346     }
0347 
0348     return 0;
0349 }
0350 
0351 /*
0352  * Logitech magic init. Detect whether the mouse is a Logitech one
0353  * and its exact model and try turning on extended protocol for ones
0354  * that support it.
0355  */
0356 
0357 int ps2pp_detect(struct psmouse *psmouse, bool set_properties)
0358 {
0359     struct ps2dev *ps2dev = &psmouse->ps2dev;
0360     const struct ps2pp_info *model_info;
0361     u8 param[4];
0362     u8 model, buttons;
0363     bool use_ps2pp = false;
0364     int error;
0365 
0366     param[0] = 0;
0367     ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
0368     ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
0369     ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
0370     ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11);
0371     param[1] = 0;
0372     ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
0373 
0374     model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
0375     buttons = param[1];
0376 
0377     if (!model || !buttons)
0378         return -ENXIO;
0379 
0380     model_info = get_model_info(model);
0381     if (model_info) {
0382 
0383 /*
0384  * Do Logitech PS2++ / PS2T++ magic init.
0385  */
0386         if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
0387 
0388             /* Unprotect RAM */
0389             param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
0390             ps2_command(ps2dev, param, 0x30d1);
0391             /* Enable features */
0392             param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
0393             ps2_command(ps2dev, param, 0x30d1);
0394             /* Enable PS2++ */
0395             param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
0396             ps2_command(ps2dev, param, 0x30d1);
0397 
0398             param[0] = 0;
0399             if (!ps2_command(ps2dev, param, 0x13d1) &&
0400                 param[0] == 0x06 && param[1] == 0x00 &&
0401                 param[2] == 0x14) {
0402                 use_ps2pp = true;
0403             }
0404 
0405         } else {
0406 
0407             param[0] = param[1] = param[2] = 0;
0408             ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
0409             ps2pp_cmd(psmouse, param, 0xDB);
0410 
0411             if ((param[0] & 0x78) == 0x48 &&
0412                 (param[1] & 0xf3) == 0xc2 &&
0413                 (param[2] & 0x03) == ((param[1] >> 2) & 3)) {
0414                 ps2pp_set_smartscroll(psmouse, false);
0415                 use_ps2pp = true;
0416             }
0417         }
0418 
0419     } else {
0420         psmouse_warn(psmouse,
0421                  "Detected unknown Logitech mouse model %d\n",
0422                  model);
0423     }
0424 
0425     if (set_properties) {
0426         psmouse->vendor = "Logitech";
0427         psmouse->model = model;
0428 
0429         if (use_ps2pp) {
0430             error = ps2pp_setup_protocol(psmouse, model_info);
0431             if (error)
0432                 return error;
0433         }
0434 
0435         if (buttons >= 3)
0436             input_set_capability(psmouse->dev, EV_KEY, BTN_MIDDLE);
0437 
0438         if (model_info)
0439             ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
0440     }
0441 
0442     return use_ps2pp ? 0 : -ENXIO;
0443 }
0444