[RFC/PATCH 1/2] usb: gadget: let gadgets control pullup on their own

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is useful on gadgets that depend on userland
daemons to function properly. We can delay connection
to the host until userland is ready.

Signed-off-by: Felipe Balbi <balbi@xxxxxx>
---
 drivers/usb/gadget/composite.c |  3 ++-
 drivers/usb/gadget/udc-core.c  | 26 ++++++++++++++++++++++++--
 include/linux/usb/composite.h  |  4 ++++
 include/linux/usb/gadget.h     |  3 +++
 4 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7c821de..790ccf2 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1784,8 +1784,9 @@ int usb_composite_probe(struct usb_composite_driver *driver)
 		driver->name = "composite";
 
 	driver->gadget_driver = composite_driver_template;
-	gadget_driver = &driver->gadget_driver;
 
+	gadget_driver = &driver->gadget_driver;
+	gadget_driver->controls_pullups = driver->controls_pullups;
 	gadget_driver->function =  (char *) driver->name;
 	gadget_driver->driver.name = driver->name;
 	gadget_driver->max_speed = driver->max_speed;
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 8a1eeb2..c0f4fca 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -235,7 +235,18 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-	usb_gadget_disconnect(udc->gadget);
+	/*
+	 * NOTICE: if gadget driver wants to control
+	 * pullup, it needs to make sure that when
+	 * user tries to rmmod the gadget driver, it
+	 * will disconnect the pullups before returning
+	 * from its ->unbind() method.
+	 *
+	 * We are truly trusting the gadget driver here.
+	 */
+	if (!udc->driver->controls_pullups)
+		usb_gadget_disconnect(udc->gadget);
+
 	udc->driver->disconnect(udc->gadget);
 	udc->driver->unbind(udc->gadget);
 	usb_gadget_udc_stop(udc->gadget, udc->driver);
@@ -300,7 +311,18 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
 		driver->unbind(udc->gadget);
 		goto err1;
 	}
-	usb_gadget_connect(udc->gadget);
+
+	/*
+	 * NOTICE: if gadget driver wants to control
+	 * pullups, it needs to make sure its calls
+	 * to usb_function_activate() and
+	 * usb_function_deactivate() are balanced,
+	 * otherwise gadget_driver will never enumerate.
+	 *
+	 * We are truly trusting the gadget driver here.
+	 */
+	if (!driver->controls_pullups)
+		usb_gadget_connect(udc->gadget);
 
 	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 	return 0;
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 3c671c1..7ae797c 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -157,6 +157,7 @@ struct usb_function {
 	int			(*get_status)(struct usb_function *);
 	int			(*func_suspend)(struct usb_function *,
 						u8 suspend_opt);
+
 	/* private: */
 	/* internals */
 	struct list_head		list;
@@ -279,6 +280,8 @@ enum {
  * @max_speed: Highest speed the driver supports.
  * @needs_serial: set to 1 if the gadget needs userspace to provide
  * 	a serial number.  If one is not provided, warning will be printed.
+ * @controls_pullups: this driver will control pullup and udc-core shouldn't
+ *	enable it by default
  * @bind: (REQUIRED) Used to allocate resources that are shared across the
  *	whole device, such as string IDs, and add its configurations using
  *	@usb_add_config(). This may fail by returning a negative errno
@@ -308,6 +311,7 @@ struct usb_composite_driver {
 	struct usb_gadget_strings		**strings;
 	enum usb_device_speed			max_speed;
 	unsigned		needs_serial:1;
+	unsigned		controls_pullups:1;
 
 	int			(*bind)(struct usb_composite_dev *cdev);
 	int			(*unbind)(struct usb_composite_dev *);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 32b734d..87971fa 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -774,6 +774,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
  * @suspend: Invoked on USB suspend.  May be called in_interrupt.
  * @resume: Invoked on USB resume.  May be called in_interrupt.
  * @driver: Driver model state for this driver.
+ * @controls_pullups: tells udc-core to not enable pullups by default
  *
  * Devices are disabled till a gadget driver successfully bind()s, which
  * means the driver will handle setup() requests needed to enumerate (and
@@ -833,6 +834,8 @@ struct usb_gadget_driver {
 
 	/* FIXME support safe rmmod */
 	struct device_driver	driver;
+
+	unsigned		controls_pullups:1;
 };
 
 
-- 
1.8.1.rc1.5.g7e0651a

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux