]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'usb-for-v4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Aug 2015 23:41:11 +0000 (16:41 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Aug 2015 23:41:11 +0000 (16:41 -0700)
Felipe writes:

usb: patches for v4.3 merge window

New support for Allwinne SoC on the MUSB driver has been added to the list of
glue layers. MUSB also got support for building all DMA engines in one binary;
this will be great for distros.

DWC3 now has no trace of dev_dbg()/dev_vdbg() usage. We will rely solely on
tracing to debug DWC3. There was also a fix for memory corruption with EP0 when
maxpacket size transfers are > 512 bytes.

Robert's EP capabilities flags is making EP selection a lot simpler. UDCs are
now required to set these flags up when adding endpoints to the framework.

Other than these, we have the usual set of miscelaneous cleanups and minor
fixes.

Signed-off-by: Felipe Balbi <balbi@ti.com>
113 files changed:
Documentation/ABI/testing/configfs-usb-gadget-loopback
Documentation/ABI/testing/configfs-usb-gadget-sourcesink
Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/generic.txt
Documentation/devicetree/bindings/usb/msm-hsusb.txt
Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt [new file with mode: 0644]
Documentation/usb/gadget-testing.txt
drivers/staging/emxx_udc/emxx_udc.c
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/core.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/udc.c
drivers/usb/common/common.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-keystone.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/dwc3-st.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/composite.c
drivers/usb/gadget/config.c
drivers/usb/gadget/configfs.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/function/f_acm.c
drivers/usb/gadget/function/f_ecm.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_loopback.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_mass_storage.h
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_ncm.c
drivers/usb/gadget/function/f_obex.c
drivers/usb/gadget/function/f_printer.c
drivers/usb/gadget/function/f_serial.c
drivers/usb/gadget/function/f_sourcesink.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/storage_common.h
drivers/usb/gadget/function/u_ether.h
drivers/usb/gadget/function/u_uac1.h
drivers/usb/gadget/legacy/Kconfig
drivers/usb/gadget/legacy/acm_ms.c
drivers/usb/gadget/legacy/audio.c
drivers/usb/gadget/legacy/cdc2.c
drivers/usb/gadget/legacy/dbgp.c
drivers/usb/gadget/legacy/ether.c
drivers/usb/gadget/legacy/g_ffs.c
drivers/usb/gadget/legacy/gmidi.c
drivers/usb/gadget/legacy/hid.c
drivers/usb/gadget/legacy/mass_storage.c
drivers/usb/gadget/legacy/multi.c
drivers/usb/gadget/legacy/ncm.c
drivers/usb/gadget/legacy/nokia.c
drivers/usb/gadget/legacy/printer.c
drivers/usb/gadget/legacy/serial.c
drivers/usb/gadget/legacy/zero.c
drivers/usb/gadget/udc/amd5536udc.c
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/bcm63xx_udc.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/fsl_qe_udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/gadget_chips.h [deleted file]
drivers/usb/gadget/udc/goku_udc.c
drivers/usb/gadget/udc/gr_udc.c
drivers/usb/gadget/udc/lpc32xx_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/mv_u3d_core.c
drivers/usb/gadget/udc/mv_udc_core.c
drivers/usb/gadget/udc/net2272.c
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/pch_udc.c
drivers/usb/gadget/udc/pxa25x_udc.c
drivers/usb/gadget/udc/pxa27x_udc.c
drivers/usb/gadget/udc/pxa27x_udc.h
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/gadget/udc/s3c-hsudc.c
drivers/usb/gadget/udc/s3c2410_udc.c
drivers/usb/gadget/udc/udc-core.c
drivers/usb/gadget/udc/udc-xilinx.c
drivers/usb/isp1760/isp1760-udc.c
drivers/usb/musb/Kconfig
drivers/usb/musb/Makefile
drivers/usb/musb/musb_cppi41.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/sunxi.c [new file with mode: 0644]
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/phy-generic.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy-omap-otg.c
drivers/usb/phy/phy-qcom-8x16-usb.c [new file with mode: 0644]
drivers/usb/phy/phy-tahvo.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/mod_gadget.c
include/linux/usb/chipidea.h
include/linux/usb/composite.h
include/linux/usb/gadget.h
include/linux/usb/msm_hsusb.h
include/linux/usb/of.h
include/linux/usb/otg.h
include/uapi/linux/usb/ch9.h

index 9aae5bfb990887a6ad3faee29830d1603a7ecb19..06beefbcf061a76f2dc1deb5696649eda35c1aaa 100644 (file)
@@ -5,4 +5,4 @@ Description:
                The attributes:
 
                qlen            - depth of loopback queue
-               bulk_buflen     - buffer length
+               buflen          - buffer length
index 29477c319f61bf16f1259962237f4b3f0a7e6287..bc7ff731aa0cf839fdc88e60e4934526387adc6a 100644 (file)
@@ -9,4 +9,4 @@ Description:
                isoc_maxpacket  - 0 - 1023 (fs), 0 - 1024 (hs/ss)
                isoc_mult       - 0..2 (hs/ss only)
                isoc_maxburst   - 0..15 (ss only)
-               qlen            - buffer length
+               buflen          - buffer length
diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
new file mode 100644 (file)
index 0000000..862cd7c
--- /dev/null
@@ -0,0 +1,29 @@
+Allwinner sun4i A10 musb DRC/OTG controller
+-------------------------------------------
+
+Required properties:
+ - compatible      : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb"
+                     or "allwinner,sun8i-a33-musb"
+ - reg             : mmio address range of the musb controller
+ - clocks          : clock specifier for the musb controller ahb gate clock
+ - reset           : reset specifier for the ahb reset (A31 and newer only)
+ - interrupts      : interrupt to which the musb controller is connected
+ - interrupt-names : must be "mc"
+ - phys            : phy specifier for the otg phy
+ - phy-names       : must be "usb"
+ - dr_mode         : Dual-Role mode must be "host" or "otg"
+ - extcon          : extcon specifier for the otg phy
+
+Example:
+
+       usb_otg: usb@01c13000 {
+               compatible = "allwinner,sun4i-a10-musb";
+               reg = <0x01c13000 0x0400>;
+               clocks = <&ahb_gates 0>;
+               interrupts = <38>;
+               interrupt-names = "mc";
+               phys = <&usbphy 0>;
+               phy-names = "usb";
+               extcon = <&usbphy 0>;
+               status = "disabled";
+       };
index 477d5bb5e51cf9089e900650279373fe89e37812..bba825711873f30d47b6cafa1ee941df57d73c7e 100644 (file)
@@ -11,6 +11,19 @@ Optional properties:
                        "peripheral" and "otg". In case this attribute isn't
                        passed via DT, USB DRD controllers should default to
                        OTG.
+ - otg-rev: tells usb driver the release number of the OTG and EH supplement
+                       with which the device and its descriptors are compliant,
+                       in binary-coded decimal (i.e. 2.0 is 0200H). This
+                       property is used if any real OTG features(HNP/SRP/ADP)
+                       is enabled, if ADP is required, otg-rev should be
+                       0x0200 or above.
+ - hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP
+                       is the basic function of real OTG except you want it
+                       to be a srp-capable only B device.
+ - srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is
+                       optional for OTG device.
+ - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is
+                       optional for OTG device.
 
 This is an attribute to a USB controller such as:
 
@@ -21,4 +34,6 @@ dwc3@4a030000 {
        usb-phy = <&usb2_phy>, <&usb3,phy>;
        maximum-speed = "super-speed";
        dr_mode = "otg";
+       otg-rev = <0x0200>;
+       adp-disable;
 };
index bd8d9e7530290a91ec161f68f305c180981bf8fe..8654a3ec23e481127260d36706a5611b9b49576a 100644 (file)
@@ -52,6 +52,10 @@ Required properties:
 Optional properties:
 - dr_mode:      One of "host", "peripheral" or "otg". Defaults to "otg"
 
+- switch-gpio:  A phandle + gpio-specifier pair. Some boards are using Dual
+                SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex
+                D+/D- USB lines between connectors.
+
 - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
                 Mode Eye Diagram test. Start address at which these values will be
                 written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
diff --git a/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt b/Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt
new file mode 100644 (file)
index 0000000..2cb2168
--- /dev/null
@@ -0,0 +1,76 @@
+Qualcomm's APQ8016/MSM8916 USB transceiver controller
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,usb-8x16-phy".
+
+- reg:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: USB PHY base address and length of the register map
+
+- clocks:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: See clock-bindings.txt section "consumers". List of
+                two clock specifiers for interface and core controller
+                clocks.
+
+- clock-names:
+    Usage: required
+    Value type: <string>
+    Definition: Must contain "iface" and "core" strings.
+
+- vddcx-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator VDCCX supply node.
+
+- v1p8-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator 1.8V supply node.
+
+- v3p3-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: phandle to the regulator 3.3V supply node.
+
+- resets:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: See reset.txt section "consumers". PHY reset specifier.
+
+- reset-names:
+    Usage: required
+    Value type: <string>
+    Definition: Must contain "phy" string.
+
+- switch-gpio:
+    Usage: optional
+    Value type: <prop-encoded-array>
+    Definition: Some boards are using Dual SPDT USB Switch, witch is
+                controlled by GPIO to de/multiplex D+/D- USB lines
+                between connectors.
+
+Example:
+       usb_phy: phy@78d9000 {
+               compatible = "qcom,usb-8x16-phy";
+               reg = <0x78d9000 0x400>;
+
+               vddcx-supply = <&pm8916_s1_corner>;
+               v1p8-supply = <&pm8916_l7>;
+               v3p3-supply = <&pm8916_l13>;
+
+               clocks = <&gcc GCC_USB_HS_AHB_CLK>,
+                            <&gcc GCC_USB_HS_SYSTEM_CLK>;
+               clock-names = "iface", "core";
+
+               resets = <&gcc GCC_USB2A_PHY_BCR>;
+               reset-names = "phy";
+
+               // D+/D- lines: 1 - Routed to HUB, 0 - Device connector
+               switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>;
+       };
+
index 592678009c15c393d59b9ce190b6a96057486160..b24d3ef89166bc16f228e97aceb6f300063edc2a 100644 (file)
@@ -237,9 +237,7 @@ Testing the LOOPBACK function
 -----------------------------
 
 device: run the gadget
-host: test-usb
-
-http://www.linux-usb.org/usbtest/testusb.c
+host: test-usb (tools/usb/testusb.c)
 
 8. MASS STORAGE function
 ========================
@@ -586,9 +584,8 @@ Testing the SOURCESINK function
 -------------------------------
 
 device: run the gadget
-host: test-usb
+host: test-usb (tools/usb/testusb.c)
 
-http://www.linux-usb.org/usbtest/testusb.c
 
 16. UAC1 function
 =================
index 4178d96f94cf152076bf6a62fdec5cd08c6bc389..b6b76ff09657134ee55f07bcce621cb97c1450c4 100644 (file)
@@ -3153,36 +3153,46 @@ static const struct usb_gadget_ops nbu2ss_gadget_ops = {
        .ioctl                  = nbu2ss_gad_ioctl,
 };
 
-static const char g_ep0_name[] = "ep0";
-static const char g_ep1_name[] = "ep1-bulk";
-static const char g_ep2_name[] = "ep2-bulk";
-static const char g_ep3_name[] = "ep3in-int";
-static const char g_ep4_name[] = "ep4-iso";
-static const char g_ep5_name[] = "ep5-iso";
-static const char g_ep6_name[] = "ep6-bulk";
-static const char g_ep7_name[] = "ep7-bulk";
-static const char g_ep8_name[] = "ep8in-int";
-static const char g_ep9_name[] = "ep9-iso";
-static const char g_epa_name[] = "epa-iso";
-static const char g_epb_name[] = "epb-bulk";
-static const char g_epc_name[] = "epc-nulk";
-static const char g_epd_name[] = "epdin-int";
-
-static const char *gp_ep_name[NUM_ENDPOINTS] = {
-       g_ep0_name,
-       g_ep1_name,
-       g_ep2_name,
-       g_ep3_name,
-       g_ep4_name,
-       g_ep5_name,
-       g_ep6_name,
-       g_ep7_name,
-       g_ep8_name,
-       g_ep9_name,
-       g_epa_name,
-       g_epb_name,
-       g_epc_name,
-       g_epd_name,
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} ep_info[NUM_ENDPOINTS] = {
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
+
+       EP_INFO("ep0",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep1-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep2-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep3in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep4-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep5-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep6-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep7-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep8in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep9-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("epa-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("epb-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("epc-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("epdin-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+
+#undef EP_INFO
 };
 
 /*-------------------------------------------------------------------------*/
@@ -3200,10 +3210,12 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
                ep->desc = NULL;
 
                ep->ep.driver_data = NULL;
-               ep->ep.name = gp_ep_name[i];
+               ep->ep.name = ep_info[i].name;
+               ep->ep.caps = ep_info[i].caps;
                ep->ep.ops = &nbu2ss_ep_ops;
 
-               ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
+               usb_ep_set_maxpacket_limit(&ep->ep,
+                               i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
 
                list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
                INIT_LIST_HEAD(&ep->queue);
index 6d6200e37b71e02b0e0d4a67cdd35f160f61de3b..f243f0b431c33e40e5b8130901dbb3cae9daf2e4 100644 (file)
@@ -406,8 +406,11 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
 static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci)
 {
 #ifdef CONFIG_USB_OTG_FSM
+       struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
+
        return ci->is_otg && ci->roles[CI_ROLE_HOST] &&
-                                       ci->roles[CI_ROLE_GADGET];
+               ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support ||
+               otg_caps->hnp_support || otg_caps->adp_support);
 #else
        return false;
 #endif
index 3ad48e1c0c57e1722311c8393ad3bd21712fa1e7..ab6212e888e1e55d7bc4655e2be474aeb308371f 100644 (file)
@@ -560,6 +560,8 @@ static irqreturn_t ci_irq(int irq, void *data)
 static int ci_get_platdata(struct device *dev,
                struct ci_hdrc_platform_data *platdata)
 {
+       int ret;
+
        if (!platdata->phy_mode)
                platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
 
@@ -588,6 +590,19 @@ static int ci_get_platdata(struct device *dev,
                                of_usb_host_tpl_support(dev->of_node);
        }
 
+       if (platdata->dr_mode == USB_DR_MODE_OTG) {
+               /* We can support HNP and SRP of OTG 2.0 */
+               platdata->ci_otg_caps.otg_rev = 0x0200;
+               platdata->ci_otg_caps.hnp_support = true;
+               platdata->ci_otg_caps.srp_support = true;
+
+               /* Update otg capabilities by DT properties */
+               ret = of_usb_update_otg_caps(dev->of_node,
+                                       &platdata->ci_otg_caps);
+               if (ret)
+                       return ret;
+       }
+
        if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
                platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
 
index 5b7061a331038d36ad20b7ec3c05b2ab1f8b3efc..3869c6d755156cf5fc00c3cee26e5f39a9a3e92f 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/usb/phy.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg-fsm.h>
+#include <linux/usb/chipidea.h>
 
 #include "ci.h"
 #include "udc.h"
index 764f668d45a9bb6ad4cde8ea0f4a8b0661dead86..c592b6f0fe217518d0633c60e3c91b159960a1d6 100644 (file)
@@ -1624,6 +1624,20 @@ static int init_eps(struct ci_hdrc *ci)
 
                        hwep->ep.name      = hwep->name;
                        hwep->ep.ops       = &usb_ep_ops;
+
+                       if (i == 0) {
+                               hwep->ep.caps.type_control = true;
+                       } else {
+                               hwep->ep.caps.type_iso = true;
+                               hwep->ep.caps.type_bulk = true;
+                               hwep->ep.caps.type_int = true;
+                       }
+
+                       if (j == TX)
+                               hwep->ep.caps.dir_in = true;
+                       else
+                               hwep->ep.caps.dir_out = true;
+
                        /*
                         * for ep0: maxP defined in desc, for other
                         * eps, maxP is set by epautoconfig() called
@@ -1827,6 +1841,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
 static int udc_start(struct ci_hdrc *ci)
 {
        struct device *dev = ci->dev;
+       struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
        int retval = 0;
 
        spin_lock_init(&ci->lock);
@@ -1834,8 +1849,12 @@ static int udc_start(struct ci_hdrc *ci)
        ci->gadget.ops          = &usb_gadget_ops;
        ci->gadget.speed        = USB_SPEED_UNKNOWN;
        ci->gadget.max_speed    = USB_SPEED_HIGH;
-       ci->gadget.is_otg       = ci->is_otg ? 1 : 0;
        ci->gadget.name         = ci->platdata->name;
+       ci->gadget.otg_caps     = otg_caps;
+
+       if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support ||
+                                               otg_caps->adp_support))
+               ci->gadget.is_otg = 1;
 
        INIT_LIST_HEAD(&ci->gadget.ep_list);
 
index b530fd403ffb2538fd2077515127414323f7012e..9e39286a4e5a1df458339cfbfd3076a3d08125ad 100644 (file)
@@ -154,6 +154,62 @@ bool of_usb_host_tpl_support(struct device_node *np)
        return false;
 }
 EXPORT_SYMBOL_GPL(of_usb_host_tpl_support);
+
+/**
+ * of_usb_update_otg_caps - to update usb otg capabilities according to
+ * the passed properties in DT.
+ * @np: Pointer to the given device_node
+ * @otg_caps: Pointer to the target usb_otg_caps to be set
+ *
+ * The function updates the otg capabilities
+ */
+int of_usb_update_otg_caps(struct device_node *np,
+                       struct usb_otg_caps *otg_caps)
+{
+       u32 otg_rev;
+
+       if (!otg_caps)
+               return -EINVAL;
+
+       if (!of_property_read_u32(np, "otg-rev", &otg_rev)) {
+               switch (otg_rev) {
+               case 0x0100:
+               case 0x0120:
+               case 0x0130:
+               case 0x0200:
+                       /* Choose the lesser one if it's already been set */
+                       if (otg_caps->otg_rev)
+                               otg_caps->otg_rev = min_t(u16, otg_rev,
+                                                       otg_caps->otg_rev);
+                       else
+                               otg_caps->otg_rev = otg_rev;
+                       break;
+               default:
+                       pr_err("%s: unsupported otg-rev: 0x%x\n",
+                                               np->full_name, otg_rev);
+                       return -EINVAL;
+               }
+       } else {
+               /*
+                * otg-rev is mandatory for otg properties, if not passed
+                * we set it to be 0 and assume it's a legacy otg device.
+                * Non-dt platform can set it afterwards.
+                */
+               otg_caps->otg_rev = 0;
+       }
+
+       if (of_find_property(np, "hnp-disable", NULL))
+               otg_caps->hnp_support = false;
+       if (of_find_property(np, "srp-disable", NULL))
+               otg_caps->srp_support = false;
+       if (of_find_property(np, "adp-disable", NULL) ||
+                               (otg_caps->otg_rev < 0x0200))
+               otg_caps->adp_support = false;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
+
 #endif
 
 MODULE_LICENSE("GPL");
index 4d47b7c092387fbbf672d9fb5b536ad94633a57c..3ee5b4c77a1f42eeecf1f222ab63e822b1530c9a 100644 (file)
@@ -2880,7 +2880,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
                epctl = readl(hs->regs + epreg);
 
                if (value) {
-                       epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
+                       epctl |= DXEPCTL_STALL | DXEPCTL_SNAK;
                        if (epctl & DXEPCTL_EPENA)
                                epctl |= DXEPCTL_EPDIS;
                } else {
@@ -3289,6 +3289,19 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
        usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);
        hs_ep->ep.ops = &s3c_hsotg_ep_ops;
 
+       if (epnum == 0) {
+               hs_ep->ep.caps.type_control = true;
+       } else {
+               hs_ep->ep.caps.type_iso = true;
+               hs_ep->ep.caps.type_bulk = true;
+               hs_ep->ep.caps.type_int = true;
+       }
+
+       if (dir_in)
+               hs_ep->ep.caps.dir_in = true;
+       else
+               hs_ep->ep.caps.dir_out = true;
+
        /*
         * if we're using dma, we need to set the next-endpoint pointer
         * to be something valid.
index dede32e809b624e9d477adb8b465f7149832d9ca..5a42c459040295a98c286ca993f9468a054682ca 100644 (file)
@@ -104,11 +104,4 @@ config USB_DWC3_QCOM
          Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside,
          say 'Y' or 'M' if you have one such device.
 
-comment "Debugging features"
-
-config USB_DWC3_DEBUG
-       bool "Enable Debugging Messages"
-       help
-         Say Y here to enable debugging messages on DWC3 Driver.
-
 endif
index c7076e37c4ed79a965eb502ebb6eaf31a1578824..acc951d46c278e2ccfb045ee1b09e438d2209229 100644 (file)
@@ -1,8 +1,6 @@
 # define_trace.h needs to know how to find our header
 CFLAGS_trace.o                         := -I$(src)
 
-ccflags-$(CONFIG_USB_DWC3_DEBUG)       := -DDEBUG
-
 obj-$(CONFIG_USB_DWC3)                 += dwc3.o
 
 dwc3-y                                 := core.o debug.o trace.o
index ff5773c66b84f22b8ffabe986546d2810d0a9864..064123e445664a5e23bb28ba48cfb1755ec7fb88 100644 (file)
@@ -455,8 +455,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                        reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
                        dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
                } else {
-                       dev_warn(dwc->dev, "HSPHY Interface not defined\n");
-
                        /* Relying on default value. */
                        if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
                                break;
index 7bd0a95b2815425d8e088dc39b83e7106177131f..dd5cb5577dcaf62d411fb9776e47a23d4a4dacf7 100644 (file)
@@ -145,7 +145,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
 
        exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk");
        if (IS_ERR(exynos->susp_clk)) {
-               dev_dbg(dev, "no suspend clk specified\n");
+               dev_info(dev, "no suspend clk specified\n");
                exynos->susp_clk = NULL;
        }
        clk_prepare_enable(exynos->susp_clk);
index fe3b9335a74e1d279da69b73e80897ca2a70d5f0..2be268d2423d9339679d38dc0a01982912424b96 100644 (file)
@@ -115,7 +115,7 @@ static int kdwc3_probe(struct platform_device *pdev)
 
        error = clk_prepare_enable(kdwc->clk);
        if (error < 0) {
-               dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n",
+               dev_err(kdwc->dev, "unable to enable usb clock, error %d\n",
                        error);
                return error;
        }
index 6b486a36863c08dd908df48375d819602672762b..a5a1b7c45743302b5ce9ae78bee9fead19b45de9 100644 (file)
@@ -128,8 +128,7 @@ struct dwc3_omap {
 
        u32                     dma_status:1;
 
-       struct extcon_specific_cable_nb extcon_vbus_dev;
-       struct extcon_specific_cable_nb extcon_id_dev;
+       struct extcon_dev       *edev;
        struct notifier_block   vbus_nb;
        struct notifier_block   id_nb;
 
@@ -225,12 +224,10 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
 
        switch (status) {
        case OMAP_DWC3_ID_GROUND:
-               dev_dbg(omap->dev, "ID GND\n");
-
                if (omap->vbus_reg) {
                        ret = regulator_enable(omap->vbus_reg);
                        if (ret) {
-                               dev_dbg(omap->dev, "regulator enable failed\n");
+                               dev_err(omap->dev, "regulator enable failed\n");
                                return;
                        }
                }
@@ -245,8 +242,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
                break;
 
        case OMAP_DWC3_VBUS_VALID:
-               dev_dbg(omap->dev, "VBUS Connect\n");
-
                val = dwc3_omap_read_utmi_ctrl(omap);
                val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
                val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG
@@ -261,8 +256,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
                        regulator_disable(omap->vbus_reg);
 
        case OMAP_DWC3_VBUS_OFF:
-               dev_dbg(omap->dev, "VBUS Disconnect\n");
-
                val = dwc3_omap_read_utmi_ctrl(omap);
                val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
                                | USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
@@ -273,7 +266,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
                break;
 
        default:
-               dev_dbg(omap->dev, "invalid state\n");
+               dev_WARN(omap->dev, "invalid state\n");
        }
 }
 
@@ -284,37 +277,8 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
 
        reg = dwc3_omap_read_irqmisc_status(omap);
 
-       if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
-               dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+       if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
                omap->dma_status = false;
-       }
-
-       if (reg & USBOTGSS_IRQMISC_OEVT)
-               dev_dbg(omap->dev, "OTG Event\n");
-
-       if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE)
-               dev_dbg(omap->dev, "DRVVBUS Rise\n");
-
-       if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE)
-               dev_dbg(omap->dev, "CHRGVBUS Rise\n");
-
-       if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE)
-               dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
-
-       if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE)
-               dev_dbg(omap->dev, "IDPULLUP Rise\n");
-
-       if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL)
-               dev_dbg(omap->dev, "DRVVBUS Fall\n");
-
-       if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL)
-               dev_dbg(omap->dev, "CHRGVBUS Fall\n");
-
-       if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL)
-               dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
-
-       if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL)
-               dev_dbg(omap->dev, "IDPULLUP Fall\n");
 
        dwc3_omap_write_irqmisc_status(omap, reg);
 
@@ -434,7 +398,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
                reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
                break;
        default:
-               dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
+               dev_WARN(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
        }
 
        dwc3_omap_write_utmi_ctrl(omap, reg);
@@ -454,23 +418,23 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
                }
 
                omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
-               ret = extcon_register_interest(&omap->extcon_vbus_dev,
-                                              edev->name, "USB",
-                                              &omap->vbus_nb);
+               ret = extcon_register_notifier(edev, EXTCON_USB,
+                                               &omap->vbus_nb);
                if (ret < 0)
                        dev_vdbg(omap->dev, "failed to register notifier for USB\n");
 
                omap->id_nb.notifier_call = dwc3_omap_id_notifier;
-               ret = extcon_register_interest(&omap->extcon_id_dev,
-                                              edev->name, "USB-HOST",
-                                              &omap->id_nb);
+               ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+                                               &omap->id_nb);
                if (ret < 0)
                        dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n");
 
-               if (extcon_get_cable_state(edev, "USB") == true)
+               if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
                        dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
-               if (extcon_get_cable_state(edev, "USB-HOST") == true)
+               if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true)
                        dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+
+               omap->edev = edev;
        }
 
        return 0;
@@ -565,11 +529,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
        return 0;
 
 err3:
-       if (omap->extcon_vbus_dev.edev)
-               extcon_unregister_interest(&omap->extcon_vbus_dev);
-       if (omap->extcon_id_dev.edev)
-               extcon_unregister_interest(&omap->extcon_id_dev);
-
+       extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
+       extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
 err2:
        dwc3_omap_disable_irqs(omap);
 
@@ -586,10 +547,8 @@ static int dwc3_omap_remove(struct platform_device *pdev)
 {
        struct dwc3_omap        *omap = platform_get_drvdata(pdev);
 
-       if (omap->extcon_vbus_dev.edev)
-               extcon_unregister_interest(&omap->extcon_vbus_dev);
-       if (omap->extcon_id_dev.edev)
-               extcon_unregister_interest(&omap->extcon_id_dev);
+       extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
+       extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
        dwc3_omap_disable_irqs(omap);
        of_platform_depopulate(omap->dev);
        pm_runtime_put_sync(&pdev->dev);
index 27e4fc896e9d93572c44acef20e25c6cea3a7d10..f62617999f3c7fb093ff09d18088560a6ecb003e 100644 (file)
@@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
                acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
                                          acpi_dwc3_byt_gpios);
 
-               /* These GPIOs will turn on the USB2 PHY */
-               gpio = gpiod_get(&pdev->dev, "cs");
-               if (!IS_ERR(gpio)) {
-                       gpiod_direction_output(gpio, 0);
-                       gpiod_set_value_cansleep(gpio, 1);
-                       gpiod_put(gpio);
-               }
+               /*
+                * These GPIOs will turn on the USB2 PHY. Note that we have to
+                * put the gpio descriptors again here because the phy driver
+                * might want to grab them, too.
+                */
+               gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+               if (IS_ERR(gpio))
+                       return PTR_ERR(gpio);
+
+               gpiod_set_value_cansleep(gpio, 1);
+               gpiod_put(gpio);
+
+               gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+               if (IS_ERR(gpio))
+                       return PTR_ERR(gpio);
 
-               gpio = gpiod_get(&pdev->dev, "reset");
-               if (!IS_ERR(gpio)) {
-                       gpiod_direction_output(gpio, 0);
+               if (gpio) {
                        gpiod_set_value_cansleep(gpio, 1);
                        gpiod_put(gpio);
                        usleep_range(10000, 11000);
index 8c2e8eec80c21d24540ebc939be6123c88cc985b..088026048f49f827a8bf5d87d15705140cedf22c 100644 (file)
@@ -48,13 +48,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
 
        qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface");
        if (IS_ERR(qdwc->iface_clk)) {
-               dev_dbg(qdwc->dev, "failed to get optional iface clock\n");
+               dev_info(qdwc->dev, "failed to get optional iface clock\n");
                qdwc->iface_clk = NULL;
        }
 
        qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep");
        if (IS_ERR(qdwc->sleep_clk)) {
-               dev_dbg(qdwc->dev, "failed to get optional sleep clock\n");
+               dev_info(qdwc->dev, "failed to get optional sleep clock\n");
                qdwc->sleep_clk = NULL;
        }
 
index 4a1a543deeda7c61b0b8378fc9a1e36553f44372..de4d52f62517a8ec744c0897e97edc516bd8643f 100644 (file)
@@ -135,8 +135,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
                        | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
 
                val |= USB3_DEVICE_NOT_HOST;
-
-               dev_dbg(dwc3_data->dev, "Configuring as Device\n");
                break;
 
        case USB_DR_MODE_HOST:
@@ -154,8 +152,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
                 */
 
                val |= USB3_DELAY_VBUSVALID;
-
-               dev_dbg(dwc3_data->dev, "Configuring as Host\n");
                break;
 
        default:
index 69e769c35cf5dc798fb34a6924c19726690592a2..5320e939e0902647edb21a5e55d7e537c1b03b33 100644 (file)
@@ -56,7 +56,7 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 }
 
 static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
-               u32 len, u32 type)
+               u32 len, u32 type, bool chain)
 {
        struct dwc3_gadget_ep_cmd_params params;
        struct dwc3_trb                 *trb;
@@ -70,7 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
                return 0;
        }
 
