Merge remote-tracking branch 'linux-2.6.32.y/master' into develop
[firefly-linux-kernel-4.4.55.git] / drivers / usb / gadget / f_rndis.c
index 5201374ae13cdae8d5328aa2815cc6d8e133782c..999a43c572bbfe4970dcd1ec83b3f802936261df 100644 (file)
@@ -23,8 +23,9 @@
 /* #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>
 
 #include <asm/atomic.h>
 
@@ -126,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 */
 };
 
@@ -284,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,
@@ -466,10 +478,10 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        usb_ep_disable(rndis->notify);
                } else {
                        VDBG(cdev, "init rndis ctrl %d\n", intf);
-                       rndis->notify_desc = ep_choose(cdev->gadget,
-                                       rndis->hs.notify,
-                                       rndis->fs.notify);
                }
+               rndis->notify_desc = ep_choose(cdev->gadget,
+                               rndis->hs.notify,
+                               rndis->fs.notify);
                usb_ep_enable(rndis->notify, rndis->notify_desc);
                rndis->notify->driver_data = rndis;
 
@@ -483,11 +495,11 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
                if (!rndis->port.in) {
                        DBG(cdev, "init rndis\n");
-                       rndis->port.in = ep_choose(cdev->gadget,
-                                       rndis->hs.in, rndis->fs.in);
-                       rndis->port.out = ep_choose(cdev->gadget,
-                                       rndis->hs.out, rndis->fs.out);
                }
+               rndis->port.in = ep_choose(cdev->gadget,
+                               rndis->hs.in, rndis->fs.in);
+               rndis->port.out = ep_choose(cdev->gadget,
+                               rndis->hs.out, rndis->fs.out);
 
                /* Avoid ZLPs; they can be troublesome. */
                rndis->port.is_zlp_ok = false;
@@ -685,11 +697,12 @@ 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 0
-// FIXME
-       if (rndis_set_param_vendor(rndis->config, vendorID,
-                               manufacturer))
-               goto fail0;
+#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
@@ -824,6 +837,11 @@ int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
        rndis->port.func.setup = rndis_setup;
        rndis->port.func.disable = rndis_disable;
 
+#ifdef CONFIG_USB_ANDROID_RNDIS
+       /* start disabled */
+       rndis->port.func.disabled = 1;
+#endif
+
        status = usb_add_function(c, &rndis->port.func);
        if (status) {
                kfree(rndis);
@@ -832,3 +850,54 @@ fail:
        }
        return status;
 }
+
+#ifdef CONFIG_USB_ANDROID_RNDIS
+#include "rndis.c"
+
+static int __init rndis_probe(struct platform_device *pdev)
+{
+       rndis_pdata = pdev->dev.platform_data;
+       return 0;
+}
+
+static struct platform_driver rndis_platform_driver = {
+       .driver = { .name = "rndis", },
+       .probe = rndis_probe,
+};
+
+int rndis_function_bind_config(struct usb_configuration *c)
+{
+       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, rndis_pdata->ethaddr);
+       return ret;
+}
+
+static struct android_usb_function rndis_function = {
+       .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;
+}
+module_init(init);
+
+#endif /* CONFIG_USB_ANDROID_RNDIS */