usb: gadget: Add RNDIS (Remote Network Driver Interface Specification) for supporting native USB Tethering.
This commit is contained in:
parent
bdfeaacf04
commit
6ca79cd6f1
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -23,7 +23,7 @@
|
||||
/* #define VERBOSE_DEBUG */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/usb/android_composite.h>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define __LINUX_USB_ANDROID_H
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user