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