18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2009, Citrix Systems, Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2010, Microsoft Corporation. 58c2ecf20Sopenharmony_ci * Copyright (c) 2011, Novell Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/init.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/completion.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/hid.h> 138c2ecf20Sopenharmony_ci#include <linux/hiddev.h> 148c2ecf20Sopenharmony_ci#include <linux/hyperv.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct hv_input_dev_info { 188c2ecf20Sopenharmony_ci unsigned int size; 198c2ecf20Sopenharmony_ci unsigned short vendor; 208c2ecf20Sopenharmony_ci unsigned short product; 218c2ecf20Sopenharmony_ci unsigned short version; 228c2ecf20Sopenharmony_ci unsigned short reserved[11]; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* The maximum size of a synthetic input message. */ 268c2ecf20Sopenharmony_ci#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Current version 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * History: 328c2ecf20Sopenharmony_ci * Beta, RC < 2008/1/22 1,0 338c2ecf20Sopenharmony_ci * RC > 2008/1/22 2,0 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci#define SYNTHHID_INPUT_VERSION_MAJOR 2 368c2ecf20Sopenharmony_ci#define SYNTHHID_INPUT_VERSION_MINOR 0 378c2ecf20Sopenharmony_ci#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \ 388c2ecf20Sopenharmony_ci (SYNTHHID_INPUT_VERSION_MAJOR << 16)) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#pragma pack(push, 1) 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Message types in the synthetic input protocol 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cienum synthhid_msg_type { 468c2ecf20Sopenharmony_ci SYNTH_HID_PROTOCOL_REQUEST, 478c2ecf20Sopenharmony_ci SYNTH_HID_PROTOCOL_RESPONSE, 488c2ecf20Sopenharmony_ci SYNTH_HID_INITIAL_DEVICE_INFO, 498c2ecf20Sopenharmony_ci SYNTH_HID_INITIAL_DEVICE_INFO_ACK, 508c2ecf20Sopenharmony_ci SYNTH_HID_INPUT_REPORT, 518c2ecf20Sopenharmony_ci SYNTH_HID_MAX 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Basic message structures. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_cistruct synthhid_msg_hdr { 588c2ecf20Sopenharmony_ci enum synthhid_msg_type type; 598c2ecf20Sopenharmony_ci u32 size; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct synthhid_msg { 638c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 648c2ecf20Sopenharmony_ci char data[1]; /* Enclosed message */ 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciunion synthhid_version { 688c2ecf20Sopenharmony_ci struct { 698c2ecf20Sopenharmony_ci u16 minor_version; 708c2ecf20Sopenharmony_ci u16 major_version; 718c2ecf20Sopenharmony_ci }; 728c2ecf20Sopenharmony_ci u32 version; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Protocol messages 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistruct synthhid_protocol_request { 798c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 808c2ecf20Sopenharmony_ci union synthhid_version version_requested; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistruct synthhid_protocol_response { 848c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 858c2ecf20Sopenharmony_ci union synthhid_version version_requested; 868c2ecf20Sopenharmony_ci unsigned char approved; 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistruct synthhid_device_info { 908c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 918c2ecf20Sopenharmony_ci struct hv_input_dev_info hid_dev_info; 928c2ecf20Sopenharmony_ci struct hid_descriptor hid_descriptor; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct synthhid_device_info_ack { 968c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 978c2ecf20Sopenharmony_ci unsigned char reserved; 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct synthhid_input_report { 1018c2ecf20Sopenharmony_ci struct synthhid_msg_hdr header; 1028c2ecf20Sopenharmony_ci char buffer[1]; 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#pragma pack(pop) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define INPUTVSC_SEND_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024) 1088c2ecf20Sopenharmony_ci#define INPUTVSC_RECV_RING_BUFFER_SIZE VMBUS_RING_SIZE(36 * 1024) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cienum pipe_prot_msg_type { 1128c2ecf20Sopenharmony_ci PIPE_MESSAGE_INVALID, 1138c2ecf20Sopenharmony_ci PIPE_MESSAGE_DATA, 1148c2ecf20Sopenharmony_ci PIPE_MESSAGE_MAXIMUM 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistruct pipe_prt_msg { 1198c2ecf20Sopenharmony_ci enum pipe_prot_msg_type type; 1208c2ecf20Sopenharmony_ci u32 size; 1218c2ecf20Sopenharmony_ci char data[1]; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistruct mousevsc_prt_msg { 1258c2ecf20Sopenharmony_ci enum pipe_prot_msg_type type; 1268c2ecf20Sopenharmony_ci u32 size; 1278c2ecf20Sopenharmony_ci union { 1288c2ecf20Sopenharmony_ci struct synthhid_protocol_request request; 1298c2ecf20Sopenharmony_ci struct synthhid_protocol_response response; 1308c2ecf20Sopenharmony_ci struct synthhid_device_info_ack ack; 1318c2ecf20Sopenharmony_ci }; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* 1358c2ecf20Sopenharmony_ci * Represents an mousevsc device 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_cistruct mousevsc_dev { 1388c2ecf20Sopenharmony_ci struct hv_device *device; 1398c2ecf20Sopenharmony_ci bool init_complete; 1408c2ecf20Sopenharmony_ci bool connected; 1418c2ecf20Sopenharmony_ci struct mousevsc_prt_msg protocol_req; 1428c2ecf20Sopenharmony_ci struct mousevsc_prt_msg protocol_resp; 1438c2ecf20Sopenharmony_ci /* Synchronize the request/response if needed */ 1448c2ecf20Sopenharmony_ci struct completion wait_event; 1458c2ecf20Sopenharmony_ci int dev_info_status; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci struct hid_descriptor *hid_desc; 1488c2ecf20Sopenharmony_ci unsigned char *report_desc; 1498c2ecf20Sopenharmony_ci u32 report_desc_size; 1508c2ecf20Sopenharmony_ci struct hv_input_dev_info hid_dev_info; 1518c2ecf20Sopenharmony_ci struct hid_device *hid_device; 1528c2ecf20Sopenharmony_ci u8 input_buf[HID_MAX_BUFFER_SIZE]; 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic struct mousevsc_dev *mousevsc_alloc_device(struct hv_device *device) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!input_dev) 1638c2ecf20Sopenharmony_ci return NULL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci input_dev->device = device; 1668c2ecf20Sopenharmony_ci hv_set_drvdata(device, input_dev); 1678c2ecf20Sopenharmony_ci init_completion(&input_dev->wait_event); 1688c2ecf20Sopenharmony_ci input_dev->init_complete = false; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return input_dev; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void mousevsc_free_device(struct mousevsc_dev *device) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci kfree(device->hid_desc); 1768c2ecf20Sopenharmony_ci kfree(device->report_desc); 1778c2ecf20Sopenharmony_ci hv_set_drvdata(device->device, NULL); 1788c2ecf20Sopenharmony_ci kfree(device); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, 1828c2ecf20Sopenharmony_ci struct synthhid_device_info *device_info) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int ret = 0; 1858c2ecf20Sopenharmony_ci struct hid_descriptor *desc; 1868c2ecf20Sopenharmony_ci struct mousevsc_prt_msg ack; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci input_device->dev_info_status = -ENOMEM; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci input_device->hid_dev_info = device_info->hid_dev_info; 1918c2ecf20Sopenharmony_ci desc = &device_info->hid_descriptor; 1928c2ecf20Sopenharmony_ci if (desc->bLength == 0) 1938c2ecf20Sopenharmony_ci goto cleanup; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* The pointer is not NULL when we resume from hibernation */ 1968c2ecf20Sopenharmony_ci kfree(input_device->hid_desc); 1978c2ecf20Sopenharmony_ci input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!input_device->hid_desc) 2008c2ecf20Sopenharmony_ci goto cleanup; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci input_device->report_desc_size = desc->desc[0].wDescriptorLength; 2038c2ecf20Sopenharmony_ci if (input_device->report_desc_size == 0) { 2048c2ecf20Sopenharmony_ci input_device->dev_info_status = -EINVAL; 2058c2ecf20Sopenharmony_ci goto cleanup; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* The pointer is not NULL when we resume from hibernation */ 2098c2ecf20Sopenharmony_ci kfree(input_device->report_desc); 2108c2ecf20Sopenharmony_ci input_device->report_desc = kzalloc(input_device->report_desc_size, 2118c2ecf20Sopenharmony_ci GFP_ATOMIC); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!input_device->report_desc) { 2148c2ecf20Sopenharmony_ci input_device->dev_info_status = -ENOMEM; 2158c2ecf20Sopenharmony_ci goto cleanup; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci memcpy(input_device->report_desc, 2198c2ecf20Sopenharmony_ci ((unsigned char *)desc) + desc->bLength, 2208c2ecf20Sopenharmony_ci desc->desc[0].wDescriptorLength); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Send the ack */ 2238c2ecf20Sopenharmony_ci memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ack.type = PIPE_MESSAGE_DATA; 2268c2ecf20Sopenharmony_ci ack.size = sizeof(struct synthhid_device_info_ack); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK; 2298c2ecf20Sopenharmony_ci ack.ack.header.size = 1; 2308c2ecf20Sopenharmony_ci ack.ack.reserved = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci ret = vmbus_sendpacket(input_device->device->channel, 2338c2ecf20Sopenharmony_ci &ack, 2348c2ecf20Sopenharmony_ci sizeof(struct pipe_prt_msg) - sizeof(unsigned char) + 2358c2ecf20Sopenharmony_ci sizeof(struct synthhid_device_info_ack), 2368c2ecf20Sopenharmony_ci (unsigned long)&ack, 2378c2ecf20Sopenharmony_ci VM_PKT_DATA_INBAND, 2388c2ecf20Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (!ret) 2418c2ecf20Sopenharmony_ci input_device->dev_info_status = 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cicleanup: 2448c2ecf20Sopenharmony_ci complete(&input_device->wait_event); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void mousevsc_on_receive(struct hv_device *device, 2508c2ecf20Sopenharmony_ci struct vmpacket_descriptor *packet) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct pipe_prt_msg *pipe_msg; 2538c2ecf20Sopenharmony_ci struct synthhid_msg *hid_msg; 2548c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev = hv_get_drvdata(device); 2558c2ecf20Sopenharmony_ci struct synthhid_input_report *input_report; 2568c2ecf20Sopenharmony_ci size_t len; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet + 2598c2ecf20Sopenharmony_ci (packet->offset8 << 3)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (pipe_msg->type != PIPE_MESSAGE_DATA) 2628c2ecf20Sopenharmony_ci return; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci hid_msg = (struct synthhid_msg *)pipe_msg->data; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci switch (hid_msg->header.type) { 2678c2ecf20Sopenharmony_ci case SYNTH_HID_PROTOCOL_RESPONSE: 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * While it will be impossible for us to protect against 2708c2ecf20Sopenharmony_ci * malicious/buggy hypervisor/host, add a check here to 2718c2ecf20Sopenharmony_ci * ensure we don't corrupt memory. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci if ((pipe_msg->size + sizeof(struct pipe_prt_msg) 2748c2ecf20Sopenharmony_ci - sizeof(unsigned char)) 2758c2ecf20Sopenharmony_ci > sizeof(struct mousevsc_prt_msg)) { 2768c2ecf20Sopenharmony_ci WARN_ON(1); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci memcpy(&input_dev->protocol_resp, pipe_msg, 2818c2ecf20Sopenharmony_ci pipe_msg->size + sizeof(struct pipe_prt_msg) - 2828c2ecf20Sopenharmony_ci sizeof(unsigned char)); 2838c2ecf20Sopenharmony_ci complete(&input_dev->wait_event); 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci case SYNTH_HID_INITIAL_DEVICE_INFO: 2878c2ecf20Sopenharmony_ci WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* 2908c2ecf20Sopenharmony_ci * Parse out the device info into device attr, 2918c2ecf20Sopenharmony_ci * hid desc and report desc 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci mousevsc_on_receive_device_info(input_dev, 2948c2ecf20Sopenharmony_ci (struct synthhid_device_info *)pipe_msg->data); 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case SYNTH_HID_INPUT_REPORT: 2978c2ecf20Sopenharmony_ci input_report = 2988c2ecf20Sopenharmony_ci (struct synthhid_input_report *)pipe_msg->data; 2998c2ecf20Sopenharmony_ci if (!input_dev->init_complete) 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci len = min(input_report->header.size, 3038c2ecf20Sopenharmony_ci (u32)sizeof(input_dev->input_buf)); 3048c2ecf20Sopenharmony_ci memcpy(input_dev->input_buf, input_report->buffer, len); 3058c2ecf20Sopenharmony_ci hid_input_report(input_dev->hid_device, HID_INPUT_REPORT, 3068c2ecf20Sopenharmony_ci input_dev->input_buf, len, 1); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci pm_wakeup_hard_event(&input_dev->device->device); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci default: 3128c2ecf20Sopenharmony_ci pr_err("unsupported hid msg type - type %d len %d\n", 3138c2ecf20Sopenharmony_ci hid_msg->header.type, hid_msg->header.size); 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void mousevsc_on_channel_callback(void *context) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct hv_device *device = context; 3228c2ecf20Sopenharmony_ci struct vmpacket_descriptor *desc; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci foreach_vmbus_pkt(desc, device->channel) { 3258c2ecf20Sopenharmony_ci switch (desc->type) { 3268c2ecf20Sopenharmony_ci case VM_PKT_COMP: 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci case VM_PKT_DATA_INBAND: 3308c2ecf20Sopenharmony_ci mousevsc_on_receive(device, desc); 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci default: 3348c2ecf20Sopenharmony_ci pr_err("Unhandled packet type %d, tid %llx len %d\n", 3358c2ecf20Sopenharmony_ci desc->type, desc->trans_id, desc->len8 * 8); 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int mousevsc_connect_to_vsp(struct hv_device *device) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci int ret = 0; 3448c2ecf20Sopenharmony_ci unsigned long t; 3458c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev = hv_get_drvdata(device); 3468c2ecf20Sopenharmony_ci struct mousevsc_prt_msg *request; 3478c2ecf20Sopenharmony_ci struct mousevsc_prt_msg *response; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci reinit_completion(&input_dev->wait_event); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci request = &input_dev->protocol_req; 3528c2ecf20Sopenharmony_ci memset(request, 0, sizeof(struct mousevsc_prt_msg)); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci request->type = PIPE_MESSAGE_DATA; 3558c2ecf20Sopenharmony_ci request->size = sizeof(struct synthhid_protocol_request); 3568c2ecf20Sopenharmony_ci request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST; 3578c2ecf20Sopenharmony_ci request->request.header.size = sizeof(unsigned int); 3588c2ecf20Sopenharmony_ci request->request.version_requested.version = SYNTHHID_INPUT_VERSION; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci ret = vmbus_sendpacket(device->channel, request, 3618c2ecf20Sopenharmony_ci sizeof(struct pipe_prt_msg) - 3628c2ecf20Sopenharmony_ci sizeof(unsigned char) + 3638c2ecf20Sopenharmony_ci sizeof(struct synthhid_protocol_request), 3648c2ecf20Sopenharmony_ci (unsigned long)request, 3658c2ecf20Sopenharmony_ci VM_PKT_DATA_INBAND, 3668c2ecf20Sopenharmony_ci VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 3678c2ecf20Sopenharmony_ci if (ret) 3688c2ecf20Sopenharmony_ci goto cleanup; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); 3718c2ecf20Sopenharmony_ci if (!t) { 3728c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3738c2ecf20Sopenharmony_ci goto cleanup; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci response = &input_dev->protocol_resp; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!response->response.approved) { 3798c2ecf20Sopenharmony_ci pr_err("synthhid protocol request failed (version %d)\n", 3808c2ecf20Sopenharmony_ci SYNTHHID_INPUT_VERSION); 3818c2ecf20Sopenharmony_ci ret = -ENODEV; 3828c2ecf20Sopenharmony_ci goto cleanup; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ); 3868c2ecf20Sopenharmony_ci if (!t) { 3878c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 3888c2ecf20Sopenharmony_ci goto cleanup; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * We should have gotten the device attr, hid desc and report 3938c2ecf20Sopenharmony_ci * desc at this point 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci ret = input_dev->dev_info_status; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cicleanup: 3988c2ecf20Sopenharmony_ci return ret; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int mousevsc_hid_parse(struct hid_device *hid) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct hv_device *dev = hid_get_drvdata(hid); 4048c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev = hv_get_drvdata(dev); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return hid_parse_report(hid, input_dev->report_desc, 4078c2ecf20Sopenharmony_ci input_dev->report_desc_size); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int mousevsc_hid_open(struct hid_device *hid) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci return 0; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int mousevsc_hid_start(struct hid_device *hid) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void mousevsc_hid_close(struct hid_device *hid) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic void mousevsc_hid_stop(struct hid_device *hid) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int mousevsc_hid_raw_request(struct hid_device *hid, 4298c2ecf20Sopenharmony_ci unsigned char report_num, 4308c2ecf20Sopenharmony_ci __u8 *buf, size_t len, 4318c2ecf20Sopenharmony_ci unsigned char rtype, 4328c2ecf20Sopenharmony_ci int reqtype) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic struct hid_ll_driver mousevsc_ll_driver = { 4388c2ecf20Sopenharmony_ci .parse = mousevsc_hid_parse, 4398c2ecf20Sopenharmony_ci .open = mousevsc_hid_open, 4408c2ecf20Sopenharmony_ci .close = mousevsc_hid_close, 4418c2ecf20Sopenharmony_ci .start = mousevsc_hid_start, 4428c2ecf20Sopenharmony_ci .stop = mousevsc_hid_stop, 4438c2ecf20Sopenharmony_ci .raw_request = mousevsc_hid_raw_request, 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic struct hid_driver mousevsc_hid_driver; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int mousevsc_probe(struct hv_device *device, 4498c2ecf20Sopenharmony_ci const struct hv_vmbus_device_id *dev_id) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int ret; 4528c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev; 4538c2ecf20Sopenharmony_ci struct hid_device *hid_dev; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci input_dev = mousevsc_alloc_device(device); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!input_dev) 4588c2ecf20Sopenharmony_ci return -ENOMEM; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci ret = vmbus_open(device->channel, 4618c2ecf20Sopenharmony_ci INPUTVSC_SEND_RING_BUFFER_SIZE, 4628c2ecf20Sopenharmony_ci INPUTVSC_RECV_RING_BUFFER_SIZE, 4638c2ecf20Sopenharmony_ci NULL, 4648c2ecf20Sopenharmony_ci 0, 4658c2ecf20Sopenharmony_ci mousevsc_on_channel_callback, 4668c2ecf20Sopenharmony_ci device 4678c2ecf20Sopenharmony_ci ); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci goto probe_err0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = mousevsc_connect_to_vsp(device); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (ret) 4758c2ecf20Sopenharmony_ci goto probe_err1; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* workaround SA-167 */ 4788c2ecf20Sopenharmony_ci if (input_dev->report_desc[14] == 0x25) 4798c2ecf20Sopenharmony_ci input_dev->report_desc[14] = 0x29; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci hid_dev = hid_allocate_device(); 4828c2ecf20Sopenharmony_ci if (IS_ERR(hid_dev)) { 4838c2ecf20Sopenharmony_ci ret = PTR_ERR(hid_dev); 4848c2ecf20Sopenharmony_ci goto probe_err1; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci hid_dev->ll_driver = &mousevsc_ll_driver; 4888c2ecf20Sopenharmony_ci hid_dev->driver = &mousevsc_hid_driver; 4898c2ecf20Sopenharmony_ci hid_dev->bus = BUS_VIRTUAL; 4908c2ecf20Sopenharmony_ci hid_dev->vendor = input_dev->hid_dev_info.vendor; 4918c2ecf20Sopenharmony_ci hid_dev->product = input_dev->hid_dev_info.product; 4928c2ecf20Sopenharmony_ci hid_dev->version = input_dev->hid_dev_info.version; 4938c2ecf20Sopenharmony_ci input_dev->hid_device = hid_dev; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse"); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci hid_set_drvdata(hid_dev, device); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ret = hid_add_device(hid_dev); 5008c2ecf20Sopenharmony_ci if (ret) 5018c2ecf20Sopenharmony_ci goto probe_err2; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci ret = hid_parse(hid_dev); 5058c2ecf20Sopenharmony_ci if (ret) { 5068c2ecf20Sopenharmony_ci hid_err(hid_dev, "parse failed\n"); 5078c2ecf20Sopenharmony_ci goto probe_err2; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (ret) { 5138c2ecf20Sopenharmony_ci hid_err(hid_dev, "hw start failed\n"); 5148c2ecf20Sopenharmony_ci goto probe_err2; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci device_init_wakeup(&device->device, true); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci input_dev->connected = true; 5208c2ecf20Sopenharmony_ci input_dev->init_complete = true; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return ret; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ciprobe_err2: 5258c2ecf20Sopenharmony_ci hid_destroy_device(hid_dev); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ciprobe_err1: 5288c2ecf20Sopenharmony_ci vmbus_close(device->channel); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ciprobe_err0: 5318c2ecf20Sopenharmony_ci mousevsc_free_device(input_dev); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return ret; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic int mousevsc_remove(struct hv_device *dev) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct mousevsc_dev *input_dev = hv_get_drvdata(dev); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci device_init_wakeup(&dev->device, false); 5428c2ecf20Sopenharmony_ci vmbus_close(dev->channel); 5438c2ecf20Sopenharmony_ci hid_hw_stop(input_dev->hid_device); 5448c2ecf20Sopenharmony_ci hid_destroy_device(input_dev->hid_device); 5458c2ecf20Sopenharmony_ci mousevsc_free_device(input_dev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int mousevsc_suspend(struct hv_device *dev) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci vmbus_close(dev->channel); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int mousevsc_resume(struct hv_device *dev) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci int ret; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci ret = vmbus_open(dev->channel, 5628c2ecf20Sopenharmony_ci INPUTVSC_SEND_RING_BUFFER_SIZE, 5638c2ecf20Sopenharmony_ci INPUTVSC_RECV_RING_BUFFER_SIZE, 5648c2ecf20Sopenharmony_ci NULL, 0, 5658c2ecf20Sopenharmony_ci mousevsc_on_channel_callback, 5668c2ecf20Sopenharmony_ci dev); 5678c2ecf20Sopenharmony_ci if (ret) 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ret = mousevsc_connect_to_vsp(dev); 5718c2ecf20Sopenharmony_ci return ret; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic const struct hv_vmbus_device_id id_table[] = { 5758c2ecf20Sopenharmony_ci /* Mouse guid */ 5768c2ecf20Sopenharmony_ci { HV_MOUSE_GUID, }, 5778c2ecf20Sopenharmony_ci { }, 5788c2ecf20Sopenharmony_ci}; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vmbus, id_table); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic struct hv_driver mousevsc_drv = { 5838c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 5848c2ecf20Sopenharmony_ci .id_table = id_table, 5858c2ecf20Sopenharmony_ci .probe = mousevsc_probe, 5868c2ecf20Sopenharmony_ci .remove = mousevsc_remove, 5878c2ecf20Sopenharmony_ci .suspend = mousevsc_suspend, 5888c2ecf20Sopenharmony_ci .resume = mousevsc_resume, 5898c2ecf20Sopenharmony_ci .driver = { 5908c2ecf20Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 5918c2ecf20Sopenharmony_ci }, 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int __init mousevsc_init(void) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci return vmbus_driver_register(&mousevsc_drv); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void __exit mousevsc_exit(void) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci vmbus_driver_unregister(&mousevsc_drv); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver"); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cimodule_init(mousevsc_init); 6088c2ecf20Sopenharmony_cimodule_exit(mousevsc_exit); 609