-       trb = dwc->ep0_trb;
+       trb = &dwc->ep0_trb[dep->free_slot];
+
+       if (chain)
+               dep->free_slot++;
 
        trb->bpl = lower_32_bits(buf_dma);
        trb->bph = upper_32_bits(buf_dma);
@@ -78,10 +81,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
        trb->ctrl = type;
 
        trb->ctrl |= (DWC3_TRB_CTRL_HWO
-                       | DWC3_TRB_CTRL_LST
-                       | DWC3_TRB_CTRL_IOC
                        | DWC3_TRB_CTRL_ISP_IMI);
 
+       if (chain)
+               trb->ctrl |= DWC3_TRB_CTRL_CHN;
+       else
+               trb->ctrl |= (DWC3_TRB_CTRL_IOC
+                               | DWC3_TRB_CTRL_LST);
+
+       if (chain)
+               return 0;
+
        memset(&params, 0, sizeof(params));
        params.param0 = upper_32_bits(dwc->ep0_trb_addr);
        params.param1 = lower_32_bits(dwc->ep0_trb_addr);
@@ -302,7 +312,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
        int                             ret;
 
        ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
-                       DWC3_TRBCTL_CONTROL_SETUP);
+                       DWC3_TRBCTL_CONTROL_SETUP, false);
        WARN_ON(ret < 0);
 }
 
@@ -783,7 +793,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        struct usb_request      *ur;
        struct dwc3_trb         *trb;
        struct dwc3_ep          *ep0;
-       u32                     transferred;
+       unsigned                transfer_size = 0;
+       unsigned                maxp;
+       unsigned                remaining_ur_length;
+       void                    *buf;
+       u32                     transferred = 0;
        u32                     status;
        u32                     length;
        u8                      epnum;
@@ -812,17 +826,37 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        }
 
        ur = &r->request;
+       buf = ur->buf;
+       remaining_ur_length = ur->length;
 
        length = trb->size & DWC3_TRB_SIZE_MASK;
 
+       maxp = ep0->endpoint.maxpacket;
+
        if (dwc->ep0_bounced) {
-               unsigned transfer_size = ur->length;
-               unsigned maxp = ep0->endpoint.maxpacket;
+               /*
+                * Handle the first TRB before handling the bounce buffer if
+                * the request length is greater than the bounce buffer size
+                */
+               if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
+                       transfer_size = ALIGN(ur->length - maxp, maxp);
+                       transferred = transfer_size - length;
+                       buf = (u8 *)buf + transferred;
+                       ur->actual += transferred;
+                       remaining_ur_length -= transferred;
+
+                       trb++;
+                       length = trb->size & DWC3_TRB_SIZE_MASK;
 
-               transfer_size += (maxp - (transfer_size % maxp));
-               transferred = min_t(u32, ur->length,
-                               transfer_size - length);
-               memcpy(ur->buf, dwc->ep0_bounce, transferred);
+                       ep0->free_slot = 0;
+               }
+
+               transfer_size = roundup((ur->length - transfer_size),
+                                       maxp);
+
+               transferred = min_t(u32, remaining_ur_length,
+                                   transfer_size - length);
+               memcpy(buf, dwc->ep0_bounce, transferred);
        } else {
                transferred = ur->length - length;
        }
@@ -844,7 +878,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
 
                        ret = dwc3_ep0_start_trans(dwc, epnum,
                                        dwc->ctrl_req_addr, 0,
-                                       DWC3_TRBCTL_CONTROL_DATA);
+                                       DWC3_TRBCTL_CONTROL_DATA, false);
                        WARN_ON(ret < 0);
                }
        }
@@ -928,10 +962,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
        if (req->request.length == 0) {
                ret = dwc3_ep0_start_trans(dwc, dep->number,
                                dwc->ctrl_req_addr, 0,
-                               DWC3_TRBCTL_CONTROL_DATA);
+                               DWC3_TRBCTL_CONTROL_DATA, false);
        } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
                        && (dep->number == 0)) {
-               u32     transfer_size;
+               u32     transfer_size = 0;
                u32     maxpacket;
 
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
@@ -941,21 +975,26 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                        return;
                }
 
-               WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
-
                maxpacket = dep->endpoint.maxpacket;
-               transfer_size = roundup(req->request.length, maxpacket);
+
+               if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
+                       transfer_size = ALIGN(req->request.length - maxpacket,
+                                             maxpacket);
+                       ret = dwc3_ep0_start_trans(dwc, dep->number,
+                                                  req->request.dma,
+                                                  transfer_size,
+                                                  DWC3_TRBCTL_CONTROL_DATA,
+                                                  true);
+               }
+
+               transfer_size = roundup((req->request.length - transfer_size),
+                                       maxpacket);
 
                dwc->ep0_bounced = true;
 
-               /*
-                * REVISIT in case request length is bigger than
-                * DWC3_EP0_BOUNCE_SIZE we will need two chained
-                * TRBs to handle the transfer.
-                */
                ret = dwc3_ep0_start_trans(dwc, dep->number,
                                dwc->ep0_bounce_addr, transfer_size,
-                               DWC3_TRBCTL_CONTROL_DATA);
+                               DWC3_TRBCTL_CONTROL_DATA, false);
        } else {
                ret = usb_gadget_map_request(&dwc->gadget, &req->request,
                                dep->number);
@@ -965,7 +1004,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
                }
 
                ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
-                               req->request.length, DWC3_TRBCTL_CONTROL_DATA);
+                               req->request.length, DWC3_TRBCTL_CONTROL_DATA,
+                               false);
        }
 
        WARN_ON(ret < 0);
@@ -980,7 +1020,7 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
                : DWC3_TRBCTL_CONTROL_STATUS2;
 
        return dwc3_ep0_start_trans(dwc, dep->number,
-                       dwc->ctrl_req_addr, 0, type);
+                       dwc->ctrl_req_addr, 0, type, false);
 }
 
 static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
index 333a7c0078fcf922b9effaae3deff795d8b0f63e..0c25704dcb6ba398a98012cf0d9480c9de4f44e2 100644 (file)
@@ -547,6 +547,23 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
        }
 
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               strlcat(dep->name, "-control", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               strlcat(dep->name, "-isoc", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               strlcat(dep->name, "-bulk", sizeof(dep->name));
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               strlcat(dep->name, "-int", sizeof(dep->name));
+               break;
+       default:
+               dev_err(dwc->dev, "invalid endpoint transfer type\n");
+       }
+
        return 0;
 }
 
@@ -586,6 +603,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
        struct dwc3             *dwc = dep->dwc;
        u32                     reg;
 
+       dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name);
+
        dwc3_remove_requests(dwc, dep);
 
        /* make sure HW endpoint isn't stalled */
@@ -602,6 +621,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
        dep->type = 0;
        dep->flags = 0;
 
+       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+                       dep->number >> 1,
+                       (dep->number & 1) ? "in" : "out");
+
        return 0;
 }
 
@@ -647,23 +670,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
                return 0;
        }
 
-       switch (usb_endpoint_type(desc)) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               strlcat(dep->name, "-control", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               strlcat(dep->name, "-isoc", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               strlcat(dep->name, "-bulk", sizeof(dep->name));
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               strlcat(dep->name, "-int", sizeof(dep->name));
-               break;
-       default:
-               dev_err(dwc->dev, "invalid endpoint transfer type\n");
-       }
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -692,10 +698,6 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
                return 0;
        }
 
-       snprintf(dep->name, sizeof(dep->name), "ep%d%s",
-                       dep->number >> 1,
-                       (dep->number & 1) ? "in" : "out");
-
        spin_lock_irqsave(&dwc->lock, flags);
        ret = __dwc3_gadget_ep_disable(dep);
        spin_unlock_irqrestore(&dwc->lock, flags);
@@ -1713,6 +1715,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
                                return ret;
                }
 
+               if (epnum == 0 || epnum == 1) {
+                       dep->endpoint.caps.type_control = true;
+               } else {
+                       dep->endpoint.caps.type_iso = true;
+                       dep->endpoint.caps.type_bulk = true;
+                       dep->endpoint.caps.type_int = true;
+               }
+
+               dep->endpoint.caps.dir_in = !!direction;
+               dep->endpoint.caps.dir_out = !direction;
+
                INIT_LIST_HEAD(&dep->request_list);
                INIT_LIST_HEAD(&dep->req_queued);
        }
@@ -2685,7 +2698,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
                goto err0;
        }
 
-       dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+       dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
                        &dwc->ep0_trb_addr, GFP_KERNEL);
        if (!dwc->ep0_trb) {
                dev_err(dwc->dev, "failed to allocate ep0 trb\n");
index 58b4657fc721d3dabda76b2138ea6c30d539992c..b474499839d395289803501fdbb57d5c6c59b785 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/utsname.h>
 
 #include <linux/usb/composite.h>
+#include <linux/usb/otg.h>
 #include <asm/unaligned.h>
 
 #include "u_os_desc.h"
@@ -209,6 +210,12 @@ int usb_add_function(struct usb_configuration *config,
        function->config = config;
        list_add_tail(&function->list, &config->functions);
 
+       if (function->bind_deactivated) {
+               value = usb_function_deactivate(function);
+               if (value)
+                       goto done;
+       }
+
        /* REVISIT *require* function->bind? */
        if (function->bind) {
                value = function->bind(config, function);
@@ -279,7 +286,7 @@ int usb_function_deactivate(struct usb_function *function)
        spin_lock_irqsave(&cdev->lock, flags);
 
        if (cdev->deactivations == 0)
-               status = usb_gadget_disconnect(cdev->gadget);
+               status = usb_gadget_deactivate(cdev->gadget);
        if (status == 0)
                cdev->deactivations++;
 
@@ -311,7 +318,7 @@ int usb_function_activate(struct usb_function *function)
        else {
                cdev->deactivations--;
                if (cdev->deactivations == 0)
-                       status = usb_gadget_connect(cdev->gadget);
+                       status = usb_gadget_activate(cdev->gadget);
        }
 
        spin_unlock_irqrestore(&cdev->lock, flags);
@@ -896,7 +903,7 @@ void usb_remove_config(struct usb_composite_dev *cdev,
 
 /* We support strings in multiple languages ... string descriptor zero
  * says which languages are supported.  The typical case will be that
- * only one language (probably English) is used, with I18N handled on
+ * only one language (probably English) is used, with i18n handled on
  * the host side.
  */
 
@@ -949,7 +956,7 @@ static int get_string(struct usb_composite_dev *cdev,
        struct usb_function             *f;
        int                             len;
 
-       /* Yes, not only is USB's I18N support probably more than most
+       /* Yes, not only is USB's i18n support probably more than most
         * folk will ever care about ... also, it's all supported here.
         * (Except for UTF8 support for Unicode's "Astral Planes".)
         */
@@ -1534,6 +1541,32 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                value = min(w_length, (u16) value);
                        }
                        break;
+               case USB_DT_OTG:
+                       if (gadget_is_otg(gadget)) {
+                               struct usb_configuration *config;
+                               int otg_desc_len = 0;
+
+                               if (cdev->config)
+                                       config = cdev->config;
+                               else
+                                       config = list_first_entry(
+                                                       &cdev->configs,
+                                               struct usb_configuration, list);
+                               if (!config)
+                                       goto done;
+
+                               if (gadget->otg_caps &&
+                                       (gadget->otg_caps->otg_rev >= 0x0200))
+                                       otg_desc_len += sizeof(
+                                               struct usb_otg20_descriptor);
+                               else
+                                       otg_desc_len += sizeof(
+                                               struct usb_otg_descriptor);
+
+                               value = min_t(int, w_length, otg_desc_len);
+                               memcpy(req->buf, config->descriptors[0], value);
+                       }
+                       break;
                }
                break;
 
index 34e12fc52c23d45fa2148212938242bb05b777f3..0fafa7a1b6f6c38cf97e085a2cd295e450261aef 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/composite.h>
+#include <linux/usb/otg.h>
 
 /**
  * usb_descriptor_fillbuf - fill buffer with descriptors
@@ -195,3 +196,58 @@ void usb_free_all_descriptors(struct usb_function *f)
        usb_free_descriptors(f->ss_descriptors);
 }
 EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
+
+struct usb_descriptor_header *usb_otg_descriptor_alloc(
+                               struct usb_gadget *gadget)
+{
+       struct usb_descriptor_header *otg_desc;
+       unsigned length = 0;
+
+       if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200))
+               length = sizeof(struct usb_otg20_descriptor);
+       else
+               length = sizeof(struct usb_otg_descriptor);
+
+       otg_desc = kzalloc(length, GFP_KERNEL);
+       return otg_desc;
+}
+EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc);
+
+int usb_otg_descriptor_init(struct usb_gadget *gadget,
+               struct usb_descriptor_header *otg_desc)
+{
+       struct usb_otg_descriptor *otg1x_desc;
+       struct usb_otg20_descriptor *otg20_desc;
+       struct usb_otg_caps *otg_caps = gadget->otg_caps;
+       u8 otg_attributes = 0;
+
+       if (!otg_desc)
+               return -EINVAL;
+
+       if (otg_caps && otg_caps->otg_rev) {
+               if (otg_caps->hnp_support)
+                       otg_attributes |= USB_OTG_HNP;
+               if (otg_caps->srp_support)
+                       otg_attributes |= USB_OTG_SRP;
+               if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200))
+                       otg_attributes |= USB_OTG_ADP;
+       } else {
+               otg_attributes = USB_OTG_SRP | USB_OTG_HNP;
+       }
+
+       if (otg_caps && (otg_caps->otg_rev >= 0x0200)) {
+               otg20_desc = (struct usb_otg20_descriptor *)otg_desc;
+               otg20_desc->bLength = sizeof(struct usb_otg20_descriptor);
+               otg20_desc->bDescriptorType = USB_DT_OTG;
+               otg20_desc->bmAttributes = otg_attributes;
+               otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev);
+       } else {
+               otg1x_desc = (struct usb_otg_descriptor *)otg_desc;
+               otg1x_desc->bLength = sizeof(struct usb_otg_descriptor);
+               otg1x_desc->bDescriptorType = USB_DT_OTG;
+               otg1x_desc->bmAttributes = otg_attributes;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_otg_descriptor_init);
index 289e20119fea25eb1d670c2abbef7ca3f671633e..294eb74fb078508f6889902e1a0c841f3b603ece 100644 (file)
@@ -41,6 +41,8 @@ int check_user_usb_string(const char *name,
 #define MAX_NAME_LEN   40
 #define MAX_USB_STRING_LANGS 2
 
+static const struct usb_descriptor_header *otg_desc[2];
+
 struct gadget_info {
        struct config_group group;
        struct config_group functions_group;
@@ -55,9 +57,6 @@ struct gadget_info {
        struct list_head available_func;
 
        const char *udc_name;
-#ifdef CONFIG_USB_OTG
-       struct usb_otg_descriptor otg;
-#endif
        struct usb_composite_driver composite;
        struct usb_composite_dev cdev;
        bool use_os_desc;
@@ -1376,6 +1375,19 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
                memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN);
        }
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc) {
+                       ret = -ENOMEM;
+                       goto err_comp_cleanup;
+               }
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* Go through all configs, attach all functions */
        list_for_each_entry(c, &gi->cdev.configs, list) {
                struct config_usb_cfg *cfg;
@@ -1383,6 +1395,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
                struct usb_function *tmp;
                struct gadget_config_name *cn;
 
+               if (gadget_is_otg(gadget))
+                       c->descriptors = otg_desc;
+
                cfg = container_of(c, struct config_usb_cfg, c);
                if (!list_empty(&cfg->string_list)) {
                        i = 0;
@@ -1437,6 +1452,8 @@ static void configfs_composite_unbind(struct usb_gadget *gadget)
        cdev = get_gadget_data(gadget);
        gi = container_of(cdev, struct gadget_info, cdev);
 
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
        purge_configs_funcs(gi);
        composite_dev_cleanup(cdev);
        usb_ep_autoconfig_reset(cdev->gadget);
@@ -1510,12 +1527,6 @@ static struct config_group *gadgets_make(
        if (!gi->composite.gadget_driver.function)
                goto err;
 
-#ifdef CONFIG_USB_OTG
-       gi->otg.bLength = sizeof(struct usb_otg_descriptor);
-       gi->otg.bDescriptorType = USB_DT_OTG;
-       gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
-#endif
-
        config_group_init_type_name(&gi->group, name,
                                &gadget_root_type);
        return &gi->group;
index 919cdfdda78b91c8a17c921a4c05ec5a6aaa600b..978435a5103875cf29890cbec24f5884ce3448a4 100644 (file)
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-#include "gadget_chips.h"
-
-/*
- * This should work with endpoints from controller drivers sharing the
- * same endpoint naming convention.  By example:
- *
- *     - ep1, ep2, ... address is fixed, not direction or type
- *     - ep1in, ep2out, ... address and direction are fixed, not type
- *     - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
- *     - ep1in-bulk, ep2out-iso, ... all three are fixed
- *     - ep-* ... no functionality restrictions
- *
- * Type suffixes are "-bulk", "-iso", or "-int".  Numbers are decimal.
- * Less common restrictions are implied by gadget_is_*().
- *
- * NOTE:  each endpoint is unidirectional, as specified by its USB
- * descriptor; and isn't specific to a configuration or altsetting.
- */
-static int
-ep_matches (
-       struct usb_gadget               *gadget,
-       struct usb_ep                   *ep,
-       struct usb_endpoint_descriptor  *desc,
-       struct usb_ss_ep_comp_descriptor *ep_comp
-)
-{
-       u8              type;
-       const char      *tmp;
-       u16             max;
-
-       int             num_req_streams = 0;
-
-       /* endpoint already claimed? */
-       if (NULL != ep->driver_data)
-               return 0;
-
-       /* only support ep0 for portable CONTROL traffic */
-       type = usb_endpoint_type(desc);
-       if (USB_ENDPOINT_XFER_CONTROL == type)
-               return 0;
-
-       /* some other naming convention */
-       if ('e' != ep->name[0])
-               return 0;
-
-       /* type-restriction:  "-iso", "-bulk", or "-int".
-        * direction-restriction:  "in", "out".
-        */
-       if ('-' != ep->name[2]) {
-               tmp = strrchr (ep->name, '-');
-               if (tmp) {
-                       switch (type) {
-                       case USB_ENDPOINT_XFER_INT:
-                               /* bulk endpoints handle interrupt transfers,
-                                * except the toggle-quirky iso-synch kind
-                                */
-                               if ('s' == tmp[2])      // == "-iso"
-                                       return 0;
-                               /* for now, avoid PXA "interrupt-in";
-                                * it's documented as never using DATA1.
-                                */
-                               if (gadget_is_pxa (gadget)
-                                               && 'i' == tmp [1])
-                                       return 0;
-                               break;
-                       case USB_ENDPOINT_XFER_BULK:
-                               if ('b' != tmp[1])      // != "-bulk"
-                                       return 0;
-                               break;
-                       case USB_ENDPOINT_XFER_ISOC:
-                               if ('s' != tmp[2])      // != "-iso"
-                                       return 0;
-                       }
-               } else {
-                       tmp = ep->name + strlen (ep->name);
-               }
-
-               /* direction-restriction:  "..in-..", "out-.." */
-               tmp--;
-               if (!isdigit (*tmp)) {
-                       if (desc->bEndpointAddress & USB_DIR_IN) {
-                               if ('n' != *tmp)
-                                       return 0;
-                       } else {
-                               if ('t' != *tmp)
-                                       return 0;
-                       }
-               }
-       }
-
-       /*
-        * Get the number of required streams from the EP companion
-        * descriptor and see if the EP matches it
-        */
-       if (usb_endpoint_xfer_bulk(desc)) {
-               if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
-                       num_req_streams = ep_comp->bmAttributes & 0x1f;
-                       if (num_req_streams > ep->max_streams)
-                               return 0;
-               }
-
-       }
-
-       /*
-        * If the protocol driver hasn't yet decided on wMaxPacketSize
-        * and wants to know the maximum possible, provide the info.
-        */
-       if (desc->wMaxPacketSize == 0)
-               desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
-
-       /* endpoint maxpacket size is an input parameter, except for bulk
-        * where it's an output parameter representing the full speed limit.
-        * the usb spec fixes high speed bulk maxpacket at 512 bytes.
-        */
-       max = 0x7ff & usb_endpoint_maxp(desc);
-       switch (type) {
-       case USB_ENDPOINT_XFER_INT:
-               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
-               if (!gadget_is_dualspeed(gadget) && max > 64)
-                       return 0;
-               /* FALLTHROUGH */
-
-       case USB_ENDPOINT_XFER_ISOC:
-               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
-               if (ep->maxpacket_limit < max)
-                       return 0;
-               if (!gadget_is_dualspeed(gadget) && max > 1023)
-                       return 0;
-
-               /* BOTH:  "high bandwidth" works only at high speed */
-               if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
-                       if (!gadget_is_dualspeed(gadget))
-                               return 0;
-                       /* configure your hardware with enough buffering!! */
-               }
-               break;
-       }
-
-       /* MATCH!! */
-
-       /* report address */
-       desc->bEndpointAddress &= USB_DIR_IN;
-       if (isdigit (ep->name [2])) {
-               u8      num = simple_strtoul (&ep->name [2], NULL, 10);
-               desc->bEndpointAddress |= num;
-       } else if (desc->bEndpointAddress & USB_DIR_IN) {
-               if (++gadget->in_epnum > 15)
-                       return 0;
-               desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
-       } else {
-               if (++gadget->out_epnum > 15)
-                       return 0;
-               desc->bEndpointAddress |= gadget->out_epnum;
-       }
-
-       /* report (variable) full speed bulk maxpacket */
-       if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
-               int size = ep->maxpacket_limit;
-
-               /* min() doesn't work on bitfields with gcc-3.5 */
-               if (size > 64)
-                       size = 64;
-               desc->wMaxPacketSize = cpu_to_le16(size);
-       }
-       ep->address = desc->bEndpointAddress;
-       return 1;
-}
-
-static struct usb_ep *
-find_ep (struct usb_gadget *gadget, const char *name)
-{
-       struct usb_ep   *ep;
-
-       list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-               if (0 == strcmp (ep->name, name))
-                       return ep;
-       }
-       return NULL;
-}
-
 /**
  * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
  * descriptor and ep companion descriptor
@@ -240,7 +60,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
  * updated with the assigned number of streams if it is
  * different from the original value. To prevent the endpoint
  * from being returned by a later autoconfig call, claim it by
- * assigning ep->driver_data to some non-null value.
+ * assigning ep->claimed to true.
  *
  * On failure, this returns a null endpoint descriptor.
  */
@@ -255,74 +75,58 @@ struct usb_ep *usb_ep_autoconfig_ss(
 
        type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 
-       /* First, apply chip-specific "best usage" knowledge.
-        * This might make a good usb_gadget_ops hook ...
-        */
-       if (gadget_is_net2280(gadget)) {
-               char name[8];
-
-               if (type == USB_ENDPOINT_XFER_INT) {
-                       /* ep-e, ep-f are PIO with only 64 byte fifos */
-                       ep = find_ep(gadget, "ep-e");
-                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
-                               goto found_ep;
-                       ep = find_ep(gadget, "ep-f");
-                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
-                               goto found_ep;
-               }
-
-               /* USB3380: use same address for usb and hardware endpoints */
-               snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
-                               usb_endpoint_dir_in(desc) ? "in" : "out");
-               ep = find_ep(gadget, name);
-               if (ep && ep_matches(gadget, ep, desc, ep_comp))
+       if (gadget->ops->match_ep) {
+               ep = gadget->ops->match_ep(gadget, desc, ep_comp);
+               if (ep)
                        goto found_ep;
-       } else if (gadget_is_goku (gadget)) {
-               if (USB_ENDPOINT_XFER_INT == type) {
-                       /* single buffering is enough */
-                       ep = find_ep(gadget, "ep3-bulk");
-                       if (ep && ep_matches(gadget, ep, desc, ep_comp))
-                               goto found_ep;
-               } else if (USB_ENDPOINT_XFER_BULK == type
-                               && (USB_DIR_IN & desc->bEndpointAddress)) {
-                       /* DMA may be available */
-                       ep = find_ep(gadget, "ep2-bulk");
-                       if (ep && ep_matches(gadget, ep, desc,
-                                             ep_comp))
-                               goto found_ep;
-               }
-
-#ifdef CONFIG_BLACKFIN
-       } else if (gadget_is_musbhdrc(gadget)) {
-               if ((USB_ENDPOINT_XFER_BULK == type) ||
-                   (USB_ENDPOINT_XFER_ISOC == type)) {
-                       if (USB_DIR_IN & desc->bEndpointAddress)
-                               ep = find_ep (gadget, "ep5in");
-                       else
-                               ep = find_ep (gadget, "ep6out");
-               } else if (USB_ENDPOINT_XFER_INT == type) {
-                       if (USB_DIR_IN & desc->bEndpointAddress)
-                               ep = find_ep(gadget, "ep1in");
-                       else
-                               ep = find_ep(gadget, "ep2out");
-               } else
-                       ep = NULL;
-               if (ep && ep_matches(gadget, ep, desc, ep_comp))
-                       goto found_ep;
-#endif
        }
 
        /* Second, look at endpoints until an unclaimed one looks usable */
        list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-               if (ep_matches(gadget, ep, desc, ep_comp))
+               if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
                        goto found_ep;
        }
 
        /* Fail */
        return NULL;
 found_ep:
+
+       /*
+        * If the protocol driver hasn't yet decided on wMaxPacketSize
+        * and wants to know the maximum possible, provide the info.
+        */
+       if (desc->wMaxPacketSize == 0)
+               desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
+
+       /* report address */
+       desc->bEndpointAddress &= USB_DIR_IN;
+       if (isdigit(ep->name[2])) {
+               u8 num = simple_strtoul(&ep->name[2], NULL, 10);
+               desc->bEndpointAddress |= num;
+       } else if (desc->bEndpointAddress & USB_DIR_IN) {
+               if (++gadget->in_epnum > 15)
+                       return NULL;
+               desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
+       } else {
+               if (++gadget->out_epnum > 15)
+                       return NULL;
+               desc->bEndpointAddress |= gadget->out_epnum;
+       }
+
+       /* report (variable) full speed bulk maxpacket */
+       if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) {
+               int size = ep->maxpacket_limit;
+
+               /* min() doesn't work on bitfields with gcc-3.5 */
+               if (size > 64)
+                       size = 64;
+               desc->wMaxPacketSize = cpu_to_le16(size);
+       }
+
+       ep->address = desc->bEndpointAddress;
        ep->desc = NULL;
        ep->comp_desc = NULL;
+       ep->claimed = true;
        return ep;
 }
 EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
@@ -354,7 +158,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
  * is initialized as if the endpoint were used at full speed.  To prevent
  * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
+ * by assigning ep->claimed to true.
  *
  * On failure, this returns a null endpoint descriptor.
  */
@@ -373,7 +177,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
  *
  * Use this for devices where one configuration may need to assign
  * endpoint resources very differently from the next one.  It clears
- * state such as ep->driver_data and the record of assigned endpoints
+ * state such as ep->claimed and the record of assigned endpoints
  * used by usb_ep_autoconfig().
  */
 void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
@@ -381,7 +185,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
        struct usb_ep   *ep;
 
        list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-               ep->driver_data = NULL;
+               ep->claimed = false;
        }
        gadget->in_epnum = 0;
        gadget->out_epnum = 0;
index aad8165e98ef84d314f74826e97d1bd0641a5b95..be9df09fde26508c6b658cd0686681fb43e1d4bb 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/err.h>
 
 #include "u_serial.h"
-#include "gadget_chips.h"
 
 
 /*
index 798760fa7e702b73285d21d6a2d69c55c351a44a..7b7424f10dddce479fca8945cd238293a2f02cc6 100644 (file)
@@ -585,8 +585,8 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        /* Enable zlps by default for ECM conformance;
                         * override for musb_hdrc (avoids txdma ovhead).
                         */
-                       ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)
-                               );
+                       ecm->port.is_zlp_ok =
+                               gadget_is_zlp_supported(cdev->gadget);
                        ecm->port.cdc_filter = DEFAULT_FILTER;
                        DBG(cdev, "activate ecm\n");
                        net = gether_connect(&ecm->port);
index 6e7be91e6097cf0cfb4d6106decc141aeb8a5eb3..adc6d52efa4639387c30bcde2ae7cee95331b1bc 100644 (file)
@@ -2897,11 +2897,17 @@ static int ffs_func_bind(struct usb_configuration *c,
                         struct usb_function *f)
 {
        struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
+       struct ffs_function *func = ffs_func_from_usb(f);
+       int ret;
 
        if (IS_ERR(ffs_opts))
                return PTR_ERR(ffs_opts);
 
-       return _ffs_func_bind(c, f);
+       ret = _ffs_func_bind(c, f);
+       if (ret && !--ffs_opts->refcnt)
+               functionfs_unbind(func->ffs);
+
+       return ret;
 }
 
 
index 39f49f1ad22f287e58df631077a9a1506381707b..6e2fe63b926741abf184f2ee54a0fe740a372e42 100644 (file)
  * This takes messages of various sizes written OUT to a device, and loops
  * them back so they can be read IN from it.  It has been used by certain
  * test applications.  It supports limited testing of data queueing logic.
