Merge tag 'v3.10.106' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / usb / gadget / composite.c
index 55f4df60f327a654bf5863bdc68d2e79d82a8530..3fc750f52639a5885855c2a19f4063391f1eac1f 100644 (file)
 
 /* #define VERBOSE_DEBUG */
 
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt
+
 #include <linux/kallsyms.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/usb/composite.h>
 #include <asm/unaligned.h>
 
+#include <linux/printk.h>
+
+
+
 /*
  * The code in this file is utility code, used to build a gadget driver
  * from one or more "function" drivers, one or more "configuration"
@@ -180,8 +189,10 @@ int usb_add_function(struct usb_configuration *config,
                struct usb_function *function)
 {
        int     value = -EINVAL;
+       
+       pr_debug("[XLOG_DEBUG][USB][COM]%s: \n", __func__);
 
-       DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
+       INFO(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
                        function->name, function,
                        config->label, config);
 
@@ -215,7 +226,7 @@ int usb_add_function(struct usb_configuration *config,
 
 done:
        if (value)
-               DBG(config->cdev, "adding '%s'/%p --> %d\n",
+               INFO(config->cdev, "adding '%s'/%p --> %d\n",
                                function->name, function, value);
        return value;
 }
@@ -223,13 +234,17 @@ EXPORT_SYMBOL_GPL(usb_add_function);
 
 void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
 {
-       if (f->disable)
+       if (f->disable) {
+               INFO(c->cdev, "disable function '%s'/%p\n", f->name, f);
                f->disable(f);
+       }
 
        bitmap_zero(f->endpoints, 32);
        list_del(&f->list);
-       if (f->unbind)
+       if (f->unbind) {
+               INFO(c->cdev, "unbind function '%s'/%p\n", f->name, f);
                f->unbind(c, f);
+       }
 }
 EXPORT_SYMBOL_GPL(usb_remove_function);
 
@@ -528,7 +543,11 @@ static int bos_desc(struct usb_composite_dev *cdev)
        usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
        usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
        usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+#ifdef CONFIG_USBIF_COMPLIANCE
+       usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT) | cpu_to_le32(USB_BESL_SUPPORT) ; 
+#else
        usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+#endif
 
        /*
         * The Superspeed USB Capability descriptor shall be implemented by all
@@ -587,12 +606,14 @@ static void reset_config(struct usb_composite_dev *cdev)
        DBG(cdev, "reset config\n");
 
        list_for_each_entry(f, &cdev->config->functions, list) {
+               INFO(cdev, "disable function '%s'/%p\n", f->name, f);
                if (f->disable)
                        f->disable(f);
 
                bitmap_zero(f->endpoints, 32);
        }
        cdev->config = NULL;
+       cdev->delayed_status = 0;
 }
 
 static int set_config(struct usb_composite_dev *cdev,
@@ -767,18 +788,19 @@ int usb_add_config(struct usb_composite_dev *cdev,
                                        struct usb_function, list);
                        list_del(&f->list);
                        if (f->unbind) {
-                               DBG(cdev, "unbind function '%s'/%p\n",
+                               INFO(cdev, "unbind function '%s'/%p\n",
                                        f->name, f);
                                f->unbind(config, f);
                                /* may free memory for "f" */
                        }
                }
                list_del(&config->list);
