linux/drivers/hid/hid-hyperv.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  Copyright (c) 2009, Citrix Systems, Inc.
   4 *  Copyright (c) 2010, Microsoft Corporation.
   5 *  Copyright (c) 2011, Novell Inc.
   6 */
   7#include <linux/init.h>
   8#include <linux/module.h>
   9#include <linux/device.h>
  10#include <linux/completion.h>
  11#include <linux/input.h>
  12#include <linux/hid.h>
  13#include <linux/hiddev.h>
  14#include <linux/hyperv.h>
  15
  16
  17struct hv_input_dev_info {
  18        unsigned int size;
  19        unsigned short vendor;
  20        unsigned short product;
  21        unsigned short version;
  22        unsigned short reserved[11];
  23};
  24
  25/* The maximum size of a synthetic input message. */
  26#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
  27
  28/*
  29 * Current version
  30 *
  31 * History:
  32 * Beta, RC < 2008/1/22        1,0
  33 * RC > 2008/1/22              2,0
  34 */
  35#define SYNTHHID_INPUT_VERSION_MAJOR    2
  36#define SYNTHHID_INPUT_VERSION_MINOR    0
  37#define SYNTHHID_INPUT_VERSION          (SYNTHHID_INPUT_VERSION_MINOR | \
  38                                         (SYNTHHID_INPUT_VERSION_MAJOR << 16))
  39
  40
  41#pragma pack(push, 1)
  42/*
  43 * Message types in the synthetic input protocol
  44 */
  45enum synthhid_msg_type {
  46        SYNTH_HID_PROTOCOL_REQUEST,
  47        SYNTH_HID_PROTOCOL_RESPONSE,
  48        SYNTH_HID_INITIAL_DEVICE_INFO,
  49        SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
  50        SYNTH_HID_INPUT_REPORT,
  51        SYNTH_HID_MAX
  52};
  53
  54/*
  55 * Basic message structures.
  56 */
  57struct synthhid_msg_hdr {
  58        enum synthhid_msg_type type;
  59        u32 size;
  60};
  61
  62struct synthhid_msg {
  63        struct synthhid_msg_hdr header;
  64        char data[1]; /* Enclosed message */
  65};
  66
  67union synthhid_version {
  68        struct {
  69                u16 minor_version;
  70                u16 major_version;
  71        };
  72        u32 version;
  73};
  74
  75/*
  76 * Protocol messages
  77 */
  78struct synthhid_protocol_request {
  79        struct synthhid_msg_hdr header;
  80        union synthhid_version version_requested;
  81};
  82
  83struct synthhid_protocol_response {
  84        struct synthhid_msg_hdr header;
  85        union synthhid_version version_requested;
  86        unsigned char approved;
  87};
  88
  89struct synthhid_device_info {
  90        struct synthhid_msg_hdr header;
  91        struct hv_input_dev_info hid_dev_info;
  92        struct hid_descriptor hid_descriptor;
  93};
  94
  95struct synthhid_device_info_ack {
  96        struct synthhid_msg_hdr header;
  97        unsigned char reserved;
  98};
  99
 100struct synthhid_input_report {
 101        struct synthhid_msg_hdr header;
 102        char buffer[1];
 103};
 104
 105#pragma pack(pop)
 106
 107#define INPUTVSC_SEND_RING_BUFFER_SIZE          (10*PAGE_SIZE)
 108#define INPUTVSC_RECV_RING_BUFFER_SIZE          (10*PAGE_SIZE)
 109
 110
 111enum pipe_prot_msg_type {
 112        PIPE_MESSAGE_INVALID,
 113        PIPE_MESSAGE_DATA,
 114        PIPE_MESSAGE_MAXIMUM
 115};
 116
 117
 118struct pipe_prt_msg {
 119        enum pipe_prot_msg_type type;
 120        u32 size;
 121        char data[1];
 122};
 123
 124struct  mousevsc_prt_msg {
 125        enum pipe_prot_msg_type type;
 126        u32 size;
 127        union {
 128                struct synthhid_protocol_request request;
 129                struct synthhid_protocol_response response;
 130                struct synthhid_device_info_ack ack;
 131        };
 132};
 133
 134/*
 135 * Represents an mousevsc device
 136 */
 137struct mousevsc_dev {
 138        struct hv_device        *device;
 139        bool                    init_complete;
 140        bool                    connected;
 141        struct mousevsc_prt_msg protocol_req;
 142        struct mousevsc_prt_msg protocol_resp;
 143        /* Synchronize the request/response if needed */
 144        struct completion       wait_event;
 145        int                     dev_info_status;
 146
 147        struct hid_descriptor   *hid_desc;
 148        unsigned char           *report_desc;
 149        u32                     report_desc_size;
 150        struct hv_input_dev_info hid_dev_info;
 151        struct hid_device       *hid_device;
 152        u8                      input_buf[HID_MAX_BUFFER_SIZE];
 153};
 154
 155
 156static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)
 157{
 158        struct mousevsc_dev *input_dev;
 159
 160        input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
 161
 162        if (!input_dev)
 163                return NULL;
 164
 165        input_dev->device = device;
 166        hv_set_drvdata(device, input_dev);
 167        init_completion(&input_dev->wait_event);
 168        input_dev->init_complete = false;
 169
 170        return input_dev;
 171}
 172
 173static void mousevsc_free_device(struct mousevsc_dev *device)
 174{
 175        kfree(device->hid_desc);
 176        kfree(device->report_desc);
 177        hv_set_drvdata(device->device, NULL);
 178        kfree(device);
 179}
 180
 181static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
 182                                struct synthhid_device_info *device_info)
 183{
 184        int ret = 0;
 185        struct hid_descriptor *desc;
 186        struct mousevsc_prt_msg ack;
 187
 188        input_device->dev_info_status = -ENOMEM;
 189
 190        input_device->hid_dev_info = device_info->hid_dev_info;
 191        desc = &device_info->hid_descriptor;
 192        if (desc->bLength == 0)
 193                goto cleanup;
 194
 195        input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
 196
 197        if (!input_device->hid_desc)
 198                goto cleanup;
 199
 200        input_device->report_desc_size = desc->desc[0].wDescriptorLength;
 201        if (input_device->report_desc_size == 0) {
 202                input_device->dev_info_status = -EINVAL;
 203                goto cleanup;
 204        }
 205
 206        input_device->report_desc = kzalloc(input_device->report_desc_size,
 207                                          GFP_ATOMIC);
 208
 209        if (!input_device->report_desc) {
 210                input_device->dev_info_status = -ENOMEM;
 211                goto cleanup;
 212        }
 213
 214        memcpy(input_device->report_desc,
 215               ((unsigned char *)desc) + desc->bLength,
 216               desc->desc[0].wDescriptorLength);
 217
 218        /* Send the ack */
 219        memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
 220
 221        ack.type = PIPE_MESSAGE_DATA;
 222        ack.size = sizeof(struct synthhid_device_info_ack);
 223
 224        ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
 225        ack.ack.header.size = 1;
 226        ack.ack.reserved = 0;
 227
 228        ret = vmbus_sendpacket(input_device->device->channel,
 229                        &ack,
 230                        sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
 231                        sizeof(struct synthhid_device_info_ack),
 232                        (unsigned long)&ack,
 233                        VM_PKT_DATA_INBAND,
 234                        VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 235
 236        if (!ret)
 237                input_device->dev_info_status = 0;
 238
 239cleanup:
 240        complete(&input_device->wait_event);
 241
 242        return;
 243}
 244
 245static void mousevsc_on_receive(struct hv_device *device,
 246                                struct vmpacket_descriptor *packet)
 247{
 248        struct pipe_prt_msg *pipe_msg;
 249        struct synthhid_msg *hid_msg;
 250        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
 251        struct synthhid_input_report *input_report;
 252        size_t len;
 253
 254        pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
 255                                                (packet->offset8 << 3));
 256
 257        if (pipe_msg->type != PIPE_MESSAGE_DATA)
 258                return;
 259
 260        hid_msg = (struct synthhid_msg *)pipe_msg->data;
 261
 262        switch (hid_msg->header.type) {
 263        case SYNTH_HID_PROTOCOL_RESPONSE:
 264                /*
 265                 * While it will be impossible for us to protect against
 266                 * malicious/buggy hypervisor/host, add a check here to
 267                 * ensure we don't corrupt memory.
 268                 */
 269                if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
 270                        - sizeof(unsigned char))
 271                        > sizeof(struct mousevsc_prt_msg)) {
 272                        WARN_ON(1);
 273                        break;
 274                }
 275
 276                memcpy(&input_dev->protocol_resp, pipe_msg,
 277                       pipe_msg->size + sizeof(struct pipe_prt_msg) -
 278                       sizeof(unsigned char));
 279                complete(&input_dev->wait_event);
 280                break;
 281
 282        case SYNTH_HID_INITIAL_DEVICE_INFO:
 283                WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
 284
 285                /*
 286                 * Parse out the device info into device attr,
 287                 * hid desc and report desc
 288                 */
 289                mousevsc_on_receive_device_info(input_dev,
 290                        (struct synthhid_device_info *)pipe_msg->data);
 291                break;
 292        case SYNTH_HID_INPUT_REPORT:
 293                input_report =
 294                        (struct synthhid_input_report *)pipe_msg->data;
 295                if (!input_dev->init_complete)
 296                        break;
 297
 298                len = min(input_report->header.size,
 299                          (u32)sizeof(input_dev->input_buf));
 300                memcpy(input_dev->input_buf, input_report->buffer, len);
 301                hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
 302                                 input_dev->input_buf, len, 1);
 303
 304                pm_wakeup_hard_event(&input_dev->device->device);
 305
 306                break;
 307        default:
 308                pr_err("unsupported hid msg type - type %d len %d\n",
 309                       hid_msg->header.type, hid_msg->header.size);
 310                break;
 311        }
 312
 313}
 314
 315static void mousevsc_on_channel_callback(void *context)
 316{
 317        const int packet_size = 0x100;
 318        int ret;
 319        struct hv_device *device = context;
 320        u32 bytes_recvd;
 321        u64 req_id;
 322        struct vmpacket_descriptor *desc;
 323        unsigned char   *buffer;
 324        int     bufferlen = packet_size;
 325
 326        buffer = kmalloc(bufferlen, GFP_ATOMIC);
 327        if (!buffer)
 328                return;
 329
 330        do {
 331                ret = vmbus_recvpacket_raw(device->channel, buffer,
 332                                        bufferlen, &bytes_recvd, &req_id);
 333
 334                switch (ret) {
 335                case 0:
 336                        if (bytes_recvd <= 0) {
 337                                kfree(buffer);
 338                                return;
 339                        }
 340                        desc = (struct vmpacket_descriptor *)buffer;
 341
 342                        switch (desc->type) {
 343                        case VM_PKT_COMP:
 344                                break;
 345
 346                        case VM_PKT_DATA_INBAND:
 347                                mousevsc_on_receive(device, desc);
 348                                break;
 349
 350                        default:
 351                                pr_err("unhandled packet type %d, tid %llx len %d\n",
 352                                        desc->type, req_id, bytes_recvd);
 353                                break;
 354                        }
 355
 356                        break;
 357
 358                case -ENOBUFS:
 359                        kfree(buffer);
 360                        /* Handle large packet */
 361                        bufferlen = bytes_recvd;
 362                        buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
 363
 364                        if (!buffer)
 365                                return;
 366
 367                        break;
 368                }
 369        } while (1);
 370
 371}
 372
 373static int mousevsc_connect_to_vsp(struct hv_device *device)
 374{
 375        int ret = 0;
 376        unsigned long t;
 377        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
 378        struct mousevsc_prt_msg *request;
 379        struct mousevsc_prt_msg *response;
 380
 381        request = &input_dev->protocol_req;
 382        memset(request, 0, sizeof(struct mousevsc_prt_msg));
 383
 384        request->type = PIPE_MESSAGE_DATA;
 385        request->size = sizeof(struct synthhid_protocol_request);
 386        request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
 387        request->request.header.size = sizeof(unsigned int);
 388        request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
 389
 390        ret = vmbus_sendpacket(device->channel, request,
 391                                sizeof(struct pipe_prt_msg) -
 392                                sizeof(unsigned char) +
 393                                sizeof(struct synthhid_protocol_request),
 394                                (unsigned long)request,
 395                                VM_PKT_DATA_INBAND,
 396                                VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 397        if (ret)
 398                goto cleanup;
 399
 400        t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
 401        if (!t) {
 402                ret = -ETIMEDOUT;
 403                goto cleanup;
 404        }
 405
 406        response = &input_dev->protocol_resp;
 407
 408        if (!response->response.approved) {
 409                pr_err("synthhid protocol request failed (version %d)\n",
 410                       SYNTHHID_INPUT_VERSION);
 411                ret = -ENODEV;
 412                goto cleanup;
 413        }
 414
 415        t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
 416        if (!t) {
 417                ret = -ETIMEDOUT;
 418                goto cleanup;
 419        }
 420
 421        /*
 422         * We should have gotten the device attr, hid desc and report
 423         * desc at this point
 424         */
 425        ret = input_dev->dev_info_status;
 426
 427cleanup:
 428        return ret;
 429}
 430
 431static int mousevsc_hid_parse(struct hid_device *hid)
 432{
 433        struct hv_device *dev = hid_get_drvdata(hid);
 434        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 435
 436        return hid_parse_report(hid, input_dev->report_desc,
 437                                input_dev->report_desc_size);
 438}
 439
 440static int mousevsc_hid_open(struct hid_device *hid)
 441{
 442        return 0;
 443}
 444
 445static int mousevsc_hid_start(struct hid_device *hid)
 446{
 447        return 0;
 448}
 449
 450static void mousevsc_hid_close(struct hid_device *hid)
 451{
 452}
 453
 454static void mousevsc_hid_stop(struct hid_device *hid)
 455{
 456}
 457
 458static int mousevsc_hid_raw_request(struct hid_device *hid,
 459                                    unsigned char report_num,
 460                                    __u8 *buf, size_t len,
 461                                    unsigned char rtype,
 462                                    int reqtype)
 463{
 464        return 0;
 465}
 466
 467static struct hid_ll_driver mousevsc_ll_driver = {
 468        .parse = mousevsc_hid_parse,
 469        .open = mousevsc_hid_open,
 470        .close = mousevsc_hid_close,
 471        .start = mousevsc_hid_start,
 472        .stop = mousevsc_hid_stop,
 473        .raw_request = mousevsc_hid_raw_request,
 474};
 475
 476static struct hid_driver mousevsc_hid_driver;
 477
 478static int mousevsc_probe(struct hv_device *device,
 479                        const struct hv_vmbus_device_id *dev_id)
 480{
 481        int ret;
 482        struct mousevsc_dev *input_dev;
 483        struct hid_device *hid_dev;
 484
 485        input_dev = mousevsc_alloc_device(device);
 486
 487        if (!input_dev)
 488                return -ENOMEM;
 489
 490        ret = vmbus_open(device->channel,
 491                INPUTVSC_SEND_RING_BUFFER_SIZE,
 492                INPUTVSC_RECV_RING_BUFFER_SIZE,
 493                NULL,
 494                0,
 495                mousevsc_on_channel_callback,
 496                device
 497                );
 498
 499        if (ret)
 500                goto probe_err0;
 501
 502        ret = mousevsc_connect_to_vsp(device);
 503
 504        if (ret)
 505                goto probe_err1;
 506
 507        /* workaround SA-167 */
 508        if (input_dev->report_desc[14] == 0x25)
 509                input_dev->report_desc[14] = 0x29;
 510
 511        hid_dev = hid_allocate_device();
 512        if (IS_ERR(hid_dev)) {
 513                ret = PTR_ERR(hid_dev);
 514                goto probe_err1;
 515        }
 516
 517        hid_dev->ll_driver = &mousevsc_ll_driver;
 518        hid_dev->driver = &mousevsc_hid_driver;
 519        hid_dev->bus = BUS_VIRTUAL;
 520        hid_dev->vendor = input_dev->hid_dev_info.vendor;
 521        hid_dev->product = input_dev->hid_dev_info.product;
 522        hid_dev->version = input_dev->hid_dev_info.version;
 523        input_dev->hid_device = hid_dev;
 524
 525        sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
 526
 527        hid_set_drvdata(hid_dev, device);
 528
 529        ret = hid_add_device(hid_dev);
 530        if (ret)
 531                goto probe_err1;
 532
 533
 534        ret = hid_parse(hid_dev);
 535        if (ret) {
 536                hid_err(hid_dev, "parse failed\n");
 537                goto probe_err2;
 538        }
 539
 540        ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
 541
 542        if (ret) {
 543                hid_err(hid_dev, "hw start failed\n");
 544                goto probe_err2;
 545        }
 546
 547        device_init_wakeup(&device->device, true);
 548
 549        input_dev->connected = true;
 550        input_dev->init_complete = true;
 551
 552        return ret;
 553
 554probe_err2:
 555        hid_destroy_device(hid_dev);
 556
 557probe_err1:
 558        vmbus_close(device->channel);
 559
 560probe_err0:
 561        mousevsc_free_device(input_dev);
 562
 563        return ret;
 564}
 565
 566
 567static int mousevsc_remove(struct hv_device *dev)
 568{
 569        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 570
 571        device_init_wakeup(&dev->device, false);
 572        vmbus_close(dev->channel);
 573        hid_hw_stop(input_dev->hid_device);
 574        hid_destroy_device(input_dev->hid_device);
 575        mousevsc_free_device(input_dev);
 576
 577        return 0;
 578}
 579
 580static const struct hv_vmbus_device_id id_table[] = {
 581        /* Mouse guid */
 582        { HV_MOUSE_GUID, },
 583        { },
 584};
 585
 586MODULE_DEVICE_TABLE(vmbus, id_table);
 587
 588static struct  hv_driver mousevsc_drv = {
 589        .name = KBUILD_MODNAME,
 590        .id_table = id_table,
 591        .probe = mousevsc_probe,
 592        .remove = mousevsc_remove,
 593        .driver = {
 594                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 595        },
 596};
 597
 598static int __init mousevsc_init(void)
 599{
 600        return vmbus_driver_register(&mousevsc_drv);
 601}
 602
 603static void __exit mousevsc_exit(void)
 604{
 605        vmbus_driver_unregister(&mousevsc_drv);
 606}
 607
 608MODULE_LICENSE("GPL");
 609MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver");
 610
 611module_init(mousevsc_init);
 612module_exit(mousevsc_exit);
 613