Staging: hv: move hyperv code out of staging directory
[linux-2.6-block.git] / drivers / staging / hv / hv_mouse.c
CommitLineData
0c3a6ede 1/*
9b9f93da
GKH
2 * Copyright (c) 2009, Citrix Systems, Inc.
3 * Copyright (c) 2010, Microsoft Corporation.
4 * Copyright (c) 2011, Novell Inc.
0c3a6ede 5 *
9b9f93da
GKH
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.
0c3a6ede 9 *
9b9f93da
GKH
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.
0c3a6ede
GKH
14 */
15#include <linux/init.h>
16#include <linux/module.h>
a58c616a 17#include <linux/delay.h>
0c3a6ede
GKH
18#include <linux/device.h>
19#include <linux/workqueue.h>
9dccaa63
GKH
20#include <linux/sched.h>
21#include <linux/wait.h>
0c3a6ede
GKH
22#include <linux/input.h>
23#include <linux/hid.h>
24#include <linux/hiddev.h>
46a97191 25#include <linux/hyperv.h>
fa003500
GKH
26
27
0f88ea5b 28struct hv_input_dev_info {
870e53ad 29 unsigned int size;
0f88ea5b
GKH
30 unsigned short vendor;
31 unsigned short product;
32 unsigned short version;
870e53ad 33 unsigned short reserved[11];
94fcc888
GKH
34};
35
fa003500
GKH
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 */
480c28df
GKH
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))
fa003500
GKH
50
51
dbbb2494 52#pragma pack(push, 1)
fa003500
GKH
53/*
54 * Message types in the synthetic input protocol
55 */
56enum synthhid_msg_type {
517812b4
S
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
fa003500
GKH
63};
64
65/*
66 * Basic message structures.
67 */
e6f83b78 68struct synthhid_msg_hdr {
32ad38f7
GKH
69 enum synthhid_msg_type type;
70 u32 size;
e6f83b78 71};
fa003500 72
e6f83b78 73struct synthhid_msg {
0ce815d5 74 struct synthhid_msg_hdr header;
cb2535ad 75 char data[1]; /* Enclosed message */
e6f83b78 76};
fa003500 77
e6f83b78 78union synthhid_version {
fa003500 79 struct {
480c28df
GKH
80 u16 minor_version;
81 u16 major_version;
fa003500 82 };
480c28df 83 u32 version;
e6f83b78 84};
fa003500
GKH
85
86/*
87 * Protocol messages
88 */
e6f83b78 89struct synthhid_protocol_request {
0ce815d5 90 struct synthhid_msg_hdr header;
480c28df 91 union synthhid_version version_requested;
e6f83b78
GKH
92};
93
94struct synthhid_protocol_response {
0ce815d5 95 struct synthhid_msg_hdr header;
480c28df 96 union synthhid_version version_requested;
325eae14 97 unsigned char approved;
e6f83b78
GKH
98};
99
100struct synthhid_device_info {
0ce815d5 101 struct synthhid_msg_hdr header;
98ad91ed 102 struct hv_input_dev_info hid_dev_info;
18bc44e3 103 struct hid_descriptor hid_descriptor;
e6f83b78 104};
fa003500 105
e6f83b78 106struct synthhid_device_info_ack {
0ce815d5 107 struct synthhid_msg_hdr header;
6ed10de1 108 unsigned char reserved;
e6f83b78 109};
fa003500 110
e6f83b78 111struct synthhid_input_report {
0ce815d5 112 struct synthhid_msg_hdr header;
e93eff9c 113 char buffer[1];
e6f83b78 114};
fa003500
GKH
115
116#pragma pack(pop)
117
dbbb2494
RP
118#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE)
119#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE)
0c3a6ede
GKH
120
121#define NBITS(x) (((x)/BITS_PER_LONG)+1)
122
9dccaa63 123enum pipe_prot_msg_type {
517812b4
S
124 PIPE_MESSAGE_INVALID,
125 PIPE_MESSAGE_DATA,
126 PIPE_MESSAGE_MAXIMUM
9dccaa63
GKH
127};
128
129
130struct pipe_prt_msg {
2012d40d 131 enum pipe_prot_msg_type type;
9877fa44 132 u32 size;
e7de0adf 133 char data[1];
9dccaa63
GKH
134};
135
9dccaa63 136struct mousevsc_prt_msg {
2012d40d 137 enum pipe_prot_msg_type type;
9877fa44 138 u32 size;
9dccaa63 139 union {
5ff9b906
GKH
140 struct synthhid_protocol_request request;
141 struct synthhid_protocol_response response;
142 struct synthhid_device_info_ack ack;
d7fa1a46 143 };
9dccaa63
GKH
144};
145
146/*
147 * Represents an mousevsc device
148 */
149struct mousevsc_dev {
ac41d402 150 struct hv_device *device;
ac41d402
HJ
151 unsigned char init_complete;
152 struct mousevsc_prt_msg protocol_req;
153 struct mousevsc_prt_msg protocol_resp;
9dccaa63 154 /* Synchronize the request/response if needed */
622a50dc 155 struct completion wait_event;
ac41d402 156 int dev_info_status;
9dccaa63 157
ac41d402
HJ
158 struct hid_descriptor *hid_desc;
159 unsigned char *report_desc;
160 u32 report_desc_size;
98ad91ed 161 struct hv_input_dev_info hid_dev_info;
4bc69405 162 int connected;
28e0d066 163 struct hid_device *hid_device;
4bc69405 164};
9dccaa63 165
28e0d066 166
2ba6810b 167static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
9dccaa63 168{
c0765e99 169 struct mousevsc_dev *input_dev;
9dccaa63 170
c0765e99 171 input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
9dccaa63 172
c0765e99 173 if (!input_dev)
9dccaa63
GKH
174 return NULL;
175
c0765e99 176 input_dev->device = device;
80e62388 177 hv_set_drvdata(device, input_dev);
622a50dc 178 init_completion(&input_dev->wait_event);
9dccaa63 179
c0765e99 180 return input_dev;
9dccaa63
GKH
181}
182
2ba6810b 183static void free_input_device(struct mousevsc_dev *device)
9dccaa63 184{
ea8646b9
S
185 kfree(device->hid_desc);
186 kfree(device->report_desc);
c411f17d 187 hv_set_drvdata(device->device, NULL);
2ba6810b 188 kfree(device);
9dccaa63
GKH
189}
190
9dccaa63 191
2ba6810b
HJ
192static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
193 struct synthhid_device_info *device_info)
9dccaa63
GKH
194{
195 int ret = 0;
196 struct hid_descriptor *desc;
197 struct mousevsc_prt_msg ack;
198
199 /* Assume success for now */
ac41d402 200 input_device->dev_info_status = 0;
9dccaa63 201
2ba6810b
HJ
202 memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
203 sizeof(struct hv_input_dev_info));
9dccaa63 204
2ba6810b 205 desc = &device_info->hid_descriptor;
7f2bad4b 206 WARN_ON(desc->bLength == 0);
9dccaa63 207
01584892 208 input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
9dccaa63 209
61c4fb47 210 if (!input_device->hid_desc)
fdb3c32c 211 goto cleanup;
9dccaa63 212
ac41d402 213 memcpy(input_device->hid_desc, desc, desc->bLength);
9dccaa63 214
ac41d402 215 input_device->report_desc_size = desc->desc[0].wDescriptorLength;
60e8615a
S
216 if (input_device->report_desc_size == 0)
217 goto cleanup;
ac41d402 218 input_device->report_desc = kzalloc(input_device->report_desc_size,
01584892 219 GFP_ATOMIC);
9dccaa63 220
61c4fb47 221 if (!input_device->report_desc)
fdb3c32c 222 goto cleanup;
9dccaa63 223
ac41d402 224 memcpy(input_device->report_desc,
9dccaa63
GKH
225 ((unsigned char *)desc) + desc->bLength,
226 desc->desc[0].wDescriptorLength);
227
228 /* Send the ack */
75e4fb22 229 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
9dccaa63 230
517812b4 231 ack.type = PIPE_MESSAGE_DATA;
9877fa44 232 ack.size = sizeof(struct synthhid_device_info_ack);
9dccaa63 233
517812b4 234 ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
5ff9b906
GKH
235 ack.ack.header.size = 1;
236 ack.ack.reserved = 0;
9dccaa63 237
ac41d402 238 ret = vmbus_sendpacket(input_device->device->channel,
9dccaa63 239 &ack,
e6f83b78
GKH
240 sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
241 sizeof(struct synthhid_device_info_ack),
9dccaa63
GKH
242 (unsigned long)&ack,
243 VM_PKT_DATA_INBAND,
244 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
61c4fb47 245 if (ret != 0)
fdb3c32c 246 goto cleanup;
9dccaa63 247
622a50dc 248 complete(&input_device->wait_event);
9dccaa63
GKH
249
250 return;
251
fdb3c32c 252cleanup:
ac41d402
HJ
253 kfree(input_device->hid_desc);
254 input_device->hid_desc = NULL;
9dccaa63 255
ac41d402
HJ
256 kfree(input_device->report_desc);
257 input_device->report_desc = NULL;
9dccaa63 258
ac41d402 259 input_device->dev_info_status = -1;
622a50dc 260 complete(&input_device->wait_event);
9dccaa63
GKH
261}
262
2ba6810b
HJ
263static void mousevsc_on_receive(struct hv_device *device,
264 struct vmpacket_descriptor *packet)
9dccaa63 265{
c0765e99
HJ
266 struct pipe_prt_msg *pipe_msg;
267 struct synthhid_msg *hid_msg;
ee2baa29 268 struct mousevsc_dev *input_dev = hv_get_drvdata(device);
6e56f27c 269 struct synthhid_input_report *input_report;
9dccaa63 270
c0765e99 271 pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
2ba6810b 272 (packet->offset8 << 3));
9dccaa63 273
517812b4 274 if (pipe_msg->type != PIPE_MESSAGE_DATA)
ee2baa29 275 return;
9dccaa63 276
c0765e99 277 hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
9dccaa63 278
c0765e99 279 switch (hid_msg->header.type) {
517812b4 280 case SYNTH_HID_PROTOCOL_RESPONSE:
c0765e99
HJ
281 memcpy(&input_dev->protocol_resp, pipe_msg,
282 pipe_msg->size + sizeof(struct pipe_prt_msg) -
9877fa44 283 sizeof(unsigned char));
622a50dc 284 complete(&input_dev->wait_event);
9dccaa63
GKH
285 break;
286
517812b4 287 case SYNTH_HID_INITIAL_DEVICE_INFO:
7f2bad4b 288 WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
9dccaa63
GKH
289
290 /*
291 * Parse out the device info into device attr,
292 * hid desc and report desc
293 */
c0765e99
HJ
294 mousevsc_on_receive_device_info(input_dev,
295 (struct synthhid_device_info *)&pipe_msg->data[0]);
9dccaa63 296 break;
517812b4 297 case SYNTH_HID_INPUT_REPORT:
6e56f27c
S
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);
9dccaa63
GKH
305 break;
306 default:
307 pr_err("unsupported hid msg type - type %d len %d",
c0765e99 308 hid_msg->header.type, hid_msg->header.size);
9dccaa63
GKH
309 break;
310 }
311
9dccaa63
GKH
312}
313
2ba6810b 314static void mousevsc_on_channel_callback(void *context)
9dccaa63
GKH
315{
316 const int packetSize = 0x100;
317 int ret = 0;
2ba6810b 318 struct hv_device *device = (struct hv_device *)context;
9dccaa63 319
c0765e99
HJ
320 u32 bytes_recvd;
321 u64 req_id;
459bce97 322 unsigned char packet[0x100];
9dccaa63
GKH
323 struct vmpacket_descriptor *desc;
324 unsigned char *buffer = packet;
325 int bufferlen = packetSize;
326
9dccaa63
GKH
327
328 do {
c0765e99
HJ
329 ret = vmbus_recvpacket_raw(device->channel, buffer,
330 bufferlen, &bytes_recvd, &req_id);
9dccaa63
GKH
331
332 if (ret == 0) {
c0765e99 333 if (bytes_recvd > 0) {
9dccaa63
GKH
334 desc = (struct vmpacket_descriptor *)buffer;
335
336 switch (desc->type) {
dbbb2494 337 case VM_PKT_COMP:
dbbb2494
RP
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;
9dccaa63
GKH
351 }
352
353 /* reset */
354 if (bufferlen > packetSize) {
355 kfree(buffer);
356
357 buffer = packet;
358 bufferlen = packetSize;
359 }
360 } else {
9dccaa63
GKH
361 if (bufferlen > packetSize) {
362 kfree(buffer);
363
364 buffer = packet;
365 bufferlen = packetSize;
366 }
367 break;
368 }
3d5cad97 369 } else if (ret == -ENOBUFS) {
9dccaa63 370 /* Handle large packet */
c0765e99 371 bufferlen = bytes_recvd;
01584892 372 buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
9dccaa63
GKH
373
374 if (buffer == NULL) {
375 buffer = packet;
376 bufferlen = packetSize;
9dccaa63
GKH
377 break;
378 }
379 }
380 } while (1);
381
9dccaa63
GKH
382 return;
383}
0c3a6ede 384
2ba6810b 385static int mousevsc_connect_to_vsp(struct hv_device *device)
ac2c9033
GKH
386{
387 int ret = 0;
622a50dc 388 int t;
8660e38f 389 struct mousevsc_dev *input_dev = hv_get_drvdata(device);
ac2c9033
GKH
390 struct mousevsc_prt_msg *request;
391 struct mousevsc_prt_msg *response;
392
ac2c9033 393
c0765e99 394 request = &input_dev->protocol_req;
ac2c9033 395
75e4fb22 396 memset(request, 0, sizeof(struct mousevsc_prt_msg));
ac2c9033 397
517812b4 398 request->type = PIPE_MESSAGE_DATA;
9877fa44 399 request->size = sizeof(struct synthhid_protocol_request);
ac2c9033 400
517812b4 401 request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
1738067e 402 request->request.header.size = sizeof(unsigned int);
5ff9b906 403 request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
ac2c9033 404
ac2c9033 405
2ba6810b 406 ret = vmbus_sendpacket(device->channel, request,
bb5da491
S
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);
61c4fb47 413 if (ret != 0)
fdb3c32c 414 goto cleanup;
ac2c9033 415
622a50dc
S
416 t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
417 if (t == 0) {
ac2c9033 418 ret = -ETIMEDOUT;
fdb3c32c 419 goto cleanup;
ac2c9033
GKH
420 }
421
c0765e99 422 response = &input_dev->protocol_resp;
ac2c9033 423
5ff9b906 424 if (!response->response.approved) {
ac2c9033 425 pr_err("synthhid protocol request failed (version %d)",
480c28df 426 SYNTHHID_INPUT_VERSION);
5cd4d030 427 ret = -ENODEV;
fdb3c32c 428 goto cleanup;
ac2c9033
GKH
429 }
430
622a50dc
S
431 t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
432 if (t == 0) {
ac2c9033 433 ret = -ETIMEDOUT;
fdb3c32c 434 goto cleanup;
ac2c9033
GKH
435 }
436
437 /*
438 * We should have gotten the device attr, hid desc and report
439 * desc at this point
440 */
61c4fb47 441 if (input_dev->dev_info_status)
5cd4d030 442 ret = -ENOMEM;
ac2c9033 443
fdb3c32c 444cleanup:
ac2c9033
GKH
445
446 return ret;
447}
448
4ab0871d
GKH
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
da5969e4
S
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
4ab0871d
GKH
465static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
466{
4ab0871d 467 struct hid_device *hid_dev;
28e0d066 468 struct mousevsc_dev *input_device = hv_get_drvdata(dev);
4ab0871d 469
da5969e4
S
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;
4ab0871d 476
0b1f0da0 477 if (hid_parse_report(hid_dev, packet, len))
4ab0871d 478 return;
4ab0871d 479
da5969e4
S
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;
4ab0871d 484
da5969e4 485 sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
4ab0871d 486
da5969e4
S
487 if (!hidinput_connect(hid_dev, 0)) {
488 hid_dev->claimed |= HID_CLAIMED_INPUT;
4ab0871d 489
da5969e4 490 input_device->connected = 1;
4ab0871d 491
4ab0871d
GKH
492 }
493
da5969e4 494 input_device->hid_device = hid_dev;
4ab0871d
GKH
495}
496
929ad795 497static int mousevsc_on_device_add(struct hv_device *device)
ac2c9033
GKH
498{
499 int ret = 0;
c0765e99 500 struct mousevsc_dev *input_dev;
ac2c9033 501
c0765e99 502 input_dev = alloc_input_device(device);
ac2c9033 503
5cd4d030
S
504 if (!input_dev)
505 return -ENOMEM;
ac2c9033 506
c0765e99 507 input_dev->init_complete = false;
ac2c9033 508
2ba6810b 509 ret = vmbus_open(device->channel,
ac2c9033
GKH
510 INPUTVSC_SEND_RING_BUFFER_SIZE,
511 INPUTVSC_RECV_RING_BUFFER_SIZE,
512 NULL,
513 0,
94e44cb5 514 mousevsc_on_channel_callback,
2ba6810b 515 device
ac2c9033
GKH
516 );
517
518 if (ret != 0) {
c0765e99 519 free_input_device(input_dev);
5cd4d030 520 return ret;
ac2c9033
GKH
521 }
522
ac2c9033 523
2ba6810b 524 ret = mousevsc_connect_to_vsp(device);
ac2c9033
GKH
525
526 if (ret != 0) {
2ba6810b 527 vmbus_close(device->channel);
c0765e99 528 free_input_device(input_dev);
ac2c9033
GKH
529 return ret;
530 }
531
ac2c9033 532
ac2c9033 533 /* workaround SA-167 */
c0765e99
HJ
534 if (input_dev->report_desc[14] == 0x25)
535 input_dev->report_desc[14] = 0x29;
ac2c9033 536
c0765e99
HJ
537 reportdesc_callback(device, input_dev->report_desc,
538 input_dev->report_desc_size);
ac2c9033 539
c0765e99 540 input_dev->init_complete = true;
ac2c9033 541
ac2c9033
GKH
542 return ret;
543}
544
84946899
S
545static int mousevsc_probe(struct hv_device *dev,
546 const struct hv_vmbus_device_id *dev_id)
0c3a6ede 547{
0c3a6ede 548
929ad795 549 return mousevsc_on_device_add(dev);
0c3a6ede 550
0c3a6ede
GKH
551}
552
415b023a 553static int mousevsc_remove(struct hv_device *dev)
0c3a6ede 554{
28e0d066 555 struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
0c3a6ede 556
c411f17d
S
557 vmbus_close(dev->channel);
558
28e0d066
S
559 if (input_dev->connected) {
560 hidinput_disconnect(input_dev->hid_device);
561 input_dev->connected = 0;
da5969e4 562 hid_destroy_device(input_dev->hid_device);
0c3a6ede
GKH
563 }
564
8ec31f93
S
565 free_input_device(input_dev);
566
567 return 0;
0c3a6ede
GKH
568}
569
1ec91ebe 570static const struct hv_vmbus_device_id id_table[] = {
c45cf2d4
GKH
571 /* Mouse guid */
572 { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
573 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
574 { },
1ec91ebe
S
575};
576
1eadd8c2 577MODULE_DEVICE_TABLE(vmbus, id_table);
0c3a6ede 578
746e8ca4 579static struct hv_driver mousevsc_drv = {
768fa219 580 .name = "mousevsc",
1ec91ebe 581 .id_table = id_table,
746e8ca4
S
582 .probe = mousevsc_probe,
583 .remove = mousevsc_remove,
1745ec50 584};
eebdd6f2 585
0c3a6ede
GKH
586static int __init mousevsc_init(void)
587{
768fa219 588 return vmbus_driver_register(&mousevsc_drv);
0c3a6ede
GKH
589}
590
591static void __exit mousevsc_exit(void)
592{
768fa219 593 vmbus_driver_unregister(&mousevsc_drv);
0c3a6ede
GKH
594}
595
0c3a6ede
GKH
596MODULE_LICENSE("GPL");
597MODULE_VERSION(HV_DRV_VERSION);
598module_init(mousevsc_init);
599module_exit(mousevsc_exit);
600