aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/composite.c
diff options
context:
space:
mode:
authorRoger Quadros <roger.quadros@nokia.com>2011-05-09 06:08:06 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-10 17:14:57 -0400
commit1b9ba000177ee47bcc5b44c7c34e48e735f5f9b1 (patch)
tree8faa82465181387e1962786de7805912a8bacb66 /drivers/usb/gadget/composite.c
parent8eadef1526886db2a471c432d2c3d154de46f5c6 (diff)
usb: gadget: composite: Allow function drivers to pause control transfers
Some USB function drivers (e.g. f_mass_storage.c) need to delay or defer the data/status stages of standard control requests like SET_CONFIGURATION or SET_INTERFACE till they are done with their bookkeeping and are actually ready for accepting new commands to their interface. They can now achieve this functionality by returning USB_GADGET_DELAYED_STATUS in their setup handlers (e.g. set_alt()). The composite framework will then defer completion of the control transfer by not completing the data/status stages. This ensures that the host does not send new packets to the interface till the function driver is ready to take them. When the function driver that requested for USB_GADGET_DELAYED_STATUS is done with its bookkeeping, it should signal the composite framework to continue with the data/status stages of the control transfer. It can do so by invoking the new API usb_composite_setup_continue(). This is where the control transfer's data/status stages are completed and host can initiate new transfers. The DELAYED_STATUS mechanism is currently only supported if the expected data phase is 0 bytes (i.e. w_length == 0). Since SET_CONFIGURATION and SET_INTERFACE are the only cases that will use this mechanism, this is not a limitation. Signed-off-by: Roger Quadros <roger.quadros@nokia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/gadget/composite.c')
-rw-r--r--drivers/usb/gadget/composite.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 82314ed2250..5cbb1a41c22 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -461,12 +461,23 @@ static int set_config(struct usb_composite_dev *cdev,
461 reset_config(cdev); 461 reset_config(cdev);
462 goto done; 462 goto done;
463 } 463 }
464
465 if (result == USB_GADGET_DELAYED_STATUS) {
466 DBG(cdev,
467 "%s: interface %d (%s) requested delayed status\n",
468 __func__, tmp, f->name);
469 cdev->delayed_status++;
470 DBG(cdev, "delayed_status count %d\n",
471 cdev->delayed_status);
472 }
464 } 473 }
465 474
466 /* when we return, be sure our power usage is valid */ 475 /* when we return, be sure our power usage is valid */
467 power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; 476 power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
468done: 477done:
469 usb_gadget_vbus_draw(gadget, power); 478 usb_gadget_vbus_draw(gadget, power);
479 if (result >= 0 && cdev->delayed_status)
480 result = USB_GADGET_DELAYED_STATUS;
470 return result; 481 return result;
471} 482}
472 483
@@ -895,6 +906,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
895 if (w_value && !f->set_alt) 906 if (w_value && !f->set_alt)
896 break; 907 break;
897 value = f->set_alt(f, w_index, w_value); 908 value = f->set_alt(f, w_index, w_value);
909 if (value == USB_GADGET_DELAYED_STATUS) {
910 DBG(cdev,
911 "%s: interface %d (%s) requested delayed status\n",
912 __func__, intf, f->name);
913 cdev->delayed_status++;
914 DBG(cdev, "delayed_status count %d\n",
915 cdev->delayed_status);
916 }
898 break; 917 break;
899 case USB_REQ_GET_INTERFACE: 918 case USB_REQ_GET_INTERFACE:
900 if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) 919 if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -958,7 +977,7 @@ unknown:
958 } 977 }
959 978
960 /* respond with data transfer before status phase? */ 979 /* respond with data transfer before status phase? */
961 if (value >= 0) { 980 if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
962 req->length = value; 981 req->length = value;
963 req->zero = value < w_length; 982 req->zero = value < w_length;
964 value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); 983 value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
@@ -967,6 +986,10 @@ unknown:
967 req->status = 0; 986 req->status = 0;
968 composite_setup_complete(gadget->ep0, req); 987 composite_setup_complete(gadget->ep0, req);
969 } 988 }
989 } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
990 WARN(cdev,
991 "%s: Delayed status not supported for w_length != 0",
992 __func__);
970 } 993 }
971 994
972done: 995done:
@@ -1289,3 +1312,40 @@ void usb_composite_unregister(struct usb_composite_driver *driver)
1289 return; 1312 return;
1290 usb_gadget_unregister_driver(&composite_driver); 1313 usb_gadget_unregister_driver(&composite_driver);
1291} 1314}
1315
1316/**
1317 * usb_composite_setup_continue() - Continue with the control transfer
1318 * @cdev: the composite device who's control transfer was kept waiting
1319 *
1320 * This function must be called by the USB function driver to continue
1321 * with the control transfer's data/status stage in case it had requested to
1322 * delay the data/status stages. A USB function's setup handler (e.g. set_alt())
1323 * can request the composite framework to delay the setup request's data/status
1324 * stages by returning USB_GADGET_DELAYED_STATUS.
1325 */
1326void usb_composite_setup_continue(struct usb_composite_dev *cdev)
1327{
1328 int value;
1329 struct usb_request *req = cdev->req;
1330 unsigned long flags;
1331
1332 DBG(cdev, "%s\n", __func__);
1333 spin_lock_irqsave(&cdev->lock, flags);
1334
1335 if (cdev->delayed_status == 0) {
1336 WARN(cdev, "%s: Unexpected call\n", __func__);
1337
1338 } else if (--cdev->delayed_status == 0) {
1339 DBG(cdev, "%s: Completing delayed status\n", __func__);
1340 req->length = 0;
1341 value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
1342 if (value < 0) {
1343 DBG(cdev, "ep_queue --> %d\n", value);
1344 req->status = 0;
1345 composite_setup_complete(cdev->gadget->ep0, req);
1346 }
1347 }
1348
1349 spin_unlock_irqrestore(&cdev->lock, flags);
1350}
1351