blob: ebd17150d6c3a7cff063a16063cc413dce9aa2c5 [file] [log] [blame]
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -08001/*
Greg Kroah-Hartman9b9f93d2011-03-02 17:49:30 -08002 * Copyright (c) 2009, Citrix Systems, Inc.
3 * Copyright (c) 2010, Microsoft Corporation.
4 * Copyright (c) 2011, Novell Inc.
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -08005 *
Greg Kroah-Hartman9b9f93d2011-03-02 17:49:30 -08006 * 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.
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -08009 *
Greg Kroah-Hartman9b9f93d2011-03-02 17:49:30 -080010 * 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.
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -080014 */
15#include <linux/init.h>
16#include <linux/module.h>
Randy Dunlapa58c6162011-04-01 09:50:54 -070017#include <linux/delay.h>
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -080018#include <linux/device.h>
19#include <linux/workqueue.h>
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -080020#include <linux/sched.h>
21#include <linux/wait.h>
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -080022#include <linux/input.h>
23#include <linux/hid.h>
24#include <linux/hiddev.h>
25#include <linux/pci.h>
26#include <linux/dmi.h>
27
K. Y. Srinivasan3f335ea2011-05-12 19:34:15 -070028#include "hyperv.h"
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080029
30
Greg Kroah-Hartman94fcc882011-03-02 17:57:51 -080031/*
32 * Data types
33 */
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -080034struct hv_input_dev_info {
35 unsigned short vendor;
36 unsigned short product;
37 unsigned short version;
38 char name[128];
Greg Kroah-Hartman94fcc882011-03-02 17:57:51 -080039};
40
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080041/* The maximum size of a synthetic input message. */
42#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
43
44/*
45 * Current version
46 *
47 * History:
48 * Beta, RC < 2008/1/22 1,0
49 * RC > 2008/1/22 2,0
50 */
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -080051#define SYNTHHID_INPUT_VERSION_MAJOR 2
52#define SYNTHHID_INPUT_VERSION_MINOR 0
53#define SYNTHHID_INPUT_VERSION (SYNTHHID_INPUT_VERSION_MINOR | \
54 (SYNTHHID_INPUT_VERSION_MAJOR << 16))
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080055
56
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +030057#pragma pack(push, 1)
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080058/*
59 * Message types in the synthetic input protocol
60 */
61enum synthhid_msg_type {
62 SynthHidProtocolRequest,
63 SynthHidProtocolResponse,
64 SynthHidInitialDeviceInfo,
65 SynthHidInitialDeviceInfoAck,
66 SynthHidInputReport,
67 SynthHidMax
68};
69
70/*
71 * Basic message structures.
72 */
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080073struct synthhid_msg_hdr {
Greg Kroah-Hartman32ad38f2011-03-02 19:01:49 -080074 enum synthhid_msg_type type;
75 u32 size;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080076};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080077
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080078struct synthhid_msg {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -080079 struct synthhid_msg_hdr header;
Greg Kroah-Hartmancb2535a2011-03-02 19:11:49 -080080 char data[1]; /* Enclosed message */
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080081};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080082
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080083union synthhid_version {
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080084 struct {
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -080085 u16 minor_version;
86 u16 major_version;
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080087 };
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -080088 u32 version;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080089};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080090
91/*
92 * Protocol messages
93 */
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080094struct synthhid_protocol_request {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -080095 struct synthhid_msg_hdr header;
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -080096 union synthhid_version version_requested;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080097};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -080098
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -080099struct synthhid_protocol_response {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -0800100 struct synthhid_msg_hdr header;
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -0800101 union synthhid_version version_requested;
Greg Kroah-Hartman325eae12011-03-02 19:19:58 -0800102 unsigned char approved;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800103};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -0800104
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800105struct synthhid_device_info {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -0800106 struct synthhid_msg_hdr header;
Greg Kroah-Hartman98ad91e2011-03-02 19:24:05 -0800107 struct hv_input_dev_info hid_dev_info;
Greg Kroah-Hartman18bc44e2011-03-02 19:27:17 -0800108 struct hid_descriptor hid_descriptor;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800109};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -0800110
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800111struct synthhid_device_info_ack {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -0800112 struct synthhid_msg_hdr header;
Greg Kroah-Hartman6ed10de2011-03-02 19:29:42 -0800113 unsigned char reserved;
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800114};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -0800115
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800116struct synthhid_input_report {
Greg Kroah-Hartman0ce815d2011-03-02 19:04:09 -0800117 struct synthhid_msg_hdr header;
Greg Kroah-Hartmane93eff92011-03-02 19:31:39 -0800118 char buffer[1];
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800119};
Greg Kroah-Hartmanfa003502011-03-02 17:53:58 -0800120
121#pragma pack(pop)
122
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +0300123#define INPUTVSC_SEND_RING_BUFFER_SIZE (10*PAGE_SIZE)
124#define INPUTVSC_RECV_RING_BUFFER_SIZE (10*PAGE_SIZE)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800125
126#define NBITS(x) (((x)/BITS_PER_LONG)+1)
127
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800128enum pipe_prot_msg_type {
129 PipeMessageInvalid = 0,
130 PipeMessageData,
131 PipeMessageMaximum
132};
133
134
135struct pipe_prt_msg {
Greg Kroah-Hartman2012d402011-03-02 19:36:15 -0800136 enum pipe_prot_msg_type type;
Greg Kroah-Hartman9877fa42011-03-02 19:38:29 -0800137 u32 size;
Greg Kroah-Hartmane7de0ad2011-03-02 19:39:48 -0800138 char data[1];
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800139};
140
141/*
142 * Data types
143 */
144struct mousevsc_prt_msg {
Greg Kroah-Hartman2012d402011-03-02 19:36:15 -0800145 enum pipe_prot_msg_type type;
Greg Kroah-Hartman9877fa42011-03-02 19:38:29 -0800146 u32 size;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800147 union {
Greg Kroah-Hartman5ff9b902011-03-02 19:41:00 -0800148 struct synthhid_protocol_request request;
149 struct synthhid_protocol_response response;
150 struct synthhid_device_info_ack ack;
Greg Kroah-Hartmand7fa1a42011-03-02 19:33:17 -0800151 };
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800152};
153
154/*
155 * Represents an mousevsc device
156 */
157struct mousevsc_dev {
Hank Janssenac41d402011-04-01 14:32:13 -0700158 struct hv_device *device;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800159 /* 0 indicates the device is being destroyed */
Hank Janssenac41d402011-04-01 14:32:13 -0700160 atomic_t ref_count;
161 int num_outstanding_req;
162 unsigned char init_complete;
163 struct mousevsc_prt_msg protocol_req;
164 struct mousevsc_prt_msg protocol_resp;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800165 /* Synchronize the request/response if needed */
Hank Janssenac41d402011-04-01 14:32:13 -0700166 wait_queue_head_t protocol_wait_event;
167 wait_queue_head_t dev_info_wait_event;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800168 int protocol_wait_condition;
169 int device_wait_condition;
Hank Janssenac41d402011-04-01 14:32:13 -0700170 int dev_info_status;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800171
Hank Janssenac41d402011-04-01 14:32:13 -0700172 struct hid_descriptor *hid_desc;
173 unsigned char *report_desc;
174 u32 report_desc_size;
Greg Kroah-Hartman98ad91e2011-03-02 19:24:05 -0800175 struct hv_input_dev_info hid_dev_info;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800176};
177
178
Greg Kroah-Hartman92d40b72011-03-02 19:42:19 -0800179static const char *driver_name = "mousevsc";
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800180
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800181static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info *info);
Greg Kroah-Hartman4f143132011-03-02 18:38:31 -0800182static void inputreport_callback(struct hv_device *dev, void *packet, u32 len);
183static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len);
184
Hank Janssen2ba68102011-04-01 14:32:11 -0700185static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800186{
Hank Janssenc0765e92011-04-01 14:32:14 -0700187 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800188
Hank Janssenc0765e92011-04-01 14:32:14 -0700189 input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800190
Hank Janssenc0765e92011-04-01 14:32:14 -0700191 if (!input_dev)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800192 return NULL;
193
194 /*
195 * Set to 2 to allow both inbound and outbound traffics
Hank Janssen94e44cb2011-04-01 14:32:10 -0700196 * (ie get_input_device() and must_get_input_device()) to proceed.
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800197 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700198 atomic_cmpxchg(&input_dev->ref_count, 0, 2);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800199
Hank Janssenc0765e92011-04-01 14:32:14 -0700200 input_dev->device = device;
201 device->ext = input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800202
Hank Janssenc0765e92011-04-01 14:32:14 -0700203 return input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800204}
205
Hank Janssen2ba68102011-04-01 14:32:11 -0700206static void free_input_device(struct mousevsc_dev *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800207{
Hank Janssenac41d402011-04-01 14:32:13 -0700208 WARN_ON(atomic_read(&device->ref_count) == 0);
Hank Janssen2ba68102011-04-01 14:32:11 -0700209 kfree(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800210}
211
212/*
213 * Get the inputdevice object if exists and its refcount > 1
214 */
Hank Janssen2ba68102011-04-01 14:32:11 -0700215static struct mousevsc_dev *get_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800216{
Hank Janssenc0765e92011-04-01 14:32:14 -0700217 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800218
Hank Janssenc0765e92011-04-01 14:32:14 -0700219 input_dev = (struct mousevsc_dev *)device->ext;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800220
221/*
222 * FIXME
223 * This sure isn't a valid thing to print for debugging, no matter
224 * what the intention is...
225 *
226 * printk(KERN_ERR "-------------------------> REFCOUNT = %d",
Hank Janssenc0765e92011-04-01 14:32:14 -0700227 * input_dev->ref_count);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800228 */
229
Hank Janssenc0765e92011-04-01 14:32:14 -0700230 if (input_dev && atomic_read(&input_dev->ref_count) > 1)
231 atomic_inc(&input_dev->ref_count);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800232 else
Hank Janssenc0765e92011-04-01 14:32:14 -0700233 input_dev = NULL;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800234
Hank Janssenc0765e92011-04-01 14:32:14 -0700235 return input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800236}
237
238/*
239 * Get the inputdevice object iff exists and its refcount > 0
240 */
Hank Janssen2ba68102011-04-01 14:32:11 -0700241static struct mousevsc_dev *must_get_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800242{
Hank Janssenc0765e92011-04-01 14:32:14 -0700243 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800244
Hank Janssenc0765e92011-04-01 14:32:14 -0700245 input_dev = (struct mousevsc_dev *)device->ext;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800246
Hank Janssenc0765e92011-04-01 14:32:14 -0700247 if (input_dev && atomic_read(&input_dev->ref_count))
248 atomic_inc(&input_dev->ref_count);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800249 else
Hank Janssenc0765e92011-04-01 14:32:14 -0700250 input_dev = NULL;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800251
Hank Janssenc0765e92011-04-01 14:32:14 -0700252 return input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800253}
254
Hank Janssen2ba68102011-04-01 14:32:11 -0700255static void put_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800256{
Hank Janssenc0765e92011-04-01 14:32:14 -0700257 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800258
Hank Janssenc0765e92011-04-01 14:32:14 -0700259 input_dev = (struct mousevsc_dev *)device->ext;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800260
Hank Janssenc0765e92011-04-01 14:32:14 -0700261 atomic_dec(&input_dev->ref_count);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800262}
263
264/*
Hank Janssen94e44cb2011-04-01 14:32:10 -0700265 * Drop ref count to 1 to effectively disable get_input_device()
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800266 */
Hank Janssen2ba68102011-04-01 14:32:11 -0700267static struct mousevsc_dev *release_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800268{
Hank Janssenc0765e92011-04-01 14:32:14 -0700269 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800270
Hank Janssenc0765e92011-04-01 14:32:14 -0700271 input_dev = (struct mousevsc_dev *)device->ext;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800272
273 /* Busy wait until the ref drop to 2, then set it to 1 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700274 while (atomic_cmpxchg(&input_dev->ref_count, 2, 1) != 2)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800275 udelay(100);
276
Hank Janssenc0765e92011-04-01 14:32:14 -0700277 return input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800278}
279
280/*
Hank Janssen2ba68102011-04-01 14:32:11 -0700281 * Drop ref count to 0. No one can use input_device object.
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800282 */
Hank Janssen2ba68102011-04-01 14:32:11 -0700283static struct mousevsc_dev *final_release_input_device(struct hv_device *device)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800284{
Hank Janssenc0765e92011-04-01 14:32:14 -0700285 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800286
Hank Janssenc0765e92011-04-01 14:32:14 -0700287 input_dev = (struct mousevsc_dev *)device->ext;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800288
289 /* Busy wait until the ref drop to 1, then set it to 0 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700290 while (atomic_cmpxchg(&input_dev->ref_count, 1, 0) != 1)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800291 udelay(100);
292
Hank Janssen2ba68102011-04-01 14:32:11 -0700293 device->ext = NULL;
Hank Janssenc0765e92011-04-01 14:32:14 -0700294 return input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800295}
296
Hank Janssen2ba68102011-04-01 14:32:11 -0700297static void mousevsc_on_send_completion(struct hv_device *device,
298 struct vmpacket_descriptor *packet)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800299{
Hank Janssenc0765e92011-04-01 14:32:14 -0700300 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800301 void *request;
302
Hank Janssenc0765e92011-04-01 14:32:14 -0700303 input_dev = must_get_input_device(device);
304 if (!input_dev) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800305 pr_err("unable to get input device...device being destroyed?");
306 return;
307 }
308
Hank Janssen2ba68102011-04-01 14:32:11 -0700309 request = (void *)(unsigned long)packet->trans_id;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800310
Hank Janssenc0765e92011-04-01 14:32:14 -0700311 if (request == &input_dev->protocol_req) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800312 /* FIXME */
313 /* Shouldn't we be doing something here? */
314 }
315
Hank Janssen2ba68102011-04-01 14:32:11 -0700316 put_input_device(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800317}
318
Hank Janssen2ba68102011-04-01 14:32:11 -0700319static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
320 struct synthhid_device_info *device_info)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800321{
322 int ret = 0;
323 struct hid_descriptor *desc;
324 struct mousevsc_prt_msg ack;
325
326 /* Assume success for now */
Hank Janssenac41d402011-04-01 14:32:13 -0700327 input_device->dev_info_status = 0;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800328
329 /* Save the device attr */
Hank Janssen2ba68102011-04-01 14:32:11 -0700330 memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
331 sizeof(struct hv_input_dev_info));
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800332
333 /* Save the hid desc */
Hank Janssen2ba68102011-04-01 14:32:11 -0700334 desc = &device_info->hid_descriptor;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800335 WARN_ON(desc->bLength > 0);
336
Hank Janssenac41d402011-04-01 14:32:13 -0700337 input_device->hid_desc = kzalloc(desc->bLength, GFP_KERNEL);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800338
Hank Janssenac41d402011-04-01 14:32:13 -0700339 if (!input_device->hid_desc) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800340 pr_err("unable to allocate hid descriptor - size %d", desc->bLength);
341 goto Cleanup;
342 }
343
Hank Janssenac41d402011-04-01 14:32:13 -0700344 memcpy(input_device->hid_desc, desc, desc->bLength);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800345
346 /* Save the report desc */
Hank Janssenac41d402011-04-01 14:32:13 -0700347 input_device->report_desc_size = desc->desc[0].wDescriptorLength;
348 input_device->report_desc = kzalloc(input_device->report_desc_size,
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800349 GFP_KERNEL);
350
Hank Janssenac41d402011-04-01 14:32:13 -0700351 if (!input_device->report_desc) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800352 pr_err("unable to allocate report descriptor - size %d",
Hank Janssenac41d402011-04-01 14:32:13 -0700353 input_device->report_desc_size);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800354 goto Cleanup;
355 }
356
Hank Janssenac41d402011-04-01 14:32:13 -0700357 memcpy(input_device->report_desc,
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800358 ((unsigned char *)desc) + desc->bLength,
359 desc->desc[0].wDescriptorLength);
360
361 /* Send the ack */
Dave Jones75e4fb22011-03-16 21:40:59 -0400362 memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800363
Greg Kroah-Hartman2012d402011-03-02 19:36:15 -0800364 ack.type = PipeMessageData;
Greg Kroah-Hartman9877fa42011-03-02 19:38:29 -0800365 ack.size = sizeof(struct synthhid_device_info_ack);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800366
Greg Kroah-Hartman5ff9b902011-03-02 19:41:00 -0800367 ack.ack.header.type = SynthHidInitialDeviceInfoAck;
368 ack.ack.header.size = 1;
369 ack.ack.reserved = 0;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800370
Hank Janssenac41d402011-04-01 14:32:13 -0700371 ret = vmbus_sendpacket(input_device->device->channel,
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800372 &ack,
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800373 sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
374 sizeof(struct synthhid_device_info_ack),
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800375 (unsigned long)&ack,
376 VM_PKT_DATA_INBAND,
377 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
378 if (ret != 0) {
Greg Kroah-Hartmane6f83b72011-03-02 18:21:01 -0800379 pr_err("unable to send synthhid device info ack - ret %d",
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800380 ret);
381 goto Cleanup;
382 }
383
Hank Janssen2ba68102011-04-01 14:32:11 -0700384 input_device->device_wait_condition = 1;
Hank Janssenac41d402011-04-01 14:32:13 -0700385 wake_up(&input_device->dev_info_wait_event);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800386
387 return;
388
389Cleanup:
Hank Janssenac41d402011-04-01 14:32:13 -0700390 kfree(input_device->hid_desc);
391 input_device->hid_desc = NULL;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800392
Hank Janssenac41d402011-04-01 14:32:13 -0700393 kfree(input_device->report_desc);
394 input_device->report_desc = NULL;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800395
Hank Janssenac41d402011-04-01 14:32:13 -0700396 input_device->dev_info_status = -1;
Hank Janssen2ba68102011-04-01 14:32:11 -0700397 input_device->device_wait_condition = 1;
Hank Janssenac41d402011-04-01 14:32:13 -0700398 wake_up(&input_device->dev_info_wait_event);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800399}
400
Hank Janssen2ba68102011-04-01 14:32:11 -0700401static void mousevsc_on_receive_input_report(struct mousevsc_dev *input_device,
402 struct synthhid_input_report *input_report)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800403{
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700404 struct hv_driver *input_drv;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800405
Hank Janssenac41d402011-04-01 14:32:13 -0700406 if (!input_device->init_complete) {
Hank Janssen2ba68102011-04-01 14:32:11 -0700407 pr_info("Initialization incomplete...ignoring input_report msg");
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800408 return;
409 }
410
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700411 input_drv = drv_to_hv_drv(input_device->device->device.driver);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800412
Hank Janssenac41d402011-04-01 14:32:13 -0700413 inputreport_callback(input_device->device,
Hank Janssen2ba68102011-04-01 14:32:11 -0700414 input_report->buffer,
415 input_report->header.size);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800416}
417
Hank Janssen2ba68102011-04-01 14:32:11 -0700418static void mousevsc_on_receive(struct hv_device *device,
419 struct vmpacket_descriptor *packet)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800420{
Hank Janssenc0765e92011-04-01 14:32:14 -0700421 struct pipe_prt_msg *pipe_msg;
422 struct synthhid_msg *hid_msg;
423 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800424
Hank Janssenc0765e92011-04-01 14:32:14 -0700425 input_dev = must_get_input_device(device);
426 if (!input_dev) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800427 pr_err("unable to get input device...device being destroyed?");
428 return;
429 }
430
Hank Janssenc0765e92011-04-01 14:32:14 -0700431 pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
Hank Janssen2ba68102011-04-01 14:32:11 -0700432 (packet->offset8 << 3));
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800433
Hank Janssenc0765e92011-04-01 14:32:14 -0700434 if (pipe_msg->type != PipeMessageData) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800435 pr_err("unknown pipe msg type - type %d len %d",
Hank Janssenc0765e92011-04-01 14:32:14 -0700436 pipe_msg->type, pipe_msg->size);
Hank Janssen2ba68102011-04-01 14:32:11 -0700437 put_input_device(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800438 return ;
439 }
440
Hank Janssenc0765e92011-04-01 14:32:14 -0700441 hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800442
Hank Janssenc0765e92011-04-01 14:32:14 -0700443 switch (hid_msg->header.type) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800444 case SynthHidProtocolResponse:
Hank Janssenc0765e92011-04-01 14:32:14 -0700445 memcpy(&input_dev->protocol_resp, pipe_msg,
446 pipe_msg->size + sizeof(struct pipe_prt_msg) -
Greg Kroah-Hartman9877fa42011-03-02 19:38:29 -0800447 sizeof(unsigned char));
Hank Janssenc0765e92011-04-01 14:32:14 -0700448 input_dev->protocol_wait_condition = 1;
449 wake_up(&input_dev->protocol_wait_event);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800450 break;
451
452 case SynthHidInitialDeviceInfo:
Hank Janssenc0765e92011-04-01 14:32:14 -0700453 WARN_ON(pipe_msg->size >= sizeof(struct hv_input_dev_info));
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800454
455 /*
456 * Parse out the device info into device attr,
457 * hid desc and report desc
458 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700459 mousevsc_on_receive_device_info(input_dev,
460 (struct synthhid_device_info *)&pipe_msg->data[0]);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800461 break;
462 case SynthHidInputReport:
Hank Janssenc0765e92011-04-01 14:32:14 -0700463 mousevsc_on_receive_input_report(input_dev,
464 (struct synthhid_input_report *)&pipe_msg->data[0]);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800465
466 break;
467 default:
468 pr_err("unsupported hid msg type - type %d len %d",
Hank Janssenc0765e92011-04-01 14:32:14 -0700469 hid_msg->header.type, hid_msg->header.size);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800470 break;
471 }
472
Hank Janssen2ba68102011-04-01 14:32:11 -0700473 put_input_device(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800474}
475
Hank Janssen2ba68102011-04-01 14:32:11 -0700476static void mousevsc_on_channel_callback(void *context)
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800477{
478 const int packetSize = 0x100;
479 int ret = 0;
Hank Janssen2ba68102011-04-01 14:32:11 -0700480 struct hv_device *device = (struct hv_device *)context;
Hank Janssenc0765e92011-04-01 14:32:14 -0700481 struct mousevsc_dev *input_dev;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800482
Hank Janssenc0765e92011-04-01 14:32:14 -0700483 u32 bytes_recvd;
484 u64 req_id;
K. Y. Srinivasan459bce92011-05-12 19:34:43 -0700485 unsigned char packet[0x100];
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800486 struct vmpacket_descriptor *desc;
487 unsigned char *buffer = packet;
488 int bufferlen = packetSize;
489
Hank Janssenc0765e92011-04-01 14:32:14 -0700490 input_dev = must_get_input_device(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800491
Hank Janssenc0765e92011-04-01 14:32:14 -0700492 if (!input_dev) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800493 pr_err("unable to get input device...device being destroyed?");
494 return;
495 }
496
497 do {
Hank Janssenc0765e92011-04-01 14:32:14 -0700498 ret = vmbus_recvpacket_raw(device->channel, buffer,
499 bufferlen, &bytes_recvd, &req_id);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800500
501 if (ret == 0) {
Hank Janssenc0765e92011-04-01 14:32:14 -0700502 if (bytes_recvd > 0) {
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800503 desc = (struct vmpacket_descriptor *)buffer;
504
505 switch (desc->type) {
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +0300506 case VM_PKT_COMP:
507 mousevsc_on_send_completion(
508 device, desc);
509 break;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800510
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +0300511 case VM_PKT_DATA_INBAND:
512 mousevsc_on_receive(
513 device, desc);
514 break;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800515
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +0300516 default:
517 pr_err("unhandled packet type %d, tid %llx len %d\n",
518 desc->type,
519 req_id,
520 bytes_recvd);
521 break;
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800522 }
523
524 /* reset */
525 if (bufferlen > packetSize) {
526 kfree(buffer);
527
528 buffer = packet;
529 bufferlen = packetSize;
530 }
531 } else {
532 /*
533 * pr_debug("nothing else to read...");
534 * reset
535 */
536 if (bufferlen > packetSize) {
537 kfree(buffer);
538
539 buffer = packet;
540 bufferlen = packetSize;
541 }
542 break;
543 }
544 } else if (ret == -2) {
545 /* Handle large packet */
Hank Janssenc0765e92011-04-01 14:32:14 -0700546 bufferlen = bytes_recvd;
547 buffer = kzalloc(bytes_recvd, GFP_KERNEL);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800548
549 if (buffer == NULL) {
550 buffer = packet;
551 bufferlen = packetSize;
552
553 /* Try again next time around */
554 pr_err("unable to allocate buffer of size %d!",
Hank Janssenc0765e92011-04-01 14:32:14 -0700555 bytes_recvd);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800556 break;
557 }
558 }
559 } while (1);
560
Hank Janssen94e44cb2011-04-01 14:32:10 -0700561 put_input_device(device);
Greg Kroah-Hartman9dccaa62011-03-02 17:42:50 -0800562
563 return;
564}
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800565
Hank Janssen2ba68102011-04-01 14:32:11 -0700566static int mousevsc_connect_to_vsp(struct hv_device *device)
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800567{
568 int ret = 0;
Hank Janssenc0765e92011-04-01 14:32:14 -0700569 struct mousevsc_dev *input_dev;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800570 struct mousevsc_prt_msg *request;
571 struct mousevsc_prt_msg *response;
572
Hank Janssenc0765e92011-04-01 14:32:14 -0700573 input_dev = get_input_device(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800574
Hank Janssenc0765e92011-04-01 14:32:14 -0700575 if (!input_dev) {
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800576 pr_err("unable to get input device...device being destroyed?");
577 return -1;
578 }
579
Hank Janssenc0765e92011-04-01 14:32:14 -0700580 init_waitqueue_head(&input_dev->protocol_wait_event);
581 init_waitqueue_head(&input_dev->dev_info_wait_event);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800582
Hank Janssenc0765e92011-04-01 14:32:14 -0700583 request = &input_dev->protocol_req;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800584
585 /*
586 * Now, initiate the vsc/vsp initialization protocol on the open channel
587 */
Dave Jones75e4fb22011-03-16 21:40:59 -0400588 memset(request, 0, sizeof(struct mousevsc_prt_msg));
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800589
Greg Kroah-Hartman2012d402011-03-02 19:36:15 -0800590 request->type = PipeMessageData;
Greg Kroah-Hartman9877fa42011-03-02 19:38:29 -0800591 request->size = sizeof(struct synthhid_protocol_request);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800592
Greg Kroah-Hartman5ff9b902011-03-02 19:41:00 -0800593 request->request.header.type = SynthHidProtocolRequest;
594 request->request.header.size = sizeof(unsigned long);
595 request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800596
597 pr_info("synthhid protocol request...");
598
Hank Janssen2ba68102011-04-01 14:32:11 -0700599 ret = vmbus_sendpacket(device->channel, request,
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800600 sizeof(struct pipe_prt_msg) -
601 sizeof(unsigned char) +
602 sizeof(struct synthhid_protocol_request),
603 (unsigned long)request,
604 VM_PKT_DATA_INBAND,
605 VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
606 if (ret != 0) {
607 pr_err("unable to send synthhid protocol request.");
608 goto Cleanup;
609 }
610
Hank Janssenc0765e92011-04-01 14:32:14 -0700611 input_dev->protocol_wait_condition = 0;
612 wait_event_timeout(input_dev->protocol_wait_event,
613 input_dev->protocol_wait_condition, msecs_to_jiffies(1000));
614 if (input_dev->protocol_wait_condition == 0) {
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800615 ret = -ETIMEDOUT;
616 goto Cleanup;
617 }
618
Hank Janssenc0765e92011-04-01 14:32:14 -0700619 response = &input_dev->protocol_resp;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800620
Greg Kroah-Hartman5ff9b902011-03-02 19:41:00 -0800621 if (!response->response.approved) {
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800622 pr_err("synthhid protocol request failed (version %d)",
Greg Kroah-Hartman480c28d2011-03-02 19:18:34 -0800623 SYNTHHID_INPUT_VERSION);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800624 ret = -1;
625 goto Cleanup;
626 }
627
Hank Janssenc0765e92011-04-01 14:32:14 -0700628 input_dev->device_wait_condition = 0;
629 wait_event_timeout(input_dev->dev_info_wait_event,
630 input_dev->device_wait_condition, msecs_to_jiffies(1000));
631 if (input_dev->device_wait_condition == 0) {
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800632 ret = -ETIMEDOUT;
633 goto Cleanup;
634 }
635
636 /*
637 * We should have gotten the device attr, hid desc and report
638 * desc at this point
639 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700640 if (!input_dev->dev_info_status)
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800641 pr_info("**** input channel up and running!! ****");
642 else
643 ret = -1;
644
645Cleanup:
Hank Janssen2ba68102011-04-01 14:32:11 -0700646 put_input_device(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800647
648 return ret;
649}
650
Hank Janssen2ba68102011-04-01 14:32:11 -0700651static int mousevsc_on_device_add(struct hv_device *device,
652 void *additional_info)
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800653{
654 int ret = 0;
Hank Janssenc0765e92011-04-01 14:32:14 -0700655 struct mousevsc_dev *input_dev;
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700656 struct hv_driver *input_drv;
Greg Kroah-Hartman98ad91e2011-03-02 19:24:05 -0800657 struct hv_input_dev_info dev_info;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800658
Hank Janssenc0765e92011-04-01 14:32:14 -0700659 input_dev = alloc_input_device(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800660
Hank Janssenc0765e92011-04-01 14:32:14 -0700661 if (!input_dev) {
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800662 ret = -1;
663 goto Cleanup;
664 }
665
Hank Janssenc0765e92011-04-01 14:32:14 -0700666 input_dev->init_complete = false;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800667
668 /* Open the channel */
Hank Janssen2ba68102011-04-01 14:32:11 -0700669 ret = vmbus_open(device->channel,
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800670 INPUTVSC_SEND_RING_BUFFER_SIZE,
671 INPUTVSC_RECV_RING_BUFFER_SIZE,
672 NULL,
673 0,
Hank Janssen94e44cb2011-04-01 14:32:10 -0700674 mousevsc_on_channel_callback,
Hank Janssen2ba68102011-04-01 14:32:11 -0700675 device
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800676 );
677
678 if (ret != 0) {
679 pr_err("unable to open channel: %d", ret);
Hank Janssenc0765e92011-04-01 14:32:14 -0700680 free_input_device(input_dev);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800681 return -1;
682 }
683
684 pr_info("InputVsc channel open: %d", ret);
685
Hank Janssen2ba68102011-04-01 14:32:11 -0700686 ret = mousevsc_connect_to_vsp(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800687
688 if (ret != 0) {
689 pr_err("unable to connect channel: %d", ret);
690
Hank Janssen2ba68102011-04-01 14:32:11 -0700691 vmbus_close(device->channel);
Hank Janssenc0765e92011-04-01 14:32:14 -0700692 free_input_device(input_dev);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800693 return ret;
694 }
695
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700696 input_drv = drv_to_hv_drv(input_dev->device->device.driver);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800697
Hank Janssenc0765e92011-04-01 14:32:14 -0700698 dev_info.vendor = input_dev->hid_dev_info.vendor;
699 dev_info.product = input_dev->hid_dev_info.product;
700 dev_info.version = input_dev->hid_dev_info.version;
Greg Kroah-Hartman98ad91e2011-03-02 19:24:05 -0800701 strcpy(dev_info.name, "Microsoft Vmbus HID-compliant Mouse");
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800702
703 /* Send the device info back up */
Hank Janssen2ba68102011-04-01 14:32:11 -0700704 deviceinfo_callback(device, &dev_info);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800705
706 /* Send the report desc back up */
707 /* workaround SA-167 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700708 if (input_dev->report_desc[14] == 0x25)
709 input_dev->report_desc[14] = 0x29;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800710
Hank Janssenc0765e92011-04-01 14:32:14 -0700711 reportdesc_callback(device, input_dev->report_desc,
712 input_dev->report_desc_size);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800713
Hank Janssenc0765e92011-04-01 14:32:14 -0700714 input_dev->init_complete = true;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800715
716Cleanup:
717 return ret;
718}
719
Hank Janssen2ba68102011-04-01 14:32:11 -0700720static int mousevsc_on_device_remove(struct hv_device *device)
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800721{
Hank Janssenc0765e92011-04-01 14:32:14 -0700722 struct mousevsc_dev *input_dev;
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800723 int ret = 0;
724
725 pr_info("disabling input device (%p)...",
Hank Janssen2ba68102011-04-01 14:32:11 -0700726 device->ext);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800727
Hank Janssenc0765e92011-04-01 14:32:14 -0700728 input_dev = release_input_device(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800729
730
731 /*
732 * At this point, all outbound traffic should be disable. We only
733 * allow inbound traffic (responses) to proceed
734 *
735 * so that outstanding requests can be completed.
736 */
Hank Janssenc0765e92011-04-01 14:32:14 -0700737 while (input_dev->num_outstanding_req) {
Hank Janssenac41d402011-04-01 14:32:13 -0700738 pr_info("waiting for %d requests to complete...",
Hank Janssenc0765e92011-04-01 14:32:14 -0700739 input_dev->num_outstanding_req);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800740
741 udelay(100);
742 }
743
Hank Janssen2ba68102011-04-01 14:32:11 -0700744 pr_info("removing input device (%p)...", device->ext);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800745
Hank Janssenc0765e92011-04-01 14:32:14 -0700746 input_dev = final_release_input_device(device);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800747
Hank Janssenc0765e92011-04-01 14:32:14 -0700748 pr_info("input device (%p) safe to remove", input_dev);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800749
750 /* Close the channel */
Hank Janssen2ba68102011-04-01 14:32:11 -0700751 vmbus_close(device->channel);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800752
Hank Janssenc0765e92011-04-01 14:32:14 -0700753 free_input_device(input_dev);
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800754
755 return ret;
756}
757
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800758
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800759/*
760 * Data types
761 */
762struct input_device_context {
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800763 struct hv_device *device_ctx;
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800764 struct hid_device *hid_device;
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800765 struct hv_input_dev_info device_info;
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800766 int connected;
767};
768
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800769
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800770static void deviceinfo_callback(struct hv_device *dev, struct hv_input_dev_info *info)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800771{
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800772 struct input_device_context *input_device_ctx =
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800773 dev_get_drvdata(&dev->device);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800774
775 memcpy(&input_device_ctx->device_info, info,
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800776 sizeof(struct hv_input_dev_info));
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800777
Greg Kroah-Hartman4f143132011-03-02 18:38:31 -0800778 DPRINT_INFO(INPUTVSC_DRV, "%s", __func__);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800779}
780
Greg Kroah-Hartman4f143132011-03-02 18:38:31 -0800781static void inputreport_callback(struct hv_device *dev, void *packet, u32 len)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800782{
783 int ret = 0;
784
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800785 struct input_device_context *input_dev_ctx =
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800786 dev_get_drvdata(&dev->device);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800787
788 ret = hid_input_report(input_dev_ctx->hid_device,
789 HID_INPUT_REPORT, packet, len, 1);
790
791 DPRINT_DBG(INPUTVSC_DRV, "hid_input_report (ret %d)", ret);
792}
793
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800794static int mousevsc_hid_open(struct hid_device *hid)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800795{
796 return 0;
797}
798
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800799static void mousevsc_hid_close(struct hid_device *hid)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800800{
801}
802
K. Y. Srinivasan9efd21e2011-04-29 13:45:10 -0700803static int mousevsc_probe(struct hv_device *dev)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800804{
805 int ret = 0;
806
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800807 struct input_device_context *input_dev_ctx;
808
809 input_dev_ctx = kmalloc(sizeof(struct input_device_context),
810 GFP_KERNEL);
811
K. Y. Srinivasan9efd21e2011-04-29 13:45:10 -0700812 dev_set_drvdata(&dev->device, input_dev_ctx);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800813
814 /* Call to the vsc driver to add the device */
K. Y. Srinivasand1f01b32011-05-10 07:55:06 -0700815 ret = mousevsc_on_device_add(dev, NULL);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800816
817 if (ret != 0) {
818 DPRINT_ERR(INPUTVSC_DRV, "unable to add input vsc device");
819
820 return -1;
821 }
822
823 return 0;
824}
825
K. Y. Srinivasan415b0232011-04-29 13:45:12 -0700826static int mousevsc_remove(struct hv_device *dev)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800827{
828 int ret = 0;
829
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800830 struct input_device_context *input_dev_ctx;
831
832 input_dev_ctx = kmalloc(sizeof(struct input_device_context),
833 GFP_KERNEL);
834
K. Y. Srinivasan415b0232011-04-29 13:45:12 -0700835 dev_set_drvdata(&dev->device, input_dev_ctx);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800836
837 if (input_dev_ctx->connected) {
838 hidinput_disconnect(input_dev_ctx->hid_device);
839 input_dev_ctx->connected = 0;
840 }
841
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800842 /*
843 * Call to the vsc driver to let it know that the device
844 * is being removed
845 */
K. Y. Srinivasanf1f66f82011-05-10 07:55:07 -0700846 ret = mousevsc_on_device_remove(dev);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800847
848 if (ret != 0) {
849 DPRINT_ERR(INPUTVSC_DRV,
850 "unable to remove vsc device (ret %d)", ret);
851 }
852
853 kfree(input_dev_ctx);
854
855 return ret;
856}
857
Greg Kroah-Hartman4f143132011-03-02 18:38:31 -0800858static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800859{
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800860 struct input_device_context *input_device_ctx =
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800861 dev_get_drvdata(&dev->device);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800862 struct hid_device *hid_dev;
863
864 /* hid_debug = -1; */
865 hid_dev = kmalloc(sizeof(struct hid_device), GFP_KERNEL);
866
867 if (hid_parse_report(hid_dev, packet, len)) {
868 DPRINT_INFO(INPUTVSC_DRV, "Unable to call hd_parse_report");
869 return;
870 }
871
872 if (hid_dev) {
873 DPRINT_INFO(INPUTVSC_DRV, "hid_device created");
874
875 hid_dev->ll_driver->open = mousevsc_hid_open;
876 hid_dev->ll_driver->close = mousevsc_hid_close;
877
Greg Kroah-Hartmanc9246c92011-03-02 18:58:35 -0800878 hid_dev->bus = BUS_VIRTUAL;
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800879 hid_dev->vendor = input_device_ctx->device_info.vendor;
880 hid_dev->product = input_device_ctx->device_info.product;
881 hid_dev->version = input_device_ctx->device_info.version;
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800882 hid_dev->dev = dev->device;
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800883
884 sprintf(hid_dev->name, "%s",
Greg Kroah-Hartman0f88ea52011-03-02 18:57:04 -0800885 input_device_ctx->device_info.name);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800886
887 /*
888 * HJ Do we want to call it with a 0
889 */
890 if (!hidinput_connect(hid_dev, 0)) {
891 hid_dev->claimed |= HID_CLAIMED_INPUT;
892
893 input_device_ctx->connected = 1;
894
895 DPRINT_INFO(INPUTVSC_DRV,
896 "HID device claimed by input\n");
897 }
898
899 if (!hid_dev->claimed) {
900 DPRINT_ERR(INPUTVSC_DRV,
901 "HID device not claimed by "
902 "input or hiddev\n");
903 }
904
905 input_device_ctx->hid_device = hid_dev;
906 }
907
908 kfree(hid_dev);
909}
910
K. Y. Srinivasan1ec91eb2011-08-25 09:48:35 -0700911static const struct hv_vmbus_device_id id_table[] = {
Greg Kroah-Hartmanc45cf2d2011-08-25 11:41:33 -0700912 /* Mouse guid */
913 { VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
914 0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
915 { },
K. Y. Srinivasan1ec91eb2011-08-25 09:48:35 -0700916};
917
918/*
919 * The mouse driver is not functional; do not auto-load it.
920 */
921/* MODULE_DEVICE_TABLE(vmbus, id_table); */
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800922
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700923static struct hv_driver mousevsc_drv = {
K. Y. Srinivasan1ec91eb2011-08-25 09:48:35 -0700924 .id_table = id_table,
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700925 .probe = mousevsc_probe,
926 .remove = mousevsc_remove,
K. Y. Srinivasan1745ec52011-05-10 07:55:20 -0700927};
K. Y. Srinivasaneebdd6f2011-05-10 07:55:19 -0700928
Greg Kroah-Hartmanac2c9032011-03-02 18:50:15 -0800929static void mousevsc_drv_exit(void)
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800930{
K. Y. Srinivasan96053ef2011-05-12 19:34:46 -0700931 vmbus_child_driver_unregister(&mousevsc_drv.driver);
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800932}
933
934static int __init mousevsc_init(void)
935{
K. Y. Srinivasan746e8ca2011-05-10 07:56:16 -0700936 struct hv_driver *drv = &mousevsc_drv;
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800937
938 DPRINT_INFO(INPUTVSC_DRV, "Hyper-V Mouse driver initializing.");
939
K. Y. Srinivasaneb94b2f2011-05-10 07:56:12 -0700940 drv->driver.name = driver_name;
Greg Kroah-Hartman7ced4812011-03-02 18:28:52 -0800941
Greg Kroah-Hartman7ced4812011-03-02 18:28:52 -0800942 /* The driver belongs to vmbus */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800943 vmbus_child_driver_register(&drv->driver);
Greg Kroah-Hartman7ced4812011-03-02 18:28:52 -0800944
945 return 0;
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800946}
947
948static void __exit mousevsc_exit(void)
949{
950 mousevsc_drv_exit();
951}
952
953/*
Greg Kroah-Hartman76e63662011-03-02 20:15:14 -0500954 * We don't want to automatically load this driver just yet, it's quite
955 * broken. It's safe if you want to load it yourself manually, but
956 * don't inflict it on unsuspecting users, that's just mean.
957 */
958#if 0
959
960/*
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800961 * We use a PCI table to determine if we should autoload this driver This is
962 * needed by distro tools to determine if the hyperv drivers should be
963 * installed and/or configured. We don't do anything else with the table, but
964 * it needs to be present.
965 */
Ruslan Pisarevdbbb2492011-07-22 15:12:47 +0300966static const struct pci_device_id microsoft_hv_pci_table[] = {
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800967 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
968 { 0 }
969};
970MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
Greg Kroah-Hartman76e63662011-03-02 20:15:14 -0500971#endif
Greg Kroah-Hartman0c3a6ed2011-02-27 07:43:10 -0800972
973MODULE_LICENSE("GPL");
974MODULE_VERSION(HV_DRV_VERSION);
975module_init(mousevsc_init);
976module_exit(mousevsc_exit);
977