- *
- *
- * This is currently packaged as a configuration driver, which can't be
- * combined with other functions to make composite devices.  However, it
- * can be combined with other independent configurations.
  */
 struct f_loopback {
        struct usb_function     function;
index f936268d26c6aaa9a5601614adf2e90319e0d364..a6eb537d77689f53e7b0e31cff14c2f523c52fe4 100644 (file)
@@ -54,7 +54,7 @@
  * following fields:
  *
  *     nluns           Number of LUNs function have (anywhere from 1
- *                             to FSG_MAX_LUNS which is 8).
+ *                             to FSG_MAX_LUNS).
  *     luns            An array of LUN configuration values.  This
  *                             should be filled for each LUN that
  *                             function will include (ie. for "nluns"
 #include <linux/string.h>
 #include <linux/freezer.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/composite.h>
 
-#include "gadget_chips.h"
 #include "configfs.h"
 
 
@@ -279,9 +279,8 @@ struct fsg_common {
        int                     cmnd_size;
        u8                      cmnd[MAX_COMMAND_SIZE];
 
-       unsigned int            nluns;
        unsigned int            lun;
-       struct fsg_lun          **luns;
+       struct fsg_lun          *luns[FSG_MAX_LUNS];
        struct fsg_lun          *curlun;
 
        unsigned int            bulk_out_maxpacket;
@@ -490,6 +489,16 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
        spin_unlock(&common->lock);
 }
 
+static int _fsg_common_get_max_lun(struct fsg_common *common)
+{
+       int i = ARRAY_SIZE(common->luns) - 1;
+
+       while (i >= 0 && !common->luns[i])
+               --i;
+
+       return i;
+}
+
 static int fsg_setup(struct usb_function *f,
                     const struct usb_ctrlrequest *ctrl)
 {
@@ -533,7 +542,7 @@ static int fsg_setup(struct usb_function *f,
                                w_length != 1)
                        return -EDOM;
                VDBG(fsg, "get max LUN\n");
-               *(u8 *)req->buf = fsg->common->nluns - 1;
+               *(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common);
 
                /* Respond with data/status */
                req->length = min((u16)1, w_length);
@@ -2131,8 +2140,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        }
 
        /* Is the CBW meaningful? */
-       if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
-                       cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
+       if (cbw->Lun >= ARRAY_SIZE(common->luns) ||
+           cbw->Flags & ~US_BULK_FLAG_IN || cbw->Length <= 0 ||
+           cbw->Length > MAX_COMMAND_SIZE) {
                DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
                                "cmdlen %u\n",
                                cbw->Lun, cbw->Flags, cbw->Length);
@@ -2159,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        if (common->data_size == 0)
                common->data_dir = DATA_DIR_NONE;
        common->lun = cbw->Lun;
-       if (common->lun < common->nluns)
+       if (common->lun < ARRAY_SIZE(common->luns))
                common->curlun = common->luns[common->lun];
        else
                common->curlun = NULL;
@@ -2307,7 +2317,7 @@ reset:
        }
 
        common->running = 1;
-       for (i = 0; i < common->nluns; ++i)
+       for (i = 0; i < ARRAY_SIZE(common->luns); ++i)
                if (common->luns[i])
                        common->luns[i]->unit_attention_data =
                                SS_RESET_OCCURRED;
@@ -2409,7 +2419,7 @@ static void handle_exception(struct fsg_common *common)
        if (old_state == FSG_STATE_ABORT_BULK_OUT)
                common->state = FSG_STATE_STATUS_PHASE;
        else {
-               for (i = 0; i < common->nluns; ++i) {
+               for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
                        curlun = common->luns[i];
                        if (!curlun)
                                continue;
@@ -2453,7 +2463,7 @@ static void handle_exception(struct fsg_common *common)
                 * a waste of time.  Ditto for the INTERFACE_CHANGE and
                 * CONFIG_CHANGE cases.
                 */
-               /* for (i = 0; i < common->nluns; ++i) */
+               /* for (i = 0; i < common->ARRAY_SIZE(common->luns); ++i) */
                /*      if (common->luns[i]) */
                /*              common->luns[i]->unit_attention_data = */
                /*                      SS_RESET_OCCURRED;  */
@@ -2552,12 +2562,11 @@ static int fsg_main_thread(void *common_)
 
        if (!common->ops || !common->ops->thread_exits
         || common->ops->thread_exits(common) < 0) {
-               struct fsg_lun **curlun_it = common->luns;
-               unsigned i = common->nluns;
+               int i;
 
                down_write(&common->filesem);
-               for (; i--; ++curlun_it) {
-                       struct fsg_lun *curlun = *curlun_it;
+               for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
+                       struct fsg_lun *curlun = common->luns[i];
                        if (!curlun || !fsg_lun_is_open(curlun))
                                continue;
 
@@ -2676,6 +2685,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
        init_completion(&common->thread_notifier);
        init_waitqueue_head(&common->fsg_wait);
        common->state = FSG_STATE_TERMINATED;
+       memset(common->luns, 0, sizeof(common->luns));
 
        return common;
 }
@@ -2742,9 +2752,9 @@ error_release:
 }
 EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers);
 
-void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs)
+void fsg_common_remove_lun(struct fsg_lun *lun)
 {
-       if (sysfs)
+       if (device_is_registered(&lun->dev))
                device_unregister(&lun->dev);
        fsg_lun_close(lun);
        kfree(lun);
@@ -2757,48 +2767,16 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n)
 
        for (i = 0; i < n; ++i)
                if (common->luns[i]) {
-                       fsg_common_remove_lun(common->luns[i], common->sysfs);
+                       fsg_common_remove_lun(common->luns[i]);
                        common->luns[i] = NULL;
                }
 }
-EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
 
 void fsg_common_remove_luns(struct fsg_common *common)
 {
-       _fsg_common_remove_luns(common, common->nluns);
-}
-
-void fsg_common_free_luns(struct fsg_common *common)
-{
-       fsg_common_remove_luns(common);
-       kfree(common->luns);
-       common->luns = NULL;
-}
-EXPORT_SYMBOL_GPL(fsg_common_free_luns);
-
-int fsg_common_set_nluns(struct fsg_common *common, int nluns)
-{
-       struct fsg_lun **curlun;
-
-       /* Find out how many LUNs there should be */
-       if (nluns < 1 || nluns > FSG_MAX_LUNS) {
-               pr_err("invalid number of LUNs: %u\n", nluns);
-               return -EINVAL;
-       }
-
-       curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
-       if (unlikely(!curlun))
-               return -ENOMEM;
-
-       if (common->luns)
-               fsg_common_free_luns(common);
-
-       common->luns = curlun;
-       common->nluns = nluns;
-
-       return 0;
+       _fsg_common_remove_luns(common, ARRAY_SIZE(common->luns));
 }
-EXPORT_SYMBOL_GPL(fsg_common_set_nluns);
+EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
 
 void fsg_common_set_ops(struct fsg_common *common,
                        const struct fsg_operations *ops)
@@ -2836,7 +2814,8 @@ int fsg_common_set_cdev(struct fsg_common *common,
         * halt bulk endpoints correctly.  If one of them is present,
         * disable stalls.
         */
-       common->can_stall = can_stall && !(gadget_is_at91(common->gadget));
+       common->can_stall = can_stall &&
+                       gadget_is_stall_supported(common->gadget);
 
        return 0;
 }
@@ -2880,7 +2859,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
        char *pathbuf, *p;
        int rc = -ENOMEM;
 
-       if (!common->nluns || !common->luns)
+       if (id >= ARRAY_SIZE(common->luns))
                return -ENODEV;
 
        if (common->luns[id])
@@ -2949,7 +2928,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
        return 0;
 
 error_lun:
-       if (common->sysfs)
+       if (device_is_registered(&lun->dev))
                device_unregister(&lun->dev);
        fsg_lun_close(lun);
        common->luns[id] = NULL;
@@ -2964,14 +2943,16 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg)
        char buf[8]; /* enough for 100000000 different numbers, decimal */
        int i, rc;
 
-       for (i = 0; i < common->nluns; ++i) {
+       fsg_common_remove_luns(common);
+
+       for (i = 0; i < cfg->nluns; ++i) {
                snprintf(buf, sizeof(buf), "lun%d", i);
                rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL);
                if (rc)
                        goto fail;
        }
 
-       pr_info("Number of LUNs=%d\n", common->nluns);
+       pr_info("Number of LUNs=%d\n", cfg->nluns);
 
        return 0;
 
@@ -3020,6 +3001,7 @@ EXPORT_SYMBOL_GPL(fsg_common_run_thread);
 static void fsg_common_release(struct kref *ref)
 {
        struct fsg_common *common = container_of(ref, struct fsg_common, ref);
+       int i;
 
        /* If the thread isn't already dead, tell it to exit now */
        if (common->state != FSG_STATE_TERMINATED) {
@@ -3027,22 +3009,14 @@ static void fsg_common_release(struct kref *ref)
                wait_for_completion(&common->thread_notifier);
        }
 
-       if (likely(common->luns)) {
-               struct fsg_lun **lun_it = common->luns;
-               unsigned i = common->nluns;
-
-               /* In error recovery common->nluns may be zero. */
-               for (; i; --i, ++lun_it) {
-                       struct fsg_lun *lun = *lun_it;
-                       if (!lun)
-                               continue;
-                       fsg_lun_close(lun);
-                       if (common->sysfs)
-                               device_unregister(&lun->dev);
-                       kfree(lun);
-               }
-
-               kfree(common->luns);
+       for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
+               struct fsg_lun *lun = common->luns[i];
+               if (!lun)
+                       continue;
+               fsg_lun_close(lun);
+               if (device_is_registered(&lun->dev))
+                       device_unregister(&lun->dev);
+               kfree(lun);
        }
 
        _fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
@@ -3056,6 +3030,7 @@ static void fsg_common_release(struct kref *ref)
 static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 {
        struct fsg_dev          *fsg = fsg_from_func(f);
+       struct fsg_common       *common = fsg->common;
        struct usb_gadget       *gadget = c->cdev->gadget;
        int                     i;
        struct usb_ep           *ep;
@@ -3063,6 +3038,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
        int                     ret;
        struct fsg_opts         *opts;
 
+       /* Don't allow to bind if we don't have at least one LUN */
+       ret = _fsg_common_get_max_lun(common);
+       if (ret < 0) {
+               pr_err("There should be at least one LUN.\n");
+               return -EINVAL;
+       }
+
        opts = fsg_opts_from_func_inst(f->fi);
        if (!opts->no_configfs) {
                ret = fsg_common_set_cdev(fsg->common, c->cdev,
@@ -3080,7 +3062,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
        /* New interface */
        i = usb_interface_id(c, f);
        if (i < 0)
-               return i;
+               goto fail;
        fsg_intf_desc.bInterfaceNumber = i;
        fsg->interface_number = i;
 
@@ -3123,7 +3105,14 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 
 autoconf_fail:
        ERROR(fsg, "unable to autoconfigure all endpoints\n");
-       return -ENOTSUPP;
+       i = -ENOTSUPP;
+fail:
+       /* terminate the thread */
+       if (fsg->common->state != FSG_STATE_TERMINATED) {
+               raise_exception(fsg->common, FSG_STATE_EXIT);
+               wait_for_completion(&fsg->common->thread_notifier);
+       }
+       return i;
 }
 
 /****************************** ALLOCATE FUNCTION *************************/
@@ -3355,7 +3344,7 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item)
                unregister_gadget_item(gadget);
        }
 
-       fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs);
+       fsg_common_remove_lun(lun_opts->lun);
        fsg_opts->common->luns[lun_opts->lun_id] = NULL;
        lun_opts->lun_id = 0;
        mutex_unlock(&fsg_opts->lock);
@@ -3509,14 +3498,11 @@ static struct usb_function_instance *fsg_alloc_inst(void)
                rc = PTR_ERR(opts->common);
                goto release_opts;
        }
-       rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS);
-       if (rc)
-               goto release_opts;
 
        rc = fsg_common_set_num_buffers(opts->common,
                                        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
        if (rc)
-               goto release_luns;
+               goto release_opts;
 
        pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
 
@@ -3524,6 +3510,9 @@ static struct usb_function_instance *fsg_alloc_inst(void)
        config.removable = true;
        rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0",
                        (const char **)&opts->func_inst.group.cg_item.ci_name);
+       if (rc)
+               goto release_buffers;
+
        opts->lun0.lun = opts->common->luns[0];
        opts->lun0.lun_id = 0;
        config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
@@ -3534,8 +3523,8 @@ static struct usb_function_instance *fsg_alloc_inst(void)
 
        return &opts->func_inst;
 
-release_luns:
-       kfree(opts->common->luns);
+release_buffers:
+       fsg_common_free_buffers(opts->common);
 release_opts:
        kfree(opts);
        return ERR_PTR(rc);
@@ -3561,23 +3550,12 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
        struct fsg_opts *opts = fsg_opts_from_func_inst(fi);
        struct fsg_common *common = opts->common;
        struct fsg_dev *fsg;
-       unsigned nluns, i;
 
        fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
        if (unlikely(!fsg))
                return ERR_PTR(-ENOMEM);
 
        mutex_lock(&opts->lock);
-       if (!opts->refcnt) {
-               for (nluns = i = 0; i < FSG_MAX_LUNS; ++i)
-                       if (common->luns[i])
-                               nluns = i + 1;
-               if (!nluns)
-                       pr_warn("No LUNS defined, continuing anyway\n");
-               else
-                       common->nluns = nluns;
-               pr_info("Number of LUNs=%u\n", common->nluns);
-       }
        opts->refcnt++;
        mutex_unlock(&opts->lock);
 
index b4866fcef30bdb94a2b8d98ccbe033cd1f1c8951..445df67756091678336dd3e9490de1c6ec595096 100644 (file)
@@ -137,14 +137,10 @@ void fsg_common_free_buffers(struct fsg_common *common);
 int fsg_common_set_cdev(struct fsg_common *common,
                        struct usb_composite_dev *cdev, bool can_stall);
 
-void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs);
+void fsg_common_remove_lun(struct fsg_lun *lun);
 
 void fsg_common_remove_luns(struct fsg_common *common);
 
-void fsg_common_free_luns(struct fsg_common *common);
-
-int fsg_common_set_nluns(struct fsg_common *common, int nluns);
-
 void fsg_common_set_ops(struct fsg_common *common,
                        const struct fsg_operations *ops);
 
index ad50a67c14656aa70f6804572486954f0e389887..a287a48292731b2b9eda7a0294eed98dfd6b0987 100644 (file)
@@ -329,6 +329,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
        unsigned i;
        int err;
 
+       /* For Control Device interface we do nothing */
+       if (intf == 0)
+               return 0;
+
        err = f_midi_start_ep(midi, f, midi->in_ep);
        if (err)
                return err;
index bdcda9f5148e5c42d2217fcae87be5f266c263f2..3f05c6bd57f0c3353b5a2973a3e344593834b5b5 100644 (file)
@@ -853,9 +853,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        /* Enable zlps by default for NCM conformance;
                         * override for musb_hdrc (avoids txdma ovhead)
                         */
-                       ncm->port.is_zlp_ok = !(
-                               gadget_is_musbhdrc(cdev->gadget)
-                               );
+                       ncm->port.is_zlp_ok =
+                               gadget_is_zlp_supported(cdev->gadget);
                        ncm->port.cdc_filter = DEFAULT_FILTER;
                        DBG(cdev, "activate ncm\n");
                        net = gether_connect(&ncm->port);
index a1b79c53499c2f4e852b1599347df3a400337745..5460426057eb232d13e6a071a47f114fb8cd4e14 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/module.h>
 
 #include "u_serial.h"
-#include "gadget_chips.h"
 
 
 /*
@@ -37,7 +36,6 @@ struct f_obex {
        u8                              data_id;
        u8                              cur_alt;
        u8                              port_num;
-       u8                              can_activate;
 };
 
 static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -268,9 +266,6 @@ static void obex_connect(struct gserial *g)
        struct usb_composite_dev *cdev = g->func.config->cdev;
        int                     status;
 
-       if (!obex->can_activate)
-               return;
-
        status = usb_function_activate(&g->func);
        if (status)
                dev_dbg(&cdev->gadget->dev,
@@ -284,9 +279,6 @@ static void obex_disconnect(struct gserial *g)
        struct usb_composite_dev *cdev = g->func.config->cdev;
        int                     status;
 
-       if (!obex->can_activate)
-               return;
-
        status = usb_function_deactivate(&g->func);
        if (status)
                dev_dbg(&cdev->gadget->dev,
@@ -304,7 +296,7 @@ static inline bool can_support_obex(struct usb_configuration *c)
         *
         * Altsettings are mandatory, however...
         */
-       if (!gadget_supports_altsettings(c->cdev->gadget))
+       if (!gadget_is_altset_supported(c->cdev->gadget))
                return false;
 
        /* everything else is *probably* fine ... */
@@ -378,17 +370,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
        if (status)
                goto fail;
 
-       /* Avoid letting this gadget enumerate until the userspace
-        * OBEX server is active.
-        */
-       status = usb_function_deactivate(f);
-       if (status < 0)
-               WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n",
-                       obex->port_num, status);
-       else
-               obex->can_activate = true;
-
-
        dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
                obex->port_num,
                gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
@@ -529,6 +510,7 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi)
        obex->port.func.get_alt = obex_get_alt;
        obex->port.func.disable = obex_disable;
        obex->port.func.free_func = obex_free;
+       obex->port.func.bind_deactivated = true;
 
        return &obex->port.func;
 }
index 357f63f47b42aba69d92e24346963645227d39e2..8e2b6bea07bc0e6a6fa1758aa38841a52afdcf3c 100644 (file)
@@ -804,6 +804,8 @@ done:
 
 static void printer_reset_interface(struct printer_dev *dev)
 {
+       unsigned long   flags;
+
        if (dev->interface < 0)
                return;
 
@@ -815,9 +817,11 @@ static void printer_reset_interface(struct printer_dev *dev)
        if (dev->out_ep->desc)
                usb_ep_disable(dev->out_ep);
 
+       spin_lock_irqsave(&dev->lock, flags);
        dev->in_ep->desc = NULL;
        dev->out_ep->desc = NULL;
        dev->interface = -1;
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 /* Change our operational Interface. */
@@ -1131,13 +1135,10 @@ static int printer_func_set_alt(struct usb_function *f,
 static void printer_func_disable(struct usb_function *f)
 {
        struct printer_dev *dev = func_to_printer(f);
-       unsigned long           flags;
 
        DBG(dev, "%s\n", __func__);
 
-       spin_lock_irqsave(&dev->lock, flags);
        printer_reset_interface(dev);
-       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static inline struct f_printer_opts
index 2e02dfabc7ae18394315de1f692d6abfc9f0f996..1d162e200e831ce1320a8e3d3f36f3bbd82b5a92 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/device.h>
 
 #include "u_serial.h"
-#include "gadget_chips.h"
 
 
 /*
index 3a5ae9900b1ee585881aa8233065ef9772de8da7..cbfaf86fe45652911744055d6549a88c88b056d3 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/err.h>
 
 #include "g_zero.h"
-#include "gadget_chips.h"
 #include "u_f.h"
 
 /*
  * queues are relatively independent, will receive a range of packet sizes,
  * and can often be made to run out completely.  Those issues are important
  * when stress testing peripheral controller drivers.
- *
- *
- * This is currently packaged as a configuration driver, which can't be
- * combined with other functions to make composite devices.  However, it
- * can be combined with other independent configurations.
  */
 struct f_sourcesink {
        struct usb_function     function;
index 53186154725330d4c1f710e4829d4a8b25b614cd..f8de7ea2a0c1e9585782e2fe60af23a41c072e37 100644 (file)
@@ -975,6 +975,29 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
                        "%s:%d Error!\n", __func__, __LINE__);
 }
 
+static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
+       struct usb_endpoint_descriptor *ep_desc,
+       unsigned int factor, bool is_playback)
+{
+       int chmask, srate, ssize;
+       u16 max_packet_size;
+
+       if (is_playback) {
+               chmask = uac2_opts->p_chmask;
+               srate = uac2_opts->p_srate;
+               ssize = uac2_opts->p_ssize;
+       } else {
+               chmask = uac2_opts->c_chmask;
+               srate = uac2_opts->c_srate;
+               ssize = uac2_opts->c_ssize;
+       }
+
+       max_packet_size = num_channels(chmask) * ssize *
+               DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
+       ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size,
+                               le16_to_cpu(ep_desc->wMaxPacketSize)));
+}
+
 static int
 afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 {
@@ -1070,10 +1093,14 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
        uac2->p_prm.uac2 = uac2;
        uac2->c_prm.uac2 = uac2;
 
+       /* Calculate wMaxPacketSize according to audio bandwidth */
+       set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
+       set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
+       set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
+       set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
+
        hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
-       hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
        hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
-       hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
 
        ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
        if (ret)
index cf0df8fbba890130f427e748a98736a4eee3a6aa..743be34605dcbff26eaf066c80578fb5112e41cf 100644 (file)
@@ -733,12 +733,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        uvc->control_req->complete = uvc_function_ep0_complete;
        uvc->control_req->context = uvc;
 
-       /* Avoid letting this gadget enumerate until the userspace server is
-        * active.
-        */
-       if ((ret = usb_function_deactivate(f)) < 0)
-               goto error;
-
        if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
                printk(KERN_INFO "v4l2_device_register failed\n");
                goto error;
@@ -949,6 +943,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
        uvc->func.disable = uvc_function_disable;
        uvc->func.setup = uvc_function_setup;
        uvc->func.free_func = uvc_free;
+       uvc->func.bind_deactivated = true;
 
        return &uvc->func;
 }
index 70c891469f574ebd1d7719fc05bcf838d1d6e3cb..c3544e61da6690f2b377e0a8e2cc8e7f835389ea 100644 (file)
@@ -123,7 +123,7 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
 #define FSG_BUFLEN     ((u32)16384)
 
 /* Maximal number of LUNs supported in mass storage function */
