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