From 7183beccd41e4d5d664ae98a30b5df193e415afb Mon Sep 17 00:00:00 2001
From: anarkia1976 <stefano.villa1976@gmail.com>
Date: Mon, 29 Jun 2015 11:52:37 +0200
Subject: [PATCH] drivers: usb: keyboard/mouse: Use Android device as USB
 keyboard/mouse

Adapt to 3.4.y 8974/bacon
Base project: https://github.com/pelya/android-keyboard-gadget
Required app: https://play.google.com/store/apps/details?id=remote.hid.keyboard.client

Steps:
* Start ADB Debugging
* Start app
* Connect device to system via USB cable

All credits to @pelya for this sweet hack.
---
 drivers/usb/gadget/Makefile                 |  2 +-
 drivers/usb/gadget/android.c                | 45 +++++++++++++++
 drivers/usb/gadget/f_hid.c                  | 87 +++++++++++++++++++++++++++--
 drivers/usb/gadget/f_hid.h                  | 16 ++++++
 drivers/usb/gadget/f_hid_android_keyboard.c | 44 +++++++++++++++
 drivers/usb/gadget/f_hid_android_mouse.c    | 40 +++++++++++++
 6 files changed, 227 insertions(+), 7 deletions(-)
 create mode 100644 drivers/usb/gadget/f_hid.h
 create mode 100644 drivers/usb/gadget/f_hid_android_keyboard.c
 create mode 100644 drivers/usb/gadget/f_hid_android_mouse.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index b8f5149..f9a58b3 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -55,7 +55,7 @@ g_webcam-y			:= webcam.o
 g_ncm-y				:= ncm.o
 g_acm_ms-y			:= acm_ms.o
 g_tcm_usb_gadget-y		:= tcm_usb_gadget.o
-g_android-y			:= android.o
+g_android-y			:= android.o f_hid.o
 
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
 obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 71b35b3..0f5b143 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -75,6 +75,9 @@
 #include "f_ccid.c"
 #include "f_mtp.c"
 #include "f_accessory.c"
+#include "f_hid.h"
+#include "f_hid_android_keyboard.c"
+#include "f_hid_android_mouse.c"
 #define USB_ETH_RNDIS y
 #include "f_rndis.c"
 #include "rndis.c"
@@ -2193,6 +2196,41 @@ static struct android_usb_function uasp_function = {
 	.bind_config	= uasp_function_bind_config,
 };
 
