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 = kzalloc(desc->bLength, GFP_ATOMIC);
 203
 204        if (!input_device->hid_desc)
 205                goto cleanup;
 206
 207        memcpy(input_device->hid_desc, desc, desc->bLength);
 208
 209        input_device->report_desc_size = desc->desc[0].wDescriptorLength;
 210        if (input_device->report_desc_size == 0) {
 211                input_device->dev_info_status = -EINVAL;
 212                goto cleanup;
 213        }
 214
 215        input_device->report_desc = kzalloc(input_device->report_desc_size,
 216                                          GFP_ATOMIC);
 217
 218        if (!input_device->report_desc) {
 219                input_device->dev_info_status = -ENOMEM;
 220                goto cleanup;
 221        }
 222
 223        memcpy(input_device->report_desc,
 224               ((unsigned char *)desc) + desc->bLength,
 225               desc->desc[0].wDescriptorLength);
 226
 227        /* Send the ack */
 228        memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
 229
 230        ack.type = PIPE_MESSAGE_DATA;
 231        ack.size = sizeof(struct synthhid_device_info_ack);
 232
 233        ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
 234        ack.ack.header.size = 1;
 235        ack.ack.reserved = 0;
 236
 237        ret = vmbus_sendpacket(input_device->device->channel,
 238                        &ack,
 239                        sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
 240                        sizeof(struct synthhid_device_info_ack),
 241                        (unsigned long)&ack,
 242                        VM_PKT_DATA_INBAND,
 243                        VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 244
 245        if (!ret)
 246                input_device->dev_info_status = 0;
 247
 248cleanup:
 249        complete(&input_device->wait_event);
 250
 251        return;
 252}
 253
 254static void mousevsc_on_receive(struct hv_device *device,
 255                                struct vmpacket_descriptor *packet)
 256{
 257        struct pipe_prt_msg *pipe_msg;
 258        struct synthhid_msg *hid_msg;
 259        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
 260        struct synthhid_input_report *input_report;
 261
 262        pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
 263                                                (packet->offset8 << 3));
 264
 265        if (pipe_msg->type != PIPE_MESSAGE_DATA)
 266                return;
 267
 268        hid_msg = (struct synthhid_msg *)pipe_msg->data;
 269
 270        switch (hid_msg->header.type) {
 271        case SYNTH_HID_PROTOCOL_RESPONSE:
 272                /*
 273                 * While it will be impossible for us to protect against
 274                 * malicious/buggy hypervisor/host, add a check here to
 275                 * ensure we don't corrupt memory.
 276                 */
 277                if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
 278                        - sizeof(unsigned char))
 279                        > sizeof(struct mousevsc_prt_msg)) {
 280                        WARN_ON(1);
 281                        break;
 282                }
 283
 284                memcpy(&input_dev->protocol_resp, pipe_msg,
 285                       pipe_msg->size + sizeof(struct pipe_prt_msg) -
 286                       sizeof(unsigned char));
 287                complete(&input_dev->wait_event);
 288                break;
 289
 290        case SYNTH_HID_INITIAL_DEVICE_INFO:
 291                WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
 292
 293                /*
 294                 * Parse out the device info into device attr,
 295                 * hid desc and report desc
 296                 */
 297                mousevsc_on_receive_device_info(input_dev,
 298                        (struct synthhid_device_info *)pipe_msg->data);
 299                break;
 300        case SYNTH_HID_INPUT_REPORT:
 301                input_report =
 302                        (struct synthhid_input_report *)pipe_msg->data;
 303                if (!input_dev->init_complete)
 304                        break;
 305                hid_input_report(input_dev->hid_device,
 306                                HID_INPUT_REPORT, input_report->buffer,
 307                                input_report->header.size, 1);
 308                break;
 309        default:
 310                pr_err("unsupported hid msg type - type %d len %d",
 311                       hid_msg->header.type, hid_msg->header.size);
 312                break;
 313        }
 314
 315}
 316
 317static void mousevsc_on_channel_callback(void *context)
 318{
 319        const int packet_size = 0x100;
 320        int ret;
 321        struct hv_device *device = context;
 322        u32 bytes_recvd;
 323        u64 req_id;
 324        struct vmpacket_descriptor *desc;
 325        unsigned char   *buffer;
 326        int     bufferlen = packet_size;
 327
 328        buffer = kmalloc(bufferlen, GFP_ATOMIC);
 329        if (!buffer)
 330                return;
 331
 332        do {
 333                ret = vmbus_recvpacket_raw(device->channel, buffer,
 334                                        bufferlen, &bytes_recvd, &req_id);
 335
 336                switch (ret) {
 337                case 0:
 338                        if (bytes_recvd <= 0) {
 339                                kfree(buffer);
 340                                return;
 341                        }
 342                        desc = (struct vmpacket_descriptor *)buffer;
 343
 344                        switch (desc->type) {
 345                        case VM_PKT_COMP:
 346                                break;
 347
 348                        case VM_PKT_DATA_INBAND:
 349                                mousevsc_on_receive(device, desc);
 350                                break;
 351
 352                        default:
 353                                pr_err("unhandled packet type %d, tid %llx len %d\n",
 354                                        desc->type, req_id, bytes_recvd);
 355                                break;
 356                        }
 357
 358                        break;
 359
 360                case -ENOBUFS:
 361                        kfree(buffer);
 362                        /* Handle large packet */
 363                        bufferlen = bytes_recvd;
 364                        buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
 365
 366                        if (!buffer)
 367                                return;
 368
 369                        break;
 370                }
 371        } while (1);
 372
 373}
 374
 375static int mousevsc_connect_to_vsp(struct hv_device *device)
 376{
 377        int ret = 0;
 378        int t;
 379        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
 380        struct mousevsc_prt_msg *request;
 381        struct mousevsc_prt_msg *response;
 382
 383        request = &input_dev->protocol_req;
 384        memset(request, 0, sizeof(struct mousevsc_prt_msg));
 385
 386        request->type = PIPE_MESSAGE_DATA;
 387        request->size = sizeof(struct synthhid_protocol_request);
 388        request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
 389        request->request.header.size = sizeof(unsigned int);
 390        request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
 391
 392        ret = vmbus_sendpacket(device->channel, request,
 393                                sizeof(struct pipe_prt_msg) -
 394                                sizeof(unsigned char) +
 395                                sizeof(struct synthhid_protocol_request),
 396                                (unsigned long)request,
 397                                VM_PKT_DATA_INBAND,
 398                                VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
 399        if (ret)
 400                goto cleanup;
 401
 402        t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
 403        if (!t) {
 404                ret = -ETIMEDOUT;
 405                goto cleanup;
 406        }
 407
 408        response = &input_dev->protocol_resp;
 409
 410        if (!response->response.approved) {
 411                pr_err("synthhid protocol request failed (version %d)\n",
 412                       SYNTHHID_INPUT_VERSION);
 413                ret = -ENODEV;
 414                goto cleanup;
 415        }
 416
 417        t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
 418        if (!t) {
 419                ret = -ETIMEDOUT;
 420                goto cleanup;
 421        }
 422
 423        /*
 424         * We should have gotten the device attr, hid desc and report
 425         * desc at this point
 426         */
 427        ret = input_dev->dev_info_status;
 428
 429cleanup:
 430        return ret;
 431}
 432
 433static int mousevsc_hid_parse(struct hid_device *hid)
 434{
 435        struct hv_device *dev = hid_get_drvdata(hid);
 436        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 437
 438        return hid_parse_report(hid, input_dev->report_desc,
 439                                input_dev->report_desc_size);
 440}
 441
 442static int mousevsc_hid_open(struct hid_device *hid)
 443{
 444        return 0;
 445}
 446
 447static int mousevsc_hid_start(struct hid_device *hid)
 448{
 449        return 0;
 450}
 451
 452static void mousevsc_hid_close(struct hid_device *hid)
 453{
 454}
 455
 456static void mousevsc_hid_stop(struct hid_device *hid)
 457{
 458}
 459
 460static struct hid_ll_driver mousevsc_ll_driver = {
 461        .parse = mousevsc_hid_parse,
 462        .open = mousevsc_hid_open,
 463        .close = mousevsc_hid_close,
 464        .start = mousevsc_hid_start,
 465        .stop = mousevsc_hid_stop,
 466};
 467
 468static struct hid_driver mousevsc_hid_driver;
 469
 470static int mousevsc_probe(struct hv_device *device,
 471                        const struct hv_vmbus_device_id *dev_id)
 472{
 473        int ret;
 474        struct mousevsc_dev *input_dev;
 475        struct hid_device *hid_dev;
 476
 477        input_dev = mousevsc_alloc_device(device);
 478
 479        if (!input_dev)
 480                return -ENOMEM;
 481
 482        ret = vmbus_open(device->channel,
 483                INPUTVSC_SEND_RING_BUFFER_SIZE,
 484                INPUTVSC_RECV_RING_BUFFER_SIZE,
 485                NULL,
 486                0,
 487                mousevsc_on_channel_callback,
 488                device
 489                );
 490
 491        if (ret)
 492                goto probe_err0;
 493
 494        ret = mousevsc_connect_to_vsp(device);
 495
 496        if (ret)
 497                goto probe_err1;
 498
 499        /* workaround SA-167 */
 500        if (input_dev->report_desc[14] == 0x25)
 501                input_dev->report_desc[14] = 0x29;
 502
 503        hid_dev = hid_allocate_device();
 504        if (IS_ERR(hid_dev)) {
 505                ret = PTR_ERR(hid_dev);
 506                goto probe_err1;
 507        }
 508
 509        hid_dev->ll_driver = &mousevsc_ll_driver;
 510        hid_dev->driver = &mousevsc_hid_driver;
 511        hid_dev->bus = BUS_VIRTUAL;
 512        hid_dev->vendor = input_dev->hid_dev_info.vendor;
 513        hid_dev->product = input_dev->hid_dev_info.product;
 514        hid_dev->version = input_dev->hid_dev_info.version;
 515        input_dev->hid_device = hid_dev;
 516
 517        sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
 518
 519        hid_set_drvdata(hid_dev, device);
 520
 521        ret = hid_add_device(hid_dev);
 522        if (ret)
 523                goto probe_err1;
 524
 525
 526        ret = hid_parse(hid_dev);
 527        if (ret) {
 528                hid_err(hid_dev, "parse failed\n");
 529                goto probe_err2;
 530        }
 531
 532        ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
 533
 534        if (ret) {
 535                hid_err(hid_dev, "hw start failed\n");
 536                goto probe_err2;
 537        }
 538
 539        input_dev->connected = true;
 540        input_dev->init_complete = true;
 541
 542        return ret;
 543
 544probe_err2:
 545        hid_destroy_device(hid_dev);
 546
 547probe_err1:
 548        vmbus_close(device->channel);
 549
 550probe_err0:
 551        mousevsc_free_device(input_dev);
 552
 553        return ret;
 554}
 555
 556
 557static int mousevsc_remove(struct hv_device *dev)
 558{
 559        struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
 560
 561        vmbus_close(dev->channel);
 562        hid_hw_stop(input_dev->hid_device);
 563        hid_destroy_device(input_dev->hid_device);
 564        mousevsc_free_device(input_dev);
 565
 566        return 0;
 567}
 568
 569static const struct hv_vmbus_device_id id_table[] = {
 570        /* Mouse guid */
 571        { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
 572                       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
 573        { },
 574};
 575
 576MODULE_DEVICE_TABLE(vmbus, id_table);
 577
 578static struct  hv_driver mousevsc_drv = {
 579        .name = KBUILD_MODNAME,
 580        .id_table = id_table,
 581        .probe = mousevsc_probe,
 582        .remove = mousevsc_remove,
 583};
 584
 585static int __init mousevsc_init(void)
 586{
 587        return vmbus_driver_register(&mousevsc_drv);
 588}
 589
 590static void __exit mousevsc_exit(void)
 591{
 592        vmbus_driver_unregister(&mousevsc_drv);
 593}
 594
 595MODULE_LICENSE("GPL");
 596MODULE_VERSION(HV_DRV_VERSION);
 597module_init(mousevsc_init);
 598module_exit(mousevsc_exit);
 599
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.