diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 7e7add8e..dcc7c990 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -320,6 +320,21 @@ static struct platform_device usb_mass_storage_device = { }, }; +#ifdef CONFIG_USB_ANDROID_RNDIS +static struct usb_ether_platform_data rndis_pdata = { + .vendorID = 0x0bb4, + .vendorDescr = "HTC", +}; + +static struct platform_device rndis_device = { + .name = "rndis", + .id = -1, + .dev = { + .platform_data = &rndis_pdata, + }, +}; +#endif + static struct android_usb_platform_data android_usb_pdata = { .vendor_id = 0x0bb4, .product_id = 0x0c02, @@ -350,6 +365,9 @@ static void htcleo_add_usb_devices(void) gpio_set_value(HTCLEO_GPIO_USBPHY_3V3_ENABLE, 1); platform_device_register(&msm_device_hsusb); platform_device_register(&usb_mass_storage_device); +#ifdef CONFIG_USB_ANDROID_RNDIS + platform_device_register(&rndis_device); +#endif platform_device_register(&android_usb_device); } diff --git a/arch/arm/mach-msm/include/mach/htc_usb.h b/arch/arm/mach-msm/include/mach/htc_usb.h index 9bcabce1..21029f58 100644 --- a/arch/arm/mach-msm/include/mach/htc_usb.h +++ b/arch/arm/mach-msm/include/mach/htc_usb.h @@ -25,14 +25,18 @@ static char *usb_functions_ums[] = { "usb_mass_storage", }; -static char *usb_functions_adb[] = { +static char *usb_functions_ums_adb[] = { "usb_mass_storage", "adb", }; #ifdef CONFIG_USB_ANDROID_RNDIS static char *usb_functions_rndis[] = { - "ether", + "rndis", +}; +static char *usb_functions_rndis_adb[] = { + "rndis", + "adb", }; #endif @@ -110,7 +114,7 @@ static char *usb_functions_diag_serial[] = { static char *usb_functions_all[] = { #ifdef CONFIG_USB_ANDROID_RNDIS - "ether", + "rndis", #endif #ifdef CONFIG_USB_ANDROID_MTP "mtp", @@ -130,15 +134,15 @@ static char *usb_functions_all[] = { static struct android_usb_product usb_products[] = { { - .product_id = 0x0c02, /* vary by board */ - .num_functions = ARRAY_SIZE(usb_functions_adb), - .functions = usb_functions_adb, - }, - { - .product_id = 0x0ff9, + .product_id = 0x0c01, .num_functions = ARRAY_SIZE(usb_functions_ums), .functions = usb_functions_ums, }, + { + .product_id = 0x0c02, + .num_functions = ARRAY_SIZE(usb_functions_ums_adb), + .functions = usb_functions_ums_adb, + }, #ifdef CONFIG_USB_ANDROID_SERIAL { .product_id = 0x0c03, @@ -215,6 +219,11 @@ static struct android_usb_product usb_products[] = { .num_functions = ARRAY_SIZE(usb_functions_rndis), .functions = usb_functions_rndis, }, + { + .product_id = 0x0ffc, + .num_functions = ARRAY_SIZE(usb_functions_rndis_adb), + .functions = usb_functions_rndis_adb, + }, #endif }; #endif diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index efbcbcc7..be23728f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -836,6 +836,15 @@ config USB_ANDROID_RNDIS help Provides RNDIS ethernet function for android gadget driver. +config USB_ANDROID_RNDIS_WCEIS + boolean "Use Windows Internet Sharing Class/SubClass/Protocol" + depends on USB_ANDROID_RNDIS + help + Causes the driver to look like a Windows-compatible Internet + Sharing device, so Windows auto-detects it. + If you enable this option, the device is no longer CDC ethernet + compatible. + config USB_ANDROID_SERIAL boolean "Android gadget Serial function" depends on USB_ANDROID diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 25cfe2f5..f2a3f3ee 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -440,7 +440,7 @@ int android_switch_function(unsigned func) !strcmp(f->name, "adb")) f->hidden = 0; else if ((func & (1 << USB_FUNCTION_RNDIS)) && - !strcmp(f->name, "ether")) + !strcmp(f->name, "rndis")) f->hidden = 0; else if ((func & (1 << USB_FUNCTION_DIAG)) && !strcmp(f->name, "diag")) @@ -499,23 +499,40 @@ void android_enable_function(struct usb_function *f, int enable) if (!!f->hidden != disable) { f->hidden = disable; + +#ifdef CONFIG_USB_ANDROID_RNDIS + if (!strcmp(f->name, "rndis")) { + struct usb_function *func; + + /* We need to specify the COMM class in the device descriptor + * if we are using RNDIS. + */ + if (enable) +#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS + dev->cdev->desc.bDeviceClass = USB_CLASS_WIRELESS_CONTROLLER; +#else + dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; +#endif + else + dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; + + /* Windows does not support other interfaces when RNDIS is enabled, + * so we disable UMS when RNDIS is on. + */ + list_for_each_entry(func, &android_config_driver.functions, list) { + if (!strcmp(func->name, "usb_mass_storage")) { + func->hidden = enable; + break; + } + } + } +#endif + product_id = get_product_id(dev); device_desc.idProduct = __constant_cpu_to_le16(product_id); if (dev->cdev) dev->cdev->desc.idProduct = device_desc.idProduct; -#ifdef CONFIG_USB_ANDROID_RNDIS - /* We need to specify the COMM class in the device descriptor - * if we are using RNDIS. - */ - if (!strcmp(f->name, "ether")) { - if (enable) - dev->cdev->desc.bDeviceClass = USB_CLASS_COMM; - else - dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE; - } -#endif - #ifdef CONFIG_USB_GADGET_MSM_72K msm_hsusb_request_reset(); #else diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 3360b481..689093b2 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -23,7 +23,7 @@ /* #define VERBOSE_DEBUG */ #include -#include +#include #include #include @@ -95,7 +95,6 @@ struct f_rndis { atomic_t notify_count; }; -static char manufacturer [10] = "HTC"; static inline struct f_rndis *func_to_rndis(struct usb_function *f) { return container_of(f, struct f_rndis, port.func); @@ -128,9 +127,16 @@ static struct usb_interface_descriptor rndis_control_intf __initdata = { /* .bInterfaceNumber = DYNAMIC */ /* status endpoint is optional; this could be patched later */ .bNumEndpoints = 1, +#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS + /* "Wireless" RNDIS; auto-detected by Windows */ + .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 3, +#else .bInterfaceClass = USB_CLASS_COMM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, +#endif /* .iInterface = DYNAMIC */ }; @@ -286,6 +292,10 @@ static struct usb_gadget_strings *rndis_strings[] = { NULL, }; +#ifdef CONFIG_USB_ANDROID_RNDIS +static struct usb_ether_platform_data *rndis_pdata; +#endif + /*-------------------------------------------------------------------------*/ static struct sk_buff *rndis_add_header(struct gether *port, @@ -583,7 +593,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) struct f_rndis *rndis = func_to_rndis(f); int status; struct usb_ep *ep; - u32 vendorID = 0x0bb4; /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); @@ -689,9 +698,13 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); - if (rndis_set_param_vendor(rndis->config, vendorID, - manufacturer)) - goto fail; +#ifdef CONFIG_USB_ANDROID_RNDIS + if (rndis_pdata) { + if (rndis_set_param_vendor(rndis->config, rndis_pdata->vendorID, + rndis_pdata->vendorDescr)) + goto fail; + } +#endif /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -816,7 +829,7 @@ int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) rndis->port.wrap = rndis_add_header; rndis->port.unwrap = rndis_rm_hdr; - rndis->port.func.name = "ether"; + rndis->port.func.name = "rndis"; rndis->port.func.strings = rndis_strings; /* descriptors are per-instance copies */ rndis->port.func.bind = rndis_bind; @@ -842,26 +855,47 @@ fail: #ifdef CONFIG_USB_ANDROID_RNDIS #include "rndis.c" -// FIXME - using bogus MAC address for now +static int __init rndis_probe(struct platform_device *pdev) +{ + rndis_pdata = pdev->dev.platform_data; + return 0; +} -static u8 ethaddr[ETH_ALEN] = { 11, 22, 33, 44, 55, 66 }; +static struct platform_driver rndis_platform_driver = { + .driver = { .name = "rndis", }, + .probe = rndis_probe, +}; int rndis_function_bind_config(struct usb_configuration *c) { - int ret = gether_setup(c->cdev->gadget, ethaddr); + int ret; + + if (!rndis_pdata) { + printk(KERN_ERR "rndis_pdata null in rndis_function_bind_config\n"); + return -1; + } + + printk(KERN_INFO + "rndis_function_bind_config MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + rndis_pdata->ethaddr[0], rndis_pdata->ethaddr[1], + rndis_pdata->ethaddr[2], rndis_pdata->ethaddr[3], + rndis_pdata->ethaddr[4], rndis_pdata->ethaddr[5]); + + ret = gether_setup(c->cdev->gadget, rndis_pdata->ethaddr); if (ret == 0) - ret = rndis_bind_config(c, ethaddr); + ret = rndis_bind_config(c, rndis_pdata->ethaddr); return ret; } static struct android_usb_function rndis_function = { - .name = "ether", + .name = "rndis", .bind_config = rndis_function_bind_config, }; static int __init init(void) { printk(KERN_INFO "f_rndis init\n"); + platform_driver_register(&rndis_platform_driver); android_register_function(&rndis_function); return 0; } diff --git a/include/linux/usb/android_composite.h b/include/linux/usb/android_composite.h index fd9d2c3a..dc40ecca 100644 --- a/include/linux/usb/android_composite.h +++ b/include/linux/usb/android_composite.h @@ -18,6 +18,7 @@ #define __LINUX_USB_ANDROID_H #include +#include struct android_usb_function { struct list_head list; @@ -26,6 +27,11 @@ struct android_usb_function { }; struct android_usb_product { + /* Vendor ID for this set of functions. + * Default vendor_id in platform data will be used if this is zero. + */ + __u16 vendor_id; + /* Default product ID. */ __u16 product_id; @@ -83,6 +89,13 @@ struct usb_mass_storage_platform_data { int cdrom_lun; }; +/* Platform data for USB ethernet driver. */ +struct usb_ether_platform_data { + u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *vendorDescr; +}; + extern void android_usb_set_connected(int on); extern void android_register_function(struct android_usb_function *f);