-#define FSG_MAX_LUNS   8
+#define FSG_MAX_LUNS   16
 
 enum fsg_buffer_state {
        BUF_STATE_EMPTY = 0,
index 334b389479165b4bf3391ee39e086f18a777ca9e..c77145bd6b5b94f65b8531f2ab061c2770edbae5 100644 (file)
@@ -20,8 +20,6 @@
 #include <linux/usb/cdc.h>
 #include <linux/netdevice.h>
 
-#include "gadget_chips.h"
-
 #define QMULT_DEFAULT 5
 
 /*
@@ -259,7 +257,7 @@ void gether_disconnect(struct gether *);
 /* Some controllers can't support CDC Ethernet (ECM) ... */
 static inline bool can_support_ecm(struct usb_gadget *gadget)
 {
-       if (!gadget_supports_altsettings(gadget))
+       if (!gadget_is_altset_supported(gadget))
                return false;
 
        /* Everything else is *presumably* fine ... but this is a bit
index fe386df6dd3e67843c597ee0301298a01c490ee7..5c2ac8e8456d83cf4c7c462cb45eb5475932c8ad 100644 (file)
@@ -21,8 +21,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
-#include "gadget_chips.h"
-
 #define FILE_PCM_PLAYBACK      "/dev/snd/pcmC0D0p"
 #define FILE_PCM_CAPTURE       "/dev/snd/pcmC0D0c"
 #define FILE_CONTROL           "/dev/snd/controlC0"
index d5a7102de696611ea45124796610a20f9fb033cd..4d682ad7bf23de10b714ce46a28a312130f37f9c 100644 (file)
@@ -339,6 +339,7 @@ config USB_CDC_COMPOSITE
 config USB_G_NOKIA
        tristate "Nokia composite gadget"
        depends on PHONET
+       depends on BLOCK
        select USB_LIBCOMPOSITE
        select USB_U_SERIAL
        select USB_U_ETHER
@@ -346,6 +347,7 @@ config USB_G_NOKIA
        select USB_F_OBEX
        select USB_F_PHONET
        select USB_F_ECM
+       select USB_F_MASS_STORAGE
        help
          The Nokia composite gadget provides support for acm, obex
          and phonet in only one composite gadget driver.
index 1194b09ae7462638d689eb99af6a15bd209c9e9e..4b158e2d1e57b829b19c8eb30c3cf8cadb6d32c4 100644 (file)
@@ -58,21 +58,7 @@ static struct usb_device_descriptor device_desc = {
        /*.bNumConfigurations = DYNAMIC*/
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /*
-        * REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 /* string IDs are assigned dynamically */
 static struct usb_string strings_dev[] = {
@@ -200,10 +186,6 @@ static int acm_ms_bind(struct usb_composite_dev *cdev)
        if (status)
                goto fail;
 
-       status = fsg_common_set_nluns(opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
        status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
        if (status)
                goto fail_set_cdev;
@@ -225,10 +207,21 @@ static int acm_ms_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto fail_string_ids;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* register our configuration */
        status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
        if (status < 0)
-               goto fail_string_ids;
+               goto fail_otg_desc;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
@@ -236,11 +229,12 @@ static int acm_ms_bind(struct usb_composite_dev *cdev)
        return 0;
 
        /* error recovery */
+fail_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail_string_ids:
        fsg_common_remove_luns(opts->common);
 fail_set_cdev:
-       fsg_common_free_luns(opts->common);
-fail_set_nluns:
        fsg_common_free_buffers(opts->common);
 fail:
        usb_put_function_instance(fi_msg);
@@ -255,6 +249,9 @@ static int acm_ms_unbind(struct usb_composite_dev *cdev)
        usb_put_function_instance(fi_msg);
        usb_put_function(f_acm);
        usb_put_function_instance(f_acm_inst);
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index f289caf18a45341dc613a676345bfe8eeb51ee8e..685cf3b4b78f8b47c3ea110bafc7637ec043c8d0 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/usb/composite.h>
 
-#include "gadget_chips.h"
 #define DRIVER_DESC            "Linux USB Audio Gadget"
 #define DRIVER_VERSION         "Feb 2, 2012"
 
@@ -124,7 +123,7 @@ static struct usb_device_descriptor device_desc = {
        .bLength =              sizeof device_desc,
        .bDescriptorType =      USB_DT_DEVICE,
 
-       .bcdUSB =               __constant_cpu_to_le16(0x200),
+       .bcdUSB =               cpu_to_le16(0x200),
 
 #ifdef CONFIG_GADGET_UAC1
        .bDeviceClass =         USB_CLASS_PER_INTERFACE,
@@ -141,8 +140,8 @@ static struct usb_device_descriptor device_desc = {
         * we support.  (As does bNumConfigurations.)  These values can
         * also be overridden by module parameters.
         */
-       .idVendor =             __constant_cpu_to_le16(AUDIO_VENDOR_NUM),
-       .idProduct =            __constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
+       .idVendor =             cpu_to_le16(AUDIO_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(AUDIO_PRODUCT_NUM),
        /* .bcdDevice = f(hardware) */
        /* .iManufacturer = DYNAMIC */
        /* .iProduct = DYNAMIC */
@@ -150,20 +149,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 /*-------------------------------------------------------------------------*/
 
@@ -259,14 +245,28 @@ static int audio_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+               if (!usb_desc)
+                       goto fail;
+               usb_otg_descriptor_init(cdev->gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
        if (status < 0)
-               goto fail;
+               goto fail_otg_desc;
        usb_composite_overwrite_options(cdev, &coverwrite);
 
        INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
        return 0;
 
+fail_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail:
 #ifndef CONFIG_GADGET_UAC1
        usb_put_function_instance(fi_uac2);
@@ -289,6 +289,9 @@ static int audio_unbind(struct usb_composite_dev *cdev)
        if (!IS_ERR_OR_NULL(fi_uac2))
                usb_put_function_instance(fi_uac2);
 #endif
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index afd3e37921a7d9f1cc879cda5fe64ac5f940b6fa..ecd8c8d62f2e9334062f68dce67a071765cdab7d 100644 (file)
@@ -60,21 +60,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
+static const struct usb_descriptor_header *otg_desc[2];
 
 /* string IDs are assigned dynamically */
 static struct usb_string strings_dev[] = {
@@ -193,10 +179,21 @@ static int cdc_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto fail1;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* register our configuration */
        status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
        if (status < 0)
-               goto fail1;
+               goto fail2;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
@@ -204,6 +201,9 @@ static int cdc_bind(struct usb_composite_dev *cdev)
 
        return 0;
 
+fail2:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail1:
        usb_put_function_instance(fi_serial);
 fail:
@@ -219,6 +219,9 @@ static int cdc_unbind(struct usb_composite_dev *cdev)
                usb_put_function(f_ecm);
        if (!IS_ERR_OR_NULL(fi_ecm))
                usb_put_function_instance(fi_ecm);
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index 204b10b1a7e7dd08c36bc00d44205e0c6753b1c2..5231a32aef55a4c6640a772038a260b76d7bf2b6 100644 (file)
@@ -35,10 +35,10 @@ static struct dbgp {
 static struct usb_device_descriptor device_desc = {
        .bLength = sizeof device_desc,
        .bDescriptorType = USB_DT_DEVICE,
-       .bcdUSB = __constant_cpu_to_le16(0x0200),
+       .bcdUSB = cpu_to_le16(0x0200),
        .bDeviceClass = USB_CLASS_VENDOR_SPEC,
-       .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
-       .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
+       .idVendor = cpu_to_le16(DRIVER_VENDOR_ID),
+       .idProduct = cpu_to_le16(DRIVER_PRODUCT_ID),
        .bNumConfigurations = 1,
 };
 
@@ -251,7 +251,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
 
        dbgp.i_ep->driver_data = gadget;
        i_desc.wMaxPacketSize =
-               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+               cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
 
        dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
        if (!dbgp.o_ep) {
@@ -262,7 +262,7 @@ static int dbgp_configure_endpoints(struct usb_gadget *gadget)
 
        dbgp.o_ep->driver_data = gadget;
        o_desc.wMaxPacketSize =
-               __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
+               cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
 
        dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress;
        dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress;
index a3323dca218f9514b4c2a5e4319d9866c950d8e5..31e9160223e9aa772669ad4128f27729e6decef5 100644 (file)
@@ -171,20 +171,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 static struct usb_string strings_dev[] = {
        [USB_GADGET_MANUFACTURER_IDX].s = "",
@@ -416,17 +403,28 @@ static int eth_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto fail1;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* register our configuration(s); RNDIS first, if it's used */
        if (has_rndis()) {
                status = usb_add_config(cdev, &rndis_config_driver,
                                rndis_do_config);
                if (status < 0)
-                       goto fail1;
+                       goto fail2;
        }
 
        status = usb_add_config(cdev, &eth_config_driver, eth_do_config);
        if (status < 0)
-               goto fail1;
+               goto fail2;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
@@ -434,6 +432,9 @@ static int eth_bind(struct usb_composite_dev *cdev)
 
        return 0;
 
+fail2:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail1:
        if (has_rndis())
                usb_put_function_instance(fi_rndis);
@@ -463,6 +464,9 @@ static int eth_unbind(struct usb_composite_dev *cdev)
                usb_put_function(f_geth);
                usb_put_function_instance(fi_geth);
        }
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index e821931c965cd9203a8011358ffeb16844dc7eed..320a81b2baa688cb4bc9db1eaad1ca7435bfca23 100644 (file)
@@ -88,21 +88,7 @@ MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
 module_param_array_named(functions, func_names, charp, &func_num, 0);
 MODULE_PARM_DESC(functions, "USB Functions list");
 
-static const struct usb_descriptor_header *gfs_otg_desc[] = {
-       (const struct usb_descriptor_header *)
-       &(const struct usb_otg_descriptor) {
-               .bLength                = sizeof(struct usb_otg_descriptor),
-               .bDescriptorType        = USB_DT_OTG,
-
-               /*
-                * REVISIT SRP-only hardware is possible, although
-                * it would not be called "OTG" ...
-                */
-               .bmAttributes           = USB_OTG_SRP | USB_OTG_HNP,
-       },
-
-       NULL
-};
+static const struct usb_descriptor_header *gfs_otg_desc[2];
 
 /* String IDs are assigned dynamically */
 static struct usb_string gfs_strings[] = {
@@ -412,6 +398,17 @@ static int gfs_bind(struct usb_composite_dev *cdev)
                goto error_rndis;
        gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(cdev->gadget) && !gfs_otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+               if (!usb_desc)
+                       goto error_rndis;
+               usb_otg_descriptor_init(cdev->gadget, usb_desc);
+               gfs_otg_desc[0] = usb_desc;
+               gfs_otg_desc[1] = NULL;
+       }
+
        for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
                struct gfs_configuration *c = gfs_configurations + i;
                int sid = USB_GADGET_FIRST_AVAIL_IDX + i;
@@ -432,6 +429,8 @@ static int gfs_bind(struct usb_composite_dev *cdev)
 
 /* TODO */
 error_unbind:
+       kfree(gfs_otg_desc[0]);
+       gfs_otg_desc[0] = NULL;
 error_rndis:
 #ifdef CONFIG_USB_FUNCTIONFS_RNDIS
        usb_put_function_instance(fi_rndis);
@@ -473,6 +472,9 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
        for (i = 0; i < N_CONF * func_num; ++i)
                usb_put_function(*(f_ffs[0] + i));
 
+       kfree(gfs_otg_desc[0]);
+       gfs_otg_desc[0] = NULL;
+
        return 0;
 }
 
index da19c486b61e33a5b3214830f1c5db42ed979a75..8a18348ae86eef3807fabc066c12c143a1ac8da2 100644 (file)
@@ -35,8 +35,6 @@
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
-#include "gadget_chips.h"
-
 #include "u_midi.h"
 
 /*-------------------------------------------------------------------------*/
@@ -88,10 +86,10 @@ MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
 static struct usb_device_descriptor device_desc = {
        .bLength =              USB_DT_DEVICE_SIZE,
        .bDescriptorType =      USB_DT_DEVICE,
-       .bcdUSB =               __constant_cpu_to_le16(0x0200),
+       .bcdUSB =               cpu_to_le16(0x0200),
        .bDeviceClass =         USB_CLASS_PER_INTERFACE,
-       .idVendor =             __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
-       .idProduct =            __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+       .idVendor =             cpu_to_le16(DRIVER_VENDOR_NUM),
+       .idProduct =            cpu_to_le16(DRIVER_PRODUCT_NUM),
        /* .iManufacturer =     DYNAMIC */
        /* .iProduct =          DYNAMIC */
        .bNumConfigurations =   1,
index 2baa572686c6acbd5e1350ab167b65a367482302..7e5d2c48476e568021fa5c550040c999c3cfa7b0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/usb/composite.h>
 #include <linux/usb/g_hid.h>
 
-#include "gadget_chips.h"
 #define DRIVER_DESC            "HID Gadget"
 #define DRIVER_VERSION         "2010/03/16"
 
@@ -68,21 +67,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-
+static const struct usb_descriptor_header *otg_desc[2];
 
 /* string IDs are assigned dynamically */
 static struct usb_string strings_dev[] = {
@@ -186,16 +171,30 @@ static int hid_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto put;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* register our configuration */
        status = usb_add_config(cdev, &config_driver, do_config);
        if (status < 0)
-               goto put;
+               goto free_otg_desc;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 
        return 0;
 
+free_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 put:
        list_for_each_entry(m, &hidg_func_list, node) {
                if (m == n)
@@ -213,6 +212,10 @@ static int hid_unbind(struct usb_composite_dev *cdev)
                usb_put_function(n->f);
                usb_put_function_instance(n->fi);
        }
+
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index e7bfb081f111e4b60e55bce9ae5cd5f0743dad20..bda3c519110fe266dec569c4e85159499fa062d1 100644 (file)
@@ -64,21 +64,7 @@ static struct usb_device_descriptor msg_device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /*
-        * REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 static struct usb_string strings_dev[] = {
        [USB_GADGET_MANUFACTURER_IDX].s = "",
@@ -191,10 +177,6 @@ static int msg_bind(struct usb_composite_dev *cdev)
        if (status)
                goto fail;
 
-       status = fsg_common_set_nluns(opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
        fsg_common_set_ops(opts->common, &ops);
 
        status = fsg_common_set_cdev(opts->common, cdev, config.can_stall);
@@ -214,9 +196,20 @@ static int msg_bind(struct usb_composite_dev *cdev)
                goto fail_string_ids;
        msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+               if (!usb_desc)
+                       goto fail_string_ids;
+               usb_otg_descriptor_init(cdev->gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
        if (status < 0)
-               goto fail_string_ids;
+               goto fail_otg_desc;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&cdev->gadget->dev,
@@ -224,11 +217,12 @@ static int msg_bind(struct usb_composite_dev *cdev)
        set_bit(0, &msg_registered);
        return 0;
 
+fail_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail_string_ids:
        fsg_common_remove_luns(opts->common);
 fail_set_cdev:
-       fsg_common_free_luns(opts->common);
-fail_set_nluns:
        fsg_common_free_buffers(opts->common);
 fail:
        usb_put_function_instance(fi_msg);
@@ -243,6 +237,9 @@ static int msg_unbind(struct usb_composite_dev *cdev)
        if (!IS_ERR(fi_msg))
                usb_put_function_instance(fi_msg);
 
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index b21b51f0c9fadb27bbe319791ad970502eb88aa3..4fe794ddcd49ced2c4206c730b251be8a008352f 100644 (file)
@@ -78,21 +78,7 @@ static struct usb_device_descriptor device_desc = {
        .idProduct =            cpu_to_le16(MULTI_PRODUCT_NUM),
 };
 
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &(struct usb_otg_descriptor){
-               .bLength =              sizeof(struct usb_otg_descriptor),
-               .bDescriptorType =      USB_DT_OTG,
-
-               /*
-                * REVISIT SRP-only hardware is possible, although
-                * it would not be called "OTG" ...
-                */
-               .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-       },
-       NULL,
-};
-
+static const struct usb_descriptor_header *otg_desc[2];
 
 enum {
        MULTI_STRING_RNDIS_CONFIG_IDX = USB_GADGET_FIRST_AVAIL_IDX,
@@ -407,10 +393,6 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
        if (status)
                goto fail2;
 
-       status = fsg_common_set_nluns(fsg_opts->common, config.nluns);
-       if (status)
-               goto fail_set_nluns;
-
        status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall);
        if (status)
                goto fail_set_cdev;
@@ -429,14 +411,25 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
                goto fail_string_ids;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto fail_string_ids;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        /* register configurations */
        status = rndis_config_register(cdev);
        if (unlikely(status < 0))
-               goto fail_string_ids;
+               goto fail_otg_desc;
 
        status = cdc_config_register(cdev);
        if (unlikely(status < 0))
-               goto fail_string_ids;
+               goto fail_otg_desc;
        usb_composite_overwrite_options(cdev, &coverwrite);
 
        /* we're done */
@@ -445,11 +438,12 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
 
 
        /* error recovery */
+fail_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail_string_ids:
        fsg_common_remove_luns(fsg_opts->common);
 fail_set_cdev:
-       fsg_common_free_luns(fsg_opts->common);
-fail_set_nluns:
        fsg_common_free_buffers(fsg_opts->common);
 fail2:
        usb_put_function_instance(fi_msg);
@@ -490,6 +484,9 @@ static int multi_unbind(struct usb_composite_dev *cdev)
        usb_put_function(f_ecm);
        usb_put_function_instance(fi_ecm);
 #endif
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index 6ce7421412e9c14d7766210ab3442d06ca8f49d6..2bae4381332d57203f95713f03e8a1f7aba9c35d 100644 (file)
@@ -69,20 +69,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 /* string IDs are assigned dynamically */
 static struct usb_string strings_dev[] = {
@@ -171,16 +158,30 @@ static int gncm_bind(struct usb_composite_dev *cdev)
        device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;
 
+       if (gadget_is_otg(gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(gadget);
+               if (!usb_desc)
+                       goto fail;
+               usb_otg_descriptor_init(gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
+       }
+
        status = usb_add_config(cdev, &ncm_config_driver,
                                ncm_do_config);
        if (status < 0)
-               goto fail;
+               goto fail1;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        dev_info(&gadget->dev, "%s\n", DRIVER_DESC);
 
        return 0;
 
+fail1:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail:
        usb_put_function_instance(f_ncm_inst);
        return status;
@@ -192,6 +193,9 @@ static int gncm_unbind(struct usb_composite_dev *cdev)
                usb_put_function(f_ncm);
        if (!IS_ERR_OR_NULL(f_ncm_inst))
                usb_put_function_instance(f_ncm_inst);
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index 4bb498a38a1c01eb17077844bc163028c3e22b93..8b3f6fb1825d56a7266eeb5c09ce115e60f26be8 100644 (file)
@@ -23,7 +23,7 @@
 #include "u_ether.h"
 #include "u_phonet.h"
 #include "u_ecm.h"
-#include "gadget_chips.h"
+#include "f_mass_storage.h"
 
 /* Defines */
 
@@ -34,6 +34,29 @@ USB_GADGET_COMPOSITE_OPTIONS();
 
 USB_ETHERNET_MODULE_PARAMETERS();
 
+static struct fsg_module_parameters fsg_mod_data = {
+       .stall = 0,
+       .luns = 2,
+       .removable_count = 2,
+       .removable = { 1, 1, },
+};
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS;
+
+#else
+
+/*
+ * Number of buffers we will use.
+ * 2 is usually enough for good buffering pipeline
+ */
+#define fsg_num_buffers        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS
+
+#endif /* CONFIG_USB_DEBUG */
+
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
 #define NOKIA_VENDOR_ID                        0x0421  /* Nokia */
 #define NOKIA_PRODUCT_ID               0x01c8  /* Nokia Gadget */
 
@@ -66,10 +89,10 @@ static struct usb_gadget_strings *dev_strings[] = {
 static struct usb_device_descriptor device_desc = {
        .bLength                = USB_DT_DEVICE_SIZE,
        .bDescriptorType        = USB_DT_DEVICE,
-       .bcdUSB                 = __constant_cpu_to_le16(0x0200),
+       .bcdUSB                 = cpu_to_le16(0x0200),
        .bDeviceClass           = USB_CLASS_COMM,
-       .idVendor               = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
-       .idProduct              = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+       .idVendor               = cpu_to_le16(NOKIA_VENDOR_ID),
+       .idProduct              = cpu_to_le16(NOKIA_PRODUCT_ID),
        .bcdDevice              = cpu_to_le16(NOKIA_VERSION_NUM),
        /* .iManufacturer = DYNAMIC */
        /* .iProduct = DYNAMIC */
@@ -94,6 +117,8 @@ static struct usb_function *f_obex1_cfg2;
 static struct usb_function *f_obex2_cfg2;
 static struct usb_function *f_phonet_cfg1;
 static struct usb_function *f_phonet_cfg2;
+static struct usb_function *f_msg_cfg1;
+static struct usb_function *f_msg_cfg2;
 
 
 static struct usb_configuration nokia_config_500ma_driver = {
@@ -117,6 +142,7 @@ static struct usb_function_instance *fi_ecm;
 static struct usb_function_instance *fi_obex1;
 static struct usb_function_instance *fi_obex2;
 static struct usb_function_instance *fi_phonet;
+static struct usb_function_instance *fi_msg;
 
 static int nokia_bind_config(struct usb_configuration *c)
 {
@@ -125,6 +151,8 @@ static int nokia_bind_config(struct usb_configuration *c)
        struct usb_function *f_obex1 = NULL;
        struct usb_function *f_ecm;
        struct usb_function *f_obex2 = NULL;
+       struct usb_function *f_msg;
+       struct fsg_opts *fsg_opts;
        int status = 0;
        int obex1_stat = -1;
        int obex2_stat = -1;
@@ -160,6 +188,12 @@ static int nokia_bind_config(struct usb_configuration *c)
                goto err_get_ecm;
        }
 
+       f_msg = usb_get_function(fi_msg);
+       if (IS_ERR(f_msg)) {
+               status = PTR_ERR(f_msg);
+               goto err_get_msg;
+       }
+
        if (!IS_ERR_OR_NULL(f_phonet)) {
                phonet_stat = usb_add_function(c, f_phonet);
                if (phonet_stat)
@@ -187,21 +221,36 @@ static int nokia_bind_config(struct usb_configuration *c)
                pr_debug("could not bind ecm config %d\n", status);
                goto err_ecm;
        }
+
+       fsg_opts = fsg_opts_from_func_inst(fi_msg);
+
+       status = fsg_common_run_thread(fsg_opts->common);
+       if (status)
+               goto err_msg;
+
+       status = usb_add_function(c, f_msg);
+       if (status)
+               goto err_msg;
+
        if (c == &nokia_config_500ma_driver) {
                f_acm_cfg1 = f_acm;
                f_ecm_cfg1 = f_ecm;
                f_phonet_cfg1 = f_phonet;
                f_obex1_cfg1 = f_obex1;
                f_obex2_cfg1 = f_obex2;
+               f_msg_cfg1 = f_msg;
        } else {
                f_acm_cfg2 = f_acm;
                f_ecm_cfg2 = f_ecm;
                f_phonet_cfg2 = f_phonet;
                f_obex1_cfg2 = f_obex1;
                f_obex2_cfg2 = f_obex2;
+               f_msg_cfg2 = f_msg;
        }
 
        return status;
+err_msg:
+       usb_remove_function(c, f_ecm);
 err_ecm:
        usb_remove_function(c, f_acm);
 err_conf:
@@ -211,6 +260,8 @@ err_conf:
                usb_remove_function(c, f_obex1);
        if (!phonet_stat)
                usb_remove_function(c, f_phonet);
+       usb_put_function(f_msg);
+err_get_msg:
        usb_put_function(f_ecm);
 err_get_ecm:
        usb_put_function(f_acm);
@@ -227,6 +278,8 @@ err_get_acm:
 static int nokia_bind(struct usb_composite_dev *cdev)
 {
        struct usb_gadget       *gadget = cdev->gadget;
+       struct fsg_opts         *fsg_opts;
+       struct fsg_config       fsg_config;
        int                     status;
 
        status = usb_string_ids_tab(cdev, strings_dev);
@@ -238,7 +291,7 @@ static int nokia_bind(struct usb_composite_dev *cdev)
        nokia_config_500ma_driver.iConfiguration = status;
        nokia_config_100ma_driver.iConfiguration = status;
 
-       if (!gadget_supports_altsettings(gadget)) {
+       if (!gadget_is_altset_supported(gadget)) {
                status = -ENODEV;
                goto err_usb;
        }
@@ -267,11 +320,42 @@ static int nokia_bind(struct usb_composite_dev *cdev)
                goto err_acm_inst;
        }
 
+       fi_msg = usb_get_function_instance("mass_storage");
+       if (IS_ERR(fi_msg)) {
+               status = PTR_ERR(fi_msg);
+               goto err_ecm_inst;
+       }
+
+       /* set up mass storage function */
+       fsg_config_from_params(&fsg_config, &fsg_mod_data, fsg_num_buffers);
+       fsg_config.vendor_name = "Nokia";
+       fsg_config.product_name = "N900";
+
+       fsg_opts = fsg_opts_from_func_inst(fi_msg);
+       fsg_opts->no_configfs = true;
+
+       status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers);
+       if (status)
+               goto err_msg_inst;
+
+       status = fsg_common_set_cdev(fsg_opts->common, cdev, fsg_config.can_stall);
+       if (status)
+               goto err_msg_buf;
+
+       fsg_common_set_sysfs(fsg_opts->common, true);
+
+       status = fsg_common_create_luns(fsg_opts->common, &fsg_config);
+       if (status)
+               goto err_msg_buf;
+
+       fsg_common_set_inquiry_string(fsg_opts->common, fsg_config.vendor_name,
+                                     fsg_config.product_name);
+
        /* finally register the configuration */
        status = usb_add_config(cdev, &nokia_config_500ma_driver,
                        nokia_bind_config);
        if (status < 0)
-               goto err_ecm_inst;
+               goto err_msg_luns;
 
        status = usb_add_config(cdev, &nokia_config_100ma_driver,
                        nokia_bind_config);
@@ -292,6 +376,12 @@ err_put_cfg1:
        if (!IS_ERR_OR_NULL(f_phonet_cfg1))
                usb_put_function(f_phonet_cfg1);
        usb_put_function(f_ecm_cfg1);
+err_msg_luns:
+       fsg_common_remove_luns(fsg_opts->common);
+err_msg_buf:
+       fsg_common_free_buffers(fsg_opts->common);
+err_msg_inst:
+       usb_put_function_instance(fi_msg);
 err_ecm_inst:
        usb_put_function_instance(fi_ecm);
 err_acm_inst:
@@ -325,7 +415,10 @@ static int nokia_unbind(struct usb_composite_dev *cdev)
        usb_put_function(f_acm_cfg2);
        usb_put_function(f_ecm_cfg1);
        usb_put_function(f_ecm_cfg2);
+       usb_put_function(f_msg_cfg1);
+       usb_put_function(f_msg_cfg2);
 
+       usb_put_function_instance(fi_msg);
        usb_put_function_instance(fi_ecm);
        if (!IS_ERR(fi_obex2))
                usb_put_function_instance(fi_obex2);
index 1ce7df1060a5b237ae2532f514d95e3edd63cf34..a22d30a4def1e0406512608d22aec7eaefd67561 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/g_printer.h>
 
-#include "gadget_chips.h"
-
 USB_GADGET_COMPOSITE_OPTIONS();
 
 #define DRIVER_DESC            "Printer Gadget"
@@ -82,16 +80,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-       .bmAttributes =         USB_OTG_SRP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 /*-------------------------------------------------------------------------*/
 
@@ -136,7 +125,6 @@ static int printer_do_config(struct usb_configuration *c)
        usb_gadget_set_selfpowered(gadget);
 
        if (gadget_is_otg(gadget)) {
-               otg_descriptor.bmAttributes |= USB_OTG_HNP;
                printer_cfg_driver.descriptors = otg_desc;
                printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
@@ -174,21 +162,39 @@ static int printer_bind(struct usb_composite_dev *cdev)
        opts->q_len = QLEN;
 
        ret = usb_string_ids_tab(cdev, strings);
-       if (ret < 0) {
-               usb_put_function_instance(fi_printer);
-               return ret;
-       }
+       if (ret < 0)
+               goto fail_put_func_inst;
+
        device_desc.iManufacturer = strings[USB_GADGET_MANUFACTURER_IDX].id;
        device_desc.iProduct = strings[USB_GADGET_PRODUCT_IDX].id;
        device_desc.iSerialNumber = strings[USB_GADGET_SERIAL_IDX].id;
 
-       ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config);
-       if (ret) {
-               usb_put_function_instance(fi_printer);
-               return ret;
+       if (gadget_is_otg(cdev->gadget) && !otg_desc[0]) {
+               struct usb_descriptor_header *usb_desc;
+
+               usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+               if (!usb_desc) {
+                       ret = -ENOMEM;
+                       goto fail_put_func_inst;
+               }
+               usb_otg_descriptor_init(cdev->gadget, usb_desc);
+               otg_desc[0] = usb_desc;
+               otg_desc[1] = NULL;
        }
+
+       ret = usb_add_config(cdev, &printer_cfg_driver, printer_do_config);
+       if (ret)
+               goto fail_free_otg_desc;
+
        usb_composite_overwrite_options(cdev, &coverwrite);
        return ret;
+
+fail_free_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+fail_put_func_inst:
+       usb_put_function_instance(fi_printer);
+       return ret;
 }
 
 static int printer_unbind(struct usb_composite_dev *cdev)
@@ -196,6 +202,9 @@ static int printer_unbind(struct usb_composite_dev *cdev)
        usb_put_function(f_printer);
        usb_put_function_instance(fi_printer);
 
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index 8b7528f9b78eff02a7d20bca4122429d6294be6d..c5d42e0347a94cbd190c7162626ec9177f130662 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/tty_flip.h>
 
 #include "u_serial.h"
-#include "gadget_chips.h"
 
 
 /* Defines */
@@ -79,20 +78,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   1,
 };
 
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
+static const struct usb_descriptor_header *otg_desc[2];
 
 /*-------------------------------------------------------------------------*/
 
@@ -191,6 +177,18 @@ static int gs_bind(struct usb_composite_dev *cdev)
        serial_config_driver.iConfiguration = status;
 
        if (gadget_is_otg(cdev->gadget)) {
+               if (!otg_desc[0]) {
+                       struct usb_descriptor_header *usb_desc;
+
+                       usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+                       if (!usb_desc) {
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+                       usb_otg_descriptor_init(cdev->gadget, usb_desc);
+                       otg_desc[0] = usb_desc;
+                       otg_desc[1] = NULL;
+               }
                serial_config_driver.descriptors = otg_desc;
                serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        }
@@ -208,13 +206,15 @@ static int gs_bind(struct usb_composite_dev *cdev)
                                "gser");
        }
        if (status < 0)
-               goto fail;
+               goto fail1;
 
        usb_composite_overwrite_options(cdev, &coverwrite);
        INFO(cdev, "%s\n", GS_VERSION_NAME);
 
        return 0;
-
+fail1:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 fail:
        return status;
 }
@@ -227,6 +227,10 @@ static int gs_unbind(struct usb_composite_dev *cdev)
                usb_put_function(f_serial[i]);
                usb_put_function_instance(fi_serial[i]);
        }
+
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index c986e8addb90ac809428f780e04cfb9242c22a90..37a410056fed2c8298211fe1491aef7765e283a5 100644 (file)
@@ -121,24 +121,7 @@ static struct usb_device_descriptor device_desc = {
        .bNumConfigurations =   2,
 };
 
-#ifdef CONFIG_USB_OTG
-static struct usb_otg_descriptor otg_descriptor = {
-       .bLength =              sizeof otg_descriptor,
-       .bDescriptorType =      USB_DT_OTG,
-
-       /* REVISIT SRP-only hardware is possible, although
-        * it would not be called "OTG" ...
-        */
-       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
-};
-
-static const struct usb_descriptor_header *otg_desc[] = {
-       (struct usb_descriptor_header *) &otg_descriptor,
-       NULL,
-};
-#else
-#define otg_desc       NULL
-#endif
+static const struct usb_descriptor_header *otg_desc[2];
 
 /* string IDs are assigned dynamically */
 /* default serial number takes at least two packets */
@@ -341,6 +324,18 @@ static int zero_bind(struct usb_composite_dev *cdev)
 
        /* support OTG systems */
        if (gadget_is_otg(cdev->gadget)) {
+               if (!otg_desc[0]) {
+                       struct usb_descriptor_header *usb_desc;
+
+                       usb_desc = usb_otg_descriptor_alloc(cdev->gadget);
+                       if (!usb_desc) {
+                               status = -ENOMEM;
+                               goto err_conf_flb;
+                       }
+                       usb_otg_descriptor_init(cdev->gadget, usb_desc);
+                       otg_desc[0] = usb_desc;
+                       otg_desc[1] = NULL;
+               }
                sourcesink_driver.descriptors = otg_desc;
                sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
                loopback_driver.descriptors = otg_desc;
@@ -359,12 +354,12 @@ static int zero_bind(struct usb_composite_dev *cdev)
        }
        status = usb_add_function(&sourcesink_driver, func_ss);
        if (status)
-               goto err_conf_flb;
+               goto err_free_otg_desc;
 
        usb_ep_autoconfig_reset(cdev->gadget);
        status = usb_add_function(&loopback_driver, func_lb);
        if (status)
-               goto err_conf_flb;
+               goto err_free_otg_desc;
 
        usb_ep_autoconfig_reset(cdev->gadget);
        usb_composite_overwrite_options(cdev, &coverwrite);
@@ -373,6 +368,9 @@ static int zero_bind(struct usb_composite_dev *cdev)
 
        return 0;
 
+err_free_otg_desc:
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
 err_conf_flb:
        usb_put_function(func_lb);
        func_lb = NULL;
@@ -397,6 +395,9 @@ static int zero_unbind(struct usb_composite_dev *cdev)
        if (!IS_ERR_OR_NULL(func_lb))
                usb_put_function(func_lb);
        usb_put_function_instance(func_inst_lb);
+       kfree(otg_desc[0]);
+       otg_desc[0] = NULL;
+
        return 0;
 }
 
index de7e5e2ccf1c8956fcce928901e4a7cc1b4a4d09..fdacddb18c006c6d0cdaaf6b51ce3b962675275e 100644 (file)
@@ -138,15 +138,82 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
 
 /* endpoint names used for print */
 static const char ep0_string[] = "ep0in";
-static const char *const ep_string[] = {
-       ep0_string,
-       "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
-       "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
-       "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
-       "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
-       "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
-       "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
-       "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} ep_info[] = {
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
+
+       EP_INFO(ep0_string,
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep1in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep2in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep3in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep4in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep5in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep6in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep7in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep8in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep9in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep10in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep11in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep12in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep13in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep14in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep15in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep0out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep1out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep2out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep3out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep4out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep5out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep6out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep7out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep8out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep9out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep10out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep11out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep12out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep13out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep14out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep15out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+
+#undef EP_INFO
 };
 
 /* DMA usage flag */
@@ -1517,7 +1584,8 @@ static void udc_setup_endpoints(struct udc *dev)
        for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
                ep = &dev->ep[tmp];
                ep->dev = dev;
-               ep->ep.name = ep_string[tmp];
+               ep->ep.name = ep_info[tmp].name;
+               ep->ep.caps = ep_info[tmp].caps;
                ep->num = tmp;
                /* txfifo size is calculated at enable time */
                ep->txfifo = dev->txfifo;
index fc4226462f8f5da2f71741a77093b7d69343afe3..d0d18947f58bfdf4147057107d0c36cd2ca20063 100644 (file)
 #define        DRIVER_VERSION  "3 May 2006"
 
 static const char driver_name [] = "at91_udc";
-static const char * const ep_names[] = {
-       "ep0",
-       "ep1",
-       "ep2",
-       "ep3-int",
-       "ep4",
-       "ep5",
+
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} ep_info[] = {
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
+
+       EP_INFO("ep0",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep1",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep2",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep3-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep4",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep5",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+
+#undef EP_INFO
 };
-#define ep0name                ep_names[0]
+
+#define ep0name                ep_info[0].name
 
 #define VBUS_POLL_TIMEOUT      msecs_to_jiffies(1000)
 
@@ -825,6 +844,7 @@ static void udc_reinit(struct at91_udc *udc)
 
        INIT_LIST_HEAD(&udc->gadget.ep_list);
        INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+       udc->gadget.quirk_stall_not_supp = 1;
 
        for (i = 0; i < NUM_ENDPOINTS; i++) {
                struct at91_ep *ep = &udc->ep[i];
@@ -1830,7 +1850,8 @@ static int at91udc_probe(struct platform_device *pdev)
 
        for (i = 0; i < NUM_ENDPOINTS; i++) {
                ep = &udc->ep[i];
-               ep->ep.name = ep_names[i];
+               ep->ep.name = ep_info[i].name;
+               ep->ep.caps = ep_info[i].caps;
                ep->ep.ops = &at91_ep_ops;
                ep->udc = udc;
                ep->int_mask = BIT(i);
index 4095cce05e6a729ccf86ff5f6394e55f7cf0511f..267d84f838e156d235212fe136a9d97b3225db03 100644 (file)
@@ -1989,6 +1989,10 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
                ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
 
                ret = of_property_read_string(pp, "name", &name);
+               if (ret) {
+                       dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
+                       goto err;
+               }
                ep->ep.name = name;
 
                ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
@@ -2063,6 +2067,17 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,
                ep->can_dma = pdata->ep[i].can_dma;
                ep->can_isoc = pdata->ep[i].can_isoc;
 
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = ep->can_isoc;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
+
                if (i)
                        list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
        }
index 9db968ba39f54aec7f102a2948ec00cc326094c6..8cbb00325824a480b9c5558202cb74d55e9d81b8 100644 (file)
 #define DRV_MODULE_NAME                "bcm63xx_udc"
 
 static const char bcm63xx_ep0name[] = "ep0";
-static const char *const bcm63xx_ep_name[] = {
-       bcm63xx_ep0name,
-       "ep1in-bulk", "ep2out-bulk", "ep3in-int", "ep4out-int",
+
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} bcm63xx_ep_info[] = {
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
+
+       EP_INFO(bcm63xx_ep0name,
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep1in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep2out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep3in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep4out-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_OUT)),
+
+#undef EP_INFO
 };
 
 static bool use_fullspeed;
@@ -943,7 +963,8 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)
        for (i = 0; i < BCM63XX_NUM_EP; i++) {
                struct bcm63xx_ep *bep = &udc->bep[i];
 
-               bep->ep.name = bcm63xx_ep_name[i];
+               bep->ep.name = bcm63xx_ep_info[i].name;
+               bep->ep.caps = bcm63xx_ep_info[i].caps;
                bep->ep_num = i;
                bep->ep.ops = &bcm63xx_udc_ep_ops;
                list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);
index 1efa61265d8d49c5116027c8e3555ae70b9cc12c..d1b81539d6320b3baed7c5bc9bc4cdde7440aee9 100644 (file)
@@ -1952,12 +1952,18 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir)
        ep->bdc = bdc;
        ep->dir = dir;
 
+       if (dir)
+               ep->usb_ep.caps.dir_in = true;
+       else
+               ep->usb_ep.caps.dir_out = true;
+
        /* ep->ep_num is the index inside bdc_ep */
        if (epnum == 1) {
                ep->ep_num = 1;
                bdc->bdc_ep_array[ep->ep_num] = ep;
                snprintf(ep->name, sizeof(ep->name), "ep%d", epnum - 1);
                usb_ep_set_maxpacket_limit(&ep->usb_ep, EP0_MAX_PKT_SIZE);
+               ep->usb_ep.caps.type_control = true;
                ep->comp_desc = NULL;
                bdc->gadget.ep0 = &ep->usb_ep;
        } else {
@@ -1971,6 +1977,9 @@ static int init_ep(struct bdc *bdc, u32 epnum, u32 dir)
                         dir & 1 ? "in" : "out");
 
                usb_ep_set_maxpacket_limit(&ep->usb_ep, 1024);
+               ep->usb_ep.caps.type_iso = true;
+               ep->usb_ep.caps.type_bulk = true;
+               ep->usb_ep.caps.type_int = true;
                ep->usb_ep.max_streams = 0;
                list_add_tail(&ep->usb_ep.ep_list, &bdc->gadget.ep_list);
        }
index 181112c88f430d39985c199312b2043337c02cf6..1379ad40d864bd42308f0c336fe931e8c757355e 100644 (file)
@@ -127,23 +127,87 @@ static inline struct dummy_request *usb_request_to_dummy_request
 
 static const char ep0name[] = "ep0";
 
-static const char *const ep_name[] = {
-       ep0name,                                /* everyone has ep0 */
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} ep_info[] = {
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
 
+       /* everyone has ep0 */
+       EP_INFO(ep0name,
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
        /* act like a pxa250: fifteen fixed function endpoints */
-       "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
-       "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
-       "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
-               "ep15in-int",
-
+       EP_INFO("ep1in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep2out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep3in-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep4out-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep5in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep6in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep7out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep8in-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep9out-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep10in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep11in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep12out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep13in-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep14out-iso",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep15in-int",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
        /* or like sa1100: two fixed function endpoints */
-       "ep1out-bulk", "ep2in-bulk",
-
+       EP_INFO("ep1out-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep2in-bulk",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
        /* and now some generic EPs so we have enough in multi config */
-       "ep3out", "ep4in", "ep5out", "ep6out", "ep7in", "ep8out", "ep9in",
-       "ep10out", "ep11out", "ep12in", "ep13out", "ep14in", "ep15out",
+       EP_INFO("ep3out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep4in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep5out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep6out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep7in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep8out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep9in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep10out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep11out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep12in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep13out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep14in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep15out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+
+#undef EP_INFO
 };
-#define DUMMY_ENDPOINTS        ARRAY_SIZE(ep_name)
+
+#define DUMMY_ENDPOINTS        ARRAY_SIZE(ep_info)
 
 /*-------------------------------------------------------------------------*/
 
@@ -938,9 +1002,10 @@ static void init_dummy_udc_hw(struct dummy *dum)
        for (i = 0; i < DUMMY_ENDPOINTS; i++) {
                struct dummy_ep *ep = &dum->ep[i];
 
-               if (!ep_name[i])
+               if (!ep_info[i].name)
                        break;
-               ep->ep.name = ep_name[i];
+               ep->ep.name = ep_info[i].name;
+               ep->ep.caps = ep_info[i].caps;
                ep->ep.ops = &dummy_ep_ops;
                list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
                ep->halted = ep->wedged = ep->already_seen =
@@ -1684,7 +1749,7 @@ static void dummy_timer(unsigned long _dum_hcd)
        }
 
        for (i = 0; i < DUMMY_ENDPOINTS; i++) {
-               if (!ep_name[i])
+               if (!ep_info[i].name)
                        break;
                dum->ep[i].already_seen = 0;
        }
index 1137e3384218c11e738b88067f01fd8ee4105f25..6ba122cc7490b42acd0d9b004283e4d26f48c167 100644 (file)
@@ -384,25 +384,15 @@ static void fotg210_ep0_queue(struct fotg210_ep *ep,
                return;
        }
        if (ep->dir_in) { /* if IN */
-               if (req->req.length) {
-                       fotg210_start_dma(ep, req);
-               } else {
-                       pr_err("%s : req->req.length = 0x%x\n",
-                              __func__, req->req.length);
-               }
+               fotg210_start_dma(ep, req);
                if ((req->req.length == req->req.actual) ||
                    (req->req.actual < ep->ep.maxpacket))
                        fotg210_done(ep, req, 0);
        } else { /* OUT */
-               if (!req->req.length) {
-                       fotg210_done(ep, req, 0);
-               } else {
-                       u32 value = ioread32(ep->fotg210->reg +
-                                               FOTG210_DMISGR0);
+               u32 value = ioread32(ep->fotg210->reg + FOTG210_DMISGR0);
 
-                       value &= ~DMISGR0_MCX_OUT_INT;
-                       iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0);
-               }
+               value &= ~DMISGR0_MCX_OUT_INT;
+               iowrite32(value, ep->fotg210->reg + FOTG210_DMISGR0);
        }
 }
 
@@ -1153,6 +1143,17 @@ static int fotg210_udc_probe(struct platform_device *pdev)
                ep->ep.name = fotg210_ep_name[i];
                ep->ep.ops = &fotg210_ep_ops;
                usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
+
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
        usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);
        fotg210->gadget.ep0 = &fotg210->ep[0]->ep;
index e0822f1b6639dfd699e212dccdf8d52ec7aa94bc..5fb6f8b4f0b4889f51d1686610ab07b40cc9bdc0 100644 (file)
@@ -2417,6 +2417,17 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
        strcpy(ep->name, ep_name[pipe_num]);
        ep->ep.name = ep_name[pipe_num];
 
+       if (pipe_num == 0) {
+               ep->ep.caps.type_control = true;
+       } else {
+               ep->ep.caps.type_iso = true;
+               ep->ep.caps.type_bulk = true;
+               ep->ep.caps.type_int = true;
+       }
+
+       ep->ep.caps.dir_in = true;
+       ep->ep.caps.dir_out = true;
+
        ep->ep.ops = &qe_ep_ops;
        ep->stopped = 1;
        usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
index c60022b46a4835b4cc2b151b7a46193fe0f5554b..aab5221d6c2e35050edccaaa170f960f90c40887 100644 (file)
@@ -2313,6 +2313,19 @@ static int struct_ep_setup(struct fsl_udc *udc, unsigned char index,
        ep->ep.ops = &fsl_ep_ops;
        ep->stopped = 0;
 
+       if (index == 0) {
+               ep->ep.caps.type_control = true;
+       } else {
+               ep->ep.caps.type_iso = true;
+               ep->ep.caps.type_bulk = true;
+               ep->ep.caps.type_int = true;
+       }
+
+       if (index & 1)
+               ep->ep.caps.dir_in = true;
+       else
+               ep->ep.caps.dir_out = true;
+
        /* for ep0: maxP defined in desc
         * for other eps, maxP is set by epautoconfig() called by gadget layer
         */
index 3970f453de4903fb55c21831e4cb511b2a2afc11..948845c90e47d3cf3333511f74673b2d7cd62daf 100644 (file)
@@ -1450,6 +1450,17 @@ static int fusb300_probe(struct platform_device *pdev)
                ep->ep.name = fusb300_ep_name[i];
                ep->ep.ops = &fusb300_ep_ops;
                usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);
+
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
        usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);
        fusb300->ep[0]->epnum = 0;
diff --git a/drivers/usb/gadget/udc/gadget_chips.h b/drivers/usb/gadget/udc/gadget_chips.h
deleted file mode 100644 (file)
index bcd04bc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * USB device controllers have lots of quirks.  Use these macros in
- * gadget drivers or other code that needs to deal with them, and which
- * autoconfigures instead of using early binding to the hardware.
- *
- * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by
- * some config file that gets updated as new hardware is supported.
- * (And avoiding all runtime comparisons in typical one-choice configs!)
- *
- * NOTE:  some of these controller drivers may not be available yet.
- * Some are available on 2.4 kernels; several are available, but not
- * yet pushed in the 2.6 mainline tree.
- */
-
-#ifndef __GADGET_CHIPS_H
-#define __GADGET_CHIPS_H
-
-#include <linux/usb/gadget.h>
-
-/*
- * NOTICE: the entries below are alphabetical and should be kept
- * that way.
- *
- * Always be sure to add new entries to the correct position or
- * accept the bashing later.
- *
- * If you have forgotten the alphabetical order let VIM/EMACS
- * do that for you.
- */
-#define gadget_is_at91(g)              (!strcmp("at91_udc", (g)->name))
-#define gadget_is_goku(g)              (!strcmp("goku_udc", (g)->name))
-#define gadget_is_musbhdrc(g)          (!strcmp("musb-hdrc", (g)->name))
-#define gadget_is_net2280(g)           (!strcmp("net2280", (g)->name))
-#define gadget_is_pxa(g)               (!strcmp("pxa25x_udc", (g)->name))
-#define gadget_is_pxa27x(g)            (!strcmp("pxa27x_udc", (g)->name))
-
-/**
- * gadget_supports_altsettings - return true if altsettings work
- * @gadget: the gadget in question
- */
-static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
-{
-       /* PXA 21x/25x/26x has no altsettings at all */
-       if (gadget_is_pxa(gadget))
-               return false;
-
-       /* PXA 27x and 3xx have *broken* altsetting support */
-       if (gadget_is_pxa27x(gadget))
-               return false;
-
-       /* Everything else is *presumably* fine ... */
-       return true;
-}
-
-#endif /* __GADGET_CHIPS_H */
index 9e8d842e8c08546ed1fe109a3586da6b3c4ee102..1fdfec14a3ba13eea57dfced8b170752e452fdb2 100644 (file)
@@ -990,6 +990,35 @@ static int goku_get_frame(struct usb_gadget *_gadget)
        return -EOPNOTSUPP;
 }
 
+static struct usb_ep *goku_match_ep(struct usb_gadget *g,
+               struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp)
+{
+       struct goku_udc *dev = to_goku_udc(g);
+       struct usb_ep *ep;
+
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_INT:
+               /* single buffering is enough */
+               ep = &dev->ep[3].ep;
+               if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp))
+                       return ep;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (usb_endpoint_dir_in(desc)) {
+                       /* DMA may be available */
+                       ep = &dev->ep[2].ep;
+                       if (usb_gadget_ep_match_desc(g, ep, desc, ep_comp))
+                               return ep;
+               }
+               break;
+       default:
+               /* nothing */ ;
+       }
+
+       return NULL;
+}
+
 static int goku_udc_start(struct usb_gadget *g,
                struct usb_gadget_driver *driver);
 static int goku_udc_stop(struct usb_gadget *g);
@@ -998,6 +1027,7 @@ static const struct usb_gadget_ops goku_ops = {
        .get_frame      = goku_get_frame,
        .udc_start      = goku_udc_start,
        .udc_stop       = goku_udc_stop,
+       .match_ep       = goku_match_ep,
        // no remote wakeup
        // not selfpowered
 };
@@ -1257,6 +1287,14 @@ static void udc_reinit (struct goku_udc *dev)
                INIT_LIST_HEAD (&ep->queue);
 
                ep_reset(NULL, ep);
+
+               if (i == 0)
+                       ep->ep.caps.type_control = true;
+               else
+                       ep->ep.caps.type_bulk = true;
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
 
        dev->ep[0].reg_mode = NULL;
index c8868870e21770782cf9049b4a8bdbcc80cf9a00..8aa2593c2c3633a7e9e81131f93a8c88f1ebb951 100644 (file)
@@ -2018,12 +2018,23 @@ static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit)
 
                usb_ep_set_maxpacket_limit(&ep->ep, MAX_CTRL_PL_SIZE);
                ep->bytes_per_buffer = MAX_CTRL_PL_SIZE;
+
+               ep->ep.caps.type_control = true;
        } else {
                usb_ep_set_maxpacket_limit(&ep->ep, (u16)maxplimit);
                list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+               ep->ep.caps.type_iso = true;
+               ep->ep.caps.type_bulk = true;
+               ep->ep.caps.type_int = true;
        }
        list_add_tail(&ep->ep_list, &dev->ep_list);
 
+       if (is_in)
+               ep->ep.caps.dir_in = true;
+       else
+               ep->ep.caps.dir_out = true;
+
        ep->tailbuf = dma_alloc_coherent(dev->dev, ep->ep.maxpacket_limit,
                                         &ep->tailbuf_paddr, GFP_ATOMIC);
        if (!ep->tailbuf)
index 3b6a7852822d4aca3832876dabae212241268efd..00b5006baf154f82885428c333a31720c98edd6a 100644 (file)
@@ -2575,6 +2575,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep0",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 0,
@@ -2586,6 +2588,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep1-int",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 2,
@@ -2597,6 +2601,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep2-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 4,
@@ -2608,6 +2614,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep3-iso",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 1023,
                .hwep_num_base  = 6,
@@ -2619,6 +2627,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep4-int",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 8,
@@ -2630,6 +2640,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep5-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 10,
@@ -2641,6 +2653,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep6-iso",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 1023,
                .hwep_num_base  = 12,
@@ -2652,6 +2666,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep7-int",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 14,
@@ -2663,6 +2679,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep8-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 16,
@@ -2674,6 +2692,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep9-iso",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 1023,
                .hwep_num_base  = 18,
@@ -2685,6 +2705,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep10-int",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 20,
@@ -2696,6 +2718,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep11-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 22,
@@ -2707,6 +2731,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep12-iso",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 1023,
                .hwep_num_base  = 24,
@@ -2718,6 +2744,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep13-int",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_INT,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 26,
@@ -2729,6 +2757,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep14-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 64,
                .hwep_num_base  = 28,
@@ -2740,6 +2770,8 @@ static const struct lpc32xx_udc controller_template = {
                .ep = {
                        .name   = "ep15-bulk",
                        .ops    = &lpc32xx_ep_ops,
+                       .caps   = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                       USB_EP_CAPS_DIR_ALL),
                },
                .maxpacket      = 1023,
                .hwep_num_base  = 30,
index 309706fe4bf0ab0fd61d37a492a2bef0d73deb2a..b1cfa96cc88f836b202f6d0ea8eb7dbcc5d09c36 100644 (file)
@@ -1052,7 +1052,7 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
                                tmp = m66592_read(m66592, M66592_INTSTS0) &
                                                                M66592_CTSQ;
                                udelay(1);
-                       } while (tmp != M66592_CS_IDST || timeout-- > 0);
+                       } while (tmp != M66592_CS_IDST && timeout-- > 0);
 
                        if (tmp == M66592_CS_IDST)
                                m66592_bset(m66592,
@@ -1644,6 +1644,17 @@ static int m66592_probe(struct platform_device *pdev)
                ep->ep.name = m66592_ep_name[i];
                ep->ep.ops = &m66592_ep_ops;
                usb_ep_set_maxpacket_limit(&ep->ep, 512);
+
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
        usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64);
        m66592->ep[0].pipenum = 0;
index ea35a248c8985fbc8ecc8b65fb4a02c1ab070738..4c489692745e0d9ee77209846ec0f63fc08e3608 100644 (file)
@@ -1324,6 +1324,9 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
        ep->ep.ops = &mv_u3d_ep_ops;
        ep->wedge = 0;
        usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE);
+       ep->ep.caps.type_control = true;
+       ep->ep.caps.dir_in = true;
+       ep->ep.caps.dir_out = true;
        ep->ep_num = 0;
        ep->ep.desc = &mv_u3d_ep0_desc;
        INIT_LIST_HEAD(&ep->queue);
@@ -1339,14 +1342,20 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)
                if (i & 1) {
                        snprintf(name, sizeof(name), "ep%din", i >> 1);
                        ep->direction = MV_U3D_EP_DIR_IN;
+                       ep->ep.caps.dir_in = true;
                } else {
                        snprintf(name, sizeof(name), "ep%dout", i >> 1);
                        ep->direction = MV_U3D_EP_DIR_OUT;
+                       ep->ep.caps.dir_out = true;
                }
                ep->u3d = u3d;
                strncpy(ep->name, name, sizeof(ep->name));
                ep->ep.name = ep->name;
 
+               ep->ep.caps.type_iso = true;
+               ep->ep.caps.type_bulk = true;
+               ep->ep.caps.type_int = true;
+
                ep->ep.ops = &mv_u3d_ep_ops;
                usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
                ep->ep_num = i / 2;
index 5da37c957b53ce34bd9820ebfd57b9f20a5815c4..339af51df57df9532749deff77efe1fc0a7c1d7f 100644 (file)
@@ -1257,6 +1257,9 @@ static int eps_init(struct mv_udc *udc)
        ep->wedge = 0;
        ep->stopped = 0;
        usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE);
+       ep->ep.caps.type_control = true;
+       ep->ep.caps.dir_in = true;
+       ep->ep.caps.dir_out = true;
        ep->ep_num = 0;
        ep->ep.desc = &mv_ep0_desc;
        INIT_LIST_HEAD(&ep->queue);
@@ -1269,14 +1272,20 @@ static int eps_init(struct mv_udc *udc)
                if (i % 2) {
                        snprintf(name, sizeof(name), "ep%din", i / 2);
                        ep->direction = EP_DIR_IN;
+                       ep->ep.caps.dir_in = true;
                } else {
                        snprintf(name, sizeof(name), "ep%dout", i / 2);
                        ep->direction = EP_DIR_OUT;
+                       ep->ep.caps.dir_out = true;
                }
                ep->udc = udc;
                strncpy(ep->name, name, sizeof(ep->name));
                ep->ep.name = ep->name;
 
+               ep->ep.caps.type_iso = true;
+               ep->ep.caps.type_bulk = true;
+               ep->ep.caps.type_int = true;
+
                ep->ep.ops = &mv_ep_ops;
                ep->stopped = 0;
                usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);
index 195baf3e1fcd4722c80e47f0789de17cf2ad0a88..18f5ebd447b8239b88f73ab4cf6897a7f47ced7a 100644 (file)
@@ -1404,6 +1404,17 @@ net2272_usb_reinit(struct net2272 *dev)
                else
                        ep->fifo_size = 64;
                net2272_ep_reset(ep);
+
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
        usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64);
 
@@ -1826,9 +1837,9 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
                                if (!e || u.r.wLength > 2)
                                        goto do_stall;
                                if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT))
-                                       status = __constant_cpu_to_le16(1);
+                                       status = cpu_to_le16(1);
                                else
-                                       status = __constant_cpu_to_le16(0);
+                                       status = cpu_to_le16(0);
 
                                /* don't bother with a request object! */
                                net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
index 2bee912ca65b1545ff32cd9933fe266f5103f779..cf0ed42f5591c93065d6d9c5741dea6967ad4829 100644 (file)
@@ -74,19 +74,58 @@ static const char driver_desc[] = DRIVER_DESC;
 
 static const u32 ep_bit[9] = { 0, 17, 2, 19, 4, 1, 18, 3, 20 };
 static const char ep0name[] = "ep0";
-static const char *const ep_name[] = {
-       ep0name,
-       "ep-a", "ep-b", "ep-c", "ep-d",
-       "ep-e", "ep-f", "ep-g", "ep-h",
-};
 
-/* Endpoint names for usb3380 advance mode */
-static const char *const ep_name_adv[] = {
-       ep0name,
-       "ep1in", "ep2out", "ep3in", "ep4out",
-       "ep1out", "ep2in", "ep3out", "ep4in",
+#define EP_INFO(_name, _caps) \
+       { \
+               .name = _name, \
+               .caps = _caps, \
+       }
+
+static const struct {
+       const char *name;
+       const struct usb_ep_caps caps;
+} ep_info_dft[] = { /* Default endpoint configuration */
+       EP_INFO(ep0name,
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-a",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-b",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-c",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-d",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-e",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-f",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-g",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep-h",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_ALL)),
+}, ep_info_adv[] = { /* Endpoints for usb3380 advance mode */
+       EP_INFO(ep0name,
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
+       EP_INFO("ep1in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep2out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep3in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep4out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep1out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep2in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
+       EP_INFO("ep3out",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
+       EP_INFO("ep4in",
+               USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
 };
 
+#undef EP_INFO
+
 /* mode 0 == ep-{a,b,c,d} 1K fifo each
  * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
  * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
@@ -1511,6 +1550,33 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
        return 0;
 }
 
+static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
+               struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp)
+{
+       char name[8];
+       struct usb_ep *ep;
+
+       if (usb_endpoint_type(desc) == USB_ENDPOINT_XFER_INT) {
+               /* ep-e, ep-f are PIO with only 64 byte fifos */
+               ep = gadget_find_ep_by_name(_gadget, "ep-e");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+               ep = gadget_find_ep_by_name(_gadget, "ep-f");
+               if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+                       return ep;
+       }
+
+       /* USB3380: use same address for usb and hardware endpoints */
+       snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
+                       usb_endpoint_dir_in(desc) ? "in" : "out");
+       ep = gadget_find_ep_by_name(_gadget, name);
+       if (ep && usb_gadget_ep_match_desc(_gadget, ep, desc, ep_comp))
+               return ep;
+
+       return NULL;
+}
+
 static int net2280_start(struct usb_gadget *_gadget,
                struct usb_gadget_driver *driver);
 static int net2280_stop(struct usb_gadget *_gadget);
@@ -1522,6 +1588,7 @@ static const struct usb_gadget_ops net2280_ops = {
        .pullup         = net2280_pullup,
        .udc_start      = net2280_start,
        .udc_stop       = net2280_stop,
+       .match_ep       = net2280_match_ep,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -2055,7 +2122,8 @@ static void usb_reinit_228x(struct net2280 *dev)
        for (tmp = 0; tmp < 7; tmp++) {
                struct net2280_ep       *ep = &dev->ep[tmp];
 
-               ep->ep.name = ep_name[tmp];
+               ep->ep.name = ep_info_dft[tmp].name;
+               ep->ep.caps = ep_info_dft[tmp].caps;
                ep->dev = dev;
                ep->num = tmp;
 
@@ -2095,7 +2163,10 @@ static void usb_reinit_338x(struct net2280 *dev)
        for (i = 0; i < dev->n_ep; i++) {
                struct net2280_ep *ep = &dev->ep[i];
 
-               ep->ep.name = dev->enhanced_mode ? ep_name_adv[i] : ep_name[i];
+               ep->ep.name = dev->enhanced_mode ? ep_info_adv[i].name :
+                                                  ep_info_dft[i].name;
+               ep->ep.caps = dev->enhanced_mode ? ep_info_adv[i].caps :
+                                                  ep_info_dft[i].caps;
                ep->dev = dev;
                ep->num = i;
 
index e2fcdb8e55961fa3fee8093f55566e6271d41be1..9b7d39484ed3afa55c95a254379b995341bc7ad4 100644 (file)
@@ -2579,6 +2579,28 @@ omap_ep_setup(char *name, u8 addr, u8 type,
        ep->double_buf = dbuf;
        ep->udc = udc;
 
+       switch (type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               ep->ep.caps.type_control = true;
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               ep->ep.caps.type_iso = true;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               ep->ep.caps.type_bulk = true;
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               ep->ep.caps.type_int = true;
+               break;
+       };
+
+       if (addr & USB_DIR_IN)
+               ep->ep.caps.dir_in = true;
+       else
+               ep->ep.caps.dir_out = true;
+
        ep->ep.name = ep->name;
        ep->ep.ops = &omap_ep_ops;
        ep->maxpacket = maxp;
index 613547f078286f157bf8f1b499e3dfca55dc0953..e5f4c5274298684576ac33794da6d929249af797 100644 (file)
@@ -620,9 +620,9 @@ static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
                dev->vbus_session = 1;
        } else {
                if (dev->driver && dev->driver->disconnect) {
-                       spin_unlock(&dev->lock);
-                       dev->driver->disconnect(&dev->gadget);
                        spin_lock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_unlock(&dev->lock);
                }
                pch_udc_set_disconnect(dev);
                dev->vbus_session = 0;
@@ -1191,9 +1191,9 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
                pch_udc_reconnect(dev);
        } else {
                if (dev->driver && dev->driver->disconnect) {
-                       spin_unlock(&dev->lock);
-                       dev->driver->disconnect(&dev->gadget);
                        spin_lock(&dev->lock);
+                       dev->driver->disconnect(&dev->gadget);
+                       spin_unlock(&dev->lock);
                }
                pch_udc_set_disconnect(dev);
        }
@@ -1488,11 +1488,11 @@ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req,
                req->dma_mapped = 0;
        }
        ep->halted = 1;
-       spin_unlock(&dev->lock);
+       spin_lock(&dev->lock);
        if (!ep->in)
                pch_udc_ep_clear_rrdy(ep);
        usb_gadget_giveback_request(&ep->ep, &req->req);
-       spin_lock(&dev->lock);
+       spin_unlock(&dev->lock);
        ep->halted = halted;
 }
 
@@ -1793,7 +1793,7 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep,
        }
        /* prevent from using desc. - set HOST BUSY */
        dma_desc->status |= PCH_UDC_BS_HST_BSY;
-       dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID);
+       dma_desc->dataptr = cpu_to_le32(DMA_ADDR_INVALID);
        req->td_data = dma_desc;
        req->td_data_last = dma_desc;
        req->chain_len = 1;
@@ -2414,7 +2414,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                        dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep;
                else /* OUT */
                        dev->gadget.ep0 = &ep->ep;
-               spin_unlock(&dev->lock);
+               spin_lock(&dev->lock);
                /* If Mass storage Reset */
                if ((dev->setup_data.bRequestType == 0x21) &&
                    (dev->setup_data.bRequest == 0xFF))
@@ -2422,7 +2422,7 @@ static void pch_udc_svc_control_out(struct pch_udc_dev *dev)
                /* call gadget with setup data received */
                setup_supported = dev->driver->setup(&dev->gadget,
                                                     &dev->setup_data);
-               spin_lock(&dev->lock);
+               spin_unlock(&dev->lock);
 
                if (dev->setup_data.bRequestType & USB_DIR_IN) {
                        ep->td_data->status = (ep->td_data->status &
@@ -2594,9 +2594,9 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
                empty_req_queue(ep);
        }
        if (dev->driver) {
-               spin_unlock(&dev->lock);
-               usb_gadget_udc_reset(&dev->gadget, dev->driver);
                spin_lock(&dev->lock);
+               usb_gadget_udc_reset(&dev->gadget, dev->driver);
+               spin_unlock(&dev->lock);
        }
 }
 
@@ -2675,9 +2675,9 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev)
                dev->ep[i].halted = 0;
        }
        dev->stall = 0;
-       spin_unlock(&dev->lock);
-       ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
        spin_lock(&dev->lock);
+       ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
+       spin_unlock(&dev->lock);
 }
 
 /**
@@ -2712,9 +2712,9 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
        dev->stall = 0;
 
        /* call gadget zero with setup data received */
-       spin_unlock(&dev->lock);
-       ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
        spin_lock(&dev->lock);
+       ret = dev->driver->setup(&dev->gadget, &dev->setup_data);
+       spin_unlock(&dev->lock);
 }
 
 /**
@@ -2747,18 +2747,18 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
        if (dev_intr & UDC_DEVINT_US) {
                if (dev->driver
                        && dev->driver->suspend) {
-                       spin_unlock(&dev->lock);
-                       dev->driver->suspend(&dev->gadget);
                        spin_lock(&dev->lock);
+                       dev->driver->suspend(&dev->gadget);
+                       spin_unlock(&dev->lock);
                }
 
                vbus = pch_vbus_gpio_get_value(dev);
                if ((dev->vbus_session == 0)
                        && (vbus != 1)) {
                        if (dev->driver && dev->driver->disconnect) {
-                               spin_unlock(&dev->lock);
-                               dev->driver->disconnect(&dev->gadget);
                                spin_lock(&dev->lock);
+                               dev->driver->disconnect(&dev->gadget);
+                               spin_unlock(&dev->lock);
                        }
                        pch_udc_reconnect(dev);
                } else if ((dev->vbus_session == 0)
@@ -2895,11 +2895,21 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)
                ep->in = ~i & 1;
                ep->ep.name = ep_string[i];
                ep->ep.ops = &pch_udc_ep_ops;
-               if (ep->in)
+               if (ep->in) {
                        ep->offset_addr = ep->num * UDC_EP_REG_SHIFT;
-               else
+                       ep->ep.caps.dir_in = true;
+               } else {
                        ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) *
                                          UDC_EP_REG_SHIFT;
+                       ep->ep.caps.dir_out = true;
+               }
+               if (i == UDC_EP0IN_IDX || i == UDC_EP0OUT_IDX) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
                /* need to set ep->ep.maxpacket and set Default Configuration?*/
                usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE);
                list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
index f6cbe667ce398a88ed0e103e2c1b1240375a8ab9..b82cb14850b6cfd4b1836452451af67d1f9289b9 100644 (file)
@@ -1176,6 +1176,7 @@ static void udc_reinit(struct pxa25x_udc *dev)
        INIT_LIST_HEAD (&dev->gadget.ep_list);
        INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
        dev->ep0state = EP0_IDLE;
+       dev->gadget.quirk_altset_not_supp = 1;
 
        /* basic endpoint records init */
        for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
@@ -1821,6 +1822,8 @@ static struct pxa25x_udc memory = {
                        .name           = ep0name,
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = EP0_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
                .reg_udccs      = &UDCCS0,
@@ -1833,6 +1836,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep1in-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1846,6 +1851,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep2out-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1861,6 +1868,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep3in-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -1874,6 +1883,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep4out-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -1888,6 +1899,7 @@ static struct pxa25x_udc memory = {
                        .name           = "ep5in-int",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = INT_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(0, 0),
                },
                .dev            = &memory,
                .fifo_size      = INT_FIFO_SIZE,
@@ -1903,6 +1915,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep6in-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1916,6 +1930,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep7out-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1930,6 +1946,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep8in-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -1943,6 +1961,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep9out-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -1957,6 +1977,7 @@ static struct pxa25x_udc memory = {
                        .name           = "ep10in-int",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = INT_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(0, 0),
                },
                .dev            = &memory,
                .fifo_size      = INT_FIFO_SIZE,
@@ -1972,6 +1993,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep11in-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1985,6 +2008,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep12out-bulk",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = BULK_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = BULK_FIFO_SIZE,
@@ -1999,6 +2024,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep13in-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_IN),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -2012,6 +2039,8 @@ static struct pxa25x_udc memory = {
                        .name           = "ep14out-iso",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = ISO_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO,
+                                               USB_EP_CAPS_DIR_OUT),
                },
                .dev            = &memory,
                .fifo_size      = ISO_FIFO_SIZE,
