linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
@ 2011-10-15  6:08 K. Y. Srinivasan
  2011-10-15  6:36 ` Joe Perches
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: K. Y. Srinivasan @ 2011-10-15  6:08 UTC (permalink / raw)
  To: gregkh, linux-kernel, devel, virtualization, dmitry.torokhov,
	linux-input
  Cc: K. Y. Srinivasan, Haiyang Zhang

In preparation for moving the mouse driver out of staging, seek community
review of the mouse driver code.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
---
 drivers/hid/Kconfig           |    6 +
 drivers/hid/Makefile          |    1 +
 drivers/hid/hv_mouse.c        |  599 +++++++++++++++++++++++++++++++++++++++++
 drivers/staging/hv/Kconfig    |    6 -
 drivers/staging/hv/Makefile   |    1 -
 drivers/staging/hv/hv_mouse.c |  599 -----------------------------------------
 6 files changed, 606 insertions(+), 606 deletions(-)
 create mode 100644 drivers/hid/hv_mouse.c
 delete mode 100644 drivers/staging/hv/hv_mouse.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 1130a89..f8b98b8 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -613,6 +613,12 @@ config HID_ZYDACRON
 	---help---
 	Support for Zydacron remote control.
 
+config HYPERV_MOUSE
+	tristate "Microsoft Hyper-V mouse driver"
+	depends on HYPERV
+	help
+	  Select this option to enable the Hyper-V mouse driver.
+
 endmenu
 
 endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 0a0a38e..436ac2e 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
 obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
 obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
 obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
+obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
 
 obj-$(CONFIG_USB_HID)		+= usbhid/
 obj-$(CONFIG_USB_MOUSE)		+= usbhid/
diff --git a/drivers/hid/hv_mouse.c b/drivers/hid/hv_mouse.c
new file mode 100644
index 0000000..ccd39c7
--- /dev/null
+++ b/drivers/hid/hv_mouse.c
@@ -0,0 +1,599 @@
+/*
+ *  Copyright (c) 2009, Citrix Systems, Inc.
+ *  Copyright (c) 2010, Microsoft Corporation.
+ *  Copyright (c) 2011, Novell Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms and conditions of the GNU General Public License,
+ *  version 2, as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ *  more details.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
+#include <linux/hyperv.h>
+
+
+struct hv_input_dev_info {
+	unsigned int size;
+	unsigned short vendor;
+	unsigned short product;
+	unsigned short version;
+	unsigned short reserved[11];
+};
+
+/* The maximum size of a synthetic input message. */
+#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
+
+/*
+ * Current version
+ *
+ * History:
+ * Beta, RC < 2008/1/22        1,0
+ * RC > 2008/1/22              2,0
+ */
+#define SYNTHHID_INPUT_VERSION_MAJOR	2
+#define SYNTHHID_INPUT_VERSION_MINOR	0
+#define SYNTHHID_INPUT_VERSION		(SYNTHHID_INPUT_VERSION_MINOR | \
+					 (SYNTHHID_INPUT_VERSION_MAJOR << 16))
+
+
+#pragma pack(push, 1)
+/*
+ * Message types in the synthetic input protocol
+ */
+enum synthhid_msg_type {
+	SYNTH_HID_PROTOCOL_REQUEST,
+	SYNTH_HID_PROTOCOL_RESPONSE,
+	SYNTH_HID_INITIAL_DEVICE_INFO,
+	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
+	SYNTH_HID_INPUT_REPORT,
+	SYNTH_HID_MAX
+};
+
+/*
+ * Basic message structures.
+ */
+struct synthhid_msg_hdr {
+	enum synthhid_msg_type type;
+	u32 size;
+};
+
+struct synthhid_msg {
+	struct synthhid_msg_hdr header;
+	char data[1]; /* Enclosed message */
+};
+
+union synthhid_version {
+	struct {
+		u16 minor_version;
+		u16 major_version;
+	};
+	u32 version;
+};
+
+/*
+ * Protocol messages
+ */
+struct synthhid_protocol_request {
+	struct synthhid_msg_hdr header;
+	union synthhid_version version_requested;
+};
+
+struct synthhid_protocol_response {
+	struct synthhid_msg_hdr header;
+	union synthhid_version version_requested;
+	unsigned char approved;
+};
+
+struct synthhid_device_info {
+	struct synthhid_msg_hdr header;
+	struct hv_input_dev_info hid_dev_info;
+	struct hid_descriptor hid_descriptor;
+};
+
+struct synthhid_device_info_ack {
+	struct synthhid_msg_hdr header;
+	unsigned char reserved;
+};
+
+struct synthhid_input_report {
+	struct synthhid_msg_hdr header;
+	char buffer[1];
+};
+
+#pragma pack(pop)
+
+#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
+#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
+
+#define NBITS(x) (((x)/BITS_PER_LONG)+1)
+
+enum pipe_prot_msg_type {
+	PIPE_MESSAGE_INVALID,
+	PIPE_MESSAGE_DATA,
+	PIPE_MESSAGE_MAXIMUM
+};
+
+
+struct pipe_prt_msg {
+	enum pipe_prot_msg_type type;
+	u32 size;
+	char data[1];
+};
+
+struct  mousevsc_prt_msg {
+	enum pipe_prot_msg_type type;
+	u32 size;
+	union {
+		struct synthhid_protocol_request request;
+		struct synthhid_protocol_response response;
+		struct synthhid_device_info_ack ack;
+	};
+};
+
+/*
+ * Represents an mousevsc device
+ */
+struct mousevsc_dev {
+	struct hv_device	*device;
+	unsigned char		init_complete;
+	struct mousevsc_prt_msg	protocol_req;
+	struct mousevsc_prt_msg	protocol_resp;
+	/* Synchronize the request/response if needed */
+	struct completion	wait_event;
+	int			dev_info_status;
+
+	struct hid_descriptor	*hid_desc;
+	unsigned char		*report_desc;
+	u32			report_desc_size;
+	struct hv_input_dev_info hid_dev_info;
+	int			connected;
+	struct hid_device       *hid_device;
+};
+
+
+static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
+{
+	struct mousevsc_dev *input_dev;
+
+	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
+
+	if (!input_dev)
+		return NULL;
+
+	input_dev->device = device;
+	hv_set_drvdata(device, input_dev);
+	init_completion(&input_dev->wait_event);
+
+	return input_dev;
+}
+
+static void free_input_device(struct mousevsc_dev *device)
+{
+	kfree(device->hid_desc);
+	kfree(device->report_desc);
+	hv_set_drvdata(device->device, NULL);
+	kfree(device);
+}
+
+
+static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
+				struct synthhid_device_info *device_info)
+{
+	int ret = 0;
+	struct hid_descriptor *desc;
+	struct mousevsc_prt_msg ack;
+
+	/* Assume success for now */
+	input_device->dev_info_status = 0;
+
+	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
+		sizeof(struct hv_input_dev_info));
+
+	desc = &device_info->hid_descriptor;
+	WARN_ON(desc->bLength == 0);
+
+	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
+
+	if (!input_device->hid_desc)
+		goto cleanup;
+
+	memcpy(input_device->hid_desc, desc, desc->bLength);
+
+	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
+	if (input_device->report_desc_size == 0)
+		goto cleanup;
+	input_device->report_desc = kzalloc(input_device->report_desc_size,
+					  GFP_ATOMIC);
+
+	if (!input_device->report_desc)
+		goto cleanup;
+
+	memcpy(input_device->report_desc,
+	       ((unsigned char *)desc) + desc->bLength,
+	       desc->desc[0].wDescriptorLength);
+
+	/* Send the ack */
+	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
+
+	ack.type = PIPE_MESSAGE_DATA;
+	ack.size = sizeof(struct synthhid_device_info_ack);
+
+	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
+	ack.ack.header.size = 1;
+	ack.ack.reserved = 0;
+
+	ret = vmbus_sendpacket(input_device->device->channel,
+			&ack,
+			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
+			sizeof(struct synthhid_device_info_ack),
+			(unsigned long)&ack,
+			VM_PKT_DATA_INBAND,
+			VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret != 0)
+		goto cleanup;
+
+	complete(&input_device->wait_event);
+
+	return;
+
+cleanup:
+	kfree(input_device->hid_desc);
+	input_device->hid_desc = NULL;
+
+	kfree(input_device->report_desc);
+	input_device->report_desc = NULL;
+
+	input_device->dev_info_status = -1;
+	complete(&input_device->wait_event);
+}
+
+static void mousevsc_on_receive(struct hv_device *device,
+				struct vmpacket_descriptor *packet)
+{
+	struct pipe_prt_msg *pipe_msg;
+	struct synthhid_msg *hid_msg;
+	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
+	struct synthhid_input_report *input_report;
+
+	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
+						(packet->offset8 << 3));
+
+	if (pipe_msg->type != PIPE_MESSAGE_DATA)
+		return;
+
+	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
+
+	switch (hid_msg->header.type) {
+	case SYNTH_HID_PROTOCOL_RESPONSE:
+		memcpy(&input_dev->protocol_resp, pipe_msg,
+		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
+		       sizeof(unsigned char));
+		complete(&input_dev->wait_event);
+		break;
+
+	case SYNTH_HID_INITIAL_DEVICE_INFO:
+		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
+
+		/*
+		 * Parse out the device info into device attr,
+		 * hid desc and report desc
+		 */
+		mousevsc_on_receive_device_info(input_dev,
+			(struct synthhid_device_info *)&pipe_msg->data[0]);
+		break;
+	case SYNTH_HID_INPUT_REPORT:
+		input_report =
+			(struct synthhid_input_report *)&pipe_msg->data[0];
+		if (!input_dev->init_complete)
+			break;
+		hid_input_report(input_dev->hid_device,
+				HID_INPUT_REPORT, input_report->buffer,
+				input_report->header.size, 1);
+		break;
+	default:
+		pr_err("unsupported hid msg type - type %d len %d",
+		       hid_msg->header.type, hid_msg->header.size);
+		break;
+	}
+
+}
+
+static void mousevsc_on_channel_callback(void *context)
+{
+	const int packetSize = 0x100;
+	int ret = 0;
+	struct hv_device *device = (struct hv_device *)context;
+
+	u32 bytes_recvd;
+	u64 req_id;
+	unsigned char packet[0x100];
+	struct vmpacket_descriptor *desc;
+	unsigned char	*buffer = packet;
+	int	bufferlen = packetSize;
+
+
+	do {
+		ret = vmbus_recvpacket_raw(device->channel, buffer,
+					bufferlen, &bytes_recvd, &req_id);
+
+		if (ret == 0) {
+			if (bytes_recvd > 0) {
+				desc = (struct vmpacket_descriptor *)buffer;
+
+				switch (desc->type) {
+				case VM_PKT_COMP:
+					break;
+
+				case VM_PKT_DATA_INBAND:
+					mousevsc_on_receive(
+						device, desc);
+					break;
+
+				default:
+					pr_err("unhandled packet type %d, tid %llx len %d\n",
+						   desc->type,
+						   req_id,
+						   bytes_recvd);
+					break;
+				}
+
+				/* reset */
+				if (bufferlen > packetSize) {
+					kfree(buffer);
+
+					buffer = packet;
+					bufferlen = packetSize;
+				}
+			} else {
+				if (bufferlen > packetSize) {
+					kfree(buffer);
+
+					buffer = packet;
+					bufferlen = packetSize;
+				}
+				break;
+			}
+		} else if (ret == -ENOBUFS) {
+			/* Handle large packet */
+			bufferlen = bytes_recvd;
+			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
+
+			if (buffer == NULL) {
+				buffer = packet;
+				bufferlen = packetSize;
+				break;
+			}
+		}
+	} while (1);
+
+	return;
+}
+
+static int mousevsc_connect_to_vsp(struct hv_device *device)
+{
+	int ret = 0;
+	int t;
+	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
+	struct mousevsc_prt_msg *request;
+	struct mousevsc_prt_msg *response;
+
+
+	request = &input_dev->protocol_req;
+
+	memset(request, 0, sizeof(struct mousevsc_prt_msg));
+
+	request->type = PIPE_MESSAGE_DATA;
+	request->size = sizeof(struct synthhid_protocol_request);
+
+	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
+	request->request.header.size = sizeof(unsigned int);
+	request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
+
+
+	ret = vmbus_sendpacket(device->channel, request,
+				sizeof(struct pipe_prt_msg) -
+				sizeof(unsigned char) +
+				sizeof(struct synthhid_protocol_request),
+				(unsigned long)request,
+				VM_PKT_DATA_INBAND,
+				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
+	if (ret != 0)
+		goto cleanup;
+
+	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	response = &input_dev->protocol_resp;
+
+	if (!response->response.approved) {
+		pr_err("synthhid protocol request failed (version %d)",
+		       SYNTHHID_INPUT_VERSION);
+		ret = -ENODEV;
+		goto cleanup;
+	}
+
+	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
+	if (t == 0) {
+		ret = -ETIMEDOUT;
+		goto cleanup;
+	}
+
+	/*
+	 * We should have gotten the device attr, hid desc and report
+	 * desc at this point
+	 */
+	if (input_dev->dev_info_status)
+		ret = -ENOMEM;
+
+cleanup:
+
+	return ret;
+}
+
+static int mousevsc_hid_open(struct hid_device *hid)
+{
+	return 0;
+}
+
+static void mousevsc_hid_close(struct hid_device *hid)
+{
+}
+
+static struct hid_ll_driver mousevsc_ll_driver = {
+	.open = mousevsc_hid_open,
+	.close = mousevsc_hid_close,
+};
+
+static struct hid_driver mousevsc_hid_driver;
+
+static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
+{
+	struct hid_device *hid_dev;
+	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
+
+	hid_dev = hid_allocate_device();
+	if (IS_ERR(hid_dev))
+		return;
+
+	hid_dev->ll_driver = &mousevsc_ll_driver;
+	hid_dev->driver = &mousevsc_hid_driver;
+
+	if (hid_parse_report(hid_dev, packet, len))
+		return;
+
+	hid_dev->bus = BUS_VIRTUAL;
+	hid_dev->vendor = input_device->hid_dev_info.vendor;
+	hid_dev->product = input_device->hid_dev_info.product;
+	hid_dev->version = input_device->hid_dev_info.version;
+
+	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
+
+	if (!hidinput_connect(hid_dev, 0)) {
+		hid_dev->claimed |= HID_CLAIMED_INPUT;
+
+		input_device->connected = 1;
+
+	}
+
+	input_device->hid_device = hid_dev;
+}
+
+static int mousevsc_on_device_add(struct hv_device *device)
+{
+	int ret = 0;
+	struct mousevsc_dev *input_dev;
+
+	input_dev = alloc_input_device(device);
+
+	if (!input_dev)
+		return -ENOMEM;
+
+	input_dev->init_complete = false;
+
+	ret = vmbus_open(device->channel,
+		INPUTVSC_SEND_RING_BUFFER_SIZE,
+		INPUTVSC_RECV_RING_BUFFER_SIZE,
+		NULL,
+		0,
+		mousevsc_on_channel_callback,
+		device
+		);
+
+	if (ret != 0) {
+		free_input_device(input_dev);
+		return ret;
+	}
+
+
+	ret = mousevsc_connect_to_vsp(device);
+
+	if (ret != 0) {
+		vmbus_close(device->channel);
+		free_input_device(input_dev);
+		return ret;
+	}
+
+
+	/* workaround SA-167 */
+	if (input_dev->report_desc[14] == 0x25)
+		input_dev->report_desc[14] = 0x29;
+
+	reportdesc_callback(device, input_dev->report_desc,
+			    input_dev->report_desc_size);
+
+	input_dev->init_complete = true;
+
+	return ret;
+}
+
+static int mousevsc_probe(struct hv_device *dev,
+			const struct hv_vmbus_device_id *dev_id)
+{
+
+	return mousevsc_on_device_add(dev);
+
+}
+
+static int mousevsc_remove(struct hv_device *dev)
+{
+	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+	vmbus_close(dev->channel);
+
+	if (input_dev->connected) {
+		hidinput_disconnect(input_dev->hid_device);
+		input_dev->connected = 0;
+		hid_destroy_device(input_dev->hid_device);
+	}
+
+	free_input_device(input_dev);
+
+	return 0;
+}
+
+static const struct hv_vmbus_device_id id_table[] = {
+	/* Mouse guid */
+	{ VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
+		       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(vmbus, id_table);
+
+static struct  hv_driver mousevsc_drv = {
+	.name = "mousevsc",
+	.id_table = id_table,
+	.probe = mousevsc_probe,
+	.remove = mousevsc_remove,
+};
+
+static int __init mousevsc_init(void)
+{
+	return vmbus_driver_register(&mousevsc_drv);
+}
+
+static void __exit mousevsc_exit(void)
+{
+	vmbus_driver_unregister(&mousevsc_drv);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(HV_DRV_VERSION);
+module_init(mousevsc_init);
+module_exit(mousevsc_exit);
diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
index 072185e..6c0dc30 100644
--- a/drivers/staging/hv/Kconfig
+++ b/drivers/staging/hv/Kconfig
@@ -9,9 +9,3 @@ config HYPERV_NET
 	depends on HYPERV && NET
 	help
 	  Select this option to enable the Hyper-V virtual network driver.
-
-config HYPERV_MOUSE
-	tristate "Microsoft Hyper-V mouse driver"
-	depends on HYPERV && HID
-	help
-	  Select this option to enable the Hyper-V mouse driver.
diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
index e071c12..3a2751e 100644
--- a/drivers/staging/hv/Makefile
+++ b/drivers/staging/hv/Makefile
@@ -1,7 +1,6 @@
 obj-$(CONFIG_HYPERV)		+= hv_timesource.o
 obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
 obj-$(CONFIG_HYPERV_NET)	+= hv_netvsc.o
-obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
 
 hv_storvsc-y := storvsc_drv.o
 hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
deleted file mode 100644
index ccd39c7..0000000
--- a/drivers/staging/hv/hv_mouse.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- *  Copyright (c) 2009, Citrix Systems, Inc.
- *  Copyright (c) 2010, Microsoft Corporation.
- *  Copyright (c) 2011, Novell Inc.
- *
- *  This program is free software; you can redistribute it and/or modify it
- *  under the terms and conditions of the GNU General Public License,
- *  version 2, as published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- *  more details.
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/input.h>
-#include <linux/hid.h>
-#include <linux/hiddev.h>
-#include <linux/hyperv.h>
-
-
-struct hv_input_dev_info {
-	unsigned int size;
-	unsigned short vendor;
-	unsigned short product;
-	unsigned short version;
-	unsigned short reserved[11];
-};
-
-/* The maximum size of a synthetic input message. */
-#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
-
-/*
- * Current version
- *
- * History:
- * Beta, RC < 2008/1/22        1,0
- * RC > 2008/1/22              2,0
- */
-#define SYNTHHID_INPUT_VERSION_MAJOR	2
-#define SYNTHHID_INPUT_VERSION_MINOR	0
-#define SYNTHHID_INPUT_VERSION		(SYNTHHID_INPUT_VERSION_MINOR | \
-					 (SYNTHHID_INPUT_VERSION_MAJOR << 16))
-
-
-#pragma pack(push, 1)
-/*
- * Message types in the synthetic input protocol
- */
-enum synthhid_msg_type {
-	SYNTH_HID_PROTOCOL_REQUEST,
-	SYNTH_HID_PROTOCOL_RESPONSE,
-	SYNTH_HID_INITIAL_DEVICE_INFO,
-	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
-	SYNTH_HID_INPUT_REPORT,
-	SYNTH_HID_MAX
-};
-
-/*
- * Basic message structures.
- */
-struct synthhid_msg_hdr {
-	enum synthhid_msg_type type;
-	u32 size;
-};
-
-struct synthhid_msg {
-	struct synthhid_msg_hdr header;
-	char data[1]; /* Enclosed message */
-};
-
-union synthhid_version {
-	struct {
-		u16 minor_version;
-		u16 major_version;
-	};
-	u32 version;
-};
-
-/*
- * Protocol messages
- */
-struct synthhid_protocol_request {
-	struct synthhid_msg_hdr header;
-	union synthhid_version version_requested;
-};
-
-struct synthhid_protocol_response {
-	struct synthhid_msg_hdr header;
-	union synthhid_version version_requested;
-	unsigned char approved;
-};
-
-struct synthhid_device_info {
-	struct synthhid_msg_hdr header;
-	struct hv_input_dev_info hid_dev_info;
-	struct hid_descriptor hid_descriptor;
-};
-
-struct synthhid_device_info_ack {
-	struct synthhid_msg_hdr header;
-	unsigned char reserved;
-};
-
-struct synthhid_input_report {
-	struct synthhid_msg_hdr header;
-	char buffer[1];
-};
-
-#pragma pack(pop)
-
-#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
-#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
-
-#define NBITS(x) (((x)/BITS_PER_LONG)+1)
-
-enum pipe_prot_msg_type {
-	PIPE_MESSAGE_INVALID,
-	PIPE_MESSAGE_DATA,
-	PIPE_MESSAGE_MAXIMUM
-};
-
-
-struct pipe_prt_msg {
-	enum pipe_prot_msg_type type;
-	u32 size;
-	char data[1];
-};
-
-struct  mousevsc_prt_msg {
-	enum pipe_prot_msg_type type;
-	u32 size;
-	union {
-		struct synthhid_protocol_request request;
-		struct synthhid_protocol_response response;
-		struct synthhid_device_info_ack ack;
-	};
-};
-
-/*
- * Represents an mousevsc device
- */
-struct mousevsc_dev {
-	struct hv_device	*device;
-	unsigned char		init_complete;
-	struct mousevsc_prt_msg	protocol_req;
-	struct mousevsc_prt_msg	protocol_resp;
-	/* Synchronize the request/response if needed */
-	struct completion	wait_event;
-	int			dev_info_status;
-
-	struct hid_descriptor	*hid_desc;
-	unsigned char		*report_desc;
-	u32			report_desc_size;
-	struct hv_input_dev_info hid_dev_info;
-	int			connected;
-	struct hid_device       *hid_device;
-};
-
-
-static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
-{
-	struct mousevsc_dev *input_dev;
-
-	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
-
-	if (!input_dev)
-		return NULL;
-
-	input_dev->device = device;
-	hv_set_drvdata(device, input_dev);
-	init_completion(&input_dev->wait_event);
-
-	return input_dev;
-}
-
-static void free_input_device(struct mousevsc_dev *device)
-{
-	kfree(device->hid_desc);
-	kfree(device->report_desc);
-	hv_set_drvdata(device->device, NULL);
-	kfree(device);
-}
-
-
-static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
-				struct synthhid_device_info *device_info)
-{
-	int ret = 0;
-	struct hid_descriptor *desc;
-	struct mousevsc_prt_msg ack;
-
-	/* Assume success for now */
-	input_device->dev_info_status = 0;
-
-	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
-		sizeof(struct hv_input_dev_info));
-
-	desc = &device_info->hid_descriptor;
-	WARN_ON(desc->bLength == 0);
-
-	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
-
-	if (!input_device->hid_desc)
-		goto cleanup;
-
-	memcpy(input_device->hid_desc, desc, desc->bLength);
-
-	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
-	if (input_device->report_desc_size == 0)
-		goto cleanup;
-	input_device->report_desc = kzalloc(input_device->report_desc_size,
-					  GFP_ATOMIC);
-
-	if (!input_device->report_desc)
-		goto cleanup;
-
-	memcpy(input_device->report_desc,
-	       ((unsigned char *)desc) + desc->bLength,
-	       desc->desc[0].wDescriptorLength);
-
-	/* Send the ack */
-	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
-
-	ack.type = PIPE_MESSAGE_DATA;
-	ack.size = sizeof(struct synthhid_device_info_ack);
-
-	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
-	ack.ack.header.size = 1;
-	ack.ack.reserved = 0;
-
-	ret = vmbus_sendpacket(input_device->device->channel,
-			&ack,
-			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
-			sizeof(struct synthhid_device_info_ack),
-			(unsigned long)&ack,
-			VM_PKT_DATA_INBAND,
-			VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-	if (ret != 0)
-		goto cleanup;
-
-	complete(&input_device->wait_event);
-
-	return;
-
-cleanup:
-	kfree(input_device->hid_desc);
-	input_device->hid_desc = NULL;
-
-	kfree(input_device->report_desc);
-	input_device->report_desc = NULL;
-
-	input_device->dev_info_status = -1;
-	complete(&input_device->wait_event);
-}
-
-static void mousevsc_on_receive(struct hv_device *device,
-				struct vmpacket_descriptor *packet)
-{
-	struct pipe_prt_msg *pipe_msg;
-	struct synthhid_msg *hid_msg;
-	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
-	struct synthhid_input_report *input_report;
-
-	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
-						(packet->offset8 << 3));
-
-	if (pipe_msg->type != PIPE_MESSAGE_DATA)
-		return;
-
-	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
-
-	switch (hid_msg->header.type) {
-	case SYNTH_HID_PROTOCOL_RESPONSE:
-		memcpy(&input_dev->protocol_resp, pipe_msg,
-		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
-		       sizeof(unsigned char));
-		complete(&input_dev->wait_event);
-		break;
-
-	case SYNTH_HID_INITIAL_DEVICE_INFO:
-		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
-
-		/*
-		 * Parse out the device info into device attr,
-		 * hid desc and report desc
-		 */
-		mousevsc_on_receive_device_info(input_dev,
-			(struct synthhid_device_info *)&pipe_msg->data[0]);
-		break;
-	case SYNTH_HID_INPUT_REPORT:
-		input_report =
-			(struct synthhid_input_report *)&pipe_msg->data[0];
-		if (!input_dev->init_complete)
-			break;
-		hid_input_report(input_dev->hid_device,
-				HID_INPUT_REPORT, input_report->buffer,
-				input_report->header.size, 1);
-		break;
-	default:
-		pr_err("unsupported hid msg type - type %d len %d",
-		       hid_msg->header.type, hid_msg->header.size);
-		break;
-	}
-
-}
-
-static void mousevsc_on_channel_callback(void *context)
-{
-	const int packetSize = 0x100;
-	int ret = 0;
-	struct hv_device *device = (struct hv_device *)context;
-
-	u32 bytes_recvd;
-	u64 req_id;
-	unsigned char packet[0x100];
-	struct vmpacket_descriptor *desc;
-	unsigned char	*buffer = packet;
-	int	bufferlen = packetSize;
-
-
-	do {
-		ret = vmbus_recvpacket_raw(device->channel, buffer,
-					bufferlen, &bytes_recvd, &req_id);
-
-		if (ret == 0) {
-			if (bytes_recvd > 0) {
-				desc = (struct vmpacket_descriptor *)buffer;
-
-				switch (desc->type) {
-				case VM_PKT_COMP:
-					break;
-
-				case VM_PKT_DATA_INBAND:
-					mousevsc_on_receive(
-						device, desc);
-					break;
-
-				default:
-					pr_err("unhandled packet type %d, tid %llx len %d\n",
-						   desc->type,
-						   req_id,
-						   bytes_recvd);
-					break;
-				}
-
-				/* reset */
-				if (bufferlen > packetSize) {
-					kfree(buffer);
-
-					buffer = packet;
-					bufferlen = packetSize;
-				}
-			} else {
-				if (bufferlen > packetSize) {
-					kfree(buffer);
-
-					buffer = packet;
-					bufferlen = packetSize;
-				}
-				break;
-			}
-		} else if (ret == -ENOBUFS) {
-			/* Handle large packet */
-			bufferlen = bytes_recvd;
-			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
-
-			if (buffer == NULL) {
-				buffer = packet;
-				bufferlen = packetSize;
-				break;
-			}
-		}
-	} while (1);
-
-	return;
-}
-
-static int mousevsc_connect_to_vsp(struct hv_device *device)
-{
-	int ret = 0;
-	int t;
-	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
-	struct mousevsc_prt_msg *request;
-	struct mousevsc_prt_msg *response;
-
-
-	request = &input_dev->protocol_req;
-
-	memset(request, 0, sizeof(struct mousevsc_prt_msg));
-
-	request->type = PIPE_MESSAGE_DATA;
-	request->size = sizeof(struct synthhid_protocol_request);
-
-	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
-	request->request.header.size = sizeof(unsigned int);
-	request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
-
-
-	ret = vmbus_sendpacket(device->channel, request,
-				sizeof(struct pipe_prt_msg) -
-				sizeof(unsigned char) +
-				sizeof(struct synthhid_protocol_request),
-				(unsigned long)request,
-				VM_PKT_DATA_INBAND,
-				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
-	if (ret != 0)
-		goto cleanup;
-
-	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	response = &input_dev->protocol_resp;
-
-	if (!response->response.approved) {
-		pr_err("synthhid protocol request failed (version %d)",
-		       SYNTHHID_INPUT_VERSION);
-		ret = -ENODEV;
-		goto cleanup;
-	}
-
-	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
-	if (t == 0) {
-		ret = -ETIMEDOUT;
-		goto cleanup;
-	}
-
-	/*
-	 * We should have gotten the device attr, hid desc and report
-	 * desc at this point
-	 */
-	if (input_dev->dev_info_status)
-		ret = -ENOMEM;
-
-cleanup:
-
-	return ret;
-}
-
-static int mousevsc_hid_open(struct hid_device *hid)
-{
-	return 0;
-}
-
-static void mousevsc_hid_close(struct hid_device *hid)
-{
-}
-
-static struct hid_ll_driver mousevsc_ll_driver = {
-	.open = mousevsc_hid_open,
-	.close = mousevsc_hid_close,
-};
-
-static struct hid_driver mousevsc_hid_driver;
-
-static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
-{
-	struct hid_device *hid_dev;
-	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
-
-	hid_dev = hid_allocate_device();
-	if (IS_ERR(hid_dev))
-		return;
-
-	hid_dev->ll_driver = &mousevsc_ll_driver;
-	hid_dev->driver = &mousevsc_hid_driver;
-
-	if (hid_parse_report(hid_dev, packet, len))
-		return;
-
-	hid_dev->bus = BUS_VIRTUAL;
-	hid_dev->vendor = input_device->hid_dev_info.vendor;
-	hid_dev->product = input_device->hid_dev_info.product;
-	hid_dev->version = input_device->hid_dev_info.version;
-
-	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
-
-	if (!hidinput_connect(hid_dev, 0)) {
-		hid_dev->claimed |= HID_CLAIMED_INPUT;
-
-		input_device->connected = 1;
-
-	}
-
-	input_device->hid_device = hid_dev;
-}
-
-static int mousevsc_on_device_add(struct hv_device *device)
-{
-	int ret = 0;
-	struct mousevsc_dev *input_dev;
-
-	input_dev = alloc_input_device(device);
-
-	if (!input_dev)
-		return -ENOMEM;
-
-	input_dev->init_complete = false;
-
-	ret = vmbus_open(device->channel,
-		INPUTVSC_SEND_RING_BUFFER_SIZE,
-		INPUTVSC_RECV_RING_BUFFER_SIZE,
-		NULL,
-		0,
-		mousevsc_on_channel_callback,
-		device
-		);
-
-	if (ret != 0) {
-		free_input_device(input_dev);
-		return ret;
-	}
-
-
-	ret = mousevsc_connect_to_vsp(device);
-
-	if (ret != 0) {
-		vmbus_close(device->channel);
-		free_input_device(input_dev);
-		return ret;
-	}
-
-
-	/* workaround SA-167 */
-	if (input_dev->report_desc[14] == 0x25)
-		input_dev->report_desc[14] = 0x29;
-
-	reportdesc_callback(device, input_dev->report_desc,
-			    input_dev->report_desc_size);
-
-	input_dev->init_complete = true;
-
-	return ret;
-}
-
-static int mousevsc_probe(struct hv_device *dev,
-			const struct hv_vmbus_device_id *dev_id)
-{
-
-	return mousevsc_on_device_add(dev);
-
-}
-
-static int mousevsc_remove(struct hv_device *dev)
-{
-	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
-
-	vmbus_close(dev->channel);
-
-	if (input_dev->connected) {
-		hidinput_disconnect(input_dev->hid_device);
-		input_dev->connected = 0;
-		hid_destroy_device(input_dev->hid_device);
-	}
-
-	free_input_device(input_dev);
-
-	return 0;
-}
-
-static const struct hv_vmbus_device_id id_table[] = {
-	/* Mouse guid */
-	{ VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
-		       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
-	{ },
-};
-
-MODULE_DEVICE_TABLE(vmbus, id_table);
-
-static struct  hv_driver mousevsc_drv = {
-	.name = "mousevsc",
-	.id_table = id_table,
-	.probe = mousevsc_probe,
-	.remove = mousevsc_remove,
-};
-
-static int __init mousevsc_init(void)
-{
-	return vmbus_driver_register(&mousevsc_drv);
-}
-
-static void __exit mousevsc_exit(void)
-{
-	vmbus_driver_unregister(&mousevsc_drv);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION(HV_DRV_VERSION);
-module_init(mousevsc_init);
-module_exit(mousevsc_exit);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-15  6:08 [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging K. Y. Srinivasan
@ 2011-10-15  6:36 ` Joe Perches
  2011-10-15 13:24   ` KY Srinivasan
  2011-10-16 22:28   ` Dan Carpenter
  2011-10-19 23:48 ` KY Srinivasan
  2011-10-23  7:24 ` Dmitry Torokhov
  2 siblings, 2 replies; 12+ messages in thread
