Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / gadget / composite.c
index ffa2a682c04b09b82bd10b334ba8ff6a1503b958..566d11d23be5460db90fd17dfb2fea3293d30ec3 100644 (file)
@@ -144,11 +144,16 @@ int config_ep_by_speed(struct usb_gadget *g,
 
 ep_found:
        /* commit results */
-       _ep->maxpacket = usb_endpoint_maxp(chosen_desc);
+       _ep->maxpacket = usb_endpoint_maxp(chosen_desc) & 0x7ff;
        _ep->desc = chosen_desc;
        _ep->comp_desc = NULL;
        _ep->maxburst = 0;
-       _ep->mult = 0;
+       _ep->mult = 1;
+
+       if (g->speed == USB_SPEED_HIGH && (usb_endpoint_xfer_isoc(_ep->desc) ||
+                               usb_endpoint_xfer_int(_ep->desc)))
+               _ep->mult = ((usb_endpoint_maxp(_ep->desc) & 0x1800) >> 11) + 1;
+
        if (!want_comp_desc)
                return 0;
 
@@ -165,7 +170,7 @@ ep_found:
                switch (usb_endpoint_type(_ep->desc)) {
                case USB_ENDPOINT_XFER_ISOC:
                        /* mult: bits 1:0 of bmAttributes */
-                       _ep->mult = comp_desc->bmAttributes & 0x3;
+                       _ep->mult = (comp_desc->bmAttributes & 0x3) + 1;
                case USB_ENDPOINT_XFER_BULK:
                case USB_ENDPOINT_XFER_INT:
                        _ep->maxburst = comp_desc->bMaxBurst + 1;
@@ -1596,9 +1601,7 @@ 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;
@@ -1607,7 +1610,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                f = cdev->config->interface[intf];
                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) {
@@ -1766,14 +1775,19 @@ unknown:
                                }
                                break;
                        }
-                       req->length = value;
-                       req->context = cdev;
-                       req->zero = value < w_length;
-                       value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
-                       if (value < 0) {
-                               DBG(cdev, "ep_queue --> %d\n", value);
-                               req->status = 0;
-                               composite_setup_complete(gadget->ep0, req);
+
+                       if (value >= 0) {
+                               req->length = value;
+                               req->context = cdev;
+                               req->zero = value < w_length;
+                               value = composite_ep0_queue(cdev, req,
+                                                           GFP_ATOMIC);
+                               if (value < 0) {
+                                       DBG(cdev, "ep_queue --> %d\n", value);
+                                       req->status = 0;
+                                       composite_setup_complete(gadget->ep0,
+                                                                req);
+                               }
                        }
                        return value;
                }
@@ -2054,6 +2068,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
 
                kfree(cdev->os_desc_req->buf);
                usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
+               cdev->os_desc_req = NULL;
        }
        if (cdev->req) {
                if (cdev->setup_pending)
@@ -2061,6 +2076,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
 
                kfree(cdev->req->buf);
                usb_ep_free_request(cdev->gadget->ep0, cdev->req);
+               cdev->req = NULL;
        }
        cdev->next_string_id = 0;
        device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);