+               pr_debug("[XLOG_DEBUG][USB][COM]bind fialed and the list should be init because there is one entry only");
                config->cdev = NULL;
        } else {
                unsigned        i;
 
-               DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
+               INFO(cdev, "cfg %d/%p speeds:%s%s%s\n",
                        config->bConfigurationValue, config,
                        config->superspeed ? " super" : "",
                        config->highspeed ? " high" : "",
@@ -811,7 +833,7 @@ done:
 }
 EXPORT_SYMBOL_GPL(usb_add_config);
 
-static void remove_config(struct usb_composite_dev *cdev,
+static void unbind_config(struct usb_composite_dev *cdev,
                              struct usb_configuration *config)
 {
        while (!list_empty(&config->functions)) {
@@ -821,17 +843,19 @@ static void remove_config(struct usb_composite_dev *cdev,
                                struct usb_function, list);
                list_del(&f->list);
                if (f->unbind) {
-                       DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+                       INFO(cdev, "unbind function '%s'/%p\n", f->name, f);
                        f->unbind(config, f);
                        /* may free memory for "f" */
                }
        }
-       list_del(&config->list);
        if (config->unbind) {
-               DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+               INFO(cdev, "unbind config '%s'/%p\n", config->label, config);
                config->unbind(config);
                        /* may free memory for "c" */
        }
+
+       /* reset all driver data to prevent leakage of ep allocation */
+       usb_ep_autoconfig_reset(cdev->gadget);
 }
 
 /**
@@ -853,9 +877,18 @@ void usb_remove_config(struct usb_composite_dev *cdev,
        if (cdev->config == config)
                reset_config(cdev);
 
+
+       if(config->cdev != NULL)
+       {
+               list_del(&config->list);
+       }else
+       {
+        DBG(cdev, "%s: config->list has been delete!! \n", __func__);
+       }
+       
        spin_unlock_irqrestore(&cdev->lock, flags);
 
-       remove_config(cdev, config);
+       unbind_config(cdev, config);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1197,7 +1230,7 @@ EXPORT_SYMBOL_GPL(usb_string_ids_n);
 
 /*-------------------------------------------------------------------------*/
 
-static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
+void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
 {
        if (req->status || req->actual != req->length)
                DBG((struct usb_composite_dev *) ep->driver_data,
@@ -1205,6 +1238,8 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
                                req->status, req->actual, req->length);
 }
 
+EXPORT_SYMBOL_GPL(composite_setup_complete);
+
 /*
  * The setup() callback implements all the ep0 functionality that's
  * not handled lower down, in hardware or the hardware driver(like
@@ -1226,6 +1261,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        struct usb_function             *f = NULL;
        u8                              endp;
 
+       pr_debug("[XLOG_DEBUG][USB][COM]%s bRequest=0x%X\n",
+               __func__, ctrl->bRequest);
+
        /* partial re-init of the response message; the function or the
         * gadget might need to intercept e.g. a control-OUT completion
         * when we delegate to it.
@@ -1242,7 +1280,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                if (ctrl->bRequestType != USB_DIR_IN)
                        goto unknown;
                switch (w_value >> 8) {
-
+#ifdef CONFIG_USBIF_COMPLIANCE
+               case USB_DT_OTG:
+            {
+            struct usb_otg_descriptor *otg_desc = req->buf;
+            otg_desc->bLength = sizeof(*otg_desc);
+            otg_desc->bDescriptorType = USB_DT_OTG;
+            otg_desc->bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
+            otg_desc->bcdOTG = cpu_to_le16(0x0200);
+                       value = min_t(int, w_length,sizeof(struct usb_otg_descriptor));
+            }
+                       break;
+#endif
                case USB_DT_DEVICE:
                        cdev->desc.bNumConfigurations =
                                count_configs(cdev, USB_DT_DEVICE);
@@ -1259,6 +1308,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
                        value = min(w_length, (u16) sizeof cdev->desc);
                        memcpy(req->buf, &cdev->desc, value);
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                                       "USB_DT_DEVICE, value=%d\n",value);
                        break;
                case USB_DT_DEVICE_QUALIFIER:
                        if (!gadget_is_dualspeed(gadget) ||
@@ -1267,8 +1318,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        device_qual(cdev);
                        value = min_t(int, w_length,
                                sizeof(struct usb_qualifier_descriptor));
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                                       "USB_DT_DEVICE_QUALIFIER, value=%d\n",value);
                        break;
                case USB_DT_OTHER_SPEED_CONFIG:
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                                       "USB_DT_OTHER_SPEED_CONFIG\n");
                        if (!gadget_is_dualspeed(gadget) ||
                            gadget->speed >= USB_SPEED_SUPER)
                                break;
@@ -1277,18 +1332,28 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        value = config_desc(cdev, w_value);
                        if (value >= 0)
                                value = min(w_length, (u16) value);
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                                       "USB_DT_CONFIG, value=%d\n",value);
                        break;
                case USB_DT_STRING:
                        value = get_string(cdev, req->buf,
                                        w_index, w_value & 0xff);
-                       if (value >= 0)
+                       if (value >= 0) {
                                value = min(w_length, (u16) value);
+                               pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                               "USB_DT_STRING, value=%d\n" ,value);
+                       }
                        break;
                case USB_DT_BOS:
                        if (gadget_is_superspeed(gadget)) {
                                value = bos_desc(cdev);
                                value = min(w_length, (u16) value);
                        }
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+                                               "USB_DT_BOS, value=%d\n",value);
+                       break;
+               default:
+                       pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR w_value=0x%X\n", w_value);
                        break;
                }
                break;
@@ -1308,6 +1373,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                spin_lock(&cdev->lock);
                value = set_config(cdev, ctrl, w_value);
                spin_unlock(&cdev->lock);
+               pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_SET_CONFIGURATION: "
+                                               "value=%d\n",value);
                break;
        case USB_REQ_GET_CONFIGURATION:
                if (ctrl->bRequestType != USB_DIR_IN)
@@ -1319,18 +1386,27 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                value = min(w_length, (u16) 1);
                break;
 
-       /* function drivers must handle get/set altsetting; if there's
-        * no get() method, we know only altsetting zero works.
-        */
+       /* function drivers must handle get/set altsetting */
        case USB_REQ_SET_INTERFACE:
                if (ctrl->bRequestType != USB_RECIP_INTERFACE)
                        goto unknown;
                if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
                        break;
-               f = cdev->config->interface[intf];
+
+               if (cdev->config)
+                   f = cdev->config->interface[intf];
+               else
+                       pr_debug("%s: cdev->config = NULL \n", __func__);
+
                if (!f)
                        break;
-               if (w_value && !f->set_alt)
+
+               /*
+                * If there's no get_alt() method, we know only altsetting zero
+                * works. There is no need to check if set_alt() is not NULL
+                * as we check this in usb_add_function().
+                */
+               if (w_value && !f->get_alt)
                        break;
                value = f->set_alt(f, w_index, w_value);
                if (value == USB_GADGET_DELAYED_STATUS) {
@@ -1366,6 +1442,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
         * interface of the function
         */
        case USB_REQ_GET_STATUS:
+               pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_STATUS\n");
                if (!gadget_is_superspeed(gadget))
                        goto unknown;
                if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
@@ -1389,12 +1466,15 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
         */
        case USB_REQ_CLEAR_FEATURE:
        case USB_REQ_SET_FEATURE:
+               pr_debug("[XLOG_DEBUG][USB][COM]%s w_value=%d\n",
+                       ((ctrl->bRequest==USB_REQ_SET_FEATURE)? "USB_REQ_SET_FEATURE" : "USB_REQ_CLEAR_FEATURE"), w_value);
                if (!gadget_is_superspeed(gadget))
                        goto unknown;
                if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
                        goto unknown;
                switch (w_value) {
                case USB_INTRF_FUNC_SUSPEND:
+                       pr_debug("[COM]USB_INTRF_FUNC_SUSPEND\n");
                        if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
                                break;
                        f = cdev->config->interface[intf];
@@ -1412,6 +1492,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                        break;
                }
                break;
+       case USB_REQ_SET_SEL:
+               pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_SET_SEL Pretend success\n");
+               value = 0;
+               break;
        default:
 unknown:
                VDBG(cdev,
@@ -1475,6 +1559,11 @@ unknown:
        }
 
 done:
+       if(value < 0) {
+               pr_debug("[XLOG_DEBUG][USB][COM]composite_setup: value=%d,"
+                               "bRequestType=0x%x, bRequest=0x%x, w_value=0x%x, w_length=0x%x \n", value,
+                               ctrl->bRequestType,     ctrl->bRequest, w_value, w_length);
+       }
        /* device either stalls (value < 0) or reports success */
        return value;
 }
@@ -1492,6 +1581,14 @@ void composite_disconnect(struct usb_gadget *gadget)
                reset_config(cdev);
        if (cdev->driver->disconnect)
                cdev->driver->disconnect(cdev);
+
+       /* ALPS00235316 and ALPS00234976 */
+       /* reset the complet function */
+       if(cdev->req->complete) {
+               pr_debug("[XLOG_DEBUG][USB][COM]%s:  reassign the complete function!!\n", __func__);
+               cdev->req->complete = composite_setup_complete;
+       }
+
        spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
@@ -1524,7 +1621,8 @@ static void __composite_unbind(struct usb_gadget *gadget, bool unbind_driver)
                struct usb_configuration        *c;
                c = list_first_entry(&cdev->configs,
                                struct usb_configuration, list);
-               remove_config(cdev, c);
+               list_del(&c->list);
+               unbind_config(cdev, c);
        }
        if (cdev->driver->unbind && unbind_driver)
                cdev->driver->unbind(cdev);
@@ -1778,6 +1876,8 @@ int usb_composite_probe(struct usb_composite_driver *driver)
        if (!driver || !driver->dev || !driver->bind)
                return -EINVAL;
 
+       pr_debug("[XLOG_DEBUG][USB][COM]%s: driver->name = %s", __func__, driver->name);
+
        if (!driver->name)
                driver->name = "composite";