From e769d72a81f65d29e0d371e11738545aa3574bae Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 18 Aug 2008 17:38:22 -0700 Subject: [PATCH] --- yaml --- r: 115747 b: refs/heads/master c: 60beed95e38793c0baff7f94433c1f639d8d5efd h: refs/heads/master i: 115745: e775568e9a2815c653b696be9c784f1c5206f9ce 115743: 73b10d20db2389c77494b6cad65e9141e4a10972 v: v3 --- [refs] | 2 +- trunk/drivers/usb/gadget/composite.c | 64 ++++++++++++++++++++++++++++ trunk/include/linux/usb/composite.h | 11 ++++- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index 616742ae8a5c..969086b79a26 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 8066134ff8140ae9d8d15cdad3fc6c60c2a8a4e5 +refs/heads/master: 60beed95e38793c0baff7f94433c1f639d8d5efd diff --git a/trunk/drivers/usb/gadget/composite.c b/trunk/drivers/usb/gadget/composite.c index 85c876c1f150..f79fdb839cb8 100644 --- a/trunk/drivers/usb/gadget/composite.c +++ b/trunk/drivers/usb/gadget/composite.c @@ -127,6 +127,70 @@ int __init usb_add_function(struct usb_configuration *config, return value; } +/** + * usb_function_deactivate - prevent function and gadget enumeration + * @function: the function that isn't yet ready to respond + * + * Blocks response of the gadget driver to host enumeration by + * preventing the data line pullup from being activated. This is + * normally called during @bind() processing to change from the + * initial "ready to respond" state, or when a required resource + * becomes available. + * + * For example, drivers that serve as a passthrough to a userspace + * daemon can block enumeration unless that daemon (such as an OBEX, + * MTP, or print server) is ready to handle host requests. + * + * Not all systems support software control of their USB peripheral + * data pullups. + * + * Returns zero on success, else negative errno. + */ +int usb_function_deactivate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + int status = 0; + + spin_lock(&cdev->lock); + + if (cdev->deactivations == 0) + status = usb_gadget_disconnect(cdev->gadget); + if (status == 0) + cdev->deactivations++; + + spin_unlock(&cdev->lock); + return status; +} + +/** + * usb_function_activate - allow function and gadget enumeration + * @function: function on which usb_function_activate() was called + * + * Reverses effect of usb_function_deactivate(). If no more functions + * are delaying their activation, the gadget driver will respond to + * host enumeration procedures. + * + * Returns zero on success, else negative errno. + */ +int usb_function_activate(struct usb_function *function) +{ + struct usb_composite_dev *cdev = function->config->cdev; + int status = 0; + + spin_lock(&cdev->lock); + + if (WARN_ON(cdev->deactivations == 0)) + status = -EINVAL; + else { + cdev->deactivations--; + if (cdev->deactivations == 0) + status = usb_gadget_connect(cdev->gadget); + } + + spin_unlock(&cdev->lock); + return status; +} + /** * usb_interface_id() - allocate an unused interface ID * @config: configuration associated with the interface diff --git a/trunk/include/linux/usb/composite.h b/trunk/include/linux/usb/composite.h index c932390c6da0..935c380ffe47 100644 --- a/trunk/include/linux/usb/composite.h +++ b/trunk/include/linux/usb/composite.h @@ -130,6 +130,9 @@ struct usb_function { int usb_add_function(struct usb_configuration *, struct usb_function *); +int usb_function_deactivate(struct usb_function *); +int usb_function_activate(struct usb_function *); + int usb_interface_id(struct usb_configuration *, struct usb_function *); /** @@ -316,9 +319,13 @@ struct usb_composite_dev { struct usb_composite_driver *driver; u8 next_string_id; - spinlock_t lock; + /* the gadget driver won't enable the data pullup + * while the deactivation count is nonzero. + */ + unsigned deactivations; - /* REVISIT use and existence of lock ... */ + /* protects at least deactivation count */ + spinlock_t lock; }; extern int usb_string_id(struct usb_composite_dev *c);