Commit 1c41a957 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'usb-for-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

usb: patches for v4.1 merge window

As usual, a big pile of commits. This time a total
of 111 non-merge commits.

Other than the usual set of cleanups and non-critical
fixes, we have some interesting work for AM335x's MUSB
babble recovery. Now that takes a lot less time and we
don't have to Reset MUSB all the time.

The printer gadget has been converted to configfs interface
and the atmel udc has learned suspend/resume with wakeup.
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parents cd0e0757 3e457371
What: /config/usb-gadget/gadget/functions/printer.name
Date: Apr 2015
KernelVersion: 4.1
Description:
The attributes:
pnp_string - Data to be passed to the host in pnp string
q_len - Number of requests per endpoint
......@@ -14,6 +14,7 @@ Optional properties:
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
- snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds.
- snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled
......
......@@ -15,7 +15,10 @@ Optional properties:
- phys: phandle + phy specifier pair
- phy-names: must be "usb"
- dmas: Must contain a list of references to DMA specifiers.
- dma-names : Must contain a list of DMA names, "tx" or "rx".
- dma-names : Must contain a list of DMA names:
- tx0 ... tx<n>
- rx0 ... rx<n>
- This <n> means DnFIFO in USBHS module.
Example:
usbhs: usb@e6590000 {
......
......@@ -19,6 +19,7 @@ provided by gadgets.
16. UAC1 function
17. UAC2 function
18. UVC function
19. PRINTER function
1. ACM function
......@@ -726,3 +727,49 @@ with these patches:
http://www.spinics.net/lists/linux-usb/msg99220.html
host: luvcview -f yuv
19. PRINTER function
====================
The function is provided by usb_f_printer.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "printer".
The printer function provides these attributes in its function directory:
pnp_string - Data to be passed to the host in pnp string
q_len - Number of requests per endpoint
Testing the PRINTER function
----------------------------
The most basic testing:
device: run the gadget
# ls -l /devices/virtual/usb_printer_gadget/
should show g_printer<number>.
If udev is active, then /dev/g_printer<number> should appear automatically.
host:
If udev is active, then e.g. /dev/usb/lp0 should appear.
host->device transmission:
device:
# cat /dev/g_printer<number>
host:
# cat > /dev/usb/lp0
device->host transmission:
# cat > /dev/g_printer<number>
host:
# cat /dev/usb/lp0
More advanced testing can be done with the prn_example
described in Documentation/usb/gadget-printer.txt.
......@@ -86,10 +86,8 @@ static int hw_device_state(struct ci_hdrc *ci, u32 dma)
/* interrupt, error, port change, reset, sleep/suspend */
hw_write(ci, OP_USBINTR, ~0,
USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
} else {
hw_write(ci, OP_USBINTR, ~0, 0);
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
}
return 0;
}
......@@ -1508,7 +1506,9 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
hw_device_reset(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
usb_udc_vbus_handler(_gadget, true);
} else {
usb_udc_vbus_handler(_gadget, false);
if (ci->driver)
ci->driver->disconnect(&ci->gadget);
hw_device_state(ci, 0);
......@@ -1574,13 +1574,12 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
if (!ci->vbus_active)
return -EOPNOTSUPP;
pm_runtime_get_sync(&ci->gadget.dev);
if (is_on)
hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
else
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
pm_runtime_put_sync(&ci->gadget.dev);
return 0;
}
......@@ -1710,6 +1709,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
spin_lock_irqsave(&ci->lock, flags);
hw_device_reset(ci);
} else {
usb_udc_vbus_handler(&ci->gadget, false);
pm_runtime_put_sync(&ci->gadget.dev);
return retval;
}
......
......@@ -59,11 +59,13 @@ config USB_DWC2_PLATFORM
config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on USB_DWC2_HOST && PCI
default USB_DWC2_HOST
depends on PCI
default n
select USB_DWC2_PLATFORM
select NOP_USB_XCEIV
help
The Designware USB2.0 PCI interface module for controllers
connected to a PCI bus. This is only used for host mode.
connected to a PCI bus.
config USB_DWC2_DEBUG
bool "Enable Debugging Messages"
......
......@@ -19,10 +19,8 @@ endif
# mode. The PCI bus interface module will called dwc2_pci.ko and the platform
# interface module will be called dwc2_platform.ko.
ifneq ($(CONFIG_USB_DWC2_PCI),)
obj-$(CONFIG_USB_DWC2) += dwc2_pci.o
dwc2_pci-y := pci.o
endif
obj-$(CONFIG_USB_DWC2_PCI) += dwc2_pci.o
dwc2_pci-y := pci.o
obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o
dwc2_platform-y := platform.o
......@@ -593,6 +593,8 @@ struct dwc2_hsotg {
struct dwc2_core_params *core_params;
enum usb_otg_state op_state;
enum usb_dr_mode dr_mode;
unsigned int hcd_enabled:1;
unsigned int gadget_enabled:1;
struct phy *phy;
struct usb_phy *uphy;
......
......@@ -257,6 +257,14 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
*/
channel->qh = NULL;
}
/* All channels have been freed, mark them available */
if (hsotg->core_params->uframe_sched > 0) {
hsotg->available_host_channels =
hsotg->core_params->host_channels;
} else {
hsotg->non_periodic_channels = 0;
hsotg->periodic_channels = 0;
}
}
/**
......
......@@ -50,113 +50,97 @@
#include <linux/usb/hcd.h>
#include <linux/usb/ch11.h>
#include <linux/platform_device.h>
#include <linux/usb/usb_phy_generic.h>
#include "core.h"
#include "hcd.h"
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
#define PCI_PRODUCT_ID_HAPS_HSOTG 0xabc0
static const char dwc2_driver_name[] = "dwc2";
static const struct dwc2_core_params dwc2_module_params = {
.otg_cap = -1,
.otg_ver = -1,
.dma_enable = -1,
.dma_desc_enable = 0,
.speed = -1,
.enable_dynamic_fifo = -1,
.en_multiple_tx_fifo = -1,
.host_rx_fifo_size = 1024,
.host_nperio_tx_fifo_size = 256,
.host_perio_tx_fifo_size = 1024,
.max_transfer_size = 65535,
.max_packet_count = 511,
.host_channels = -1,
.phy_type = -1,
.phy_utmi_width = -1,
.phy_ulpi_ddr = -1,
.phy_ulpi_ext_vbus = -1,
.i2c_enable = -1,
.ulpi_fs_ls = -1,
.host_support_fs_ls_low_power = -1,
.host_ls_low_power_phy_clk = -1,
.ts_dline = -1,
.reload_ctl = -1,
.ahbcfg = -1,
.uframe_sched = -1,
static const char dwc2_driver_name[] = "dwc2-pci";
struct dwc2_pci_glue {
struct platform_device *dwc2;
struct platform_device *phy;
};
/**
* dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
* DWC_otg driver
*
* @dev: Bus device
*
* This routine is called, for example, when the rmmod command is executed. The
* device may or may not be electrically present. If it is present, the driver
* stops device processing. Any resources used on behalf of this device are
* freed.
*/
static void dwc2_driver_remove(struct pci_dev *dev)
static void dwc2_pci_remove(struct pci_dev *pci)
{
struct dwc2_hsotg *hsotg = pci_get_drvdata(dev);
struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
dwc2_hcd_remove(hsotg);
pci_disable_device(dev);
platform_device_unregister(glue->dwc2);
usb_phy_generic_unregister(glue->phy);
kfree(glue);
pci_set_drvdata(pci, NULL);
}
/**
* dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
* driver
*
* @dev: Bus device
*
* This routine creates the driver components required to control the device
* (core, HCD, and PCD) and initializes the device. The driver components are
* stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved
* in the device private data. This allows the driver to access the dwc2_hsotg
* structure on subsequent calls to driver methods for this device.
*/
static int dwc2_driver_probe(struct pci_dev *dev,
static int dwc2_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
struct dwc2_hsotg *hsotg;
int retval;
struct resource res[2];
struct platform_device *dwc2;
struct platform_device *phy;
int ret;
struct device *dev = &pci->dev;
struct dwc2_pci_glue *glue;
ret = pcim_enable_device(pci);
if (ret) {
dev_err(dev, "failed to enable pci device\n");
return -ENODEV;
}
pci_set_master(pci);
hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
if (!hsotg)
dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
if (!dwc2) {
dev_err(dev, "couldn't allocate dwc2 device\n");
return -ENOMEM;
}
hsotg->dev = &dev->dev;
hsotg->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]);
if (IS_ERR(hsotg->regs))
return PTR_ERR(hsotg->regs);
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
(unsigned long)pci_resource_start(dev, 0), hsotg->regs);
res[0].start = pci_resource_start(pci, 0);
res[0].end = pci_resource_end(pci, 0);
res[0].name = "dwc2";
res[0].flags = IORESOURCE_MEM;
if (pci_enable_device(dev) < 0)
return -ENODEV;
res[1].start = pci->irq;
res[1].name = "dwc2";
res[1].flags = IORESOURCE_IRQ;
pci_set_master(dev);
ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc2 device\n");
return ret;
}
retval = devm_request_irq(hsotg->dev, dev->irq,
dwc2_handle_common_intr, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (retval)
return retval;
dwc2->dev.parent = dev;
spin_lock_init(&hsotg->lock);
retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
if (retval) {
pci_disable_device(dev);
return retval;
phy = usb_phy_generic_register();
if (IS_ERR(phy)) {
dev_err(dev, "error registering generic PHY (%ld)\n",
PTR_ERR(phy));
return PTR_ERR(phy);
}
pci_set_drvdata(dev, hsotg);
ret = platform_device_add(dwc2);
if (ret) {
dev_err(dev, "failed to register dwc2 device\n");
goto err;
}
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
glue->phy = phy;
glue->dwc2 = dwc2;
pci_set_drvdata(pci, glue);
return retval;
return 0;
err:
usb_phy_generic_unregister(phy);
platform_device_put(dwc2);
return ret;
}
static const struct pci_device_id dwc2_pci_ids[] = {
......@@ -174,8 +158,8 @@ MODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
static struct pci_driver dwc2_pci_driver = {
.name = dwc2_driver_name,
.id_table = dwc2_pci_ids,
.probe = dwc2_driver_probe,
.remove = dwc2_driver_remove,
.probe = dwc2_pci_probe,
.remove = dwc2_pci_remove,
};
module_pci_driver(dwc2_pci_driver);
......
......@@ -121,7 +121,9 @@ static int dwc2_driver_remove(struct platform_device *dev)
{
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
if (hsotg->hcd_enabled)
dwc2_hcd_remove(hsotg);
if (hsotg->gadget_enabled)
s3c_hsotg_remove(hsotg);
return 0;
......@@ -234,12 +236,23 @@ static int dwc2_driver_probe(struct platform_device *dev)
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg, irq);
if (retval)
return retval;
hsotg->gadget_enabled = 1;
}
if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) {
retval = dwc2_hcd_init(hsotg, irq, params);
if (retval)
if (retval) {
if (hsotg->gadget_enabled)
s3c_hsotg_remove(hsotg);
return retval;
}
hsotg->hcd_enabled = 1;
}
platform_set_drvdata(dev, hsotg);
......
......@@ -104,11 +104,4 @@ config USB_DWC3_DEBUG
help
Say Y here to enable debugging messages on DWC3 Driver.
config DWC3_HOST_USB3_LPM_ENABLE
bool "Enable USB3 LPM Capability"
depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
default n
help
Select this when you want to enable USB3 LPM with dwc3 xhci host.
endif
......@@ -774,17 +774,13 @@ static int dwc3_probe(struct platform_device *pdev)
* since it will be requested by the xhci-plat driver.
*/
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
if (IS_ERR(regs)) {
ret = PTR_ERR(regs);
goto err0;
}
dwc->regs = regs;
dwc->regs_size = resource_size(res);
/*
* restore res->start back to its original value so that,
* in case the probe is deferred, we don't end up getting error in
* request the memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
/* default to highest possible threshold */
lpm_nyet_threshold = 0xff;
......@@ -808,6 +804,8 @@ static int dwc3_probe(struct platform_device *pdev)
"snps,is-utmi-l1-suspend");
of_property_read_u8(node, "snps,hird-threshold",
&hird_threshold);
dwc->usb3_lpm_capable = of_property_read_bool(node,
"snps,usb3_lpm_capable");
dwc->needs_fifo_resize = of_property_read_bool(node,
"tx-fifo-resize");
......@@ -848,6 +846,7 @@ static int dwc3_probe(struct platform_device *pdev)
hird_threshold = pdata->hird_threshold;
dwc->needs_fifo_resize = pdata->tx_fifo_resize;
dwc->usb3_lpm_capable = pdata->usb3_lpm_capable;
dwc->dr_mode = pdata->dr_mode;
dwc->disable_scramble_quirk = pdata->disable_scramble_quirk;
......@@ -878,7 +877,7 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_core_get_phy(dwc);
if (ret)
return ret;
goto err0;
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
......@@ -899,7 +898,7 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
ret = -ENOMEM;
goto err0;
goto err1;
}
if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
......@@ -913,65 +912,81 @@ static int dwc3_probe(struct platform_device *pdev)
ret = dwc3_core_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize core\n");
goto err0;
goto err1;
}
usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy);
if (ret < 0)
goto err1;
goto err2;
ret = phy_power_on(dwc->usb3_generic_phy);
if (ret < 0)
goto err_usb2phy_power;
goto err3;
ret = dwc3_event_buffers_setup(dwc);
if (ret) {
dev_err(dwc->dev, "failed to setup event buffers\n");
goto err_usb3phy_power;
goto err4;
}
ret = dwc3_core_init_mode(dwc);
if (ret)
goto err2;
goto err5;
ret = dwc3_debugfs_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize debugfs\n");
goto err3;
goto err6;
}
pm_runtime_allow(dev);
return 0;
err3:
err6:
dwc3_core_exit_mode(dwc);
err2:
err5:
dwc3_event_buffers_cleanup(dwc);
err_usb3phy_power:
err4:
phy_power_off(dwc->usb3_generic_phy);
err_usb2phy_power:
err3:
phy_power_off(dwc->usb2_generic_phy);
err1:
err2:
usb_phy_set_suspend(dwc->usb2_phy, 1);
usb_phy_set_suspend(dwc->usb3_phy, 1);
dwc3_core_exit(dwc);
err0:
err1:
dwc3_free_event_buffers(dwc);
err0:
/*
* restore res->start back to its original value so that, in case the
* probe is deferred, we don't end up getting error in request the
* memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
return ret;
}
static int dwc3_remove(struct platform_device *pdev)
{
struct dwc3 *dwc = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/*
* restore res->start back to its original value so that, in case the
* probe is deferred, we don't end up getting error in request the
* memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
dwc3_debugfs_exit(dwc);
dwc3_core_exit_mode(dwc);
......
......@@ -689,6 +689,7 @@ struct dwc3_scratchpad_array {
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @start_config_issued: true when StartConfig command has been issued
* @three_stage_setup: set if we perform a three phase setup
* @usb3_lpm_capable: set if hadrware supports Link Power Management
* @disable_scramble_quirk: set if we enable the disable scramble quirk
* @u2exit_lfps_quirk: set if we enable u2exit lfps quirk
* @u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
......@@ -812,6 +813,7 @@ struct dwc3 {
unsigned setup_packet_pending:1;
unsigned start_config_issued:1;
unsigned three_stage_setup:1;
unsigned usb3_lpm_capable:1;
unsigned disable_scramble_quirk:1;
unsigned u2exit_lfps_quirk:1;
......
......@@ -325,15 +325,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
return IRQ_HANDLED;
}
static int dwc3_omap_remove_core(struct device *dev, void *c)
{
struct platform_device *pdev = to_platform_device(dev);
of_device_unregister(pdev);
return 0;
}
static void dwc3_omap_enable_irqs(struct dwc3_omap *omap)
{
u32 reg;
......@@ -600,7 +591,7 @@ static int dwc3_omap_remove(struct platform_device *pdev)
if (omap->extcon_id_dev.edev)
extcon_unregister_interest(&omap->extcon_id_dev);
dwc3_omap_disable_irqs(omap);
device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core);
of_platform_depopulate(omap->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......
......@@ -24,8 +24,6 @@
#include "platform_data.h"
/* FIXME define these in <linux/pci_ids.h> */
#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
......
......@@ -1855,7 +1855,6 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int i;
int ret;
do {
req = next_request(&dep->req_queued);
if (!req) {
WARN_ON_ONCE(1);
......@@ -1874,14 +1873,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
event, status);
if (ret)
break;
}while (++i < req->request.num_mapped_sgs);
} while (++i < req->request.num_mapped_sgs);
dwc3_gadget_giveback(dep, req, status);
if (ret)
break;
} while (1);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
if (list_empty(&dep->request_list)) {
......
......@@ -49,9 +49,7 @@ int dwc3_host_init(struct dwc3 *dwc)
memset(&pdata, 0, sizeof(pdata));
#ifdef CONFIG_DWC3_HOST_USB3_LPM_ENABLE
pdata.usb3_lpm_capable = 1;
#endif
pdata.usb3_lpm_capable = dwc->usb3_lpm_capable;
ret = platform_device_add_data(xhci, &pdata, sizeof(pdata));
if (ret) {
......
......@@ -24,6 +24,7 @@ struct dwc3_platform_data {
enum usb_device_speed maximum_speed;
enum usb_dr_mode dr_mode;
bool tx_fifo_resize;
bool usb3_lpm_capable;
unsigned is_utmi_l1_suspend:1;
u8 hird_threshold;
......
......@@ -196,6 +196,9 @@ config USB_F_MIDI
config USB_F_HID
tristate
config USB_F_PRINTER
tristate
choice
tristate "USB Gadget Drivers"
default USB_ETH
......@@ -434,6 +437,20 @@ config USB_CONFIGFS_F_UVC
device. It provides a userspace API to process UVC control requests
and stream video data to the host.
config USB_CONFIGFS_F_PRINTER
bool "Printer function"
select USB_F_PRINTER
depends on USB_CONFIGFS
help
The Printer function channels data between the USB host and a
userspace program driving the print engine. The user space
program reads and writes the device file /dev/g_printer<X> to
receive or send printer data. It can use ioctl calls to
the device file to get or set printer status.
For more information, see Documentation/usb/gadget_printer.txt
which includes sample code for accessing the device file.
source "drivers/usb/gadget/legacy/Kconfig"
endchoice
......
......@@ -1161,11 +1161,11 @@ static struct usb_gadget_string_container *copy_gadget_strings(
* This function will create a deep copy of usb_gadget_strings and usb_string
* and attach it to the cdev. The actual string (usb_string.s) will not be
* copied but only a referenced will be made. The struct usb_gadget_strings
* array may contain multiple languges and should be NULL terminated.
* array may contain multiple languages and should be NULL terminated.
* The ->language pointer of each struct usb_gadget_strings has to contain the
* same amount of entries.
* For instance: sp[0] is en-US, sp[1] is es-ES. It is expected that the first
* usb_string entry of es-ES containts the translation of the first usb_string
* usb_string entry of es-ES contains the translation of the first usb_string
* entry of en-US. Therefore both entries become the same id assign.
*/
struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,
......@@ -1472,6 +1472,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
req->length = 0;
gadget->ep0->driver_data = cdev;
/*
* Don't let non-standard requests match any of the cases below
* by accident.
*/
if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
goto unknown;
switch (ctrl->bRequest) {
/* we handle all standard USB descriptors */
......@@ -1751,6 +1758,10 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* take such requests too, if that's ever needed: to work
* in config 0, etc.
*/
list_for_each_entry(f, &cdev->config->functions, list)
if (f->req_match && f->req_match(f, ctrl))
goto try_fun_setup;
f = NULL;
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_INTERFACE:
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
......@@ -1768,7 +1779,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
f = NULL;
break;
}
try_fun_setup:
if (f && f->setup)
value = f->setup(f, ctrl);
else {
......
......@@ -42,3 +42,5 @@ usb_f_midi-y := f_midi.o
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
usb_f_hid-y := f_hid.o
obj-$(CONFIG_USB_F_HID) += usb_f_hid.o
usb_f_printer-y := f_printer.o
obj-$(CONFIG_USB_F_PRINTER) += usb_f_printer.o
......@@ -908,7 +908,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
/* disable/free request and end point */
usb_ep_disable(hidg->in_ep);
usb_ep_dequeue(hidg->in_ep, hidg->req);
kfree(hidg->req->buf);
usb_ep_free_request(hidg->in_ep, hidg->req);
......
......@@ -1085,7 +1085,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
if (!curlun) { /* Unsupported LUNs are okay */
common->bad_lun_okay = 1;
memset(buf, 0, 36);
buf[0] = 0x7f; /* Unsupported, no device-type */
buf[0] = TYPE_NO_LUN; /* Unsupported, no device-type */
buf[4] = 31; /* Additional length */
return 36;
}
......
This diff is collapsed.
/*
* u_printer.h
*
* Utility definitions for the printer function
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef U_PRINTER_H
#define U_PRINTER_H
#include <linux/usb/composite.h>
#define PNP_STRING_LEN 1024
struct f_printer_opts {
struct usb_function_instance func_inst;
int minor;
char pnp_string[PNP_STRING_LEN];
unsigned q_len;
/*
* Protect the data from concurrent access by read/write
* and create symlink/remove symlink
*/
struct mutex lock;
int refcnt;
};
#endif /* U_PRINTER_H */
......@@ -912,7 +912,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch)
unsigned long flags;
int status;
pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %ps\n",
port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
......
......@@ -301,6 +301,7 @@ config USB_MIDI_GADGET
config USB_G_PRINTER
tristate "Printer Gadget"
select USB_LIBCOMPOSITE
select USB_F_PRINTER
help
The Printer Gadget channels data between the USB host and a
userspace program driving the print engine. The user space
......
This diff is collapsed.
......@@ -152,7 +152,7 @@ static int regs_dbg_open(struct inode *inode, struct file *file)
spin_lock_irq(&udc->lock);
for (i = 0; i < inode->i_size / 4; i++)
data[i] = __raw_readl(udc->regs + i * 4);
data[i] = usba_io_readl(udc->regs + i * 4);
spin_unlock_irq(&udc->lock);
file->private_data = data;
......@@ -1249,7 +1249,7 @@ static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
if (crq->wLength != cpu_to_le16(sizeof(status)))
goto stall;
ep->state = DATA_STAGE_IN;
__raw_writew(status, ep->fifo);
usba_io_writew(status, ep->fifo);
usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
break;
}
......@@ -1739,43 +1739,95 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
return IRQ_HANDLED;
}
static irqreturn_t usba_vbus_irq(int irq, void *devid)
static int start_clock(struct usba_udc *udc)
{
struct usba_udc *udc = devid;
int vbus;
int ret;
/* debounce */
udelay(10);
if (udc->clocked)
return 0;
spin_lock(&udc->lock);
ret = clk_prepare_enable(udc->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(udc->hclk);
if (ret) {
clk_disable_unprepare(udc->pclk);
return ret;
}
/* May happen if Vbus pin toggles during probe() */
if (!udc->driver)
goto out;
udc->clocked = true;
return 0;
}
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
static void stop_clock(struct usba_udc *udc)
{
if (!udc->clocked)
return;
clk_disable_unprepare(udc->hclk);
clk_disable_unprepare(udc->pclk);
udc->clocked = false;
}
static int usba_start(struct usba_udc *udc)
{
unsigned long flags;
int ret;
ret = start_clock(udc);
if (ret)
return ret;
spin_lock_irqsave(&udc->lock, flags);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_int_enb_set(udc, USBA_END_OF_RESET);
} else {
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
static void usba_stop(struct usba_udc *udc)
{
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
/* This will also disable the DP pullup */
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
if (udc->driver->disconnect) {
spin_unlock(&udc->lock);
spin_unlock_irqrestore(&udc->lock, flags);
stop_clock(udc);
}
static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
{
struct usba_udc *udc = devid;
int vbus;
/* debounce */
udelay(10);
mutex_lock(&udc->vbus_mutex);
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
usba_start(udc);
} else {
usba_stop(udc);
if (udc->driver->disconnect)
udc->driver->disconnect(&udc->gadget);
spin_lock(&udc->lock);
}
}
udc->vbus_prev = vbus;
}
out:
spin_unlock(&udc->lock);
mutex_unlock(&udc->vbus_mutex);
return IRQ_HANDLED;
}
......@@ -1787,55 +1839,47 @@ static int atmel_usba_start(struct usb_gadget *gadget,
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver;
spin_unlock_irqrestore(&udc->lock, flags);
ret = clk_prepare_enable(udc->pclk);
if (ret)
return ret;
ret = clk_prepare_enable(udc->hclk);
if (ret) {
clk_disable_unprepare(udc->pclk);
return ret;
}
mutex_lock(&udc->vbus_mutex);
udc->vbus_prev = 0;
if (gpio_is_valid(udc->vbus_pin))
enable_irq(gpio_to_irq(udc->vbus_pin));
/* If Vbus is present, enable the controller and wait for reset */
spin_lock_irqsave(&udc->lock, flags);
if (vbus_is_present(udc) && udc->vbus_prev == 0) {
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_int_enb_set(udc, USBA_END_OF_RESET);
udc->vbus_prev = vbus_is_present(udc);
if (udc->vbus_prev) {
ret = usba_start(udc);
if (ret)
goto err;
}
spin_unlock_irqrestore(&udc->lock, flags);
mutex_unlock(&udc->vbus_mutex);
return 0;
err:
if (gpio_is_valid(udc->vbus_pin))
disable_irq(gpio_to_irq(udc->vbus_pin));
mutex_unlock(&udc->vbus_mutex);
spin_lock_irqsave(&udc->lock, flags);
udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
udc->driver = NULL;
spin_unlock_irqrestore(&udc->lock, flags);
return ret;
}
static int atmel_usba_stop(struct usb_gadget *gadget)
{
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
if (gpio_is_valid(udc->vbus_pin))
disable_irq(gpio_to_irq(udc->vbus_pin));
spin_lock_irqsave(&udc->lock, flags);
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
spin_unlock_irqrestore(&udc->lock, flags);
/* This will also disable the DP pullup */
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(udc->hclk);
clk_disable_unprepare(udc->pclk);
usba_stop(udc);
udc->driver = NULL;
......@@ -2057,6 +2101,7 @@ static int usba_udc_probe(struct platform_device *pdev)
return PTR_ERR(hclk);
spin_lock_init(&udc->lock);
mutex_init(&udc->vbus_mutex);
udc->pdev = pdev;
udc->pclk = pclk;
udc->hclk = hclk;
......@@ -2111,17 +2156,17 @@ static int usba_udc_probe(struct platform_device *pdev)
if (gpio_is_valid(udc->vbus_pin)) {
if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) {
ret = devm_request_irq(&pdev->dev,
gpio_to_irq(udc->vbus_pin),
usba_vbus_irq, 0,
irq_set_status_flags(gpio_to_irq(udc->vbus_pin),
IRQ_NOAUTOEN);
ret = devm_request_threaded_irq(&pdev->dev,
gpio_to_irq(udc->vbus_pin), NULL,
usba_vbus_irq_thread, IRQF_ONESHOT,
"atmel_usba_udc", udc);
if (ret) {
udc->vbus_pin = -ENODEV;
dev_warn(&udc->pdev->dev,
"failed to request vbus irq; "
"assuming always on\n");
} else {
disable_irq(gpio_to_irq(udc->vbus_pin));
}
} else {
/* gpio_request fail so use -EINVAL for gpio_is_valid */
......@@ -2132,6 +2177,7 @@ static int usba_udc_probe(struct platform_device *pdev)
ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (ret)
return ret;
device_init_wakeup(&pdev->dev, 1);
usba_init_debugfs(udc);
for (i = 1; i < udc->num_ep; i++)
......@@ -2147,6 +2193,7 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
udc = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
usb_del_gadget_udc(&udc->gadget);
for (i = 1; i < udc->num_ep; i++)
......@@ -2156,10 +2203,65 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int usba_udc_suspend(struct device *dev)
{
struct usba_udc *udc = dev_get_drvdata(dev);
/* Not started */
if (!udc->driver)
return 0;
mutex_lock(&udc->vbus_mutex);
if (!device_may_wakeup(dev)) {
usba_stop(udc);
goto out;
}
/*
* Device may wake up. We stay clocked if we failed
* to request vbus irq, assuming always on.
*/
if (gpio_is_valid(udc->vbus_pin)) {
usba_stop(udc);
enable_irq_wake(gpio_to_irq(udc->vbus_pin));
}
out:
mutex_unlock(&udc->vbus_mutex);
return 0;
}
static int usba_udc_resume(struct device *dev)
{
struct usba_udc *udc = dev_get_drvdata(dev);
/* Not started */
if (!udc->driver)
return 0;
if (device_may_wakeup(dev) && gpio_is_valid(udc->vbus_pin))
disable_irq_wake(gpio_to_irq(udc->vbus_pin));
/* If Vbus is present, enable the controller and wait for reset */
mutex_lock(&udc->vbus_mutex);
udc->vbus_prev = vbus_is_present(udc);
if (udc->vbus_prev)
usba_start(udc);
mutex_unlock(&udc->vbus_mutex);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume);
static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {
.name = "atmel_usba_udc",
.pm = &usba_udc_pm_ops,
.of_match_table = of_match_ptr(atmel_udc_dt_ids),
},
};
......
......@@ -191,18 +191,28 @@
| USBA_BF(name, value))
/* Register access macros */
#ifdef CONFIG_AVR32
#define usba_io_readl __raw_readl
#define usba_io_writel __raw_writel
#define usba_io_writew __raw_writew
#else
#define usba_io_readl readl_relaxed
#define usba_io_writel writel_relaxed
#define usba_io_writew writew_relaxed
#endif
#define usba_readl(udc, reg) \
__raw_readl((udc)->regs + USBA_##reg)
usba_io_readl((udc)->regs + USBA_##reg)
#define usba_writel(udc, reg, value) \
__raw_writel((value), (udc)->regs + USBA_##reg)
usba_io_writel((value), (udc)->regs + USBA_##reg)
#define usba_ep_readl(ep, reg) \
__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
usba_io_readl((ep)->ep_regs + USBA_EPT_##reg)
#define usba_ep_writel(ep, reg, value) \
__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
usba_io_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
#define usba_dma_readl(ep, reg) \
__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
usba_io_readl((ep)->dma_regs + USBA_DMA_##reg)
#define usba_dma_writel(ep, reg, value) \
__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
usba_io_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
/* Calculate base address for a given endpoint or DMA controller */
#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
......@@ -313,6 +323,9 @@ struct usba_udc {
/* Protect hw registers from concurrent modifications */
spinlock_t lock;
/* Mutex to prevent concurrent start or stop */
struct mutex vbus_mutex;
void __iomem *regs;
void __iomem *fifo;
......@@ -328,6 +341,7 @@ struct usba_udc {
struct clk *hclk;
struct usba_ep *usba_ep;
bool bias_pulse_needed;
bool clocked;
u16 devstatus;
......
......@@ -2631,7 +2631,7 @@ static int __init init(void)
return -EINVAL;
if (mod_data.num < 1 || mod_data.num > MAX_NUM_UDC) {
pr_err("Number of emulated UDC must be in range of 1%d\n",
pr_err("Number of emulated UDC must be in range of 1...%d\n",
MAX_NUM_UDC);
return -EINVAL;
}
......
......@@ -1024,8 +1024,7 @@ static const char proc_node_name [] = "driver/udc";
static void dump_intmask(struct seq_file *m, const char *label, u32 mask)
{
/* int_status is the same format ... */
seq_printf(m,
"%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",
seq_printf(m, "%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",
label, mask,
(mask & INT_PWRDETECT) ? " power" : "",
(mask & INT_SYSERROR) ? " sys" : "",
......@@ -1053,6 +1052,51 @@ static void dump_intmask(struct seq_file *m, const char *label, u32 mask)
(mask & INT_SUSPEND) ? " suspend" : "");
}
static const char *udc_ep_state(enum ep0state state)
{
switch (state) {
case EP0_DISCONNECT:
return "ep0_disconnect";
case EP0_IDLE:
return "ep0_idle";
case EP0_IN:
return "ep0_in";
case EP0_OUT:
return "ep0_out";
case EP0_STATUS:
return "ep0_status";
case EP0_STALL:
return "ep0_stall";
case EP0_SUSPEND:
return "ep0_suspend";
}
return "ep0_?";
}
static const char *udc_ep_status(u32 status)
{
switch (status & EPxSTATUS_EP_MASK) {
case EPxSTATUS_EP_READY:
return "ready";
case EPxSTATUS_EP_DATAIN:
return "packet";
case EPxSTATUS_EP_FULL:
return "full";
case EPxSTATUS_EP_TX_ERR: /* host will retry */
return "tx_err";
case EPxSTATUS_EP_RX_ERR:
return "rx_err";
case EPxSTATUS_EP_BUSY: /* ep0 only */
return "busy";
case EPxSTATUS_EP_STALL:
return "stall";
case EPxSTATUS_EP_INVALID: /* these "can't happen" */
return "invalid";
}
return "?";
}
static int udc_proc_read(struct seq_file *m, void *v)
{
......@@ -1079,18 +1123,7 @@ static int udc_proc_read(struct seq_file *m, void *v)
is_usb_connected
? ((tmp & PW_PULLUP) ? "full speed" : "powered")
: "disconnected",
({const char *state;
switch(dev->ep0state){
case EP0_DISCONNECT: state = "ep0_disconnect"; break;
case EP0_IDLE: state = "ep0_idle"; break;
case EP0_IN: state = "ep0_in"; break;
case EP0_OUT: state = "ep0_out"; break;
case EP0_STATUS: state = "ep0_status"; break;
case EP0_STALL: state = "ep0_stall"; break;
case EP0_SUSPEND: state = "ep0_suspend"; break;
default: state = "ep0_?"; break;
} state; })
);
udc_ep_state(dev->ep0state));
dump_intmask(m, "int_status", readl(&regs->int_status));
dump_intmask(m, "int_enable", readl(&regs->int_enable));
......@@ -1099,17 +1132,17 @@ static int udc_proc_read(struct seq_file *m, void *v)
goto done;
/* registers for (active) device and ep0 */
if (seq_printf(m, "\nirqs %lu\ndataset %02x "
"single.bcs %02x.%02x state %x addr %u\n",
seq_printf(m, "\nirqs %lu\ndataset %02x single.bcs %02x.%02x state %x addr %u\n",
dev->irqs, readl(&regs->DataSet),
readl(&regs->EPxSingle), readl(&regs->EPxBCS),
readl(&regs->UsbState),
readl(&regs->address)) < 0)
readl(&regs->address));
if (seq_has_overflowed(m))
goto done;
tmp = readl(&regs->dma_master);
if (seq_printf(m,
"dma %03X =" EIGHTBITS "%s %s\n", tmp,
seq_printf(m, "dma %03X =" EIGHTBITS "%s %s\n",
tmp,
(tmp & MST_EOPB_DIS) ? " eopb-" : "",
(tmp & MST_EOPB_ENA) ? " eopb+" : "",
(tmp & MST_TIMEOUT_DIS) ? " tmo-" : "",
......@@ -1121,9 +1154,8 @@ static int udc_proc_read(struct seq_file *m, void *v)
(tmp & MST_RD_ENA) ? " IN" : "",
(tmp & MST_WR_ENA) ? " OUT" : "",
(tmp & MST_CONNECTION)
? "ep1in/ep2out"
: "ep1out/ep2in") < 0)
(tmp & MST_CONNECTION) ? "ep1in/ep2out" : "ep1out/ep2in");
if (seq_has_overflowed(m))
goto done;
/* dump endpoint queues */
......@@ -1135,44 +1167,23 @@ static int udc_proc_read(struct seq_file *m, void *v)
continue;
tmp = readl(ep->reg_status);
if (seq_printf(m,
"%s %s max %u %s, irqs %lu, "
"status %02x (%s) " FOURBITS "\n",
seq_printf(m, "%s %s max %u %s, irqs %lu, status %02x (%s) " FOURBITS "\n",
ep->ep.name,
ep->is_in ? "in" : "out",
ep->ep.maxpacket,
ep->dma ? "dma" : "pio",
ep->irqs,
tmp, ({ char *s;
switch (tmp & EPxSTATUS_EP_MASK) {
case EPxSTATUS_EP_READY:
s = "ready"; break;
case EPxSTATUS_EP_DATAIN:
s = "packet"; break;
case EPxSTATUS_EP_FULL:
s = "full"; break;
case EPxSTATUS_EP_TX_ERR: // host will retry
s = "tx_err"; break;
case EPxSTATUS_EP_RX_ERR:
s = "rx_err"; break;
case EPxSTATUS_EP_BUSY: /* ep0 only */
s = "busy"; break;
case EPxSTATUS_EP_STALL:
s = "stall"; break;
case EPxSTATUS_EP_INVALID: // these "can't happen"
s = "invalid"; break;
default:
s = "?"; break;
} s; }),
tmp, udc_ep_status(tmp),
(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",
(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",
(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "",
(tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : ""
) < 0)
(tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : "");
if (seq_has_overflowed(m))
goto done;
if (list_empty(&ep->queue)) {
if (seq_puts(m, "\t(nothing queued)\n") < 0)
seq_puts(m, "\t(nothing queued)\n");
if (seq_has_overflowed(m))
goto done;
continue;
}
......@@ -1187,10 +1198,10 @@ static int udc_proc_read(struct seq_file *m, void *v)
} else
tmp = req->req.actual;
if (seq_printf(m,
"\treq %p len %u/%u buf %p\n",
seq_printf(m, "\treq %p len %u/%u buf %p\n",
&req->req, tmp, req->req.length,
req->req.buf) < 0)
req->req.buf);
if (seq_has_overflowed(m))
goto done;
}
}
......
......@@ -1803,23 +1803,14 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep,
req = container_of(_req, struct lpc32xx_request, req);
ep = container_of(_ep, struct lpc32xx_ep, ep);
if (!_req || !_req->complete || !_req->buf ||
if (!_ep || !_req || !_req->complete || !_req->buf ||
!list_empty(&req->queue))
return -EINVAL;
udc = ep->udc;
if (!_ep) {
dev_dbg(udc->dev, "invalid ep\n");
return -EINVAL;
}
if ((!udc) || (!udc->driver) ||
(udc->gadget.speed == USB_SPEED_UNKNOWN)) {
dev_dbg(udc->dev, "invalid device\n");
return -EINVAL;
}
if (udc->gadget.speed == USB_SPEED_UNKNOWN)
return -EPIPE;
if (ep->lep) {
struct lpc32xx_usbd_dd_gad *dd;
......
This diff is collapsed.
......@@ -96,7 +96,6 @@ struct net2280_ep {
struct net2280_ep_regs __iomem *regs;
struct net2280_dma_regs __iomem *dma;
struct net2280_dma *dummy;
struct usb338x_fifo_regs __iomem *fiforegs;
dma_addr_t td_dma; /* of dummy */
struct net2280 *dev;
unsigned long irqs;
......@@ -181,7 +180,6 @@ struct net2280 {
struct net2280_dma_regs __iomem *dma;
struct net2280_dep_regs __iomem *dep;
struct net2280_ep_regs __iomem *epregs;
struct usb338x_fifo_regs __iomem *fiforegs;
struct usb338x_ll_regs __iomem *llregs;
struct usb338x_ll_lfps_regs __iomem *ll_lfps_regs;
struct usb338x_ll_tsn_regs __iomem *ll_tsn_regs;
......
......@@ -93,23 +93,22 @@ static void handle_ep(struct pxa_ep *ep);
static int state_dbg_show(struct seq_file *s, void *p)
{
struct pxa_udc *udc = s->private;
int pos = 0, ret;
u32 tmp;
ret = -ENODEV;
if (!udc->driver)
goto out;
return -ENODEV;
/* basic device status */
pos += seq_printf(s, DRIVER_DESC "\n"
"%s version: %s\nGadget driver: %s\n",
seq_printf(s, DRIVER_DESC "\n"
"%s version: %s\n"
"Gadget driver: %s\n",
driver_name, DRIVER_VERSION,
udc->driver ? udc->driver->driver.name : "(none)");
tmp = udc_readl(udc, UDCCR);
pos += seq_printf(s,
"udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), "
"con=%d,inter=%d,altinter=%d\n", tmp,
seq_printf(s,
"udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), con=%d,inter=%d,altinter=%d\n",
tmp,
(tmp & UDCCR_OEN) ? " oen":"",
(tmp & UDCCR_AALTHNP) ? " aalthnp":"",
(tmp & UDCCR_AHNP) ? " rem" : "",
......@@ -124,19 +123,16 @@ static int state_dbg_show(struct seq_file *s, void *p)
(tmp & UDCCR_AIN) >> UDCCR_AIN_S,
(tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
/* registers for device and ep0 */
pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, "
"reconfig=%lu\n",
seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, reconfig=%lu\n",
udc->stats.irqs_reset, udc->stats.irqs_suspend,
udc->stats.irqs_resume, udc->stats.irqs_reconfig);
ret = 0;
out:
return ret;
return 0;
}
static int queues_dbg_show(struct seq_file *s, void *p)
......@@ -144,50 +140,47 @@ static int queues_dbg_show(struct seq_file *s, void *p)
struct pxa_udc *udc = s->private;
struct pxa_ep *ep;
struct pxa27x_request *req;
int pos = 0, i, maxpkt, ret;
int i, maxpkt;
ret = -ENODEV;
if (!udc->driver)
goto out;
return -ENODEV;
/* dump endpoint queues */
for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
ep = &udc->pxa_ep[i];
maxpkt = ep->fifo_size;
pos += seq_printf(s, "%-12s max_pkt=%d %s\n",
seq_printf(s, "%-12s max_pkt=%d %s\n",
EPNAME(ep), maxpkt, "pio");
if (list_empty(&ep->queue)) {
pos += seq_printf(s, "\t(nothing queued)\n");
seq_puts(s, "\t(nothing queued)\n");
continue;
}
list_for_each_entry(req, &ep->queue, queue) {
pos += seq_printf(s, "\treq %p len %d/%d buf %p\n",
seq_printf(s, "\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
}
}
ret = 0;
out:
return ret;
return 0;
}
static int eps_dbg_show(struct seq_file *s, void *p)
{
struct pxa_udc *udc = s->private;
struct pxa_ep *ep;
int pos = 0, i, ret;
int i;
u32 tmp;
ret = -ENODEV;
if (!udc->driver)
goto out;
return -ENODEV;
ep = &udc->pxa_ep[0];
tmp = udc_ep_readl(ep, UDCCSR);
pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp,
seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n",
tmp,
(tmp & UDCCSR0_SA) ? " sa" : "",
(tmp & UDCCSR0_RNE) ? " rne" : "",
(tmp & UDCCSR0_FST) ? " fst" : "",
......@@ -198,10 +191,7 @@ static int eps_dbg_show(struct seq_file *s, void *p)
for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
ep = &udc->pxa_ep[i];
tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
pos += seq_printf(s, "%-12s: "
"IN %lu(%lu reqs), OUT %lu(%lu reqs), "
"irqs=%lu, udccr=0x%08x, udccsr=0x%03x, "
"udcbcr=%d\n",
seq_printf(s, "%-12s: IN %lu(%lu reqs), OUT %lu(%lu reqs), irqs=%lu, udccr=0x%08x, udccsr=0x%03x, udcbcr=%d\n",
EPNAME(ep),
ep->stats.in_bytes, ep->stats.in_ops,
ep->stats.out_bytes, ep->stats.out_ops,
......@@ -210,9 +200,7 @@ static int eps_dbg_show(struct seq_file *s, void *p)
udc_ep_readl(ep, UDCBCR));
}
ret = 0;
out:
return ret;
return 0;
}
static int eps_dbg_open(struct inode *inode, struct file *file)
......
......@@ -35,6 +35,8 @@
* @dev - the child device to the actual controller
* @gadget - the gadget. For use by the class code
* @list - for use by the udc class driver
* @vbus - for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
*
* This represents the internal data structure which is used by the UDC-class
* to hold information about udc driver and gadget together.
......@@ -44,6 +46,7 @@ struct usb_udc {
struct usb_gadget *gadget;
struct device dev;
struct list_head list;
bool vbus;
};
static struct class *udc_class;
......@@ -129,19 +132,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);
static void usb_gadget_state_work(struct work_struct *work)
{
struct usb_gadget *gadget = work_to_gadget(work);
struct usb_udc *udc = NULL;
mutex_lock(&udc_lock);
list_for_each_entry(udc, &udc_list, list)
if (udc->gadget == gadget)
goto found;
mutex_unlock(&udc_lock);
return;
found:
mutex_unlock(&udc_lock);
struct usb_udc *udc = gadget->udc;
if (udc)
sysfs_notify(&udc->dev.kobj, NULL, "state");
}
......@@ -155,6 +148,34 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
/* ------------------------------------------------------------------------- */
static void usb_udc_connect_control(struct usb_udc *udc)
{
if (udc->vbus)
usb_gadget_connect(udc->gadget);
else
usb_gadget_disconnect(udc->gadget);
}
/**
* usb_udc_vbus_handler - updates the udc core vbus status, and try to
* connect or disconnect gadget
* @gadget: The gadget which vbus change occurs
* @status: The vbus status
*
* The udc driver calls it when it wants to connect or disconnect gadget
* according to vbus status.
*/
void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
{
struct usb_udc *udc = gadget->udc;
if (udc) {
udc->vbus = status;
usb_udc_connect_control(udc);
}
}
EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
/**
* usb_gadget_udc_reset - notifies the udc core that bus reset occurs
* @gadget: The gadget which bus reset occurs
......@@ -278,6 +299,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
goto err3;
udc->gadget = gadget;
gadget->udc = udc;
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
......@@ -287,6 +309,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
goto err4;
usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;
mutex_unlock(&udc_lock);
......@@ -348,21 +371,14 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
*/
void usb_del_gadget_udc(struct usb_gadget *gadget)
{
struct usb_udc *udc = NULL;
mutex_lock(&udc_lock);
list_for_each_entry(udc, &udc_list, list)
if (udc->gadget == gadget)
goto found;
dev_err(gadget->dev.parent, "gadget not registered.\n");
mutex_unlock(&udc_lock);
struct usb_udc *udc = gadget->udc;
if (!udc)
return;
found:
dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
......@@ -397,7 +413,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri
driver->unbind(udc->gadget);
goto err1;
}
usb_gadget_connect(udc->gadget);
usb_udc_connect_control(udc);
kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
return 0;
......
This diff is collapsed.
......@@ -160,7 +160,8 @@ struct musb_io;
* @init: turns on clocks, sets up platform-specific registers, etc
* @exit: undoes @init
* @set_mode: forcefully changes operating mode
* @try_ilde: tries to idle the IP
* @try_idle: tries to idle the IP
* @recover: platform-specific babble recovery
* @vbus_status: returns vbus status if possible
* @set_vbus: forces vbus status
* @adjust_channel_params: pre check for standard dma channel_program func
......@@ -196,7 +197,7 @@ struct musb_platform_ops {
void (*write_fifo)(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf);
int (*set_mode)(struct musb *musb, u8 mode);
void (*try_idle)(struct musb *musb, unsigned long timeout);
int (*reset)(struct musb *musb);
int (*recover)(struct musb *musb);
int (*vbus_status)(struct musb *musb);
void (*set_vbus)(struct musb *musb, int on);
......@@ -300,7 +301,6 @@ struct musb {
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
struct delayed_work recover_work;
struct delayed_work deassert_reset_work;
struct delayed_work finish_resume_work;
u16 hwvers;
......@@ -558,12 +558,12 @@ static inline void musb_platform_try_idle(struct musb *musb,
musb->ops->try_idle(musb, timeout);
}
static inline int musb_platform_reset(struct musb *musb)
static inline int musb_platform_recover(struct musb *musb)
{
if (!musb->ops->reset)
return -EINVAL;
if (!musb->ops->recover)
return 0;
return musb->ops->reset(musb);
return musb->ops->recover(musb);
}
static inline int musb_platform_get_vbus_status(struct musb *musb)
......
......@@ -225,10 +225,12 @@ static void cppi41_dma_callback(void *private_data)
struct dma_channel *channel = private_data;
struct cppi41_dma_channel *cppi41_channel = channel->private_data;
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
struct cppi41_dma_controller *controller;
struct musb *musb = hw_ep->musb;
unsigned long flags;
struct dma_tx_state txstate;
u32 transferred;
int is_hs = 0;
bool empty;
spin_lock_irqsave(&musb->lock, flags);
......@@ -248,12 +250,14 @@ static void cppi41_dma_callback(void *private_data)
transferred < cppi41_channel->packet_sz)
cppi41_channel->prog_len = 0;
if (cppi41_channel->is_tx)
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
if (!cppi41_channel->is_tx || empty) {
cppi41_trans_done(cppi41_channel);
} else {
struct cppi41_dma_controller *controller;
int is_hs = 0;
goto out;
}
/*
* On AM335x it has been observed that the TX interrupt fires
* too early that means the TXFIFO is not yet empty but the DMA
......@@ -277,20 +281,16 @@ static void cppi41_dma_callback(void *private_data)
unsigned wait = 25;
do {
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty)
break;
wait--;
if (!wait)
break;
udelay(1);
} while (1);
empty = musb_is_tx_fifo_empty(hw_ep);
if (empty) {
cppi41_trans_done(cppi41_channel);
goto out;
}
wait--;
if (!wait)
break;
cpu_relax();
} while (1);
}
list_add_tail(&cppi41_channel->tx_check,
&controller->early_tx_list);
......@@ -302,7 +302,7 @@ static void cppi41_dma_callback(void *private_data)
20 * NSEC_PER_USEC,
HRTIMER_MODE_REL);
}
}
out:
spin_unlock_irqrestore(&musb->lock, flags);
}
......
This diff is collapsed.
......@@ -1876,44 +1876,6 @@ static int musb_gadget_start(struct usb_gadget *g,
return retval;
}
static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
{
int i;
struct musb_hw_ep *hw_ep;
/* don't disconnect if it's not connected */
if (musb->g.speed == USB_SPEED_UNKNOWN)
driver = NULL;
else
musb->g.speed = USB_SPEED_UNKNOWN;
/* deactivate the hardware */
if (musb->softconnect) {
musb->softconnect = 0;
musb_pullup(musb, 0);
}
musb_stop(musb);
/* killing any outstanding requests will quiesce the driver;
* then report disconnect
*/
if (driver) {
for (i = 0, hw_ep = musb->endpoints;
i < musb->nr_endpoints;
i++, hw_ep++) {
musb_ep_select(musb->mregs, i);
if (hw_ep->is_shared_fifo /* || !epnum */) {
nuke(&hw_ep->ep_in, -ESHUTDOWN);
} else {
if (hw_ep->max_packet_sz_tx)
nuke(&hw_ep->ep_in, -ESHUTDOWN);
if (hw_ep->max_packet_sz_rx)
nuke(&hw_ep->ep_out, -ESHUTDOWN);
}
}
}
}
/*
* Unregister the gadget driver. Used by gadget drivers when
* unregistering themselves from the controller.
......@@ -1940,7 +1902,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
(void) musb_gadget_vbus_draw(&musb->g, 0);
musb->xceiv->otg->state = OTG_STATE_UNDEFINED;
stop_activity(musb, NULL);
musb_stop(musb);
otg_set_peripheral(musb->xceiv->otg, NULL);
musb->is_active = 0;
......
......@@ -202,13 +202,13 @@ config USB_RCAR_GEN2_PHY
config USB_ULPI
bool "Generic ULPI Transceiver Driver"
depends on ARM || ARM64
select USB_ULPI_VIEWPORT
help
Enable this to support ULPI connected USB OTG transceivers which
are likely found on embedded boards.
config USB_ULPI_VIEWPORT
bool
depends on USB_ULPI
help
Provides read/write operations to the ULPI phy register set for
controllers with a viewport register (e.g. Chipidea/ARC controllers).
......
......@@ -27,7 +27,7 @@ static const char *const usbphy_modes[] = {
* @np: Pointer to the given device_node
*
* The function gets phy interface string from property 'phy_type',
* and returns the correspondig enum usb_phy_interface
* and returns the corresponding enum usb_phy_interface
*/
enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np)
{
......
......@@ -893,7 +893,7 @@ static int abx500_usb_link_status_update(struct ab8500_usb *ab)
/*
* Disconnection Sequence:
* 1. Disconect Interrupt
* 1. Disconnect Interrupt
* 2. Disable regulators
* 3. Disable AB clock
* 4. Disable the Phy
......
This diff is collapsed.
......@@ -81,7 +81,9 @@ static void devm_usb_phy_release(struct device *dev, void *res)
static int devm_usb_phy_match(struct device *dev, void *res, void *match_data)
{
return res == match_data;
struct usb_phy **phy = res;
return *phy == match_data;
}
/**
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -58,6 +58,7 @@ struct usbhs_pkt {
struct usbhs_pkt *pkt);
struct work_struct work;
dma_addr_t dma;
dma_cookie_t cookie;
void *buf;
int length;
int trans;
......
This diff is collapsed.
This diff is collapsed.
......@@ -97,6 +97,7 @@ void usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len);
void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
u16 epnum, u16 maxp);
void usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable);
#define usbhs_pipe_sequence_data0(pipe) usbhs_pipe_data_sequence(pipe, 0)
#define usbhs_pipe_sequence_data1(pipe) usbhs_pipe_data_sequence(pipe, 1)
......
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