-
-
Save DavidNorena/4b56b3434d23bae73bcf314dde7f5a4c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile | |
index 581a5ae..6be0aa5 100644 | |
--- a/drivers/usb/gadget/Makefile | |
+++ b/drivers/usb/gadget/Makefile | |
@@ -67,7 +67,7 @@ | |
g_webcam-y := webcam.o | |
g_ncm-y := ncm.o | |
g_acm_ms-y := acm_ms.o | |
-g_android-y := android.o | |
+g_android-y := android.o f_hid.o | |
g_tcm_usb_gadget-y := tcm_usb_gadget.o | |
obj-$(CONFIG_USB_ZERO) += g_zero.o | |
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c | |
index 4de9562..b26ea34 100644 | |
--- a/drivers/usb/gadget/android.c | |
+++ b/drivers/usb/gadget/android.c | |
@@ -58,6 +58,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" | |
#include "f_rndis.c" | |
#include "rndis.c" | |
#include "f_qc_ecm.c" | |
@@ -2635,6 +2638,41 @@ | |
}; | |
#endif | |
+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 int android_uasp_connect_cb(bool connect) | |
{ | |
/* | |
@@ -2704,6 +2742,7 @@ | |
&ncm_function, | |
&mass_storage_function, | |
&accessory_function, | |
+ &hid_function, | |
#ifdef CONFIG_SND_PCM | |
&audio_source_function, | |
#endif | |
@@ -3066,6 +3105,9 @@ | |
free_android_config(dev, conf); | |
} | |
+ /* HID driver always enabled, it's the whole point of this kernel patch */ | |
+ android_enable_function(dev, conf, "hid"); | |
+ | |
mutex_unlock(&dev->mutex); | |
return size; | |
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c | |
index 83a266b..236bdf4 100644 | |
--- a/drivers/usb/gadget/f_hid.c | |
+++ b/drivers/usb/gadget/f_hid.c | |
@@ -17,8 +17,10 @@ | |
#include <linux/poll.h> | |
#include <linux/uaccess.h> | |
#include <linux/wait.h> | |
+#include <linux/delay.h> | |
#include <linux/sched.h> | |
#include <linux/usb/g_hid.h> | |
+#include "f_hid.h" | |
static int major, minors; | |
static struct class *hidg_class; | |
@@ -60,6 +62,43 @@ | |
struct usb_ep *out_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); | |
@@ -176,6 +215,11 @@ | |
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 (!list_empty(&hidg->completed_out_req)) | |
@@ -260,6 +304,11 @@ | |
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); | |
} | |
@@ -300,7 +349,18 @@ | |
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) | |
@@ -399,7 +459,12 @@ | |
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | |
| HID_REQ_GET_PROTOCOL): | |
VDBG(cdev, "get_protocol\n"); | |
- goto stall; | |
+ length = min_t(unsigned, length, 1); | |
+ if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) | |
+ ((u8 *) req->buf)[0] = 0; /* Boot protocol */ | |
+ else | |
+ ((u8 *) req->buf)[0] = 1; /* Report protocol */ | |
+ goto respond; | |
break; | |
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | |
@@ -411,6 +476,14 @@ | |
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 | |
| HID_REQ_SET_PROTOCOL): | |
VDBG(cdev, "set_protocol\n"); | |
+ length = 0; | |
+ if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { | |
+ if (value == 0) /* Boot protocol */ | |
+ goto respond; | |
+ } else { | |
+ if (value == 1) /* Report protocol */ | |
+ goto respond; | |
+ } | |
goto stall; | |
break; | |
@@ -560,13 +633,15 @@ | |
.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) | |
@@ -632,6 +707,7 @@ | |
goto fail; | |
device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor); | |
+ hacky_device_list_add(hidg); | |
return 0; | |
@@ -651,12 +727,20 @@ | |
{ | |
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); | |
@@ -689,7 +773,7 @@ | |
/*-------------------------------------------------------------------------*/ | |
/* 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; | |
@@ -743,7 +827,7 @@ | |
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..1824bdd | |
--- /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 = 1, /* Boot Interface 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..075d125 | |
--- /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 = 1, /* Boot Interface 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 | |
+ } | |
+}; | |
+ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment