Commit 1be025d3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (260 commits)
  usb: renesas_usbhs: fixup inconsistent return from usbhs_pkt_push()
  usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB.
  USB: gadget: midi: memory leak in f_midi_bind_config()
  USB: gadget: midi: fix range check in f_midi_out_open()
  QE/FHCI: fixed the CONTROL bug
  usb: renesas_usbhs: tidyup for smatch warnings
  USB: Fix USB Kconfig dependency problem on 85xx/QoirQ platforms
  EHCI: workaround for MosChip controller bug
  usb: gadget: file_storage: fix race on unloading
  USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers
  USB: ftdi_sio.c:Fill MSR fields of the ftdi async_icount structure
  USB: ftdi_sio.c: Fill LSR fields of the ftdi async_icount structure
  USB: ftdi_sio.c:Fill TX field of the ftdi async_icount structure
  USB: ftdi_sio.c: Fill the RX field of the ftdi async_icount structure
  USB: ftdi_sio.c: Basic icount infrastructure for ftdi_sio
  usb/isp1760: Let OF bindings depend on general CONFIG_OF instead of PPC_OF .
  USB: ftdi_sio: Support TI/Luminary Micro Stellaris BD-ICDI Board
  USB: Fix runtime wakeup on OHCI
  xHCI/USB: Make xHCI driver have a BOS descriptor.
  usb: gadget: add new usb gadget for ACM and mass storage
  ...
