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 #if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST)
17 #include <kunit/test.h>
18 #endif
19
20 struct hv_input_dev_info {
21 unsigned int size;
22 unsigned short vendor;
23 unsigned short product;
24 unsigned short version;
25 unsigned short reserved[11];
26 };
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 */
45 enum 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 */
57 struct synthhid_msg_hdr {
58 enum synthhid_msg_type type;
59 u32 size;
60 };
61
62 union synthhid_version {
63 struct {
64 u16 minor_version;
65 u16 major_version;
66 };
67 u32 version;
68 };
69
70 /*
71 * Protocol messages
72 */
73 struct synthhid_protocol_request {
74 struct synthhid_msg_hdr header;
75 union synthhid_version version_requested;
76 };
77
78 struct synthhid_protocol_response {
79 struct synthhid_msg_hdr header;
80 union synthhid_version version_requested;
81 unsigned char approved;
82 };
83
84 struct synthhid_device_info {
85 struct synthhid_msg_hdr header;
86 struct hv_input_dev_info hid_dev_info;
87 struct hid_descriptor hid_descriptor;
88 };
89
90 struct synthhid_device_info_ack {
91 struct synthhid_msg_hdr header;
92 unsigned char reserved;
93 };
94
95 struct synthhid_input_report {
96 struct synthhid_msg_hdr header;
97 char buffer[];
98 };
99
100 #pragma pack(pop)
101
102 #define INPUTVSC_SEND_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024)
103 #define INPUTVSC_RECV_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024)
104
105
106 enum pipe_prot_msg_type {
107 PIPE_MESSAGE_INVALID,
108 PIPE_MESSAGE_DATA,
109 PIPE_MESSAGE_MAXIMUM
110 };
111
112
113 struct pipe_prt_msg {
114 enum pipe_prot_msg_type type;
115 u32 size;
116 char data[];
117 };
118
119 struct mousevsc_prt_msg {
120 enum pipe_prot_msg_type type;
121 u32 size;
122 union {
123 struct synthhid_protocol_request request;
124 struct synthhid_protocol_response response;
125 struct synthhid_device_info_ack ack;
126 };
127 };
128
129 /*
130 * Represents an mousevsc device
131 */
132 struct mousevsc_dev {
133 struct hv_device *device;
134 bool init_complete;
135 bool connected;
136 struct mousevsc_prt_msg protocol_req;
137 struct mousevsc_prt_msg protocol_resp;
138 /* Synchronize the request/response if needed */
139 struct completion wait_event;
140 int dev_info_status;
141
142 struct hid_descriptor *hid_desc;
143 unsigned char *report_desc;
144 u32 report_desc_size;
145 struct hv_input_dev_info hid_dev_info;
146 struct hid_device *hid_device;
147 u8 input_buf[HID_MAX_BUFFER_SIZE];
148 };
149
150
mousevsc_alloc_device(struct hv_device * device)151 static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)
152 {
153 struct mousevsc_dev *input_dev;
154
155 input_dev = kzalloc_obj(struct mousevsc_dev);
156
157 if (!input_dev)
158 return NULL;
159
160 input_dev->device = device;
161 hv_set_drvdata(device, input_dev);
162 init_completion(&input_dev->wait_event);
163 input_dev->init_complete = false;
164
165 return input_dev;
166 }
167
mousevsc_free_device(struct mousevsc_dev * device)168 static void mousevsc_free_device(struct mousevsc_dev *device)
169 {
170 kfree(device->hid_desc);
171 kfree(device->report_desc);
172 hv_set_drvdata(device->device, NULL);
173 kfree(device);
174 }
175
mousevsc_on_receive_device_info(struct mousevsc_dev * input_device,struct synthhid_device_info * device_info,u32 device_info_size)176 static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
177 struct synthhid_device_info *device_info,
178 u32 device_info_size)
179 {
180 int ret = 0;
181 struct hid_descriptor *desc;
182 struct mousevsc_prt_msg ack;
183 size_t desc_offset;
184 size_t desc_size;
185
186 input_device->dev_info_status = -ENOMEM;
187
188 if (device_info_size < sizeof(*device_info)) {
189 input_device->dev_info_status = -EINVAL;
190 goto cleanup;
191 }
192
193 input_device->hid_dev_info = device_info->hid_dev_info;
194 desc = &device_info->hid_descriptor;
195 desc_offset = offsetof(struct synthhid_device_info, hid_descriptor);
196 desc_size = device_info_size - desc_offset;
197 if (desc->bLength == 0)
198 goto cleanup;
199 if (desc->bLength < sizeof(*desc) || desc->bLength > desc_size) {
200 input_device->dev_info_status = -EINVAL;
201 goto cleanup;
202 }
203
204 /* The pointer is not NULL when we resume from hibernation */
205 kfree(input_device->hid_desc);
206 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
207
208 if (!input_device->hid_desc)
209 goto cleanup;
210
211 input_device->report_desc_size = le16_to_cpu(
212 desc->rpt_desc.wDescriptorLength);
213 if (input_device->report_desc_size == 0) {
214 input_device->dev_info_status = -EINVAL;
215 goto cleanup;
216 }
217 if (input_device->report_desc_size > desc_size - desc->bLength) {
218 input_device->dev_info_status = -EINVAL;
219 goto cleanup;
220 }
221
222 /* The pointer is not NULL when we resume from hibernation */
223 kfree(input_device->report_desc);
224 input_device->report_desc = kzalloc(input_device->report_desc_size,
225 GFP_ATOMIC);
226
227 if (!input_device->report_desc) {
228 input_device->dev_info_status = -ENOMEM;
229 goto cleanup;
230 }
231
232 memcpy(input_device->report_desc,
233 ((unsigned char *)desc) + desc->bLength,
234 le16_to_cpu(desc->rpt_desc.wDescriptorLength));
235
236 /* Send the ack */
237 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
238
239 ack.type = PIPE_MESSAGE_DATA;
240 ack.size = sizeof(struct synthhid_device_info_ack);
241
242 ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
243 ack.ack.header.size = 1;
244 ack.ack.reserved = 0;
245
246 if (IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) &&
247 !input_device->device) {
248 ret = 0;
249 } else {
250 ret = vmbus_sendpacket(input_device->device->channel,
251 &ack,
252 sizeof(struct pipe_prt_msg) +
253 sizeof(struct synthhid_device_info_ack),
254 (unsigned long)&ack,
255 VM_PKT_DATA_INBAND,
256 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
257 }
258
259 if (!ret)
260 input_device->dev_info_status = 0;
261
262 cleanup:
263 complete(&input_device->wait_event);
264
265 return;
266 }
267
mousevsc_on_receive(struct hv_device * device,struct vmpacket_descriptor * packet)268 static void mousevsc_on_receive(struct hv_device *device,
269 struct vmpacket_descriptor *packet)
270 {
271 struct pipe_prt_msg *pipe_msg;
272 struct synthhid_msg_hdr *hid_msg_hdr;
273 struct mousevsc_dev *input_dev = hv_get_drvdata(device);
274 struct synthhid_input_report *input_report;
275 size_t len;
276
277 pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
278 (packet->offset8 << 3));
279
280 if (pipe_msg->type != PIPE_MESSAGE_DATA)
281 return;
282
283 hid_msg_hdr = (struct synthhid_msg_hdr *)pipe_msg->data;
284
285 switch (hid_msg_hdr->type) {
286 case SYNTH_HID_PROTOCOL_RESPONSE:
287 len = struct_size(pipe_msg, data, pipe_msg->size);
288
289 /*
290 * While it will be impossible for us to protect against
291 * malicious/buggy hypervisor/host, add a check here to
292 * ensure we don't corrupt memory.
293 */
294 if (WARN_ON(len > sizeof(struct mousevsc_prt_msg)))
295 break;
296
297 memcpy(&input_dev->protocol_resp, pipe_msg, len);
298 complete(&input_dev->wait_event);
299 break;
300
301 case SYNTH_HID_INITIAL_DEVICE_INFO:
302 if (WARN_ON_ONCE(pipe_msg->size <
303 sizeof(struct synthhid_device_info)))
304 break;
305
306 /*
307 * Parse out the device info into device attr,
308 * hid desc and report desc
309 */
310 mousevsc_on_receive_device_info(input_dev,
311 (struct synthhid_device_info *)pipe_msg->data,
312 pipe_msg->size);
313 break;
314 case SYNTH_HID_INPUT_REPORT:
315 input_report =
316 (struct synthhid_input_report *)pipe_msg->data;
317 if (!input_dev->init_complete)
318 break;
319
320 len = min(input_report->header.size,
321 (u32)sizeof(input_dev->input_buf));
322 memcpy(input_dev->input_buf, input_report->buffer, len);
323 hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
324 input_dev->input_buf, len, 1);
325
326 pm_wakeup_hard_event(&input_dev->device->device);
327
328 break;
329 default:
330 pr_err("unsupported hid msg type - type %d len %d\n",
331 hid_msg_hdr->type, hid_msg_hdr->size);
332 break;
333 }
334
335 }
336
mousevsc_on_channel_callback(void * context)337 static void mousevsc_on_channel_callback(void *context)
338 {
339 struct hv_device *device = context;
340 struct vmpacket_descriptor *desc;
341
342 foreach_vmbus_pkt(desc, device->channel) {
343 switch (desc->type) {
344 case VM_PKT_COMP:
345 break;
346
347 case VM_PKT_DATA_INBAND:
348 mousevsc_on_receive(device, desc);
349 break;
350
351 default:
352 pr_err("Unhandled packet type %d, tid %llx len %d\n",
353 desc->type, desc->trans_id, desc->len8 * 8);
354 break;
355 }
356 }
357 }
358
mousevsc_connect_to_vsp(struct hv_device * device)359 static int mousevsc_connect_to_vsp(struct hv_device *device)
360 {
361 int ret = 0;
362 unsigned long t;
363 struct mousevsc_dev *input_dev = hv_get_drvdata(device);
364 struct mousevsc_prt_msg *request;
365 struct mousevsc_prt_msg *response;
366
367 reinit_completion(&input_dev->wait_event);
368
369 request = &input_dev->protocol_req;
370 memset(request, 0, sizeof(struct mousevsc_prt_msg));
371
372 request->type = PIPE_MESSAGE_DATA;
373 request->size = sizeof(struct synthhid_protocol_request);
374 request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
375 request->request.header.size = sizeof(unsigned int);
376 request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
377
378 ret = vmbus_sendpacket(device->channel, request,
379 sizeof(struct pipe_prt_msg) +
380 sizeof(struct synthhid_protocol_request),
381 (unsigned long)request,
382 VM_PKT_DATA_INBAND,
383 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
384 if (ret)
385 goto cleanup;
386
387 t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
388 if (!t) {
389 ret = -ETIMEDOUT;
390 goto cleanup;
391 }
392
393 response = &input_dev->protocol_resp;
394
395 if (!response->response.approved) {
396 pr_err("synthhid protocol request failed (version %d)\n",
397 SYNTHHID_INPUT_VERSION);
398 ret = -ENODEV;
399 goto cleanup;
400 }
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 /*
409 * We should have gotten the device attr, hid desc and report
410 * desc at this point
411 */
412 ret = input_dev->dev_info_status;
413
414 cleanup:
415 return ret;
416 }
417
mousevsc_hid_parse(struct hid_device * hid)418 static int mousevsc_hid_parse(struct hid_device *hid)
419 {
420 struct hv_device *dev = hid_get_drvdata(hid);
421 struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
422
423 return hid_parse_report(hid, input_dev->report_desc,
424 input_dev->report_desc_size);
425 }
426
mousevsc_hid_open(struct hid_device * hid)427 static int mousevsc_hid_open(struct hid_device *hid)
428 {
429 return 0;
430 }
431
mousevsc_hid_start(struct hid_device * hid)432 static int mousevsc_hid_start(struct hid_device *hid)
433 {
434 return 0;
435 }
436
mousevsc_hid_close(struct hid_device * hid)437 static void mousevsc_hid_close(struct hid_device *hid)
438 {
439 }
440
mousevsc_hid_stop(struct hid_device * hid)441 static void mousevsc_hid_stop(struct hid_device *hid)
442 {
443 }
444
mousevsc_hid_raw_request(struct hid_device * hid,unsigned char report_num,__u8 * buf,size_t len,unsigned char rtype,int reqtype)445 static int mousevsc_hid_raw_request(struct hid_device *hid,
446 unsigned char report_num,
447 __u8 *buf, size_t len,
448 unsigned char rtype,
449 int reqtype)
450 {
451 return 0;
452 }
453
mousevsc_hid_probe(struct hid_device * hid_dev,const struct hid_device_id * id)454 static int mousevsc_hid_probe(struct hid_device *hid_dev, const struct hid_device_id *id)
455 {
456 int ret;
457
458 ret = hid_parse(hid_dev);
459 if (ret) {
460 hid_err(hid_dev, "parse failed\n");
461 return ret;
462 }
463
464 ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);
465 if (ret) {
466 hid_err(hid_dev, "hw start failed\n");
467 return ret;
468 }
469
470 return 0;
471 }
472
473 static const struct hid_ll_driver mousevsc_ll_driver = {
474 .parse = mousevsc_hid_parse,
475 .open = mousevsc_hid_open,
476 .close = mousevsc_hid_close,
477 .start = mousevsc_hid_start,
478 .stop = mousevsc_hid_stop,
479 .raw_request = mousevsc_hid_raw_request,
480 };
481
482 static const struct hid_device_id mousevsc_devices[] = {
483 { HID_DEVICE(BUS_VIRTUAL, HID_GROUP_ANY, 0x045E, 0x0621) },
484 { }
485 };
486
487 static struct hid_driver mousevsc_hid_driver = {
488 .name = "hid-hyperv",
489 .id_table = mousevsc_devices,
490 .probe = mousevsc_hid_probe,
491 };
492
mousevsc_probe(struct hv_device * device,const struct hv_vmbus_device_id * dev_id)493 static int mousevsc_probe(struct hv_device *device,
494 const struct hv_vmbus_device_id *dev_id)
495 {
496 int ret;
497 struct mousevsc_dev *input_dev;
498 struct hid_device *hid_dev;
499
500 input_dev = mousevsc_alloc_device(device);
501
502 if (!input_dev)
503 return -ENOMEM;
504
505 ret = vmbus_open(device->channel,
506 INPUTVSC_SEND_RING_BUFFER_SIZE,
507 INPUTVSC_RECV_RING_BUFFER_SIZE,
508 NULL,
509 0,
510 mousevsc_on_channel_callback,
511 device
512 );
513
514 if (ret)
515 goto probe_err0;
516
517 ret = mousevsc_connect_to_vsp(device);
518
519 if (ret)
520 goto probe_err1;
521
522 /* workaround SA-167 */
523 if (input_dev->report_desc[14] == 0x25)
524 input_dev->report_desc[14] = 0x29;
525
526 hid_dev = hid_allocate_device();
527 if (IS_ERR(hid_dev)) {
528 ret = PTR_ERR(hid_dev);
529 goto probe_err1;
530 }
531
532 hid_dev->ll_driver = &mousevsc_ll_driver;
533 hid_dev->bus = BUS_VIRTUAL;
534 hid_dev->vendor = input_dev->hid_dev_info.vendor;
535 hid_dev->product = input_dev->hid_dev_info.product;
536 hid_dev->version = input_dev->hid_dev_info.version;
537 input_dev->hid_device = hid_dev;
538
539 sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
540
541 hid_set_drvdata(hid_dev, device);
542
543 ret = hid_add_device(hid_dev);
544 if (ret)
545 goto probe_err2;
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
554 probe_err2:
555 hid_destroy_device(hid_dev);
556
557 probe_err1:
558 vmbus_close(device->channel);
559
560 probe_err0:
561 mousevsc_free_device(input_dev);
562
563 return ret;
564 }
565
566
mousevsc_remove(struct hv_device * dev)567 static void 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
mousevsc_suspend(struct hv_device * dev)578 static int mousevsc_suspend(struct hv_device *dev)
579 {
580 vmbus_close(dev->channel);
581
582 return 0;
583 }
584
mousevsc_resume(struct hv_device * dev)585 static int mousevsc_resume(struct hv_device *dev)
586 {
587 int ret;
588
589 ret = vmbus_open(dev->channel,
590 INPUTVSC_SEND_RING_BUFFER_SIZE,
591 INPUTVSC_RECV_RING_BUFFER_SIZE,
592 NULL, 0,
593 mousevsc_on_channel_callback,
594 dev);
595 if (ret)
596 return ret;
597
598 ret = mousevsc_connect_to_vsp(dev);
599 return ret;
600 }
601
602 static const struct hv_vmbus_device_id id_table[] = {
603 /* Mouse guid */
604 { HV_MOUSE_GUID, },
605 { },
606 };
607
608 MODULE_DEVICE_TABLE(vmbus, id_table);
609
610 static struct hv_driver mousevsc_drv = {
611 .name = KBUILD_MODNAME,
612 .id_table = id_table,
613 .probe = mousevsc_probe,
614 .remove = mousevsc_remove,
615 .suspend = mousevsc_suspend,
616 .resume = mousevsc_resume,
617 .driver = {
618 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
619 },
620 };
621
mousevsc_init(void)622 static int __init mousevsc_init(void)
623 {
624 int ret;
625
626 ret = hid_register_driver(&mousevsc_hid_driver);
627 if (ret)
628 return ret;
629
630 ret = vmbus_driver_register(&mousevsc_drv);
631 if (ret)
632 hid_unregister_driver(&mousevsc_hid_driver);
633
634 return ret;
635 }
636
mousevsc_exit(void)637 static void __exit mousevsc_exit(void)
638 {
639 vmbus_driver_unregister(&mousevsc_drv);
640 hid_unregister_driver(&mousevsc_hid_driver);
641 }
642
643 MODULE_LICENSE("GPL");
644 MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver");
645
646 #if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST)
mousevsc_kunit_alloc_dev(struct kunit * test)647 static struct mousevsc_dev *mousevsc_kunit_alloc_dev(struct kunit *test)
648 {
649 struct mousevsc_dev *input_dev;
650
651 input_dev = kunit_kzalloc(test, sizeof(*input_dev), GFP_KERNEL);
652 if (!input_dev)
653 return NULL;
654
655 init_completion(&input_dev->wait_event);
656
657 return input_dev;
658 }
659
mousevsc_device_info_zero_blength(struct kunit * test)660 static void mousevsc_device_info_zero_blength(struct kunit *test)
661 {
662 struct synthhid_device_info *info;
663 struct mousevsc_dev *input_dev;
664
665 input_dev = mousevsc_kunit_alloc_dev(test);
666 KUNIT_ASSERT_NOT_NULL(test, input_dev);
667 info = kunit_kzalloc(test, sizeof(*info), GFP_KERNEL);
668 KUNIT_ASSERT_NOT_NULL(test, info);
669
670 info->hid_descriptor.bLength = 0;
671
672 mousevsc_on_receive_device_info(input_dev, info, sizeof(*info));
673
674 KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -ENOMEM);
675 }
676
mousevsc_device_info_valid_descriptor(struct kunit * test)677 static void mousevsc_device_info_valid_descriptor(struct kunit *test)
678 {
679 struct synthhid_device_info *info;
680 struct mousevsc_dev *input_dev;
681 u8 *report;
682
683 input_dev = mousevsc_kunit_alloc_dev(test);
684 KUNIT_ASSERT_NOT_NULL(test, input_dev);
685 info = kunit_kzalloc(test, sizeof(*info) + 4, GFP_KERNEL);
686 KUNIT_ASSERT_NOT_NULL(test, info);
687
688 info->hid_descriptor.bLength = sizeof(struct hid_descriptor);
689 info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(4);
690 report = (u8 *)(info + 1);
691 memset(report, 0x42, 4);
692
693 mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 4);
694
695 KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, 0);
696 KUNIT_EXPECT_EQ(test, input_dev->report_desc_size, 4);
697 KUNIT_EXPECT_MEMEQ(test, input_dev->report_desc, report, 4);
698
699 kfree(input_dev->hid_desc);
700 kfree(input_dev->report_desc);
701 }
702
mousevsc_device_info_report_desc_oob(struct kunit * test)703 static void mousevsc_device_info_report_desc_oob(struct kunit *test)
704 {
705 struct synthhid_device_info *info;
706 struct mousevsc_dev *input_dev;
707 u8 *report;
708
709 input_dev = mousevsc_kunit_alloc_dev(test);
710 KUNIT_ASSERT_NOT_NULL(test, input_dev);
711 info = kunit_kzalloc(test, sizeof(*info) + 8, GFP_KERNEL);
712 KUNIT_ASSERT_NOT_NULL(test, info);
713
714 info->hid_descriptor.bLength = sizeof(struct hid_descriptor);
715 info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(64);
716 report = (u8 *)(info + 1);
717 memset(report, 0x42, 8);
718
719 mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 8);
720
721 KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -EINVAL);
722
723 kfree(input_dev->hid_desc);
724 }
725
726 static struct kunit_case mousevsc_test_cases[] = {
727 KUNIT_CASE(mousevsc_device_info_zero_blength),
728 KUNIT_CASE(mousevsc_device_info_valid_descriptor),
729 KUNIT_CASE(mousevsc_device_info_report_desc_oob),
730 {}
731 };
732
733 static struct kunit_suite mousevsc_test_suite = {
734 .name = "hid_hyperv_mouse",
735 .test_cases = mousevsc_test_cases,
736 };
737
738 kunit_test_suite(mousevsc_test_suite);
739 #endif
740
741 module_init(mousevsc_init);
742 module_exit(mousevsc_exit);
743