Staging: hv: add mouse driver
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / hv / hv_mouse_drv.c
blob09f7d05f1495cd69b968dd9940e729513c2f7f0f
1 /*
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
20 * this program.
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>
36 //#include "osd.h"
37 #include "hv_api.h"
38 #include "logging.h"
39 #include "version_info.h"
40 #include "vmbus.h"
41 #include "mousevsc_api.h"
43 #define NBITS(x) (((x)/BITS_PER_LONG)+1)
47 * Data types
49 struct input_device_context {
50 struct vm_device *device_ctx;
51 struct hid_device *hid_device;
52 struct input_dev_info device_info;
53 int connected;
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)
78 int ret = 0;
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)
92 return 0;
95 void mousevsc_hid_close(struct hid_device *hid)
99 int mousevsc_probe(struct device *device)
101 int ret = 0;
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),
114 GFP_KERNEL);
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);
121 if (ret != 0) {
122 DPRINT_ERR(INPUTVSC_DRV, "unable to add input vsc device");
124 return -1;
127 return 0;
131 int mousevsc_remove(struct device *device)
133 int ret = 0;
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),
146 GFP_KERNEL);
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) {
156 return -1;
160 * Call to the vsc driver to let it know that the device
161 * is being removed
163 ret = mousevsc_drv_obj->Base.dev_rm(device_obj);
165 if (ret != 0) {
166 DPRINT_ERR(INPUTVSC_DRV,
167 "unable to remove vsc device (ret %d)", ret);
170 kfree(input_dev_ctx);
172 return ret;
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");
187 return;
190 if (hid_dev) {
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;
226 kfree(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))
237 int ret = 0;
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);
260 return ret;
264 int mousevsc_drv_exit_cb(struct device *dev, void *data)
266 struct device **curr = (struct device **)data;
267 *curr = dev;
269 return 1;
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;
276 int ret;
278 struct device *current_dev = NULL;
280 while (1) {
281 current_dev = NULL;
283 /* Get the device */
284 ret = driver_for_each_device(&drv_ctx->driver, NULL, (void *)&current_dev, mousevsc_drv_exit_cb);
285 if (ret)
286 printk(KERN_ERR "Can't find mouse device!\n");
288 if (current_dev == NULL)
289 break;
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);
300 return;
303 static int __init mousevsc_init(void)
305 int ret;
307 DPRINT_INFO(INPUTVSC_DRV, "Hyper-V Mouse driver initializing.");
309 ret = mousevsc_drv_init(mouse_vsc_initialize);
311 return ret;
314 static void __exit mousevsc_exit(void)
316 mousevsc_drv_exit();
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 */
327 { 0 }
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);