linux/drivers/input/mouse/vmmouse.c
<<
>>
Prefs
   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 */
  73struct 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 */
 115static 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 */
 141static 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 */
 223static 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 */
 247static 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 */
 271static 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 */
 316static 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 */
 324static 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 */
 343int 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 */
 375static 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 */
 393static 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 */
 420int 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
 478init_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}
 487