+static int hid_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev)
+{
+	return ghid_setup(cdev->gadget, 2);
+}
+
+static void hid_function_cleanup(struct android_usb_function *f)
+{
+	ghid_cleanup();
+}
+
+static int hid_function_bind_config(struct android_usb_function *f, struct usb_configuration *c)
+{
+	int ret;
+	printk(KERN_INFO "hid keyboard\n");
+	ret = hidg_bind_config(c, &ghid_device_android_keyboard, 0);
+	if (ret) {
+		pr_info("%s: hid_function_bind_config keyboard failed: %d\n", __func__, ret);
+		return ret;
+	}
+	printk(KERN_INFO "hid mouse\n");
+	ret = hidg_bind_config(c, &ghid_device_android_mouse, 1);
+	if (ret) {
+		pr_info("%s: hid_function_bind_config mouse failed: %d\n", __func__, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static struct android_usb_function hid_function = {
+	.name		= "hid",
+	.init		= hid_function_init,
+	.cleanup	= hid_function_cleanup,
+	.bind_config	= hid_function_bind_config,
+};
+
 static struct android_usb_function *supported_functions[] = {
 	&ffs_function,
 	&mbim_function,
@@ -2223,6 +2261,7 @@ static struct android_usb_function *supported_functions[] = {
 	&audio_source_function,
 #endif
 	&uasp_function,
+	&hid_function,
 	&charger_function,
 	NULL
 };
@@ -2506,6 +2545,7 @@ functions_store(struct device *pdev, struct device_attribute *attr,
 	int err;
 	int is_ffs;
 	int ffs_enabled = 0;
+	int hid_enabled;
 
 	mutex_lock(&dev->mutex);
 
@@ -2574,7 +2614,12 @@ functions_store(struct device *pdev, struct device_attribute *attr,
 			if (err)
 				pr_err("android_usb: Cannot enable '%s' (%d)",
 								   name, err);
+			if (!strcmp(name, "hid"))
+				hid_enabled = 1;
 		}
+		/* HID driver always enabled, it's the whole point of this kernel patch */
+		if (hid_enabled)
+			android_enable_function(dev, conf, "hid");
 	}
 
 	/* Free uneeded configurations if exists */
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index a4330fa..fa52b72 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -18,7 +18,9 @@
 #include <linux/poll.h>
 #include <linux/uaccess.h>
 #include <linux/wait.h>
+#include <linux/delay.h>
 #include <linux/usb/g_hid.h>
+#include "f_hid.h"
 
 static int major, minors;
 static struct class *hidg_class;
@@ -52,6 +54,43 @@ struct f_hidg {
 	struct usb_ep			*in_ep;
 };
 
+/* Hacky device list to fix f_hidg_write being called after device destroyed.
+   It covers only most common race conditions, there will be rare crashes anyway. */
+enum { HACKY_DEVICE_LIST_SIZE = 4 };
+static struct f_hidg *hacky_device_list[HACKY_DEVICE_LIST_SIZE];
+static void hacky_device_list_add(struct f_hidg *hidg)
+{
+	int i;
+	for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) {
+		if (!hacky_device_list[i]) {
+			hacky_device_list[i] = hidg;
+			return;
+		}
+	}
+	pr_err("%s: too many devices, not adding device %p\n", __func__, hidg);
+}
+static void hacky_device_list_remove(struct f_hidg *hidg)
+{
+	int i;
+	for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) {
+		if (hacky_device_list[i] == hidg) {
+			hacky_device_list[i] = NULL;
+			return;
+		}
+	}
+	pr_err("%s: cannot find device %p\n", __func__, hidg);
+}
+static int hacky_device_list_check(struct f_hidg *hidg)
+{
+	int i;
+	for (i = 0; i < HACKY_DEVICE_LIST_SIZE; i++) {
+		if (hacky_device_list[i] == hidg) {
+			return 0;
+		}
+	}
+	return 1;
+}
+
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
 {
 	return container_of(f, struct f_hidg, func);
@@ -140,6 +179,11 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer,
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
 
+	if (hacky_device_list_check(hidg)) {
+		pr_err("%s: trying to read from device %p that was destroyed\n", __func__, hidg);
+		return -EIO;
+	}
+
 	spin_lock_irqsave(&hidg->spinlock, flags);
 
 #define READ_COND (hidg->set_report_buff != NULL)
@@ -194,6 +238,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
 
+	if (hacky_device_list_check(hidg)) {
+		pr_err("%s: trying to write to device %p that was destroyed\n", __func__, hidg);
+		return -EIO;
+	}
+
 	mutex_lock(&hidg->lock);
 
 #define WRITE_COND (!hidg->write_pending)
@@ -208,6 +257,11 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
 				hidg->write_queue, WRITE_COND))
 			return -ERESTARTSYS;
 
+		if (hacky_device_list_check(hidg)) {
+			pr_err("%s: trying to write to device %p that was destroyed\n", __func__, hidg);
+			return -EIO;
+		}
+
 		mutex_lock(&hidg->lock);
 	}
 
@@ -248,7 +302,18 @@ static unsigned int f_hidg_poll(struct file *file, poll_table *wait)
 	struct f_hidg	*hidg  = file->private_data;
 	unsigned int	ret = 0;
 
+	if (hacky_device_list_check(hidg)) {
+		pr_err("%s: trying to poll device %p that was destroyed\n", __func__, hidg);
+		return -EIO;
+	}
+
 	poll_wait(file, &hidg->read_queue, wait);
+
+	if (hacky_device_list_check(hidg)) {
+		pr_err("%s: trying to poll device %p that was destroyed\n", __func__, hidg);
+		return -EIO;
+	}
+
 	poll_wait(file, &hidg->write_queue, wait);
 
 	if (WRITE_COND)
@@ -448,13 +513,15 @@ const struct file_operations f_hidg_fops = {
 	.llseek		= noop_llseek,
 };
 
-static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
+static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct usb_ep		*ep;
 	struct f_hidg		*hidg = func_to_hidg(f);
 	int			status;
 	dev_t			dev;
 
+	pr_info("%s: creating device %p\n", __func__, hidg);
+
 	/* allocate instance-specific interface IDs, and patch descriptors */
 	status = usb_interface_id(c, f);
 	if (status < 0)
