/* * 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" MODULE_AUTHOR("Mike Lockwood"); MODULE_DESCRIPTION("Android Composite USB Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); static char *g_android_function = "mass"; module_param_named(function, g_android_function, charp, S_IRUGO); static const char longname[] = "Gadget Android"; /* Default vendor and product IDs, overridden by platform data */ #define VENDOR_ID 0x0BB4 #define PRODUCT_ID 0x0001 #define ADB_PRODUCT_ID 0x0C01 /* Platform data */ static struct android_usb_platform_data android_platform_data = { .vendor_id = 0x18D1, .product_id = 0x0001, .adb_product_id = 0x0002, .version = 0x1, .product_name = "USB Mass Storage", .manufacturer_name = "Ingenic", .serial_number = "01234567890ABCDEF", }; /* LUN attribute table - Which also decides the amount of LUN */ static lun_attr_t lun_attr_table[] = { { /* LUN 0 */ "Ingenic", /* LUN 0 - Vendor */ "USB Disk", /* LUN 0 - Product */ 0, }, { /* LUN 1 */ "Ingenic", /* LUN 1 - Vendor */ "SD Card Reader", /* LUN 1 - Product */ 0, }, }; struct android_dev { struct usb_gadget *gadget; 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 #define STRING_MS_OS_IDX 3 #define STRING_MS_OS_ID 0xee /* 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", [STRING_MS_OS_IDX].s = "Microsoft", { } /* 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 int android_bind_config(struct usb_configuration *c) { int ret; printk(KERN_DEBUG "android_bind_config\n"); if (!strcmp(g_android_function, "adb")) { printk(KERN_INFO"Andorid Gadget: Function -> adb.\n"); ret = adb_function_add(c); if (ret) return ret; }else{ printk(KERN_INFO"Android Gadget: Function -> USB Mass storage.\n"); ret = mass_storage_function_add(c, lun_attr_table, sizeof(lun_attr_table) / sizeof(lun_attr_t)); if (ret) return ret; } return 0; } static struct usb_configuration android_config = { .label = "android", .bind = android_bind_config, .bConfigurationValue = 1, .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, .bMaxPower = 0x80, /* 250ma */ }; static int 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; strings_dev[STRING_MS_OS_IDX].id = STRING_MS_OS_ID; /* register our configuration */ ret = usb_add_config(cdev, &android_config); 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); } } } 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; } if (!strcmp(g_android_function, "adb")) { printk(KERN_INFO "enabling adb\n"); enable_adb(_android_dev, 1); return 0; }else return -ENODEV; } 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 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:%s, pdata: %p\n", pdev->name, 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 void android_platform_device_release(struct device *dev) { return; }; static struct platform_device android_platform_device = { .name = "android_usb", .id = -1, .dev = { .platform_data = &android_platform_data, .release = android_platform_device_release, }, }; static struct platform_driver android_platform_driver = { .driver = { .name = "android_usb", }, .probe = android_probe, }; static int __init init(void) { struct android_dev *dev; unsigned long status = 0; int ret; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; set_bit(0, &status); /* 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_device_register(&android_platform_device); if (ret) { goto err; } set_bit(1, &status); ret = platform_driver_register(&android_platform_driver); if (ret) { goto err; } set_bit(2, &status); ret = misc_register(&adb_enable_device); if (ret) { goto err; } set_bit(3, &status); ret = usb_composite_register(&android_usb_driver); if (ret) { goto err; } printk(KERN_INFO "Android Gadget Initialized.\n"); return 0; err: if (test_bit(3, &status)) { misc_deregister(&adb_enable_device); } if (test_bit(2, &status)) { platform_driver_unregister(&android_platform_driver); } if (test_bit(1, &status)) { platform_device_unregister(&android_platform_device); } if (test_bit(0, &status)) { kfree(dev); dev = NULL; } return ret; } module_init(init); static void __exit cleanup(void) { usb_composite_unregister(&android_usb_driver); misc_deregister(&adb_enable_device); platform_device_unregister(&android_platform_device); platform_driver_unregister(&android_platform_driver); kfree(_android_dev); _android_dev = NULL; } module_exit(cleanup);