From 7183beccd41e4d5d664ae98a30b5df193e415afb Mon Sep 17 00:00:00 2001 From: anarkia1976 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 #include #include +#include #include +#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 +#include +#include +#include + +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 +#include + +/* 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 +#include + +/* 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 + } +}; +