This patch adds some new gadget APIs that should help on
some hardware.  It doesn't implement them for any of the
controller drivers though:

   - usb_gadget_{connect,disconnect}() offering control
     over the D+ (or maybe D-) pullup so that the host
     can detect this USB peripheral.

   - usb_gadget_vbus_{connect,disconnect)() are for use
     by external transceiver (or GPIO) drivers to report
     to the controller driver that there's a host on the
     other end.

   - usb_gadget_vbus_draw() is for use both by such
     transceiver drivers and by gadget drivers, to control
     the current usage ... think "battery recharging".

The connect/disconnect patch is based on one provided by
Alex Sanks (thanks!) to help support a particular printer
driver better.  Basically, the user mode component of the
system needs to be active before it's OK to enumerate.
I changed his patch slightly so bind() can say "wait!".
Another use of these calls:  simplify gadgetfs, getting
rid of the need to explicitly list some controllers.

The pxa2xx platform_data scheme touches some of the same
issues (vbus and pullup), so maybe some handhelds.org folk
will see improvements that these APIs facilitate.

All of this starts to matter more on OTG-capable systems,
like some OMAP boards, where there's additional fun like
modes where system supplying VBUS power is acting for
a while in a peripheral role ... :)

I'm circulating this patch for feedback, not yet for
inclusion in standard kernels.  But I'll put a version
of it into my gadget-2.6 tree.

- Dave

--- linux-2.5/include/linux/usb_gadget.h        2004-04-14 18:26:44.000000000 -0700
+++ gadget-2.6/include/linux/usb_gadget.h       2004-06-11 09:52:59.519514536 -0700
@@ -453,7 +453,10 @@
 struct usb_gadget_ops {
        int     (*get_frame)(struct usb_gadget *);
        int     (*wakeup)(struct usb_gadget *);
-       int     (*set_selfpowered) (struct usb_gadget *, int value);
+       int     (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
+       int     (*vbus_session) (struct usb_gadget *, int is_active);
+       int     (*vbus_draw) (struct usb_gadget *, unsigned mA);
+       int     (*pullup) (struct usb_gadget *, int is_on);
        int     (*ioctl)(struct usb_gadget *,
                                unsigned code, unsigned long param);
 };
@@ -568,6 +578,107 @@
        return gadget->ops->set_selfpowered (gadget, 0);
 }
 
+/**
+ * usb_gadget_vbus_connect - Notify controller that VBUS is powered
+ * @gadget:The device which now has VBUS power.
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session starting.  Common responses include
+ * resuming the controller, activating the D+ (or D-) pullup to let the
+ * host detect that a USB device is attached, and starting to draw power
+ * (8mA or possibly more, especially after SET_CONFIGURATION).
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_connect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 1);
+}
+
+/**
+ * usb_gadget_vbus_draw - constrain controller's VBUS power usage
+ * @gadget:The device whose VBUS usage is being described
+ * @mA:How much current to draw, in milliAmperes.  This should be twice
+ *     the value listed in the configuration descriptor bMaxPower field.
+ *
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume.  For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+       if (!gadget->ops->vbus_draw)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_draw (gadget, mA);
+}
+
+/**
+ * usb_gadget_vbus_disconnect - notify controller about VBUS session end
+ * @gadget:the device whose VBUS supply is being described
+ *
+ * This call is used by a driver for an external transceiver (or GPIO)
+ * that detects a VBUS power session ending.  Common responses include
+ * reversing everything done in usb_gadget_vbus_connect().
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
+{
+       if (!gadget->ops->vbus_session)
+               return -EOPNOTSUPP;
+       return gadget->ops->vbus_session (gadget, 0);
+}
+
+/**
+ * usb_gadget_connect - connect to the USB host
+ * @gadget:the peripheral being connected
+ *
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).  This pullup always enabled unless
+ * usb_gadget_disconnect() has been used to disable it.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_connect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 1);
+}
+
+/**
+ * usb_gadget_disconnect - disconnect from the USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * This routine may be used during the gadget driver bind() call to prevent
+ * the peripheral from ever being visible to the USB host, unless later
+ * usb_gadget_connect() is called.  For example, user mode components may
+ * need to be activated before the system can talk to hosts.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_disconnect (struct usb_gadget *gadget)
+{
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+       return gadget->ops->pullup (gadget, 0);
+}
+
+
 
 /*-------------------------------------------------------------------------*/
 

Reply via email to