root/drivers/input/mouse/vmmouse.c

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

DEFINITIONS

This source file includes following definitions.
  1. vmmouse_report_button
  2. vmmouse_report_events
  3. vmmouse_process_byte
  4. vmmouse_disable
  5. vmmouse_enable
  6. vmmouse_check_hypervisor
  7. vmmouse_detect
  8. vmmouse_disconnect
  9. vmmouse_reconnect
  10. vmmouse_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors.
   4  *
   5  * Copyright (C) 2014, VMware, Inc. All Rights Reserved.
   6  *
   7  * Twin device code is hugely inspired by the ALPS driver.
   8  * Authors:
   9  *   Dmitry Torokhov <dmitry.torokhov@gmail.com>
  10  *   Thomas Hellstrom <thellstrom@vmware.com>
  11  */
  12 
  13 #include <linux/input.h>
  14 #include <linux/serio.h>
  15 #include <linux/libps2.h>
  16 #include <linux/slab.h>
  17 #include <linux/module.h>
  18 #include <asm/hypervisor.h>
  19 #include <asm/vmware.h>
  20 
  21 #include "psmouse.h"
  22 #include "vmmouse.h"
  23 
  24 #define VMMOUSE_PROTO_MAGIC                     0x564D5868U
  25 
  26 /*
  27  * Main commands supported by the vmmouse hypervisor port.
  28  */
  29 #define VMMOUSE_PROTO_CMD_GETVERSION            10
  30 #define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA       39
  31 #define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS     40
  32 #define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND    41
  33 #define VMMOUSE_PROTO_CMD_ABSPOINTER_RESTRICT   86
  34 
  35 /*
  36  * Subcommands for VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND
  37  */
  38 #define VMMOUSE_CMD_ENABLE                      0x45414552U
  39 #define VMMOUSE_CMD_DISABLE                     0x000000f5U
  40 #define VMMOUSE_CMD_REQUEST_RELATIVE            0x4c455252U
  41 #define VMMOUSE_CMD_REQUEST_ABSOLUTE            0x53424152U
  42 
  43 #define VMMOUSE_ERROR                           0xffff0000U
  44 
  45 #define VMMOUSE_VERSION_ID                      0x3442554aU
  46 
  47 #define VMMOUSE_RELATIVE_PACKET                 0x00010000U
  48 
  49 #define VMMOUSE_LEFT_BUTTON                     0x20
  50 #define VMMOUSE_RIGHT_BUTTON                    0x10
  51 #define VMMOUSE_MIDDLE_BUTTON                   0x08
  52 
  53 /*
  54  * VMMouse Restrict command
  55  */
  56 #define VMMOUSE_RESTRICT_ANY                    0x00
  57 #define VMMOUSE_RESTRICT_CPL0                   0x01
  58 #define VMMOUSE_RESTRICT_IOPL                   0x02
  59 
  60 #define VMMOUSE_MAX_X                           0xFFFF
  61 #define VMMOUSE_MAX_Y                           0xFFFF
  62 
  63 #define VMMOUSE_VENDOR "VMware"
  64 #define VMMOUSE_NAME   "VMMouse"
  65 
  66 /**
  67  * struct vmmouse_data - private data structure for the vmmouse driver
  68  *
  69  * @abs_dev: "Absolute" device used to report absolute mouse movement.
  70  * @phys: Physical path for the absolute device.
  71  * @dev_name: Name attribute name for the absolute device.
  72  */
  73 struct vmmouse_data {
  74         struct input_dev *abs_dev;
  75         char phys[32];
  76         char dev_name[128];
  77 };
  78 
  79 /**
  80  * Hypervisor-specific bi-directional communication channel
  81  * implementing the vmmouse protocol. Should never execute on
  82  * bare metal hardware.
  83  */
  84 #define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4)   \
  85 ({                                                      \
  86         unsigned long __dummy1, __dummy2;               \
  87         __asm__ __volatile__ (VMWARE_HYPERCALL :        \
  88                 "=a"(out1),                             \
  89                 "=b"(out2),                             \
  90                 "=c"(out3),                             \
  91                 "=d"(out4),                             \
  92                 "=S"(__dummy1),                         \
  93                 "=D"(__dummy2) :                        \
  94                 "a"(VMMOUSE_PROTO_MAGIC),               \
  95                 "b"(in1),                               \
  96                 "c"(VMMOUSE_PROTO_CMD_##cmd),           \
  97                 "d"(0) :                                \
  98                 "memory");                              \
  99 })
 100 
 101 /**
 102  * vmmouse_report_button - report button state on the correct input device
 103  *
 104  * @psmouse:  Pointer to the psmouse struct
 105  * @abs_dev:  The absolute input device
 106  * @rel_dev:  The relative input device
 107  * @pref_dev: The preferred device for reporting
 108  * @code:     Button code
 109  * @value:    Button value
 110  *
 111  * Report @value and @code on @pref_dev, unless the button is already
 112  * pressed on the other device, in which case the state is reported on that
 113  * device.
 114  */
 115 static void vmmouse_report_button(struct psmouse *psmouse,
 116                                   struct input_dev *abs_dev,
 117                                   struct input_dev *rel_dev,
 118                                   struct input_dev *pref_dev,
 119                                   unsigned int code, int value)
 120 {
 121         if (test_bit(code, abs_dev->key))
 122                 pref_dev = abs_dev;
 123         else if (test_bit(code, rel_dev->key))
 124                 pref_dev = rel_dev;
 125 
 126         input_report_key(pref_dev, code, value);
 127 }
 128 
 129 /**
 130  * vmmouse_report_events - process events on the vmmouse communications channel
 131  *
 132  * @psmouse: Pointer to the psmouse struct
 133  *
 134  * This function pulls events from the vmmouse communications channel and
 135  * reports them on the correct (absolute or relative) input device. When the
 136  * communications channel is drained, or if we've processed more than 255
 137  * psmouse commands, the function returns PSMOUSE_FULL_PACKET. If there is a
 138  * host- or synchronization error, the function returns PSMOUSE_BAD_DATA in
 139  * the hope that the caller will reset the communications channel.
 140  */
 141 static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
 142 {
 143         struct input_dev *rel_dev = psmouse->dev;
 144         struct vmmouse_data *priv = psmouse->private;
 145         struct input_dev *abs_dev = priv->abs_dev;
 146         struct input_dev *pref_dev;
 147         u32 status, x, y, z;
 148         u32 dummy1, dummy2, dummy3;
 149         unsigned int queue_length;
 150         unsigned int count = 255;
 151 
 152         while (count--) {
 153                 /* See if we have motion data. */
 154                 VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
 155                             status, dummy1, dummy2, dummy3);
 156                 if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
 157                         psmouse_err(psmouse, "failed to fetch status data\n");
 158                         /*
 159                          * After a few attempts this will result in
 160                          * reconnect.
 161                          */
 162                         return PSMOUSE_BAD_DATA;
 163                 }
 164 
 165                 queue_length = status & 0xffff;
 166                 if (queue_length == 0)
 167                         break;
 168 
 169                 if (queue_length % 4) {
 170                         psmouse_err(psmouse, "invalid queue length\n");
 171                         return PSMOUSE_BAD_DATA;
 172                 }
 173 
 174                 /* Now get it */
 175                 VMMOUSE_CMD(ABSPOINTER_DATA, 4, status, x, y, z);
 176 
 177                 /*
 178                  * And report what we've got. Prefer to report button
 179                  * events on the same device where we report motion events.
 180                  * This doesn't work well with the mouse wheel, though. See
 181                  * below. Ideally we would want to report that on the
 182                  * preferred device as well.
 183                  */
 184                 if (status & VMMOUSE_RELATIVE_PACKET) {
 185                         pref_dev = rel_dev;
 186                         input_report_rel(rel_dev, REL_X, (s32)x);
 187                         input_report_rel(rel_dev, REL_Y, -(s32)y);
 188                 } else {
 189                         pref_dev = abs_dev;
 190                         input_report_abs(abs_dev, ABS_X, x);
 191                         input_report_abs(abs_dev, ABS_Y, y);
 192                 }
 193 
 194                 /* Xorg seems to ignore wheel events on absolute devices */
 195                 input_report_rel(rel_dev, REL_WHEEL, -(s8)((u8) z));
 196 
 197                 vmmouse_report_button(psmouse, abs_dev, rel_dev,
 198                                       pref_dev, BTN_LEFT,
 199                                       status & VMMOUSE_LEFT_BUTTON);
 200                 vmmouse_report_button(psmouse, abs_dev, rel_dev,
 201                                       pref_dev, BTN_RIGHT,
 202                                       status & VMMOUSE_RIGHT_BUTTON);
 203                 vmmouse_report_button(psmouse, abs_dev, rel_dev,
 204                                       pref_dev, BTN_MIDDLE,
 205                                       status & VMMOUSE_MIDDLE_BUTTON);
 206                 input_sync(abs_dev);
 207                 input_sync(rel_dev);
 208         }
 209 
 210         return PSMOUSE_FULL_PACKET;
 211 }
 212 
 213 /**
 214  * vmmouse_process_byte - process data on the ps/2 channel
 215  *
 216  * @psmouse: Pointer to the psmouse struct
 217  *
 218  * When the ps/2 channel indicates that there is vmmouse data available,
 219  * call vmmouse channel processing. Otherwise, continue to accept bytes. If
 220  * there is a synchronization or communication data error, return
 221  * PSMOUSE_BAD_DATA in the hope that the caller will reset the mouse.
 222  */
 223 static psmouse_ret_t vmmouse_process_byte(struct psmouse *psmouse)
 224 {
 225         unsigned char *packet = psmouse->packet;
 226 
 227         switch (psmouse->pktcnt) {
 228         case 1:
 229                 return (packet[0] & 0x8) == 0x8 ?
 230                         PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
 231 
 232         case 2:
 233                 return PSMOUSE_GOOD_DATA;
 234 
 235         default:
 236                 return vmmouse_report_events(psmouse);
 237         }
 238 }
 239 
 240 /**
 241  * vmmouse_disable - Disable vmmouse
 242  *
 243  * @psmouse: Pointer to the psmouse struct
 244  *
 245  * Tries to disable vmmouse mode.
 246  */
 247 static void vmmouse_disable(struct psmouse *psmouse)
 248 {
 249         u32 status;
 250         u32 dummy1, dummy2, dummy3, dummy4;
 251 
 252         VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE,
 253                     dummy1, dummy2, dummy3, dummy4);
 254 
 255         VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
 256                     status, dummy1, dummy2, dummy3);
 257 
 258         if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR)
 259                 psmouse_warn(psmouse, "failed to disable vmmouse device\n");
 260 }
 261 
 262 /**
 263  * vmmouse_enable - Enable vmmouse and request absolute mode.
 264  *
 265  * @psmouse: Pointer to the psmouse struct
 266  *
 267  * Tries to enable vmmouse mode. Performs basic checks and requests
 268  * absolute vmmouse mode.
 269  * Returns 0 on success, -ENODEV on failure.
 270  */
 271 static int vmmouse_enable(struct psmouse *psmouse)
 272 {
 273         u32 status, version;
 274         u32 dummy1, dummy2, dummy3, dummy4;
 275 
 276         /*
 277          * Try enabling the device. If successful, we should be able to
 278          * read valid version ID back from it.
 279          */
 280         VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE,
 281                     dummy1, dummy2, dummy3, dummy4);
 282 
 283         /*
 284          * See if version ID can be retrieved.
 285          */
 286         VMMOUSE_CMD(ABSPOINTER_STATUS, 0, status, dummy1, dummy2, dummy3);
 287         if ((status & 0x0000ffff) == 0) {
 288                 psmouse_dbg(psmouse, "empty flags - assuming no device\n");
 289                 return -ENXIO;
 290         }
 291 
 292         VMMOUSE_CMD(ABSPOINTER_DATA, 1 /* single item */,
 293                     version, dummy1, dummy2, dummy3);
 294         if (version != VMMOUSE_VERSION_ID) {
 295                 psmouse_dbg(psmouse, "Unexpected version value: %u vs %u\n",
 296                             (unsigned) version, VMMOUSE_VERSION_ID);
 297                 vmmouse_disable(psmouse);
 298                 return -ENXIO;
 299         }
 300 
 301         /*
 302          * Restrict ioport access, if possible.
 303          */
 304         VMMOUSE_CMD(ABSPOINTER_RESTRICT, VMMOUSE_RESTRICT_CPL0,
 305                     dummy1, dummy2, dummy3, dummy4);
 306 
 307         VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_REQUEST_ABSOLUTE,
 308                     dummy1, dummy2, dummy3, dummy4);
 309 
 310         return 0;
 311 }
 312 
 313 /*
 314  * Array of supported hypervisors.
 315  */
 316 static enum x86_hypervisor_type vmmouse_supported_hypervisors[] = {
 317         X86_HYPER_VMWARE,
 318         X86_HYPER_KVM,
 319 };
 320 
 321 /**
 322  * vmmouse_check_hypervisor - Check if we're running on a supported hypervisor
 323  */
 324 static bool vmmouse_check_hypervisor(void)
 325 {
 326         int i;
 327 
 328         for (i = 0; i < ARRAY_SIZE(vmmouse_supported_hypervisors); i++)
 329                 if (vmmouse_supported_hypervisors[i] == x86_hyper_type)
 330                         return true;
 331 
 332         return false;
 333 }
 334 
 335 /**
 336  * vmmouse_detect - Probe whether vmmouse is available
 337  *
 338  * @psmouse: Pointer to the psmouse struct
 339  * @set_properties: Whether to set psmouse name and vendor
 340  *
 341  * Returns 0 if vmmouse channel is available. Negative error code if not.
 342  */
 343 int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
 344 {
 345         u32 response, version, dummy1, dummy2;
 346 
 347         if (!vmmouse_check_hypervisor()) {
 348                 psmouse_dbg(psmouse,
 349                             "VMMouse not running on supported hypervisor.\n");
 350                 return -ENXIO;
 351         }
 352 
 353         /* Check if the device is present */
 354         response = ~VMMOUSE_PROTO_MAGIC;
 355         VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
 356         if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
 357                 return -ENXIO;
 358 
 359         if (set_properties) {
 360                 psmouse->vendor = VMMOUSE_VENDOR;
 361                 psmouse->name = VMMOUSE_NAME;
 362                 psmouse->model = version;
 363         }
 364 
 365         return 0;
 366 }
 367 
 368 /**
 369  * vmmouse_disconnect - Take down vmmouse driver
 370  *
 371  * @psmouse: Pointer to the psmouse struct
 372  *
 373  * Takes down vmmouse driver and frees resources set up in vmmouse_init().
 374  */
 375 static void vmmouse_disconnect(struct psmouse *psmouse)
 376 {
 377         struct vmmouse_data *priv = psmouse->private;
 378 
 379         vmmouse_disable(psmouse);
 380         psmouse_reset(psmouse);
 381         input_unregister_device(priv->abs_dev);
 382         kfree(priv);
 383 }
 384 
 385 /**
 386  * vmmouse_reconnect - Reset the ps/2 - and vmmouse connections
 387  *
 388  * @psmouse: Pointer to the psmouse struct
 389  *
 390  * Attempts to reset the mouse connections. Returns 0 on success and
 391  * -1 on failure.
 392  */
 393 static int vmmouse_reconnect(struct psmouse *psmouse)
 394 {
 395         int error;
 396 
 397         psmouse_reset(psmouse);
 398         vmmouse_disable(psmouse);
 399         error = vmmouse_enable(psmouse);
 400         if (error) {
 401                 psmouse_err(psmouse,
 402                             "Unable to re-enable mouse when reconnecting, err: %d\n",
 403                             error);
 404                 return error;
 405         }
 406 
 407         return 0;
 408 }
 409 
 410 /**
 411  * vmmouse_init - Initialize the vmmouse driver
 412  *
 413  * @psmouse: Pointer to the psmouse struct
 414  *
 415  * Requests the device and tries to enable vmmouse mode.
 416  * If successful, sets up the input device for relative movement events.
 417  * It also allocates another input device and sets it up for absolute motion
 418  * events. Returns 0 on success and -1 on failure.
 419  */
 420 int vmmouse_init(struct psmouse *psmouse)
 421 {
 422         struct vmmouse_data *priv;
 423         struct input_dev *rel_dev = psmouse->dev, *abs_dev;
 424         int error;
 425 
 426         psmouse_reset(psmouse);
 427         error = vmmouse_enable(psmouse);
 428         if (error)
 429                 return error;
 430 
 431         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 432         abs_dev = input_allocate_device();
 433         if (!priv || !abs_dev) {
 434                 error = -ENOMEM;
 435                 goto init_fail;
 436         }
 437 
 438         priv->abs_dev = abs_dev;
 439         psmouse->private = priv;
 440 
 441         /* Set up and register absolute device */
 442         snprintf(priv->phys, sizeof(priv->phys), "%s/input1",
 443                  psmouse->ps2dev.serio->phys);
 444 
 445         /* Mimic name setup for relative device in psmouse-base.c */
 446         snprintf(priv->dev_name, sizeof(priv->dev_name), "%s %s %s",
 447                  VMMOUSE_PSNAME, VMMOUSE_VENDOR, VMMOUSE_NAME);
 448         abs_dev->phys = priv->phys;
 449         abs_dev->name = priv->dev_name;
 450         abs_dev->id.bustype = BUS_I8042;
 451         abs_dev->id.vendor = 0x0002;
 452         abs_dev->id.product = PSMOUSE_VMMOUSE;
 453         abs_dev->id.version = psmouse->model;
 454         abs_dev->dev.parent = &psmouse->ps2dev.serio->dev;
 455 
 456         /* Set absolute device capabilities */
 457         input_set_capability(abs_dev, EV_KEY, BTN_LEFT);
 458         input_set_capability(abs_dev, EV_KEY, BTN_RIGHT);
 459         input_set_capability(abs_dev, EV_KEY, BTN_MIDDLE);
 460         input_set_capability(abs_dev, EV_ABS, ABS_X);
 461         input_set_capability(abs_dev, EV_ABS, ABS_Y);
 462         input_set_abs_params(abs_dev, ABS_X, 0, VMMOUSE_MAX_X, 0, 0);
 463         input_set_abs_params(abs_dev, ABS_Y, 0, VMMOUSE_MAX_Y, 0, 0);
 464 
 465         error = input_register_device(priv->abs_dev);
 466         if (error)
 467                 goto init_fail;
 468 
 469         /* Add wheel capability to the relative device */
 470         input_set_capability(rel_dev, EV_REL, REL_WHEEL);
 471 
 472         psmouse->protocol_handler = vmmouse_process_byte;
 473         psmouse->disconnect = vmmouse_disconnect;
 474         psmouse->reconnect = vmmouse_reconnect;
 475 
 476         return 0;
 477 
 478 init_fail:
 479         vmmouse_disable(psmouse);
 480         psmouse_reset(psmouse);
 481         input_free_device(abs_dev);
 482         kfree(priv);
 483         psmouse->private = NULL;
 484 
 485         return error;
 486 }

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