reset_config(cdev);
                        goto done;
                }
+
+               if (result == USB_GADGET_DELAYED_STATUS) {
+                       DBG(cdev,
+                        "%s: interface %d (%s) requested delayed status\n",
+                                       __func__, tmp, f->name);
+                       cdev->delayed_status++;
+                       DBG(cdev, "delayed_status count %d\n",
+                                       cdev->delayed_status);
+               }
        }
 
        /* when we return, be sure our power usage is valid */
        power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
 done:
        usb_gadget_vbus_draw(gadget, power);
+       if (result >= 0 && cdev->delayed_status)
+               result = USB_GADGET_DELAYED_STATUS;
        return result;
 }
 
                if (w_value && !f->set_alt)
                        break;
                value = f->set_alt(f, w_index, w_value);
+               if (value == USB_GADGET_DELAYED_STATUS) {
+                       DBG(cdev,
+                        "%s: interface %d (%s) requested delayed status\n",
+                                       __func__, intf, f->name);
+                       cdev->delayed_status++;
+                       DBG(cdev, "delayed_status count %d\n",
+                                       cdev->delayed_status);
+               }
                break;
        case USB_REQ_GET_INTERFACE:
                if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
        }
 
        /* respond with data transfer before status phase? */
-       if (value >= 0) {
+       if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
                req->length = value;
                req->zero = value < w_length;
                value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
                        req->status = 0;
                        composite_setup_complete(gadget->ep0, req);
                }
+       } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
+               WARN(cdev,
+                       "%s: Delayed status not supported for w_length != 0",
+                       __func__);
        }
 
 done:
                return;
        usb_gadget_unregister_driver(&composite_driver);
 }
+
+/**
+ * usb_composite_setup_continue() - Continue with the control transfer
+ * @cdev: the composite device who's control transfer was kept waiting
+ *
+ * This function must be called by the USB function driver to continue
+ * with the control transfer's data/status stage in case it had requested to
+ * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
+ * can request the composite framework to delay the setup request's data/status
+ * stages by returning USB_GADGET_DELAYED_STATUS.
+ */
+void usb_composite_setup_continue(struct usb_composite_dev *cdev)
+{
+       int                     value;
+       struct usb_request      *req = cdev->req;
+       unsigned long           flags;
+
+       DBG(cdev, "%s\n", __func__);
+       spin_lock_irqsave(&cdev->lock, flags);
+
+       if (cdev->delayed_status == 0) {
+               WARN(cdev, "%s: Unexpected call\n", __func__);
+
+       } else if (--cdev->delayed_status == 0) {
+               DBG(cdev, "%s: Completing delayed status\n", __func__);
+               req->length = 0;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0) {
+                       DBG(cdev, "ep_queue --> %d\n", value);
+                       req->status = 0;
+                       composite_setup_complete(cdev->gadget->ep0, req);
+               }
+       }
+
+       spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
+/*
+ * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
+ * wish to delay the data/status stages of the control transfer till they
+ * are ready. The control transfer will then be kept from completing till
+ * all the function drivers that requested for USB_GADGET_DELAYED_STAUS
+ * invoke usb_composite_setup_continue().
+ */
+#define USB_GADGET_DELAYED_STATUS       0x7fff /* Impossibly large value */
 
 struct usb_configuration;
 
 extern int usb_composite_probe(struct usb_composite_driver *driver,
                               int (*bind)(struct usb_composite_dev *cdev));
 extern void usb_composite_unregister(struct usb_composite_driver *driver);
+extern void usb_composite_setup_continue(struct usb_composite_dev *cdev);
 
 
 /**
         */
        unsigned                        deactivations;
 
-       /* protects at least deactivation count */
+       /* the composite driver won't complete the control transfer's
+        * data/status stages till delayed_status is zero.
+        */
+       int                             delayed_status;
+
+       /* protects deactivations and delayed_status counts*/
        spinlock_t                      lock;
 };