2 * Copyright 2009 Citrix Systems, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * For clarity, the licensor of this program does not intend that a
19 * "derivative work" include code which compiles header information from
22 * This code has been modified from its original by
23 * Hank Janssen <hjanssen@microsoft.com>
26 #include <linux/init.h>
27 #include <linux/module.h>
28 #include <linux/device.h>
29 #include <linux/workqueue.h>
30 #include <linux/input.h>
31 #include <linux/hid.h>
32 #include <linux/hiddev.h>
33 #include <linux/pci.h>
34 #include <linux/dmi.h>
39 #include "version_info.h"
41 #include "mousevsc_api.h"
43 #define NBITS(x) (((x)/BITS_PER_LONG)+1)
49 struct input_device_context
{
50 struct vm_device
*device_ctx
;
51 struct hid_device
*hid_device
;
52 struct input_dev_info device_info
;
56 struct mousevsc_driver_context
{
57 struct driver_context drv_ctx
;
58 struct mousevsc_drv_obj drv_obj
;
61 static struct mousevsc_driver_context g_mousevsc_drv
;
63 void mousevsc_deviceinfo_callback(struct hv_device
*dev
,
64 struct input_dev_info
*info
)
66 struct vm_device
*device_ctx
= to_vm_device(dev
);
67 struct input_device_context
*input_device_ctx
=
68 dev_get_drvdata(&device_ctx
->device
);
70 memcpy(&input_device_ctx
->device_info
, info
,
71 sizeof(struct input_dev_info
));
73 DPRINT_INFO(INPUTVSC_DRV
, "mousevsc_deviceinfo_callback()");
76 void mousevsc_inputreport_callback(struct hv_device
*dev
, void *packet
, u32 len
)
80 struct vm_device
*device_ctx
= to_vm_device(dev
);
81 struct input_device_context
*input_dev_ctx
=
82 dev_get_drvdata(&device_ctx
->device
);
84 ret
= hid_input_report(input_dev_ctx
->hid_device
,
85 HID_INPUT_REPORT
, packet
, len
, 1);
87 DPRINT_DBG(INPUTVSC_DRV
, "hid_input_report (ret %d)", ret
);
90 int mousevsc_hid_open(struct hid_device
*hid
)
95 void mousevsc_hid_close(struct hid_device
*hid
)
99 int mousevsc_probe(struct device
*device
)
103 struct driver_context
*driver_ctx
=
104 driver_to_driver_context(device
->driver
);
105 struct mousevsc_driver_context
*mousevsc_drv_ctx
=
106 (struct mousevsc_driver_context
*)driver_ctx
;
107 struct mousevsc_drv_obj
*mousevsc_drv_obj
= &mousevsc_drv_ctx
->drv_obj
;
109 struct vm_device
*device_ctx
= device_to_vm_device(device
);
110 struct hv_device
*device_obj
= &device_ctx
->device_obj
;
111 struct input_device_context
*input_dev_ctx
;
113 input_dev_ctx
= kmalloc(sizeof(struct input_device_context
),
116 dev_set_drvdata(device
, input_dev_ctx
);
118 /* Call to the vsc driver to add the device */
119 ret
= mousevsc_drv_obj
->Base
.dev_add(device_obj
, NULL
);
122 DPRINT_ERR(INPUTVSC_DRV
, "unable to add input vsc device");
131 int mousevsc_remove(struct device
*device
)
135 struct driver_context
*driver_ctx
=
136 driver_to_driver_context(device
->driver
);
137 struct mousevsc_driver_context
*mousevsc_drv_ctx
=
138 (struct mousevsc_driver_context
*)driver_ctx
;
139 struct mousevsc_drv_obj
*mousevsc_drv_obj
= &mousevsc_drv_ctx
->drv_obj
;
141 struct vm_device
*device_ctx
= device_to_vm_device(device
);
142 struct hv_device
*device_obj
= &device_ctx
->device_obj
;
143 struct input_device_context
*input_dev_ctx
;
145 input_dev_ctx
= kmalloc(sizeof(struct input_device_context
),
148 dev_set_drvdata(device
, input_dev_ctx
);
150 if (input_dev_ctx
->connected
) {
151 hidinput_disconnect(input_dev_ctx
->hid_device
);
152 input_dev_ctx
->connected
= 0;
155 if (!mousevsc_drv_obj
->Base
.dev_rm
) {
160 * Call to the vsc driver to let it know that the device
163 ret
= mousevsc_drv_obj
->Base
.dev_rm(device_obj
);
166 DPRINT_ERR(INPUTVSC_DRV
,
167 "unable to remove vsc device (ret %d)", ret
);
170 kfree(input_dev_ctx
);
175 void mousevsc_reportdesc_callback(struct hv_device
*dev
, void *packet
, u32 len
)
177 struct vm_device
*device_ctx
= to_vm_device(dev
);
178 struct input_device_context
*input_device_ctx
=
179 dev_get_drvdata(&device_ctx
->device
);
180 struct hid_device
*hid_dev
;
182 /* hid_debug = -1; */
183 hid_dev
= kmalloc(sizeof(struct hid_device
), GFP_KERNEL
);
185 if (hid_parse_report(hid_dev
, packet
, len
)) {
186 DPRINT_INFO(INPUTVSC_DRV
, "Unable to call hd_parse_report");
191 DPRINT_INFO(INPUTVSC_DRV
, "hid_device created");
193 hid_dev
->ll_driver
->open
= mousevsc_hid_open
;
194 hid_dev
->ll_driver
->close
= mousevsc_hid_close
;
196 hid_dev
->bus
= 0x06; /* BUS_VIRTUAL */
197 hid_dev
->vendor
= input_device_ctx
->device_info
.VendorID
;
198 hid_dev
->product
= input_device_ctx
->device_info
.ProductID
;
199 hid_dev
->version
= input_device_ctx
->device_info
.VersionNumber
;
200 hid_dev
->dev
= device_ctx
->device
;
202 sprintf(hid_dev
->name
, "%s",
203 input_device_ctx
->device_info
.Name
);
206 * HJ Do we want to call it with a 0
208 if (!hidinput_connect(hid_dev
, 0)) {
209 hid_dev
->claimed
|= HID_CLAIMED_INPUT
;
211 input_device_ctx
->connected
= 1;
213 DPRINT_INFO(INPUTVSC_DRV
,
214 "HID device claimed by input\n");
217 if (!hid_dev
->claimed
) {
218 DPRINT_ERR(INPUTVSC_DRV
,
219 "HID device not claimed by "
220 "input or hiddev\n");
223 input_device_ctx
->hid_device
= hid_dev
;
231 * Name: mousevsc_drv_init()
233 * Desc: Driver initialization.
235 int mousevsc_drv_init(int (*pfn_drv_init
)(struct hv_driver
*pfn_drv_init
))
238 struct mousevsc_drv_obj
*input_drv_obj
= &g_mousevsc_drv
.drv_obj
;
239 struct driver_context
*drv_ctx
= &g_mousevsc_drv
.drv_ctx
;
241 // vmbus_get_interface(&input_drv_obj->Base.VmbusChannelInterface);
243 input_drv_obj
->OnDeviceInfo
= mousevsc_deviceinfo_callback
;
244 input_drv_obj
->OnInputReport
= mousevsc_inputreport_callback
;
245 input_drv_obj
->OnReportDescriptor
= mousevsc_reportdesc_callback
;
247 /* Callback to client driver to complete the initialization */
248 pfn_drv_init(&input_drv_obj
->Base
);
250 drv_ctx
->driver
.name
= input_drv_obj
->Base
.name
;
251 memcpy(&drv_ctx
->class_id
, &input_drv_obj
->Base
.dev_type
,
252 sizeof(struct hv_guid
));
254 drv_ctx
->probe
= mousevsc_probe
;
255 drv_ctx
->remove
= mousevsc_remove
;
257 /* The driver belongs to vmbus */
258 vmbus_child_driver_register(drv_ctx
);
264 int mousevsc_drv_exit_cb(struct device
*dev
, void *data
)
266 struct device
**curr
= (struct device
**)data
;
272 void mousevsc_drv_exit(void)
274 struct mousevsc_drv_obj
*mousevsc_drv_obj
= &g_mousevsc_drv
.drv_obj
;
275 struct driver_context
*drv_ctx
= &g_mousevsc_drv
.drv_ctx
;
278 struct device
*current_dev
= NULL
;
284 ret
= driver_for_each_device(&drv_ctx
->driver
, NULL
, (void *)¤t_dev
, mousevsc_drv_exit_cb
);
286 printk(KERN_ERR
"Can't find mouse device!\n");
288 if (current_dev
== NULL
)
291 /* Initiate removal from the top-down */
292 device_unregister(current_dev
);
295 if (mousevsc_drv_obj
->Base
.cleanup
)
296 mousevsc_drv_obj
->Base
.cleanup(&mousevsc_drv_obj
->Base
);
298 vmbus_child_driver_unregister(drv_ctx
);
303 static int __init
mousevsc_init(void)
307 DPRINT_INFO(INPUTVSC_DRV
, "Hyper-V Mouse driver initializing.");
309 ret
= mousevsc_drv_init(mouse_vsc_initialize
);
314 static void __exit
mousevsc_exit(void)
320 * We use a PCI table to determine if we should autoload this driver This is
321 * needed by distro tools to determine if the hyperv drivers should be
322 * installed and/or configured. We don't do anything else with the table, but
323 * it needs to be present.
325 const static struct pci_device_id microsoft_hv_pci_table
[] = {
326 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
329 MODULE_DEVICE_TABLE(pci
, microsoft_hv_pci_table
);
331 MODULE_LICENSE("GPL");
332 MODULE_VERSION(HV_DRV_VERSION
);
333 module_init(mousevsc_init
);
334 module_exit(mousevsc_exit
);