From: Joe Perches @ 2011-10-15  6:36 UTC (permalink / raw)
  To: K. Y. Srinivasan
  Cc: gregkh, linux-kernel, devel, virtualization, dmitry.torokhov,
	linux-input, Haiyang Zhang

On Fri, 2011-10-14 at 23:08 -0700, K. Y. Srinivasan wrote:
> In preparation for moving the mouse driver out of staging, seek community
> review of the mouse driver code.
> 
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>

Just some stylistic things, none of which should
prevent any code movement.

> +++ b/drivers/hid/hv_mouse.c
[]
> +struct mousevsc_dev {
> +	struct hv_device	*device;
> +	unsigned char		init_complete;

bool?

[]
> +static void mousevsc_on_channel_callback(void *context)
> +{
> +	const int packetSize = 0x100;
> +	int ret = 0;
> +	struct hv_device *device = (struct hv_device *)context;
> +
> +	u32 bytes_recvd;
> +	u64 req_id;
> +	unsigned char packet[0x100];
		[packetSize];

> +	struct vmpacket_descriptor *desc;
> +	unsigned char	*buffer = packet;
> +	int	bufferlen = packetSize;
> +
> +
trivial extra blank line

> +	do {
> +		ret = vmbus_recvpacket_raw(device->channel, buffer,
> +					bufferlen, &bytes_recvd, &req_id);
> +
> +		if (ret == 0) {
> +			if (bytes_recvd > 0) {
> +				desc = (struct vmpacket_descriptor *)buffer;
> +
> +				switch (desc->type) {
> +				case VM_PKT_COMP:
> +					break;
> +
> +				case VM_PKT_DATA_INBAND:
> +					mousevsc_on_receive(
> +						device, desc);
> +					break;
> +
> +				default:
> +					pr_err("unhandled packet type %d, tid %llx len %d\n",
> +						   desc->type,
> +						   req_id,
> +						   bytes_recvd);
> +					break;
> +				}
> +
> +				/* reset */
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +			} else {
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +				break;
> +			}
> +		} else if (ret == -ENOBUFS) {
> +			/* Handle large packet */
> +			bufferlen = bytes_recvd;
> +			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> +
> +			if (buffer == NULL) {
> +				buffer = packet;
> +				bufferlen = packetSize;
> +				break;
> +			}
> +		}
> +	} while (1);

This do {} while (1); seems like it could be simpler,
less indented and less confusing if it used continues
or gotos like below (if I wrote it correctly...)

loop:
	ret = vmbus_bus_recvpacket_raw(device->channel, buffer,
				       bufferlen, &bytes_recvd, &req_id);
	switch (ret) {
	case -ENOBUFS:
		/* Handle large packet */
		bufferlen = bytes_recvd;
		buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
/*
Why kzalloc and not kmalloc?
The stack variable packet is not memset to 0,
why should buffer be zeroed?
*/
		if (!buffer)
			return;
		goto loop;
	case 0:
		if (bytes_recvd <= 0)
			goto loop;
		desc = (struct vmpacket_descriptor *)buffer;

		switch (desc->type) {
		case VM_PKT_COMP:
			break;
		case VM_PKT_DATA_INBAND:
			mousevsc_on_receive(device, desc);
			break;
		default:
			pr_err("unhandled packet type %d, tid %llx len %d\n",
			       desc->type, req_id, bytes_recvd);
			break;
		}
		/* reset to original buffers */
		if (bufferlen > packetSize) {
			kfree(buffer);
			buffer = packet;
			bufferlen = packetSize;
		}
	}
	goto loop;
}

> +
> +static int mousevsc_connect_to_vsp(struct hv_device *device)
> +{
[]
> +	if (!response->response.approved) {
> +		pr_err("synthhid protocol request failed (version %d)",
> +		       SYNTHHID_INPUT_VERSION);

Missing \n at end of format string

[]
> +static int mousevsc_on_device_add(struct hv_device *device)
> +{
[]
> +	ret = vmbus_open(device->channel,
> +		INPUTVSC_SEND_RING_BUFFER_SIZE,
> +		INPUTVSC_RECV_RING_BUFFER_SIZE,
> +		NULL,
> +		0,
> +		mousevsc_on_channel_callback,
> +		device
> +		);

Nicer if aligned to open paren I think.

	ret = vmbus_open(device->channel,
			 INPUTVSC_SEND_RING_BUFFER_SIZE,
			 INPUTVSC_RECV_RING_BUFFER_SIZE,
			 NULL, 0, mousevsc_on_channel_callback,
			 device);



^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-15  6:36 ` Joe Perches
@ 2011-10-15 13:24   ` KY Srinivasan
  2011-10-16 22:28   ` Dan Carpenter
  1 sibling, 0 replies; 12+ messages in thread
From: KY Srinivasan @ 2011-10-15 13:24 UTC (permalink / raw)
  To: Joe Perches
  Cc: gregkh@suse.de, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org, virtualization@lists.osdl.org,
	dmitry.torokhov@gmail.com, linux-input@vger.kernel.org,
	Haiyang Zhang



> -----Original Message-----
> From: Joe Perches [mailto:joe@perches.com]
> Sent: Saturday, October 15, 2011 2:37 AM
> To: KY Srinivasan
> Cc: gregkh@suse.de; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; virtualization@lists.osdl.org;
> dmitry.torokhov@gmail.com; linux-input@vger.kernel.org; Haiyang Zhang
> Subject: Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> staging
> 
> On Fri, 2011-10-14 at 23:08 -0700, K. Y. Srinivasan wrote:
> > In preparation for moving the mouse driver out of staging, seek community
> > review of the mouse driver code.
> >
> > Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> 
> Just some stylistic things, none of which should
> prevent any code movement.

Thanks Joe. I will fix the issues you have noted either before or after
moving the code out of staging based on other review comments.

Regards,

K. Y 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-15  6:36 ` Joe Perches
  2011-10-15 13:24   ` KY Srinivasan
@ 2011-10-16 22:28   ` Dan Carpenter
  2011-10-16 23:03     ` Joe Perches
  1 sibling, 1 reply; 12+ messages in thread
From: Dan Carpenter @ 2011-10-16 22:28 UTC (permalink / raw)
  To: Joe Perches
  Cc: gregkh, Haiyang Zhang, dmitry.torokhov, linux-kernel,
	virtualization, linux-input, devel

On Fri, Oct 14, 2011 at 11:36:36PM -0700, Joe Perches wrote:
> This do {} while (1); seems like it could be simpler,
> less indented and less confusing if it used continues
> or gotos like below (if I wrote it correctly...)
> 
> loop:
> 	ret = vmbus_bus_recvpacket_raw(device->channel, buffer,
> 				       bufferlen, &bytes_recvd, &req_id);
> 	switch (ret) {
> 	case -ENOBUFS:
> 		/* Handle large packet */
> 		bufferlen = bytes_recvd;
> 		buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> /*
> Why kzalloc and not kmalloc?
> The stack variable packet is not memset to 0,
> why should buffer be zeroed?
> */
> 		if (!buffer)
> 			return;
> 		goto loop;
> 	case 0:
> 		if (bytes_recvd <= 0)
> 			goto loop;

In the original we called break here (which is equivelent to a
return).  Btw setting a stack variable and then returning immediately
like the original code did is pointless.

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-16 22:28   ` Dan Carpenter
@ 2011-10-16 23:03     ` Joe Perches
  0 siblings, 0 replies; 12+ messages in thread
From: Joe Perches @ 2011-10-16 23:03 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: K. Y. Srinivasan, dmitry.torokhov, Haiyang Zhang, gregkh,
	linux-kernel, virtualization, linux-input, devel

On Mon, 2011-10-17 at 01:28 +0300, Dan Carpenter wrote:
> On Fri, Oct 14, 2011 at 11:36:36PM -0700, Joe Perches wrote:
[]
> > 	case 0:
> > 		if (bytes_recvd <= 0)
> > 			goto loop;
> In the original we called break here (which is equivelent to a
> return).  Btw setting a stack variable and then returning immediately
> like the original code did is pointless.

OK, return it is.

Perhaps this is better.  (two of the breaks could be goto loop)

I did add a couple of checks to make sure kmalloc'd
memory was always freed.

Another possible simplification is to always use kmalloc
instead of using stack and/or kmalloc.

static void mousevsc_on_channel_callback(void *context)
{
	static const int packetSize = 0x100;
	unsigned char packet[packetSize];
	int ret;
	struct hv_device *device = (struct hv_device *)context;
	u32 bytes_recvd;
	u64 req_id;
	struct vmpacket_descriptor *desc;
	unsigned char *buffer = packet;
	int bufferlen = packetSize;
	bool malloced =  false;

loop:
	ret = vmbus_bus_recvpacket_raw(device->channel, buffer, bufferlen,
				       &bytes_recvd, &req_id);
	switch (ret) {
	case -ENOBUFS:		/* Handle large packet */

		if (malloced)	/* Maybe repeated -ENOBUFS ? */
			kfree(buffer);

		bufferlen = bytes_recvd;
		buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
		if (!buffer)
			return;
		malloced = true;
		break;

	case 0:
		if (bytes_recvd <= 0) {
			if (malloced)
				kfree(buffer);
			return;
		}

		desc = (struct vmpacket_descriptor *)buffer;

		switch (desc->type) {
		case VM_PKT_DATA_INBAND:
			mousevsc_on_receive(device, desc);
			break;
		default:
			pr_err("unhandled packet type %d, tid %llx len %d\n",
			       desc->type, req_id, bytes_recvd);
			break;
		}
		/* reset to original buffers */
		if (malloced) {
			kfree(buffer);
			malloced = false;
			buffer = packet;
			bufferlen = packetSize;
		}
		break;
	}

	goto loop;
}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-15  6:08 [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging K. Y. Srinivasan
  2011-10-15  6:36 ` Joe Perches
@ 2011-10-19 23:48 ` KY Srinivasan
  2011-10-23  7:24 ` Dmitry Torokhov
  2 siblings, 0 replies; 12+ messages in thread
From: KY Srinivasan @ 2011-10-19 23:48 UTC (permalink / raw)
  To: KY Srinivasan, gregkh@suse.de, dmitry.torokhov@gmail.com,
	linux-input@vger.kernel.org
  Cc: Haiyang Zhang

Dmitry,

Please let me know if you have any issues with
this code; I will address them as soon as possible. Looking forward to
hearing from you.

Regards,

K. Y


> -----Original Message-----
> From: K. Y. Srinivasan [mailto:kys@microsoft.com]
> Sent: Saturday, October 15, 2011 2:08 AM
> To: gregkh@suse.de; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; virtualization@lists.osdl.org;
> dmitry.torokhov@gmail.com; linux-input@vger.kernel.org
> Cc: KY Srinivasan; Haiyang Zhang
> Subject: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> staging
> 
> In preparation for moving the mouse driver out of staging, seek community
> review of the mouse driver code.
> 
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> ---
>  drivers/hid/Kconfig           |    6 +
>  drivers/hid/Makefile          |    1 +
>  drivers/hid/hv_mouse.c        |  599
> +++++++++++++++++++++++++++++++++++++++++
>  drivers/staging/hv/Kconfig    |    6 -
>  drivers/staging/hv/Makefile   |    1 -
>  drivers/staging/hv/hv_mouse.c |  599 -----------------------------------------
>  6 files changed, 606 insertions(+), 606 deletions(-)
>  create mode 100644 drivers/hid/hv_mouse.c
>  delete mode 100644 drivers/staging/hv/hv_mouse.c
> 
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 1130a89..f8b98b8 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -613,6 +613,12 @@ config HID_ZYDACRON
>  	---help---
>  	Support for Zydacron remote control.
> 
> +config HYPERV_MOUSE
> +	tristate "Microsoft Hyper-V mouse driver"
> +	depends on HYPERV
> +	help
> +	  Select this option to enable the Hyper-V mouse driver.
> +
>  endmenu
> 
>  endif # HID_SUPPORT
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 0a0a38e..436ac2e 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
>  obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
>  obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
>  obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
> +obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
> 
>  obj-$(CONFIG_USB_HID)		+= usbhid/
>  obj-$(CONFIG_USB_MOUSE)		+= usbhid/
> diff --git a/drivers/hid/hv_mouse.c b/drivers/hid/hv_mouse.c
> new file mode 100644
> index 0000000..ccd39c7
> --- /dev/null
> +++ b/drivers/hid/hv_mouse.c
> @@ -0,0 +1,599 @@
> +/*
> + *  Copyright (c) 2009, Citrix Systems, Inc.
> + *  Copyright (c) 2010, Microsoft Corporation.
> + *  Copyright (c) 2011, Novell Inc.
> + *
> + *  This program is free software; you can redistribute it and/or modify it
> + *  under the terms and conditions of the GNU General Public License,
> + *  version 2, as published by the Free Software Foundation.
> + *
> + *  This program is distributed in the hope it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> for
> + *  more details.
> + */
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/workqueue.h>
> +#include <linux/sched.h>
> +#include <linux/wait.h>
> +#include <linux/input.h>
> +#include <linux/hid.h>
> +#include <linux/hiddev.h>
> +#include <linux/hyperv.h>
> +
> +
> +struct hv_input_dev_info {
> +	unsigned int size;
> +	unsigned short vendor;
> +	unsigned short product;
> +	unsigned short version;
> +	unsigned short reserved[11];
> +};
> +
> +/* The maximum size of a synthetic input message. */
> +#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
> +
> +/*
> + * Current version
> + *
> + * History:
> + * Beta, RC < 2008/1/22        1,0
> + * RC > 2008/1/22              2,0
> + */
> +#define SYNTHHID_INPUT_VERSION_MAJOR	2
> +#define SYNTHHID_INPUT_VERSION_MINOR	0
> +#define SYNTHHID_INPUT_VERSION
> 	(SYNTHHID_INPUT_VERSION_MINOR | \
> +					 (SYNTHHID_INPUT_VERSION_MAJOR <<
> 16))
> +
> +
> +#pragma pack(push, 1)
> +/*
> + * Message types in the synthetic input protocol
> + */
> +enum synthhid_msg_type {
> +	SYNTH_HID_PROTOCOL_REQUEST,
> +	SYNTH_HID_PROTOCOL_RESPONSE,
> +	SYNTH_HID_INITIAL_DEVICE_INFO,
> +	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
> +	SYNTH_HID_INPUT_REPORT,
> +	SYNTH_HID_MAX
> +};
> +
> +/*
> + * Basic message structures.
> + */
> +struct synthhid_msg_hdr {
> +	enum synthhid_msg_type type;
> +	u32 size;
> +};
> +
> +struct synthhid_msg {
> +	struct synthhid_msg_hdr header;
> +	char data[1]; /* Enclosed message */
> +};
> +
> +union synthhid_version {
> +	struct {
> +		u16 minor_version;
> +		u16 major_version;
> +	};
> +	u32 version;
> +};
> +
> +/*
> + * Protocol messages
> + */
> +struct synthhid_protocol_request {
> +	struct synthhid_msg_hdr header;
> +	union synthhid_version version_requested;
> +};
> +
> +struct synthhid_protocol_response {
> +	struct synthhid_msg_hdr header;
> +	union synthhid_version version_requested;
> +	unsigned char approved;
> +};
> +
> +struct synthhid_device_info {
> +	struct synthhid_msg_hdr header;
> +	struct hv_input_dev_info hid_dev_info;
> +	struct hid_descriptor hid_descriptor;
> +};
> +
> +struct synthhid_device_info_ack {
> +	struct synthhid_msg_hdr header;
> +	unsigned char reserved;
> +};
> +
> +struct synthhid_input_report {
> +	struct synthhid_msg_hdr header;
> +	char buffer[1];
> +};
> +
> +#pragma pack(pop)
> +
> +#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> +#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> +
> +#define NBITS(x) (((x)/BITS_PER_LONG)+1)
> +
> +enum pipe_prot_msg_type {
> +	PIPE_MESSAGE_INVALID,
> +	PIPE_MESSAGE_DATA,
> +	PIPE_MESSAGE_MAXIMUM
> +};
> +
> +
> +struct pipe_prt_msg {
> +	enum pipe_prot_msg_type type;
> +	u32 size;
> +	char data[1];
> +};
> +
> +struct  mousevsc_prt_msg {
> +	enum pipe_prot_msg_type type;
> +	u32 size;
> +	union {
> +		struct synthhid_protocol_request request;
> +		struct synthhid_protocol_response response;
> +		struct synthhid_device_info_ack ack;
> +	};
> +};
> +
> +/*
> + * Represents an mousevsc device
> + */
> +struct mousevsc_dev {
> +	struct hv_device	*device;
> +	unsigned char		init_complete;
> +	struct mousevsc_prt_msg	protocol_req;
> +	struct mousevsc_prt_msg	protocol_resp;
> +	/* Synchronize the request/response if needed */
> +	struct completion	wait_event;
> +	int			dev_info_status;
> +
> +	struct hid_descriptor	*hid_desc;
> +	unsigned char		*report_desc;
> +	u32			report_desc_size;
> +	struct hv_input_dev_info hid_dev_info;
> +	int			connected;
> +	struct hid_device       *hid_device;
> +};
> +
> +
> +static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
> +{
> +	struct mousevsc_dev *input_dev;
> +
> +	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
> +
> +	if (!input_dev)
> +		return NULL;
> +
> +	input_dev->device = device;
> +	hv_set_drvdata(device, input_dev);
> +	init_completion(&input_dev->wait_event);
> +
> +	return input_dev;
> +}
> +
> +static void free_input_device(struct mousevsc_dev *device)
> +{
> +	kfree(device->hid_desc);
> +	kfree(device->report_desc);
> +	hv_set_drvdata(device->device, NULL);
> +	kfree(device);
> +}
> +
> +
> +static void mousevsc_on_receive_device_info(struct mousevsc_dev
> *input_device,
> +				struct synthhid_device_info *device_info)
> +{
> +	int ret = 0;
> +	struct hid_descriptor *desc;
> +	struct mousevsc_prt_msg ack;
> +
> +	/* Assume success for now */
> +	input_device->dev_info_status = 0;
> +
> +	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
> +		sizeof(struct hv_input_dev_info));
> +
> +	desc = &device_info->hid_descriptor;
> +	WARN_ON(desc->bLength == 0);
> +
> +	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
> +
> +	if (!input_device->hid_desc)
> +		goto cleanup;
> +
> +	memcpy(input_device->hid_desc, desc, desc->bLength);
> +
> +	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
> +	if (input_device->report_desc_size == 0)
> +		goto cleanup;
> +	input_device->report_desc = kzalloc(input_device->report_desc_size,
> +					  GFP_ATOMIC);
> +
> +	if (!input_device->report_desc)
> +		goto cleanup;
> +
> +	memcpy(input_device->report_desc,
> +	       ((unsigned char *)desc) + desc->bLength,
> +	       desc->desc[0].wDescriptorLength);
> +
> +	/* Send the ack */
> +	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
> +
> +	ack.type = PIPE_MESSAGE_DATA;
> +	ack.size = sizeof(struct synthhid_device_info_ack);
> +
> +	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
> +	ack.ack.header.size = 1;
> +	ack.ack.reserved = 0;
> +
> +	ret = vmbus_sendpacket(input_device->device->channel,
> +			&ack,
> +			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
> +			sizeof(struct synthhid_device_info_ack),
> +			(unsigned long)&ack,
> +			VM_PKT_DATA_INBAND,
> +
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> +	if (ret != 0)
> +		goto cleanup;
> +
> +	complete(&input_device->wait_event);
> +
> +	return;
> +
> +cleanup:
> +	kfree(input_device->hid_desc);
> +	input_device->hid_desc = NULL;
> +
> +	kfree(input_device->report_desc);
> +	input_device->report_desc = NULL;
> +
> +	input_device->dev_info_status = -1;
> +	complete(&input_device->wait_event);
> +}
> +
> +static void mousevsc_on_receive(struct hv_device *device,
> +				struct vmpacket_descriptor *packet)
> +{
> +	struct pipe_prt_msg *pipe_msg;
> +	struct synthhid_msg *hid_msg;
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> +	struct synthhid_input_report *input_report;
> +
> +	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
> +						(packet->offset8 << 3));
> +
> +	if (pipe_msg->type != PIPE_MESSAGE_DATA)
> +		return;
> +
> +	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
> +
> +	switch (hid_msg->header.type) {
> +	case SYNTH_HID_PROTOCOL_RESPONSE:
> +		memcpy(&input_dev->protocol_resp, pipe_msg,
> +		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
> +		       sizeof(unsigned char));
> +		complete(&input_dev->wait_event);
> +		break;
> +
> +	case SYNTH_HID_INITIAL_DEVICE_INFO:
> +		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
> +
> +		/*
> +		 * Parse out the device info into device attr,
> +		 * hid desc and report desc
> +		 */
> +		mousevsc_on_receive_device_info(input_dev,
> +			(struct synthhid_device_info *)&pipe_msg->data[0]);
> +		break;
> +	case SYNTH_HID_INPUT_REPORT:
> +		input_report =
> +			(struct synthhid_input_report *)&pipe_msg->data[0];
> +		if (!input_dev->init_complete)
> +			break;
> +		hid_input_report(input_dev->hid_device,
> +				HID_INPUT_REPORT, input_report->buffer,
> +				input_report->header.size, 1);
> +		break;
> +	default:
> +		pr_err("unsupported hid msg type - type %d len %d",
> +		       hid_msg->header.type, hid_msg->header.size);
> +		break;
> +	}
> +
> +}
> +
> +static void mousevsc_on_channel_callback(void *context)
> +{
> +	const int packetSize = 0x100;
> +	int ret = 0;
> +	struct hv_device *device = (struct hv_device *)context;
> +
> +	u32 bytes_recvd;
> +	u64 req_id;
> +	unsigned char packet[0x100];
> +	struct vmpacket_descriptor *desc;
> +	unsigned char	*buffer = packet;
> +	int	bufferlen = packetSize;
> +
> +
> +	do {
> +		ret = vmbus_recvpacket_raw(device->channel, buffer,
> +					bufferlen, &bytes_recvd, &req_id);
> +
> +		if (ret == 0) {
> +			if (bytes_recvd > 0) {
> +				desc = (struct vmpacket_descriptor *)buffer;
> +
> +				switch (desc->type) {
> +				case VM_PKT_COMP:
> +					break;
> +
> +				case VM_PKT_DATA_INBAND:
> +					mousevsc_on_receive(
> +						device, desc);
> +					break;
> +
> +				default:
> +					pr_err("unhandled packet type %d, tid
> %llx len %d\n",
> +						   desc->type,
> +						   req_id,
> +						   bytes_recvd);
> +					break;
> +				}
> +
> +				/* reset */
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +			} else {
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +				break;
> +			}
> +		} else if (ret == -ENOBUFS) {
> +			/* Handle large packet */
> +			bufferlen = bytes_recvd;
> +			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> +
> +			if (buffer == NULL) {
> +				buffer = packet;
> +				bufferlen = packetSize;
> +				break;
> +			}
> +		}
> +	} while (1);
> +
> +	return;
> +}
> +
> +static int mousevsc_connect_to_vsp(struct hv_device *device)
> +{
> +	int ret = 0;
> +	int t;
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> +	struct mousevsc_prt_msg *request;
> +	struct mousevsc_prt_msg *response;
> +
> +
> +	request = &input_dev->protocol_req;
> +
> +	memset(request, 0, sizeof(struct mousevsc_prt_msg));
> +
> +	request->type = PIPE_MESSAGE_DATA;
> +	request->size = sizeof(struct synthhid_protocol_request);
> +
> +	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
> +	request->request.header.size = sizeof(unsigned int);
> +	request->request.version_requested.version =
> SYNTHHID_INPUT_VERSION;
> +
> +
> +	ret = vmbus_sendpacket(device->channel, request,
> +				sizeof(struct pipe_prt_msg) -
> +				sizeof(unsigned char) +
> +				sizeof(struct synthhid_protocol_request),
> +				(unsigned long)request,
> +				VM_PKT_DATA_INBAND,
> +
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> +	if (ret != 0)
> +		goto cleanup;
> +
> +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> +	if (t == 0) {
> +		ret = -ETIMEDOUT;
> +		goto cleanup;
> +	}
> +
> +	response = &input_dev->protocol_resp;
> +
> +	if (!response->response.approved) {
> +		pr_err("synthhid protocol request failed (version %d)",
> +		       SYNTHHID_INPUT_VERSION);
> +		ret = -ENODEV;
> +		goto cleanup;
> +	}
> +
> +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> +	if (t == 0) {
> +		ret = -ETIMEDOUT;
> +		goto cleanup;
> +	}
> +
> +	/*
> +	 * We should have gotten the device attr, hid desc and report
> +	 * desc at this point
> +	 */
> +	if (input_dev->dev_info_status)
> +		ret = -ENOMEM;
> +
> +cleanup:
> +
> +	return ret;
> +}
> +
> +static int mousevsc_hid_open(struct hid_device *hid)
> +{
> +	return 0;
> +}
> +
> +static void mousevsc_hid_close(struct hid_device *hid)
> +{
> +}
> +
> +static struct hid_ll_driver mousevsc_ll_driver = {
> +	.open = mousevsc_hid_open,
> +	.close = mousevsc_hid_close,
> +};
> +
> +static struct hid_driver mousevsc_hid_driver;
> +
> +static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
> +{
> +	struct hid_device *hid_dev;
> +	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
> +
> +	hid_dev = hid_allocate_device();
> +	if (IS_ERR(hid_dev))
> +		return;
> +
> +	hid_dev->ll_driver = &mousevsc_ll_driver;
> +	hid_dev->driver = &mousevsc_hid_driver;
> +
> +	if (hid_parse_report(hid_dev, packet, len))
> +		return;
> +
> +	hid_dev->bus = BUS_VIRTUAL;
> +	hid_dev->vendor = input_device->hid_dev_info.vendor;
> +	hid_dev->product = input_device->hid_dev_info.product;
> +	hid_dev->version = input_device->hid_dev_info.version;
> +
> +	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
> +
> +	if (!hidinput_connect(hid_dev, 0)) {
> +		hid_dev->claimed |= HID_CLAIMED_INPUT;
> +
> +		input_device->connected = 1;
> +
> +	}
> +
> +	input_device->hid_device = hid_dev;
> +}
> +
> +static int mousevsc_on_device_add(struct hv_device *device)
> +{
> +	int ret = 0;
> +	struct mousevsc_dev *input_dev;
> +
> +	input_dev = alloc_input_device(device);
> +
> +	if (!input_dev)
> +		return -ENOMEM;
> +
> +	input_dev->init_complete = false;
> +
> +	ret = vmbus_open(device->channel,
> +		INPUTVSC_SEND_RING_BUFFER_SIZE,
> +		INPUTVSC_RECV_RING_BUFFER_SIZE,
> +		NULL,
> +		0,
> +		mousevsc_on_channel_callback,
> +		device
> +		);
> +
> +	if (ret != 0) {
> +		free_input_device(input_dev);
> +		return ret;
> +	}
> +
> +
> +	ret = mousevsc_connect_to_vsp(device);
> +
> +	if (ret != 0) {
> +		vmbus_close(device->channel);
> +		free_input_device(input_dev);
> +		return ret;
> +	}
> +
> +
> +	/* workaround SA-167 */
> +	if (input_dev->report_desc[14] == 0x25)
> +		input_dev->report_desc[14] = 0x29;
> +
> +	reportdesc_callback(device, input_dev->report_desc,
> +			    input_dev->report_desc_size);
> +
> +	input_dev->init_complete = true;
> +
> +	return ret;
> +}
> +
> +static int mousevsc_probe(struct hv_device *dev,
> +			const struct hv_vmbus_device_id *dev_id)
> +{
> +
> +	return mousevsc_on_device_add(dev);
> +
> +}
> +
> +static int mousevsc_remove(struct hv_device *dev)
> +{
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
> +
> +	vmbus_close(dev->channel);
> +
> +	if (input_dev->connected) {
> +		hidinput_disconnect(input_dev->hid_device);
> +		input_dev->connected = 0;
> +		hid_destroy_device(input_dev->hid_device);
> +	}
> +
> +	free_input_device(input_dev);
> +
> +	return 0;
> +}
> +
> +static const struct hv_vmbus_device_id id_table[] = {
> +	/* Mouse guid */
> +	{ VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
> +		       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(vmbus, id_table);
> +
> +static struct  hv_driver mousevsc_drv = {
> +	.name = "mousevsc",
> +	.id_table = id_table,
> +	.probe = mousevsc_probe,
> +	.remove = mousevsc_remove,
> +};
> +
> +static int __init mousevsc_init(void)
> +{
> +	return vmbus_driver_register(&mousevsc_drv);
> +}
> +
> +static void __exit mousevsc_exit(void)
> +{
> +	vmbus_driver_unregister(&mousevsc_drv);
> +}
> +
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(HV_DRV_VERSION);
> +module_init(mousevsc_init);
> +module_exit(mousevsc_exit);
> diff --git a/drivers/staging/hv/Kconfig b/drivers/staging/hv/Kconfig
> index 072185e..6c0dc30 100644
> --- a/drivers/staging/hv/Kconfig
> +++ b/drivers/staging/hv/Kconfig
> @@ -9,9 +9,3 @@ config HYPERV_NET
>  	depends on HYPERV && NET
>  	help
>  	  Select this option to enable the Hyper-V virtual network driver.
> -
> -config HYPERV_MOUSE
> -	tristate "Microsoft Hyper-V mouse driver"
> -	depends on HYPERV && HID
> -	help
> -	  Select this option to enable the Hyper-V mouse driver.
> diff --git a/drivers/staging/hv/Makefile b/drivers/staging/hv/Makefile
> index e071c12..3a2751e 100644
> --- a/drivers/staging/hv/Makefile
> +++ b/drivers/staging/hv/Makefile
> @@ -1,7 +1,6 @@
>  obj-$(CONFIG_HYPERV)		+= hv_timesource.o
>  obj-$(CONFIG_HYPERV_STORAGE)	+= hv_storvsc.o
>  obj-$(CONFIG_HYPERV_NET)	+= hv_netvsc.o
> -obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
> 
>  hv_storvsc-y := storvsc_drv.o
>  hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o
> diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c
> deleted file mode 100644
> index ccd39c7..0000000
> --- a/drivers/staging/hv/hv_mouse.c
> +++ /dev/null
> @@ -1,599 +0,0 @@
> -/*
> - *  Copyright (c) 2009, Citrix Systems, Inc.
> - *  Copyright (c) 2010, Microsoft Corporation.
> - *  Copyright (c) 2011, Novell Inc.
> - *
> - *  This program is free software; you can redistribute it and/or modify it
> - *  under the terms and conditions of the GNU General Public License,
> - *  version 2, as published by the Free Software Foundation.
> - *
> - *  This program is distributed in the hope it will be useful, but WITHOUT
> - *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> - *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> for
> - *  more details.
> - */
> -#include <linux/init.h>
> -#include <linux/module.h>
> -#include <linux/delay.h>
> -#include <linux/device.h>
> -#include <linux/workqueue.h>
> -#include <linux/sched.h>
> -#include <linux/wait.h>
> -#include <linux/input.h>
> -#include <linux/hid.h>
> -#include <linux/hiddev.h>
> -#include <linux/hyperv.h>
> -
> -
> -struct hv_input_dev_info {
> -	unsigned int size;
> -	unsigned short vendor;
> -	unsigned short product;
> -	unsigned short version;
> -	unsigned short reserved[11];
> -};
> -
> -/* The maximum size of a synthetic input message. */
> -#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
> -
> -/*
> - * Current version
> - *
> - * History:
> - * Beta, RC < 2008/1/22        1,0
> - * RC > 2008/1/22              2,0
> - */
> -#define SYNTHHID_INPUT_VERSION_MAJOR	2
> -#define SYNTHHID_INPUT_VERSION_MINOR	0
> -#define SYNTHHID_INPUT_VERSION
> 	(SYNTHHID_INPUT_VERSION_MINOR | \
> -					 (SYNTHHID_INPUT_VERSION_MAJOR <<
> 16))
> -
> -
> -#pragma pack(push, 1)
> -/*
> - * Message types in the synthetic input protocol
> - */
> -enum synthhid_msg_type {
> -	SYNTH_HID_PROTOCOL_REQUEST,
> -	SYNTH_HID_PROTOCOL_RESPONSE,
> -	SYNTH_HID_INITIAL_DEVICE_INFO,
> -	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
> -	SYNTH_HID_INPUT_REPORT,
> -	SYNTH_HID_MAX
> -};
> -
> -/*
> - * Basic message structures.
> - */
> -struct synthhid_msg_hdr {
> -	enum synthhid_msg_type type;
> -	u32 size;
> -};
> -
> -struct synthhid_msg {
> -	struct synthhid_msg_hdr header;
> -	char data[1]; /* Enclosed message */
> -};
> -
> -union synthhid_version {
> -	struct {
> -		u16 minor_version;
> -		u16 major_version;
> -	};
> -	u32 version;
> -};
> -
> -/*
> - * Protocol messages
> - */
> -struct synthhid_protocol_request {
> -	struct synthhid_msg_hdr header;
> -	union synthhid_version version_requested;
> -};
> -
> -struct synthhid_protocol_response {
> -	struct synthhid_msg_hdr header;
> -	union synthhid_version version_requested;
> -	unsigned char approved;
> -};
> -
> -struct synthhid_device_info {
> -	struct synthhid_msg_hdr header;
> -	struct hv_input_dev_info hid_dev_info;
> -	struct hid_descriptor hid_descriptor;
> -};
> -
> -struct synthhid_device_info_ack {
> -	struct synthhid_msg_hdr header;
> -	unsigned char reserved;
> -};
> -
> -struct synthhid_input_report {
> -	struct synthhid_msg_hdr header;
> -	char buffer[1];
> -};
> -
> -#pragma pack(pop)
> -
> -#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> -#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> -
> -#define NBITS(x) (((x)/BITS_PER_LONG)+1)
> -
> -enum pipe_prot_msg_type {
> -	PIPE_MESSAGE_INVALID,
> -	PIPE_MESSAGE_DATA,
> -	PIPE_MESSAGE_MAXIMUM
> -};
> -
> -
> -struct pipe_prt_msg {
> -	enum pipe_prot_msg_type type;
> -	u32 size;
> -	char data[1];
> -};
> -
> -struct  mousevsc_prt_msg {
> -	enum pipe_prot_msg_type type;
> -	u32 size;
> -	union {
> -		struct synthhid_protocol_request request;
> -		struct synthhid_protocol_response response;
> -		struct synthhid_device_info_ack ack;
> -	};
> -};
> -
> -/*
> - * Represents an mousevsc device
> - */
> -struct mousevsc_dev {
> -	struct hv_device	*device;
> -	unsigned char		init_complete;
> -	struct mousevsc_prt_msg	protocol_req;
> -	struct mousevsc_prt_msg	protocol_resp;
> -	/* Synchronize the request/response if needed */
> -	struct completion	wait_event;
> -	int			dev_info_status;
> -
> -	struct hid_descriptor	*hid_desc;
> -	unsigned char		*report_desc;
> -	u32			report_desc_size;
> -	struct hv_input_dev_info hid_dev_info;
> -	int			connected;
> -	struct hid_device       *hid_device;
> -};
> -
> -
> -static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
> -{
> -	struct mousevsc_dev *input_dev;
> -
> -	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
> -
> -	if (!input_dev)
> -		return NULL;
> -
> -	input_dev->device = device;
> -	hv_set_drvdata(device, input_dev);
> -	init_completion(&input_dev->wait_event);
> -
> -	return input_dev;
> -}
> -
> -static void free_input_device(struct mousevsc_dev *device)
> -{
> -	kfree(device->hid_desc);
> -	kfree(device->report_desc);
> -	hv_set_drvdata(device->device, NULL);
> -	kfree(device);
> -}
> -
> -
> -static void mousevsc_on_receive_device_info(struct mousevsc_dev
> *input_device,
> -				struct synthhid_device_info *device_info)
> -{
> -	int ret = 0;
> -	struct hid_descriptor *desc;
> -	struct mousevsc_prt_msg ack;
> -
> -	/* Assume success for now */
> -	input_device->dev_info_status = 0;
> -
> -	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
> -		sizeof(struct hv_input_dev_info));
> -
> -	desc = &device_info->hid_descriptor;
> -	WARN_ON(desc->bLength == 0);
> -
> -	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
> -
> -	if (!input_device->hid_desc)
> -		goto cleanup;
> -
> -	memcpy(input_device->hid_desc, desc, desc->bLength);
> -
> -	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
> -	if (input_device->report_desc_size == 0)
> -		goto cleanup;
> -	input_device->report_desc = kzalloc(input_device->report_desc_size,
> -					  GFP_ATOMIC);
> -
> -	if (!input_device->report_desc)
> -		goto cleanup;
> -
> -	memcpy(input_device->report_desc,
> -	       ((unsigned char *)desc) + desc->bLength,
> -	       desc->desc[0].wDescriptorLength);
> -
> -	/* Send the ack */
> -	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
> -
> -	ack.type = PIPE_MESSAGE_DATA;
> -	ack.size = sizeof(struct synthhid_device_info_ack);
> -
> -	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
> -	ack.ack.header.size = 1;
> -	ack.ack.reserved = 0;
> -
> -	ret = vmbus_sendpacket(input_device->device->channel,
> -			&ack,
> -			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
> -			sizeof(struct synthhid_device_info_ack),
> -			(unsigned long)&ack,
> -			VM_PKT_DATA_INBAND,
> -
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> -	if (ret != 0)
> -		goto cleanup;
> -
> -	complete(&input_device->wait_event);
> -
> -	return;
> -
> -cleanup:
> -	kfree(input_device->hid_desc);
> -	input_device->hid_desc = NULL;
> -
> -	kfree(input_device->report_desc);
> -	input_device->report_desc = NULL;
> -
> -	input_device->dev_info_status = -1;
> -	complete(&input_device->wait_event);
> -}
> -
> -static void mousevsc_on_receive(struct hv_device *device,
> -				struct vmpacket_descriptor *packet)
> -{
> -	struct pipe_prt_msg *pipe_msg;
> -	struct synthhid_msg *hid_msg;
> -	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> -	struct synthhid_input_report *input_report;
> -
> -	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
> -						(packet->offset8 << 3));
> -
> -	if (pipe_msg->type != PIPE_MESSAGE_DATA)
> -		return;
> -
> -	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
> -
> -	switch (hid_msg->header.type) {
> -	case SYNTH_HID_PROTOCOL_RESPONSE:
> -		memcpy(&input_dev->protocol_resp, pipe_msg,
> -		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
> -		       sizeof(unsigned char));
> -		complete(&input_dev->wait_event);
> -		break;
> -
> -	case SYNTH_HID_INITIAL_DEVICE_INFO:
> -		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
> -
> -		/*
> -		 * Parse out the device info into device attr,
> -		 * hid desc and report desc
> -		 */
> -		mousevsc_on_receive_device_info(input_dev,
> -			(struct synthhid_device_info *)&pipe_msg->data[0]);
> -		break;
> -	case SYNTH_HID_INPUT_REPORT:
> -		input_report =
> -			(struct synthhid_input_report *)&pipe_msg->data[0];
> -		if (!input_dev->init_complete)
> -			break;
> -		hid_input_report(input_dev->hid_device,
> -				HID_INPUT_REPORT, input_report->buffer,
> -				input_report->header.size, 1);
> -		break;
> -	default:
> -		pr_err("unsupported hid msg type - type %d len %d",
> -		       hid_msg->header.type, hid_msg->header.size);
> -		break;
> -	}
> -
> -}
> -
> -static void mousevsc_on_channel_callback(void *context)
> -{
> -	const int packetSize = 0x100;
> -	int ret = 0;
> -	struct hv_device *device = (struct hv_device *)context;
> -
> -	u32 bytes_recvd;
> -	u64 req_id;
> -	unsigned char packet[0x100];
> -	struct vmpacket_descriptor *desc;
> -	unsigned char	*buffer = packet;
> -	int	bufferlen = packetSize;
> -
> -
> -	do {
> -		ret = vmbus_recvpacket_raw(device->channel, buffer,
> -					bufferlen, &bytes_recvd, &req_id);
> -
> -		if (ret == 0) {
> -			if (bytes_recvd > 0) {
> -				desc = (struct vmpacket_descriptor *)buffer;
> -
> -				switch (desc->type) {
> -				case VM_PKT_COMP:
> -					break;
> -
> -				case VM_PKT_DATA_INBAND:
> -					mousevsc_on_receive(
> -						device, desc);
> -					break;
> -
> -				default:
> -					pr_err("unhandled packet type %d, tid
> %llx len %d\n",
> -						   desc->type,
> -						   req_id,
> -						   bytes_recvd);
> -					break;
> -				}
> -
> -				/* reset */
> -				if (bufferlen > packetSize) {
> -					kfree(buffer);
> -
> -					buffer = packet;
> -					bufferlen = packetSize;
> -				}
> -			} else {
> -				if (bufferlen > packetSize) {
> -					kfree(buffer);
> -
> -					buffer = packet;
> -					bufferlen = packetSize;
> -				}
> -				break;
> -			}
> -		} else if (ret == -ENOBUFS) {
> -			/* Handle large packet */
> -			bufferlen = bytes_recvd;
> -			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> -
> -			if (buffer == NULL) {
> -				buffer = packet;
> -				bufferlen = packetSize;
> -				break;
> -			}
> -		}
> -	} while (1);
> -
> -	return;
> -}
> -
> -static int mousevsc_connect_to_vsp(struct hv_device *device)
> -{
> -	int ret = 0;
> -	int t;
> -	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> -	struct mousevsc_prt_msg *request;
> -	struct mousevsc_prt_msg *response;
> -
> -
> -	request = &input_dev->protocol_req;
> -
> -	memset(request, 0, sizeof(struct mousevsc_prt_msg));
> -
> -	request->type = PIPE_MESSAGE_DATA;
> -	request->size = sizeof(struct synthhid_protocol_request);
> -
> -	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
> -	request->request.header.size = sizeof(unsigned int);
> -	request->request.version_requested.version =
> SYNTHHID_INPUT_VERSION;
> -
> -
> -	ret = vmbus_sendpacket(device->channel, request,
> -				sizeof(struct pipe_prt_msg) -
> -				sizeof(unsigned char) +
> -				sizeof(struct synthhid_protocol_request),
> -				(unsigned long)request,
> -				VM_PKT_DATA_INBAND,
> -
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> -	if (ret != 0)
> -		goto cleanup;
> -
> -	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> -	if (t == 0) {
> -		ret = -ETIMEDOUT;
> -		goto cleanup;
> -	}
> -
> -	response = &input_dev->protocol_resp;
> -
> -	if (!response->response.approved) {
> -		pr_err("synthhid protocol request failed (version %d)",
> -		       SYNTHHID_INPUT_VERSION);
> -		ret = -ENODEV;
> -		goto cleanup;
> -	}
> -
> -	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> -	if (t == 0) {
> -		ret = -ETIMEDOUT;
> -		goto cleanup;
> -	}
> -
> -	/*
> -	 * We should have gotten the device attr, hid desc and report
> -	 * desc at this point
> -	 */
> -	if (input_dev->dev_info_status)
> -		ret = -ENOMEM;
> -
> -cleanup:
> -
> -	return ret;
> -}
> -
> -static int mousevsc_hid_open(struct hid_device *hid)
> -{
> -	return 0;
> -}
> -
> -static void mousevsc_hid_close(struct hid_device *hid)
> -{
> -}
> -
> -static struct hid_ll_driver mousevsc_ll_driver = {
> -	.open = mousevsc_hid_open,
> -	.close = mousevsc_hid_close,
> -};
> -
> -static struct hid_driver mousevsc_hid_driver;
> -
> -static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
> -{
> -	struct hid_device *hid_dev;
> -	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
> -
> -	hid_dev = hid_allocate_device();
> -	if (IS_ERR(hid_dev))
> -		return;
> -
> -	hid_dev->ll_driver = &mousevsc_ll_driver;
> -	hid_dev->driver = &mousevsc_hid_driver;
> -
> -	if (hid_parse_report(hid_dev, packet, len))
> -		return;
> -
> -	hid_dev->bus = BUS_VIRTUAL;
> -	hid_dev->vendor = input_device->hid_dev_info.vendor;
> -	hid_dev->product = input_device->hid_dev_info.product;
> -	hid_dev->version = input_device->hid_dev_info.version;
> -
> -	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
> -
> -	if (!hidinput_connect(hid_dev, 0)) {
> -		hid_dev->claimed |= HID_CLAIMED_INPUT;
> -
> -		input_device->connected = 1;
> -
> -	}
> -
> -	input_device->hid_device = hid_dev;
> -}
> -
> -static int mousevsc_on_device_add(struct hv_device *device)
> -{
> -	int ret = 0;
> -	struct mousevsc_dev *input_dev;
> -
> -	input_dev = alloc_input_device(device);
> -
> -	if (!input_dev)
> -		return -ENOMEM;
> -
> -	input_dev->init_complete = false;
> -
> -	ret = vmbus_open(device->channel,
> -		INPUTVSC_SEND_RING_BUFFER_SIZE,
> -		INPUTVSC_RECV_RING_BUFFER_SIZE,
> -		NULL,
> -		0,
> -		mousevsc_on_channel_callback,
> -		device
> -		);
> -
> -	if (ret != 0) {
> -		free_input_device(input_dev);
> -		return ret;
> -	}
> -
> -
> -	ret = mousevsc_connect_to_vsp(device);
> -
> -	if (ret != 0) {
> -		vmbus_close(device->channel);
> -		free_input_device(input_dev);
> -		return ret;
> -	}
> -
> -
> -	/* workaround SA-167 */
> -	if (input_dev->report_desc[14] == 0x25)
> -		input_dev->report_desc[14] = 0x29;
> -
> -	reportdesc_callback(device, input_dev->report_desc,
> -			    input_dev->report_desc_size);
> -
> -	input_dev->init_complete = true;
> -
> -	return ret;
> -}
> -
> -static int mousevsc_probe(struct hv_device *dev,
> -			const struct hv_vmbus_device_id *dev_id)
> -{
> -
> -	return mousevsc_on_device_add(dev);
> -
> -}
> -
> -static int mousevsc_remove(struct hv_device *dev)
> -{
> -	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
> -
> -	vmbus_close(dev->channel);
> -
> -	if (input_dev->connected) {
> -		hidinput_disconnect(input_dev->hid_device);
> -		input_dev->connected = 0;
> -		hid_destroy_device(input_dev->hid_device);
> -	}
> -
> -	free_input_device(input_dev);
> -
> -	return 0;
> -}
> -
> -static const struct hv_vmbus_device_id id_table[] = {
> -	/* Mouse guid */
> -	{ VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
> -		       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
> -	{ },
> -};
> -
> -MODULE_DEVICE_TABLE(vmbus, id_table);
> -
> -static struct  hv_driver mousevsc_drv = {
> -	.name = "mousevsc",
> -	.id_table = id_table,
> -	.probe = mousevsc_probe,
> -	.remove = mousevsc_remove,
> -};
> -
> -static int __init mousevsc_init(void)
> -{
> -	return vmbus_driver_register(&mousevsc_drv);
> -}
> -
> -static void __exit mousevsc_exit(void)
> -{
> -	vmbus_driver_unregister(&mousevsc_drv);
> -}
> -
> -MODULE_LICENSE("GPL");
> -MODULE_VERSION(HV_DRV_VERSION);
> -module_init(mousevsc_init);
> -module_exit(mousevsc_exit);
> --
> 1.7.4.1
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-15  6:08 [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging K. Y. Srinivasan
  2011-10-15  6:36 ` Joe Perches
  2011-10-19 23:48 ` KY Srinivasan
@ 2011-10-23  7:24 ` Dmitry Torokhov
  2011-10-23 14:33   ` KY Srinivasan
  2011-10-23 15:45   ` KY Srinivasan
  2 siblings, 2 replies; 12+ messages in thread
From: Dmitry Torokhov @ 2011-10-23  7:24 UTC (permalink / raw)
  To: K. Y. Srinivasan
  Cc: gregkh, linux-kernel, devel, virtualization, linux-input,
	Haiyang Zhang, Jiri Kosina

Hi K. Y.,

On Fri, Oct 14, 2011 at 11:08:27PM -0700, K. Y. Srinivasan wrote:
> In preparation for moving the mouse driver out of staging, seek community
> review of the mouse driver code.
> 

Because it is a HID driver it should go through Jiri Kosina's tree
(CCed). Still, a few comments below.

> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> ---
>  drivers/hid/Kconfig           |    6 +
>  drivers/hid/Makefile          |    1 +
>  drivers/hid/hv_mouse.c        |  599 +++++++++++++++++++++++++++++++++++++++++
>  drivers/staging/hv/Kconfig    |    6 -
>  drivers/staging/hv/Makefile   |    1 -
>  drivers/staging/hv/hv_mouse.c |  599 -----------------------------------------
>  6 files changed, 606 insertions(+), 606 deletions(-)
>  create mode 100644 drivers/hid/hv_mouse.c
>  delete mode 100644 drivers/staging/hv/hv_mouse.c
> 
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 1130a89..f8b98b8 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -613,6 +613,12 @@ config HID_ZYDACRON
>  	---help---
>  	Support for Zydacron remote control.
>  
> +config HYPERV_MOUSE
> +	tristate "Microsoft Hyper-V mouse driver"
> +	depends on HYPERV
> +	help
> +	  Select this option to enable the Hyper-V mouse driver.
> +
>  endmenu
>  
>  endif # HID_SUPPORT
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 0a0a38e..436ac2e 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
>  obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
>  obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
>  obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
> +obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
>  
>  obj-$(CONFIG_USB_HID)		+= usbhid/
>  obj-$(CONFIG_USB_MOUSE)		+= usbhid/
> diff --git a/drivers/hid/hv_mouse.c b/drivers/hid/hv_mouse.c
> new file mode 100644
> index 0000000..ccd39c7
> --- /dev/null
> +++ b/drivers/hid/hv_mouse.c
> @@ -0,0 +1,599 @@
> +/*
> + *  Copyright (c) 2009, Citrix Systems, Inc.
> + *  Copyright (c) 2010, Microsoft Corporation.
> + *  Copyright (c) 2011, Novell Inc.
> + *
> + *  This program is free software; you can redistribute it and/or modify it
> + *  under the terms and conditions of the GNU General Public License,
> + *  version 2, as published by the Free Software Foundation.
> + *
> + *  This program is distributed in the hope it will be useful, but WITHOUT
> + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + *  more details.
> + */
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/workqueue.h>

Is this really needed?

> +#include <linux/sched.h>

You probably want completion.h instead.

> +#include <linux/wait.h>
> +#include <linux/input.h>
> +#include <linux/hid.h>
> +#include <linux/hiddev.h>
> +#include <linux/hyperv.h>
> +
> +
> +struct hv_input_dev_info {
> +	unsigned int size;
> +	unsigned short vendor;
> +	unsigned short product;
> +	unsigned short version;
> +	unsigned short reserved[11];
> +};
> +
> +/* The maximum size of a synthetic input message. */
> +#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
> +
> +/*
> + * Current version
> + *
> + * History:
> + * Beta, RC < 2008/1/22        1,0
> + * RC > 2008/1/22              2,0
> + */
> +#define SYNTHHID_INPUT_VERSION_MAJOR	2
> +#define SYNTHHID_INPUT_VERSION_MINOR	0
> +#define SYNTHHID_INPUT_VERSION		(SYNTHHID_INPUT_VERSION_MINOR | \
> +					 (SYNTHHID_INPUT_VERSION_MAJOR << 16))
> +
> +
> +#pragma pack(push, 1)
> +/*
> + * Message types in the synthetic input protocol
> + */
> +enum synthhid_msg_type {
> +	SYNTH_HID_PROTOCOL_REQUEST,
> +	SYNTH_HID_PROTOCOL_RESPONSE,
> +	SYNTH_HID_INITIAL_DEVICE_INFO,
> +	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
> +	SYNTH_HID_INPUT_REPORT,
> +	SYNTH_HID_MAX
> +};
> +
> +/*
> + * Basic message structures.
> + */
> +struct synthhid_msg_hdr {
> +	enum synthhid_msg_type type;
> +	u32 size;
> +};
> +
> +struct synthhid_msg {
> +	struct synthhid_msg_hdr header;
> +	char data[1]; /* Enclosed message */
> +};
> +
> +union synthhid_version {
> +	struct {
> +		u16 minor_version;
> +		u16 major_version;
> +	};
> +	u32 version;
> +};
> +
> +/*
> + * Protocol messages
> + */
> +struct synthhid_protocol_request {
> +	struct synthhid_msg_hdr header;
> +	union synthhid_version version_requested;
> +};
> +
> +struct synthhid_protocol_response {
> +	struct synthhid_msg_hdr header;
> +	union synthhid_version version_requested;
> +	unsigned char approved;
> +};
> +
> +struct synthhid_device_info {
> +	struct synthhid_msg_hdr header;
> +	struct hv_input_dev_info hid_dev_info;
> +	struct hid_descriptor hid_descriptor;
> +};
> +
> +struct synthhid_device_info_ack {
> +	struct synthhid_msg_hdr header;
> +	unsigned char reserved;
> +};
> +
> +struct synthhid_input_report {
> +	struct synthhid_msg_hdr header;
> +	char buffer[1];
> +};
> +
> +#pragma pack(pop)
> +
> +#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> +#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> +
> +#define NBITS(x) (((x)/BITS_PER_LONG)+1)
> +
> +enum pipe_prot_msg_type {
> +	PIPE_MESSAGE_INVALID,
> +	PIPE_MESSAGE_DATA,
> +	PIPE_MESSAGE_MAXIMUM
> +};
> +
> +
> +struct pipe_prt_msg {
> +	enum pipe_prot_msg_type type;
> +	u32 size;
> +	char data[1];
> +};
> +
> +struct  mousevsc_prt_msg {
> +	enum pipe_prot_msg_type type;
> +	u32 size;
> +	union {
> +		struct synthhid_protocol_request request;
> +		struct synthhid_protocol_response response;
> +		struct synthhid_device_info_ack ack;
> +	};
> +};
> +
> +/*
> + * Represents an mousevsc device
> + */
> +struct mousevsc_dev {
> +	struct hv_device	*device;
> +	unsigned char		init_complete;
> +	struct mousevsc_prt_msg	protocol_req;
> +	struct mousevsc_prt_msg	protocol_resp;
> +	/* Synchronize the request/response if needed */
> +	struct completion	wait_event;
> +	int			dev_info_status;
> +
> +	struct hid_descriptor	*hid_desc;
> +	unsigned char		*report_desc;
> +	u32			report_desc_size;
> +	struct hv_input_dev_info hid_dev_info;
> +	int			connected;

bool?

> +	struct hid_device       *hid_device;
> +};
> +
> +
> +static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
> +{
> +	struct mousevsc_dev *input_dev;
> +
> +	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
> +

This blank line is extra.

> +	if (!input_dev)
> +		return NULL;
> +
> +	input_dev->device = device;
> +	hv_set_drvdata(device, input_dev);
> +	init_completion(&input_dev->wait_event);
> +
> +	return input_dev;
> +}
> +
> +static void free_input_device(struct mousevsc_dev *device)
> +{
> +	kfree(device->hid_desc);
> +	kfree(device->report_desc);
> +	hv_set_drvdata(device->device, NULL);
> +	kfree(device);
> +}
> +
> +
> +static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
> +				struct synthhid_device_info *device_info)
> +{
> +	int ret = 0;
> +	struct hid_descriptor *desc;
> +	struct mousevsc_prt_msg ack;
> +
> +	/* Assume success for now */
> +	input_device->dev_info_status = 0;
> +
> +	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
> +		sizeof(struct hv_input_dev_info));
> +
> +	desc = &device_info->hid_descriptor;
> +	WARN_ON(desc->bLength == 0);
> +
> +	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
> +
> +	if (!input_device->hid_desc)
> +		goto cleanup;
> +
> +	memcpy(input_device->hid_desc, desc, desc->bLength);
> +
> +	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
> +	if (input_device->report_desc_size == 0)
> +		goto cleanup;
> +	input_device->report_desc = kzalloc(input_device->report_desc_size,
> +					  GFP_ATOMIC);
> +
> +	if (!input_device->report_desc)
> +		goto cleanup;
> +
> +	memcpy(input_device->report_desc,
> +	       ((unsigned char *)desc) + desc->bLength,
> +	       desc->desc[0].wDescriptorLength);
> +
> +	/* Send the ack */
> +	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
> +
> +	ack.type = PIPE_MESSAGE_DATA;
> +	ack.size = sizeof(struct synthhid_device_info_ack);
> +
> +	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
> +	ack.ack.header.size = 1;
> +	ack.ack.reserved = 0;

That looks like a constant structure...

> +
> +	ret = vmbus_sendpacket(input_device->device->channel,
> +			&ack,
> +			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
> +			sizeof(struct synthhid_device_info_ack),
> +			(unsigned long)&ack,
> +			VM_PKT_DATA_INBAND,
> +			VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> +	if (ret != 0)
> +		goto cleanup;
> +
> +	complete(&input_device->wait_event);
> +
> +	return;
> +
> +cleanup:
> +	kfree(input_device->hid_desc);
> +	input_device->hid_desc = NULL;
> +
> +	kfree(input_device->report_desc);
> +	input_device->report_desc = NULL;
> +
> +	input_device->dev_info_status = -1;
> +	complete(&input_device->wait_event);
> +}
> +
> +static void mousevsc_on_receive(struct hv_device *device,
> +				struct vmpacket_descriptor *packet)
> +{
> +	struct pipe_prt_msg *pipe_msg;
> +	struct synthhid_msg *hid_msg;
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> +	struct synthhid_input_report *input_report;
> +
> +	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
> +						(packet->offset8 << 3));
> +
> +	if (pipe_msg->type != PIPE_MESSAGE_DATA)
> +		return;
> +
> +	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
> +
> +	switch (hid_msg->header.type) {
> +	case SYNTH_HID_PROTOCOL_RESPONSE:
> +		memcpy(&input_dev->protocol_resp, pipe_msg,
> +		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
> +		       sizeof(unsigned char));
> +		complete(&input_dev->wait_event);
> +		break;
> +
> +	case SYNTH_HID_INITIAL_DEVICE_INFO:
> +		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
> +
> +		/*
> +		 * Parse out the device info into device attr,
> +		 * hid desc and report desc
> +		 */
> +		mousevsc_on_receive_device_info(input_dev,
> +			(struct synthhid_device_info *)&pipe_msg->data[0]);
> +		break;
> +	case SYNTH_HID_INPUT_REPORT:
> +		input_report =
> +			(struct synthhid_input_report *)&pipe_msg->data[0];
> +		if (!input_dev->init_complete)
> +			break;
> +		hid_input_report(input_dev->hid_device,
> +				HID_INPUT_REPORT, input_report->buffer,
> +				input_report->header.size, 1);
> +		break;
> +	default:
> +		pr_err("unsupported hid msg type - type %d len %d",
> +		       hid_msg->header.type, hid_msg->header.size);
> +		break;
> +	}
> +
> +}
> +
> +static void mousevsc_on_channel_callback(void *context)
> +{
> +	const int packetSize = 0x100;
> +	int ret = 0;
> +	struct hv_device *device = (struct hv_device *)context;

No need to cast.

> +
> +	u32 bytes_recvd;
> +	u64 req_id;
> +	unsigned char packet[0x100];

Hmm, 100 bytes on stack... and are we in interrupt context by any
chance?

> +	struct vmpacket_descriptor *desc;
> +	unsigned char	*buffer = packet;
> +	int	bufferlen = packetSize;
> +
> +
> +	do {
> +		ret = vmbus_recvpacket_raw(device->channel, buffer,
> +					bufferlen, &bytes_recvd, &req_id);
> +
> +		if (ret == 0) {
> +			if (bytes_recvd > 0) {
> +				desc = (struct vmpacket_descriptor *)buffer;
> +
> +				switch (desc->type) {
> +				case VM_PKT_COMP:
> +					break;
> +
> +				case VM_PKT_DATA_INBAND:
> +					mousevsc_on_receive(
> +						device, desc);
> +					break;
> +
> +				default:
> +					pr_err("unhandled packet type %d, tid %llx len %d\n",
> +						   desc->type,
> +						   req_id,
> +						   bytes_recvd);
> +					break;
> +				}
> +
> +				/* reset */
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +			} else {
> +				if (bufferlen > packetSize) {
> +					kfree(buffer);
> +
> +					buffer = packet;
> +					bufferlen = packetSize;
> +				}
> +				break;
> +			}
> +		} else if (ret == -ENOBUFS) {
> +			/* Handle large packet */
> +			bufferlen = bytes_recvd;
> +			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> +

What happens if we receive even larger amount of data after allocating
the buffer?

> +			if (buffer == NULL) {
> +				buffer = packet;
> +				bufferlen = packetSize;
> +				break;
> +			}
> +		}
> +	} while (1);

So we can be looping indefinitely here as long as other side keeps
sending data?

> +
> +	return;

No naked returns please.

> +}
> +
> +static int mousevsc_connect_to_vsp(struct hv_device *device)
> +{
> +	int ret = 0;
> +	int t;
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> +	struct mousevsc_prt_msg *request;
> +	struct mousevsc_prt_msg *response;
> +
> +
> +	request = &input_dev->protocol_req;
> +
> +	memset(request, 0, sizeof(struct mousevsc_prt_msg));
> +
> +	request->type = PIPE_MESSAGE_DATA;
> +	request->size = sizeof(struct synthhid_protocol_request);
> +
> +	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
> +	request->request.header.size = sizeof(unsigned int);
> +	request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
> +
> +
> +	ret = vmbus_sendpacket(device->channel, request,
> +				sizeof(struct pipe_prt_msg) -
> +				sizeof(unsigned char) +
> +				sizeof(struct synthhid_protocol_request),
> +				(unsigned long)request,
> +				VM_PKT_DATA_INBAND,
> +				VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> +	if (ret != 0)
> +		goto cleanup;
> +
> +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> +	if (t == 0) {
> +		ret = -ETIMEDOUT;
> +		goto cleanup;
> +	}
> +
> +	response = &input_dev->protocol_resp;
> +
> +	if (!response->response.approved) {
> +		pr_err("synthhid protocol request failed (version %d)",
> +		       SYNTHHID_INPUT_VERSION);
> +		ret = -ENODEV;
> +		goto cleanup;
> +	}
> +
> +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);

We just completed the wait for this completion, why are we waiting on
the same completion again?

> +	if (t == 0) {
> +		ret = -ETIMEDOUT;
> +		goto cleanup;
> +	}
> +
> +	/*
> +	 * We should have gotten the device attr, hid desc and report
> +	 * desc at this point
> +	 */
> +	if (input_dev->dev_info_status)
> +		ret = -ENOMEM;

-ENOMEM seems wrong.

> +
> +cleanup:
> +
> +	return ret;
> +}
> +
> +static int mousevsc_hid_open(struct hid_device *hid)
> +{
> +	return 0;
> +}
> +
> +static void mousevsc_hid_close(struct hid_device *hid)
> +{
> +}
> +
> +static struct hid_ll_driver mousevsc_ll_driver = {
> +	.open = mousevsc_hid_open,
> +	.close = mousevsc_hid_close,
> +};
> +
> +static struct hid_driver mousevsc_hid_driver;
> +
> +static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
> +{

This is called from mousevsc_on_device_add() which is part of device
probe. Why it is split into separate function with bizzare arguments is
beyond me. 

> +	struct hid_device *hid_dev;
> +	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
> +
> +	hid_dev = hid_allocate_device();
> +	if (IS_ERR(hid_dev))
> +		return;

This is not very helpful.

> +
> +	hid_dev->ll_driver = &mousevsc_ll_driver;
> +	hid_dev->driver = &mousevsc_hid_driver;
> +
> +	if (hid_parse_report(hid_dev, packet, len))
> +		return;

Neither is this.

> +
> +	hid_dev->bus = BUS_VIRTUAL;
> +	hid_dev->vendor = input_device->hid_dev_info.vendor;
> +	hid_dev->product = input_device->hid_dev_info.product;
> +	hid_dev->version = input_device->hid_dev_info.version;
> +
> +	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
> +
> +	if (!hidinput_connect(hid_dev, 0)) {
> +		hid_dev->claimed |= HID_CLAIMED_INPUT;

Why do you force hidinput claim? Let the normal rules do it.

> +
> +		input_device->connected = 1;

		input_device->connected = true;

> +
> +	}
> +
> +	input_device->hid_device = hid_dev;

This assignment is probably too late.

> +}
> +
> +static int mousevsc_on_device_add(struct hv_device *device)

The only caller of this is mousevsc_probe() so why do you have it>
> +{
> +	int ret = 0;
> +	struct mousevsc_dev *input_dev;
> +
> +	input_dev = alloc_input_device(device);
> +
> +	if (!input_dev)
> +		return -ENOMEM;
> +
> +	input_dev->init_complete = false;
> +
> +	ret = vmbus_open(device->channel,
> +		INPUTVSC_SEND_RING_BUFFER_SIZE,
> +		INPUTVSC_RECV_RING_BUFFER_SIZE,
> +		NULL,
> +		0,
> +		mousevsc_on_channel_callback,
> +		device
> +		);
> +
> +	if (ret != 0) {
> +		free_input_device(input_dev);
> +		return ret;
> +	}
> +
> +
> +	ret = mousevsc_connect_to_vsp(device);
> +
> +	if (ret != 0) {
> +		vmbus_close(device->channel);
> +		free_input_device(input_dev);
> +		return ret;
> +	}
> +
> +
> +	/* workaround SA-167 */
> +	if (input_dev->report_desc[14] == 0x25)
> +		input_dev->report_desc[14] = 0x29;
> +
> +	reportdesc_callback(device, input_dev->report_desc,
> +			    input_dev->report_desc_size);
> +
> +	input_dev->init_complete = true;
> +
> +	return ret;
> +}
> +
> +static int mousevsc_probe(struct hv_device *dev,
> +			const struct hv_vmbus_device_id *dev_id)
> +{
> +
> +	return mousevsc_on_device_add(dev);
> +
> +}
> +
> +static int mousevsc_remove(struct hv_device *dev)
> +{
> +	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
> +
> +	vmbus_close(dev->channel);
> +
> +	if (input_dev->connected) {
> +		hidinput_disconnect(input_dev->hid_device);
> +		input_dev->connected = 0;
> +		hid_destroy_device(input_dev->hid_device);

hid_destroy_device() should disconnect registered handlers for you; you
do not need to do that manually.

> +	}
> +
> +	free_input_device(input_dev);

Calling it input device is terribly confusing to me. I'd also freed it
inline (and used gotos to unwind errors in probe()).

> +
> +	return 0;
> +}
> +
> +static const struct hv_vmbus_device_id id_table[] = {
> +	/* Mouse guid */
> +	{ VMBUS_DEVICE(0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
> +		       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A) },
> +	{ },
> +};
> +
> +MODULE_DEVICE_TABLE(vmbus, id_table);
> +
> +static struct  hv_driver mousevsc_drv = {
> +	.name = "mousevsc",
> +	.id_table = id_table,
> +	.probe = mousevsc_probe,
> +	.remove = mousevsc_remove,
> +};
> +
> +static int __init mousevsc_init(void)
> +{
> +	return vmbus_driver_register(&mousevsc_drv);
> +}
> +
> +static void __exit mousevsc_exit(void)
> +{
> +	vmbus_driver_unregister(&mousevsc_drv);
> +}
> +
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION(HV_DRV_VERSION);
> +module_init(mousevsc_init);
> +module_exit(mousevsc_exit);

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-23  7:24 ` Dmitry Torokhov
@ 2011-10-23 14:33   ` KY Srinivasan
  2011-10-23 15:45   ` KY Srinivasan
  1 sibling, 0 replies; 12+ messages in thread
From: KY Srinivasan @ 2011-10-23 14:33 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Jiri Kosina, Haiyang Zhang, gregkh@suse.de,
	linux-kernel@vger.kernel.org, virtualization@lists.osdl.org,
	linux-input@vger.kernel.org, devel@linuxdriverproject.org



> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Sunday, October 23, 2011 3:24 AM
> To: KY Srinivasan
> Cc: gregkh@suse.de; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; virtualization@lists.osdl.org; linux-
> input@vger.kernel.org; Haiyang Zhang; Jiri Kosina
> Subject: Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> staging
> 
> Hi K. Y.,
> 
> On Fri, Oct 14, 2011 at 11:08:27PM -0700, K. Y. Srinivasan wrote:
> > In preparation for moving the mouse driver out of staging, seek community
> > review of the mouse driver code.
> >
> 
> Because it is a HID driver it should go through Jiri Kosina's tree
> (CCed). Still, a few comments below.

Thanks Dmitry. I will address the comments you have given me, and will
work with Jiri to get this driver out of staging.

Regards,

K. Y

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-23  7:24 ` Dmitry Torokhov
  2011-10-23 14:33   ` KY Srinivasan
@ 2011-10-23 15:45   ` KY Srinivasan
  2011-10-27  0:09     ` Dmitry Torokhov
  1 sibling, 1 reply; 12+ messages in thread
From: KY Srinivasan @ 2011-10-23 15:45 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: gregkh@suse.de, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org, virtualization@lists.osdl.org,
	linux-input@vger.kernel.org, Haiyang Zhang, Jiri Kosina



> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Sunday, October 23, 2011 3:24 AM
> To: KY Srinivasan
> Cc: gregkh@suse.de; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; virtualization@lists.osdl.org; linux-
> input@vger.kernel.org; Haiyang Zhang; Jiri Kosina
> Subject: Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> staging
> 
> Hi K. Y.,
> 
> On Fri, Oct 14, 2011 at 11:08:27PM -0700, K. Y. Srinivasan wrote:
> > In preparation for moving the mouse driver out of staging, seek community
> > review of the mouse driver code.
> >
> 
> Because it is a HID driver it should go through Jiri Kosina's tree
> (CCed). Still, a few comments below.
> 
> > Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> > Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
> > ---
> >  drivers/hid/Kconfig           |    6 +
> >  drivers/hid/Makefile          |    1 +
> >  drivers/hid/hv_mouse.c        |  599
> +++++++++++++++++++++++++++++++++++++++++
> >  drivers/staging/hv/Kconfig    |    6 -
> >  drivers/staging/hv/Makefile   |    1 -
> >  drivers/staging/hv/hv_mouse.c |  599 -----------------------------------------
> >  6 files changed, 606 insertions(+), 606 deletions(-)
> >  create mode 100644 drivers/hid/hv_mouse.c
> >  delete mode 100644 drivers/staging/hv/hv_mouse.c
> >
> > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> > index 1130a89..f8b98b8 100644
> > --- a/drivers/hid/Kconfig
> > +++ b/drivers/hid/Kconfig
> > @@ -613,6 +613,12 @@ config HID_ZYDACRON
> >  	---help---
> >  	Support for Zydacron remote control.
> >
> > +config HYPERV_MOUSE
> > +	tristate "Microsoft Hyper-V mouse driver"
> > +	depends on HYPERV
> > +	help
> > +	  Select this option to enable the Hyper-V mouse driver.
> > +
> >  endmenu
> >
> >  endif # HID_SUPPORT
> > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> > index 0a0a38e..436ac2e 100644
> > --- a/drivers/hid/Makefile
> > +++ b/drivers/hid/Makefile
> > @@ -76,6 +76,7 @@ obj-$(CONFIG_HID_ZYDACRON)	+= hid-zydacron.o
> >  obj-$(CONFIG_HID_WACOM)		+= hid-wacom.o
> >  obj-$(CONFIG_HID_WALTOP)	+= hid-waltop.o
> >  obj-$(CONFIG_HID_WIIMOTE)	+= hid-wiimote.o
> > +obj-$(CONFIG_HYPERV_MOUSE)	+= hv_mouse.o
> >
> >  obj-$(CONFIG_USB_HID)		+= usbhid/
> >  obj-$(CONFIG_USB_MOUSE)		+= usbhid/
> > diff --git a/drivers/hid/hv_mouse.c b/drivers/hid/hv_mouse.c
> > new file mode 100644
> > index 0000000..ccd39c7
> > --- /dev/null
> > +++ b/drivers/hid/hv_mouse.c
> > @@ -0,0 +1,599 @@
> > +/*
> > + *  Copyright (c) 2009, Citrix Systems, Inc.
> > + *  Copyright (c) 2010, Microsoft Corporation.
> > + *  Copyright (c) 2011, Novell Inc.
> > + *
> > + *  This program is free software; you can redistribute it and/or modify it
> > + *  under the terms and conditions of the GNU General Public License,
> > + *  version 2, as published by the Free Software Foundation.
> > + *
> > + *  This program is distributed in the hope it will be useful, but WITHOUT
> > + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
> or
> > + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> for
> > + *  more details.
> > + */
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/delay.h>
> > +#include <linux/device.h>
> > +#include <linux/workqueue.h>
> 
> Is this really needed?
> 
> > +#include <linux/sched.h>
> 
> You probably want completion.h instead.

I will fix this.
> 
> > +#include <linux/wait.h>
> > +#include <linux/input.h>
> > +#include <linux/hid.h>
> > +#include <linux/hiddev.h>
> > +#include <linux/hyperv.h>
> > +
> > +
> > +struct hv_input_dev_info {
> > +	unsigned int size;
> > +	unsigned short vendor;
> > +	unsigned short product;
> > +	unsigned short version;
> > +	unsigned short reserved[11];
> > +};
> > +
> > +/* The maximum size of a synthetic input message. */
> > +#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
> > +
> > +/*
> > + * Current version
> > + *
> > + * History:
> > + * Beta, RC < 2008/1/22        1,0
> > + * RC > 2008/1/22              2,0
> > + */
> > +#define SYNTHHID_INPUT_VERSION_MAJOR	2
> > +#define SYNTHHID_INPUT_VERSION_MINOR	0
> > +#define SYNTHHID_INPUT_VERSION
> 	(SYNTHHID_INPUT_VERSION_MINOR | \
> > +					 (SYNTHHID_INPUT_VERSION_MAJOR <<
> 16))
> > +
> > +
> > +#pragma pack(push, 1)
> > +/*
> > + * Message types in the synthetic input protocol
> > + */
> > +enum synthhid_msg_type {
> > +	SYNTH_HID_PROTOCOL_REQUEST,
> > +	SYNTH_HID_PROTOCOL_RESPONSE,
> > +	SYNTH_HID_INITIAL_DEVICE_INFO,
> > +	SYNTH_HID_INITIAL_DEVICE_INFO_ACK,
> > +	SYNTH_HID_INPUT_REPORT,
> > +	SYNTH_HID_MAX
> > +};
> > +
> > +/*
> > + * Basic message structures.
> > + */
> > +struct synthhid_msg_hdr {
> > +	enum synthhid_msg_type type;
> > +	u32 size;
> > +};
> > +
> > +struct synthhid_msg {
> > +	struct synthhid_msg_hdr header;
> > +	char data[1]; /* Enclosed message */
> > +};
> > +
> > +union synthhid_version {
> > +	struct {
> > +		u16 minor_version;
> > +		u16 major_version;
> > +	};
> > +	u32 version;
> > +};
> > +
> > +/*
> > + * Protocol messages
> > + */
> > +struct synthhid_protocol_request {
> > +	struct synthhid_msg_hdr header;
> > +	union synthhid_version version_requested;
> > +};
> > +
> > +struct synthhid_protocol_response {
> > +	struct synthhid_msg_hdr header;
> > +	union synthhid_version version_requested;
> > +	unsigned char approved;
> > +};
> > +
> > +struct synthhid_device_info {
> > +	struct synthhid_msg_hdr header;
> > +	struct hv_input_dev_info hid_dev_info;
> > +	struct hid_descriptor hid_descriptor;
> > +};
> > +
> > +struct synthhid_device_info_ack {
> > +	struct synthhid_msg_hdr header;
> > +	unsigned char reserved;
> > +};
> > +
> > +struct synthhid_input_report {
> > +	struct synthhid_msg_hdr header;
> > +	char buffer[1];
> > +};
> > +
> > +#pragma pack(pop)
> > +
> > +#define INPUTVSC_SEND_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> > +#define INPUTVSC_RECV_RING_BUFFER_SIZE		(10*PAGE_SIZE)
> > +
> > +#define NBITS(x) (((x)/BITS_PER_LONG)+1)
> > +
> > +enum pipe_prot_msg_type {
> > +	PIPE_MESSAGE_INVALID,
> > +	PIPE_MESSAGE_DATA,
> > +	PIPE_MESSAGE_MAXIMUM
> > +};
> > +
> > +
> > +struct pipe_prt_msg {
> > +	enum pipe_prot_msg_type type;
> > +	u32 size;
> > +	char data[1];
> > +};
> > +
> > +struct  mousevsc_prt_msg {
> > +	enum pipe_prot_msg_type type;
> > +	u32 size;
> > +	union {
> > +		struct synthhid_protocol_request request;
> > +		struct synthhid_protocol_response response;
> > +		struct synthhid_device_info_ack ack;
> > +	};
> > +};
> > +
> > +/*
> > + * Represents an mousevsc device
> > + */
> > +struct mousevsc_dev {
> > +	struct hv_device	*device;
> > +	unsigned char		init_complete;
> > +	struct mousevsc_prt_msg	protocol_req;
> > +	struct mousevsc_prt_msg	protocol_resp;
> > +	/* Synchronize the request/response if needed */
> > +	struct completion	wait_event;
> > +	int			dev_info_status;
> > +
> > +	struct hid_descriptor	*hid_desc;
> > +	unsigned char		*report_desc;
> > +	u32			report_desc_size;
> > +	struct hv_input_dev_info hid_dev_info;
> > +	int			connected;
> 
> bool?
> 
> > +	struct hid_device       *hid_device;
> > +};
> > +
> > +
> > +static struct mousevsc_dev *alloc_input_device(struct hv_device *device)
> > +{
> > +	struct mousevsc_dev *input_dev;
> > +
> > +	input_dev = kzalloc(sizeof(struct mousevsc_dev), GFP_KERNEL);
> > +
> 
> This blank line is extra.
> 
> > +	if (!input_dev)
> > +		return NULL;
> > +
> > +	input_dev->device = device;
> > +	hv_set_drvdata(device, input_dev);
> > +	init_completion(&input_dev->wait_event);
> > +
> > +	return input_dev;
> > +}
> > +
> > +static void free_input_device(struct mousevsc_dev *device)
> > +{
> > +	kfree(device->hid_desc);
> > +	kfree(device->report_desc);
> > +	hv_set_drvdata(device->device, NULL);
> > +	kfree(device);
> > +}
> > +
> > +
> > +static void mousevsc_on_receive_device_info(struct mousevsc_dev
> *input_device,
> > +				struct synthhid_device_info *device_info)
> > +{
> > +	int ret = 0;
> > +	struct hid_descriptor *desc;
> > +	struct mousevsc_prt_msg ack;
> > +
> > +	/* Assume success for now */
> > +	input_device->dev_info_status = 0;
> > +
> > +	memcpy(&input_device->hid_dev_info, &device_info->hid_dev_info,
> > +		sizeof(struct hv_input_dev_info));
> > +
> > +	desc = &device_info->hid_descriptor;
> > +	WARN_ON(desc->bLength == 0);
> > +
> > +	input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
> > +
> > +	if (!input_device->hid_desc)
> > +		goto cleanup;
> > +
> > +	memcpy(input_device->hid_desc, desc, desc->bLength);
> > +
> > +	input_device->report_desc_size = desc->desc[0].wDescriptorLength;
> > +	if (input_device->report_desc_size == 0)
> > +		goto cleanup;
> > +	input_device->report_desc = kzalloc(input_device->report_desc_size,
> > +					  GFP_ATOMIC);
> > +
> > +	if (!input_device->report_desc)
> > +		goto cleanup;
> > +
> > +	memcpy(input_device->report_desc,
> > +	       ((unsigned char *)desc) + desc->bLength,
> > +	       desc->desc[0].wDescriptorLength);
> > +
> > +	/* Send the ack */
> > +	memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
> > +
> > +	ack.type = PIPE_MESSAGE_DATA;
> > +	ack.size = sizeof(struct synthhid_device_info_ack);
> > +
> > +	ack.ack.header.type = SYNTH_HID_INITIAL_DEVICE_INFO_ACK;
> > +	ack.ack.header.size = 1;
> > +	ack.ack.reserved = 0;
> 
> That looks like a constant structure...

Will clean this up.
> 
> > +
> > +	ret = vmbus_sendpacket(input_device->device->channel,
> > +			&ack,
> > +			sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
> > +			sizeof(struct synthhid_device_info_ack),
> > +			(unsigned long)&ack,
> > +			VM_PKT_DATA_INBAND,
> > +
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> > +	if (ret != 0)
> > +		goto cleanup;
> > +
> > +	complete(&input_device->wait_event);
> > +
> > +	return;
> > +
> > +cleanup:
> > +	kfree(input_device->hid_desc);
> > +	input_device->hid_desc = NULL;
> > +
> > +	kfree(input_device->report_desc);
> > +	input_device->report_desc = NULL;
> > +
> > +	input_device->dev_info_status = -1;
> > +	complete(&input_device->wait_event);
> > +}
> > +
> > +static void mousevsc_on_receive(struct hv_device *device,
> > +				struct vmpacket_descriptor *packet)
> > +{
> > +	struct pipe_prt_msg *pipe_msg;
> > +	struct synthhid_msg *hid_msg;
> > +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> > +	struct synthhid_input_report *input_report;
> > +
> > +	pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
> > +						(packet->offset8 << 3));
> > +
> > +	if (pipe_msg->type != PIPE_MESSAGE_DATA)
> > +		return;
> > +
> > +	hid_msg = (struct synthhid_msg *)&pipe_msg->data[0];
> > +
> > +	switch (hid_msg->header.type) {
> > +	case SYNTH_HID_PROTOCOL_RESPONSE:
> > +		memcpy(&input_dev->protocol_resp, pipe_msg,
> > +		       pipe_msg->size + sizeof(struct pipe_prt_msg) -
> > +		       sizeof(unsigned char));
> > +		complete(&input_dev->wait_event);
> > +		break;
> > +
> > +	case SYNTH_HID_INITIAL_DEVICE_INFO:
> > +		WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
> > +
> > +		/*
> > +		 * Parse out the device info into device attr,
> > +		 * hid desc and report desc
> > +		 */
> > +		mousevsc_on_receive_device_info(input_dev,
> > +			(struct synthhid_device_info *)&pipe_msg->data[0]);
> > +		break;
> > +	case SYNTH_HID_INPUT_REPORT:
> > +		input_report =
> > +			(struct synthhid_input_report *)&pipe_msg->data[0];
> > +		if (!input_dev->init_complete)
> > +			break;
> > +		hid_input_report(input_dev->hid_device,
> > +				HID_INPUT_REPORT, input_report->buffer,
> > +				input_report->header.size, 1);
> > +		break;
> > +	default:
> > +		pr_err("unsupported hid msg type - type %d len %d",
> > +		       hid_msg->header.type, hid_msg->header.size);
> > +		break;
> > +	}
> > +
> > +}
> > +
> > +static void mousevsc_on_channel_callback(void *context)
> > +{
> > +	const int packetSize = 0x100;
> > +	int ret = 0;
> > +	struct hv_device *device = (struct hv_device *)context;
> 
> No need to cast.
> 
> > +
> > +	u32 bytes_recvd;
> > +	u64 req_id;
> > +	unsigned char packet[0x100];
> 
> Hmm, 100 bytes on stack... and are we in interrupt context by any
> chance?
> 
> > +	struct vmpacket_descriptor *desc;
> > +	unsigned char	*buffer = packet;
> > +	int	bufferlen = packetSize;
> > +
> > +
> > +	do {
> > +		ret = vmbus_recvpacket_raw(device->channel, buffer,
> > +					bufferlen, &bytes_recvd, &req_id);
> > +
> > +		if (ret == 0) {
> > +			if (bytes_recvd > 0) {
> > +				desc = (struct vmpacket_descriptor *)buffer;
> > +
> > +				switch (desc->type) {
> > +				case VM_PKT_COMP:
> > +					break;
> > +
> > +				case VM_PKT_DATA_INBAND:
> > +					mousevsc_on_receive(
> > +						device, desc);
> > +					break;
> > +
> > +				default:
> > +					pr_err("unhandled packet type %d, tid
> %llx len %d\n",
> > +						   desc->type,
> > +						   req_id,
> > +						   bytes_recvd);
> > +					break;
> > +				}
> > +
> > +				/* reset */
> > +				if (bufferlen > packetSize) {
> > +					kfree(buffer);
> > +
> > +					buffer = packet;
> > +					bufferlen = packetSize;
> > +				}
> > +			} else {
> > +				if (bufferlen > packetSize) {
> > +					kfree(buffer);
> > +
> > +					buffer = packet;
> > +					bufferlen = packetSize;
> > +				}
> > +				break;
> > +			}
> > +		} else if (ret == -ENOBUFS) {
> > +			/* Handle large packet */
> > +			bufferlen = bytes_recvd;
> > +			buffer = kzalloc(bytes_recvd, GFP_ATOMIC);
> > +
> 
> What happens if we receive even larger amount of data after allocating
> the buffer?

I will cleanup this function. 
> 
> > +			if (buffer == NULL) {
> > +				buffer = packet;
> > +				bufferlen = packetSize;
> > +				break;
> > +			}
> > +		}
> > +	} while (1);
> 
> So we can be looping indefinitely here as long as other side keeps
> sending data?
The current protocol requires that the consumer handle all available data on the
channel before exiting the handler; this is used to optimize signaling on the ring 
buffer between the producer and the consumer.

> 
> > +
> > +	return;
> 
> No naked returns please.
> 
> > +}
> > +
> > +static int mousevsc_connect_to_vsp(struct hv_device *device)
> > +{
> > +	int ret = 0;
> > +	int t;
> > +	struct mousevsc_dev *input_dev = hv_get_drvdata(device);
> > +	struct mousevsc_prt_msg *request;
> > +	struct mousevsc_prt_msg *response;
> > +
> > +
> > +	request = &input_dev->protocol_req;
> > +
> > +	memset(request, 0, sizeof(struct mousevsc_prt_msg));
> > +
> > +	request->type = PIPE_MESSAGE_DATA;
> > +	request->size = sizeof(struct synthhid_protocol_request);
> > +
> > +	request->request.header.type = SYNTH_HID_PROTOCOL_REQUEST;
> > +	request->request.header.size = sizeof(unsigned int);
> > +	request->request.version_requested.version =
> SYNTHHID_INPUT_VERSION;
> > +
> > +
> > +	ret = vmbus_sendpacket(device->channel, request,
> > +				sizeof(struct pipe_prt_msg) -
> > +				sizeof(unsigned char) +
> > +				sizeof(struct synthhid_protocol_request),
> > +				(unsigned long)request,
> > +				VM_PKT_DATA_INBAND,
> > +
> 	VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
> > +	if (ret != 0)
> > +		goto cleanup;
> > +
> > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > +	if (t == 0) {
> > +		ret = -ETIMEDOUT;
> > +		goto cleanup;
> > +	}
> > +
> > +	response = &input_dev->protocol_resp;
> > +
> > +	if (!response->response.approved) {
> > +		pr_err("synthhid protocol request failed (version %d)",
> > +		       SYNTHHID_INPUT_VERSION);
> > +		ret = -ENODEV;
> > +		goto cleanup;
> > +	}
> > +
> > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> 
> We just completed the wait for this completion, why are we waiting on
> the same completion again?

In response to our initial query, we expect the host to respond back with two
distinct pieces of information; we wait for both these responses.
 
> 
> > +	if (t == 0) {
> > +		ret = -ETIMEDOUT;
> > +		goto cleanup;
> > +	}
> > +
> > +	/*
> > +	 * We should have gotten the device attr, hid desc and report
> > +	 * desc at this point
> > +	 */
> > +	if (input_dev->dev_info_status)
> > +		ret = -ENOMEM;
> 
> -ENOMEM seems wrong.
> 
There are many failures here and not being able to allocate memory is the 
primary one; and so I chose to capture that.
 
> > +
> > +cleanup:
> > +
> > +	return ret;
> > +}
> > +
> > +static int mousevsc_hid_open(struct hid_device *hid)
> > +{
> > +	return 0;
> > +}
> > +
> > +static void mousevsc_hid_close(struct hid_device *hid)
> > +{
> > +}
> > +
> > +static struct hid_ll_driver mousevsc_ll_driver = {
> > +	.open = mousevsc_hid_open,
> > +	.close = mousevsc_hid_close,
> > +};
> > +
> > +static struct hid_driver mousevsc_hid_driver;
> > +
> > +static void reportdesc_callback(struct hv_device *dev, void *packet, u32 len)
> > +{
> 
> This is called from mousevsc_on_device_add() which is part of device
> probe. Why it is split into separate function with bizzare arguments is
> beyond me.

I will clean this up.

> 
> > +	struct hid_device *hid_dev;
> > +	struct mousevsc_dev *input_device = hv_get_drvdata(dev);
> > +
> > +	hid_dev = hid_allocate_device();
> > +	if (IS_ERR(hid_dev))
> > +		return;
> 
> This is not very helpful.

I will clean this up.
> 
> > +
> > +	hid_dev->ll_driver = &mousevsc_ll_driver;
> > +	hid_dev->driver = &mousevsc_hid_driver;
> > +
> > +	if (hid_parse_report(hid_dev, packet, len))
> > +		return;
> 
> Neither is this.
> 
> > +
> > +	hid_dev->bus = BUS_VIRTUAL;
> > +	hid_dev->vendor = input_device->hid_dev_info.vendor;
> > +	hid_dev->product = input_device->hid_dev_info.product;
> > +	hid_dev->version = input_device->hid_dev_info.version;
> > +
> > +	sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
> > +
> > +	if (!hidinput_connect(hid_dev, 0)) {
> > +		hid_dev->claimed |= HID_CLAIMED_INPUT;
> 
> Why do you force hidinput claim? Let the normal rules do it.
> 
> > +
> > +		input_device->connected = 1;
> 
> 		input_device->connected = true;
> 
> > +
> > +	}
> > +
> > +	input_device->hid_device = hid_dev;
> 
> This assignment is probably too late.
I will address this.
> 
> > +}
> > +
> > +static int mousevsc_on_device_add(struct hv_device *device)
> 
> The only caller of this is mousevsc_probe() so why do you have it

I will address this.

>
> > +{
> > +	int ret = 0;
> > +	struct mousevsc_dev *input_dev;
> > +
> > +	input_dev = alloc_input_device(device);
> > +
> > +	if (!input_dev)
> > +		return -ENOMEM;
> > +
> > +	input_dev->init_complete = false;
> > +
> > +	ret = vmbus_open(device->channel,
> > +		INPUTVSC_SEND_RING_BUFFER_SIZE,
> > +		INPUTVSC_RECV_RING_BUFFER_SIZE,
> > +		NULL,
> > +		0,
> > +		mousevsc_on_channel_callback,
> > +		device
> > +		);
> > +
> > +	if (ret != 0) {
> > +		free_input_device(input_dev);
> > +		return ret;
> > +	}
> > +
> > +
> > +	ret = mousevsc_connect_to_vsp(device);
> > +
> > +	if (ret != 0) {
> > +		vmbus_close(device->channel);
> > +		free_input_device(input_dev);
> > +		return ret;
> > +	}
> > +
> > +
> > +	/* workaround SA-167 */
> > +	if (input_dev->report_desc[14] == 0x25)
> > +		input_dev->report_desc[14] = 0x29;
> > +
> > +	reportdesc_callback(device, input_dev->report_desc,
> > +			    input_dev->report_desc_size);
> > +
> > +	input_dev->init_complete = true;
> > +
> > +	return ret;
> > +}
> > +
> > +static int mousevsc_probe(struct hv_device *dev,
> > +			const struct hv_vmbus_device_id *dev_id)
> > +{
> > +
> > +	return mousevsc_on_device_add(dev);
> > +
> > +}
> > +
> > +static int mousevsc_remove(struct hv_device *dev)
> > +{
> > +	struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
> > +
> > +	vmbus_close(dev->channel);
> > +
> > +	if (input_dev->connected) {
> > +		hidinput_disconnect(input_dev->hid_device);
> > +		input_dev->connected = 0;
> > +		hid_destroy_device(input_dev->hid_device);
> 
> hid_destroy_device() should disconnect registered handlers for you; you
> do not need to do that manually.
> 
> > +	}
> > +
> > +	free_input_device(input_dev);
> 
> Calling it input device is terribly confusing to me. I'd also freed it
> inline (and used gotos to unwind errors in probe()).
> 

I will clean this up.

Regards,

K. Y

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-23 15:45   ` KY Srinivasan
@ 2011-10-27  0:09     ` Dmitry Torokhov
  2011-10-27  1:19       ` KY Srinivasan
  0 siblings, 1 reply; 12+ messages in thread
From: Dmitry Torokhov @ 2011-10-27  0:09 UTC (permalink / raw)
  To: KY Srinivasan
  Cc: gregkh@suse.de, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org, virtualization@lists.osdl.org,
	linux-input@vger.kernel.org, Haiyang Zhang, Jiri Kosina

On Sun, Oct 23, 2011 at 03:45:14PM +0000, KY Srinivasan wrote:
> > > +
> > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > > +	if (t == 0) {
> > > +		ret = -ETIMEDOUT;
> > > +		goto cleanup;
> > > +	}
> > > +
> > > +	response = &input_dev->protocol_resp;
> > > +
> > > +	if (!response->response.approved) {
> > > +		pr_err("synthhid protocol request failed (version %d)",
> > > +		       SYNTHHID_INPUT_VERSION);
> > > +		ret = -ENODEV;
> > > +		goto cleanup;
> > > +	}
> > > +
> > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > 
> > We just completed the wait for this completion, why are we waiting on
> > the same completion again?
> 
> In response to our initial query, we expect the host to respond back with two
> distinct pieces of information; we wait for both these responses.

I think you misunderstand how completion works in Linux. IIRC about
Windows events they are different ;) You can not signal completion
several times and then expect to wait corrsponding number of times. Once
you signal completion is it, well, complete.

>  
> > 
> > > +	if (t == 0) {
> > > +		ret = -ETIMEDOUT;
> > > +		goto cleanup;
> > > +	}
> > > +
> > > +	/*
> > > +	 * We should have gotten the device attr, hid desc and report
> > > +	 * desc at this point
> > > +	 */
> > > +	if (input_dev->dev_info_status)
> > > +		ret = -ENOMEM;
> > 
> > -ENOMEM seems wrong.
> > 
> There are many failures here and not being able to allocate memory is the 
> primary one; and so I chose to capture that.

Any chance that these failures have their own exit paths?

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 12+ messages in thread

* RE: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-27  0:09     ` Dmitry Torokhov
@ 2011-10-27  1:19       ` KY Srinivasan
  2011-10-27  4:31         ` Dmitry Torokhov
  0 siblings, 1 reply; 12+ messages in thread
From: KY Srinivasan @ 2011-10-27  1:19 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: gregkh@suse.de, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org, virtualization@lists.osdl.org,
	linux-input@vger.kernel.org, Haiyang Zhang, Jiri Kosina



> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Wednesday, October 26, 2011 8:09 PM
> To: KY Srinivasan
> Cc: gregkh@suse.de; linux-kernel@vger.kernel.org;
> devel@linuxdriverproject.org; virtualization@lists.osdl.org; linux-
> input@vger.kernel.org; Haiyang Zhang; Jiri Kosina
> Subject: Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> staging
> 
> On Sun, Oct 23, 2011 at 03:45:14PM +0000, KY Srinivasan wrote:
> > > > +
> > > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > > > +	if (t == 0) {
> > > > +		ret = -ETIMEDOUT;
> > > > +		goto cleanup;
> > > > +	}
> > > > +
> > > > +	response = &input_dev->protocol_resp;
> > > > +
> > > > +	if (!response->response.approved) {
> > > > +		pr_err("synthhid protocol request failed (version %d)",
> > > > +		       SYNTHHID_INPUT_VERSION);
> > > > +		ret = -ENODEV;
> > > > +		goto cleanup;
> > > > +	}
> > > > +
> > > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > >
> > > We just completed the wait for this completion, why are we waiting on
> > > the same completion again?
> >
> > In response to our initial query, we expect the host to respond back with two
> > distinct pieces of information; we wait for both these responses.
> 
> I think you misunderstand how completion works in Linux. IIRC about
> Windows events they are different ;) You can not signal completion
> several times and then expect to wait corrsponding number of times. Once
> you signal completion is it, well, complete.

Looking at the code for complete(), it looks like the "done" state is incremented
each time complete() is invoked and  the  code for do_wait_for_common() decrements the 
done state each time it is invoked (if the completion is properly signaled and we are not dealing
with a timeout. So, what am I missing here.

> 
> >
> > >
> > > > +	if (t == 0) {
> > > > +		ret = -ETIMEDOUT;
> > > > +		goto cleanup;
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * We should have gotten the device attr, hid desc and report
> > > > +	 * desc at this point
> > > > +	 */
> > > > +	if (input_dev->dev_info_status)
> > > > +		ret = -ENOMEM;
> > >
> > > -ENOMEM seems wrong.
> > >
> > There are many failures here and not being able to allocate memory is the
> > primary one; and so I chose to capture that.
> 
> Any chance that these failures have their own exit paths?

This is called from the probe functions and these errors are percolated up. On a different
note, I cleaned up this code based on the feedback I got from you. The patches have been 
sent out.

Regards,

K. Y


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging
  2011-10-27  1:19       ` KY Srinivasan
@ 2011-10-27  4:31         ` Dmitry Torokhov
  0 siblings, 0 replies; 12+ messages in thread
From: Dmitry Torokhov @ 2011-10-27  4:31 UTC (permalink / raw)
  To: KY Srinivasan
  Cc: gregkh@suse.de, linux-kernel@vger.kernel.org,
	devel@linuxdriverproject.org, virtualization@lists.osdl.org,
	linux-input@vger.kernel.org, Haiyang Zhang, Jiri Kosina

On Thu, Oct 27, 2011 at 01:19:50AM +0000, KY Srinivasan wrote:
> 
> 
> > -----Original Message-----
> > From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> > Sent: Wednesday, October 26, 2011 8:09 PM
> > To: KY Srinivasan
> > Cc: gregkh@suse.de; linux-kernel@vger.kernel.org;
> > devel@linuxdriverproject.org; virtualization@lists.osdl.org; linux-
> > input@vger.kernel.org; Haiyang Zhang; Jiri Kosina
> > Subject: Re: [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of
> > staging
> > 
> > On Sun, Oct 23, 2011 at 03:45:14PM +0000, KY Srinivasan wrote:
> > > > > +
> > > > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > > > > +	if (t == 0) {
> > > > > +		ret = -ETIMEDOUT;
> > > > > +		goto cleanup;
> > > > > +	}
> > > > > +
> > > > > +	response = &input_dev->protocol_resp;
> > > > > +
> > > > > +	if (!response->response.approved) {
> > > > > +		pr_err("synthhid protocol request failed (version %d)",
> > > > > +		       SYNTHHID_INPUT_VERSION);
> > > > > +		ret = -ENODEV;
> > > > > +		goto cleanup;
> > > > > +	}
> > > > > +
> > > > > +	t = wait_for_completion_timeout(&input_dev->wait_event, 5*HZ);
> > > >
> > > > We just completed the wait for this completion, why are we waiting on
> > > > the same completion again?
> > >
> > > In response to our initial query, we expect the host to respond back with two
> > > distinct pieces of information; we wait for both these responses.
> > 
> > I think you misunderstand how completion works in Linux. IIRC about
> > Windows events they are different ;) You can not signal completion
> > several times and then expect to wait corrsponding number of times. Once
> > you signal completion is it, well, complete.
> 
> Looking at the code for complete(), it looks like the "done" state is incremented
> each time complete() is invoked and  the  code for do_wait_for_common() decrements the 
> done state each time it is invoked (if the completion is properly signaled and we are not dealing
> with a timeout. So, what am I missing here.

Hmm, you are right. I am not sure why I thought that completion has to
be re-initialized before it can be reused... I guess this is true only
if one uses complete_all().

-- 
Dmitry

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-10-27  4:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-15  6:08 [PATCH 1/1] Staging: hv: mousevsc: Move the mouse driver out of staging K. Y. Srinivasan
2011-10-15  6:36 ` Joe Perches
2011-10-15 13:24   ` KY Srinivasan
2011-10-16 22:28   ` Dan Carpenter
2011-10-16 23:03     ` Joe Perches
2011-10-19 23:48 ` KY Srinivasan
2011-10-23  7:24 ` Dmitry Torokhov
2011-10-23 14:33   ` KY Srinivasan
2011-10-23 15:45   ` KY Srinivasan
2011-10-27  0:09     ` Dmitry Torokhov
2011-10-27  1:19       ` KY Srinivasan
2011-10-27  4:31         ` Dmitry Torokhov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).