/* * Gadget Driver for Android * * Copyright (C) 2008 Google, Inc. * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved. * Author: Mike Lockwood * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that 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. * */ /* #define DEBUG */ /* #define VERBOSE_DEBUG */ #include #include #include #include #include #include #include #include #include #include #include #include "gadget_chips.h" /* * Kbuild is not very cooperative with respect to linking separately * compiled library objects into one module. So for now we won't use * separate compilation ... ensuring init/exit sections work to shrink * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ #include "usbstring.c" #include "config.c" #include "epautoconf.c" #include "composite.c" #include "f_diag.c" #include "f_rmnet_smd.c" #include "f_rmnet_sdio.c" #include "f_rmnet_smd_sdio.c" #include "f_rmnet.c" #include "f_mass_storage.c" #include "u_serial.c" #include "u_sdio.c" #include "u_smd.c" #include "u_bam.c" #include "u_rmnet_ctrl_smd.c" #include "u_ctrl_hsic.c" #include "u_data_hsic.c" #include "f_serial.c" #include "f_acm.c" #include "f_adb.c" #include "f_ccid.c" #include "f_mtp.c" #include "f_accessory.c" #define USB_ETH_RNDIS y #include "f_rndis.c" #include "rndis.c" #include "u_ether.c" MODULE_AUTHOR("Mike Lockwood"); MODULE_DESCRIPTION("Android Composite USB Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); static const char longname[] = "Gadget Android"; /* Default vendor and product IDs, overridden by userspace */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 struct android_usb_function { char *name; void *config; struct device *dev; char *dev_name; struct device_attribute **attributes; /* for android_dev.enabled_functions */ struct list_head enabled_list; /* Optional: initialization during gadget bind */ int (*init)(struct android_usb_function *, struct usb_composite_dev *); /* Optional: cleanup during gadget unbind */ void (*cleanup)(struct android_usb_function *); int (*bind_config)(struct android_usb_function *, struct usb_configuration *); /* Optional: called when the configuration is removed */ void (*unbind_config)(struct android_usb_function *, struct usb_configuration *); /* Optional: handle ctrl requests before the device is configured */ int (*ctrlrequest)(struct android_usb_function *, struct usb_composite_dev *, const struct usb_ctrlrequest *); }; struct android_dev { struct android_usb_function **functions; struct list_head enabled_functions; struct usb_composite_dev *cdev; struct device *dev; struct android_usb_platform_data *pdata; bool enabled; struct mutex mutex; bool connected; bool sw_connected; struct work_struct work; }; static struct class *android_class; static struct android_dev *_android_dev; static int android_bind_config(struct usb_configuration *c); static void android_unbind_config(struct usb_configuration *c); /* string IDs are assigned dynamically */ #define STRING_MANUFACTURER_IDX 0 #define STRING_PRODUCT_IDX 1 #define STRING_SERIAL_IDX 2 static char manufacturer_string[256]; static char product_string[256]; static char serial_string[256]; /* String Table */ static struct usb_string strings_dev[] = { [STRING_MANUFACTURER_IDX].s = manufacturer_string, [STRING_PRODUCT_IDX].s = product_string, [STRING_SERIAL_IDX].s = serial_string, { } /* end of list */ }; static struct usb_gadget_strings stringtab_dev = { .language = 0x0409, /* en-us */ .strings = strings_dev, }; static struct usb_gadget_strings *dev_strings[] = { &stringtab_dev, NULL, }; static struct usb_device_descriptor device_desc = { .bLength = sizeof(device_desc), .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, .idVendor = __constant_cpu_to_le16(VENDOR_ID), .idProduct = __constant_cpu_to_le16(PRODUCT_ID), .bcdDevice = __constant_cpu_to_le16(0xffff), .bNumConfigurations = 1, }; static struct usb_otg_descriptor otg_descriptor = { .bLength = sizeof otg_descriptor, .bDescriptorType = USB_DT_OTG, .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, .bcdOTG = __constant_cpu_to_le16(0x0200), }; static const struct usb_descriptor_header *otg_desc[] = { (struct usb_descriptor_header *) &otg_descriptor, NULL, }; static struct usb_configuration android_config_driver = { .label = "android", .unbind = android_unbind_config, .bConfigurationValue = 1, }; static void android_work(struct work_struct *data) { struct android_dev *dev = container_of(data, struct android_dev, work); struct usb_composite_dev *cdev = dev->cdev; char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; char *connected[2] = { "USB_STATE=CONNECTED", NULL }; char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; char **uevent_envp = NULL; unsigned long flags; spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) uevent_envp = configured; else if (dev->connected != dev->sw_connected) uevent_envp = dev->connected ? connected : disconnected; dev->sw_connected = dev->connected; spin_unlock_irqrestore(&cdev->lock, flags); if (uevent_envp) { kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp); pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]); } else { pr_info("%s: did not send uevent (%d %d %p)\n", __func__, dev->connected, dev->sw_connected, cdev->config); } } /*-------------------------------------------------------------------------*/ /* Supported functions initialization */ /* RMNET_SMD */ static int rmnet_smd_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return rmnet_smd_bind_config(c); } static struct android_usb_function rmnet_smd_function = { .name = "rmnet_smd", .bind_config = rmnet_smd_function_bind_config, }; /* RMNET_SDIO */ static int rmnet_sdio_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return rmnet_sdio_function_add(c); } static struct android_usb_function rmnet_sdio_function = { .name = "rmnet_sdio", .bind_config = rmnet_sdio_function_bind_config, }; /* RMNET_SMD_SDIO */ static int rmnet_smd_sdio_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return rmnet_smd_sdio_init(); } static void rmnet_smd_sdio_function_cleanup(struct android_usb_function *f) { rmnet_smd_sdio_cleanup(); } static int rmnet_smd_sdio_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return rmnet_smd_sdio_function_add(c); } static struct device_attribute *rmnet_smd_sdio_attributes[] = { &dev_attr_transport, NULL }; static struct android_usb_function rmnet_smd_sdio_function = { .name = "rmnet_smd_sdio", .init = rmnet_smd_sdio_function_init, .cleanup = rmnet_smd_sdio_function_cleanup, .bind_config = rmnet_smd_sdio_bind_config, .attributes = rmnet_smd_sdio_attributes, }; /*rmnet transport string format(per port):"ctrl0,data0,ctrl1,data1..." */ #define MAX_XPORT_STR_LEN 50 static char rmnet_transports[MAX_XPORT_STR_LEN]; static void rmnet_function_cleanup(struct android_usb_function *f) { frmnet_cleanup(); } static int rmnet_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { int i; int err = 0; char *ctrl_name; char *data_name; char buf[MAX_XPORT_STR_LEN], *b; static int rmnet_initialized, ports; if (!rmnet_initialized) { rmnet_initialized = 1; strlcpy(buf, rmnet_transports, sizeof(buf)); b = strim(buf); while (b) { ctrl_name = strsep(&b, ","); data_name = strsep(&b, ","); if (ctrl_name && data_name) { err = frmnet_init_port(ctrl_name, data_name); if (err) { pr_err("rmnet: Cannot open ctrl port:" "'%s' data port:'%s'\n", ctrl_name, data_name); goto out; } ports++; } } err = rmnet_gport_setup(); if (err) { pr_err("rmnet: Cannot setup transports"); goto out; } } for (i = 0; i < ports; i++) { err = frmnet_bind_config(c, i); if (err) { pr_err("Could not bind rmnet%u config\n", i); break; } } out: return err; } static ssize_t rmnet_transports_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", rmnet_transports); } static ssize_t rmnet_transports_store( struct device *device, struct device_attribute *attr, const char *buff, size_t size) { strlcpy(rmnet_transports, buff, sizeof(rmnet_transports)); return size; } static struct device_attribute dev_attr_rmnet_transports = __ATTR(transports, S_IRUGO | S_IWUSR, rmnet_transports_show, rmnet_transports_store); static struct device_attribute *rmnet_function_attributes[] = { &dev_attr_rmnet_transports, NULL }; static struct android_usb_function rmnet_function = { .name = "rmnet", .cleanup = rmnet_function_cleanup, .bind_config = rmnet_function_bind_config, .attributes = rmnet_function_attributes, }; /* DIAG */ static char diag_clients[32]; /*enabled DIAG clients- "diag[,diag_mdm]" */ static ssize_t clients_store( struct device *device, struct device_attribute *attr, const char *buff, size_t size) { strlcpy(diag_clients, buff, sizeof(diag_clients)); return size; } static DEVICE_ATTR(clients, S_IWUSR, NULL, clients_store); static struct device_attribute *diag_function_attributes[] = { &dev_attr_clients, NULL }; static int diag_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return diag_setup(); } static void diag_function_cleanup(struct android_usb_function *f) { diag_cleanup(); } static int diag_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { char *name; char buf[32], *b; int once = 0, err = -1; int (*notify)(uint32_t, const char *); strlcpy(buf, diag_clients, sizeof(buf)); b = strim(buf); while (b) { notify = NULL; name = strsep(&b, ","); /* Allow only first diag channel to update pid and serial no */ if (_android_dev->pdata && !once++) notify = _android_dev->pdata->update_pid_and_serial_num; if (name) { err = diag_function_add(c, name, notify); if (err) pr_err("diag: Cannot open channel '%s'", name); } } return err; } static struct android_usb_function diag_function = { .name = "diag", .init = diag_function_init, .cleanup = diag_function_cleanup, .bind_config = diag_function_bind_config, .attributes = diag_function_attributes, }; /* SERIAL */ static char serial_transports[32]; /*enabled FSERIAL ports - "tty[,sdio]"*/ static ssize_t serial_transports_store( struct device *device, struct device_attribute *attr, const char *buff, size_t size) { strlcpy(serial_transports, buff, sizeof(serial_transports)); return size; } static DEVICE_ATTR(transports, S_IWUSR, NULL, serial_transports_store); static struct device_attribute *serial_function_attributes[] = { &dev_attr_transports, NULL }; static void serial_function_cleanup(struct android_usb_function *f) { gserial_cleanup(); } static int serial_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { char *name; char buf[32], *b; int err = -1, i; static int serial_initialized = 0, ports = 0; if (serial_initialized) goto bind_config; serial_initialized = 1; strlcpy(buf, serial_transports, sizeof(buf)); b = strim(buf); while (b) { name = strsep(&b, ","); if (name) { err = gserial_init_port(ports, name); if (err) { pr_err("serial: Cannot open port '%s'", name); goto out; } ports++; } } err = gport_setup(c); if (err) { pr_err("serial: Cannot setup transports"); goto out; } bind_config: for (i = 0; i < ports; i++) { err = gser_bind_config(c, i); if (err) { pr_err("serial: bind_config failed for port %d", i); goto out; } } out: return err; } static struct android_usb_function serial_function = { .name = "serial", .cleanup = serial_function_cleanup, .bind_config = serial_function_bind_config, .attributes = serial_function_attributes, }; /* ACM */ static char acm_transports[32]; /*enabled ACM ports - "tty[,sdio]"*/ static ssize_t acm_transports_store( struct device *device, struct device_attribute *attr, const char *buff, size_t size) { strlcpy(acm_transports, buff, sizeof(acm_transports)); return size; } static DEVICE_ATTR(acm_transports, S_IWUSR, NULL, acm_transports_store); static struct device_attribute *acm_function_attributes[] = { &dev_attr_acm_transports, NULL }; static void acm_function_cleanup(struct android_usb_function *f) { gserial_cleanup(); } static int acm_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { char *name; char buf[32], *b; int err = -1, i; static int acm_initialized, ports; if (acm_initialized) goto bind_config; acm_initialized = 1; strlcpy(buf, acm_transports, sizeof(buf)); b = strim(buf); while (b) { name = strsep(&b, ","); if (name) { err = acm_init_port(ports, name); if (err) { pr_err("acm: Cannot open port '%s'", name); goto out; } ports++; } } err = acm_port_setup(c); if (err) { pr_err("acm: Cannot setup transports"); goto out; } bind_config: for (i = 0; i < ports; i++) { err = acm_bind_config(c, i); if (err) { pr_err("acm: bind_config failed for port %d", i); goto out; } } out: return err; } static struct android_usb_function acm_function = { .name = "acm", .cleanup = acm_function_cleanup, .bind_config = acm_function_bind_config, .attributes = acm_function_attributes, }; /* ADB */ static int adb_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return adb_setup(); } static void adb_function_cleanup(struct android_usb_function *f) { adb_cleanup(); } static int adb_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return adb_bind_config(c); } static struct android_usb_function adb_function = { .name = "adb", .init = adb_function_init, .cleanup = adb_function_cleanup, .bind_config = adb_function_bind_config, }; /* CCID */ static int ccid_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return ccid_setup(); } static void ccid_function_cleanup(struct android_usb_function *f) { ccid_cleanup(); } static int ccid_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return ccid_bind_config(c); } static struct android_usb_function ccid_function = { .name = "ccid", .init = ccid_function_init, .cleanup = ccid_function_cleanup, .bind_config = ccid_function_bind_config, }; static int mtp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return mtp_setup(); } static void mtp_function_cleanup(struct android_usb_function *f) { mtp_cleanup(); } static int mtp_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return mtp_bind_config(c, false); } static int ptp_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { /* nothing to do - initialization is handled by mtp_function_init */ return 0; } static void ptp_function_cleanup(struct android_usb_function *f) { /* nothing to do - cleanup is handled by mtp_function_cleanup */ } static int ptp_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return mtp_bind_config(c, true); } static int mtp_function_ctrlrequest(struct android_usb_function *f, struct usb_composite_dev *cdev, const struct usb_ctrlrequest *c) { return mtp_ctrlrequest(cdev, c); } static struct android_usb_function mtp_function = { .name = "mtp", .init = mtp_function_init, .cleanup = mtp_function_cleanup, .bind_config = mtp_function_bind_config, .ctrlrequest = mtp_function_ctrlrequest, }; /* PTP function is same as MTP with slightly different interface descriptor */ static struct android_usb_function ptp_function = { .name = "ptp", .init = ptp_function_init, .cleanup = ptp_function_cleanup, .bind_config = ptp_function_bind_config, }; struct rndis_function_config { u8 ethaddr[ETH_ALEN]; u32 vendorID; char manufacturer[256]; bool wceis; }; static int rndis_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL); if (!f->config) return -ENOMEM; return 0; } static void rndis_function_cleanup(struct android_usb_function *f) { kfree(f->config); f->config = NULL; } static int rndis_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { int ret; struct rndis_function_config *rndis = f->config; if (!rndis) { pr_err("%s: rndis_pdata\n", __func__); return -1; } pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); if (ret) { pr_err("%s: gether_setup failed\n", __func__); return ret; } if (rndis->wceis) { /* "Wireless" RNDIS; auto-detected by Windows */ rndis_iad_descriptor.bFunctionClass = USB_CLASS_WIRELESS_CONTROLLER; rndis_iad_descriptor.bFunctionSubClass = 0x01; rndis_iad_descriptor.bFunctionProtocol = 0x03; rndis_control_intf.bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER; rndis_control_intf.bInterfaceSubClass = 0x01; rndis_control_intf.bInterfaceProtocol = 0x03; } return rndis_bind_config(c, rndis->ethaddr, rndis->vendorID, rndis->manufacturer); } static void rndis_function_unbind_config(struct android_usb_function *f, struct usb_configuration *c) { gether_cleanup(); } static ssize_t rndis_manufacturer_show(struct device *dev, struct device_attribute *attr, char *buf) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; return snprintf(buf, PAGE_SIZE, "%s\n", config->manufacturer); } static ssize_t rndis_manufacturer_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; if (size >= sizeof(config->manufacturer)) return -EINVAL; if (sscanf(buf, "%255s", config->manufacturer) == 1) return size; return -1; } static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show, rndis_manufacturer_store); static ssize_t rndis_wceis_show(struct device *dev, struct device_attribute *attr, char *buf) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; return snprintf(buf, PAGE_SIZE, "%d\n", config->wceis); } static ssize_t rndis_wceis_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; int value; if (sscanf(buf, "%d", &value) == 1) { config->wceis = value; return size; } return -EINVAL; } static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show, rndis_wceis_store); static ssize_t rndis_ethaddr_show(struct device *dev, struct device_attribute *attr, char *buf) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *rndis = f->config; return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); } static ssize_t rndis_ethaddr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *rndis = f->config; if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", (int *)&rndis->ethaddr[0], (int *)&rndis->ethaddr[1], (int *)&rndis->ethaddr[2], (int *)&rndis->ethaddr[3], (int *)&rndis->ethaddr[4], (int *)&rndis->ethaddr[5]) == 6) return size; return -EINVAL; } static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show, rndis_ethaddr_store); static ssize_t rndis_vendorID_show(struct device *dev, struct device_attribute *attr, char *buf) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; return snprintf(buf, PAGE_SIZE, "%04x\n", config->vendorID); } static ssize_t rndis_vendorID_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct android_usb_function *f = dev_get_drvdata(dev); struct rndis_function_config *config = f->config; int value; if (sscanf(buf, "%04x", &value) == 1) { config->vendorID = value; return size; } return -EINVAL; } static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show, rndis_vendorID_store); static struct device_attribute *rndis_function_attributes[] = { &dev_attr_manufacturer, &dev_attr_wceis, &dev_attr_ethaddr, &dev_attr_vendorID, NULL }; static struct android_usb_function rndis_function = { .name = "rndis", .init = rndis_function_init, .cleanup = rndis_function_cleanup, .bind_config = rndis_function_bind_config, .unbind_config = rndis_function_unbind_config, .attributes = rndis_function_attributes, }; struct mass_storage_function_config { struct fsg_config fsg; struct fsg_common *common; }; static int mass_storage_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { struct mass_storage_function_config *config; struct fsg_common *common; int err; config = kzalloc(sizeof(struct mass_storage_function_config), GFP_KERNEL); if (!config) return -ENOMEM; config->fsg.nluns = 1; config->fsg.luns[0].removable = 1; common = fsg_common_init(NULL, cdev, &config->fsg); if (IS_ERR(common)) { kfree(config); return PTR_ERR(common); } err = sysfs_create_link(&f->dev->kobj, &common->luns[0].dev.kobj, "lun"); if (err) { fsg_common_release(&common->ref); kfree(config); return err; } config->common = common; f->config = config; return 0; } static void mass_storage_function_cleanup(struct android_usb_function *f) { kfree(f->config); f->config = NULL; } static int mass_storage_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { struct mass_storage_function_config *config = f->config; return fsg_bind_config(c->cdev, c, config->common); } static ssize_t mass_storage_inquiry_show(struct device *dev, struct device_attribute *attr, char *buf) { struct android_usb_function *f = dev_get_drvdata(dev); struct mass_storage_function_config *config = f->config; return snprintf(buf, PAGE_SIZE, "%s\n", config->common->inquiry_string); } static ssize_t mass_storage_inquiry_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct android_usb_function *f = dev_get_drvdata(dev); struct mass_storage_function_config *config = f->config; if (size >= sizeof(config->common->inquiry_string)) return -EINVAL; if (sscanf(buf, "%28s", config->common->inquiry_string) != 1) return -EINVAL; return size; } static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR, mass_storage_inquiry_show, mass_storage_inquiry_store); static struct device_attribute *mass_storage_function_attributes[] = { &dev_attr_inquiry_string, NULL }; static struct android_usb_function mass_storage_function = { .name = "mass_storage", .init = mass_storage_function_init, .cleanup = mass_storage_function_cleanup, .bind_config = mass_storage_function_bind_config, .attributes = mass_storage_function_attributes, }; static int accessory_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { return acc_setup(); } static void accessory_function_cleanup(struct android_usb_function *f) { acc_cleanup(); } static int accessory_function_bind_config(struct android_usb_function *f, struct usb_configuration *c) { return acc_bind_config(c); } static int accessory_function_ctrlrequest(struct android_usb_function *f, struct usb_composite_dev *cdev, const struct usb_ctrlrequest *c) { return acc_ctrlrequest(cdev, c); } static struct android_usb_function accessory_function = { .name = "accessory", .init = accessory_function_init, .cleanup = accessory_function_cleanup, .bind_config = accessory_function_bind_config, .ctrlrequest = accessory_function_ctrlrequest, }; static struct android_usb_function *supported_functions[] = { &rmnet_smd_function, &rmnet_sdio_function, &rmnet_smd_sdio_function, &rmnet_function, &diag_function, &serial_function, &adb_function, &ccid_function, &acm_function, &mtp_function, &ptp_function, &rndis_function, &mass_storage_function, &accessory_function, NULL }; static void android_cleanup_functions(struct android_usb_function **functions) { struct android_usb_function *f; struct device_attribute **attrs; struct device_attribute *attr; while (*functions) { f = *functions++; if (f->dev) { device_destroy(android_class, f->dev->devt); kfree(f->dev_name); } else continue; if (f->cleanup) f->cleanup(f); attrs = f->attributes; if (attrs) { while ((attr = *attrs++)) device_remove_file(f->dev, attr); } } } static int android_init_functions(struct android_usb_function **functions, struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct android_usb_function *f; struct device_attribute **attrs; struct device_attribute *attr; int err = 0; int index = 1; /* index 0 is for android0 device */ for (; (f = *functions++); index++) { f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); if (!f->dev_name) { err = -ENOMEM; goto err_out; } f->dev = device_create(android_class, dev->dev, MKDEV(0, index), f, f->dev_name); if (IS_ERR(f->dev)) { pr_err("%s: Failed to create dev %s", __func__, f->dev_name); err = PTR_ERR(f->dev); f->dev = NULL; goto err_create; } if (f->init) { err = f->init(f, cdev); if (err) { pr_err("%s: Failed to init %s", __func__, f->name); goto err_init; } } attrs = f->attributes; if (attrs) { while ((attr = *attrs++) && !err) err = device_create_file(f->dev, attr); } if (err) { pr_err("%s: Failed to create function %s attributes", __func__, f->name); goto err_attrs; } } return 0; err_attrs: for (attr = *(attrs -= 2); attrs != f->attributes; attr = *(attrs--)) device_remove_file(f->dev, attr); if (f->cleanup) f->cleanup(f); err_init: device_destroy(android_class, f->dev->devt); err_create: f->dev = NULL; kfree(f->dev_name); err_out: android_cleanup_functions(dev->functions); return err; } static int android_bind_enabled_functions(struct android_dev *dev, struct usb_configuration *c) { struct android_usb_function *f; int ret; list_for_each_entry(f, &dev->enabled_functions, enabled_list) { ret = f->bind_config(f, c); if (ret) { pr_err("%s: %s failed", __func__, f->name); return ret; } } return 0; } static void android_unbind_enabled_functions(struct android_dev *dev, struct usb_configuration *c) { struct android_usb_function *f; list_for_each_entry(f, &dev->enabled_functions, enabled_list) { if (f->unbind_config) f->unbind_config(f, c); } } static int android_enable_function(struct android_dev *dev, char *name) { struct android_usb_function **functions = dev->functions; struct android_usb_function *f; while ((f = *functions++)) { if (!strcmp(name, f->name)) { list_add_tail(&f->enabled_list, &dev->enabled_functions); return 0; } } return -EINVAL; } /*-------------------------------------------------------------------------*/ /* /sys/class/android_usb/android%d/ interface */ static ssize_t remote_wakeup_show(struct device *pdev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", !!(android_config_driver.bmAttributes & USB_CONFIG_ATT_WAKEUP)); } static ssize_t remote_wakeup_store(struct device *pdev, struct device_attribute *attr, const char *buff, size_t size) { int enable = 0; sscanf(buff, "%d", &enable); pr_debug("android_usb: %s remote wakeup\n", enable ? "enabling" : "disabling"); if (enable) android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; else android_config_driver.bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; return size; } static ssize_t functions_show(struct device *pdev, struct device_attribute *attr, char *buf) { struct android_dev *dev = dev_get_drvdata(pdev); struct android_usb_function *f; char *buff = buf; mutex_lock(&dev->mutex); list_for_each_entry(f, &dev->enabled_functions, enabled_list) buff += snprintf(buff, PAGE_SIZE, "%s,", f->name); mutex_unlock(&dev->mutex); if (buff != buf) *(buff-1) = '\n'; return buff - buf; } static ssize_t functions_store(struct device *pdev, struct device_attribute *attr, const char *buff, size_t size) { struct android_dev *dev = dev_get_drvdata(pdev); char *name; char buf[256], *b; int err; mutex_lock(&dev->mutex); if (dev->enabled) { mutex_unlock(&dev->mutex); return -EBUSY; } INIT_LIST_HEAD(&dev->enabled_functions); strlcpy(buf, buff, sizeof(buf)); b = strim(buf); while (b) { name = strsep(&b, ","); if (name) { err = android_enable_function(dev, name); if (err) pr_err("android_usb: Cannot enable '%s'", name); } } mutex_unlock(&dev->mutex); return size; } static ssize_t enable_show(struct device *pdev, struct device_attribute *attr, char *buf) { struct android_dev *dev = dev_get_drvdata(pdev); return snprintf(buf, PAGE_SIZE, "%d\n", dev->enabled); } static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, const char *buff, size_t size) { struct android_dev *dev = dev_get_drvdata(pdev); struct usb_composite_dev *cdev = dev->cdev; int enabled = 0; mutex_lock(&dev->mutex); sscanf(buff, "%d", &enabled); if (enabled && !dev->enabled) { /* update values in composite driver's copy of device descriptor */ cdev->desc.idVendor = device_desc.idVendor; cdev->desc.idProduct = device_desc.idProduct; cdev->desc.bcdDevice = device_desc.bcdDevice; cdev->desc.bDeviceClass = device_desc.bDeviceClass; cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass; cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol; if (usb_add_config(cdev, &android_config_driver, android_bind_config)) return size; usb_gadget_connect(cdev->gadget); dev->enabled = true; } else if (!enabled && dev->enabled) { usb_gadget_disconnect(cdev->gadget); /* Cancel pending control requests */ usb_ep_dequeue(cdev->gadget->ep0, cdev->req); usb_remove_config(cdev, &android_config_driver); dev->enabled = false; } else { pr_err("android_usb: already %s\n", dev->enabled ? "enabled" : "disabled"); } mutex_unlock(&dev->mutex); return size; } static ssize_t state_show(struct device *pdev, struct device_attribute *attr, char *buf) { struct android_dev *dev = dev_get_drvdata(pdev); struct usb_composite_dev *cdev = dev->cdev; char *state = "DISCONNECTED"; unsigned long flags; if (!cdev) goto out; spin_lock_irqsave(&cdev->lock, flags); if (cdev->config) state = "CONFIGURED"; else if (dev->connected) state = "CONNECTED"; spin_unlock_irqrestore(&cdev->lock, flags); out: return snprintf(buf, PAGE_SIZE, "%s\n", state); } #define DESCRIPTOR_ATTR(field, format_string) \ static ssize_t \ field ## _show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return snprintf(buf, PAGE_SIZE, \ format_string, device_desc.field); \ } \ static ssize_t \ field ## _store(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t size) \ { \ int value; \ if (sscanf(buf, format_string, &value) == 1) { \ device_desc.field = value; \ return size; \ } \ return -1; \ } \ static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); #define DESCRIPTOR_STRING_ATTR(field, buffer) \ static ssize_t \ field ## _show(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ return snprintf(buf, PAGE_SIZE, "%s", buffer); \ } \ static ssize_t \ field ## _store(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t size) \ { \ if (size >= sizeof(buffer)) return -EINVAL; \ if (sscanf(buf, "%255s", buffer) == 1) { \ return size; \ } \ return -1; \ } \ static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); DESCRIPTOR_ATTR(idVendor, "%04x\n") DESCRIPTOR_ATTR(idProduct, "%04x\n") DESCRIPTOR_ATTR(bcdDevice, "%04x\n") DESCRIPTOR_ATTR(bDeviceClass, "%d\n") DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n") DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n") DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string) DESCRIPTOR_STRING_ATTR(iProduct, product_string) DESCRIPTOR_STRING_ATTR(iSerial, serial_string) static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store); static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); static DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show, remote_wakeup_store); static struct device_attribute *android_usb_attributes[] = { &dev_attr_idVendor, &dev_attr_idProduct, &dev_attr_bcdDevice, &dev_attr_bDeviceClass, &dev_attr_bDeviceSubClass, &dev_attr_bDeviceProtocol, &dev_attr_iManufacturer, &dev_attr_iProduct, &dev_attr_iSerial, &dev_attr_functions, &dev_attr_enable, &dev_attr_state, &dev_attr_remote_wakeup, NULL }; /*-------------------------------------------------------------------------*/ /* Composite driver */ static int android_bind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; int ret = 0; ret = android_bind_enabled_functions(dev, c); if (ret) return ret; return 0; } static void android_unbind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; android_unbind_enabled_functions(dev, c); } static int android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; int gcnum, id, ret; usb_gadget_disconnect(gadget); ret = android_init_functions(dev->functions, cdev); if (ret) return ret; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. */ id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_PRODUCT_IDX].id = id; device_desc.iProduct = id; /* Default strings - should be updated by userspace */ strlcpy(manufacturer_string, "Android", sizeof(manufacturer_string) - 1); strlcpy(product_string, "Android", sizeof(product_string) - 1); strlcpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; if (gadget_is_otg(cdev->gadget)) android_config_driver.descriptors = otg_desc; gcnum = usb_gadget_controller_number(gadget); if (gcnum >= 0) device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); else { /* gadget zero is so simple (for now, no altsettings) that * it SHOULD NOT have problems with bulk-capable hardware. * so just warn about unrcognized controllers -- don't panic. * * things like configuration and altsetting numbering * can need hardware-specific attention though. */ pr_warning("%s: controller '%s' not recognized\n", longname, gadget->name); device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } dev->cdev = cdev; return 0; } static int android_usb_unbind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; manufacturer_string[0] = '\0'; product_string[0] = '\0'; serial_string[0] = '0'; cancel_work_sync(&dev->work); android_cleanup_functions(dev->functions); return 0; } static struct usb_composite_driver android_usb_driver = { .name = "android_usb", .dev = &device_desc, .strings = dev_strings, .unbind = android_usb_unbind, .max_speed = USB_SPEED_SUPER }; static int android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) { struct android_dev *dev = _android_dev; struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_request *req = cdev->req; struct android_usb_function *f; int value = -EOPNOTSUPP; unsigned long flags; req->zero = 0; req->complete = composite_setup_complete; req->length = 0; gadget->ep0->driver_data = cdev; list_for_each_entry(f, &dev->enabled_functions, enabled_list) { if (f->ctrlrequest) { value = f->ctrlrequest(f, cdev, c); if (value >= 0) break; } } /* Special case the accessory function. * It needs to handle control requests before it is enabled. */ if (value < 0) value = acc_ctrlrequest(cdev, c); if (value < 0) value = composite_setup(gadget, c); spin_lock_irqsave(&cdev->lock, flags); if (!dev->connected) { dev->connected = 1; schedule_work(&dev->work); } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) { schedule_work(&dev->work); } spin_unlock_irqrestore(&cdev->lock, flags); return value; } static void android_disconnect(struct usb_gadget *gadget) { struct android_dev *dev = _android_dev; struct usb_composite_dev *cdev = get_gadget_data(gadget); unsigned long flags; composite_disconnect(gadget); spin_lock_irqsave(&cdev->lock, flags); dev->connected = 0; schedule_work(&dev->work); spin_unlock_irqrestore(&cdev->lock, flags); } static int android_create_device(struct android_dev *dev) { struct device_attribute **attrs = android_usb_attributes; struct device_attribute *attr; int err; dev->dev = device_create(android_class, NULL, MKDEV(0, 0), NULL, "android0"); if (IS_ERR(dev->dev)) return PTR_ERR(dev->dev); dev_set_drvdata(dev->dev, dev); while ((attr = *attrs++)) { err = device_create_file(dev->dev, attr); if (err) { device_destroy(android_class, dev->dev->devt); return err; } } return 0; } static void android_destroy_device(struct android_dev *dev) { struct device_attribute **attrs = android_usb_attributes; struct device_attribute *attr; while ((attr = *attrs++)) device_remove_file(dev->dev, attr); device_destroy(android_class, dev->dev->devt); } static int __devinit android_probe(struct platform_device *pdev) { struct android_usb_platform_data *pdata = pdev->dev.platform_data; struct android_dev *dev = _android_dev; int ret = 0; dev->pdata = pdata; ret = usb_composite_probe(&android_usb_driver, android_bind); if (ret) { pr_err("%s(): Failed to register android " "composite driver\n", __func__); } return ret; } static int android_remove(struct platform_device *pdev) { usb_composite_unregister(&android_usb_driver); return 0; } static struct platform_driver android_platform_driver = { .driver = { .name = "android_usb"}, .probe = android_probe, .remove = android_remove, }; static int __init init(void) { struct android_dev *dev; int ret; android_class = class_create(THIS_MODULE, "android_usb"); if (IS_ERR(android_class)) return PTR_ERR(android_class); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { pr_err("%s(): Failed to alloc memory for android_dev\n", __func__); class_destroy(android_class); return -ENOMEM; } dev->functions = supported_functions; INIT_LIST_HEAD(&dev->enabled_functions); INIT_WORK(&dev->work, android_work); mutex_init(&dev->mutex); ret = android_create_device(dev); if (ret) { pr_err("%s(): android_create_device failed\n", __func__); goto err_dev; } _android_dev = dev; /* Override composite driver functions */ composite_driver.setup = android_setup; composite_driver.disconnect = android_disconnect; ret = platform_driver_register(&android_platform_driver); if (ret) { pr_err("%s(): Failed to register android" "platform driver\n", __func__); goto err_probe; } return ret; err_probe: android_destroy_device(dev); err_dev: kfree(dev); class_destroy(android_class); return ret; } module_init(init); static void __exit cleanup(void) { platform_driver_unregister(&android_platform_driver); android_destroy_device(_android_dev); kfree(_android_dev); class_destroy(android_class); _android_dev = NULL; } module_exit(cleanup);