595 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 17struct hv_input_dev_info {18 unsigned int size;19 unsigned short vendor;20 unsigned short product;21 unsigned short version;22 unsigned short reserved[11];23};24 25/*26 * Current version27 *28 * History:29 * Beta, RC < 2008/1/22 1,030 * RC > 2008/1/22 2,031 */32#define SYNTHHID_INPUT_VERSION_MAJOR 233#define SYNTHHID_INPUT_VERSION_MINOR 034#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \35 (SYNTHHID_INPUT_VERSION_MAJOR << 16))36 37 38#pragma pack(push, 1)39/*40 * Message types in the synthetic input protocol41 */42enum synthhid_msg_type {43 SYNTH_HID_PROTOCOL_REQUEST,44 SYNTH_HID_PROTOCOL_RESPONSE,45 SYNTH_HID_INITIAL_DEVICE_INFO,46 SYNTH_HID_INITIAL_DEVICE_INFO_ACK,47 SYNTH_HID_INPUT_REPORT,48 SYNTH_HID_MAX49};50 51/*52 * Basic message structures.53 */54struct synthhid_msg_hdr {55 enum synthhid_msg_type type;56 u32 size;57};58 59union synthhid_version {60 struct {61 u16 minor_version;62 u16 major_version;63 };64 u32 version;65};66 67/*68 * Protocol messages69 */70struct synthhid_protocol_request {71 struct synthhid_msg_hdr header;72 union synthhid_version version_requested;73};74 75struct synthhid_protocol_response {76 struct synthhid_msg_hdr header;77 union synthhid_version version_requested;78 unsigned char approved;79};80 81struct synthhid_device_info {82 struct synthhid_msg_hdr header;83 struct hv_input_dev_info hid_dev_info;84 struct hid_descriptor hid_descriptor;85};86 87struct synthhid_device_info_ack {88 struct synthhid_msg_hdr header;89 unsigned char reserved;90};91 92struct synthhid_input_report {93 struct synthhid_msg_hdr header;94 char buffer[];95};96 97#pragma pack(pop)98 99#define INPUTVSC_SEND_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024)100#define INPUTVSC_RECV_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024)101 102 103enum pipe_prot_msg_type {104 PIPE_MESSAGE_INVALID,105 PIPE_MESSAGE_DATA,106 PIPE_MESSAGE_MAXIMUM107};108 109 110struct pipe_prt_msg {111 enum pipe_prot_msg_type type;112 u32 size;113 char data[];114};115 116struct mousevsc_prt_msg {117 enum pipe_prot_msg_type type;118 u32 size;119 union {120 struct synthhid_protocol_request request;121 struct synthhid_protocol_response response;122 struct synthhid_device_info_ack ack;123 };124};125 126/*127 * Represents an mousevsc device128 */129struct mousevsc_dev {130 struct hv_device *device;131 bool init_complete;132 bool connected;133 struct mousevsc_prt_msg protocol_req;134 struct mousevsc_prt_msg protocol_resp;135 /* Synchronize the request/response if needed */136 struct completion wait_event;137 int dev_info_status;138 139 struct hid_descriptor *hid_desc;140 unsigned char *report_desc;141 u32 report_desc_size;142 struct hv_input_dev_info hid_dev_info;143 struct hid_device *hid_device;144 u8 input_buf[HID_MAX_BUFFER_SIZE];145};146 147 148static struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device)149{150 struct mousevsc_dev *input_dev;151 152 input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);153 154 if (!input_dev)155 return NULL;156 157 input_dev->device = device;158 hv_set_drvdata(device, input_dev);159 init_completion(&input_dev->wait_event);160 input_dev->init_complete = false;161 162 return input_dev;163}164 165static void mousevsc_free_device(struct mousevsc_dev *device)166{167 kfree(device->hid_desc);168 kfree(device->report_desc);169 hv_set_drvdata(device->device, NULL);170 kfree(device);171}172 173static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,174 struct synthhid_device_info *device_info)175{176 int ret = 0;177 struct hid_descriptor *desc;178 struct mousevsc_prt_msg ack;179 180 input_device->dev_info_status = -ENOMEM;181 182 input_device->hid_dev_info = device_info->hid_dev_info;183 desc = &device_info->hid_descriptor;184 if (desc->bLength == 0)185 goto cleanup;186 187 /* The pointer is not NULL when we resume from hibernation */188 kfree(input_device->hid_desc);189 input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);190 191 if (!input_device->hid_desc)192 goto cleanup;193 194 input_device->report_desc_size = le16_to_cpu(195 desc->desc[0].wDescriptorLength);196 if (input_device->report_desc_size == 0) {197 input_device->dev_info_status = -EINVAL;198 goto cleanup;199 }200 201 /* The pointer is not NULL when we resume from hibernation */202 kfree(input_device->report_desc);203 input_device->report_desc = kzalloc(input_device->report_desc_size,204 GFP_ATOMIC);205 206 if (!input_device->report_desc) {207 input_device->dev_info_status = -ENOMEM;208 goto cleanup;209 }210 211 memcpy(input_device->report_desc,212 ((unsigned char *)desc) + desc->bLength,213 le16_to_cpu(desc->desc[0].wDescriptorLength));214 215 /* Send the ack */216 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));217 218 ack.type = PIPE_MESSAGE_DATA;219 ack.size = sizeof(struct synthhid_device_info_ack);220 221 ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;222 ack.ack.header.size = 1;223 ack.ack.reserved = 0;224 225 ret = vmbus_sendpacket(input_device->device->channel,226 &ack,227 sizeof(struct pipe_prt_msg) +228 sizeof(struct synthhid_device_info_ack),229 (unsigned long)&ack,230 VM_PKT_DATA_INBAND,231 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);232 233 if (!ret)234 input_device->dev_info_status = 0;235 236cleanup:237 complete(&input_device->wait_event);238 239 return;240}241 242static void mousevsc_on_receive(struct hv_device *device,243 struct vmpacket_descriptor *packet)244{245 struct pipe_prt_msg *pipe_msg;246 struct synthhid_msg_hdr *hid_msg_hdr;247 struct mousevsc_dev *input_dev = hv_get_drvdata(device);248 struct synthhid_input_report *input_report;249 size_t len;250 251 pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +252 (packet->offset8 << 3));253 254 if (pipe_msg->type != PIPE_MESSAGE_DATA)255 return;256 257 hid_msg_hdr = (struct synthhid_msg_hdr *)pipe_msg->data;258 259 switch (hid_msg_hdr->type) {260 case SYNTH_HID_PROTOCOL_RESPONSE:261 len = struct_size(pipe_msg, data, pipe_msg->size);262 263 /*264 * While it will be impossible for us to protect against265 * malicious/buggy hypervisor/host, add a check here to266 * ensure we don't corrupt memory.267 */268 if (WARN_ON(len > sizeof(struct mousevsc_prt_msg)))269 break;270 271 memcpy(&input_dev->protocol_resp, pipe_msg, len);272 complete(&input_dev->wait_event);273 break;274 275 case SYNTH_HID_INITIAL_DEVICE_INFO:276 WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));277 278 /*279 * Parse out the device info into device attr,280 * hid desc and report desc281 */282 mousevsc_on_receive_device_info(input_dev,283 (struct synthhid_device_info *)pipe_msg->data);284 break;285 case SYNTH_HID_INPUT_REPORT:286 input_report =287 (struct synthhid_input_report *)pipe_msg->data;288 if (!input_dev->init_complete)289 break;290 291 len = min(input_report->header.size,292 (u32)sizeof(input_dev->input_buf));293 memcpy(input_dev->input_buf, input_report->buffer, len);294 hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,295 input_dev->input_buf, len, 1);296 297 pm_wakeup_hard_event(&input_dev->device->device);298 299 break;300 default:301 pr_err("unsupported hid msg type - type %d len %d\n",302 hid_msg_hdr->type, hid_msg_hdr->size);303 break;304 }305 306}307 308static void mousevsc_on_channel_callback(void *context)309{310 struct hv_device *device = context;311 struct vmpacket_descriptor *desc;312 313 foreach_vmbus_pkt(desc, device->channel) {314 switch (desc->type) {315 case VM_PKT_COMP:316 break;317 318 case VM_PKT_DATA_INBAND:319 mousevsc_on_receive(device, desc);320 break;321 322 default:323 pr_err("Unhandled packet type %d, tid %llx len %d\n",324 desc->type, desc->trans_id, desc->len8 * 8);325 break;326 }327 }328}329 330static int mousevsc_connect_to_vsp(struct hv_device *device)331{332 int ret = 0;333 unsigned long t;334 struct mousevsc_dev *input_dev = hv_get_drvdata(device);335 struct mousevsc_prt_msg *request;336 struct mousevsc_prt_msg *response;337 338 reinit_completion(&input_dev->wait_event);339 340 request = &input_dev->protocol_req;341 memset(request, 0, sizeof(struct mousevsc_prt_msg));342 343 request->type = PIPE_MESSAGE_DATA;344 request->size = sizeof(struct synthhid_protocol_request);345 request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;346 request->request.header.size = sizeof(unsigned int);347 request->request.version_requested.version = SYNTHHID_INPUT_VERSION;348 349 ret = vmbus_sendpacket(device->channel, request,350 sizeof(struct pipe_prt_msg) +351 sizeof(struct synthhid_protocol_request),352 (unsigned long)request,353 VM_PKT_DATA_INBAND,354 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);355 if (ret)356 goto cleanup;357 358 t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);359 if (!t) {360 ret = -ETIMEDOUT;361 goto cleanup;362 }363 364 response = &input_dev->protocol_resp;365 366 if (!response->response.approved) {367 pr_err("synthhid protocol request failed (version %d)\n",368 SYNTHHID_INPUT_VERSION);369 ret = -ENODEV;370 goto cleanup;371 }372 373 t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);374 if (!t) {375 ret = -ETIMEDOUT;376 goto cleanup;377 }378 379 /*380 * We should have gotten the device attr, hid desc and report381 * desc at this point382 */383 ret = input_dev->dev_info_status;384 385cleanup:386 return ret;387}388 389static int mousevsc_hid_parse(struct hid_device *hid)390{391 struct hv_device *dev = hid_get_drvdata(hid);392 struct mousevsc_dev *input_dev = hv_get_drvdata(dev);393 394 return hid_parse_report(hid, input_dev->report_desc,395 input_dev->report_desc_size);396}397 398static int mousevsc_hid_open(struct hid_device *hid)399{400 return 0;401}402 403static int mousevsc_hid_start(struct hid_device *hid)404{405 return 0;406}407 408static void mousevsc_hid_close(struct hid_device *hid)409{410}411 412static void mousevsc_hid_stop(struct hid_device *hid)413{414}415 416static int mousevsc_hid_raw_request(struct hid_device *hid,417 unsigned char report_num,418 __u8 *buf, size_t len,419 unsigned char rtype,420 int reqtype)421{422 return 0;423}424 425static const struct hid_ll_driver mousevsc_ll_driver = {426 .parse = mousevsc_hid_parse,427 .open = mousevsc_hid_open,428 .close = mousevsc_hid_close,429 .start = mousevsc_hid_start,430 .stop = mousevsc_hid_stop,431 .raw_request = mousevsc_hid_raw_request,432};433 434static struct hid_driver mousevsc_hid_driver;435 436static int mousevsc_probe(struct hv_device *device,437 const struct hv_vmbus_device_id *dev_id)438{439 int ret;440 struct mousevsc_dev *input_dev;441 struct hid_device *hid_dev;442 443 input_dev = mousevsc_alloc_device(device);444 445 if (!input_dev)446 return -ENOMEM;447 448 ret = vmbus_open(device->channel,449 INPUTVSC_SEND_RING_BUFFER_SIZE,450 INPUTVSC_RECV_RING_BUFFER_SIZE,451 NULL,452 0,453 mousevsc_on_channel_callback,454 device455 );456 457 if (ret)458 goto probe_err0;459 460 ret = mousevsc_connect_to_vsp(device);461 462 if (ret)463 goto probe_err1;464 465 /* workaround SA-167 */466 if (input_dev->report_desc[14] == 0x25)467 input_dev->report_desc[14] = 0x29;468 469 hid_dev = hid_allocate_device();470 if (IS_ERR(hid_dev)) {471 ret = PTR_ERR(hid_dev);472 goto probe_err1;473 }474 475 hid_dev->ll_driver = &mousevsc_ll_driver;476 hid_dev->driver = &mousevsc_hid_driver;477 hid_dev->bus = BUS_VIRTUAL;478 hid_dev->vendor = input_dev->hid_dev_info.vendor;479 hid_dev->product = input_dev->hid_dev_info.product;480 hid_dev->version = input_dev->hid_dev_info.version;481 input_dev->hid_device = hid_dev;482 483 sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");484 485 hid_set_drvdata(hid_dev, device);486 487 ret = hid_add_device(hid_dev);488 if (ret)489 goto probe_err2;490 491 492 ret = hid_parse(hid_dev);493 if (ret) {494 hid_err(hid_dev, "parse failed\n");495 goto probe_err2;496 }497 498 ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV);499 500 if (ret) {501 hid_err(hid_dev, "hw start failed\n");502 goto probe_err2;503 }504 505 device_init_wakeup(&device->device, true);506 507 input_dev->connected = true;508 input_dev->init_complete = true;509 510 return ret;511 512probe_err2:513 hid_destroy_device(hid_dev);514 515probe_err1:516 vmbus_close(device->channel);517 518probe_err0:519 mousevsc_free_device(input_dev);520 521 return ret;522}523 524 525static void mousevsc_remove(struct hv_device *dev)526{527 struct mousevsc_dev *input_dev = hv_get_drvdata(dev);528 529 device_init_wakeup(&dev->device, false);530 vmbus_close(dev->channel);531 hid_hw_stop(input_dev->hid_device);532 hid_destroy_device(input_dev->hid_device);533 mousevsc_free_device(input_dev);534}535 536static int mousevsc_suspend(struct hv_device *dev)537{538 vmbus_close(dev->channel);539 540 return 0;541}542 543static int mousevsc_resume(struct hv_device *dev)544{545 int ret;546 547 ret = vmbus_open(dev->channel,548 INPUTVSC_SEND_RING_BUFFER_SIZE,549 INPUTVSC_RECV_RING_BUFFER_SIZE,550 NULL, 0,551 mousevsc_on_channel_callback,552 dev);553 if (ret)554 return ret;555 556 ret = mousevsc_connect_to_vsp(dev);557 return ret;558}559 560static const struct hv_vmbus_device_id id_table[] = {561 /* Mouse guid */562 { HV_MOUSE_GUID, },563 { },564};565 566MODULE_DEVICE_TABLE(vmbus, id_table);567 568static struct hv_driver mousevsc_drv = {569 .name = KBUILD_MODNAME,570 .id_table = id_table,571 .probe = mousevsc_probe,572 .remove = mousevsc_remove,573 .suspend = mousevsc_suspend,574 .resume = mousevsc_resume,575 .driver = {576 .probe_type = PROBE_PREFER_ASYNCHRONOUS,577 },578};579 580static int __init mousevsc_init(void)581{582 return vmbus_driver_register(&mousevsc_drv);583}584 585static void __exit mousevsc_exit(void)586{587 vmbus_driver_unregister(&mousevsc_drv);588}589 590MODULE_LICENSE("GPL");591MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver");592 593module_init(mousevsc_init);594module_exit(mousevsc_exit);595