linux/drivers/hid/hid-hyperv.c
<<
>>
Prefs
   1/*
   2 *  Copyright (c) 2009, Citrix Systems, Inc.
   3 *  Copyright (c) 2010, Microsoft Corporation.
   4 *  Copyright (c) 2011, Novell Inc.
   5 *
   6 *  This program is free software; you can redistribute it and/or modify it
   7 *  under the terms and conditions of the GNU General Public License,
   8 *  version 2, as published by the Free Software Foundation.
   9 *
  10 *  This program is distributed in the hope it will be useful, but WITHOUT
  11 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 *  more details.
  14 */
  15#include <linux/init.h>
  16#include <linux/module.h>
  17#include <linux/device.h>
  18#include <linux/completion.h>
  19#include <linux/input.h>
  20#include <linux/hid.h>
  21#include <linux/hiddev.h>
  22#include <linux/hyperv.h>
  23
  24
  25struct hv_input_dev_info {
  26        unsigned int size;
  27        unsigned short vendor;
  28        unsigned short product;
  29        unsigned short version;
  30        unsigned short reserved[11];
  31};
  32
  33/* The maximum size of a synthetic input message. */
  34#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
  35
  36/*
  37 * Current version
  38 *
  39 * History:
  40 * Beta, RC < 2008/1/22        1,0
  41 * RC > 2008/1/22              2,0
  42 */
  43#define SYNTHHID_INPUT_VERSION_MAJOR    2
  44#define SYNTHHID_INPUT_VERSION_MINOR    0
  45#define SYNTHHID_INPUT_VERSION          (SYNTHHID_INPUT_VERSION_MINOR | \
  46                                         (SYNTHHID_INPUT_VERSION_MAJOR << 16))
  47
  48
  49#pragma pack(push, 1)
  50/*
  51 * Message types in the synthetic input protocol
  52 */
  53enum synthhid_msg_type {
  54        SYNTH_HID_PROTOCOL_REQUEST,
  55        SYNTH_HID_PROTOCOL_RESPONSE,
  56        SYNTH_HID_INITIAL_DEVICE_INFO,
  57        SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
  58        SYNTH_HID_INPUT_REPORT,
  59        SYNTH_HID_MAX
  60};
  61
  62/*
  63 * Basic message structures.
  64 */
  65struct synthhid_msg_hdr {
  66        enum synthhid_msg_type type;
  67        u32 size;
  68};
  69
  70struct synthhid_msg {
  71        struct synthhid_msg_hdr header;
  72        char data[1]; /* Enclosed message */
  73};
  74
  75union synthhid_version {
  76        struct {
  77                u16 minor_version;
  78                u16 major_version;
  79        };
  80        u32 version;
  81};
  82
  83/*
  84 * Protocol messages
  85 */
  86struct synthhid_protocol_request {
  87        struct synthhid_msg_hdr header;
  88        union synthhid_version version_requested;
  89};
  90
  91struct synthhid_protocol_response {
  92        struct synthhid_msg_hdr header;
  93        union synthhid_version version_requested;
  94        unsigned char approved;
  95};
  96
  97struct synthhid_device_info {
  98        struct synthhid_msg_hdr header;
  99        struct hv_input_dev_info hid_dev_info;
 100        struct hid_descriptor hid_descriptor;
 101};
 102
 103struct synthhid_device_info_ack {
 104        struct synthhid_msg_hdr header;
 105        unsigned char reserved;
 106};
 107
 108struct synthhid_input_report {
 109        struct synthhid_msg_hdr header;
 110        char buffer[1];
 111};
 112
 113#pragma pack(pop)
 114
 115#define INPUTVSC_SEND_RING_BUFFER_SIZE          (10*PAGE_SIZE)
 116#define INPUTVSC_RECV_RING_BUFFER_SIZE          (10*PAGE_SIZE)
 117
 118
 119enum pipe_prot_msg_type {
 120        PIPE_MESSAGE_INVALID,
 121        PIPE_MESSAGE_DATA,
 122        PIPE_MESSAGE_MAXIMUM
 123};
 124
 125
 126struct pipe_prt_msg {
 127        enum pipe_prot_msg_type type;
 128        u32 size;
 129        char data[1];
 130};
 131
 132struct  mousevsc_prt_msg {
 133        enum pipe_prot_msg_type type;
 134        u32 size;
 135        union {
 136                struct synthhid_protocol_request request;
 137                struct synthhid_protocol_response response;
 138                struct synthhid_device_info_ack ack;
 139        };
 140};
 141
 142/*
 143 * Represents an mousevsc device
 144 */
 145struct mousevsc_dev {
 146        struct hv_device        *device;
 147        bool                    init_complete;
 148        bool                    connected;
 149        struct mousevsc_prt_msg protocol_req;
 150        struct mousevsc_prt_msg protocol_resp;
 151        /* Synchronize the request/response if needed */
 152        struct completion       wait_event;
 153        int                     dev_info_status;
 154
 155        struct hid_descriptor   *hid_desc;
 156        unsigned char           *report_desc;
 157        u32                     report_desc_size;
 158        struct hv_input_dev_info hid_dev_info;
 159        struct hid_device       *hid_device;
 160};
 161
 162
 163static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)
 164{
 165        struct mousevsc_dev *input_dev;
 166
 167        input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
 168
 169        if (!input_dev)
 170                return NULL;
 171
 172        input_dev->device = device;
 173        hv_set_drvdata(device, input_dev);
 174        init_completion(&input_dev->wait_event);
 175        input_dev->init_complete = false;
 176
 177        return input_dev;
 178}
 179
 180static void mousevsc_free_device(struct mousevsc_dev *device)
 181{
 182        kfree(device->hid_desc);
 183        kfree(device->report_desc);
 184        hv_set_drvdata(device->device, NULL);
 185        kfree(device);
 186}
 187
 188static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
 189                                struct synthhid_device_info *device_info)
 190{
 191        int ret = 0;
 192        struct hid_descriptor *desc;
 193        struct mousevsc_prt_msg ack;
 194
 195        input_device->dev_info_status = -ENOMEM;
 196
 197        input_device->hid_dev_info = device_info->hid_dev_info;
 198        desc = &device_info->hid_descriptor;
 199        if (desc->bLength == 0)
 200                goto cleanup;
 201
 202        input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
 203
 204        if (!input_device->hid_desc)
 205                goto cleanup;
 206
 207        input_device->report_desc_size = desc->desc[0].wDescriptorLength;
 208        if (input_device->report_desc_size == 0) {
 209                input_device->dev_info_status = -EINVAL;
 210                goto cleanup;
 211        }
 212
 213        input_device->report_desc = kzalloc(input_device->report_desc_size,
 214                                          GFP_ATOMIC);
 215
 216        if (!input_device->report_desc) {
 217                input_device->dev_info_status = -ENOMEM;
 218                goto cleanup;
 219        }
 220
 221        memcpy(input_device->report_desc,
 222               ((unsigned char *)desc) + desc->bLength,
 223               desc->desc[0].wDescriptorLength);
 224
 225        /* Send the ack */
 226        memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
 227
 228        ack.type = PIPE_MESSAGE_DATA;
 229        ack.size = sizeof(struct synthhid_device_info_ack);
 230
 231        ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
 232        ack.ack.header.size = 1;
 233        ack.ack.reserved = 0;
 234
 235        ret = vmbus_sendpacket(input_device->device->channel,
 236                        &ack,
 237                        sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
 238                        sizeof(struct synthhid_device_info_ack),
 239                        (unsigned long)&ack,
 240                        VM_PKT_DATA_INBAND,
 241                        VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 242
 243        if (!ret)
 244                input_device->dev_info_status = 0;
 245
 246cleanup:
 247        complete(&input_device->wait_event);
 248
 249        return;
 250}
 251
 252static void mousevsc_on_receive(struct hv_device *device,
 253                                struct vmpacket_descriptor *packet)
 254{
 255        struct pipe_prt_msg *pipe_msg;
 256        struct synthhid_msg *hid_msg;
 257        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
 258        struct synthhid_input_report *input_report;
 259
 260        pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
 261                                                (packet->offset8 << 3));
 262
 263        if (pipe_msg->type != PIPE_MESSAGE_DATA)
 264                return;
 265
 266        hid_msg = (struct synthhid_msg *)pipe_msg->data;
 267
 268        switch (hid_msg->header.type) {
 269        case SYNTH_HID_PROTOCOL_RESPONSE:
 270                /*
 271                 * While it will be impossible for us to protect against
 272                 * malicious/buggy hypervisor/host, add a check here to
 273                 * ensure we don't corrupt memory.
 274                 */
 275                if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
 276                        - sizeof(unsigned char))
 277                        > sizeof(struct mousevsc_prt_msg)) {
 278                        WARN_ON(1);
 279                        break;
 280                }
 281
 282                memcpy(&input_dev->protocol_resp, pipe_msg,
 283                       pipe_msg->size + sizeof(struct pipe_prt_msg) -
 284                       sizeof(unsigned char));
 285                complete(&input_dev->wait_event);
 286                break;
 287
 288        case SYNTH_HID_INITIAL_DEVICE_INFO:
 289                WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
 290
 291                /*
 292                 * Parse out the device info into device attr,
 293                 * hid desc and report desc
 294                 */
 295                mousevsc_on_receive_device_info(input_dev,
 296                        (struct synthhid_device_info *)pipe_msg->data);
 297                break;
 298        case SYNTH_HID_INPUT_REPORT:
 299                input_report =
 300                        (struct synthhid_input_report *)pipe_msg->data;
 301                if (!input_dev->init_complete)
 302                        break;
 303                hid_input_report(input_dev->hid_device,
 304                                HID_INPUT_REPORT, input_report->buffer,
 305                                input_report->header.size, 1);
 306                break;
 307        default:
 308                pr_err("unsupported hid msg type - type %d len %d",
 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        int 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 struct hid_ll_driver mousevsc_ll_driver = {
 459        .parse = mousevsc_hid_parse,
 460        .open = mousevsc_hid_open,
 461        .close = mousevsc_hid_close,
 462        .start = mousevsc_hid_start,
 463        .stop = mousevsc_hid_stop,
 464};
 465
 466static struct hid_driver mousevsc_hid_driver;
 467
 468static int mousevsc_probe(struct hv_device *device,
 469                        const struct hv_vmbus_device_id *dev_id)
 470{
 471        int ret;
 472        struct mousevsc_dev *input_dev;
 473        struct hid_device *hid_dev;
 474
 475        input_dev = mousevsc_alloc_device(device);
 476
 477        if (!input_dev)
 478                return -ENOMEM;
 479
 480        ret = vmbus_open(device->channel,
 481                INPUTVSC_SEND_RING_BUFFER_SIZE,
 482                INPUTVSC_RECV_RING_BUFFER_SIZE,
 483                NULL,
 484                0,
 485                mousevsc_on_channel_callback,
 486                device
 487                );
 488
 489        if (ret)
 490                goto probe_err0;
 491
 492        ret = mousevsc_connect_to_vsp(device);
 493
 494        if (ret)
 495                goto probe_err1;
 496
 497        /* workaround SA-167 */
 498        if (input_dev->report_desc[14] == 0x25)
 499                input_dev->report_desc[14] = 0x29;
 500
 501        hid_dev = hid_allocate_device();
 502        if (IS_ERR(hid_dev)) {
 503                ret = PTR_ERR(hid_dev);
 504                goto probe_err1;
 505        }
 506
 507        hid_dev->ll_driver = &mousevsc_ll_driver;
 508        hid_dev->driver = &mousevsc_hid_driver;
 509        hid_dev->bus = BUS_VIRTUAL;
 510        hid_dev->vendor = input_dev->hid_dev_info.vendor;
 511        hid_dev->product = input_dev->hid_dev_info.product;
 512        hid_dev->version = input_dev->hid_dev_info.version;
 513        input_dev->hid_device = hid_dev;
 514
 515        sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
 516
 517        hid_set_drvdata(hid_dev, device);
 518
 519        ret = hid_add_device(hid_dev);
 520        if (ret)
 521                goto probe_err1;
 522
 523
 524        ret = hid_parse(hid_dev);
 525        if (ret) {
 526                hid_err(hid_dev, "parse failed\n");
 527                goto probe_err2;
 528        }
 529
 530        ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
 531
 532        if (ret) {
 533                hid_err(hid_dev, "hw start failed\n");
 534                goto probe_err2;
 535        }
 536
 537        input_dev->connected = true;
 538        input_dev->init_complete = true;
 539
 540        return ret;
 541
 542probe_err2:
 543        hid_destroy_device(hid_dev);
 544
 545probe_err1:
 546        vmbus_close(device->channel);
 547
 548probe_err0:
 549        mousevsc_free_device(input_dev);
 550
 551        return ret;
 552}
 553
 554
 555static int mousevsc_remove(struct hv_device *dev)
 556{
 557        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 558
 559        vmbus_close(dev->channel);
 560        hid_hw_stop(input_dev->hid_device);
 561        hid_destroy_device(input_dev->hid_device);
 562        mousevsc_free_device(input_dev);
 563
 564        return 0;
 565}
 566
 567static const struct hv_vmbus_device_id id_table[] = {
 568        /* Mouse guid */
 569        { HV_MOUSE_GUID, },
 570        { },
 571};
 572
 573MODULE_DEVICE_TABLE(vmbus, id_table);
 574
 575static struct  hv_driver mousevsc_drv = {
 576        .name = KBUILD_MODNAME,
 577        .id_table = id_table,
 578        .probe = mousevsc_probe,
 579        .remove = mousevsc_remove,
 580};
 581
 582static int __init mousevsc_init(void)
 583{
 584        return vmbus_driver_register(&mousevsc_drv);
 585}
 586
 587static void __exit mousevsc_exit(void)
 588{
 589        vmbus_driver_unregister(&mousevsc_drv);
 590}
 591
 592MODULE_LICENSE("GPL");
 593MODULE_VERSION(HV_DRV_VERSION);
 594module_init(mousevsc_init);
 595module_exit(mousevsc_exit);
 596
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.