Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 248844
b: refs/heads/master
c: 1b9ba00
h: refs/heads/master
v: v3
  • Loading branch information
Roger Quadros authored and Greg Kroah-Hartman committed May 10, 2011
1 parent c4697a6 commit 6d53d30
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8eadef1526886db2a471c432d2c3d154de46f5c6
refs/heads/master: 1b9ba000177ee47bcc5b44c7c34e48e735f5f9b1
62 changes: 61 additions & 1 deletion trunk/drivers/usb/gadget/composite.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,12 +461,23 @@ static int set_config(struct usb_composite_dev *cdev,
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;
}

Expand Down Expand Up @@ -895,6 +906,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
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))
Expand Down Expand Up @@ -958,7 +977,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}

/* 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);
Expand All @@ -967,6 +986,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
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:
Expand Down Expand Up @@ -1289,3 +1312,40 @@ void usb_composite_unregister(struct usb_composite_driver *driver)
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);
}

16 changes: 15 additions & 1 deletion trunk/include/linux/usb/composite.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
#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;

Expand Down Expand Up @@ -285,6 +293,7 @@ struct usb_composite_driver {
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);


/**
Expand Down Expand Up @@ -342,7 +351,12 @@ struct usb_composite_dev {
*/
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;
};

Expand Down

0 comments on commit 6d53d30

Please sign in to comment.