/* * Gadget Driver for Android * * Copyright (C) 2008 Google, Inc. * 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 #include "f_mass_storage.h" #include "f_adb.h" #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" 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 platform data */ #define VENDOR_ID 0x18D1 #define PRODUCT_ID 0x0001 #define ADB_PRODUCT_ID 0x0002 struct android_dev { struct usb_composite_dev *cdev; int product_id; int adb_product_id; int version; int adb_enabled; int nluns; }; static atomic_t adb_enable_excl; static struct android_dev *_android_dev; /* string IDs are assigned dynamically */ #define STRING_MANUFACTURER_IDX 0 #define STRING_PRODUCT_IDX 1 #define STRING_SERIAL_IDX 2 /* String Table */ static struct usb_string strings_dev[] = { /* These dummy values should be overridden by platform data */ [STRING_MANUFACTURER_IDX].s = "Android", [STRING_PRODUCT_IDX].s = "Android", [STRING_SERIAL_IDX].s = "0123456789ABCDEF", { } /* 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, }; void android_usb_set_connected(int connected) { if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) { if (connected) usb_gadget_connect(_android_dev->cdev->gadget); else usb_gadget_disconnect(_android_dev->cdev->gadget); } } static int __init android_bind_config(struct usb_configuration *c) { struct android_dev *dev = _android_dev; int ret; printk(KERN_DEBUG "android_bind_config\n"); ret = mass_storage_function_add(dev->cdev, c, dev->nluns); if (ret) return ret; return adb_function_add(dev->cdev, c); } static int android_setup_config(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl); static struct usb_configuration android_config_driver = { .label = "android", .bind = android_bind_config, .setup = android_setup_config, .bConfigurationValue = 1, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 0xFA, /* 500ma */ }; static int android_setup_config(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl) { int i; int ret = -EOPNOTSUPP; for (i = 0; i < android_config_driver.next_interface_id; i++) { if (android_config_driver.interface[i]->setup) { ret = android_config_driver.interface[i]->setup( android_config_driver.interface[i], ctrl); if (ret >= 0) return ret; } } return ret; } static int __init android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; int gcnum; int id; int ret; printk(KERN_INFO "android_bind\n"); /* 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; id = usb_string_id(cdev); if (id < 0) return id; strings_dev[STRING_SERIAL_IDX].id = id; device_desc.iSerialNumber = id; if (gadget->ops->wakeup) android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; /* register our configuration */ ret = usb_add_config(cdev, &android_config_driver); if (ret) { printk(KERN_ERR "usb_add_config failed\n"); return ret; } 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); } usb_gadget_set_selfpowered(gadget); dev->cdev = cdev; return 0; } static struct usb_composite_driver android_usb_driver = { .name = "android_usb", .dev = &device_desc, .strings = dev_strings, .bind = android_bind, }; static void enable_adb(struct android_dev *dev, int enable) { if (enable != dev->adb_enabled) { dev->adb_enabled = enable; adb_function_enable(enable); /* set product ID to the appropriate value */ if (enable) device_desc.idProduct = __constant_cpu_to_le16(dev->adb_product_id); else device_desc.idProduct = __constant_cpu_to_le16(dev->product_id); if (dev->cdev) dev->cdev->desc.idProduct = device_desc.idProduct; /* force reenumeration */ if (dev->cdev && dev->cdev->gadget && dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) { usb_gadget_disconnect(dev->cdev->gadget); msleep(10); usb_gadget_connect(dev->cdev->gadget); usb_gadget_vbus_connect(dev->cdev->gadget); } } } static int adb_enable_open(struct inode *ip, struct file *fp) { if (atomic_inc_return(&adb_enable_excl) != 1) { atomic_dec(&adb_enable_excl); return -EBUSY; } printk(KERN_INFO "enabling adb\n"); enable_adb(_android_dev, 1); return 0; } static int adb_enable_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "disabling adb\n"); enable_adb(_android_dev, 0); atomic_dec(&adb_enable_excl); return 0; } static const struct file_operations adb_enable_fops = { .owner = THIS_MODULE, .open = adb_enable_open, .release = adb_enable_release, }; static struct miscdevice adb_enable_device = { .minor = MISC_DYNAMIC_MINOR, .name = "android_adb_enable", .fops = &adb_enable_fops, }; static int __init android_probe(struct platform_device *pdev) { struct android_usb_platform_data *pdata = pdev->dev.platform_data; struct android_dev *dev = _android_dev; printk(KERN_INFO "android_probe pdata: %p\n", pdata); if (pdata) { if (pdata->vendor_id) device_desc.idVendor = __constant_cpu_to_le16(pdata->vendor_id); if (pdata->product_id) { dev->product_id = pdata->product_id; device_desc.idProduct = __constant_cpu_to_le16(pdata->product_id); } if (pdata->adb_product_id) dev->adb_product_id = pdata->adb_product_id; if (pdata->version) dev->version = pdata->version; if (pdata->product_name) strings_dev[STRING_PRODUCT_IDX].s = pdata->product_name; if (pdata->manufacturer_name) strings_dev[STRING_MANUFACTURER_IDX].s = pdata->manufacturer_name; if (pdata->serial_number) strings_dev[STRING_SERIAL_IDX].s = pdata->serial_number; dev->nluns = pdata->nluns; } return 0; } static struct platform_driver android_platform_driver = { .driver = { .name = "android_usb", }, .probe = android_probe, }; static int __init init(void) { struct android_dev *dev; int ret; printk(KERN_INFO "android init\n"); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; /* set default values, which should be overridden by platform data */ dev->product_id = PRODUCT_ID; dev->adb_product_id = ADB_PRODUCT_ID; _android_dev = dev; ret = platform_driver_register(&android_platform_driver); if (ret) return ret; ret = misc_register(&adb_enable_device); if (ret) { platform_driver_unregister(&android_platform_driver); return ret; } ret = usb_composite_register(&android_usb_driver); if (ret) { misc_deregister(&adb_enable_device); platform_driver_unregister(&android_platform_driver); } return ret; } late_initcall(init); static void __exit cleanup(void) { usb_composite_unregister(&android_usb_driver); misc_deregister(&adb_enable_device); platform_driver_unregister(&android_platform_driver); kfree(_android_dev); _android_dev = NULL; } module_exit(cleanup);