@@ -2026,6 +2055,7 @@ static struct pxa25x_udc memory = {
                        .name           = "ep15in-int",
                        .ops            = &pxa25x_ep_ops,
                        .maxpacket      = INT_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(0, 0),
                },
                .dev            = &memory,
                .fifo_size      = INT_FIFO_SIZE,
index b51226abade625d2ac0f34de68a72842d9c6742b..670ac0b12f00842ad7a5b840c941f2e8a8a7f1cc 100644 (file)
@@ -1710,6 +1710,7 @@ static void udc_init_data(struct pxa_udc *dev)
        INIT_LIST_HEAD(&dev->gadget.ep_list);
        INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
        dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
+       dev->gadget.quirk_altset_not_supp = 1;
        ep0_idle(dev);
 
        /* PXA endpoints init */
@@ -2422,7 +2423,7 @@ static int pxa_udc_probe(struct platform_device *pdev)
                }
                udc->udc_command = mach->udc_command;
        } else {
-               udc->gpiod = devm_gpiod_get(&pdev->dev, NULL);
+               udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS);
        }
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index 11e14232794b55a5fe2f75dc22b1f325578507e2..cea2cb79b30c011d60c93761cac10807366e78ee 100644 (file)
 /*
  * Endpoint definition helpers
  */
-#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
-{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
+#define USB_EP_DEF(addr, bname, dir, type, maxpkt, ctype, cdir) \
+{ .usb_ep = {  .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, \
+               .caps = USB_EP_CAPS(ctype, cdir), }, \
   .desc = {    .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
-               .bmAttributes = type, \
+               .bmAttributes = USB_ENDPOINT_XFER_ ## type, \
                .wMaxPacketSize = maxpkt, }, \
   .dev = &memory \
 }
-#define USB_EP_BULK(addr, bname, dir) \
-  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
-#define USB_EP_ISO(addr, bname, dir) \
-  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
-#define USB_EP_INT(addr, bname, dir) \
-  USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
-#define USB_EP_IN_BULK(n)      USB_EP_BULK(n, "ep" #n "in-bulk", 1)
-#define USB_EP_OUT_BULK(n)     USB_EP_BULK(n, "ep" #n "out-bulk", 0)
-#define USB_EP_IN_ISO(n)       USB_EP_ISO(n,  "ep" #n "in-iso", 1)
-#define USB_EP_OUT_ISO(n)      USB_EP_ISO(n,  "ep" #n "out-iso", 0)
-#define USB_EP_IN_INT(n)       USB_EP_INT(n,  "ep" #n "in-int", 1)
-#define USB_EP_CTRL            USB_EP_DEF(0,  "ep0", 0, 0, EP0_FIFO_SIZE)
+#define USB_EP_BULK(addr, bname, dir, cdir) \
+       USB_EP_DEF(addr, bname, dir, BULK, BULK_FIFO_SIZE, \
+               USB_EP_CAPS_TYPE_BULK, cdir)
+#define USB_EP_ISO(addr, bname, dir, cdir) \
+       USB_EP_DEF(addr, bname, dir, ISOC, ISO_FIFO_SIZE, \
+               USB_EP_CAPS_TYPE_ISO, cdir)
+#define USB_EP_INT(addr, bname, dir, cdir) \
+       USB_EP_DEF(addr, bname, dir, INT, INT_FIFO_SIZE, \
+               USB_EP_CAPS_TYPE_INT, cdir)
+#define USB_EP_IN_BULK(n)      USB_EP_BULK(n, "ep" #n "in-bulk", 1, \
+                                       USB_EP_CAPS_DIR_IN)
+#define USB_EP_OUT_BULK(n)     USB_EP_BULK(n, "ep" #n "out-bulk", 0, \
+                                       USB_EP_CAPS_DIR_OUT)
+#define USB_EP_IN_ISO(n)       USB_EP_ISO(n,  "ep" #n "in-iso", 1, \
+                                       USB_EP_CAPS_DIR_IN)
+#define USB_EP_OUT_ISO(n)      USB_EP_ISO(n,  "ep" #n "out-iso", 0, \
+                                       USB_EP_CAPS_DIR_OUT)
+#define USB_EP_IN_INT(n)       USB_EP_INT(n,  "ep" #n "in-int", 1, \
+                                       USB_EP_CAPS_DIR_IN)
+#define USB_EP_CTRL    USB_EP_DEF(0,  "ep0", 0, CONTROL, EP0_FIFO_SIZE, \
+                               USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)
 
 #define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
 { \
index 0293f7169deeace9688bab19316b2bd04fa8641c..baa0609a429d99d47711f9c33b5745dc9bd3888d 100644 (file)
@@ -1935,6 +1935,16 @@ static int r8a66597_probe(struct platform_device *pdev)
                ep->ep.name = r8a66597_ep_name[i];
                ep->ep.ops = &r8a66597_ep_ops;
                usb_ep_set_maxpacket_limit(&ep->ep, 512);
+
+               if (i == 0) {
+                       ep->ep.caps.type_control = true;
+               } else {
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
+               }
+               ep->ep.caps.dir_in = true;
+               ep->ep.caps.dir_out = true;
        }
        usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64);
        r8a66597->ep[0].pipenum = 0;
index 85a712a033439b5cb3ac1fa16646049051581304..e9def42ce50d735eaafb9a39abb0b8f497392402 100644 (file)
@@ -1005,6 +1005,21 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
        hsep->stopped = 0;
        hsep->wedge = 0;
 
+       if (epnum == 0) {
+               hsep->ep.caps.type_control = true;
+               hsep->ep.caps.dir_in = true;
+               hsep->ep.caps.dir_out = true;
+       } else {
+               hsep->ep.caps.type_iso = true;
+               hsep->ep.caps.type_bulk = true;
+               hsep->ep.caps.type_int = true;
+       }
+
+       if (epnum & 1)
+               hsep->ep.caps.dir_in = true;
+       else
+               hsep->ep.caps.dir_out = true;
+
        set_index(hsudc, epnum);
        writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR);
 }
index 5d9aa81969b442a708307304c23738ae79d410f3..eb3571ee59e3c4a454b87e2103a921ed88eea2f7 100644 (file)
@@ -1691,6 +1691,8 @@ static struct s3c2410_udc memory = {
                        .name           = ep0name,
                        .ops            = &s3c2410_ep_ops,
                        .maxpacket      = EP0_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
        },
@@ -1702,6 +1704,8 @@ static struct s3c2410_udc memory = {
                        .name           = "ep1-bulk",
                        .ops            = &s3c2410_ep_ops,
                        .maxpacket      = EP_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
                .fifo_size      = EP_FIFO_SIZE,
@@ -1714,6 +1718,8 @@ static struct s3c2410_udc memory = {
                        .name           = "ep2-bulk",
                        .ops            = &s3c2410_ep_ops,
                        .maxpacket      = EP_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
                .fifo_size      = EP_FIFO_SIZE,
@@ -1726,6 +1732,8 @@ static struct s3c2410_udc memory = {
                        .name           = "ep3-bulk",
                        .ops            = &s3c2410_ep_ops,
                        .maxpacket      = EP_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
                .fifo_size      = EP_FIFO_SIZE,
@@ -1738,6 +1746,8 @@ static struct s3c2410_udc memory = {
                        .name           = "ep4-bulk",
                        .ops            = &s3c2410_ep_ops,
                        .maxpacket      = EP_FIFO_SIZE,
+                       .caps           = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
+                                               USB_EP_CAPS_DIR_ALL),
                },
                .dev            = &memory,
                .fifo_size      = EP_FIFO_SIZE,
index 89ed5e71a1991e0cd249c48b18bd04dd67bacf91..f660afba715da9babd033892e7b08c6096abfed9 100644 (file)
@@ -131,6 +131,96 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
 
 /* ------------------------------------------------------------------------- */
 
+/**
+ * gadget_find_ep_by_name - returns ep whose name is the same as sting passed
+ *     in second parameter or NULL if searched endpoint not found
+ * @g: controller to check for quirk
+ * @name: name of searched endpoint
+ */
+struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g, const char *name)
+{
+       struct usb_ep *ep;
+
+       gadget_for_each_ep(ep, g) {
+               if (!strcmp(ep->name, name))
+                       return ep;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(gadget_find_ep_by_name);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
+               struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp)
+{
+       u8              type;
+       u16             max;
+       int             num_req_streams = 0;
+
+       /* endpoint already claimed? */
+       if (ep->claimed)
+               return 0;
+
+       type = usb_endpoint_type(desc);
+       max = 0x7ff & usb_endpoint_maxp(desc);
+
+       if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
+               return 0;
+       if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
+               return 0;
+
+       if (max > ep->maxpacket_limit)
+               return 0;
+
+       /* "high bandwidth" works only at high speed */
+       if (!gadget_is_dualspeed(gadget) && usb_endpoint_maxp(desc) & (3<<11))
+               return 0;
+
+       switch (type) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               /* only support ep0 for portable CONTROL traffic */
+               return 0;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->caps.type_iso)
+                       return 0;
+               /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
+               if (!gadget_is_dualspeed(gadget) && max > 1023)
+                       return 0;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (!ep->caps.type_bulk)
+                       return 0;
+               if (ep_comp && gadget_is_superspeed(gadget)) {
+                       /* Get the number of required streams from the
+                        * EP companion descriptor and see if the EP
+                        * matches it
+                        */
+                       num_req_streams = ep_comp->bmAttributes & 0x1f;
+                       if (num_req_streams > ep->max_streams)
+                               return 0;
+               }
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               /* Bulk endpoints handle interrupt transfers,
+                * except the toggle-quirky iso-synch kind
+                */
+               if (!ep->caps.type_int && !ep->caps.type_bulk)
+                       return 0;
+               /* INT:  limit 64 bytes full speed, 1024 high/super speed */
+               if (!gadget_is_dualspeed(gadget) && max > 64)
+                       return 0;
+               break;
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_ep_match_desc);
+
+/* ------------------------------------------------------------------------- */
+
 static void usb_gadget_state_work(struct work_struct *work)
 {
        struct usb_gadget *gadget = work_to_gadget(work);
index 1f24274477ab9352ce582f96bfbfbdd61605d07e..1cbb0ac6b18233c36535a7bd42668e623119c4c5 100644 (file)
@@ -1317,12 +1317,21 @@ static void xudc_eps_init(struct xusb_udc *udc)
                        snprintf(ep->name, EPNAME_SIZE, "ep%d", ep_number);
                        ep->ep_usb.name = ep->name;
                        ep->ep_usb.ops = &xusb_ep_ops;
+
+                       ep->ep_usb.caps.type_iso = true;
+                       ep->ep_usb.caps.type_bulk = true;
+                       ep->ep_usb.caps.type_int = true;
                } else {
                        ep->ep_usb.name = ep0name;
                        usb_ep_set_maxpacket_limit(&ep->ep_usb, EP0_MAX_PACKET);
                        ep->ep_usb.ops = &xusb_ep0_ops;
+
+                       ep->ep_usb.caps.type_control = true;
                }
 
+               ep->ep_usb.caps.dir_in = true;
+               ep->ep_usb.caps.dir_out = true;
+
                ep->udc = udc;
                ep->epnumber = ep_number;
                ep->desc = NULL;
index 18ebf5b1f2560d99f6722ce46877cc1b7b72ff9c..1c3d0fd658fa81bd31a60a7c59eec3c89bb0e5aa 100644 (file)
@@ -1382,14 +1382,25 @@ static void isp1760_udc_init_eps(struct isp1760_udc *udc)
                 * This fits in the 8kB FIFO without double-buffering.
                 */
                if (ep_num == 0) {
-                       ep->ep.maxpacket = 64;
+                       usb_ep_set_maxpacket_limit(&ep->ep, 64);
+                       ep->ep.caps.type_control = true;
+                       ep->ep.caps.dir_in = true;
+                       ep->ep.caps.dir_out = true;
                        ep->maxpacket = 64;
                        udc->gadget.ep0 = &ep->ep;
                } else {
-                       ep->ep.maxpacket = 512;
+                       usb_ep_set_maxpacket_limit(&ep->ep, 512);
+                       ep->ep.caps.type_iso = true;
+                       ep->ep.caps.type_bulk = true;
+                       ep->ep.caps.type_int = true;
                        ep->maxpacket = 0;
                        list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
                }
+
+               if (is_in)
+                       ep->ep.caps.dir_in = true;
+               else
+                       ep->ep.caps.dir_out = true;
        }
 }
 
index 39db8b603627cae44b86bcbd2d9d028027cbe651..1f2037bbeb0d1619572a2912bda7fa6e2c168ac0 100644 (file)
@@ -5,7 +5,7 @@
 
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
-       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)'
        depends on (USB || USB_GADGET)
        help
          Say Y here if your system has a dual role high speed USB
@@ -20,6 +20,8 @@ config USB_MUSB_HDRC
          Analog Devices parts using this IP include Blackfin BF54x,
          BF525 and BF527.
 
+         Allwinner SoCs using this IP include A10, A13, A20, ...
+
          If you do not know what this is, please say N.
 
          To compile this driver as a module, choose M here; the
@@ -60,6 +62,15 @@ endchoice
 
 comment "Platform Glue Layer"
 
+config USB_MUSB_SUNXI
+       tristate "Allwinner (sunxi)"
+       depends on ARCH_SUNXI
+       depends on NOP_USB_XCEIV
+       depends on PHY_SUN4I_USB
+       depends on EXTCON
+       depends on GENERIC_PHY
+       select SUNXI_SRAM
+
 config USB_MUSB_DAVINCI
        tristate "DaVinci"
        depends on ARCH_DAVINCI_DMx
@@ -113,19 +124,20 @@ config USB_MUSB_JZ4740
 config USB_MUSB_AM335X_CHILD
        tristate
 
-choice
-       prompt 'MUSB DMA mode'
-       default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740
-       default USB_UX500_DMA if USB_MUSB_UX500
-       default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
-       default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
-       default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
-       default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \
-                               || USB_MUSB_DSPS
+comment "MUSB DMA mode"
+
+config MUSB_PIO_ONLY
+       bool 'Disable DMA (always use PIO)'
        help
-         Unfortunately, only one option can be enabled here. Ideally one
-         should be able to build all these drivers into one kernel to
-         allow using DMA on multiplatform kernels.
+         All data is copied between memory and FIFO by the CPU.
+         DMA controllers are ignored.
+
+         Do not choose this unless DMA support for your SOC or board
+         is unavailable (or unstable).  When DMA is enabled at compile time,
+         you can still disable it at run time using the "use_dma=n" module
+         parameter.
+
+if !MUSB_PIO_ONLY
 
 config USB_UX500_DMA
        bool 'ST Ericsson Ux500'
@@ -157,17 +169,6 @@ config USB_TUSB_OMAP_DMA
        help
          Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
 
-config MUSB_PIO_ONLY
-       bool 'Disable DMA (always use PIO)'
-       help
-         All data is copied between memory and FIFO by the CPU.
-         DMA controllers are ignored.
-
-         Do not choose this unless DMA support for your SOC or board
-         is unavailable (or unstable).  When DMA is enabled at compile time,
-         you can still disable it at run time using the "use_dma=n" module
-         parameter.
-
-endchoice
+endif # !MUSB_PIO_ONLY
 
 endif # USB_MUSB_HDRC
index ba495018b4168d74b5a8271f1dbfa509dbcd2442..f95befe18cc1907f86aaf3e78fb366062bf4be7a 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX)                  += da8xx.o
 obj-$(CONFIG_USB_MUSB_BLACKFIN)                        += blackfin.o
 obj-$(CONFIG_USB_MUSB_UX500)                   += ux500.o
 obj-$(CONFIG_USB_MUSB_JZ4740)                  += jz4740.o
+obj-$(CONFIG_USB_MUSB_SUNXI)                   += sunxi.o
 
 
 obj-$(CONFIG_USB_MUSB_AM335X_CHILD)            += musb_am335x.o
index 4d1b44c232ee4e19e79b8ebd10f0626ad4be635a..d07cafb7d5f5a1d6c992d184dff22cd53b48b3de 100644 (file)
@@ -614,7 +614,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
 {
        struct musb *musb = controller->musb;
        struct device *dev = musb->controller;
-       struct device_node *np = dev->of_node;
+       struct device_node *np = dev->parent->of_node;
        struct cppi41_dma_channel *cppi41_channel;
        int count;
        int i;
@@ -664,7 +664,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
                musb_dma->status = MUSB_DMA_STATUS_FREE;
                musb_dma->max_len = SZ_4M;
 
-               dc = dma_request_slave_channel(dev, str);
+               dc = dma_request_slave_channel(dev->parent, str);
                if (!dc) {
                        dev_err(dev, "Failed to request %s.\n", str);
                        ret = -EPROBE_DEFER;
@@ -695,7 +695,7 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *base)
        struct cppi41_dma_controller *controller;
        int ret = 0;
 
-       if (!musb->controller->of_node) {
+       if (!musb->controller->parent->of_node) {
                dev_err(musb->controller, "Need DT for the DMA engine.\n");
                return NULL;
        }
index 625d482f1a97f30fea1135f5f03cd8155c36a206..67ad630c86c9c1179c7b7cdc5b42f13a26fc5a32 100644 (file)
@@ -313,8 +313,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
 
                /* MUSB_TXCSR_P_ISO is still set correctly */
 
-#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
-               {
+               if (musb_dma_inventra(musb) || musb_dma_ux500(musb)) {
                        if (request_size < musb_ep->packet_sz)
                                musb_ep->dma->desired_mode = 0;
                        else
@@ -365,7 +364,6 @@ static void txstate(struct musb *musb, struct musb_request *req)
                        }
                }
 
-#endif
                if (is_cppi_enabled(musb)) {
                        /* program endpoint CSR first, then setup DMA */
                        csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
@@ -641,8 +639,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                        use_mode_1 = 0;
 
                if (request->actual < request->length) {
-#ifdef CONFIG_USB_INVENTRA_DMA
-                       if (is_buffer_mapped(req)) {
+                       if (!is_buffer_mapped(req))
+                               goto buffer_aint_mapped;
+
+                       if (musb_dma_inventra(musb)) {
                                struct dma_controller   *c;
                                struct dma_channel      *channel;
                                int                     use_dma = 0;
@@ -716,8 +716,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (use_dma)
                                        return;
                        }
-#elif defined(CONFIG_USB_UX500_DMA)
-                       if ((is_buffer_mapped(req)) &&
+
+                       if ((musb_dma_ux500(musb)) &&
                                (request->actual < request->length)) {
 
                                struct dma_controller *c;
@@ -765,7 +765,6 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 
                                        return;
                        }
-#endif /* Mentor's DMA */
 
                        len = request->length - request->actual;
                        dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
@@ -775,8 +774,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
 
                        fifo_count = min_t(unsigned, len, fifo_count);
 
-#ifdef CONFIG_USB_TUSB_OMAP_DMA
-                       if (tusb_dma_omap(musb) && is_buffer_mapped(req)) {
+                       if (tusb_dma_omap(musb)) {
                                struct dma_controller *c = musb->dma_controller;
                                struct dma_channel *channel = musb_ep->dma;
                                u32 dma_addr = request->dma + request->actual;
@@ -790,23 +788,22 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                if (ret)
                                        return;
                        }
-#endif
+
                        /*
                         * Unmap the dma buffer back to cpu if dma channel
                         * programming fails. This buffer is mapped if the
                         * channel allocation is successful
                         */
-                        if (is_buffer_mapped(req)) {
-                               unmap_dma_buffer(req, musb);
-
-                               /*
-                                * Clear DMAENAB and AUTOCLEAR for the
-                                * PIO mode transfer
-                                */
-                               csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
-                               musb_writew(epio, MUSB_RXCSR, csr);
-                       }
+                       unmap_dma_buffer(req, musb);
 
+                       /*
+                        * Clear DMAENAB and AUTOCLEAR for the
+                        * PIO mode transfer
+                        */
+                       csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR);
+                       musb_writew(epio, MUSB_RXCSR, csr);
+
+buffer_aint_mapped:
                        musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *)
                                        (request->buf + request->actual));
                        request->actual += fifo_count;
@@ -1684,6 +1681,40 @@ static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
        return 0;
 }
 
+#ifdef CONFIG_BLACKFIN
+static struct usb_ep *musb_match_ep(struct usb_gadget *g,
+               struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp)
+{
+       struct usb_ep *ep = NULL;
+
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_ISOC:
+       case USB_ENDPOINT_XFER_BULK:
+               if (usb_endpoint_dir_in(desc))
+                       ep = gadget_find_ep_by_name(g, "ep5in");
+               else
+                       ep = gadget_find_ep_by_name(g, "ep6out");
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               if (usb_endpoint_dir_in(desc))
+                       ep = gadget_find_ep_by_name(g, "ep1in");
+               else
+                       ep = gadget_find_ep_by_name(g, "ep2out");
+               break;
+       default:
+               break;
+       }
+
+       if (ep && usb_gadget_ep_match_desc(g, ep, desc, ep_comp))
+               return ep;
+
+       return NULL;
+}
+#else
+#define musb_match_ep NULL
+#endif
+
 static int musb_gadget_start(struct usb_gadget *g,
                struct usb_gadget_driver *driver);
 static int musb_gadget_stop(struct usb_gadget *g);
@@ -1697,6 +1728,7 @@ static const struct usb_gadget_ops musb_gadget_operations = {
        .pullup                 = musb_gadget_pullup,
        .udc_start              = musb_gadget_start,
        .udc_stop               = musb_gadget_stop,
+       .match_ep               = musb_match_ep,
 };
 
 /* ----------------------------------------------------------------------- */
@@ -1729,6 +1761,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
        INIT_LIST_HEAD(&ep->end_point.ep_list);
        if (!epnum) {
                usb_ep_set_maxpacket_limit(&ep->end_point, 64);
+               ep->end_point.caps.type_control = true;
                ep->end_point.ops = &musb_g_ep0_ops;
                musb->g.ep0 = &ep->end_point;
        } else {
@@ -1736,9 +1769,20 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
                        usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx);
                else
                        usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx);
+               ep->end_point.caps.type_iso = true;
+               ep->end_point.caps.type_bulk = true;
+               ep->end_point.caps.type_int = true;
                ep->end_point.ops = &musb_ep_ops;
                list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);
        }