parents 2d03423b a2c76b83
What: /sys/bus/pci/drivers/ehci_hcd/.../companion
/sys/bus/usb/devices/usbN/../companion
Date: January 2007
KernelVersion: 2.6.21
Contact: Alan Stern <stern@rowland.harvard.edu>
Description:
PCI-based EHCI USB controllers (i.e., high-speed USB-2.0
controllers) are often implemented along with a set of
"companion" full/low-speed USB-1.1 controllers. When a
high-speed device is plugged in, the connection is routed
to the EHCI controller; when a full- or low-speed device
is plugged in, the connection is routed to the companion
controller.
Sometimes you want to force a high-speed device to connect
at full speed, which can be accomplished by forcing the
connection to be routed to the companion controller.
That's what this file does. Writing a port number to the
file causes connections on that port to be routed to the
companion controller, and writing the negative of a port
number returns the port to normal operation.
For example: To force the high-speed device attached to
port 4 on bus 2 to run at full speed:
echo 4 >/sys/bus/usb/devices/usb2/../companion
To return the port to high-speed operation:
echo -4 >/sys/bus/usb/devices/usb2/../companion
Reading the file gives the list of ports currently forced
to the companion controller.
Note: Some EHCI controllers do not have companions; they
may contain an internal "transaction translator" or they
may be attached directly to a "rate-matching hub". This
mechanism will not work with such controllers. Also, it
cannot be used to force a port on a high-speed hub to
connect at full speed.
Note: When this file was first added, it appeared in a
different sysfs directory. The location given above is
correct for 2.6.35 (and probably several earlier kernel
versions as well).
...@@ -142,3 +142,18 @@ Description: ...@@ -142,3 +142,18 @@ Description:
such devices. such devices.
Users: Users:
usb_modeswitch usb_modeswitch
What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
Date: September 2011
Contact: Andiry Xu <andiry.xu@amd.com>
Description:
If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
is plugged in to a xHCI host which support link PM, it will
perform a LPM test; if the test is passed and host supports
USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
be enabled for the device and the USB device directory will
contain a file named power/usb2_hardware_lpm. The file holds
a string value (enable or disable) indicating whether or not
USB2 hardware LPM is enabled for the device. Developer can
write y/Y/1 or n/N/0 to the file to enable/disable the
feature.
TODO
~~~~~~
Please pick something while reading :)
- Convert interrupt handler to per-ep-thread-irq
As it turns out some DWC3-commands ~1ms to complete. Currently we spin
until the command completes which is bad.
Implementation idea:
- dwc core implements a demultiplexing irq chip for interrupts per
endpoint. The interrupt numbers are allocated during probe and belong
to the device. If MSI provides per-endpoint interrupt this dummy
interrupt chip can be replaced with "real" interrupts.
- interrupts are requested / allocated on usb_ep_enable() and removed on
usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
for ep0/1.
- dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
until the command completes.
- the interrupt handler is split into the following pieces:
- primary handler of the device
goes through every event and calls generic_handle_irq() for event
it. On return from generic_handle_irq() in acknowledges the event
counter so interrupt goes away (eventually).
- threaded handler of the device
none
- primary handler of the EP-interrupt
reads the event and tries to process it. Everything that requries
sleeping is handed over to the Thread. The event is saved in an
per-endpoint data-structure.
We probably have to pay attention not to process events once we
handed something to thread so we don't process event X prio Y
where X > Y.
- threaded handler of the EP-interrupt
handles the remaining EP work which might sleep such as waiting
for command completion.
Latency:
There should be no increase in latency since the interrupt-thread has a
high priority and will be run before an average task in user land
(except the user changed priorities).
...@@ -487,3 +487,29 @@ succeed, it may still remain active and thus cause the system to ...@@ -487,3 +487,29 @@ succeed, it may still remain active and thus cause the system to
resume as soon as the system suspend is complete. Or the remote resume as soon as the system suspend is complete. Or the remote
wakeup may fail and get lost. Which outcome occurs depends on timing wakeup may fail and get lost. Which outcome occurs depends on timing
and on the hardware and firmware design. and on the hardware and firmware design.
xHCI hardware link PM
---------------------
xHCI host controller provides hardware link power management to usb2.0
(xHCI 1.0 feature) and usb3.0 devices which support link PM. By
enabling hardware LPM, the host can automatically put the device into
lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices),
which state device can enter and resume very quickly.
The user interface for controlling USB2 hardware LPM is located in the
power/ subdirectory of each USB device's sysfs directory, that is, in
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
relevant attribute files is usb2_hardware_lpm.
power/usb2_hardware_lpm
When a USB2 device which support LPM is plugged to a
xHCI host root hub which support software LPM, the
host will run a software LPM test for it; if the device
enters L1 state and resume successfully and the host
supports USB2 hardware LPM, this file will show up and
driver will enable hardware LPM for the device. You
can write y/Y/1 or n/N/0 to the file to enable/disable
USB2 hardware LPM manually. This is for test purpose mainly.
...@@ -2136,6 +2136,14 @@ M: Matthew Garrett <mjg59@srcf.ucam.org> ...@@ -2136,6 +2136,14 @@ M: Matthew Garrett <mjg59@srcf.ucam.org>
S: Maintained S: Maintained
F: drivers/platform/x86/dell-wmi.c F: drivers/platform/x86/dell-wmi.c
DESIGNWARE USB3 DRD IP DRIVER
M: Felipe Balbi <balbi@ti.com>
L: linux-usb@vger.kernel.org
L: linux-omap@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
S: Maintained
F: drivers/usb/dwc3/
DEVICE NUMBER REGISTRY DEVICE NUMBER REGISTRY
M: Torben Mathiasen <device@lanana.org> M: Torben Mathiasen <device@lanana.org>
W: http://lanana.org/docs/device-list/index.html W: http://lanana.org/docs/device-list/index.html
......
...@@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb; ...@@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb;
extern struct pxa_device_desc pxa168_device_keypad; extern struct pxa_device_desc pxa168_device_keypad;
extern struct pxa_device_desc pxa168_device_eth; extern struct pxa_device_desc pxa168_device_eth;
struct pxa168_usb_pdata {
/* If NULL, default phy init routine for PXA168 would be called */
int (*phy_init)(void __iomem *usb_phy_reg_base);
};
/* pdata can be NULL */
int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
static inline int pxa168_add_uart(int id) static inline int pxa168_add_uart(int id)
{ {
struct pxa_device_desc *d = NULL; struct pxa_device_desc *d = NULL;
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include <mach/dma.h> #include <mach/dma.h>
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/mfp.h> #include <mach/mfp.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/pxa168.h>
#include "common.h" #include "common.h"
#include "clock.h" #include "clock.h"
...@@ -83,6 +86,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000); ...@@ -83,6 +86,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
static APMU_CLK(nand, NAND, 0x19b, 156000000); static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(lcd, LCD, 0x7f, 312000000); static APMU_CLK(lcd, LCD, 0x7f, 312000000);
static APMU_CLK(eth, ETH, 0x09, 0); static APMU_CLK(eth, ETH, 0x09, 0);
static APMU_CLK(usb, USB, 0x12, 0);
/* device and clock bindings */ /* device and clock bindings */
static struct clk_lookup pxa168_clkregs[] = { static struct clk_lookup pxa168_clkregs[] = {
...@@ -104,6 +108,7 @@ static struct clk_lookup pxa168_clkregs[] = { ...@@ -104,6 +108,7 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL), INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL), INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"), INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
}; };
static int __init pxa168_init(void) static int __init pxa168_init(void)
...@@ -169,3 +174,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61); ...@@ -169,3 +174,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8); PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c); PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff); PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff);
struct resource pxa168_usb_host_resources[] = {
/* USB Host conroller register base */
[0] = {
.start = 0xd4209000,
.end = 0xd4209000 + 0x200,
.flags = IORESOURCE_MEM,
.name = "pxa168-usb-host",
},
/* USB PHY register base */
[1] = {
.start = 0xd4206000,
.end = 0xd4206000 + 0xff,
.flags = IORESOURCE_MEM,
.name = "pxa168-usb-phy",
},
[2] = {
.start = IRQ_PXA168_USB2,
.end = IRQ_PXA168_USB2,
.flags = IORESOURCE_IRQ,
},
};
static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
struct platform_device pxa168_device_usb_host = {
.name = "pxa168-ehci",
.id = -1,
.dev = {
.dma_mask = &pxa168_usb_host_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
.resource = pxa168_usb_host_resources,
};
int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
{
pxa168_device_usb_host.dev.platform_data = pdata;
return platform_device_register(&pxa168_device_usb_host);
}
...@@ -242,14 +242,11 @@ obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \ ...@@ -242,14 +242,11 @@ obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \ obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
hsmmc.o hsmmc.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \ obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
hsmmc.o \ hsmmc.o
omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \ obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \
hsmmc.o \ hsmmc.o
omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o \ obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
omap_phy_internal.o \
obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o
...@@ -260,6 +257,8 @@ obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o ...@@ -260,6 +257,8 @@ obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o
usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o
obj-y += $(usbfs-m) $(usbfs-y) obj-y += $(usbfs-m) $(usbfs-y)
obj-y += usb-musb.o obj-y += usb-musb.o
obj-y += omap_phy_internal.o
obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o
obj-y += usb-host.o obj-y += usb-host.o
......
...@@ -810,6 +810,7 @@ static struct usbhs_private usbhs1_private = { ...@@ -810,6 +810,7 @@ static struct usbhs_private usbhs1_private = {
}, },
.driver_param = { .driver_param = {
.buswait_bwait = 4, .buswait_bwait = 4,
.has_otg = 1,
.pipe_type = usbhs1_pipe_cfg, .pipe_type = usbhs1_pipe_cfg,
.pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg), .pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg),
.d0_tx_id = SHDMA_SLAVE_USB1_TX, .d0_tx_id = SHDMA_SLAVE_USB1_TX,
......
...@@ -12,6 +12,11 @@ menuconfig USB_SUPPORT ...@@ -12,6 +12,11 @@ menuconfig USB_SUPPORT
if USB_SUPPORT if USB_SUPPORT
config USB_COMMON
tristate
default y
depends on USB || USB_GADGET
# Host-side USB depends on having a host controller # Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ... # NOTE: dummy_hcd is always an option, but it's ignored here ...
# NOTE: SL-811 option should be board-specific ... # NOTE: SL-811 option should be board-specific ...
...@@ -19,6 +24,7 @@ config USB_ARCH_HAS_HCD ...@@ -19,6 +24,7 @@ config USB_ARCH_HAS_HCD
boolean boolean
default y if USB_ARCH_HAS_OHCI default y if USB_ARCH_HAS_OHCI
default y if USB_ARCH_HAS_EHCI default y if USB_ARCH_HAS_EHCI
default y if USB_ARCH_HAS_XHCI
default y if PCMCIA && !M32R # sl811_cs default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811 default y if ARM # SL-811
default y if BLACKFIN # SL-811 default y if BLACKFIN # SL-811
...@@ -54,7 +60,7 @@ config USB_ARCH_HAS_OHCI ...@@ -54,7 +60,7 @@ config USB_ARCH_HAS_OHCI
# some non-PCI hcds implement EHCI # some non-PCI hcds implement EHCI
config USB_ARCH_HAS_EHCI config USB_ARCH_HAS_EHCI
boolean boolean
default y if PPC_83xx default y if FSL_SOC
default y if PPC_MPC512x default y if PPC_MPC512x
default y if SOC_AU1200 default y if SOC_AU1200
default y if ARCH_IXP4XX default y if ARCH_IXP4XX
...@@ -69,6 +75,12 @@ config USB_ARCH_HAS_EHCI ...@@ -69,6 +75,12 @@ config USB_ARCH_HAS_EHCI
default y if ARCH_MSM default y if ARCH_MSM
default y if MICROBLAZE default y if MICROBLAZE
default y if SPARC_LEON default y if SPARC_LEON
default y if ARCH_MMP
default PCI
# some non-PCI HCDs implement xHCI
config USB_ARCH_HAS_XHCI
boolean
default PCI default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
...@@ -110,6 +122,8 @@ config USB ...@@ -110,6 +122,8 @@ config USB
source "drivers/usb/core/Kconfig" source "drivers/usb/core/Kconfig"
source "drivers/usb/dwc3/Kconfig"
source "drivers/usb/mon/Kconfig" source "drivers/usb/mon/Kconfig"
source "drivers/usb/wusbcore/Kconfig" source "drivers/usb/wusbcore/Kconfig"
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_MON) += mon/ obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_PCI) += host/ obj-$(CONFIG_PCI) += host/
...@@ -51,3 +53,5 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb/ ...@@ -51,3 +53,5 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_OTG_UTILS) += otg/ obj-$(CONFIG_USB_OTG_UTILS) += otg/
obj-$(CONFIG_USB_GADGET) += gadget/ obj-$(CONFIG_USB_GADGET) += gadget/
obj-$(CONFIG_USB_COMMON) += usb-common.o
...@@ -1058,11 +1058,11 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1058,11 +1058,11 @@ static int acm_probe(struct usb_interface *intf,
goto alloc_fail; goto alloc_fail;
} }
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); ctrlsize = usb_endpoint_maxp(epctrl);
readsize = le16_to_cpu(epread->wMaxPacketSize) * readsize = usb_endpoint_maxp(epread) *
(quirks == SINGLE_RX_URB ? 1 : 2); (quirks == SINGLE_RX_URB ? 1 : 2);
acm->combined_interfaces = combined_interfaces; acm->combined_interfaces = combined_interfaces;
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20; acm->writesize = usb_endpoint_maxp(epwrite) * 20;
acm->control = control_interface; acm->control = control_interface;
acm->data = data_interface; acm->data = data_interface;
acm->minor = minor; acm->minor = minor;
...@@ -1534,6 +1534,9 @@ static const struct usb_device_id acm_ids[] = { ...@@ -1534,6 +1534,9 @@ static const struct usb_device_id acm_ids[] = {
{ NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
{ SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
/* Support for Owen devices */
{ USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
/* Support Lego NXT using pbLua firmware */ /* Support Lego NXT using pbLua firmware */
......
...@@ -682,7 +682,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -682,7 +682,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!ep || !usb_endpoint_is_int_in(ep)) if (!ep || !usb_endpoint_is_int_in(ep))
goto err; goto err;
desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); desc->wMaxPacketSize = usb_endpoint_maxp(ep);
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0; desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
......
...@@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) ...@@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++) for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
if (current_setting->endpoint[n].desc.bEndpointAddress == if (current_setting->endpoint[n].desc.bEndpointAddress ==
data->bulk_in) data->bulk_in)
max_size = le16_to_cpu(current_setting->endpoint[n]. max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
desc.wMaxPacketSize);
if (max_size == 0) { if (max_size == 0) {
dev_err(dev, "Couldn't get wMaxPacketSize\n"); dev_err(dev, "Couldn't get wMaxPacketSize\n");
...@@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) ...@@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
desc = &current_setting->endpoint[n].desc; desc = &current_setting->endpoint[n].desc;
if (desc->bEndpointAddress == data->bulk_in) if (desc->bEndpointAddress == data->bulk_in)
max_size = le16_to_cpu(desc->wMaxPacketSize); max_size = usb_endpoint_maxp(desc);
} }
if (max_size == 0) { if (max_size == 0) {
......
...@@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, ...@@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
if (usb_endpoint_xfer_isoc(&ep->desc)) if (usb_endpoint_xfer_isoc(&ep->desc))
max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
le16_to_cpu(ep->desc.wMaxPacketSize); usb_endpoint_maxp(&ep->desc);
else if (usb_endpoint_xfer_int(&ep->desc)) else if (usb_endpoint_xfer_int(&ep->desc))
max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) * max_tx = usb_endpoint_maxp(&ep->desc) *
(desc->bMaxBurst + 1); (desc->bMaxBurst + 1);
else else
max_tx = 999999; max_tx = 999999;
...@@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
cfgno, inum, asnum, d->bEndpointAddress); cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT; endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint->desc.bInterval = 1; endpoint->desc.bInterval = 1;
if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8) if (usb_endpoint_maxp(&endpoint->desc) > 8)
endpoint->desc.wMaxPacketSize = cpu_to_le16(8); endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
} }
...@@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
&& usb_endpoint_xfer_bulk(d)) { && usb_endpoint_xfer_bulk(d)) {
unsigned maxp; unsigned maxp;
maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff; maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
if (maxp != 512) if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d " dev_warn(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n", "bulk endpoint 0x%X has invalid maxpacket %d\n",
...@@ -755,3 +755,106 @@ int usb_get_configuration(struct usb_device *dev) ...@@ -755,3 +755,106 @@ int usb_get_configuration(struct usb_device *dev)
dev_err(ddev, "out of memory\n"); dev_err(ddev, "out of memory\n");
return result; return result;
} }
void usb_release_bos_descriptor(struct usb_device *dev)
{
if (dev->bos) {
kfree(dev->bos->desc);
kfree(dev->bos);
dev->bos = NULL;
}
}
/* Get BOS descriptor set */
int usb_get_bos_descriptor(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
struct usb_bos_descriptor *bos;
struct usb_dev_cap_header *cap;
unsigned char *buffer;
int length, total_len, num, i;
int ret;
bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
if (!bos)
return -ENOMEM;
/* Get BOS descriptor */
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
if (ret < USB_DT_BOS_SIZE) {
dev_err(ddev, "unable to get BOS descriptor\n");
if (ret >= 0)
ret = -ENOMSG;
kfree(bos);
return ret;
}
length = bos->bLength;
total_len = le16_to_cpu(bos->wTotalLength);
num = bos->bNumDeviceCaps;
kfree(bos);
if (total_len < length)
return -EINVAL;
dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
if (!dev->bos)
return -ENOMEM;
/* Now let's get the whole BOS descriptor set */
buffer = kzalloc(total_len, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto err;
}
dev->bos->desc = (struct usb_bos_descriptor *)buffer;
ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
if (ret < total_len) {
dev_err(ddev, "unable to get BOS descriptor set\n");
if (ret >= 0)
ret = -ENOMSG;
goto err;
}
total_len -= length;
for (i = 0; i < num; i++) {
buffer += length;
cap = (struct usb_dev_cap_header *)buffer;
length = cap->bLength;
if (total_len < length)
break;
total_len -= length;
if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
dev_warn(ddev, "descriptor type invalid, skip\n");
continue;
}
switch (cap->bDevCapabilityType) {
case USB_CAP_TYPE_WIRELESS_USB:
/* Wireless USB cap descriptor is handled by wusb */
break;
case USB_CAP_TYPE_EXT:
dev->bos->ext_cap =
(struct usb_ext_cap_descriptor *)buffer;
break;
case USB_SS_CAP_TYPE:
dev->bos->ss_cap =
(struct usb_ss_cap_descriptor *)buffer;
break;
case CONTAINER_ID_TYPE:
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
default:
break;
}
}
return 0;
err:
usb_release_bos_descriptor(dev);
return ret;
}
...@@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, ...@@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
dir = usb_endpoint_dir_in(desc) ? 'I' : 'O'; dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
if (speed == USB_SPEED_HIGH) { if (speed == USB_SPEED_HIGH) {
switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) { switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
case 1 << 11: case 1 << 11:
bandwidth = 2; break; bandwidth = 2; break;
case 2 << 11: case 2 << 11:
...@@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, ...@@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
desc->bmAttributes, type, desc->bmAttributes, type,
(le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) * (usb_endpoint_maxp(desc) & 0x07ff) *
bandwidth, bandwidth,
interval, unit); interval, unit);
return start; return start;
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/user_namespace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
...@@ -68,7 +69,7 @@ struct dev_state { ...@@ -68,7 +69,7 @@ struct dev_state {
wait_queue_head_t wait; /* wake up if a request completed */ wait_queue_head_t wait; /* wake up if a request completed */
unsigned int discsignr; unsigned int discsignr;
struct pid *disc_pid; struct pid *disc_pid;
uid_t disc_uid, disc_euid; const struct cred *cred;
void __user *disccontext; void __user *disccontext;
unsigned long ifclaimed; unsigned long ifclaimed;
u32 secid; u32 secid;
...@@ -79,7 +80,7 @@ struct async { ...@@ -79,7 +80,7 @@ struct async {
struct list_head asynclist; struct list_head asynclist;
struct dev_state *ps; struct dev_state *ps;
struct pid *pid; struct pid *pid;
uid_t uid, euid; const struct cred *cred;
unsigned int signr; unsigned int signr;
unsigned int ifnum; unsigned int ifnum;
void __user *userbuffer; void __user *userbuffer;
...@@ -248,6 +249,7 @@ static struct async *alloc_async(unsigned int numisoframes) ...@@ -248,6 +249,7 @@ static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as) static void free_async(struct async *as)
{ {
put_pid(as->pid); put_pid(as->pid);
put_cred(as->cred);
kfree(as->urb->transfer_buffer); kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet); kfree(as->urb->setup_packet);
usb_free_urb(as->urb); usb_free_urb(as->urb);
...@@ -393,9 +395,8 @@ static void async_completed(struct urb *urb) ...@@ -393,9 +395,8 @@ static void async_completed(struct urb *urb)
struct dev_state *ps = as->ps; struct dev_state *ps = as->ps;
struct siginfo sinfo; struct siginfo sinfo;
struct pid *pid = NULL; struct pid *pid = NULL;
uid_t uid = 0;
uid_t euid = 0;
u32 secid = 0; u32 secid = 0;
const struct cred *cred = NULL;
int signr; int signr;
spin_lock(&ps->lock); spin_lock(&ps->lock);
...@@ -407,9 +408,8 @@ static void async_completed(struct urb *urb) ...@@ -407,9 +408,8 @@ static void async_completed(struct urb *urb)
sinfo.si_errno = as->status; sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO; sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb; sinfo.si_addr = as->userurb;
pid = as->pid; pid = get_pid(as->pid);
uid = as->uid; cred = get_cred(as->cred);
euid = as->euid;
secid = as->secid; secid = as->secid;
} }
snoop(&urb->dev->dev, "urb complete\n"); snoop(&urb->dev->dev, "urb complete\n");
...@@ -422,9 +422,11 @@ static void async_completed(struct urb *urb) ...@@ -422,9 +422,11 @@ static void async_completed(struct urb *urb)
cancel_bulk_urbs(ps, as->bulk_addr); cancel_bulk_urbs(ps, as->bulk_addr);
spin_unlock(&ps->lock); spin_unlock(&ps->lock);
if (signr) if (signr) {
kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);
euid, secid); put_pid(pid);
put_cred(cred);
}
wake_up(&ps->wait); wake_up(&ps->wait);
} }
...@@ -607,9 +609,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep) ...@@ -607,9 +609,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
} }
static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
unsigned int index) unsigned int request, unsigned int index)
{ {
int ret = 0; int ret = 0;
struct usb_host_interface *alt_setting;
if (ps->dev->state != USB_STATE_UNAUTHENTICATED if (ps->dev->state != USB_STATE_UNAUTHENTICATED
&& ps->dev->state != USB_STATE_ADDRESS && ps->dev->state != USB_STATE_ADDRESS
...@@ -618,6 +621,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, ...@@ -618,6 +621,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
return 0; return 0;
/*
* check for the special corner case 'get_device_id' in the printer
* class specification, where wIndex is (interface << 8 | altsetting)
* instead of just interface
*/
if (requesttype == 0xa1 && request == 0) {
alt_setting = usb_find_alt_setting(ps->dev->actconfig,
index >> 8, index & 0xff);
if (alt_setting
&& alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
index >>= 8;
}
index &= 0xff; index &= 0xff;
switch (requesttype & USB_RECIP_MASK) { switch (requesttype & USB_RECIP_MASK) {
case USB_RECIP_ENDPOINT: case USB_RECIP_ENDPOINT:
...@@ -656,7 +672,6 @@ static int usbdev_open(struct inode *inode, struct file *file) ...@@ -656,7 +672,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
{ {
struct usb_device *dev = NULL; struct usb_device *dev = NULL;
struct dev_state *ps; struct dev_state *ps;
const struct cred *cred = current_cred();
int ret; int ret;
ret = -ENOMEM; ret = -ENOMEM;
...@@ -706,8 +721,7 @@ static int usbdev_open(struct inode *inode, struct file *file) ...@@ -706,8 +721,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
init_waitqueue_head(&ps->wait); init_waitqueue_head(&ps->wait);
ps->discsignr = 0; ps->discsignr = 0;
ps->disc_pid = get_pid(task_pid(current)); ps->disc_pid = get_pid(task_pid(current));
ps->disc_uid = cred->uid; ps->cred = get_current_cred();
ps->disc_euid = cred->euid;
ps->disccontext = NULL; ps->disccontext = NULL;
ps->ifclaimed = 0; ps->ifclaimed = 0;
security_task_getsecid(current, &ps->secid); security_task_getsecid(current, &ps->secid);
...@@ -749,6 +763,7 @@ static int usbdev_release(struct inode *inode, struct file *file) ...@@ -749,6 +763,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
usb_unlock_device(dev); usb_unlock_device(dev);
usb_put_dev(dev); usb_put_dev(dev);
put_pid(ps->disc_pid); put_pid(ps->disc_pid);
put_cred(ps->cred);
as = async_getcompleted(ps); as = async_getcompleted(ps);
while (as) { while (as) {
...@@ -770,7 +785,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) ...@@ -770,7 +785,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (copy_from_user(&ctrl, arg, sizeof(ctrl))) if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT; return -EFAULT;
ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
ctrl.wIndex);
if (ret) if (ret)
return ret; return ret;
wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */
...@@ -1048,7 +1064,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1048,7 +1064,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_host_endpoint *ep; struct usb_host_endpoint *ep;
struct async *as; struct async *as;
struct usb_ctrlrequest *dr = NULL; struct usb_ctrlrequest *dr = NULL;
const struct cred *cred = current_cred();
unsigned int u, totlen, isofrmlen; unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1; int ret, ifnum = -1;
int is_in; int is_in;
...@@ -1100,7 +1115,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1100,7 +1115,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr); kfree(dr);
return -EINVAL; return -EINVAL;
} }
ret = check_ctrlrecip(ps, dr->bRequestType, ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
le16_to_cpup(&dr->wIndex)); le16_to_cpup(&dr->wIndex));
if (ret) { if (ret) {
kfree(dr); kfree(dr);
...@@ -1262,8 +1277,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, ...@@ -1262,8 +1277,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->signr = uurb->signr; as->signr = uurb->signr;
as->ifnum = ifnum; as->ifnum = ifnum;
as->pid = get_pid(task_pid(current)); as->pid = get_pid(task_pid(current));
as->uid = cred->uid; as->cred = get_current_cred();
as->euid = cred->euid;
security_task_getsecid(current, &as->secid); security_task_getsecid(current, &as->secid);
if (!is_in && uurb->buffer_length > 0) { if (!is_in && uurb->buffer_length > 0) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
...@@ -1981,9 +1995,8 @@ static void usbdev_remove(struct usb_device *udev) ...@@ -1981,9 +1995,8 @@ static void usbdev_remove(struct usb_device *udev)
sinfo.si_errno = EPIPE; sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO; sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = ps->disccontext; sinfo.si_addr = ps->disccontext;
kill_pid_info_as_uid(ps->discsignr, &sinfo, kill_pid_info_as_cred(ps->discsignr, &sinfo,
ps->disc_pid, ps->disc_uid, ps->disc_pid, ps->cred, ps->secid);
ps->disc_euid, ps->secid);
} }
} }
} }
......
...@@ -1583,7 +1583,7 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) ...@@ -1583,7 +1583,7 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count), __func__, atomic_read(&intf->dev.power.usage_count),
status); status);
if (status > 0) if (status > 0 || status == -EINPROGRESS)
status = 0; status = 0;
return status; return status;
} }
...@@ -1700,6 +1700,20 @@ int usb_runtime_idle(struct device *dev) ...@@ -1700,6 +1700,20 @@ int usb_runtime_idle(struct device *dev)
return 0; return 0;
} }
int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
int ret = -EPERM;
if (hcd->driver->set_usb2_hw_lpm) {
ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
if (!ret)
udev->usb2_hw_lpm_enabled = enable;
}
return ret;
}
#endif /* CONFIG_USB_SUSPEND */ #endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
......
...@@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev, ...@@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev,
{ {
struct ep_device *ep = to_ep_device(dev); struct ep_device *ep = to_ep_device(dev);
return sprintf(buf, "%04x\n", return sprintf(buf, "%04x\n",
le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff); usb_endpoint_maxp(ep->desc) & 0x07ff);
} }
static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
......
...@@ -242,7 +242,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -242,7 +242,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_master(dev); pci_set_master(dev);
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
if (retval != 0) if (retval != 0)
goto unmap_registers; goto unmap_registers;
set_hs_companion(dev, hcd); set_hs_companion(dev, hcd);
......
...@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd; struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength; u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer; u8 *ubuf = urb->transfer_buffer;
u8 tbuf [sizeof (struct usb_hub_descriptor)] /*
* tbuf should be as big as the BOS descriptor and
* the USB hub descriptor.
*/
u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
__attribute__((aligned(4))); __attribute__((aligned(4)));
const u8 *bufp = tbuf; const u8 *bufp = tbuf;
unsigned len = 0; unsigned len = 0;
...@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
else /* unsupported IDs --> "protocol stall" */ else /* unsupported IDs --> "protocol stall" */
goto error; goto error;
break; break;
case USB_DT_BOS << 8:
goto nongeneric;
default: default:
goto error; goto error;
} }
...@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* CLASS REQUESTS (and errors) */ /* CLASS REQUESTS (and errors) */
default: default:
nongeneric:
/* non-generic request */ /* non-generic request */
switch (typeReq) { switch (typeReq) {
case GetHubStatus: case GetHubStatus:
...@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case GetHubDescriptor: case GetHubDescriptor:
len = sizeof (struct usb_hub_descriptor); len = sizeof (struct usb_hub_descriptor);
break; break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
/* len is returned by hub_control */
break;
} }
status = hcd->driver->hub_control (hcd, status = hcd->driver->hub_control (hcd,
typeReq, wValue, wIndex, typeReq, wValue, wIndex,
...@@ -615,7 +625,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -615,7 +625,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
status = -EPIPE; status = -EPIPE;
} }
if (status) { if (status < 0) {
len = 0; len = 0;
if (status != -EPIPE) { if (status != -EPIPE) {
dev_dbg (hcd->self.controller, dev_dbg (hcd->self.controller,
...@@ -624,6 +634,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -624,6 +634,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
typeReq, wValue, wIndex, typeReq, wValue, wIndex,
wLength, status); wLength, status);
} }
} else if (status > 0) {
/* hub_control may return the length of data copied. */
len = status;
status = 0;
} }
if (len) { if (len) {
if (urb->transfer_buffer_length < len) if (urb->transfer_buffer_length < len)
...@@ -2429,7 +2443,7 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2429,7 +2443,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
* but drivers can override it in reset() if needed, along with * but drivers can override it in reset() if needed, along with
* recording the overall controller's system wakeup capability. * recording the overall controller's system wakeup capability.
*/ */
device_init_wakeup(&rhdev->dev, 1); device_set_wakeup_capable(&rhdev->dev, 1);
/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
* registered. But since the controller can die at any time, * registered. But since the controller can die at any time,
...@@ -2478,6 +2492,13 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -2478,6 +2492,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
} }
if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd); usb_hcd_poll_rh_status(hcd);
/*
* Host controllers don't generate their own wakeup requests;
* they only forward requests from the root hub. Therefore
* controllers should always be enabled for remote wakeup.
*/
device_wakeup_enable(hcd->self.controller);
return retval; return retval;
error_create_attr_group: error_create_attr_group:
......
This diff is collapsed.
...@@ -435,7 +435,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, ...@@ -435,7 +435,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
len = sg->length; len = sg->length;
if (length) { if (length) {
len = min_t(unsigned, len, length); len = min_t(size_t, len, length);
length -= len; length -= len;
if (length == 0) if (length == 0)
io->entries = i + 1; io->entries = i + 1;
......
...@@ -38,6 +38,27 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -38,6 +38,27 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Creative SB Audigy 2 NX */ /* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam C200 */
{ USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam C250 */
{ USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam C300 */
{ USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam B/C500 */
{ USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam Pro 9000 */
{ USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam C310 */
{ USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Webcam C270 */
{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Harmony 700-series */ /* Logitech Harmony 700-series */
{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
...@@ -69,6 +90,9 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -69,6 +90,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x06a3, 0x0006), .driver_info = { USB_DEVICE(0x06a3, 0x0006), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS }, USB_QUIRK_CONFIG_INTF_STRINGS },
/* Guillemot Webcam Hercules Dualpix Exchange*/
{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
/* M-Systems Flash Disk Pioneers */ /* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
......
...@@ -412,6 +412,56 @@ set_level(struct device *dev, struct device_attribute *attr, ...@@ -412,6 +412,56 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
static ssize_t
show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct usb_device *udev = to_usb_device(dev);
const char *p;
if (udev->usb2_hw_lpm_enabled == 1)
p = "enabled";
else
p = "disabled";
return sprintf(buf, "%s\n", p);
}
static ssize_t
set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
bool value;
int ret;
usb_lock_device(udev);
ret = strtobool(buf, &value);
if (!ret)
ret = usb_set_usb2_hardware_lpm(udev, value);
usb_unlock_device(udev);
if (!ret)
return count;
return ret;
}
static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
set_usb2_hardware_lpm);
static struct attribute *usb2_hardware_lpm_attr[] = {
&dev_attr_usb2_hardware_lpm.attr,
NULL,
};
static struct attribute_group usb2_hardware_lpm_attr_group = {
.name = power_group_name,
.attrs = usb2_hardware_lpm_attr,
};
static struct attribute *power_attrs[] = { static struct attribute *power_attrs[] = {
&dev_attr_autosuspend.attr, &dev_attr_autosuspend.attr,
&dev_attr_level.attr, &dev_attr_level.attr,
...@@ -428,13 +478,20 @@ static int add_power_attributes(struct device *dev) ...@@ -428,13 +478,20 @@ static int add_power_attributes(struct device *dev)
{ {
int rc = 0; int rc = 0;
if (is_usb_device(dev)) if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
rc = sysfs_merge_group(&dev->kobj, &power_attr_group); rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
if (udev->usb2_hw_lpm_capable == 1)
rc = sysfs_merge_group(&dev->kobj,
&usb2_hardware_lpm_attr_group);
}
return rc; return rc;
} }
static void remove_power_attributes(struct device *dev) static void remove_power_attributes(struct device *dev)
{ {
sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
sysfs_unmerge_group(&dev->kobj, &power_attr_group); sysfs_unmerge_group(&dev->kobj, &power_attr_group);
} }
......
...@@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) ...@@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
dev->state < USB_STATE_CONFIGURED) dev->state < USB_STATE_CONFIGURED)
return -ENODEV; return -ENODEV;
max = le16_to_cpu(ep->desc.wMaxPacketSize); max = usb_endpoint_maxp(&ep->desc);
if (max <= 0) { if (max <= 0) {
dev_dbg(&dev->dev, dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
......
...@@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev) ...@@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev)
hcd = bus_to_hcd(udev->bus); hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev); usb_destroy_configuration(udev);
usb_release_bos_descriptor(udev);
usb_put_hcd(hcd); usb_put_hcd(hcd);
kfree(udev->product); kfree(udev->product);
kfree(udev->manufacturer); kfree(udev->manufacturer);
......
...@@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev); ...@@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size); unsigned int size);
extern int usb_get_bos_descriptor(struct usb_device *dev);
extern void usb_release_bos_descriptor(struct usb_device *dev);
extern char *usb_cache_string(struct usb_device *udev, int index); extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_choose_configuration(struct usb_device *udev); extern int usb_choose_configuration(struct usb_device *udev);
...@@ -80,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev); ...@@ -80,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev);
extern int usb_runtime_suspend(struct device *dev); extern int usb_runtime_suspend(struct device *dev);
extern int usb_runtime_resume(struct device *dev); extern int usb_runtime_resume(struct device *dev);
extern int usb_runtime_idle(struct device *dev); extern int usb_runtime_idle(struct device *dev);
extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
#else #else
...@@ -94,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev) ...@@ -94,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev)
return 0; return 0;
} }
static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
{
return 0;
}
#endif #endif
extern struct bus_type usb_bus_type; extern struct bus_type usb_bus_type;
......
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
depends on (USB || USB_GADGET)
select USB_OTG_UTILS
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
If you choose to build this driver is a dynamically linked
module, the module will be called dwc3.ko.
if USB_DWC3
config USB_DWC3_DEBUG
bool "Enable Debugging Messages"
help
Say Y here to enable debugging messages on DWC3 Driver.
config USB_DWC3_VERBOSE
bool "Enable Verbose Debugging Messages"
depends on USB_DWC3_DEBUG
help
Say Y here to enable verbose debugging messages on DWC3 Driver.
endif
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
ifneq ($(CONFIG_USB_GADGET_DWC3),)
dwc3-y += gadget.o ep0.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
endif
##
# Platform-specific glue layers go here
#
# NOTICE: Make sure your glue layer doesn't depend on anything
# which is arch-specific and that it compiles on all situations.
#
# We want to keep this requirement in order to be able to compile
# the entire driver (with all its glue layers) on several architectures
# and make sure it compiles fine. This will also help with allmodconfig
# and allyesconfig builds.
#
# The only exception is the PCI glue layer, but that's only because
# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
##
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
endif
This diff is collapsed.
This diff is collapsed.
/**
* debug.h - DesignWare USB3 DRD Controller Debug Header
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "core.h"
#ifdef CONFIG_DEBUG_FS
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
#else
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
{ }
#endif
This diff is collapsed.
This diff is collapsed.
/**
* dwc3-pci.c - PCI Specific glue layer
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define DWC3_PCI_DEVS_POSSIBLE 32
struct dwc3_pci {
struct device *dev;
struct platform_device *dwc3;
};
static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
{
int id;
again:
id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
if (id < DWC3_PCI_DEVS_POSSIBLE) {
int old;
old = test_and_set_bit(id, dwc3_pci_devs);
if (old)
goto again;
} else {
dev_err(glue->dev, "no space for new device\n");
id = -ENOMEM;
}
return 0;
}
static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
{
int ret;
if (id < 0)
return;
ret = test_bit(id, dwc3_pci_devs);
WARN(!ret, "Device: %s\nID %d not in use\n",
dev_driver_string(glue->dev), id);
clear_bit(id, dwc3_pci_devs);
}
static int __devinit dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
struct resource res[2];
struct platform_device *dwc3;
struct dwc3_pci *glue;
int ret = -ENOMEM;
int devid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pci->dev, "not enough memory\n");
goto err0;
}
glue->dev = &pci->dev;
ret = pci_enable_device(pci);
if (ret) {
dev_err(&pci->dev, "failed to enable pci device\n");
goto err1;
}
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
devid = dwc3_pci_get_device_id(glue);
if (devid < 0)
goto err2;
dwc3 = platform_device_alloc("dwc3-pci", devid);
if (!dwc3) {
dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
goto err3;
}
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
res[0].start = pci_resource_start(pci, 0);
res[0].end = pci_resource_end(pci, 0);
res[0].name = "dwc_usb3";
res[0].flags = IORESOURCE_MEM;
res[1].start = pci->irq;
res[1].name = "dwc_usb3";
res[1].flags = IORESOURCE_IRQ;
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
goto err4;
}
pci_set_drvdata(pci, glue);
dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
dwc3->dev.dma_mask = pci->dev.dma_mask;
dwc3->dev.dma_parms = pci->dev.dma_parms;
dwc3->dev.parent = &pci->dev;
glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pci->dev, "failed to register dwc3 device\n");
goto err4;
}
return 0;
err4:
pci_set_drvdata(pci, NULL);
platform_device_put(dwc3);
err3:
dwc3_pci_put_device_id(glue, devid);
err2:
pci_disable_device(pci);
err1:
kfree(pci);
err0:
return ret;
}
static void __devexit dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
dwc3_pci_put_device_id(glue, glue->dwc3->id);
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
pci_disable_device(pci);
kfree(glue);
}
static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
{
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
},
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
static struct pci_driver dwc3_pci_driver = {
.name = "pci-dwc3",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = __devexit_p(dwc3_pci_remove),
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
static int __devinit dwc3_pci_init(void)
{
return pci_register_driver(&dwc3_pci_driver);
}
module_init(dwc3_pci_init);
static void __exit dwc3_pci_exit(void)
{
pci_unregister_driver(&dwc3_pci_driver);
}
module_exit(dwc3_pci_exit);
This diff is collapsed.
This diff is collapsed.
/**
* gadget.h - DesignWare USB3 DRD Gadget Header
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DRIVERS_USB_DWC3_GADGET_H
#define __DRIVERS_USB_DWC3_GADGET_H
#include <linux/list.h>
#include <linux/usb/gadget.h>
#include "io.h"
struct dwc3;
#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
/* DEPCFG parameter 1 */
#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
/* DEPCFG parameter 0 */
#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
/* DEPXFERCFG parameter 0 */
#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
struct dwc3_gadget_ep_cmd_params {
u32 param2;
u32 param1;
u32 param0;
};
/* -------------------------------------------------------------------------- */
struct dwc3_request {
struct usb_request request;
struct list_head list;
struct dwc3_ep *dep;
u8 epnum;
struct dwc3_trb_hw *trb;
dma_addr_t trb_dma;
unsigned direction:1;
unsigned mapped:1;
unsigned queued:1;
};
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
static inline struct dwc3_request *next_request(struct list_head *list)
{
if (list_empty(list))
return NULL;
return list_first_entry(list, struct dwc3_request, list);
}
static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
{
struct dwc3_ep *dep = req->dep;
req->queued = true;
list_move_tail(&req->list, &dep->req_queued);
}
#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
return 0;
}
#endif
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
void dwc3_map_buffer_to_dma(struct dwc3_request *req);
void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
* @dwc: DesignWare USB3 Pointer
* @number: DWC endpoint number
*
* Caller should take care of locking
*/
static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
{
u32 res_id;
res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
return DWC3_DEPCMD_GET_RSC_IDX(res_id);
}
/**
* dwc3_gadget_event_string - returns event name
* @event: the event code
*/
static inline const char *dwc3_gadget_event_string(u8 event)
{
switch (event) {
case DWC3_DEVICE_EVENT_DISCONNECT:
return "Disconnect";
case DWC3_DEVICE_EVENT_RESET:
return "Reset";
case DWC3_DEVICE_EVENT_CONNECT_DONE:
return "Connection Done";
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
return "Link Status Change";
case DWC3_DEVICE_EVENT_WAKEUP:
return "WakeUp";
case DWC3_DEVICE_EVENT_EOPF:
return "End-Of-Frame";
case DWC3_DEVICE_EVENT_SOF:
return "Start-Of-Frame";
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
return "Erratic Error";
case DWC3_DEVICE_EVENT_CMD_CMPL:
return "Command Complete";
case DWC3_DEVICE_EVENT_OVERFLOW:
return "Overflow";
}
return "UNKNOWN";
}
/**
* dwc3_ep_event_string - returns event name
* @event: then event code
*/
static inline const char *dwc3_ep_event_string(u8 event)
{
switch (event) {
case DWC3_DEPEVT_XFERCOMPLETE:
return "Transfer Complete";
case DWC3_DEPEVT_XFERINPROGRESS:
return "Transfer In-Progress";
case DWC3_DEPEVT_XFERNOTREADY:
return "Transfer Not Ready";
case DWC3_DEPEVT_RXTXFIFOEVT:
return "FIFO";
case DWC3_DEPEVT_STREAMEVT:
return "Stream";
case DWC3_DEPEVT_EPCMDCMPLT:
return "Endpoint Command Complete";
}
return "UNKNOWN";
}
#endif /* __DRIVERS_USB_DWC3_GADGET_H */
/**
* io.h - DesignWare USB3 DRD IO Header
*
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Felipe Balbi <balbi@ti.com>,
* Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2, as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DRIVERS_USB_DWC3_IO_H
#define __DRIVERS_USB_DWC3_IO_H
#include <asm/io.h>
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
return readl(base + offset);
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
writel(value, base + offset);
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
...@@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW ...@@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW
This value will be used except for system-specific gadget This value will be used except for system-specific gadget
drivers that have more specific information. drivers that have more specific information.
config USB_GADGET_STORAGE_NUM_BUFFERS
int "Number of storage pipeline buffers"
range 2 4
default 2
help
Usually 2 buffers are enough to establish a good buffering
pipeline. The number may be increased in order to compensate
for a bursty VFS behaviour. For instance there may be CPU wake up
latencies that makes the VFS to appear bursty in a system with
an CPU on-demand governor. Especially if DMA is doing IO to
offload the CPU. In this case the CPU will go into power
save often and spin up occasionally to move data within VFS.
If selecting USB_GADGET_DEBUG_FILES this value may be set by
a module parameter as well.
If unsure, say 2.
# #
# USB Peripheral Controller Support # USB Peripheral Controller Support
# #
...@@ -255,12 +271,11 @@ config USB_S3C_HSOTG ...@@ -255,12 +271,11 @@ config USB_S3C_HSOTG
integrated into the S3C64XX series SoC. integrated into the S3C64XX series SoC.
config USB_IMX config USB_IMX
tristate "Freescale IMX USB Peripheral Controller" tristate "Freescale i.MX1 USB Peripheral Controller"
depends on ARCH_MX1 depends on ARCH_MXC
help help
Freescale's IMX series include an integrated full speed Freescale's i.MX1 includes an integrated full speed
USB 1.1 device controller. The controller in the IMX series USB 1.1 device controller.
is register-compatible.
It has Six fixed-function endpoints, as well as endpoint It has Six fixed-function endpoints, as well as endpoint
zero (for control transfers). zero (for control transfers).
...@@ -303,6 +318,18 @@ config USB_PXA_U2O ...@@ -303,6 +318,18 @@ config USB_PXA_U2O
PXA9xx Processor series include a high speed USB2.0 device PXA9xx Processor series include a high speed USB2.0 device
controller, which support high speed and full speed USB peripheral. controller, which support high speed and full speed USB peripheral.
config USB_GADGET_DWC3
tristate "DesignWare USB3.0 (DRD) Controller"
depends on USB_DWC3
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
help
DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
which can be configured for peripheral-only, host-only, hub-only
and Dual-Role operation. This Controller was first integrated into
the OMAP5 series of processors. More information about the OMAP5
version of this controller, refer to http://www.ti.com/omap5.
# #
# Controllers available in both integrated and discrete versions # Controllers available in both integrated and discrete versions
# #
...@@ -846,6 +873,16 @@ config USB_G_NOKIA ...@@ -846,6 +873,16 @@ config USB_G_NOKIA
It's only really useful for N900 hardware. If you're building It's only really useful for N900 hardware. If you're building
a kernel for N900, say Y or M here. If unsure, say N. a kernel for N900, say Y or M here. If unsure, say N.
config USB_G_ACM_MS
tristate "CDC Composite Device (ACM and mass storage)"
depends on BLOCK
help
This driver provides two functions in one configuration:
a mass storage, and a CDC ACM (serial port) link.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_acm_ms".
config USB_G_MULTI config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)" tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET depends on BLOCK && NET
......
...@@ -28,7 +28,7 @@ obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o ...@@ -28,7 +28,7 @@ obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o obj-$(CONFIG_USB_PXA_U2O) += mv_udc.o
mv_udc-y := mv_udc_core.o mv_udc_phy.o mv_udc-y := mv_udc_core.o
obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
...@@ -51,6 +51,7 @@ g_dbgp-y := dbgp.o ...@@ -51,6 +51,7 @@ g_dbgp-y := dbgp.o
g_nokia-y := nokia.o g_nokia-y := nokia.o
g_webcam-y := webcam.o g_webcam-y := webcam.o
g_ncm-y := ncm.o g_ncm-y := ncm.o
g_acm_ms-y := acm_ms.o
obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o obj-$(CONFIG_USB_AUDIO) += g_audio.o
...@@ -69,3 +70,4 @@ obj-$(CONFIG_USB_G_MULTI) += g_multi.o ...@@ -69,3 +70,4 @@ obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o
obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
This diff is collapsed.
...@@ -8,15 +8,6 @@ ...@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/* /*
...@@ -354,7 +345,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) ...@@ -354,7 +345,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
writel(tmp, &dev->ep[ep->num].regs->ctl); writel(tmp, &dev->ep[ep->num].regs->ctl);
/* set max packet size */ /* set max packet size */
maxpacket = le16_to_cpu(desc->wMaxPacketSize); maxpacket = usb_endpoint_maxp(desc);
tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE); tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
ep->ep.maxpacket = maxpacket; ep->ep.maxpacket = maxpacket;
...@@ -3014,13 +3005,8 @@ __acquires(dev->lock) ...@@ -3014,13 +3005,8 @@ __acquires(dev->lock)
/* link up all endpoints */ /* link up all endpoints */
udc_setup_endpoints(dev); udc_setup_endpoints(dev);
if (dev->gadget.speed == USB_SPEED_HIGH) { dev_info(&dev->pdev->dev, "Connect: %s\n",
dev_info(&dev->pdev->dev, "Connect: speed = %s\n", usb_speed_string(dev->gadget.speed));
"high");
} else if (dev->gadget.speed == USB_SPEED_FULL) {
dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
"full");
}
/* init ep 0 */ /* init ep 0 */
activate_control_endpoints(dev); activate_control_endpoints(dev);
......
...@@ -8,15 +8,6 @@ ...@@ -8,15 +8,6 @@
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef AMD5536UDC_H #ifndef AMD5536UDC_H
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep, ...@@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep,
mEp->num = usb_endpoint_num(desc); mEp->num = usb_endpoint_num(desc);
mEp->type = usb_endpoint_type(desc); mEp->type = usb_endpoint_type(desc);
mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize); mEp->ep.maxpacket = usb_endpoint_maxp(desc);
dbg_event(_usb_addr(mEp), "ENABLE", 0); dbg_event(_usb_addr(mEp), "ENABLE", 0);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment