|
@@ -1246,10 +1246,49 @@ EXPORT_SYMBOL_GPL(usb_string_ids_n);
|
|
|
|
|
|
static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
|
|
|
{
|
|
|
+ struct usb_composite_dev *cdev;
|
|
|
+
|
|
|
if (req->status || req->actual != req->length)
|
|
|
DBG((struct usb_composite_dev *) ep->driver_data,
|
|
|
"setup complete --> %d, %d/%d\n",
|
|
|
req->status, req->actual, req->length);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * REVIST The same ep0 requests are shared with function drivers
|
|
|
+ * so they don't have to maintain the same ->complete() stubs.
|
|
|
+ *
|
|
|
+ * Because of that, we need to check for the validity of ->context
|
|
|
+ * here, even though we know we've set it to something useful.
|
|
|
+ */
|
|
|
+ if (!req->context)
|
|
|
+ return;
|
|
|
+
|
|
|
+ cdev = req->context;
|
|
|
+
|
|
|
+ if (cdev->req == req)
|
|
|
+ cdev->setup_pending = false;
|
|
|
+ else if (cdev->os_desc_req == req)
|
|
|
+ cdev->os_desc_pending = false;
|
|
|
+ else
|
|
|
+ WARN(1, "unknown request %p\n", req);
|
|
|
+}
|
|
|
+
|
|
|
+static int composite_ep0_queue(struct usb_composite_dev *cdev,
|
|
|
+ struct usb_request *req, gfp_t gfp_flags)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = usb_ep_queue(cdev->gadget->ep0, req, gfp_flags);
|
|
|
+ if (ret == 0) {
|
|
|
+ if (cdev->req == req)
|
|
|
+ cdev->setup_pending = true;
|
|
|
+ else if (cdev->os_desc_req == req)
|
|
|
+ cdev->os_desc_pending = true;
|
|
|
+ else
|
|
|
+ WARN(1, "unknown request %p\n", req);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int count_ext_compat(struct usb_configuration *c)
|
|
@@ -1690,7 +1729,7 @@ unknown:
|
|
|
req->length = value;
|
|
|
req->context = cdev;
|
|
|
req->zero = value < w_length;
|
|
|
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
|
|
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
|
|
|
if (value < 0) {
|
|
|
DBG(cdev, "ep_queue --> %d\n", value);
|
|
|
req->status = 0;
|
|
@@ -1762,7 +1801,7 @@ unknown:
|
|
|
req->length = value;
|
|
|
req->context = cdev;
|
|
|
req->zero = value < w_length;
|
|
|
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
|
|
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
|
|
|
if (value < 0) {
|
|
|
DBG(cdev, "ep_queue --> %d\n", value);
|
|
|
req->status = 0;
|
|
@@ -1957,10 +1996,16 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
|
|
|
kfree(uc);
|
|
|
}
|
|
|
if (cdev->os_desc_req) {
|
|
|
+ if (cdev->os_desc_pending)
|
|
|
+ usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req);
|
|
|
+
|
|
|
kfree(cdev->os_desc_req->buf);
|
|
|
usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req);
|
|
|
}
|
|
|
if (cdev->req) {
|
|
|
+ if (cdev->setup_pending)
|
|
|
+ usb_ep_dequeue(cdev->gadget->ep0, cdev->req);
|
|
|
+
|
|
|
kfree(cdev->req->buf);
|
|
|
usb_ep_free_request(cdev->gadget->ep0, cdev->req);
|
|
|
}
|
|
@@ -2165,7 +2210,7 @@ void usb_composite_setup_continue(struct usb_composite_dev *cdev)
|
|
|
DBG(cdev, "%s: Completing delayed status\n", __func__);
|
|
|
req->length = 0;
|
|
|
req->context = cdev;
|
|
|
- value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
|
|
|
+ value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
|
|
|
if (value < 0) {
|
|
|
DBG(cdev, "ep_queue --> %d\n", value);
|
|
|
req->status = 0;
|