+
+       if (!epnum || hw_ep->is_shared_fifo) {
+               ep->end_point.caps.dir_in = true;
+               ep->end_point.caps.dir_out = true;
+       } else if (is_in)
+               ep->end_point.caps.dir_in = true;
+       else
+               ep->end_point.caps.dir_out = true;
 }
 
 /*
@@ -2075,6 +2119,7 @@ __acquires(musb->lock)
        musb->g.b_hnp_enable = 0;
        musb->g.a_alt_hnp_support = 0;
        musb->g.a_hnp_support = 0;
+       musb->g.quirk_zlp_not_supp = 1;
 
        /* Normal reset, as B-Device;
         * or else after HNP, as A-Device
diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c
new file mode 100644 (file)
index 0000000..f9f6304
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * Allwinner sun4i MUSB Glue Layer
+ *
+ * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy-sun4i-usb.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/sunxi/sunxi_sram.h>
+#include <linux/usb/musb.h>
+#include <linux/usb/of.h>
+#include <linux/usb/usb_phy_generic.h>
+#include <linux/workqueue.h>
+#include "musb_core.h"
+
+/*
+ * Register offsets, note sunxi musb has a different layout then most
+ * musb implementations, we translate the layout in musb_readb & friends.
+ */
+#define SUNXI_MUSB_POWER                       0x0040
+#define SUNXI_MUSB_DEVCTL                      0x0041
+#define SUNXI_MUSB_INDEX                       0x0042
+#define SUNXI_MUSB_VEND0                       0x0043
+#define SUNXI_MUSB_INTRTX                      0x0044
+#define SUNXI_MUSB_INTRRX                      0x0046
+#define SUNXI_MUSB_INTRTXE                     0x0048
+#define SUNXI_MUSB_INTRRXE                     0x004a
+#define SUNXI_MUSB_INTRUSB                     0x004c
+#define SUNXI_MUSB_INTRUSBE                    0x0050
+#define SUNXI_MUSB_FRAME                       0x0054
+#define SUNXI_MUSB_TXFIFOSZ                    0x0090
+#define SUNXI_MUSB_TXFIFOADD                   0x0092
+#define SUNXI_MUSB_RXFIFOSZ                    0x0094
+#define SUNXI_MUSB_RXFIFOADD                   0x0096
+#define SUNXI_MUSB_FADDR                       0x0098
+#define SUNXI_MUSB_TXFUNCADDR                  0x0098
+#define SUNXI_MUSB_TXHUBADDR                   0x009a
+#define SUNXI_MUSB_TXHUBPORT                   0x009b
+#define SUNXI_MUSB_RXFUNCADDR                  0x009c
+#define SUNXI_MUSB_RXHUBADDR                   0x009e
+#define SUNXI_MUSB_RXHUBPORT                   0x009f
+#define SUNXI_MUSB_CONFIGDATA                  0x00c0
+
+/* VEND0 bits */
+#define SUNXI_MUSB_VEND0_PIO_MODE              0
+
+/* flags */
+#define SUNXI_MUSB_FL_ENABLED                  0
+#define SUNXI_MUSB_FL_HOSTMODE                 1
+#define SUNXI_MUSB_FL_HOSTMODE_PEND            2
+#define SUNXI_MUSB_FL_VBUS_ON                  3
+#define SUNXI_MUSB_FL_PHY_ON                   4
+#define SUNXI_MUSB_FL_HAS_SRAM                 5
+#define SUNXI_MUSB_FL_HAS_RESET                        6
+#define SUNXI_MUSB_FL_NO_CONFIGDATA            7
+
+/* Our read/write methods need access and do not get passed in a musb ref :| */
+static struct musb *sunxi_musb;
+
+struct sunxi_glue {
+       struct device           *dev;
+       struct platform_device  *musb;
+       struct clk              *clk;
+       struct reset_control    *rst;
+       struct phy              *phy;
+       struct platform_device  *usb_phy;
+       struct usb_phy          *xceiv;
+       unsigned long           flags;
+       struct work_struct      work;
+       struct extcon_dev       *extcon;
+       struct notifier_block   host_nb;
+};
+
+/* phy_power_on / off may sleep, so we use a workqueue  */
+static void sunxi_musb_work(struct work_struct *work)
+{
+       struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work);
+       bool vbus_on, phy_on;
+
+       if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
+               return;
+
+       if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) {
+               struct musb *musb = platform_get_drvdata(glue->musb);
+               unsigned long flags;
+               u8 devctl;
+
+               spin_lock_irqsave(&musb->lock, flags);
+
+               devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL);
+               if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
+                       set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+                       musb->xceiv->otg->default_a = 1;
+                       musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+                       MUSB_HST_MODE(musb);
+                       devctl |= MUSB_DEVCTL_SESSION;
+               } else {
+                       clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+                       musb->xceiv->otg->default_a = 0;
+                       musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+                       MUSB_DEV_MODE(musb);
+                       devctl &= ~MUSB_DEVCTL_SESSION;
+               }
+               writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL);
+
+               spin_unlock_irqrestore(&musb->lock, flags);
+       }
+
+       vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+       phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+
+       if (phy_on != vbus_on) {
+               if (vbus_on) {
+                       phy_power_on(glue->phy);
+                       set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+               } else {
+                       phy_power_off(glue->phy);
+                       clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+               }
+       }
+}
+
+static void sunxi_musb_set_vbus(struct musb *musb, int is_on)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       if (is_on)
+               set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+       else
+               clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+
+       schedule_work(&glue->work);
+}
+
+static void sunxi_musb_pre_root_reset_end(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       sun4i_usb_phy_set_squelch_detect(glue->phy, false);
+}
+
+static void sunxi_musb_post_root_reset_end(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       sun4i_usb_phy_set_squelch_detect(glue->phy, true);
+}
+
+static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
+{
+       struct musb *musb = __hci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&musb->lock, flags);
+
+       musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB);
+       if (musb->int_usb)
+               writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB);
+
+       /*
+        * sunxi musb often signals babble on low / full speed device
+        * disconnect, without ever raising MUSB_INTR_DISCONNECT, since
+        * normally babble never happens treat it as disconnect.
+        */
+       if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) {
+               musb->int_usb &= ~MUSB_INTR_BABBLE;
+               musb->int_usb |= MUSB_INTR_DISCONNECT;
+       }
+
+       if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) {
+               /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+               musb_ep_select(musb->mregs, 0);
+               musb_writeb(musb->mregs, MUSB_FADDR, 0);
+       }
+
+       musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX);
+       if (musb->int_tx)
+               writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX);
+
+       musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX);
+       if (musb->int_rx)
+               writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX);
+
+       musb_interrupt(musb);
+
+       spin_unlock_irqrestore(&musb->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int sunxi_musb_host_notifier(struct notifier_block *nb,
+                                   unsigned long event, void *ptr)
+{
+       struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb);
+
+       if (event)
+               set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
+       else
+               clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
+
+       set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags);
+       schedule_work(&glue->work);
+
+       return NOTIFY_DONE;
+}
+
+static int sunxi_musb_init(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+       int ret;
+
+       sunxi_musb = musb;
+       musb->phy = glue->phy;
+       musb->xceiv = glue->xceiv;
+
+       if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) {
+               ret = sunxi_sram_claim(musb->controller->parent);
+               if (ret)
+                       return ret;
+       }
+
+       ret = clk_prepare_enable(glue->clk);
+       if (ret)
+               goto error_sram_release;
+
+       if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
+               ret = reset_control_deassert(glue->rst);
+               if (ret)
+                       goto error_clk_disable;
+       }
+
+       writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
+
+       /* Register notifier before calling phy_init() */
+       if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) {
+               ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
+                                              &glue->host_nb);
+               if (ret)
+                       goto error_reset_assert;
+       }
+
+       ret = phy_init(glue->phy);
+       if (ret)
+               goto error_unregister_notifier;
+
+       if (musb->port_mode == MUSB_PORT_MODE_HOST) {
+               ret = phy_power_on(glue->phy);
+               if (ret)
+                       goto error_phy_exit;
+               set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+               /* Stop musb work from turning vbus off again */
+               set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+       }
+
+       musb->isr = sunxi_musb_interrupt;
+
+       /* Stop the musb-core from doing runtime pm (not supported on sunxi) */
+       pm_runtime_get(musb->controller);
+
+       return 0;
+
+error_phy_exit:
+       phy_exit(glue->phy);
+error_unregister_notifier:
+       if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+               extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
+                                          &glue->host_nb);
+error_reset_assert:
+       if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
+               reset_control_assert(glue->rst);
+error_clk_disable:
+       clk_disable_unprepare(glue->clk);
+error_sram_release:
+       if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
+               sunxi_sram_release(musb->controller->parent);
+       return ret;
+}
+
+static int sunxi_musb_exit(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       pm_runtime_put(musb->controller);
+
+       cancel_work_sync(&glue->work);
+       if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags))
+               phy_power_off(glue->phy);
+
+       phy_exit(glue->phy);
+
+       if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+               extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
+                                          &glue->host_nb);
+
+       if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
+               reset_control_assert(glue->rst);
+
+       clk_disable_unprepare(glue->clk);
+       if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
+               sunxi_sram_release(musb->controller->parent);
+
+       return 0;
+}
+
+static void sunxi_musb_enable(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       /* musb_core does not call us in a balanced manner */
+       if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
+               return;
+
+       schedule_work(&glue->work);
+}
+
+static void sunxi_musb_disable(struct musb *musb)
+{
+       struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
+}
+
+/*
+ * sunxi musb register layout
+ * 0x00 - 0x17 fifo regs, 1 long per fifo
+ * 0x40 - 0x57 generic control regs (power - frame)
+ * 0x80 - 0x8f ep control regs (addressed through hw_ep->regs, indexed)
+ * 0x90 - 0x97 fifo control regs (indexed)
+ * 0x98 - 0x9f multipoint / busctl regs (indexed)
+ * 0xc0                configdata reg
+ */
+
+static u32 sunxi_musb_fifo_offset(u8 epnum)
+{
+       return (epnum * 4);
+}
+
+static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset)
+{
+       WARN_ONCE(offset != 0,
+                 "sunxi_musb_ep_offset called with non 0 offset\n");
+
+       return 0x80; /* indexed, so ignore epnum */
+}
+
+static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset)
+{
+       return SUNXI_MUSB_TXFUNCADDR + offset;
+}
+
+static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset)
+{
+       struct sunxi_glue *glue;
+
+       if (addr == sunxi_musb->mregs) {
+               /* generic control or fifo control reg access */
+               switch (offset) {
+               case MUSB_FADDR:
+                       return readb(addr + SUNXI_MUSB_FADDR);
+               case MUSB_POWER:
+                       return readb(addr + SUNXI_MUSB_POWER);
+               case MUSB_INTRUSB:
+                       return readb(addr + SUNXI_MUSB_INTRUSB);
+               case MUSB_INTRUSBE:
+                       return readb(addr + SUNXI_MUSB_INTRUSBE);
+               case MUSB_INDEX:
+                       return readb(addr + SUNXI_MUSB_INDEX);
+               case MUSB_TESTMODE:
+                       return 0; /* No testmode on sunxi */
+               case MUSB_DEVCTL:
+                       return readb(addr + SUNXI_MUSB_DEVCTL);
+               case MUSB_TXFIFOSZ:
+                       return readb(addr + SUNXI_MUSB_TXFIFOSZ);
+               case MUSB_RXFIFOSZ:
+                       return readb(addr + SUNXI_MUSB_RXFIFOSZ);
+               case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */
+                       glue = dev_get_drvdata(sunxi_musb->controller->parent);
+                       /* A33 saves a reg, and we get to hardcode this */
+                       if (test_bit(SUNXI_MUSB_FL_NO_CONFIGDATA,
+                                    &glue->flags))
+                               return 0xde;
+
+                       return readb(addr + SUNXI_MUSB_CONFIGDATA);
+               /* Offset for these is fixed by sunxi_musb_busctl_offset() */
+               case SUNXI_MUSB_TXFUNCADDR:
+               case SUNXI_MUSB_TXHUBADDR:
+               case SUNXI_MUSB_TXHUBPORT:
+               case SUNXI_MUSB_RXFUNCADDR:
+               case SUNXI_MUSB_RXHUBADDR:
+               case SUNXI_MUSB_RXHUBPORT:
+                       /* multipoint / busctl reg access */
+                       return readb(addr + offset);
+               default:
+                       dev_err(sunxi_musb->controller->parent,
+                               "Error unknown readb offset %u\n", offset);
+                       return 0;
+               }
+       } else if (addr == (sunxi_musb->mregs + 0x80)) {
+               /* ep control reg access */
+               /* sunxi has a 2 byte hole before the txtype register */
+               if (offset >= MUSB_TXTYPE)
+                       offset += 2;
+               return readb(addr + offset);
+       }
+
+       dev_err(sunxi_musb->controller->parent,
+               "Error unknown readb at 0x%x bytes offset\n",
+               (int)(addr - sunxi_musb->mregs));
+       return 0;
+}
+
+static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+       if (addr == sunxi_musb->mregs) {
+               /* generic control or fifo control reg access */
+               switch (offset) {
+               case MUSB_FADDR:
+                       return writeb(data, addr + SUNXI_MUSB_FADDR);
+               case MUSB_POWER:
+                       return writeb(data, addr + SUNXI_MUSB_POWER);
+               case MUSB_INTRUSB:
+                       return writeb(data, addr + SUNXI_MUSB_INTRUSB);
+               case MUSB_INTRUSBE:
+                       return writeb(data, addr + SUNXI_MUSB_INTRUSBE);
+               case MUSB_INDEX:
+                       return writeb(data, addr + SUNXI_MUSB_INDEX);
+               case MUSB_TESTMODE:
+                       if (data)
+                               dev_warn(sunxi_musb->controller->parent,
+                                       "sunxi-musb does not have testmode\n");
+                       return;
+               case MUSB_DEVCTL:
+                       return writeb(data, addr + SUNXI_MUSB_DEVCTL);
+               case MUSB_TXFIFOSZ:
+                       return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ);
+               case MUSB_RXFIFOSZ:
+                       return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ);
+               /* Offset for these is fixed by sunxi_musb_busctl_offset() */
+               case SUNXI_MUSB_TXFUNCADDR:
+               case SUNXI_MUSB_TXHUBADDR:
+               case SUNXI_MUSB_TXHUBPORT:
+               case SUNXI_MUSB_RXFUNCADDR:
+               case SUNXI_MUSB_RXHUBADDR:
+               case SUNXI_MUSB_RXHUBPORT:
+                       /* multipoint / busctl reg access */
+                       return writeb(data, addr + offset);
+               default:
+                       dev_err(sunxi_musb->controller->parent,
+                               "Error unknown writeb offset %u\n", offset);
+                       return;
+               }
+       } else if (addr == (sunxi_musb->mregs + 0x80)) {
+               /* ep control reg access */
+               if (offset >= MUSB_TXTYPE)
+                       offset += 2;
+               return writeb(data, addr + offset);
+       }
+
+       dev_err(sunxi_musb->controller->parent,
+               "Error unknown writeb at 0x%x bytes offset\n",
+               (int)(addr - sunxi_musb->mregs));
+}
+
+static u16 sunxi_musb_readw(const void __iomem *addr, unsigned offset)
+{
+       if (addr == sunxi_musb->mregs) {
+               /* generic control or fifo control reg access */
+               switch (offset) {
+               case MUSB_INTRTX:
+                       return readw(addr + SUNXI_MUSB_INTRTX);
+               case MUSB_INTRRX:
+                       return readw(addr + SUNXI_MUSB_INTRRX);
+               case MUSB_INTRTXE:
+                       return readw(addr + SUNXI_MUSB_INTRTXE);
+               case MUSB_INTRRXE:
+                       return readw(addr + SUNXI_MUSB_INTRRXE);
+               case MUSB_FRAME:
+                       return readw(addr + SUNXI_MUSB_FRAME);
+               case MUSB_TXFIFOADD:
+                       return readw(addr + SUNXI_MUSB_TXFIFOADD);
+               case MUSB_RXFIFOADD:
+                       return readw(addr + SUNXI_MUSB_RXFIFOADD);
+               case MUSB_HWVERS:
+                       return 0; /* sunxi musb version is not known */
+               default:
+                       dev_err(sunxi_musb->controller->parent,
+                               "Error unknown readw offset %u\n", offset);
+                       return 0;
+               }
+       } else if (addr == (sunxi_musb->mregs + 0x80)) {
+               /* ep control reg access */
+               return readw(addr + offset);
+       }
+
+       dev_err(sunxi_musb->controller->parent,
+               "Error unknown readw at 0x%x bytes offset\n",
+               (int)(addr - sunxi_musb->mregs));
+       return 0;
+}
+
+static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data)
+{
+       if (addr == sunxi_musb->mregs) {
+               /* generic control or fifo control reg access */
+               switch (offset) {
+               case MUSB_INTRTX:
+                       return writew(data, addr + SUNXI_MUSB_INTRTX);
+               case MUSB_INTRRX:
+                       return writew(data, addr + SUNXI_MUSB_INTRRX);
+               case MUSB_INTRTXE:
+                       return writew(data, addr + SUNXI_MUSB_INTRTXE);
+               case MUSB_INTRRXE:
+                       return writew(data, addr + SUNXI_MUSB_INTRRXE);
+               case MUSB_FRAME:
+                       return writew(data, addr + SUNXI_MUSB_FRAME);
+               case MUSB_TXFIFOADD:
+                       return writew(data, addr + SUNXI_MUSB_TXFIFOADD);
+               case MUSB_RXFIFOADD:
+                       return writew(data, addr + SUNXI_MUSB_RXFIFOADD);
+               default:
+                       dev_err(sunxi_musb->controller->parent,
+                               "Error unknown writew offset %u\n", offset);
+                       return;
+               }
+       } else if (addr == (sunxi_musb->mregs + 0x80)) {
+               /* ep control reg access */
+               return writew(data, addr + offset);
+       }
+
+       dev_err(sunxi_musb->controller->parent,
+               "Error unknown writew at 0x%x bytes offset\n",
+               (int)(addr - sunxi_musb->mregs));
+}
+
+static const struct musb_platform_ops sunxi_musb_ops = {
+       .quirks         = MUSB_INDEXED_EP,
+       .init           = sunxi_musb_init,
+       .exit           = sunxi_musb_exit,
+       .enable         = sunxi_musb_enable,
+       .disable        = sunxi_musb_disable,
+       .fifo_offset    = sunxi_musb_fifo_offset,
+       .ep_offset      = sunxi_musb_ep_offset,
+       .busctl_offset  = sunxi_musb_busctl_offset,
+       .readb          = sunxi_musb_readb,
+       .writeb         = sunxi_musb_writeb,
+       .readw          = sunxi_musb_readw,
+       .writew         = sunxi_musb_writew,
+       .set_vbus       = sunxi_musb_set_vbus,
+       .pre_root_reset_end = sunxi_musb_pre_root_reset_end,
+       .post_root_reset_end = sunxi_musb_post_root_reset_end,
+};
+
+/* Allwinner OTG supports up to 5 endpoints */
+#define SUNXI_MUSB_MAX_EP_NUM  6
+#define SUNXI_MUSB_RAM_BITS    11
+
+static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
+       MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
+       MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
+       MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
+       MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
+       MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
+       MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
+       MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
+       MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
+       MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
+       MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
+};
+
+static struct musb_hdrc_config sunxi_musb_hdrc_config = {
+       .fifo_cfg       = sunxi_musb_mode_cfg,
+       .fifo_cfg_size  = ARRAY_SIZE(sunxi_musb_mode_cfg),
+       .multipoint     = true,
+       .dyn_fifo       = true,
+       .soft_con       = true,
+       .num_eps        = SUNXI_MUSB_MAX_EP_NUM,
+       .ram_bits       = SUNXI_MUSB_RAM_BITS,
+       .dma            = 0,
+};
+
+static int sunxi_musb_probe(struct platform_device *pdev)
+{
+       struct musb_hdrc_platform_data  pdata;
+       struct platform_device_info     pinfo;
+       struct sunxi_glue               *glue;
+       struct device_node              *np = pdev->dev.of_node;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Error no device tree node found\n");
+               return -EINVAL;
+       }
+
+       glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
+       if (!glue)
+               return -ENOMEM;
+
+       memset(&pdata, 0, sizeof(pdata));
+       switch (of_usb_get_dr_mode(np)) {
+#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
+       case USB_DR_MODE_HOST:
+               pdata.mode = MUSB_PORT_MODE_HOST;
+               break;
+#endif
+#ifdef CONFIG_USB_MUSB_DUAL_ROLE
+       case USB_DR_MODE_OTG:
+               glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
+               if (IS_ERR(glue->extcon)) {
+                       if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+                       dev_err(&pdev->dev, "Invalid or missing extcon\n");
+                       return PTR_ERR(glue->extcon);
+               }
+               pdata.mode = MUSB_PORT_MODE_DUAL_ROLE;
+               break;
+#endif
+       default:
+               dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
+               return -EINVAL;
+       }
+       pdata.platform_ops      = &sunxi_musb_ops;
+       pdata.config            = &sunxi_musb_hdrc_config;
+
+       glue->dev = &pdev->dev;
+       INIT_WORK(&glue->work, sunxi_musb_work);
+       glue->host_nb.notifier_call = sunxi_musb_host_notifier;
+
+       if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
+               set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
+
+       if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
+               set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
+
+       if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) {
+               set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
+               set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags);
+       }
+
+       glue->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(glue->clk)) {
+               dev_err(&pdev->dev, "Error getting clock: %ld\n",
+                       PTR_ERR(glue->clk));
+               return PTR_ERR(glue->clk);
+       }
+
+       if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
+               glue->rst = devm_reset_control_get(&pdev->dev, NULL);
+               if (IS_ERR(glue->rst)) {
+                       if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
+                               return -EPROBE_DEFER;
+                       dev_err(&pdev->dev, "Error getting reset %ld\n",
+                               PTR_ERR(glue->rst));
+                       return PTR_ERR(glue->rst);
+               }
+       }
+
+       glue->phy = devm_phy_get(&pdev->dev, "usb");
+       if (IS_ERR(glue->phy)) {
+               if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               dev_err(&pdev->dev, "Error getting phy %ld\n",
+                       PTR_ERR(glue->phy));
+               return PTR_ERR(glue->phy);
+       }
+
+       glue->usb_phy = usb_phy_generic_register();
+       if (IS_ERR(glue->usb_phy)) {
+               dev_err(&pdev->dev, "Error registering usb-phy %ld\n",
+                       PTR_ERR(glue->usb_phy));
+               return PTR_ERR(glue->usb_phy);
+       }
+
+       glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
+       if (IS_ERR(glue->xceiv)) {
+               ret = PTR_ERR(glue->xceiv);
+               dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret);
+               goto err_unregister_usb_phy;
+       }
+
+       platform_set_drvdata(pdev, glue);
+
+       memset(&pinfo, 0, sizeof(pinfo));
+       pinfo.name       = "musb-hdrc";
+       pinfo.id        = PLATFORM_DEVID_AUTO;
+       pinfo.parent    = &pdev->dev;
+       pinfo.res       = pdev->resource;
+       pinfo.num_res   = pdev->num_resources;
+       pinfo.data      = &pdata;
+       pinfo.size_data = sizeof(pdata);
+
+       glue->musb = platform_device_register_full(&pinfo);
+       if (IS_ERR(glue->musb)) {
+               ret = PTR_ERR(glue->musb);
+               dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
+               goto err_unregister_usb_phy;
+       }
+
+       return 0;
+
+err_unregister_usb_phy:
+       usb_phy_generic_unregister(glue->usb_phy);
+       return ret;
+}
+
+static int sunxi_musb_remove(struct platform_device *pdev)
+{
+       struct sunxi_glue *glue = platform_get_drvdata(pdev);
+       struct platform_device *usb_phy = glue->usb_phy;
+
+       platform_device_unregister(glue->musb); /* Frees glue ! */
+       usb_phy_generic_unregister(usb_phy);
+
+       return 0;
+}
+
+static const struct of_device_id sunxi_musb_match[] = {
+       { .compatible = "allwinner,sun4i-a10-musb", },
+       { .compatible = "allwinner,sun6i-a31-musb", },
+       { .compatible = "allwinner,sun8i-a33-musb", },
+       {}
+};
+
+static struct platform_driver sunxi_musb_driver = {
+       .probe = sunxi_musb_probe,
+       .remove = sunxi_musb_remove,
+       .driver = {
+               .name = "musb-sunxi",
+               .of_match_table = sunxi_musb_match,
+       },
+};
+module_platform_driver(sunxi_musb_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
index 869c0cfcad98e28948c30ce68329fb34ab89d99a..7d3beee2a587d84e60ecffab4b4703dee4cd6976 100644 (file)
@@ -152,6 +152,20 @@ config USB_MSM_OTG
          This driver is not supported on boards like trout which
          has an external PHY.
 
+config USB_QCOM_8X16_PHY
+       tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support"
+       depends on ARCH_QCOM || COMPILE_TEST
+       depends on RESET_CONTROLLER
+       select USB_PHY
+       select USB_ULPI_VIEWPORT
+       help
+         Enable this to support the USB transceiver on Qualcomm 8x16 chipsets.
+         It handles PHY initialization, clock management, power management,
+         and workarounds required after resetting the hardware.
+
+         To compile this driver as a module, choose M here: the
+         module will be called phy-qcom-8x16-usb.
+
 config USB_MV_OTG
        tristate "Marvell USB OTG support"
        depends on USB_EHCI_MV && USB_MV_UDC && PM
index e36ab1d46d8b4fed21445e9c4adc2e7fe1e0974b..19c0dccbb1161b11ba001ee62181027a614be187 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_USB_EHCI_TEGRA)          += phy-tegra-usb.o
 obj-$(CONFIG_USB_GPIO_VBUS)            += phy-gpio-vbus-usb.o
 obj-$(CONFIG_USB_ISP1301)              += phy-isp1301.o
 obj-$(CONFIG_USB_MSM_OTG)              += phy-msm-usb.o
+obj-$(CONFIG_USB_QCOM_8X16_PHY)        += phy-qcom-8x16-usb.o
 obj-$(CONFIG_USB_MV_OTG)               += phy-mv-usb.o
 obj-$(CONFIG_USB_MXS_PHY)              += phy-mxs-usb.o
 obj-$(CONFIG_USB_RCAR_PHY)             += phy-rcar-usb.o
index deee68eafb72a70c8c504d659e8fc573cc270d09..ec6ecd03269cc90a3aa113e8070cfba14c8aa6c3 100644 (file)
@@ -218,11 +218,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
                        clk_rate = 0;
 
                needs_vcc = of_property_read_bool(node, "vcc-supply");
-               nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
+               nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
+                                                          GPIOD_ASIS);
                err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
                if (!err) {
                        nop->gpiod_vbus = devm_gpiod_get_optional(dev,
-                                                        "vbus-detect");
+                                                        "vbus-detect",
+                                                        GPIOD_ASIS);
                        err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
                }
        } else if (pdata) {
index 00c49bb1bd29a8ac9a63d6f6a69aea6a71e837d8..c58c3c0dbe35edebec10a89ad7477484f4cab902 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/slab.h>
@@ -32,6 +33,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/reboot.h>
 #include <linux/reset.h>
 
 #include <linux/usb.h>
@@ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event,
        else
                clear_bit(B_SESS_VLD, &motg->inputs);
 
+       if (test_bit(B_SESS_VLD, &motg->inputs)) {
+               /* Switch D+/D- lines to Device connector */
+               gpiod_set_value_cansleep(motg->switch_gpio, 0);
+       } else {
+               /* Switch D+/D- lines to Hub */
+               gpiod_set_value_cansleep(motg->switch_gpio, 1);
+       }
+
        schedule_work(&motg->sm_work);
 
        return NOTIFY_DONE;
@@ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
 
        motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
 
+       motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch",
+                                                   GPIOD_OUT_LOW);
+       if (IS_ERR(motg->switch_gpio))
+               return PTR_ERR(motg->switch_gpio);
+
        ext_id = ERR_PTR(-ENODEV);
        ext_vbus = ERR_PTR(-ENODEV);
        if (of_property_read_bool(node, "extcon")) {
@@ -1561,15 +1576,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
        }
 
        if (!IS_ERR(ext_vbus)) {
+               motg->vbus.extcon = ext_vbus;
                motg->vbus.nb.notifier_call = msm_otg_vbus_notifier;
-               ret = extcon_register_interest(&motg->vbus.conn, ext_vbus->name,
-                                              "USB", &motg->vbus.nb);
+               ret = extcon_register_notifier(ext_vbus, EXTCON_USB,
+                                               &motg->vbus.nb);
                if (ret < 0) {
                        dev_err(&pdev->dev, "register VBUS notifier failed\n");
                        return ret;
                }
 
-               ret = extcon_get_cable_state(ext_vbus, "USB");
+               ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB);
                if (ret)
                        set_bit(B_SESS_VLD, &motg->inputs);
                else
@@ -1577,15 +1593,16 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
        }
 
        if (!IS_ERR(ext_id)) {
+               motg->id.extcon = ext_id;
                motg->id.nb.notifier_call = msm_otg_id_notifier;
-               ret = extcon_register_interest(&motg->id.conn, ext_id->name,
-                                              "USB-HOST", &motg->id.nb);
+               ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST,
+                                               &motg->id.nb);
                if (ret < 0) {
                        dev_err(&pdev->dev, "register ID notifier failed\n");
                        return ret;
                }
 
-               ret = extcon_get_cable_state(ext_id, "USB-HOST");
+               ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST);
                if (ret)
                        clear_bit(ID, &motg->inputs);
                else
@@ -1615,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
        return 0;
 }
 
+static int msm_otg_reboot_notify(struct notifier_block *this,
+                                unsigned long code, void *unused)
+{
+       struct msm_otg *motg = container_of(this, struct msm_otg, reboot);
+
+       /*
+        * Ensure that D+/D- lines are routed to uB connector, so
+        * we could load bootloader/kernel at next reboot
+        */
+       gpiod_set_value_cansleep(motg->switch_gpio, 0);
+       return NOTIFY_DONE;
+}
+
 static int msm_otg_probe(struct platform_device *pdev)
 {
        struct regulator_bulk_data regs[3];
@@ -1779,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev)
                        dev_dbg(&pdev->dev, "Can not create mode change file\n");
        }
 
+       if (test_bit(B_SESS_VLD, &motg->inputs)) {
+               /* Switch D+/D- lines to Device connector */
+               gpiod_set_value_cansleep(motg->switch_gpio, 0);
+       } else {
+               /* Switch D+/D- lines to Hub */
+               gpiod_set_value_cansleep(motg->switch_gpio, 1);
+       }
+
+       motg->reboot.notifier_call = msm_otg_reboot_notify;
+       register_reboot_notifier(&motg->reboot);
+
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
@@ -1805,10 +1846,16 @@ static int msm_otg_remove(struct platform_device *pdev)
        if (phy->otg->host || phy->otg->gadget)
                return -EBUSY;
 
-       if (motg->id.conn.edev)
-               extcon_unregister_interest(&motg->id.conn);
-       if (motg->vbus.conn.edev)
-               extcon_unregister_interest(&motg->vbus.conn);
+       unregister_reboot_notifier(&motg->reboot);
+
+       /*
+        * Ensure that D+/D- lines are routed to uB connector, so
+        * we could load bootloader/kernel at next reboot
+        */
+       gpiod_set_value_cansleep(motg->switch_gpio, 0);
+
+       extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb);
+       extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb);
 
        msm_otg_debugfs_cleanup();
        cancel_delayed_work_sync(&motg->chg_work);
index 56ee7603034b890fa49d7bf6574692d5c6383e41..1270906ccb95808714d174f0461a081c8d1d1cc6 100644 (file)
@@ -30,8 +30,7 @@ struct otg_device {
        void __iomem                    *base;
        bool                            id;
        bool                            vbus;
-       struct extcon_specific_cable_nb vbus_dev;
-       struct extcon_specific_cable_nb id_dev;
+       struct extcon_dev               *extcon;
        struct notifier_block           vbus_nb;
        struct notifier_block           id_nb;
 };
@@ -106,6 +105,7 @@ static int omap_otg_probe(struct platform_device *pdev)
        extcon = extcon_get_extcon_dev(config->extcon);
        if (!extcon)
                return -EPROBE_DEFER;
+       otg_dev->extcon = extcon;
 
        otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
        if (!otg_dev)
@@ -118,20 +118,19 @@ static int omap_otg_probe(struct platform_device *pdev)
        otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
        otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
 
-       ret = extcon_register_interest(&otg_dev->id_dev, config->extcon,
-                                      "USB-HOST", &otg_dev->id_nb);
+       ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb);
        if (ret)
                return ret;
 
-       ret = extcon_register_interest(&otg_dev->vbus_dev, config->extcon,
-                                      "USB", &otg_dev->vbus_nb);
+       ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb);
        if (ret) {
-               extcon_unregister_interest(&otg_dev->id_dev);
+               extcon_unregister_notifier(extcon, EXTCON_USB_HOST,
+                                       &otg_dev->id_nb);
                return ret;
        }
 
-       otg_dev->id = extcon_get_cable_state(extcon, "USB-HOST");
-       otg_dev->vbus = extcon_get_cable_state(extcon, "USB");
+       otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST);
+       otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB);
        omap_otg_set_mode(otg_dev);
 
        rev = readl(otg_dev->base);
@@ -147,9 +146,10 @@ static int omap_otg_probe(struct platform_device *pdev)
 static int omap_otg_remove(struct platform_device *pdev)
 {
        struct otg_device *otg_dev = platform_get_drvdata(pdev);
+       struct extcon_dev *edev = otg_dev->extcon;
 
-       extcon_unregister_interest(&otg_dev->id_dev);
-       extcon_unregister_interest(&otg_dev->vbus_dev);
+       extcon_unregister_notifier(edev, EXTCON_USB_HOST,&otg_dev->id_nb);
+       extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb);
 
        return 0;
 }
diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c
new file mode 100644 (file)
index 0000000..5d357a9
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/ulpi.h>
+
+#define HSPHY_AHBBURST                 0x0090
+#define HSPHY_AHBMODE                  0x0098
+#define HSPHY_GENCONFIG                        0x009c
+#define HSPHY_GENCONFIG_2              0x00a0
+
+#define HSPHY_USBCMD                   0x0140
+#define HSPHY_ULPI_VIEWPORT            0x0170
+#define HSPHY_CTRL                     0x0240
+
+#define HSPHY_TXFIFO_IDLE_FORCE_DIS    BIT(4)
+#define HSPHY_SESS_VLD_CTRL_EN         BIT(7)
+#define HSPHY_POR_ASSERT               BIT(0)
+#define HSPHY_RETEN                    BIT(1)
+
+#define HSPHY_SESS_VLD_CTRL            BIT(25)
+
+#define ULPI_PWR_CLK_MNG_REG           0x88
+#define ULPI_PWR_OTG_COMP_DISABLE      BIT(0)
+
+#define ULPI_MISC_A                    0x96
+#define ULPI_MISC_A_VBUSVLDEXTSEL      BIT(1)
+#define ULPI_MISC_A_VBUSVLDEXT         BIT(0)
+
+#define HSPHY_3P3_MIN                  3050000 /* uV */
+#define HSPHY_3P3_MAX                  3300000 /* uV */
+
+#define HSPHY_1P8_MIN                  1800000 /* uV */
+#define HSPHY_1P8_MAX                  1800000 /* uV */
+
+#define HSPHY_VDD_MIN                  5
+#define HSPHY_VDD_MAX                  7
+
+struct phy_8x16 {
+       struct usb_phy                  phy;
+       void __iomem                    *regs;
+       struct clk                      *core_clk;
+       struct clk                      *iface_clk;
+       struct regulator                *v3p3;
+       struct regulator                *v1p8;
+       struct regulator                *vdd;
+
+       struct reset_control            *phy_reset;
+
+       struct extcon_specific_cable_nb vbus_cable;
+       struct notifier_block           vbus_notify;
+
+       struct gpio_desc                *switch_gpio;
+       struct notifier_block           reboot_notify;
+};
+
+static int phy_8x16_regulators_enable(struct phy_8x16 *qphy)
+{
+       int ret;
+
+       ret = regulator_set_voltage(qphy->vdd, HSPHY_VDD_MIN, HSPHY_VDD_MAX);
+       if (ret)
+               return ret;
+
+       ret = regulator_enable(qphy->vdd);
+       if (ret)
+               return ret;
+
+       ret = regulator_set_voltage(qphy->v3p3, HSPHY_3P3_MIN, HSPHY_3P3_MAX);
+       if (ret)
+               goto off_vdd;
+
+       ret = regulator_enable(qphy->v3p3);
+       if (ret)
+               goto off_vdd;
+
+       ret = regulator_set_voltage(qphy->v1p8, HSPHY_1P8_MIN, HSPHY_1P8_MAX);
+       if (ret)
+               goto off_3p3;
+
+       ret = regulator_enable(qphy->v1p8);
+       if (ret)
+               goto off_3p3;
+
+       return 0;
+
+off_3p3:
+       regulator_disable(qphy->v3p3);
+off_vdd:
+       regulator_disable(qphy->vdd);
+
+       return ret;
+}
+
+static void phy_8x16_regulators_disable(struct phy_8x16 *qphy)
+{
+       regulator_disable(qphy->v1p8);
+       regulator_disable(qphy->v3p3);
+       regulator_disable(qphy->vdd);
+}
+
+static int phy_8x16_notify_connect(struct usb_phy *phy,
+                                  enum usb_device_speed speed)
+{
+       struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy);
+       u32 val;
+
+       val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
+       usb_phy_io_write(&qphy->phy, val, ULPI_SET(ULPI_MISC_A));
+
+       val = readl(qphy->regs + HSPHY_USBCMD);
+       val |= HSPHY_SESS_VLD_CTRL;
+       writel(val, qphy->regs + HSPHY_USBCMD);
+
+       return 0;
+}
+
+static int phy_8x16_notify_disconnect(struct usb_phy *phy,
+                                     enum usb_device_speed speed)
+{
+       struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy);
+       u32 val;
+
+       val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
+       usb_phy_io_write(&qphy->phy, val, ULPI_CLR(ULPI_MISC_A));
+
+       val = readl(qphy->regs + HSPHY_USBCMD);
+       val &= ~HSPHY_SESS_VLD_CTRL;
+       writel(val, qphy->regs + HSPHY_USBCMD);
+
+       return 0;
+}
+
+static int phy_8x16_vbus_on(struct phy_8x16 *qphy)
+{
+       phy_8x16_notify_connect(&qphy->phy, USB_SPEED_UNKNOWN);
+
+       /* Switch D+/D- lines to Device connector */
+       gpiod_set_value_cansleep(qphy->switch_gpio, 0);
+
+       return 0;
+}
+
+static int phy_8x16_vbus_off(struct phy_8x16 *qphy)
+{
+       phy_8x16_notify_disconnect(&qphy->phy, USB_SPEED_UNKNOWN);
+
+       /* Switch D+/D- lines to USB HUB */
+       gpiod_set_value_cansleep(qphy->switch_gpio, 1);
+
+       return 0;
+}
+
+static int phy_8x16_vbus_notify(struct notifier_block *nb, unsigned long event,
+                               void *ptr)
+{
+       struct phy_8x16 *qphy = container_of(nb, struct phy_8x16, vbus_notify);
+
+       if (event)
+               phy_8x16_vbus_on(qphy);
+       else
+               phy_8x16_vbus_off(qphy);
+
+       return NOTIFY_DONE;
+}
+
+static int phy_8x16_init(struct usb_phy *phy)
+{
+       struct phy_8x16 *qphy = container_of(phy, struct phy_8x16, phy);
+       u32 val, init[] = {0x44, 0x6B, 0x24, 0x13};
+       u32 addr = ULPI_EXT_VENDOR_SPECIFIC;
+       int idx, state;
+
+       for (idx = 0; idx < ARRAY_SIZE(init); idx++)
+               usb_phy_io_write(phy, init[idx], addr + idx);
+
+       reset_control_reset(qphy->phy_reset);
+
+       /* Assert USB HSPHY_POR */
+       val = readl(qphy->regs + HSPHY_CTRL);
+       val |= HSPHY_POR_ASSERT;
+       writel(val, qphy->regs + HSPHY_CTRL);
+
+       /*
+        * wait for minimum 10 microseconds as suggested in HPG.
+        * Use a slightly larger value since the exact value didn't
+        * work 100% of the time.
+        */
+       usleep_range(12, 15);
+
+       /* Deassert USB HSPHY_POR */
+       val = readl(qphy->regs + HSPHY_CTRL);
+       val &= ~HSPHY_POR_ASSERT;
+       writel(val, qphy->regs + HSPHY_CTRL);
+
+       usleep_range(10, 15);
+
+       writel(0x00, qphy->regs + HSPHY_AHBBURST);
+       writel(0x08, qphy->regs + HSPHY_AHBMODE);
+
+       /* workaround for rx buffer collision issue */
+       val = readl(qphy->regs + HSPHY_GENCONFIG);
+       val &= ~HSPHY_TXFIFO_IDLE_FORCE_DIS;
+       writel(val, qphy->regs + HSPHY_GENCONFIG);
+
+       val = readl(qphy->regs + HSPHY_GENCONFIG_2);
+       val |= HSPHY_SESS_VLD_CTRL_EN;
+       writel(val, qphy->regs + HSPHY_GENCONFIG_2);
+
+       val = ULPI_PWR_OTG_COMP_DISABLE;
+       usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG));
+
+       state = extcon_get_cable_state(qphy->vbus_cable.edev, "USB");
+       if (state)
+               phy_8x16_vbus_on(qphy);
+       else
+               phy_8x16_vbus_off(qphy);
+
+       val = usb_phy_io_read(&qphy->phy, ULPI_FUNC_CTRL);
+       val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+       val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+       usb_phy_io_write(&qphy->phy, val, ULPI_FUNC_CTRL);
+
+       return 0;
+}
+
+static void phy_8x16_shutdown(struct usb_phy *phy)
+{
+       u32 val;
+
+       /* Put the controller in non-driving mode */
+       val = usb_phy_io_read(phy, ULPI_FUNC_CTRL);
+       val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+       val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
+       usb_phy_io_write(phy, val, ULPI_FUNC_CTRL);
+}
+
+static int phy_8x16_read_devicetree(struct phy_8x16 *qphy)
+{
+       struct regulator_bulk_data regs[3];
+       struct device *dev = qphy->phy.dev;
+       int ret;
+
+       qphy->core_clk = devm_clk_get(dev, "core");
+       if (IS_ERR(qphy->core_clk))
+               return PTR_ERR(qphy->core_clk);
+
+       qphy->iface_clk = devm_clk_get(dev, "iface");
+       if (IS_ERR(qphy->iface_clk))
+               return PTR_ERR(qphy->iface_clk);
+
+       regs[0].supply = "v3p3";
+       regs[1].supply = "v1p8";
+       regs[2].supply = "vddcx";
+
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(regs), regs);
+       if (ret)
+               return ret;
+
+       qphy->v3p3 = regs[0].consumer;
+       qphy->v1p8 = regs[1].consumer;
+       qphy->vdd  = regs[2].consumer;
+
+       qphy->phy_reset = devm_reset_control_get(dev, "phy");
+       if (IS_ERR(qphy->phy_reset))
+               return PTR_ERR(qphy->phy_reset);
+
+       qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch",
+                                                  GPIOD_OUT_LOW);
+       if (IS_ERR(qphy->switch_gpio))
+               return PTR_ERR(qphy->switch_gpio);
+
+       return 0;
+}
+
+static int phy_8x16_reboot_notify(struct notifier_block *this,
+                                 unsigned long code, void *unused)
+{
+       struct phy_8x16 *qphy;
+
+       qphy = container_of(this, struct phy_8x16, reboot_notify);
+
+       /*
+        * Ensure that D+/D- lines are routed to uB connector, so
+        * we could load bootloader/kernel at next reboot_notify
+        */
+       gpiod_set_value_cansleep(qphy->switch_gpio, 0);
+       return NOTIFY_DONE;
+}
+
+static int phy_8x16_probe(struct platform_device *pdev)
+{
+       struct extcon_dev *edev;
+       struct phy_8x16 *qphy;
+       struct resource *res;
+       struct usb_phy *phy;
+       int ret;
+
+       qphy = devm_kzalloc(&pdev->dev, sizeof(*qphy), GFP_KERNEL);
+       if (!qphy)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, qphy);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!qphy->regs)
+               return -ENOMEM;
+
+       phy                     = &qphy->phy;
+       phy->dev                = &pdev->dev;
+       phy->label              = dev_name(&pdev->dev);
+       phy->init               = phy_8x16_init;
+       phy->shutdown           = phy_8x16_shutdown;
+       phy->notify_connect     = phy_8x16_notify_connect;
+       phy->notify_disconnect  = phy_8x16_notify_disconnect;
+       phy->io_priv            = qphy->regs + HSPHY_ULPI_VIEWPORT;
+       phy->io_ops             = &ulpi_viewport_access_ops;
+       phy->type               = USB_PHY_TYPE_USB2;
+
+       ret = phy_8x16_read_devicetree(qphy);
+       if (ret < 0)
+               return ret;
+
+       edev = extcon_get_edev_by_phandle(phy->dev, 0);
+       if (IS_ERR(edev))
+               return PTR_ERR(edev);
+
+       ret = clk_set_rate(qphy->core_clk, INT_MAX);
+       if (ret < 0)
+               dev_dbg(phy->dev, "Can't boost core clock\n");
+
+       ret = clk_prepare_enable(qphy->core_clk);
+       if (ret < 0)
+               return ret;
+
+       ret = clk_prepare_enable(qphy->iface_clk);
+       if (ret < 0)
+               goto off_core;
+
+       ret = phy_8x16_regulators_enable(qphy);
+       if (0 && ret)
+               goto off_clks;
+
+       qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify;
+       ret = extcon_register_interest(&qphy->vbus_cable, edev->name,
+                                      "USB", &qphy->vbus_notify);
+       if (ret < 0)
+               goto off_power;
+
+       ret = usb_add_phy_dev(&qphy->phy);
+       if (ret)
+               goto off_extcon;
+
+       qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify;
+       register_reboot_notifier(&qphy->reboot_notify);
+
+       return 0;
+
+off_extcon:
+       extcon_unregister_interest(&qphy->vbus_cable);
+off_power:
+       phy_8x16_regulators_disable(qphy);
+off_clks:
+       clk_disable_unprepare(qphy->iface_clk);
+off_core:
+       clk_disable_unprepare(qphy->core_clk);
+       return ret;
+}
+
+static int phy_8x16_remove(struct platform_device *pdev)
+{
+       struct phy_8x16 *qphy = platform_get_drvdata(pdev);
+
+       unregister_reboot_notifier(&qphy->reboot_notify);
+       extcon_unregister_interest(&qphy->vbus_cable);
+
+       /*
+        * Ensure that D+/D- lines are routed to uB connector, so
+        * we could load bootloader/kernel at next reboot_notify
+        */
+       gpiod_set_value_cansleep(qphy->switch_gpio, 0);
+
+       usb_remove_phy(&qphy->phy);
+
+       clk_disable_unprepare(qphy->iface_clk);
+       clk_disable_unprepare(qphy->core_clk);
+       phy_8x16_regulators_disable(qphy);
+       return 0;
+}
+
+static const struct of_device_id phy_8x16_dt_match[] = {
+       { .compatible = "qcom,usb-8x16-phy" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, phy_8x16_dt_match);
+
+static struct platform_driver phy_8x16_driver = {
+       .probe  = phy_8x16_probe,
+       .remove = phy_8x16_remove,
+       .driver = {
+               .name = "phy-qcom-8x16-usb",
+               .of_match_table = phy_8x16_dt_match,
+       },
+};
+module_platform_driver(phy_8x16_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm APQ8016/MSM8916 chipsets USB transceiver driver");
index b40d6a87d69491b3a016c2a481026580a2d9a143..ab5d364f6e8c7964e004c01c78b50baf3f32832c 100644 (file)
@@ -57,7 +57,7 @@ struct tahvo_usb {
        struct clk              *ick;
        int                     irq;
        int                     tahvo_mode;
-       struct extcon_dev       extcon;
+       struct extcon_dev       *extcon;
 };
 
 static const unsigned int tahvo_cable[] = {
@@ -121,7 +121,7 @@ static void check_vbus_state(struct tahvo_usb *tu)
        prev_state = tu->vbus_state;
        tu->vbus_state = reg & TAHVO_STAT_VBUS;
        if (prev_state != tu->vbus_state) {
-               extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
+               extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state);
                sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state");
        }
 }
@@ -130,7 +130,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu)
 {
        struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
 
-       extcon_set_cable_state(&tu->extcon, "USB-HOST", true);
+       extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, true);
 
        /* Power up the transceiver in USB host mode */
        retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND |
@@ -149,7 +149,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu)
 {
        struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent);
 
-       extcon_set_cable_state(&tu->extcon, "USB-HOST", false);
+       extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, false);
 
        /* Power up transceiver and set it in USB peripheral mode */
        retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT |
@@ -365,11 +365,13 @@ static int tahvo_usb_probe(struct platform_device *pdev)
         */
        tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS;
 
-       tu->extcon.name = DRIVER_NAME;
-       tu->extcon.supported_cable = tahvo_cable;
-       tu->extcon.dev.parent = &pdev->dev;
+       tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable);
+       if (IS_ERR(tu->extcon)) {
+               dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+               return -ENOMEM;
+       }
 
-       ret = extcon_dev_register(&tu->extcon);
+       ret = devm_extcon_dev_register(&pdev->dev, tu->extcon);
        if (ret) {
                dev_err(&pdev->dev, "could not register extcon device: %d\n",
                        ret);
@@ -377,9 +379,9 @@ static int tahvo_usb_probe(struct platform_device *pdev)
        }
 
        /* Set the initial cable state. */
-       extcon_set_cable_state(&tu->extcon, "USB-HOST",
+       extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST,
                               tu->tahvo_mode == TAHVO_MODE_HOST);
-       extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state);
+       extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state);
 
        /* Create OTG interface */
        tahvo_usb_power_off(tu);
@@ -396,7 +398,7 @@ static int tahvo_usb_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev, "cannot register USB transceiver: %d\n",
                        ret);
-               goto err_extcon_unreg;
+               goto err_disable_clk;
        }
 
        dev_set_drvdata(&pdev->dev, tu);
@@ -424,8 +426,6 @@ err_free_irq:
        free_irq(tu->irq, tu);
 err_remove_phy:
        usb_remove_phy(&tu->phy);
-err_extcon_unreg:
-       extcon_dev_unregister(&tu->extcon);
 err_disable_clk:
        if (!IS_ERR(tu->ick))
                clk_disable(tu->ick);
@@ -440,7 +440,6 @@ static int tahvo_usb_remove(struct platform_device *pdev)
        sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group);
        free_irq(tu->irq, tu);
        usb_remove_phy(&tu->phy);
-       extcon_dev_unregister(&tu->extcon);
        if (!IS_ERR(tu->ick))
                clk_disable(tu->ick);
 
index e8bf40808b3989c59bd4bb61a32986b3e57f77a2..7b98e1d9194cb3571452c7143603f4e9d9966244 100644 (file)
@@ -388,7 +388,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
 
        if (enable && !mod) {
                if (priv->edev) {
-                       cable = extcon_get_cable_state(priv->edev, "USB-HOST");
+                       cable = extcon_get_cable_state_(priv->edev, EXTCON_USB_HOST);
                        if ((cable > 0 && id != USBHS_HOST) ||
                            (!cable && id != USBHS_GADGET)) {
                                dev_info(&pdev->dev,
index 54f916fa238d0428bed717b9f86121864ceb8d72..de4f97d84a822ffd746b5550dcb68da08b581438 100644 (file)
@@ -52,7 +52,7 @@ struct usbhsg_gpriv {
 
        struct usb_gadget_driver        *driver;
        struct usb_phy          *transceiver;
-       bool                     vbus_active;
+       bool                     vbus_active;
 
        u32     status;
 #define USBHSG_STATUS_STARTED          (1 << 0)
@@ -1103,12 +1103,18 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
                if (usbhsg_is_dcp(uep)) {
                        gpriv->gadget.ep0 = &uep->ep;
                        usb_ep_set_maxpacket_limit(&uep->ep, 64);
+                       uep->ep.caps.type_control = true;
                }
                /* init normal pipe */
                else {
                        usb_ep_set_maxpacket_limit(&uep->ep, 512);
+                       uep->ep.caps.type_iso = true;
+                       uep->ep.caps.type_bulk = true;
+                       uep->ep.caps.type_int = true;
                        list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list);
                }
+               uep->ep.caps.dir_in = true;
+               uep->ep.caps.dir_out = true;
        }
 
        ret = usb_add_gadget_udc(dev, &gpriv->gadget);
index ab94f78c4dd15ee4554a4eff996c862b7a6fd869..e10cefc721ad11d093e725748de6e271194324e5 100644 (file)
@@ -34,6 +34,7 @@ struct ci_hdrc_platform_data {
 #define CI_HDRC_CONTROLLER_STOPPED_EVENT       1
        void    (*notify_event) (struct ci_hdrc *ci, unsigned event);
        struct regulator        *reg_vbus;
+       struct usb_otg_caps     ci_otg_caps;
        bool                    tpl_support;
 };
 
index 2511469a99048996fa53232801fdb6a72bb90d4b..1074b8921a5dc59dda948ef39e7281f63d420efb 100644 (file)
@@ -228,6 +228,8 @@ struct usb_function {
        struct list_head                list;
        DECLARE_BITMAP(endpoints, 32);
        const struct usb_function_instance *fi;
+
+       unsigned int            bind_deactivated:1;
 };
 
 int usb_add_function(struct usb_configuration *, struct usb_function *);
index 4f3dfb7d065420d012eeade7154575100473602c..c14a69b36d27b14afc1da26ab616797e7daaaf8d 100644 (file)
@@ -140,11 +140,50 @@ struct usb_ep_ops {
        void (*fifo_flush) (struct usb_ep *ep);
 };
 
+/**
+ * struct usb_ep_caps - endpoint capabilities description
+ * @type_control:Endpoint supports control type (reserved for ep0).
+ * @type_iso:Endpoint supports isochronous transfers.
+ * @type_bulk:Endpoint supports bulk transfers.
+ * @type_int:Endpoint supports interrupt transfers.
+ * @dir_in:Endpoint supports IN direction.
+ * @dir_out:Endpoint supports OUT direction.
+ */
+struct usb_ep_caps {
+       unsigned type_control:1;
+       unsigned type_iso:1;
+       unsigned type_bulk:1;
+       unsigned type_int:1;
+       unsigned dir_in:1;
+       unsigned dir_out:1;
+};
+
+#define USB_EP_CAPS_TYPE_CONTROL     0x01
+#define USB_EP_CAPS_TYPE_ISO         0x02
+#define USB_EP_CAPS_TYPE_BULK        0x04
+#define USB_EP_CAPS_TYPE_INT         0x08
+#define USB_EP_CAPS_TYPE_ALL \
+       (USB_EP_CAPS_TYPE_ISO | USB_EP_CAPS_TYPE_BULK | USB_EP_CAPS_TYPE_INT)
+#define USB_EP_CAPS_DIR_IN           0x01
+#define USB_EP_CAPS_DIR_OUT          0x02
+#define USB_EP_CAPS_DIR_ALL  (USB_EP_CAPS_DIR_IN | USB_EP_CAPS_DIR_OUT)
+
+#define USB_EP_CAPS(_type, _dir) \
+       { \
+               .type_control = !!(_type & USB_EP_CAPS_TYPE_CONTROL), \
+               .type_iso = !!(_type & USB_EP_CAPS_TYPE_ISO), \
+               .type_bulk = !!(_type & USB_EP_CAPS_TYPE_BULK), \
+               .type_int = !!(_type & USB_EP_CAPS_TYPE_INT), \
+               .dir_in = !!(_dir & USB_EP_CAPS_DIR_IN), \
+               .dir_out = !!(_dir & USB_EP_CAPS_DIR_OUT), \
+       }
+
 /**
  * struct usb_ep - device side representation of USB endpoint
  * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep_list:the gadget's ep_list holds all of its endpoints
+ * @caps:The structure describing types and directions supported by endoint.
  * @maxpacket:The maximum packet size used on this endpoint.  The initial
  *     value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
@@ -167,12 +206,15 @@ struct usb_ep_ops {
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
  * and is accessed only in response to a driver setup() callback.
  */
+
 struct usb_ep {
        void                    *driver_data;
 
        const char              *name;
        const struct usb_ep_ops *ops;
        struct list_head        ep_list;
+       struct usb_ep_caps      caps;
+       bool                    claimed;
        unsigned                maxpacket:16;
        unsigned                maxpacket_limit:16;
        unsigned                max_streams:16;
@@ -492,6 +534,9 @@ struct usb_gadget_ops {
        int     (*udc_start)(struct usb_gadget *,
                        struct usb_gadget_driver *);
        int     (*udc_stop)(struct usb_gadget *);
+       struct usb_ep *(*match_ep)(struct usb_gadget *,
+                       struct usb_endpoint_descriptor *,
+                       struct usb_ss_ep_comp_descriptor *);
 };
 
 /**
@@ -511,6 +556,7 @@ struct usb_gadget_ops {
  * @dev: Driver model state for this abstract device.
  * @out_epnum: last used out ep number
  * @in_epnum: last used in ep number
+ * @otg_caps: OTG capabilities of this gadget.
  * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *     gadget driver must provide a USB OTG descriptor.
@@ -526,6 +572,9 @@ struct usb_gadget_ops {
  * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
  *     MaxPacketSize.
  * @is_selfpowered: if the gadget is self-powered.
+ * @deactivated: True if gadget is deactivated - in deactivated state it cannot
+ *     be connected.
+ * @connected: True if gadget is connected.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
  * functions, handling all usb configurations and interfaces.  Gadget
@@ -559,6 +608,7 @@ struct usb_gadget {
        struct device                   dev;
        unsigned                        out_epnum;
        unsigned                        in_epnum;
+       struct usb_otg_caps             *otg_caps;
 
        unsigned                        sg_supported:1;
        unsigned                        is_otg:1;
@@ -567,7 +617,12 @@ struct usb_gadget {
        unsigned                        a_hnp_support:1;
        unsigned                        a_alt_hnp_support:1;
        unsigned                        quirk_ep_out_aligned_size:1;
+       unsigned                        quirk_altset_not_supp:1;
+       unsigned                        quirk_stall_not_supp:1;
+       unsigned                        quirk_zlp_not_supp:1;
        unsigned                        is_selfpowered:1;
+       unsigned                        deactivated:1;
+       unsigned                        connected:1;
 };
 #define work_to_gadget(w)      (container_of((w), struct usb_gadget, work))
 
@@ -584,7 +639,6 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
 #define gadget_for_each_ep(tmp, gadget) \
        list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
 
-
 /**
  * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget
  *     requires quirk_ep_out_aligned_size, otherwise reguens len.
@@ -602,6 +656,34 @@ usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len)
                        round_up(len, (size_t)ep->desc->wMaxPacketSize);
 }
 
+/**
+ * gadget_is_altset_supported - return true iff the hardware supports
+ *     altsettings
+ * @g: controller to check for quirk
+ */
+static inline int gadget_is_altset_supported(struct usb_gadget *g)
+{
+       return !g->quirk_altset_not_supp;
+}
+
+/**
+ * gadget_is_stall_supported - return true iff the hardware supports stalling
+ * @g: controller to check for quirk
+ */
+static inline int gadget_is_stall_supported(struct usb_gadget *g)
+{
+       return !g->quirk_stall_not_supp;
+}
+
+/**
+ * gadget_is_zlp_supported - return true iff the hardware supports zlp
+ * @g: controller to check for quirk
+ */
+static inline int gadget_is_zlp_supported(struct usb_gadget *g)
+{
+       return !g->quirk_zlp_not_supp;
+}
+
 /**
  * gadget_is_dualspeed - return true iff the hardware handles high speed
  * @g: controller that might support both high and full speeds
@@ -771,9 +853,24 @@ static inline int usb_gadget_vbus_disconnect(struct usb_gadget *gadget)
  */
 static inline int usb_gadget_connect(struct usb_gadget *gadget)
 {
+       int ret;
+
        if (!gadget->ops->pullup)
                return -EOPNOTSUPP;
-       return gadget->ops->pullup(gadget, 1);
+
+       if (gadget->deactivated) {
+               /*
+                * If gadget is deactivated we only save new state.
+                * Gadget will be connected automatically after activation.
+                */
+               gadget->connected = true;
+               return 0;
+       }
+
+       ret = gadget->ops->pullup(gadget, 1);
+       if (!ret)
+               gadget->connected = 1;
+       return ret;
 }
 
 /**
@@ -784,20 +881,88 @@ static inline int usb_gadget_connect(struct usb_gadget *gadget)
  * as a disconnect (when a VBUS session is active).  Not all systems
  * support software pullup controls.
  *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
+{
+       int ret;
+
+       if (!gadget->ops->pullup)
+               return -EOPNOTSUPP;
+
+       if (gadget->deactivated) {
+               /*
+                * If gadget is deactivated we only save new state.
+                * Gadget will stay disconnected after activation.
+                */
+               gadget->connected = false;
+               return 0;
+       }
+
+       ret = gadget->ops->pullup(gadget, 0);
+       if (!ret)
+               gadget->connected = 0;
+       return ret;
+}
+
+/**
+ * usb_gadget_deactivate - deactivate function which is not ready to work
+ * @gadget: the peripheral being deactivated
+ *
  * 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
+ * usb_gadget_activate() 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)
+static inline int usb_gadget_deactivate(struct usb_gadget *gadget)
 {
-       if (!gadget->ops->pullup)
-               return -EOPNOTSUPP;
-       return gadget->ops->pullup(gadget, 0);
+       int ret;
+
+       if (gadget->deactivated)
+               return 0;
+
+       if (gadget->connected) {
+               ret = usb_gadget_disconnect(gadget);
+               if (ret)
+                       return ret;
+               /*
+                * If gadget was being connected before deactivation, we want
+                * to reconnect it in usb_gadget_activate().
+                */
+               gadget->connected = true;
+       }
+       gadget->deactivated = true;
+
+       return 0;
 }
 
+/**
+ * usb_gadget_activate - activate function which is not ready to work
+ * @gadget: the peripheral being activated
+ *
+ * This routine activates gadget which was previously deactivated with
+ * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_activate(struct usb_gadget *gadget)
+{
+       if (!gadget->deactivated)
+               return 0;
+
+       gadget->deactivated = false;
+
+       /*
+        * If gadget has been connected before deactivation, or became connected
+        * while it was being deactivated, we call usb_gadget_connect().
+        */
+       if (gadget->connected)
+               return usb_gadget_connect(gadget);
+
+       return 0;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -1002,6 +1167,10 @@ int usb_assign_descriptors(struct usb_function *f,
                struct usb_descriptor_header **ss);
 void usb_free_all_descriptors(struct usb_function *f);
 
+struct usb_descriptor_header *usb_otg_descriptor_alloc(
+                               struct usb_gadget *gadget);
+int usb_otg_descriptor_init(struct usb_gadget *gadget,
+               struct usb_descriptor_header *otg_desc);
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify map/unmap of usb_requests to/from DMA */
@@ -1034,6 +1203,21 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep,
 
 /*-------------------------------------------------------------------------*/
 
+/* utility to find endpoint by name */
+
+extern struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g,
+               const char *name);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility to check if endpoint caps match descriptor needs */
+
+extern int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
+               struct usb_ep *ep, struct usb_endpoint_descriptor *desc,
+               struct usb_ss_ep_comp_descriptor *ep_comp);
+
+/*-------------------------------------------------------------------------*/
+
 /* utility to update vbus status for udc core, it may be scheduled */
 extern void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status);
 
index e55a1504266ec0333853793fa17e947feac02efd..8c8f6854c993b056ae6246ca58091fa9904602b2 100644 (file)
@@ -128,7 +128,7 @@ struct msm_otg_platform_data {
  */
 struct msm_usb_cable {
        struct notifier_block           nb;
-       struct extcon_specific_cable_nb conn;
+       struct extcon_dev               *extcon;
 };
 
 /**
@@ -155,6 +155,10 @@ struct msm_usb_cable {
  *     starting controller using usbcmd run/stop bit.
  * @vbus: VBUS signal state trakining, using extcon framework
  * @id: ID signal state trakining, using extcon framework
+ * @switch_gpio: Descriptor for GPIO used to control external Dual
+ *               SPDT USB Switch.
+ * @reboot: Used to inform the driver to route USB D+/D- line to Device
+ *         connector
  */
 struct msm_otg {
        struct usb_phy phy;
@@ -188,6 +192,9 @@ struct msm_otg {
 
        struct msm_usb_cable vbus;
        struct msm_usb_cable id;
+
+       struct gpio_desc *switch_gpio;
+       struct notifier_block reboot;
 };
 
 #endif
index cfe0528cdbb1048dd87e3d2910f2eaec454d3607..8c5a818ec2447aca31ce542e1cbb087f7b6fb04e 100644 (file)
@@ -15,6 +15,8 @@
 enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np);
 enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np);
 bool of_usb_host_tpl_support(struct device_node *np);
+int of_usb_update_otg_caps(struct device_node *np,
+                       struct usb_otg_caps *otg_caps);
 #else
 static inline enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np)
 {
@@ -30,6 +32,11 @@ static inline bool of_usb_host_tpl_support(struct device_node *np)
 {
        return false;
 }
+static inline int of_usb_update_otg_caps(struct device_node *np,
+                               struct usb_otg_caps *otg_caps)
+{
+       return 0;
+}
 #endif
 
 #if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_USB_SUPPORT)
index 52661c5da69012a3da3aa75d76a69ee45e6e92f0..bd1dcf8161009d78153082c23e7890a57f1b6b4f 100644 (file)
@@ -41,6 +41,21 @@ struct usb_otg {
 
 };
 
+/**
+ * struct usb_otg_caps - describes the otg capabilities of the device
+ * @otg_rev: The OTG revision number the device is compliant with, it's
+ *             in binary-coded decimal (i.e. 2.0 is 0200H).
+ * @hnp_support: Indicates if the device supports HNP.
+ * @srp_support: Indicates if the device supports SRP.
+ * @adp_support: Indicates if the device supports ADP.
+ */
+struct usb_otg_caps {
+       u16 otg_rev;
+       bool hnp_support;
+       bool srp_support;
+       bool adp_support;
+};
+
 extern const char *usb_otg_state_string(enum usb_otg_state state);
 
 /* Context: can sleep */
index aa33fd1b2d4f3a7575dc160d906907133119f1d5..f7adc6e01f9ea4544363d6f1bfa446854c813dec 100644 (file)
@@ -674,9 +674,21 @@ struct usb_otg_descriptor {
        __u8  bmAttributes;     /* support for HNP, SRP, etc */
 } __attribute__ ((packed));
 
+/* USB_DT_OTG (from OTG 2.0 supplement) */
+struct usb_otg20_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bmAttributes;     /* support for HNP, SRP and ADP, etc */
+       __le16 bcdOTG;          /* OTG and EH supplement release number
+                                * in binary-coded decimal(i.e. 2.0 is 0200H)
+                                */
+} __attribute__ ((packed));
+
 /* from usb_otg_descriptor.bmAttributes */
 #define USB_OTG_SRP            (1 << 0)
 #define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
+#define USB_OTG_ADP            (1 << 2)        /* support ADP */
 
 /*-------------------------------------------------------------------------*/