2016-12-21 19:30:02 -05:00

433 lines
14 KiB
Diff

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
+ }
+};
+