@@ -493,8 +560,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 
 	hidg_hs_in_ep_desc.bEndpointAddress =
 		hidg_fs_in_ep_desc.bEndpointAddress;
-	hidg_hs_out_ep_desc.bEndpointAddress =
-		hidg_fs_out_ep_desc.bEndpointAddress;
 
 	status = usb_assign_descriptors(f, hidg_fs_descriptors,
 			hidg_hs_descriptors, NULL);
@@ -514,6 +579,7 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 		goto fail;
 
 	device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
+	hacky_device_list_add(hidg);
 
 	return 0;
 
@@ -533,12 +599,21 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 	struct f_hidg *hidg = func_to_hidg(f);
 
+	pr_info("%s: destroying device %p\n", __func__, hidg);
+	/* This does not cover all race conditions, only most common one */
+	mutex_lock(&hidg->lock);
+	hacky_device_list_remove(hidg);
+	mutex_unlock(&hidg->lock);
+
 	device_destroy(hidg_class, MKDEV(major, hidg->minor));
 	cdev_del(&hidg->cdev);
 
 	/* disable/free request and end point */
 	usb_ep_disable(hidg->in_ep);
-	usb_ep_dequeue(hidg->in_ep, hidg->req);
+	/* TODO: calling this function crash kernel,
+	   not calling this funct ion crash kernel inside f_hidg_write */
+	/* usb_ep_dequeue(hidg->in_ep, hidg->req); */
+
 	kfree(hidg->req->buf);
 	usb_ep_free_request(hidg->in_ep, hidg->req);
 
@@ -572,7 +647,7 @@ static struct usb_gadget_strings *ct_func_strings[] = {
 /*-------------------------------------------------------------------------*/
 /*                             usb_configuration                           */
 
-int __init hidg_bind_config(struct usb_configuration *c,
+int hidg_bind_config(struct usb_configuration *c,
 			    struct hidg_func_descriptor *fdesc, int index)
 {
 	struct f_hidg *hidg;
@@ -623,7 +698,7 @@ int __init hidg_bind_config(struct usb_configuration *c,
 	return status;
 }
 
-int __init ghid_setup(struct usb_gadget *g, int count)
+int ghid_setup(struct usb_gadget *g, int count)
 {
 	int status;
 	dev_t dev;
diff --git a/drivers/usb/gadget/f_hid.h b/drivers/usb/gadget/f_hid.h
new file mode 100644
index 0000000..ad3527a
--- /dev/null
+++ b/drivers/usb/gadget/f_hid.h
@@ -0,0 +1,16 @@
+#ifndef _GADGET_F_HID_H
+#define _GADGET_F_HID_H
+
+#include <linux/hid.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/g_hid.h>
+
+int hidg_bind_config(struct usb_configuration *c,
+			    struct hidg_func_descriptor *fdesc, int index);
+
+int ghid_setup(struct usb_gadget *g, int count);
+
+void ghid_cleanup(void);
+
+#endif
diff --git a/drivers/usb/gadget/f_hid_android_keyboard.c b/drivers/usb/gadget/f_hid_android_keyboard.c
new file mode 100644
index 0000000..76180eb
--- /dev/null
+++ b/drivers/usb/gadget/f_hid_android_keyboard.c
@@ -0,0 +1,44 @@
+#include <linux/platform_device.h>
+#include <linux/usb/g_hid.h>
+
+/* hid descriptor for a keyboard */
+static struct hidg_func_descriptor ghid_device_android_keyboard = {
+	.subclass		= 0, /* No subclass */
+	.protocol		= 1, /* Keyboard */
+	.report_length		= 8,
+	.report_desc_length	= 63,
+	.report_desc		= {
+		0x05, 0x01,	/* USAGE_PAGE (Generic Desktop)	          */
+		0x09, 0x06,	/* USAGE (Keyboard)                       */
+		0xa1, 0x01,	/* COLLECTION (Application)               */
+		0x05, 0x07,	/*   USAGE_PAGE (Keyboard)                */
+		0x19, 0xe0,	/*   USAGE_MINIMUM (Keyboard LeftControl) */
+		0x29, 0xe7,	/*   USAGE_MAXIMUM (Keyboard Right GUI)   */
+		0x15, 0x00,	/*   LOGICAL_MINIMUM (0)                  */
+		0x25, 0x01,	/*   LOGICAL_MAXIMUM (1)                  */
+		0x75, 0x01,	/*   REPORT_SIZE (1)                      */
+		0x95, 0x08,	/*   REPORT_COUNT (8)                     */
+		0x81, 0x02,	/*   INPUT (Data,Var,Abs)                 */
+		0x95, 0x01,	/*   REPORT_COUNT (1)                     */
+		0x75, 0x08,	/*   REPORT_SIZE (8)                      */
+		0x81, 0x03,	/*   INPUT (Cnst,Var,Abs)                 */
+		0x95, 0x05,	/*   REPORT_COUNT (5)                     */
+		0x75, 0x01,	/*   REPORT_SIZE (1)                      */
+		0x05, 0x08,	/*   USAGE_PAGE (LEDs)                    */
+		0x19, 0x01,	/*   USAGE_MINIMUM (Num Lock)             */
+		0x29, 0x05,	/*   USAGE_MAXIMUM (Kana)                 */
+		0x91, 0x02,	/*   OUTPUT (Data,Var,Abs)                */
+		0x95, 0x01,	/*   REPORT_COUNT (1)                     */
+		0x75, 0x03,	/*   REPORT_SIZE (3)                      */
+		0x91, 0x03,	/*   OUTPUT (Cnst,Var,Abs)                */
+		0x95, 0x06,	/*   REPORT_COUNT (6)                     */
+		0x75, 0x08,	/*   REPORT_SIZE (8)                      */
+		0x15, 0x00,	/*   LOGICAL_MINIMUM (0)                  */
+		0x25, 0x65,	/*   LOGICAL_MAXIMUM (101)                */
+		0x05, 0x07,	/*   USAGE_PAGE (Keyboard)                */
+		0x19, 0x00,	/*   USAGE_MINIMUM (Reserved)             */
+		0x29, 0x65,	/*   USAGE_MAXIMUM (Keyboard Application) */
+		0x81, 0x00,	/*   INPUT (Data,Ary,Abs)                 */
+		0xc0		/* END_COLLECTION                         */
+	}
+};
diff --git a/drivers/usb/gadget/f_hid_android_mouse.c b/drivers/usb/gadget/f_hid_android_mouse.c
new file mode 100644
index 0000000..8a6ab0a
--- /dev/null
+++ b/drivers/usb/gadget/f_hid_android_mouse.c
@@ -0,0 +1,40 @@
+#include <linux/platform_device.h>
+#include <linux/usb/g_hid.h>
+
+/* HID descriptor for a mouse */
+static struct hidg_func_descriptor ghid_device_android_mouse = {
+	.subclass      = 0, /* No subclass */
+	.protocol      = 2, /* Mouse */
+	.report_length = 4,
+	.report_desc_length	= 52,
+	.report_desc = {
+		0x05, 0x01,  //Usage Page(Generic Desktop Controls)
+		0x09, 0x02,  //Usage (Mouse)
+		0xa1, 0x01,  //Collection (Application)
+		0x09, 0x01,  //Usage (pointer)
+		0xa1, 0x00,  //Collection (Physical)
+		0x05, 0x09,  //Usage Page (Button)
+		0x19, 0x01,  //Usage Minimum(1)
+		0x29, 0x05,  //Usage Maximum(5)
+		0x15, 0x00,  //Logical Minimum(1)
+		0x25, 0x01,  //Logical Maximum(1)
+		0x95, 0x05,  //Report Count(5)
+		0x75, 0x01,  //Report Size(1)
+		0x81, 0x02,  //Input(Data,Variable,Absolute,BitField)
+		0x95, 0x01,  //Report Count(1)
+		0x75, 0x03,  //Report Size(3)
+		0x81, 0x01,  //Input(Constant,Array,Absolute,BitField)
+		0x05, 0x01,  //Usage Page(Generic Desktop Controls)
+		0x09, 0x30,  //Usage(x)
+		0x09, 0x31,  //Usage(y)
+		0x09, 0x38,  //Usage(Wheel)
+		0x15, 0x81,  //Logical Minimum(-127)
+		0x25, 0x7F,  //Logical Maximum(127)
+		0x75, 0x08,  //Report Size(8)
+		0x95, 0x03,  //Report Count(3)
+		0x81, 0x06,  //Input(Data,Variable,Relative,BitField)
+		0xc0,  //End Collection
+		0xc0  //End Collection
+	}
+};
+
