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,
const struct pci_device_id *id)
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,8 +121,10 @@ static int dwc2_driver_remove(struct platform_device *dev)
{
struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
dwc2_hcd_remove(hsotg);
s3c_hsotg_remove(hsotg);
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);
retval = dwc2_gadget_init(hsotg, irq);
if (retval)
return retval;
retval = dwc2_hcd_init(hsotg, irq, params);
if (retval)
return retval;
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 (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,32 +1855,27 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
unsigned int i;
int ret;
req = next_request(&dep->req_queued);
if (!req) {
WARN_ON_ONCE(1);
return 1;
}
i = 0;
do {
req = next_request(&dep->req_queued);
if (!req) {
WARN_ON_ONCE(1);
return 1;
}
i = 0;
do {
slot = req->start_slot + i;
if ((slot == DWC3_TRB_NUM - 1) &&
slot = req->start_slot + i;
if ((slot == DWC3_TRB_NUM - 1) &&
usb_endpoint_xfer_isoc(dep->endpoint.desc))
slot++;
slot %= DWC3_TRB_NUM;
trb = &dep->trb_pool[slot];
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
event, status);
if (ret)
break;
}while (++i < req->request.num_mapped_sgs);
dwc3_gadget_giveback(dep, req, status);
slot++;
slot %= DWC3_TRB_NUM;
trb = &dep->trb_pool[slot];
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
event, status);
if (ret)
break;
} while (1);
} while (++i < req->request.num_mapped_sgs);
dwc3_gadget_giveback(dep, req, status);
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
......
......@@ -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,7 +1739,72 @@ 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)
{
int ret;
if (udc->clocked)
return 0;
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;
}
udc->clocked = true;
return 0;
}
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);
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);
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;
......@@ -1747,35 +1812,22 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
/* debounce */
udelay(10);
spin_lock(&udc->lock);
/* May happen if Vbus pin toggles during probe() */
if (!udc->driver)
goto out;
mutex_lock(&udc->vbus_mutex);
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_int_enb_set(udc, USBA_END_OF_RESET);
usba_start(udc);
} else {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
if (udc->driver->disconnect) {
spin_unlock(&udc->lock);
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,35 +1024,79 @@ 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",
label, mask,
(mask & INT_PWRDETECT) ? " power" : "",
(mask & INT_SYSERROR) ? " sys" : "",
(mask & INT_MSTRDEND) ? " in-dma" : "",
(mask & INT_MSTWRTMOUT) ? " wrtmo" : "",
(mask & INT_MSTWREND) ? " out-dma" : "",
(mask & INT_MSTWRSET) ? " wrset" : "",
(mask & INT_ERR) ? " err" : "",
(mask & INT_SOF) ? " sof" : "",
(mask & INT_EP3NAK) ? " ep3nak" : "",
(mask & INT_EP2NAK) ? " ep2nak" : "",
(mask & INT_EP1NAK) ? " ep1nak" : "",
(mask & INT_EP3DATASET) ? " ep3" : "",
(mask & INT_EP2DATASET) ? " ep2" : "",
(mask & INT_EP1DATASET) ? " ep1" : "",
(mask & INT_STATUSNAK) ? " ep0snak" : "",
(mask & INT_STATUS) ? " ep0status" : "",
(mask & INT_SETUP) ? " setup" : "",
(mask & INT_ENDPOINT0) ? " ep0" : "",
(mask & INT_USBRESET) ? " reset" : "",
(mask & INT_SUSPEND) ? " suspend" : "");
seq_printf(m, "%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n",
label, mask,
(mask & INT_PWRDETECT) ? " power" : "",
(mask & INT_SYSERROR) ? " sys" : "",
(mask & INT_MSTRDEND) ? " in-dma" : "",
(mask & INT_MSTWRTMOUT) ? " wrtmo" : "",
(mask & INT_MSTWREND) ? " out-dma" : "",
(mask & INT_MSTWRSET) ? " wrset" : "",
(mask & INT_ERR) ? " err" : "",
(mask & INT_SOF) ? " sof" : "",
(mask & INT_EP3NAK) ? " ep3nak" : "",
(mask & INT_EP2NAK) ? " ep2nak" : "",
(mask & INT_EP1NAK) ? " ep1nak" : "",
(mask & INT_EP3DATASET) ? " ep3" : "",
(mask & INT_EP2DATASET) ? " ep2" : "",
(mask & INT_EP1DATASET) ? " ep1" : "",
(mask & INT_STATUSNAK) ? " ep0snak" : "",
(mask & INT_STATUS) ? " ep0status" : "",
(mask & INT_SETUP) ? " setup" : "",
(mask & INT_ENDPOINT0) ? " ep0" : "",
(mask & INT_USBRESET) ? " reset" : "",
(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)
{
......@@ -1068,29 +1112,18 @@ static int udc_proc_read(struct seq_file *m, void *v)
tmp = readl(&regs->power_detect);
is_usb_connected = tmp & PW_DETECT;
seq_printf(m,
"%s - %s\n"
"%s version: %s %s\n"
"Gadget driver: %s\n"
"Host %s, %s\n"
"\n",
pci_name(dev->pdev), driver_desc,
driver_name, DRIVER_VERSION, dmastr(),
dev->driver ? dev->driver->driver.name : "(none)",
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; })
);
"%s - %s\n"
"%s version: %s %s\n"
"Gadget driver: %s\n"
"Host %s, %s\n"
"\n",
pci_name(dev->pdev), driver_desc,
driver_name, DRIVER_VERSION, dmastr(),
dev->driver ? dev->driver->driver.name : "(none)",
is_usb_connected
? ((tmp & PW_PULLUP) ? "full speed" : "powered")
: "disconnected",
udc_ep_state(dev->ep0state));
dump_intmask(m, "int_status", readl(&regs->int_status));
dump_intmask(m, "int_enable", readl(&regs->int_enable));
......@@ -1099,31 +1132,30 @@ 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",
dev->irqs, readl(&regs->DataSet),
readl(&regs->EPxSingle), readl(&regs->EPxBCS),
readl(&regs->UsbState),
readl(&regs->address)) < 0)
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));
if (seq_has_overflowed(m))
goto done;
tmp = readl(&regs->dma_master);
if (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-" : "",
(tmp & MST_TIMEOUT_ENA) ? " tmo+" : "",
(tmp & MST_RD_EOPB) ? " eopb" : "",
(tmp & MST_RD_RESET) ? " in_reset" : "",
(tmp & MST_WR_RESET) ? " out_reset" : "",
(tmp & MST_RD_ENA) ? " IN" : "",
(tmp & MST_WR_ENA) ? " OUT" : "",
(tmp & MST_CONNECTION)
? "ep1in/ep2out"
: "ep1out/ep2in") < 0)
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-" : "",
(tmp & MST_TIMEOUT_ENA) ? " tmo+" : "",
(tmp & MST_RD_EOPB) ? " eopb" : "",
(tmp & MST_RD_RESET) ? " in_reset" : "",
(tmp & MST_WR_RESET) ? " out_reset" : "",
(tmp & MST_RD_ENA) ? " IN" : "",
(tmp & MST_WR_ENA) ? " OUT" : "",
(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",
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 & EPxSTATUS_TOGGLE) ? "data1" : "data0",
(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",
(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "",
(tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : ""
) < 0)
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, udc_ep_status(tmp),
(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",
(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",
(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "",
(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",
&req->req, tmp, req->req.length,
req->req.buf) < 0)
seq_printf(m, "\treq %p len %u/%u buf %p\n",
&req->req, tmp, req->req.length,
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,50 +93,46 @@ 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",
driver_name, DRIVER_VERSION,
udc->driver ? udc->driver->driver.name : "(none)");
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,
(tmp & UDCCR_OEN) ? " oen":"",
(tmp & UDCCR_AALTHNP) ? " aalthnp":"",
(tmp & UDCCR_AHNP) ? " rem" : "",
(tmp & UDCCR_BHNP) ? " rstir" : "",
(tmp & UDCCR_DWRE) ? " dwre" : "",
(tmp & UDCCR_SMAC) ? " smac" : "",
(tmp & UDCCR_EMCE) ? " emce" : "",
(tmp & UDCCR_UDR) ? " udr" : "",
(tmp & UDCCR_UDA) ? " uda" : "",
(tmp & UDCCR_UDE) ? " ude" : "",
(tmp & UDCCR_ACN) >> UDCCR_ACN_S,
(tmp & UDCCR_AIN) >> UDCCR_AIN_S,
(tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
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" : "",
(tmp & UDCCR_BHNP) ? " rstir" : "",
(tmp & UDCCR_DWRE) ? " dwre" : "",
(tmp & UDCCR_SMAC) ? " smac" : "",
(tmp & UDCCR_EMCE) ? " emce" : "",
(tmp & UDCCR_UDR) ? " udr" : "",
(tmp & UDCCR_UDA) ? " uda" : "",
(tmp & UDCCR_UDE) ? " ude" : "",
(tmp & UDCCR_ACN) >> UDCCR_ACN_S,
(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",
udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
pos += 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",
udc->stats.irqs_reset, udc->stats.irqs_suspend,
udc->stats.irqs_resume, udc->stats.irqs_reconfig);
ret = 0;
out:
return ret;
seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
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);
return 0;
}
static int queues_dbg_show(struct seq_file *s, void *p)
......@@ -144,75 +140,67 @@ 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",
EPNAME(ep), maxpkt, "pio");
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",
&req->req, req->req.actual,
req->req.length, req->req.buf);
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,
(tmp & UDCCSR0_SA) ? " sa" : "",
(tmp & UDCCSR0_RNE) ? " rne" : "",
(tmp & UDCCSR0_FST) ? " fst" : "",
(tmp & UDCCSR0_SST) ? " sst" : "",
(tmp & UDCCSR0_DME) ? " dme" : "",
(tmp & UDCCSR0_IPR) ? " ipr" : "",
(tmp & UDCCSR0_OPC) ? " opc" : "");
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" : "",
(tmp & UDCCSR0_SST) ? " sst" : "",
(tmp & UDCCSR0_DME) ? " dme" : "",
(tmp & UDCCSR0_IPR) ? " ipr" : "",
(tmp & UDCCSR0_OPC) ? " opc" : "");
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",
EPNAME(ep),
ep->stats.in_bytes, ep->stats.in_ops,
ep->stats.out_bytes, ep->stats.out_ops,
ep->stats.irqs,
tmp, udc_ep_readl(ep, UDCCSR),
udc_ep_readl(ep, UDCBCR));
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,
ep->stats.irqs,
tmp, udc_ep_readl(ep, UDCCSR),
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;
......@@ -128,21 +131,11 @@ 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_gadget *gadget = work_to_gadget(work);
struct usb_udc *udc = gadget->udc;
sysfs_notify(&udc->dev.kobj, NULL, "state");
if (udc)
sysfs_notify(&udc->dev.kobj, NULL, "state");
}
void usb_gadget_set_state(struct usb_gadget *gadget,
......@@ -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;
struct usb_udc *udc = gadget->udc;
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);
return;
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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -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.
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