diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 12:19:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-29 12:19:23 -0700 |
commit | ec25e246b94a3233ab064994ef05a170bdba0e7c (patch) | |
tree | 49b7d7e4c46e13bb465c7b832961596e41e8526a /drivers/usb | |
parent | 507ffe4f3840ac24890a8123c702cf1b7fe4d33c (diff) | |
parent | 4626b8daf9bb00ce6b4d533c1a155211ad880f32 (diff) | |
download | linux-ec25e246b94a3233ab064994ef05a170bdba0e7c.tar.gz linux-ec25e246b94a3233ab064994ef05a170bdba0e7c.tar.bz2 linux-ec25e246b94a3233ab064994ef05a170bdba0e7c.zip |
Merge tag 'usb-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB patches from Greg Kroah-Hartman:
"Here's the big USB pull request for 3.10-rc1.
Lots of USB patches here, the majority being USB gadget changes and
USB-serial driver cleanups, the rest being ARM build fixes / cleanups,
and individual driver updates. We also finally got some chipidea
fixes, which have been delayed for a number of kernel releases, as the
maintainer has now reappeared.
All of these have been in linux-next for a while"
* tag 'usb-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (568 commits)
USB: ehci-msm: USB_MSM_OTG needs USB_PHY
USB: OHCI: avoid conflicting platform drivers
USB: OMAP: ISP1301 needs USB_PHY
USB: lpc32xx: ISP1301 needs USB_PHY
USB: ftdi_sio: enable two UART ports on ST Microconnect Lite
usb: phy: tegra: don't call into tegra-ehci directly
usb: phy: phy core cannot yet be a module
USB: Fix initconst in ehci driver
usb-storage: CY7C68300A chips do not support Cypress ATACB
USB: serial: option: Added support Olivetti Olicard 145
USB: ftdi_sio: correct ST Micro Connect Lite PIDs
ARM: mxs_defconfig: add CONFIG_USB_PHY
ARM: imx_v6_v7_defconfig: add CONFIG_USB_PHY
usb: phy: remove exported function from __init section
usb: gadget: zero: put function instances on unbind
usb: gadget: f_sourcesink.c: correct a copy-paste misnomer
usb: gadget: cdc2: fix error return code in cdc_do_config()
usb: gadget: multi: fix error return code in rndis_do_config()
usb: gadget: f_obex: fix error return code in obex_bind()
USB: storage: convert to use module_usb_driver()
...
Diffstat (limited to 'drivers/usb')
267 files changed, 9961 insertions, 9728 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 640ae6c6d2d2..92e1dc94ecc8 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -122,9 +122,9 @@ config USB To compile this driver as a module, choose M here: the module will be called usbcore. -source "drivers/usb/core/Kconfig" +if USB -source "drivers/usb/dwc3/Kconfig" +source "drivers/usb/core/Kconfig" source "drivers/usb/mon/Kconfig" @@ -134,8 +134,6 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" -source "drivers/usb/chipidea/Kconfig" - source "drivers/usb/renesas_usbhs/Kconfig" source "drivers/usb/class/Kconfig" @@ -144,12 +142,19 @@ source "drivers/usb/storage/Kconfig" source "drivers/usb/image/Kconfig" +endif + +source "drivers/usb/dwc3/Kconfig" + +source "drivers/usb/chipidea/Kconfig" + comment "USB port drivers" - depends on USB + +if USB config USB_USS720 tristate "USS720 parport driver" - depends on USB && PARPORT + depends on PARPORT select PARPORT_NOT_PC ---help--- This driver is for USB parallel port adapters that use the Lucent @@ -180,12 +185,12 @@ source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" -source "drivers/usb/phy/Kconfig" - source "drivers/usb/atm/Kconfig" -source "drivers/usb/gadget/Kconfig" +endif # USB + +source "drivers/usb/phy/Kconfig" -source "drivers/usb/otg/Kconfig" +source "drivers/usb/gadget/Kconfig" endif # USB_SUPPORT diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 8f5ebced5df0..c41feba8d5c0 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -6,8 +6,6 @@ obj-$(CONFIG_USB) += core/ -obj-$(CONFIG_USB_OTG_UTILS) += otg/ - obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_MON) += mon/ @@ -46,7 +44,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ -obj-$(CONFIG_USB_OTG_UTILS) += phy/ +obj-$(CONFIG_USB_PHY) += phy/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig index be0b8daac9c7..0f922942a07a 100644 --- a/drivers/usb/atm/Kconfig +++ b/drivers/usb/atm/Kconfig @@ -4,7 +4,7 @@ menuconfig USB_ATM tristate "USB DSL modem support" - depends on USB && ATM + depends on ATM select CRC32 default n help diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 35f10bfe15db..d3527dd8b90c 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -672,9 +672,6 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) struct usbatm_control *ctrl = UDSL_SKB(skb); int err; - vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__, - skb, skb->len); - /* racy disconnection check - fine */ if (!instance || instance->disconnected) { #ifdef DEBUG @@ -684,6 +681,9 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) goto fail; } + vdbg(&instance->usb_intf->dev, "%s called (skb 0x%p, len %u)", __func__, + skb, skb->len); + if (vcc->qos.aal != ATM_AAL5) { atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); err = -EINVAL; diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index d92ca325b104..4ab83e98219b 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),) endif ifneq ($(CONFIG_OF_DEVICE),) - obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx6q.o + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_imx.o usbmisc_imx.o endif diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index e25d1263da13..b0a6bce064ca 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -21,6 +21,7 @@ /****************************************************************************** * DEFINE *****************************************************************************/ +#define TD_PAGE_COUNT 5 #define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ #define ENDPT_MAX 32 @@ -129,6 +130,7 @@ struct hw_bank { * @vbus_active: is VBUS active * @transceiver: pointer to USB PHY, if any * @hcd: pointer to usb_hcd for ehci host driver + * @debugfs: root dentry for this controller in debugfs */ struct ci13xxx { struct device *dev; @@ -139,7 +141,6 @@ struct ci13xxx { enum ci_role role; bool is_otg; struct work_struct work; - struct work_struct vbus_work; struct workqueue_struct *wq; struct dma_pool *qh_pool; @@ -165,6 +166,7 @@ struct ci13xxx { bool global_phy; struct usb_phy *transceiver; struct usb_hcd *hcd; + struct dentry *debugfs; }; static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) @@ -234,19 +236,6 @@ enum ci13xxx_regs { }; /** - * ffs_nr: find first (least significant) bit set - * @x: the word to search - * - * This function returns bit number (instead of position) - */ -static inline int ffs_nr(u32 x) -{ - int n = ffs(x); - - return n ? n-1 : 32; -} - -/** * hw_read: reads from a hw register * @reg: register index * @mask: bitfield mask @@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 val = hw_read(ci, reg, ~0); hw_write(ci, reg, mask, data); - return (val & mask) >> ffs_nr(mask); + return (val & mask) >> __ffs(mask); } int hw_device_reset(struct ci13xxx *ci, u32 mode); diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c index 8c291220be7f..8faec9dbbb84 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.c +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev) if (of_find_property(np, "disable-over-current", NULL)) usbdev->disable_oc = 1; + if (of_find_property(np, "external-vbus-divider", NULL)) + usbdev->evdo = 1; + return 0; } EXPORT_SYMBOL_GPL(usbmisc_get_init_data); @@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev) goto err; } + if (usbmisc_ops && usbmisc_ops->post) { + ret = usbmisc_ops->post(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "usbmisc post failed, ret=%d\n", ret); + goto put_np; + } + } + data->ci_pdev = plat_ci; platform_set_drvdata(pdev, data); diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h index 9cd2e910b1ca..550bfa457620 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.h +++ b/drivers/usb/chipidea/ci13xxx_imx.h @@ -13,6 +13,8 @@ struct usbmisc_ops { /* It's called once when probe a usb device */ int (*init)(struct device *dev); + /* It's called once after adding a usb device */ + int (*post)(struct device *dev); }; struct usbmisc_usb_device { @@ -20,6 +22,7 @@ struct usbmisc_usb_device { int index; unsigned int disable_oc:1; /* over current detect disabled */ + unsigned int evdo:1; /* set external vbus divider option */ }; int usbmisc_set_ops(const struct usbmisc_ops *ops); diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c index 9b227e39299a..4e1fc61b9d95 100644 --- a/drivers/usb/chipidea/ci13xxx_pci.c +++ b/drivers/usb/chipidea/ci13xxx_pci.c @@ -23,17 +23,17 @@ /****************************************************************************** * PCI block *****************************************************************************/ -struct ci13xxx_platform_data pci_platdata = { +static struct ci13xxx_platform_data pci_platdata = { .name = UDC_DRIVER_NAME, .capoffset = DEF_CAPOFFSET, }; -struct ci13xxx_platform_data langwell_pci_platdata = { +static struct ci13xxx_platform_data langwell_pci_platdata = { .name = UDC_DRIVER_NAME, .capoffset = 0, }; -struct ci13xxx_platform_data penwell_pci_platdata = { +static struct ci13xxx_platform_data penwell_pci_platdata = { .name = UDC_DRIVER_NAME, .capoffset = 0, .power_budget = 200, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 57cae1f897b2..450107e5f657 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -51,15 +51,12 @@ */ #include <linux/delay.h> #include <linux/device.h> -#include <linux/dmapool.h> #include <linux/dma-mapping.h> -#include <linux/init.h> #include <linux/platform_device.h> #include <linux/module.h> #include <linux/idr.h> #include <linux/interrupt.h> #include <linux/io.h> -#include <linux/irq.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pm_runtime.h> @@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode) if (mode > TEST_MODE_MAX) return -EINVAL; - hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); + hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC)); return 0; } @@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode) */ u8 hw_port_test_get(struct ci13xxx *ci) { - return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); + return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC); } static int hw_device_init(struct ci13xxx *ci, void __iomem *base) @@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base) ci->hw_bank.cap = ci->hw_bank.abs; ci->hw_bank.cap += ci->platdata->capoffset; - ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap); + ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff); hw_alloc_regmap(ci, false); reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> - ffs_nr(HCCPARAMS_LEN); + __ffs(HCCPARAMS_LEN); ci->hw_bank.lpm = reg; hw_alloc_regmap(ci, !!reg); ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; @@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base) ci->hw_bank.size /= sizeof(u32); reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> - ffs_nr(DCCPARAMS_DEN); + __ffs(DCCPARAMS_DEN); ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ if (ci->hw_ep_max > ENDPT_MAX) @@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work) } } -static ssize_t show_role(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *ci = dev_get_drvdata(dev); - - return sprintf(buf, "%s\n", ci_role(ci)->name); -} - -static ssize_t store_role(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *ci = dev_get_drvdata(dev); - enum ci_role role; - int ret; - - for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) - if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name)) - break; - - if (role == CI_ROLE_END || role == ci->role) - return -EINVAL; - - ci_role_stop(ci); - ret = ci_role_start(ci, role); - if (ret) - return ret; - - return count; -} - -static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role); - static irqreturn_t ci_irq(int irq, void *data) { struct ci13xxx *ci = data; @@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } - base = devm_request_and_ioremap(dev, res); - if (!base) { - dev_err(dev, "can't request and ioremap resource\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); if (!ci) { @@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (ret) goto stop; - ret = device_create_file(dev, &dev_attr_role); - if (ret) - goto rm_attr; - if (ci->is_otg) hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); - return ret; + ret = dbg_create_files(ci); + if (!ret) + return 0; -rm_attr: - device_remove_file(dev, &dev_attr_role); + free_irq(ci->irq, ci); stop: ci_role_stop(ci); rm_wq: @@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev) { struct ci13xxx *ci = platform_get_drvdata(pdev); + dbg_remove_files(ci); flush_workqueue(ci->wq); destroy_workqueue(ci->wq); - device_remove_file(ci->dev, &dev_attr_role); free_irq(ci->irq, ci); ci_role_stop(ci); diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index a62c4a47d52c..36a7063a6cba 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -1,590 +1,126 @@ -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dmapool.h> -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <linux/usb/otg.h> -#include <linux/usb/chipidea.h> #include "ci.h" #include "udc.h" #include "bits.h" #include "debug.h" -/* Interrupt statistics */ -#define ISR_MASK 0x1F -static struct isr_statistics { - u32 test; - u32 ui; - u32 uei; - u32 pci; - u32 uri; - u32 sli; - u32 none; - struct { - u32 cnt; - u32 buf[ISR_MASK+1]; - u32 idx; - } hndl; -} isr_statistics; - -void dbg_interrupt(u32 intmask) -{ - if (!intmask) { - isr_statistics.none++; - return; - } - - isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask; - isr_statistics.hndl.idx &= ISR_MASK; - isr_statistics.hndl.cnt++; - - if (USBi_URI & intmask) - isr_statistics.uri++; - if (USBi_PCI & intmask) - isr_statistics.pci++; - if (USBi_UEI & intmask) - isr_statistics.uei++; - if (USBi_UI & intmask) - isr_statistics.ui++; - if (USBi_SLI & intmask) - isr_statistics.sli++; -} - /** - * hw_register_read: reads all device registers (execute without interruption) - * @buf: destination buffer - * @size: buffer size - * - * This function returns number of registers read + * ci_device_show: prints information about device capabilities and status */ -static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size) +static int ci_device_show(struct seq_file *s, void *data) { - unsigned i; - - if (size > ci->hw_bank.size) - size = ci->hw_bank.size; - - for (i = 0; i < size; i++) - buf[i] = hw_read(ci, i * sizeof(u32), ~0); - - return size; -} - -/** - * hw_register_write: writes to register - * @addr: register address - * @data: register value - * - * This function returns an error code - */ -static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data) -{ - /* align */ - addr /= sizeof(u32); - - if (addr >= ci->hw_bank.size) - return -EINVAL; - - /* align */ - addr *= sizeof(u32); - - hw_write(ci, addr, ~0, data); - return 0; -} - -/** - * hw_intr_clear: disables interrupt & clears interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_clear(struct ci13xxx *ci, int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_write(ci, OP_USBINTR, BIT(n), 0); - hw_write(ci, OP_USBSTS, BIT(n), BIT(n)); - return 0; -} - -/** - * hw_intr_force: enables interrupt & forces interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_force(struct ci13xxx *ci, int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); - hw_write(ci, OP_USBINTR, BIT(n), BIT(n)); - hw_write(ci, OP_USBSTS, BIT(n), BIT(n)); - hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0); - return 0; -} - -/** - * show_device: prints information about device capabilities and status - * - * Check "device.h" for details - */ -static ssize_t show_device(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); + struct ci13xxx *ci = s->private; struct usb_gadget *gadget = &ci->gadget; - int n = 0; - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); + seq_printf(s, "speed = %d\n", gadget->speed); + seq_printf(s, "max_speed = %d\n", gadget->max_speed); + seq_printf(s, "is_otg = %d\n", gadget->is_otg); + seq_printf(s, "is_a_peripheral = %d\n", gadget->is_a_peripheral); + seq_printf(s, "b_hnp_enable = %d\n", gadget->b_hnp_enable); + seq_printf(s, "a_hnp_support = %d\n", gadget->a_hnp_support); + seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support); + seq_printf(s, "name = %s\n", + (gadget->name ? gadget->name : "")); + + if (!ci->driver) return 0; - } - - n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", - gadget->speed); - n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", - gadget->max_speed); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", - gadget->is_otg); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", - gadget->is_a_peripheral); - n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", - gadget->b_hnp_enable); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", - gadget->a_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", - gadget->a_alt_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", - (gadget->name ? gadget->name : "")); - - return n; -} -static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); - -/** - * show_driver: prints information about attached gadget (if any) - * - * Check "device.h" for details - */ -static ssize_t show_driver(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget_driver *driver = ci->driver; - int n = 0; - - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - if (driver == NULL) - return scnprintf(buf, PAGE_SIZE, - "There is no gadget attached!\n"); - n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", - (driver->function ? driver->function : "")); - n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->max_speed); + seq_printf(s, "gadget function = %s\n", + (ci->driver->function ? ci->driver->function : "")); + seq_printf(s, "gadget max speed = %d\n", ci->driver->max_speed); - return n; -} -static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); - -/* Maximum event message length */ -#define DBG_DATA_MSG 64UL - -/* Maximum event messages */ -#define DBG_DATA_MAX 128UL - -/* Event buffer descriptor */ -static struct { - char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ - unsigned idx; /* index */ - unsigned tty; /* print to console? */ - rwlock_t lck; /* lock */ -} dbg_data = { - .idx = 0, - .tty = 0, - .lck = __RW_LOCK_UNLOCKED(dbg_data.lck) -}; - -/** - * dbg_dec: decrements debug event index - * @idx: buffer index - */ -static void dbg_dec(unsigned *idx) -{ - *idx = (*idx - 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ - *idx = (*idx + 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_print: prints the common part of the event - * @addr: endpoint address - * @name: event name - * @status: status - * @extra: extra information - */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) -{ - struct timeval tval; - unsigned int stamp; - unsigned long flags; - - write_lock_irqsave(&dbg_data.lck, flags); - - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ - stamp = stamp * 1000000 + tval.tv_usec; - - scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, - "%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); - - dbg_inc(&dbg_data.idx); - - write_unlock_irqrestore(&dbg_data.lck, flags); - - if (dbg_data.tty != 0) - pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); -} - -/** - * dbg_done: prints a DONE event - * @addr: endpoint address - * @td: transfer descriptor - * @status: status - */ -void dbg_done(u8 addr, const u32 token, int status) -{ - char msg[DBG_DATA_MSG]; - - scnprintf(msg, sizeof(msg), "%d %02X", - (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), - (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); - dbg_print(addr, "DONE", status, msg); -} - -/** - * dbg_event: prints a generic event - * @addr: endpoint address - * @name: event name - * @status: status - */ -void dbg_event(u8 addr, const char *name, int status) -{ - if (name != NULL) - dbg_print(addr, name, status, ""); -} - -/* - * dbg_queue: prints a QUEUE event - * @addr: endpoint address - * @req: USB request - * @status: status - */ -void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%d %d", !req->no_interrupt, req->length); - dbg_print(addr, "QUEUE", status, msg); - } -} - -/** - * dbg_setup: prints a SETUP event - * @addr: endpoint address - * @req: setup request - */ -void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%02X %02X %04X %04X %d", req->bRequestType, - req->bRequest, le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); - dbg_print(addr, "SETUP", 0, msg); - } + return 0; } -/** - * show_events: displays the event buffer - * - * Check "device.h" for details - */ -static ssize_t show_events(struct device *dev, struct device_attribute *attr, - char *buf) +static int ci_device_open(struct inode *inode, struct file *file) { - unsigned long flags; - unsigned i, j, n = 0; - - if (attr == NULL || buf == NULL) { - dev_err(dev->parent, "[%s] EINVAL\n", __func__); - return 0; - } - - read_lock_irqsave(&dbg_data.lck, flags); - - i = dbg_data.idx; - for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { - n += strlen(dbg_data.buf[i]); - if (n >= PAGE_SIZE) { - n -= strlen(dbg_data.buf[i]); - break; - } - } - for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) - j += scnprintf(buf + j, PAGE_SIZE - j, - "%s", dbg_data.buf[i]); - - read_unlock_irqrestore(&dbg_data.lck, flags); - - return n; + return single_open(file, ci_device_show, inode->i_private); } -/** - * store_events: configure if events are going to be also printed to console - * - * Check "device.h" for details - */ -static ssize_t store_events(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned tty; - - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { - dev_err(dev, "<1|0>: enable|disable console log\n"); - goto done; - } - - dbg_data.tty = tty; - dev_info(dev, "tty = %u", dbg_data.tty); - - done: - return count; -} -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); +static const struct file_operations ci_device_fops = { + .open = ci_device_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /** - * show_inters: interrupt status, enable status and historic - * - * Check "device.h" for details + * ci_port_test_show: reads port test mode */ -static ssize_t show_inters(struct device *dev, struct device_attribute *attr, - char *buf) +static int ci_port_test_show(struct seq_file *s, void *data) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); + struct ci13xxx *ci = s->private; unsigned long flags; - u32 intr; - unsigned i, j, n = 0; - - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); - return 0; - } + unsigned mode; spin_lock_irqsave(&ci->lock, flags); - - /*n += scnprintf(buf + n, PAGE_SIZE - n, - "status = %08x\n", hw_read_intr_status(ci)); - n += scnprintf(buf + n, PAGE_SIZE - n, - "enable = %08x\n", hw_read_intr_enable(ci));*/ - - n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", - isr_statistics.test); - n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", - isr_statistics.ui); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", - isr_statistics.uei); - n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", - isr_statistics.pci); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", - isr_statistics.uri); - n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", - isr_statistics.sli); - n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", - isr_statistics.none); - n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", - isr_statistics.hndl.cnt); - - for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { - i &= ISR_MASK; - intr = isr_statistics.hndl.buf[i]; - - if (USBi_UI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); - intr &= ~USBi_UI; - if (USBi_UEI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); - intr &= ~USBi_UEI; - if (USBi_PCI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); - intr &= ~USBi_PCI; - if (USBi_URI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); - intr &= ~USBi_URI; - if (USBi_SLI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); - intr &= ~USBi_SLI; - if (intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); - if (isr_statistics.hndl.buf[i]) - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); - } - + mode = hw_port_test_get(ci); spin_unlock_irqrestore(&ci->lock, flags); - return n; -} - -/** - * store_inters: enable & force or disable an individual interrutps - * (to be used for test purposes only) - * - * Check "device.h" for details - */ -static ssize_t store_inters(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned en, bit; - - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "EINVAL\n"); - goto done; - } + seq_printf(s, "mode = %u\n", mode); - if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { - dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n"); - goto done; - } - - spin_lock_irqsave(&ci->lock, flags); - if (en) { - if (hw_intr_force(ci, bit)) - dev_err(dev, "invalid bit number\n"); - else - isr_statistics.test++; - } else { - if (hw_intr_clear(ci, bit)) - dev_err(dev, "invalid bit number\n"); - } - spin_unlock_irqrestore(&ci->lock, flags); - - done: - return count; + return 0; } -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); /** - * show_port_test: reads port test mode - * - * Check "device.h" for details + * ci_port_test_write: writes port test mode */ -static ssize_t show_port_test(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); + struct seq_file *s = file->private_data; + struct ci13xxx *ci = s->private; unsigned long flags; unsigned mode; + char buf[32]; + int ret; - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "EINVAL\n"); - return 0; - } + if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + if (sscanf(buf, "%u", &mode) != 1) + return -EINVAL; spin_lock_irqsave(&ci->lock, flags); - mode = hw_port_test_get(ci); + ret = hw_port_test_set(ci, mode); spin_unlock_irqrestore(&ci->lock, flags); - return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); + return ret ? ret : count; } -/** - * store_port_test: writes port test mode - * - * Check "device.h" for details - */ -static ssize_t store_port_test(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int ci_port_test_open(struct inode *inode, struct file *file) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &mode) != 1) { - dev_err(ci->dev, "<mode>: set port test mode"); - goto done; - } - - spin_lock_irqsave(&ci->lock, flags); - if (hw_port_test_set(ci, mode)) - dev_err(ci->dev, "invalid mode\n"); - spin_unlock_irqrestore(&ci->lock, flags); - - done: - return count; + return single_open(file, ci_port_test_show, inode->i_private); } -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, - show_port_test, store_port_test); + +static const struct file_operations ci_port_test_fops = { + .open = ci_port_test_open, + .write = ci_port_test_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details + * ci_qheads_show: DMA contents of all queue heads */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, - char *buf) +static int ci_qheads_show(struct seq_file *s, void *data) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); + struct ci13xxx *ci = s->private; unsigned long flags; - unsigned i, j, n = 0; + unsigned i, j; - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); + if (ci->role != CI_ROLE_GADGET) { + seq_printf(s, "not in gadget mode\n"); return 0; } @@ -593,209 +129,173 @@ static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i]; struct ci13xxx_ep *mEpTx = &ci->ci13xxx_ep[i + ci->hw_ep_max/2]; - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: RX=%08X TX=%08X\n", - i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); - for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X %08X\n", j, - *((u32 *)mEpRx->qh.ptr + j), - *((u32 *)mEpTx->qh.ptr + j)); - } + seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n", + i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); + for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) + seq_printf(s, " %04X: %08X %08X\n", j, + *((u32 *)mEpRx->qh.ptr + j), + *((u32 *)mEpTx->qh.ptr + j)); } spin_unlock_irqrestore(&ci->lock, flags); - return n; + return 0; +} + +static int ci_qheads_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_qheads_show, inode->i_private); } -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); + +static const struct file_operations ci_qheads_fops = { + .open = ci_qheads_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /** - * show_registers: dumps all registers - * - * Check "device.h" for details + * ci_requests_show: DMA contents of all requests currently queued (all endpts) */ -#define DUMP_ENTRIES 512 -static ssize_t show_registers(struct device *dev, - struct device_attribute *attr, char *buf) +static int ci_requests_show(struct seq_file *s, void *data) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); + struct ci13xxx *ci = s->private; unsigned long flags; - u32 *dump; - unsigned i, k, n = 0; - - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); - return 0; - } + struct list_head *ptr = NULL; + struct ci13xxx_req *req = NULL; + unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32); - dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); - if (!dump) { - dev_err(ci->dev, "%s: out of memory\n", __func__); + if (ci->role != CI_ROLE_GADGET) { + seq_printf(s, "not in gadget mode\n"); return 0; } spin_lock_irqsave(&ci->lock, flags); - k = hw_register_read(ci, dump, DUMP_ENTRIES); - spin_unlock_irqrestore(&ci->lock, flags); + for (i = 0; i < ci->hw_ep_max; i++) + list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) { + req = list_entry(ptr, struct ci13xxx_req, queue); - for (i = 0; i < k; i++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - "reg[0x%04X] = 0x%08X\n", - i * (unsigned)sizeof(u32), dump[i]); - } - kfree(dump); + seq_printf(s, "EP=%02i: TD=%08X %s\n", + i % (ci->hw_ep_max / 2), (u32)req->dma, + ((i < ci->hw_ep_max/2) ? "RX" : "TX")); + + for (j = 0; j < qsize; j++) + seq_printf(s, " %04X: %08X\n", j, + *((u32 *)req->ptr + j)); + } + spin_unlock_irqrestore(&ci->lock, flags); - return n; + return 0; } -/** - * store_registers: writes value to register address - * - * Check "device.h" for details - */ -static ssize_t store_registers(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int ci_requests_open(struct inode *inode, struct file *file) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long addr, data, flags; + return single_open(file, ci_requests_show, inode->i_private); +} - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); - goto done; - } +static const struct file_operations ci_requests_fops = { + .open = ci_requests_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; - if (sscanf(buf, "%li %li", &addr, &data) != 2) { - dev_err(ci->dev, - "<addr> <data>: write data to register address\n"); - goto done; - } +static int ci_role_show(struct seq_file *s, void *data) +{ + struct ci13xxx *ci = s->private; - spin_lock_irqsave(&ci->lock, flags); - if (hw_register_write(ci, addr, data)) - dev_err(ci->dev, "invalid address range\n"); - spin_unlock_irqrestore(&ci->lock, flags); + seq_printf(s, "%s\n", ci_role(ci)->name); - done: - return count; + return 0; } -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, - show_registers, store_registers); -/** - * show_requests: DMA contents of all requests currently queued (all endpts) - * - * Check "device.h" for details - */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t ci_role_write(struct file *file, const char __user *ubuf, + size_t count, loff_t *ppos) { - struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - struct list_head *ptr = NULL; - struct ci13xxx_req *req = NULL; - unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); - - if (attr == NULL || buf == NULL) { - dev_err(ci->dev, "[%s] EINVAL\n", __func__); - return 0; - } + struct seq_file *s = file->private_data; + struct ci13xxx *ci = s->private; + enum ci_role role; + char buf[8]; + int ret; + + if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) + return -EFAULT; + + for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) + if (ci->roles[role] && + !strncmp(buf, ci->roles[role]->name, + strlen(ci->roles[role]->name))) + break; - spin_lock_irqsave(&ci->lock, flags); - for (i = 0; i < ci->hw_ep_max; i++) - list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) - { - req = list_entry(ptr, struct ci13xxx_req, queue); + if (role == CI_ROLE_END || role == ci->role) + return -EINVAL; - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: TD=%08X %s\n", - i % ci->hw_ep_max/2, (u32)req->dma, - ((i < ci->hw_ep_max/2) ? "RX" : "TX")); + ci_role_stop(ci); + ret = ci_role_start(ci, role); - for (j = 0; j < qSize; j++) - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X\n", j, - *((u32 *)req->ptr + j)); - } - spin_unlock_irqrestore(&ci->lock, flags); + return ret ? ret : count; +} - return n; +static int ci_role_open(struct inode *inode, struct file *file) +{ + return single_open(file, ci_role_show, inode->i_private); } -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); + +static const struct file_operations ci_role_fops = { + .open = ci_role_open, + .write = ci_role_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /** * dbg_create_files: initializes the attribute interface - * @dev: device + * @ci: device * * This function returns an error code */ -int dbg_create_files(struct device *dev) +int dbg_create_files(struct ci13xxx *ci) { - int retval = 0; - - if (dev == NULL) - return -EINVAL; - retval = device_create_file(dev, &dev_attr_device); - if (retval) - goto done; - retval = device_create_file(dev, &dev_attr_driver); - if (retval) - goto rm_device; - retval = device_create_file(dev, &dev_attr_events); - if (retval) - goto rm_driver; - retval = device_create_file(dev, &dev_attr_inters); - if (retval) - goto rm_events; - retval = device_create_file(dev, &dev_attr_port_test); - if (retval) - goto rm_inters; - retval = device_create_file(dev, &dev_attr_qheads); - if (retval) - goto rm_port_test; - retval = device_create_file(dev, &dev_attr_registers); - if (retval) - goto rm_qheads; - retval = device_create_file(dev, &dev_attr_requests); - if (retval) - goto rm_registers; - return 0; - - rm_registers: - device_remove_file(dev, &dev_attr_registers); - rm_qheads: - device_remove_file(dev, &dev_attr_qheads); - rm_port_test: - device_remove_file(dev, &dev_attr_port_test); - rm_inters: - device_remove_file(dev, &dev_attr_inters); - rm_events: - device_remove_file(dev, &dev_attr_events); - rm_driver: - device_remove_file(dev, &dev_attr_driver); - rm_device: - device_remove_file(dev, &dev_attr_device); - done: - return retval; + struct dentry *dent; + + ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL); + if (!ci->debugfs) + return -ENOMEM; + + dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, + &ci_device_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, + ci, &ci_port_test_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci, + &ci_qheads_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci, + &ci_requests_fops); + if (!dent) + goto err; + + dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, + &ci_role_fops); + if (dent) + return 0; +err: + debugfs_remove_recursive(ci->debugfs); + return -ENOMEM; } /** * dbg_remove_files: destroys the attribute interface - * @dev: device - * - * This function returns an error code + * @ci: device */ -int dbg_remove_files(struct device *dev) +void dbg_remove_files(struct ci13xxx *ci) { - if (dev == NULL) - return -EINVAL; - device_remove_file(dev, &dev_attr_requests); - device_remove_file(dev, &dev_attr_registers); - device_remove_file(dev, &dev_attr_qheads); - device_remove_file(dev, &dev_attr_port_test); - device_remove_file(dev, &dev_attr_inters); - device_remove_file(dev, &dev_attr_events); - device_remove_file(dev, &dev_attr_driver); - device_remove_file(dev, &dev_attr_device); - return 0; + debugfs_remove_recursive(ci->debugfs); } diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h index 80d96865775c..7ca6ca0a24a5 100644 --- a/drivers/usb/chipidea/debug.h +++ b/drivers/usb/chipidea/debug.h @@ -14,42 +14,16 @@ #define __DRIVERS_USB_CHIPIDEA_DEBUG_H #ifdef CONFIG_USB_CHIPIDEA_DEBUG -void dbg_interrupt(u32 intmask); -void dbg_done(u8 addr, const u32 token, int status); -void dbg_event(u8 addr, const char *name, int status); -void dbg_queue(u8 addr, const struct usb_request *req, int status); -void dbg_setup(u8 addr, const struct usb_ctrlrequest *req); -int dbg_create_files(struct device *dev); -int dbg_remove_files(struct device *dev); +int dbg_create_files(struct ci13xxx *ci); +void dbg_remove_files(struct ci13xxx *ci); #else -static inline void dbg_interrupt(u32 intmask) -{ -} - -static inline void dbg_done(u8 addr, const u32 token, int status) -{ -} - -static inline void dbg_event(u8 addr, const char *name, int status) -{ -} - -static inline void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ -} - -static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ -} - -static inline int dbg_create_files(struct device *dev) +static inline int dbg_create_files(struct ci13xxx *ci) { return 0; } -static inline int dbg_remove_files(struct device *dev) +static inline void dbg_remove_files(struct ci13xxx *ci) { - return 0; } #endif diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index f64fbea1cf20..519ead2443c5 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -13,14 +13,8 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/dmapool.h> -#include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> +#include <linux/irqreturn.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/pm_runtime.h> @@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type) if (dir) { mask = ENDPTCTRL_TXT; /* type */ - data = type << ffs_nr(mask); + data = type << __ffs(mask); mask |= ENDPTCTRL_TXS; /* unstall */ mask |= ENDPTCTRL_TXR; /* reset data toggle */ @@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type) data |= ENDPTCTRL_TXE; } else { mask = ENDPTCTRL_RXT; /* type */ - data = type << ffs_nr(mask); + data = type << __ffs(mask); mask |= ENDPTCTRL_RXS; /* unstall */ mask |= ENDPTCTRL_RXR; /* reset data toggle */ @@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci) return reg; } -static void hw_enable_vbus_intr(struct ci13xxx *ci) -{ - hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS); - hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE); - queue_work(ci->wq, &ci->vbus_work); -} - -static void hw_disable_vbus_intr(struct ci13xxx *ci) -{ - hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0); -} - /** * hw_test_and_clear_setup_guard: test & clear setup guard (execute without * interruption) @@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci) static void hw_usb_set_address(struct ci13xxx *ci, u8 value) { hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR, - value << ffs_nr(DEVICEADDR_USBADR)); + value << __ffs(DEVICEADDR_USBADR)); } /** @@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci) return 0; } -static void vbus_work(struct work_struct *work) -{ - struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work); - - if (hw_read(ci, OP_OTGSC, OTGSC_AVV)) - usb_gadget_vbus_connect(&ci->gadget); - else - usb_gadget_vbus_disconnect(&ci->gadget); -} - /****************************************************************************** * UTIL block *****************************************************************************/ @@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) return -ENOMEM; memset(mReq->zptr, 0, sizeof(*mReq->zptr)); - mReq->zptr->next = TD_TERMINATE; - mReq->zptr->token = TD_STATUS_ACTIVE; + mReq->zptr->next = cpu_to_le32(TD_TERMINATE); + mReq->zptr->token = cpu_to_le32(TD_STATUS_ACTIVE); if (!mReq->req.no_interrupt) - mReq->zptr->token |= TD_IOC; + mReq->zptr->token |= cpu_to_le32(TD_IOC); } ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir); if (ret) @@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) * TODO - handle requests which spawns into several TDs */ memset(mReq->ptr, 0, sizeof(*mReq->ptr)); - mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); - mReq->ptr->token &= TD_TOTAL_BYTES; - mReq->ptr->token |= TD_STATUS_ACTIVE; + mReq->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES)); + mReq->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES); + mReq->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE); if (mReq->zptr) { - mReq->ptr->next = mReq->zdma; + mReq->ptr->next = cpu_to_le32(mReq->zdma); } else { - mReq->ptr->next = TD_TERMINATE; + mReq->ptr->next = cpu_to_le32(TD_TERMINATE); if (!mReq->req.no_interrupt) - mReq->ptr->token |= TD_IOC; + mReq->ptr->token |= cpu_to_le32(TD_IOC); + } + mReq->ptr->page[0] = cpu_to_le32(mReq->req.dma); + for (i = 1; i < TD_PAGE_COUNT; i++) { + u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE; + page &= ~TD_RESERVED_MASK; + mReq->ptr->page[i] = cpu_to_le32(page); } - mReq->ptr->page[0] = mReq->req.dma; - for (i = 1; i < 5; i++) - mReq->ptr->page[i] = - (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; + + wmb(); if (!list_empty(&mEp->qh.queue)) { struct ci13xxx_req *mReqPrev; int n = hw_ep_bit(mEp->num, mEp->dir); int tmp_stat; + u32 next = mReq->dma & TD_ADDR_MASK; mReqPrev = list_entry(mEp->qh.queue.prev, struct ci13xxx_req, queue); if (mReqPrev->zptr) - mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; + mReqPrev->zptr->next = cpu_to_le32(next); else - mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; + mReqPrev->ptr->next = cpu_to_le32(next); wmb(); if (hw_read(ci, OP_ENDPTPRIME, BIT(n))) goto done; @@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) } /* QH configuration */ - mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ - mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ - mEp->qh.ptr->cap |= QH_ZLT; + mEp->qh.ptr->td.next = cpu_to_le32(mReq->dma); /* TERMINATE = 0 */ + mEp->qh.ptr->td.token &= + cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); wmb(); /* synchronize before ep prime */ @@ -506,14 +483,16 @@ done: */ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) { + u32 tmptoken = le32_to_cpu(mReq->ptr->token); + if (mReq->req.status != -EALREADY) return -EINVAL; - if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) + if ((TD_STATUS_ACTIVE & tmptoken) != 0) return -EBUSY; if (mReq->zptr) { - if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) + if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0) return -EBUSY; dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); mReq->zptr = NULL; @@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir); - mReq->req.status = mReq->ptr->token & TD_STATUS; + mReq->req.status = tmptoken & TD_STATUS; if ((TD_STATUS_HALTED & mReq->req.status) != 0) mReq->req.status = -1; else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) @@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) mReq->req.status = -1; - mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; - mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); + mReq->req.actual = tmptoken & TD_TOTAL_BYTES; + mReq->req.actual >>= __ffs(TD_TOTAL_BYTES); mReq->req.actual = mReq->req.length - mReq->req.actual; mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; @@ -561,6 +540,12 @@ __acquires(mEp->lock) struct ci13xxx_req *mReq = \ list_entry(mEp->qh.queue.next, struct ci13xxx_req, queue); + + if (mReq->zptr) { + dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); + mReq->zptr = NULL; + } + list_del_init(&mReq->queue); mReq->req.status = -ESHUTDOWN; @@ -629,8 +614,6 @@ __acquires(ci->lock) { int retval; - dbg_event(0xFF, "BUS RST", 0); - spin_unlock(&ci->lock); retval = _gadget_stop_activity(&ci->gadget); if (retval) @@ -668,6 +651,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) } /** + * _ep_queue: queues (submits) an I/O request to an endpoint + * + * Caller must hold lock + */ +static int _ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t __maybe_unused gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + struct ci13xxx *ci = mEp->ci; + int retval = 0; + + if (ep == NULL || req == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (req->length) + mEp = (ci->ep0_dir == RX) ? + ci->ep0out : ci->ep0in; + if (!list_empty(&mEp->qh.queue)) { + _ep_nuke(mEp); + retval = -EOVERFLOW; + dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", + _usb_addr(mEp)); + } + } + + /* first nuke then test link, e.g. previous status has not sent */ + if (!list_empty(&mReq->queue)) { + dev_err(mEp->ci->dev, "request already in queue\n"); + return -EBUSY; + } + + if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) { + dev_err(mEp->ci->dev, "request bigger than one td\n"); + return -EMSGSIZE; + } + + /* push request */ + mReq->req.status = -EINPROGRESS; + mReq->req.actual = 0; + + retval = _hardware_enqueue(mEp, mReq); + + if (retval == -EALREADY) + retval = 0; + if (!retval) + list_add_tail(&mReq->queue, &mEp->qh.queue); + + return retval; +} + +/** * isr_get_status_response: get_status request response * @ci: ci struct * @setup: setup request packet @@ -714,9 +750,7 @@ __acquires(mEp->lock) } /* else do nothing; reserved for future use */ - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, req, gfp_flags); - spin_lock(mEp->lock); + retval = _ep_queue(&mEp->ep, req, gfp_flags); if (retval) goto err_free_buf; @@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) * This function returns an error code */ static int isr_setup_status_phase(struct ci13xxx *ci) -__releases(mEp->lock) -__acquires(mEp->lock) { int retval; struct ci13xxx_ep *mEp; @@ -773,9 +805,7 @@ __acquires(mEp->lock) ci->status->context = ci; ci->status->complete = isr_setup_status_complete; - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC); - spin_lock(mEp->lock); + retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC); return retval; } @@ -801,7 +831,6 @@ __acquires(mEp->lock) if (retval < 0) break; list_del_init(&mReq->queue); - dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); if (mReq->req.complete != NULL) { spin_unlock(mEp->lock); if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && @@ -814,8 +843,6 @@ __acquires(mEp->lock) if (retval == -EBUSY) retval = 0; - if (retval < 0) - dbg_event(_usb_addr(mEp), "DONE", retval); return retval; } @@ -847,8 +874,6 @@ __acquires(ci->lock) if (err > 0) /* needs status phase */ err = isr_setup_status_phase(ci); if (err < 0) { - dbg_event(_usb_addr(mEp), - "ERROR", err); spin_unlock(&ci->lock); if (usb_ep_set_halt(&mEp->ep)) dev_err(ci->dev, @@ -884,8 +909,6 @@ __acquires(ci->lock) ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; - dbg_setup(_usb_addr(mEp), &req); - switch (req.bRequest) { case USB_REQ_CLEAR_FEATURE: if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && @@ -997,8 +1020,6 @@ delegate: } if (err < 0) { - dbg_event(_usb_addr(mEp), "ERROR", err); - spin_unlock(&ci->lock); if (usb_ep_set_halt(&mEp->ep)) dev_err(ci->dev, "error: ep_set_halt\n"); @@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep, struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); int retval = 0; unsigned long flags; + u32 cap = 0; if (ep == NULL || desc == NULL) return -EINVAL; @@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep, mEp->ep.maxpacket = usb_endpoint_maxp(desc); - dbg_event(_usb_addr(mEp), "ENABLE", 0); - - mEp->qh.ptr->cap = 0; - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->qh.ptr->cap |= QH_IOS; - else if (mEp->type == USB_ENDPOINT_XFER_ISOC) - mEp->qh.ptr->cap &= ~QH_MULT; - else - mEp->qh.ptr->cap &= ~QH_ZLT; + cap |= QH_IOS; + if (mEp->num) + cap |= QH_ZLT; + cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; + + mEp->qh.ptr->cap = cpu_to_le32(cap); - mEp->qh.ptr->cap |= - (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; - mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ + mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE); /* needed? */ /* * Enable endpoints in the HW other than ep0 as ep0 @@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep) direction = mEp->dir; do { - dbg_event(_usb_addr(mEp), "DISABLE", 0); - retval |= _ep_nuke(mEp); retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir); @@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) } } - dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); - return (mReq == NULL) ? NULL : &mReq->req; } @@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req) dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); kfree(mReq); - dbg_event(_usb_addr(mEp), "FREE", 0); - spin_unlock_irqrestore(mEp->lock, flags); } @@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t __maybe_unused gfp_flags) { struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - struct ci13xxx *ci = mEp->ci; int retval = 0; unsigned long flags; @@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req, return -EINVAL; spin_lock_irqsave(mEp->lock, flags); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (req->length) - mEp = (ci->ep0_dir == RX) ? - ci->ep0out : ci->ep0in; - if (!list_empty(&mEp->qh.queue)) { - _ep_nuke(mEp); - retval = -EOVERFLOW; - dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", - _usb_addr(mEp)); - } - } - - /* first nuke then test link, e.g. previous status has not sent */ - if (!list_empty(&mReq->queue)) { - retval = -EBUSY; - dev_err(mEp->ci->dev, "request already in queue\n"); - goto done; - } - - if (req->length > 4 * CI13XXX_PAGE_SIZE) { - req->length = 4 * CI13XXX_PAGE_SIZE; - retval = -EMSGSIZE; - dev_warn(mEp->ci->dev, "request length truncated\n"); - } - - dbg_queue(_usb_addr(mEp), req, retval); - - /* push request */ - mReq->req.status = -EINPROGRESS; - mReq->req.actual = 0; - - retval = _hardware_enqueue(mEp, mReq); - - if (retval == -EALREADY) { - dbg_event(_usb_addr(mEp), "QUEUE", retval); - retval = 0; - } - if (!retval) - list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: + retval = _ep_queue(ep, req, gfp_flags); spin_unlock_irqrestore(mEp->lock, flags); return retval; } @@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) spin_lock_irqsave(mEp->lock, flags); - dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - hw_ep_flush(mEp->ci, mEp->num, mEp->dir); /* pop request */ @@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value) direction = mEp->dir; do { - dbg_event(_usb_addr(mEp), "HALT", value); retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value); if (!value) @@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep) return -EINVAL; spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "WEDGE", 0); mEp->wedge = 1; - spin_unlock_irqrestore(mEp->lock, flags); return usb_ep_set_halt(ep); @@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep) spin_lock_irqsave(mEp->lock, flags); - dbg_event(_usb_addr(mEp), "FFLUSH", 0); hw_ep_flush(mEp->ci, mEp->num, mEp->dir); spin_unlock_irqrestore(mEp->lock, flags); @@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) if (is_active) { pm_runtime_get_sync(&_gadget->dev); hw_device_reset(ci, USBMODE_CM_DC); - hw_enable_vbus_intr(ci); hw_device_state(ci, ci->ep0out->qh.dma); } else { hw_device_state(ci, 0); @@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget, pm_runtime_get_sync(&ci->gadget.dev); if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) { if (ci->vbus_active) { - if (ci->platdata->flags & CI13XXX_REGS_SHARED) { + if (ci->platdata->flags & CI13XXX_REGS_SHARED) hw_device_reset(ci, USBMODE_CM_DC); - hw_enable_vbus_intr(ci); - } } else { pm_runtime_put_sync(&ci->gadget.dev); goto done; @@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci) } } intr = hw_test_and_clear_intr_active(ci); - dbg_interrupt(intr); if (intr) { /* order defines priority - do NOT change it */ @@ -1676,29 +1633,12 @@ static irqreturn_t udc_irq(struct ci13xxx *ci) } else { retval = IRQ_NONE; } - - intr = hw_read(ci, OP_OTGSC, ~0); - hw_write(ci, OP_OTGSC, ~0, intr); - - if (intr & (OTGSC_AVVIE & OTGSC_AVVIS)) - queue_work(ci->wq, &ci->vbus_work); - spin_unlock(&ci->lock); return retval; } /** - * udc_release: driver release function - * @dev: device - * - * Currently does nothing - */ -static void udc_release(struct device *dev) -{ -} - -/** * udc_start: initialize gadget role * @ci: chipidea controller */ @@ -1717,12 +1657,6 @@ static int udc_start(struct ci13xxx *ci) INIT_LIST_HEAD(&ci->gadget.ep_list); - dev_set_name(&ci->gadget.dev, "gadget"); - ci->gadget.dev.dma_mask = dev->dma_mask; - ci->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; - ci->gadget.dev.parent = dev; - ci->gadget.dev.release = udc_release; - /* alloc resources */ ci->qh_pool = dma_pool_create("ci13xxx_qh", dev, sizeof(struct ci13xxx_qh), @@ -1758,24 +1692,13 @@ static int udc_start(struct ci13xxx *ci) retval = hw_device_reset(ci, USBMODE_CM_DC); if (retval) goto put_transceiver; - hw_enable_vbus_intr(ci); - } - - retval = device_register(&ci->gadget.dev); - if (retval) { - put_device(&ci->gadget.dev); - goto put_transceiver; } - retval = dbg_create_files(ci->dev); - if (retval) - goto unreg_device; - if (!IS_ERR_OR_NULL(ci->transceiver)) { retval = otg_set_peripheral(ci->transceiver->otg, &ci->gadget); if (retval) - goto remove_dbg; + goto put_transceiver; } retval = usb_add_gadget_udc(dev, &ci->gadget); @@ -1795,10 +1718,6 @@ remove_trans: } dev_err(dev, "error = %i\n", retval); -remove_dbg: - dbg_remove_files(ci->dev); -unreg_device: - device_unregister(&ci->gadget.dev); put_transceiver: if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy) usb_put_phy(ci->transceiver); @@ -1821,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci) if (ci == NULL) return; - hw_disable_vbus_intr(ci); - cancel_work_sync(&ci->vbus_work); - usb_del_gadget_udc(&ci->gadget); destroy_eps(ci); @@ -1836,8 +1752,6 @@ static void udc_stop(struct ci13xxx *ci) if (ci->global_phy) usb_put_phy(ci->transceiver); } - dbg_remove_files(ci->dev); - device_unregister(&ci->gadget.dev); /* my kobject is dynamic, I swear! */ memset(&ci->gadget, 0, sizeof(ci->gadget)); } @@ -1864,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci) rdrv->irq = udc_irq; rdrv->name = "gadget"; ci->roles[CI_ROLE_GADGET] = rdrv; - INIT_WORK(&ci->vbus_work, vbus_work); return 0; } diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h index 4ff2384d7ca8..d12e8b59b110 100644 --- a/drivers/usb/chipidea/udc.h +++ b/drivers/usb/chipidea/udc.h @@ -40,7 +40,7 @@ struct ci13xxx_td { #define TD_CURR_OFFSET (0x0FFFUL << 0) #define TD_FRAME_NUM (0x07FFUL << 0) #define TD_RESERVED_MASK (0x0FFFUL << 0) -} __attribute__ ((packed)); +} __attribute__ ((packed, aligned(4))); /* DMA layout of queue heads */ struct ci13xxx_qh { @@ -57,7 +57,7 @@ struct ci13xxx_qh { /* 9 */ u32 RESERVED; struct usb_ctrlrequest setup; -} __attribute__ ((packed)); +} __attribute__ ((packed, aligned(4))); /** * struct ci13xxx_req - usb request representation diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c new file mode 100644 index 000000000000..714a6bd810ed --- /dev/null +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -0,0 +1,261 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include "ci13xxx_imx.h" + +#define USB_DEV_MAX 4 + +#define MX25_USB_PHY_CTRL_OFFSET 0x08 +#define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23) + +#define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08 +#define MX53_USB_UH2_CTRL_OFFSET 0x14 +#define MX53_USB_UH3_CTRL_OFFSET 0x18 +#define MX53_BM_OVER_CUR_DIS_H1 BIT(5) +#define MX53_BM_OVER_CUR_DIS_OTG BIT(8) +#define MX53_BM_OVER_CUR_DIS_UHx BIT(30) + +#define MX6_BM_OVER_CUR_DIS BIT(7) + +struct imx_usbmisc { + void __iomem *base; + spinlock_t lock; + struct clk *clk; + struct usbmisc_usb_device usbdev[USB_DEV_MAX]; + const struct usbmisc_ops *ops; +}; + +static struct imx_usbmisc *usbmisc; + +static struct usbmisc_usb_device *get_usbdev(struct device *dev) +{ + int i, ret; + + for (i = 0; i < USB_DEV_MAX; i++) { + if (usbmisc->usbdev[i].dev == dev) + return &usbmisc->usbdev[i]; + else if (!usbmisc->usbdev[i].dev) + break; + } + + if (i >= USB_DEV_MAX) + return ERR_PTR(-EBUSY); + + ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); + if (ret) + return ERR_PTR(ret); + + return &usbmisc->usbdev[i]; +} + +static int usbmisc_imx25_post(struct device *dev) +{ + struct usbmisc_usb_device *usbdev; + void __iomem *reg; + unsigned long flags; + u32 val; + + usbdev = get_usbdev(dev); + if (IS_ERR(usbdev)) + return PTR_ERR(usbdev); + + reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; + + if (usbdev->evdo) { + spin_lock_irqsave(&usbmisc->lock, flags); + val = readl(reg); + writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); + spin_unlock_irqrestore(&usbmisc->lock, flags); + usleep_range(5000, 10000); /* needed to stabilize voltage */ + } + + return 0; +} + +static int usbmisc_imx53_init(struct device *dev) +{ + struct usbmisc_usb_device *usbdev; + void __iomem *reg = NULL; + unsigned long flags; + u32 val = 0; + + usbdev = get_usbdev(dev); + if (IS_ERR(usbdev)) + return PTR_ERR(usbdev); + + if (usbdev->disable_oc) { + spin_lock_irqsave(&usbmisc->lock, flags); + switch (usbdev->index) { + case 0: + reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; + break; + case 1: + reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; + break; + case 2: + reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + break; + case 3: + reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + break; + } + if (reg && val) + writel(val, reg); + spin_unlock_irqrestore(&usbmisc->lock, flags); + } + + return 0; +} + +static int usbmisc_imx6q_init(struct device *dev) +{ + + struct usbmisc_usb_device *usbdev; + unsigned long flags; + u32 reg; + + usbdev = get_usbdev(dev); + if (IS_ERR(usbdev)) + return PTR_ERR(usbdev); + + if (usbdev->disable_oc) { + spin_lock_irqsave(&usbmisc->lock, flags); + reg = readl(usbmisc->base + usbdev->index * 4); + writel(reg | MX6_BM_OVER_CUR_DIS, + usbmisc->base + usbdev->index * 4); + spin_unlock_irqrestore(&usbmisc->lock, flags); + } + + return 0; +} + +static const struct usbmisc_ops imx25_usbmisc_ops = { + .post = usbmisc_imx25_post, +}; + +static const struct usbmisc_ops imx53_usbmisc_ops = { + .init = usbmisc_imx53_init, +}; + +static const struct usbmisc_ops imx6q_usbmisc_ops = { + .init = usbmisc_imx6q_init, +}; + +static const struct of_device_id usbmisc_imx_dt_ids[] = { + { + .compatible = "fsl,imx25-usbmisc", + .data = &imx25_usbmisc_ops, + }, + { + .compatible = "fsl,imx53-usbmisc", + .data = &imx53_usbmisc_ops, + }, + { + .compatible = "fsl,imx6q-usbmisc", + .data = &imx6q_usbmisc_ops, + }, + { /* sentinel */ } +}; + +static int usbmisc_imx_probe(struct platform_device *pdev) +{ + struct resource *res; + struct imx_usbmisc *data; + int ret; + struct of_device_id *tmp_dev; + + if (usbmisc) + return -EBUSY; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&data->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->clk)) { + dev_err(&pdev->dev, + "failed to get clock, err=%ld\n", PTR_ERR(data->clk)); + return PTR_ERR(data->clk); + } + + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed, err=%d\n", ret); + return ret; + } + + tmp_dev = (struct of_device_id *) + of_match_device(usbmisc_imx_dt_ids, &pdev->dev); + data->ops = (const struct usbmisc_ops *)tmp_dev->data; + usbmisc = data; + ret = usbmisc_set_ops(data->ops); + if (ret) { + usbmisc = NULL; + clk_disable_unprepare(data->clk); + return ret; + } + + return 0; +} + +static int usbmisc_imx_remove(struct platform_device *pdev) +{ + usbmisc_unset_ops(usbmisc->ops); + clk_disable_unprepare(usbmisc->clk); + usbmisc = NULL; + return 0; +} + +static struct platform_driver usbmisc_imx_driver = { + .probe = usbmisc_imx_probe, + .remove = usbmisc_imx_remove, + .driver = { + .name = "usbmisc_imx", + .owner = THIS_MODULE, + .of_match_table = usbmisc_imx_dt_ids, + }, +}; + +int usbmisc_imx_drv_init(void) +{ + return platform_driver_register(&usbmisc_imx_driver); +} +subsys_initcall(usbmisc_imx_drv_init); + +void usbmisc_imx_drv_exit(void) +{ + platform_driver_unregister(&usbmisc_imx_driver); +} +module_exit(usbmisc_imx_drv_exit); + +MODULE_ALIAS("platform:usbmisc-imx"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("driver for imx usb non-core registers"); +MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c deleted file mode 100644 index a1bce391e825..000000000000 --- a/drivers/usb/chipidea/usbmisc_imx6q.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2012 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> - -#include "ci13xxx_imx.h" - -#define USB_DEV_MAX 4 - -#define BM_OVER_CUR_DIS BIT(7) - -struct imx6q_usbmisc { - void __iomem *base; - spinlock_t lock; - struct clk *clk; - struct usbmisc_usb_device usbdev[USB_DEV_MAX]; -}; - -static struct imx6q_usbmisc *usbmisc; - -static struct usbmisc_usb_device *get_usbdev(struct device *dev) -{ - int i, ret; - - for (i = 0; i < USB_DEV_MAX; i++) { - if (usbmisc->usbdev[i].dev == dev) - return &usbmisc->usbdev[i]; - else if (!usbmisc->usbdev[i].dev) - break; - } - - if (i >= USB_DEV_MAX) - return ERR_PTR(-EBUSY); - - ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); - if (ret) - return ERR_PTR(ret); - - return &usbmisc->usbdev[i]; -} - -static int usbmisc_imx6q_init(struct device *dev) -{ - - struct usbmisc_usb_device *usbdev; - unsigned long flags; - u32 reg; - - usbdev = get_usbdev(dev); - if (IS_ERR(usbdev)) - return PTR_ERR(usbdev); - - if (usbdev->disable_oc) { - spin_lock_irqsave(&usbmisc->lock, flags); - reg = readl(usbmisc->base + usbdev->index * 4); - writel(reg | BM_OVER_CUR_DIS, - usbmisc->base + usbdev->index * 4); - spin_unlock_irqrestore(&usbmisc->lock, flags); - } - - return 0; -} - -static const struct usbmisc_ops imx6q_usbmisc_ops = { - .init = usbmisc_imx6q_init, -}; - -static const struct of_device_id usbmisc_imx6q_dt_ids[] = { - { .compatible = "fsl,imx6q-usbmisc"}, - { /* sentinel */ } -}; - -static int usbmisc_imx6q_probe(struct platform_device *pdev) -{ - struct resource *res; - struct imx6q_usbmisc *data; - int ret; - - if (usbmisc) - return -EBUSY; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_init(&data->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(data->base)) - return PTR_ERR(data->base); - - data->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(data->clk)) { - dev_err(&pdev->dev, - "failed to get clock, err=%ld\n", PTR_ERR(data->clk)); - return PTR_ERR(data->clk); - } - - ret = clk_prepare_enable(data->clk); - if (ret) { - dev_err(&pdev->dev, - "clk_prepare_enable failed, err=%d\n", ret); - return ret; - } - - ret = usbmisc_set_ops(&imx6q_usbmisc_ops); - if (ret) { - clk_disable_unprepare(data->clk); - return ret; - } - - usbmisc = data; - - return 0; -} - -static int usbmisc_imx6q_remove(struct platform_device *pdev) -{ - usbmisc_unset_ops(&imx6q_usbmisc_ops); - clk_disable_unprepare(usbmisc->clk); - return 0; -} - -static struct platform_driver usbmisc_imx6q_driver = { - .probe = usbmisc_imx6q_probe, - .remove = usbmisc_imx6q_remove, - .driver = { - .name = "usbmisc_imx6q", - .owner = THIS_MODULE, - .of_match_table = usbmisc_imx6q_dt_ids, - }, -}; - -int __init usbmisc_imx6q_drv_init(void) -{ - return platform_driver_register(&usbmisc_imx6q_driver); -} -subsys_initcall(usbmisc_imx6q_drv_init); - -void __exit usbmisc_imx6q_drv_exit(void) -{ - platform_driver_unregister(&usbmisc_imx6q_driver); -} -module_exit(usbmisc_imx6q_drv_exit); - -MODULE_ALIAS("platform:usbmisc-imx6q"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("driver for imx6q usb non-core registers"); -MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig index 316aac8e4ca1..bb8b73682a70 100644 --- a/drivers/usb/class/Kconfig +++ b/drivers/usb/class/Kconfig @@ -2,11 +2,10 @@ # USB Class driver configuration # comment "USB Device Class drivers" - depends on USB config USB_ACM tristate "USB Modem (CDC ACM) support" - depends on USB && TTY + depends on TTY ---help--- This driver supports USB modems and ISDN adapters which support the Communication Device Class Abstract Control Model interface. @@ -21,7 +20,6 @@ config USB_ACM config USB_PRINTER tristate "USB Printer support" - depends on USB help Say Y here if you want to connect a USB printer to your computer's USB port. @@ -31,7 +29,6 @@ config USB_PRINTER config USB_WDM tristate "USB Wireless Device Management support" - depends on USB ---help--- This driver supports the WMC Device Management functionality of cell phones compliant to the CDC WMC specification. You can use @@ -42,7 +39,6 @@ config USB_WDM config USB_TMC tristate "USB Test and Measurement Class support" - depends on USB help Say Y here if you want to connect a USB device that follows the USB.org specification for USB Test and Measurement devices diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index c77f7ae48f1c..171d7a9df3ae 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -828,14 +828,6 @@ static int acm_tty_ioctl(struct tty_struct *tty, return rv; } -static const __u32 acm_tty_speed[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, - 1200, 1800, 2400, 4800, 9600, 19200, 38400, - 57600, 115200, 230400, 460800, 500000, 576000, - 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -}; - static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 122d056d96d5..8a230f0ef77c 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -13,6 +13,7 @@ */ #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/ioctl.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/mutex.h> @@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file) return 0; } +static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct wdm_device *desc = file->private_data; + int rv = 0; + + switch (cmd) { + case IOCTL_WDM_MAX_COMMAND: + if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand))) + rv = -EFAULT; + break; + default: + rv = -ENOTTY; + } + return rv; +} + static const struct file_operations wdm_fops = { .owner = THIS_MODULE, .read = wdm_read, @@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = { .flush = wdm_flush, .release = wdm_release, .poll = wdm_poll, + .unlocked_ioctl = wdm_ioctl, + .compat_ioctl = wdm_ioctl, .llseek = noop_llseek, }; diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 70d69d06054f..4c5506ae5e45 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -718,50 +718,32 @@ exit: static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) { - u8 *buffer; int rv; - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - rv = usb_clear_halt(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out)); if (rv < 0) { dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", rv); - goto exit; + return rv; } - rv = 0; - -exit: - kfree(buffer); - return rv; + return 0; } static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) { - u8 *buffer; int rv; - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - rv = usb_clear_halt(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); if (rv < 0) { dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", rv); - goto exit; + return rv; } - rv = 0; - -exit: - kfree(buffer); - return rv; + return 0; } static int get_capabilities(struct usbtmc_device_data *data) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f70c1a1694ad..8772b3659296 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -3,7 +3,6 @@ # config USB_DEBUG bool "USB verbose debug messages" - depends on USB help Say Y here if you want the USB core & hub drivers to produce a bunch of debug messages to the system log. Select this if you are having a @@ -11,7 +10,6 @@ config USB_DEBUG config USB_ANNOUNCE_NEW_DEVICES bool "USB announce new devices" - depends on USB default N help Say Y here if you want the USB core to always announce the @@ -25,11 +23,24 @@ config USB_ANNOUNCE_NEW_DEVICES log, or have any doubts about this, say N here. comment "Miscellaneous USB options" - depends on USB + +config USB_DEFAULT_PERSIST + bool "Enable USB persist by default" + default y + help + Say N here if you don't want USB power session persistance + enabled by default. If you say N it will make suspended USB + devices that lose power get reenumerated as if they had been + unplugged, causing any mounted filesystems to be lost. The + persist feature can still be enabled for individual devices + through the power/persist sysfs node. See + Documentation/usb/persist.txt for more info. + + If you have any questions about this, say Y here, only say N + if you know exactly what you are doing. config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation" - depends on USB help If you say Y here, the USB subsystem will use dynamic minor allocation for any device that uses the USB major number. @@ -38,25 +49,8 @@ config USB_DYNAMIC_MINORS If you are unsure about this, say N here. -config USB_SUSPEND - bool "USB runtime power management (autosuspend) and wakeup" - depends on USB && PM_RUNTIME - help - If you say Y here, you can use driver calls or the sysfs - "power/control" file to enable or disable autosuspend for - individual USB peripherals (see - Documentation/usb/power-management.txt for more details). - - Also, USB "remote wakeup" signaling is supported, whereby some - USB devices (like keyboards and network adapters) can wake up - their parent hub. That wakeup cascades up the USB tree, and - could wake the system from states like suspend-to-RAM. - - If you are unsure about this, say N here. - config USB_OTG bool "OTG support" - depends on USB depends on USB_SUSPEND default n help diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8823e98989fe..caefc800f298 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -739,6 +739,8 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, index &= 0xff; switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: + if ((index & ~USB_DIR_IN) == 0) + return 0; ret = findintfep(ps->dev, index); if (ret >= 0) ret = checkintf(ps, ret); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d938b2b99e31..6eab440e1542 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1196,9 +1196,14 @@ done: * * This is the central routine for suspending USB devices. It calls the * suspend methods for all the interface drivers in @udev and then calls - * the suspend method for @udev itself. If an error occurs at any stage, - * all the interfaces which were suspended are resumed so that they remain - * in the same state as the device. + * the suspend method for @udev itself. When the routine is called in + * autosuspend, if an error occurs at any stage, all the interfaces + * which were suspended are resumed so that they remain in the same + * state as the device, but when called from system sleep, all error + * from suspend methods of interfaces and the non-root-hub device itself + * are simply ignored, so all suspended interfaces are only resumed + * to the device's state when @udev is root-hub and its suspend method + * returns failure. * * Autosuspend requests originating from a child device or an interface * driver may be made without the protection of @udev's device lock, but @@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { - msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); - while (++i < n) { - intf = udev->actconfig->interface[i]; - usb_resume_interface(udev, intf, msg, 0); + if (udev->actconfig) { + msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); + while (++i < n) { + intf = udev->actconfig->interface[i]; + usb_resume_interface(udev, intf, msg, 0); + } } /* If the suspend succeeded then prevent any more URB submissions @@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg) #endif /* CONFIG_PM */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME /** * usb_enable_autosuspend - allow a USB device to be autosuspended @@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) return ret; } -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */ struct bus_type usb_bus_type = { .name = "usb", diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 271e761f563e..acbfeb0a0119 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev) c = usb_choose_configuration(udev); if (c >= 0) { err = usb_set_configuration(udev, c); - if (err) { + if (err && err != -ENODEV) { dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); /* This need not be fatal. The user can try to diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 2b487d4797bd..caeb8d6d39fb 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -37,119 +37,123 @@ /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ -#ifdef CONFIG_PM_SLEEP - -/* Coordinate handoffs between EHCI and companion controllers - * during system resume +/* + * Coordinate handoffs between EHCI and companion controllers + * during EHCI probing and system resume. */ -static DEFINE_MUTEX(companions_mutex); +static DECLARE_RWSEM(companions_rwsem); #define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI #define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI #define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI -enum companion_action { - SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS -}; +static inline int is_ohci_or_uhci(struct pci_dev *pdev) +{ + return pdev->class == CL_OHCI || pdev->class == CL_UHCI; +} + +typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd); -static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, - enum companion_action action) +/* Iterate over PCI devices in the same slot as pdev and call fn for each */ +static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, + companion_fn fn) { struct pci_dev *companion; struct usb_hcd *companion_hcd; unsigned int slot = PCI_SLOT(pdev->devfn); - /* Iterate through other PCI functions in the same slot. - * If pdev is OHCI or UHCI then we are looking for EHCI, and - * vice versa. + /* + * Iterate through other PCI functions in the same slot. + * If the function's drvdata isn't set then it isn't bound to + * a USB host controller driver, so skip it. */ companion = NULL; for_each_pci_dev(companion) { if (companion->bus != pdev->bus || PCI_SLOT(companion->devfn) != slot) continue; - companion_hcd = pci_get_drvdata(companion); if (!companion_hcd) continue; - - /* For SET_HS_COMPANION, store a pointer to the EHCI bus in - * the OHCI/UHCI companion bus structure. - * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus - * in the OHCI/UHCI companion bus structure. - * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI - * companion controllers have fully resumed. - */ - - if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && - companion->class == CL_EHCI) { - /* action must be SET_HS_COMPANION */ - dev_dbg(&companion->dev, "HS companion for %s\n", - dev_name(&pdev->dev)); - hcd->self.hs_companion = &companion_hcd->self; - - } else if (pdev->class == CL_EHCI && - (companion->class == CL_OHCI || - companion->class == CL_UHCI)) { - switch (action) { - case SET_HS_COMPANION: - dev_dbg(&pdev->dev, "HS companion for %s\n", - dev_name(&companion->dev)); - companion_hcd->self.hs_companion = &hcd->self; - break; - case CLEAR_HS_COMPANION: - companion_hcd->self.hs_companion = NULL; - break; - case WAIT_FOR_COMPANIONS: - device_pm_wait_for_dev(&pdev->dev, - &companion->dev); - break; - } - } + fn(pdev, hcd, companion, companion_hcd); } } -static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * We're about to add an EHCI controller, which will unceremoniously grab + * all the port connections away from its companions. To prevent annoying + * error messages, lock the companion's root hub and gracefully unconfigure + * it beforehand. Leave it locked until the EHCI controller is all set. + */ +static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd) { - mutex_lock(&companions_mutex); - dev_set_drvdata(&pdev->dev, hcd); - companion_common(pdev, hcd, SET_HS_COMPANION); - mutex_unlock(&companions_mutex); + struct usb_device *udev; + + if (is_ohci_or_uhci(companion)) { + udev = companion_hcd->self.root_hub; + usb_lock_device(udev); + usb_set_configuration(udev, 0); + } } -static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * Adding the EHCI controller has either succeeded or failed. Set the + * companion pointer accordingly, and in either case, reconfigure and + * unlock the root hub. + */ +static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd) { - mutex_lock(&companions_mutex); - dev_set_drvdata(&pdev->dev, NULL); + struct usb_device *udev; - /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ - if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) - hcd->self.hs_companion = NULL; + if (is_ohci_or_uhci(companion)) { + if (dev_get_drvdata(&pdev->dev)) { /* Succeeded */ + dev_dbg(&pdev->dev, "HS companion for %s\n", + dev_name(&companion->dev)); + companion_hcd->self.hs_companion = &hcd->self; + } + udev = companion_hcd->self.root_hub; + usb_set_configuration(udev, 1); + usb_unlock_device(udev); + } +} - /* Otherwise search for companion buses and clear their pointers */ - else - companion_common(pdev, hcd, CLEAR_HS_COMPANION); - mutex_unlock(&companions_mutex); +/* + * We just added a non-EHCI controller. Find the EHCI controller to + * which it is a companion, and store a pointer to the bus structure. + */ +static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ + if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) { + dev_dbg(&pdev->dev, "FS/LS companion for %s\n", + dev_name(&companion->dev)); + hcd->self.hs_companion = &companion_hcd->self; + } } -static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) +/* We are removing an EHCI controller. Clear the companions' pointers. */ +static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd) { - /* Only EHCI controllers need to wait. - * No locking is needed because a controller cannot be resumed - * while one of its companions is getting unbound. - */ - if (pdev->class == CL_EHCI) - companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); + if (is_ohci_or_uhci(companion)) + companion_hcd->self.hs_companion = NULL; } -#else /* !CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM -static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} +/* An EHCI controller must wait for its companions before resuming. */ +static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, + struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ + if (is_ohci_or_uhci(companion)) + device_pm_wait_for_dev(&pdev->dev, &companion->dev); +} -#endif /* !CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -217,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) driver->description)) { dev_dbg(&dev->dev, "controller already in use\n"); retval = -EBUSY; - goto clear_companion; + goto put_hcd; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { @@ -244,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (region == PCI_ROM_RESOURCE) { dev_dbg(&dev->dev, "no i/o regions available\n"); retval = -EBUSY; - goto clear_companion; + goto put_hcd; } } pci_set_master(dev); - retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); + /* Note: dev_set_drvdata must be called while holding the rwsem */ + if (dev->class == CL_EHCI) { + down_write(&companions_rwsem); + dev_set_drvdata(&dev->dev, hcd); + for_each_companion(dev, hcd, ehci_pre_add); + retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); + if (retval != 0) + dev_set_drvdata(&dev->dev, NULL); + for_each_companion(dev, hcd, ehci_post_add); + up_write(&companions_rwsem); + } else { + down_read(&companions_rwsem); + dev_set_drvdata(&dev->dev, hcd); + retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); + if (retval != 0) + dev_set_drvdata(&dev->dev, NULL); + else + for_each_companion(dev, hcd, non_ehci_add); + up_read(&companions_rwsem); + } + if (retval != 0) goto unmap_registers; - set_hs_companion(dev, hcd); if (pci_dev_run_wake(dev)) pm_runtime_put_noidle(&dev->dev); @@ -266,8 +289,7 @@ release_mem_region: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else release_region(hcd->rsrc_start, hcd->rsrc_len); -clear_companion: - clear_hs_companion(dev, hcd); +put_hcd: usb_put_hcd(hcd); disable_pci: pci_disable_device(dev); @@ -310,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev) usb_hcd_irq(0, hcd); local_irq_enable(); - usb_remove_hcd(hcd); + /* Note: dev_set_drvdata must be called while holding the rwsem */ + if (dev->class == CL_EHCI) { + down_write(&companions_rwsem); + for_each_companion(dev, hcd, ehci_remove); + usb_remove_hcd(hcd); + dev_set_drvdata(&dev->dev, NULL); + up_write(&companions_rwsem); + } else { + /* Not EHCI; just clear the companion pointer */ + down_read(&companions_rwsem); + hcd->self.hs_companion = NULL; + usb_remove_hcd(hcd); + dev_set_drvdata(&dev->dev, NULL); + up_read(&companions_rwsem); + } + if (hcd->driver->flags & HCD_MEMORY) { iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else { release_region(hcd->rsrc_start, hcd->rsrc_len); } - clear_hs_companion(dev, hcd); + usb_put_hcd(hcd); pci_disable_device(dev); } @@ -463,8 +500,15 @@ static int resume_common(struct device *dev, int event) pci_set_master(pci_dev); if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { - if (event != PM_EVENT_AUTO_RESUME) - wait_for_companions(pci_dev, hcd); + + /* + * Only EHCI controllers have to wait for their companions. + * No locking is needed because PCI controller drivers do not + * get unbound during system resume. + */ + if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) + for_each_companion(pci_dev, hcd, + ehci_wait_for_companions); retval = hcd->driver->pci_resume(hcd, event == PM_EVENT_RESTORE); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index f9ec44cbb82f..d53547d2e4c7 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) #endif /* CONFIG_PM */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME /* Workqueue routine for root-hub remote wakeup */ static void hcd_resume_work(struct work_struct *work) @@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) } EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */ /*-------------------------------------------------------------------------*/ @@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, init_timer(&hcd->rh_timer); hcd->rh_timer.function = rh_timer_func; hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME INIT_WORK(&hcd->wakeup_work, hcd_resume_work); #endif @@ -2590,7 +2590,7 @@ error_create_attr_group: hcd->rh_registered = 0; spin_unlock_irq(&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME cancel_work_sync(&hcd->wakeup_work); #endif mutex_lock(&usb_bus_list_lock); @@ -2645,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) hcd->rh_registered = 0; spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME cancel_work_sync(&hcd->wakeup_work); #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5480352f984d..feef9351463d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1, mutex_lock(&hub->status_mutex); ret = get_port_status(hub->hdev, port1, &hub->status->port); if (ret < 4) { - dev_err(hub->intfdev, - "%s failed (err = %d)\n", __func__, ret); + if (ret != -ENODEV) + dev_err(hub->intfdev, + "%s failed (err = %d)\n", __func__, ret); if (ret >= 0) ret = -EIO; } else { @@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work) /* drop lock so HCD can concurrently report other TT errors */ spin_unlock_irqrestore (&hub->tt.lock, flags); status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); - if (status) + if (status && status != -ENODEV) dev_err (&hdev->dev, "clear tt %d (%04x) error %d\n", clear->tt, clear->devinfo, status); @@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub, mutex_lock(&hub->status_mutex); ret = get_hub_status(hub->hdev, &hub->status->hub); - if (ret < 0) - dev_err (hub->intfdev, - "%s failed (err = %d)\n", __func__, ret); - else { + if (ret < 0) { + if (ret != -ENODEV) + dev_err(hub->intfdev, + "%s failed (err = %d)\n", __func__, ret); + } else { *status = le16_to_cpu(hub->status->hub.wHubStatus); *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; @@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1) return -EINVAL; ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); - if (ret) { - dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", - port1, ret); + if (ret) return ret; - } /* Wait for the link to enter the disabled state. */ for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { @@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); } - if (ret) + if (ret && ret != -ENODEV) dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", port1, ret); return ret; @@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub, message = "hub has too many ports!"; ret = -ENODEV; goto fail; + } else if (hub->descriptor->bNbrPorts == 0) { + message = "hub doesn't have any ports!"; + ret = -ENODEV; + goto fail; } hdev->maxchild = hub->descriptor->bNbrPorts; @@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev) if (udev->config == NULL) { err = usb_get_configuration(udev); if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); + if (err != -ENODEV) + dev_err(&udev->dev, "can't read configurations, error %d\n", + err); return err; } } @@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1, status = set_port_feature(hub->hdev, port1, (warm ? USB_PORT_FEAT_BH_PORT_RESET : USB_PORT_FEAT_RESET)); - if (status) { + if (status == -ENODEV) { + ; /* The hub is gone */ + } else if (status) { dev_err(hub->intfdev, "cannot %sreset port %d (err = %d)\n", warm ? "warm " : "", port1, status); } else { status = hub_port_wait_reset(hub, port1, udev, delay, warm); - if (status && status != -ENOTCONN) + if (status && status != -ENOTCONN && status != -ENODEV) dev_dbg(hub->intfdev, "port_wait_reset: err = %d\n", status); @@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev) } EXPORT_SYMBOL_GPL(usb_enable_ltm); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM /* * usb_disable_function_remotewakeup - disable usb3.0 * device's function remote wakeup @@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev) * Linux (2.6) currently has NO mechanisms to initiate that: no khubd * timer, no SRP, no requests through sysfs. * - * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when - * the root hub for their bus goes into global suspend ... so we don't - * (falsely) update the device power state to say it suspended. + * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get + * suspended only when their bus goes into global suspend (i.e., the root + * hub is suspended). Nevertheless, we change @udev->state to + * USB_STATE_SUSPENDED as this is the device's "logical" state. The actual + * upstream port setting is stored in @udev->port_is_suspended. * * Returns 0 on success, else negative errno. */ @@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) enum pm_qos_flags_status pm_qos_stat; int port1 = udev->portnum; int status; + bool really_suspend = true; /* enable remote wakeup when appropriate; this lets the device * wake up the upstream hub (including maybe the root hub). @@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); - else + else if (PMSG_IS_AUTO(msg)) status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); + /* + * For system suspend, we do not need to enable the suspend feature + * on individual USB-2 ports. The devices will automatically go + * into suspend a few ms after the root hub stops sending packets. + * The USB 2.0 spec calls this "global suspend". + */ + else { + really_suspend = false; + status = 0; + } if (status) { dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); @@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) (PMSG_IS_AUTO(msg) ? "auto-" : ""), udev->do_remote_wakeup); usb_set_device_state(udev, USB_STATE_SUSPENDED); - udev->port_is_suspended = 1; - msleep(10); + if (really_suspend) { + udev->port_is_suspended = 1; + msleep(10); + } } /* @@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) return status; } +#endif /* CONFIG_PM */ + +#ifdef CONFIG_PM_RUNTIME + /* caller has locked udev */ int usb_remote_wakeup(struct usb_device *udev) { @@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev) return status; } -#else /* CONFIG_USB_SUSPEND */ - -/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ - -int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ - return 0; -} - -/* However we may need to do a reset-resume */ - -int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ - struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - int port1 = udev->portnum; - int status; - u16 portchange, portstatus; - - status = hub_port_status(hub, port1, &portstatus, &portchange); - status = check_port_resume_type(udev, - hub, port1, status, portchange, portstatus); - - if (status) { - dev_dbg(&udev->dev, "can't resume, status %d\n", status); - hub_port_logical_disconnect(hub, port1); - } else if (udev->reset_resume) { - dev_dbg(&udev->dev, "reset-resume\n"); - status = usb_reset_and_verify_device(udev); - } - return status; -} - #endif static int check_ports_changed(struct usb_hub *hub) @@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, goto fail; } if (r) { - dev_err(&udev->dev, - "device descriptor read/64, error %d\n", - r); + if (r != -ENODEV) + dev_err(&udev->dev, "device descriptor read/64, error %d\n", + r); retval = -EMSGSIZE; continue; } @@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, msleep(200); } if (retval < 0) { - dev_err(&udev->dev, - "device not accepting address %d, error %d\n", - devnum, retval); + if (retval != -ENODEV) + dev_err(&udev->dev, "device not accepting address %d, error %d\n", + devnum, retval); goto fail; } if (udev->speed == USB_SPEED_SUPER) { @@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = usb_get_device_descriptor(udev, 8); if (retval < 8) { - dev_err(&udev->dev, + if (retval != -ENODEV) + dev_err(&udev->dev, "device descriptor read/8, error %d\n", retval); if (retval >= 0) @@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { - dev_err(&udev->dev, "device descriptor read/all, error %d\n", - retval); + if (retval != -ENODEV) + dev_err(&udev->dev, "device descriptor read/all, error %d\n", + retval); if (retval >= 0) retval = -ENOMSG; goto fail; @@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (portstatus & USB_PORT_STAT_ENABLE) { status = 0; /* Nothing to do */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME } else if (udev->state == USB_STATE_SUSPENDED && udev->persist_enabled) { /* For a suspended device, treat this as a @@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, USB_PORT_STAT_C_ENABLE)) { status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { - if (printk_ratelimit()) + if (status != -ENODEV && printk_ratelimit()) dev_err(hub_dev, "connect-debounce failed, " "port %d disabled\n", port1); portstatus &= ~USB_PORT_STAT_CONNECTION; @@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, else unit_load = 100; + status = 0; for (i = 0; i < SET_CONFIG_TRIES; i++) { /* reallocate for each attempt, since references @@ -4526,9 +4522,11 @@ loop: } if (hub->hdev->parent || !hcd->driver->port_handed_over || - !(hcd->driver->port_handed_over)(hcd, port1)) - dev_err(hub_dev, "unable to enumerate USB device on port %d\n", - port1); + !(hcd->driver->port_handed_over)(hcd, port1)) { + if (status != -ENOTCONN && status != -ENODEV) + dev_err(hub_dev, "unable to enumerate USB device on port %d\n", + port1); + } done: hub_port_disable(hub, port1, 1); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 65d4e55552c6..b8bad294eeb8 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -70,7 +70,7 @@ static void usb_port_device_release(struct device *dev) kfree(port_dev); } -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME static int usb_port_runtime_resume(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); @@ -138,7 +138,7 @@ static int usb_port_runtime_suspend(struct device *dev) #endif static const struct dev_pm_ops usb_port_pm_ops = { -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME .runtime_suspend = usb_port_runtime_suspend, .runtime_resume = usb_port_runtime_resume, .runtime_idle = pm_generic_runtime_idle, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 3113c1d71442..ab5638d9c707 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev) dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); - /* For the present, all devices default to USB-PERSIST enabled */ -#if 0 /* was: #ifdef CONFIG_PM */ - /* Hubs are automatically enabled for USB-PERSIST */ - if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) +#ifdef CONFIG_USB_DEFAULT_PERSIST + if (!(udev->quirks & USB_QUIRK_RESET)) udev->persist_enabled = 1; - #else - /* In the absence of PM, we can safely enable USB-PERSIST - * for all devices. It will affect things like hub resets - * and EMF-related port disables. - */ - if (!(udev->quirks & USB_QUIRK_RESET)) + /* Hubs are automatically enabled for USB-PERSIST */ + if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) udev->persist_enabled = 1; -#endif /* CONFIG_PM */ +#endif /* CONFIG_USB_DEFAULT_PERSIST */ } void usb_detect_interface_quirks(struct usb_device *udev) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 3f81a3dc6867..aa38db44818a 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev) #endif /* CONFIG_PM */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME static ssize_t show_connected_duration(struct device *dev, struct device_attribute *attr, @@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev) #define add_power_attributes(dev) 0 #define remove_power_attributes(dev) do {} while (0) -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */ /* Descriptor fields */ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index e0d9d948218c..16927fa88fbd 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb); void usb_poison_urb(struct urb *urb) { might_sleep(); - if (!(urb && urb->dev && urb->ep)) + if (!urb) return; atomic_inc(&urb->reject); + if (!urb->dev || !urb->ep) + return; + usb_hcd_unlink_urb(urb, -ENOENT); wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e092b414dc50..b10da720f2b4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore"; static bool nousb; /* Disable USB when built into kernel image */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME static int usb_autosuspend_delay = 2; /* Default delay value, * in seconds */ module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); @@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = { .thaw = usb_dev_thaw, .poweroff = usb_dev_poweroff, .restore = usb_dev_restore, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME .runtime_suspend = usb_runtime_suspend, .runtime_resume = usb_runtime_resume, .runtime_idle = usb_runtime_idle, diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a7f20bde0e5e..823857767a16 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) #endif -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME extern void usb_autosuspend_device(struct usb_device *udev); extern int usb_autoresume_device(struct usb_device *udev); diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 68e9a2c5a01a..ea5ee9c21c35 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,6 @@ config USB_DWC3 tristate "DesignWare USB3 DRD Core Support" depends on (USB || USB_GADGET) && GENERIC_HARDIRQS - select USB_OTG_UTILS select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ffa6b004a84b..c35d49d39b76 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -140,7 +140,8 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, * Returns a pointer to the allocated event buffer structure on success * otherwise ERR_PTR(errno). */ -static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) +static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, + unsigned length) { struct dwc3_event_buffer *evt; @@ -259,6 +260,17 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) } } +static void dwc3_core_num_eps(struct dwc3 *dwc) +{ + struct dwc3_hwparams *parms = &dwc->hwparams; + + dwc->num_in_eps = DWC3_NUM_IN_EPS(parms); + dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps; + + dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n", + dwc->num_in_eps, dwc->num_out_eps); +} + static void dwc3_cache_hwparams(struct dwc3 *dwc) { struct dwc3_hwparams *parms = &dwc->hwparams; @@ -335,13 +347,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (dwc->revision < DWC3_REVISION_190A) reg |= DWC3_GCTL_U2RSTECN; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); + dwc3_core_num_eps(dwc); - ret = dwc3_event_buffers_setup(dwc); - if (ret) { - dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err0; - } + dwc3_writel(dwc->regs, DWC3_GCTL, reg); return 0; @@ -351,8 +359,6 @@ err0: static void dwc3_core_exit(struct dwc3 *dwc) { - dwc3_event_buffers_cleanup(dwc); - usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); } @@ -428,12 +434,32 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); } - if (IS_ERR_OR_NULL(dwc->usb2_phy)) { + if (IS_ERR(dwc->usb2_phy)) { + ret = PTR_ERR(dwc->usb2_phy); + + /* + * if -ENXIO is returned, it means PHY layer wasn't + * enabled, so it makes no sense to return -EPROBE_DEFER + * in that case, since no PHY driver will ever probe. + */ + if (ret == -ENXIO) + return ret; + dev_err(dev, "no usb2 phy configured\n"); return -EPROBE_DEFER; } - if (IS_ERR_OR_NULL(dwc->usb3_phy)) { + if (IS_ERR(dwc->usb3_phy)) { + ret = PTR_ERR(dwc->usb2_phy); + + /* + * if -ENXIO is returned, it means PHY layer wasn't + * enabled, so it makes no sense to return -EPROBE_DEFER + * in that case, since no PHY driver will ever probe. + */ + if (ret == -ENXIO) + return ret; + dev_err(dev, "no usb3 phy configured\n"); return -EPROBE_DEFER; } @@ -448,6 +474,10 @@ static int dwc3_probe(struct platform_device *pdev) dwc->regs_size = resource_size(res); dwc->dev = dev; + dev->dma_mask = dev->parent->dma_mask; + dev->dma_parms = dev->parent->dma_parms; + dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); + if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; else if (!strncmp("high", maximum_speed, 4)) @@ -480,7 +510,18 @@ static int dwc3_probe(struct platform_device *pdev) goto err0; } - mode = DWC3_MODE(dwc->hwparams.hwparams0); + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err1; + } + + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = DWC3_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + mode = DWC3_MODE_DEVICE; + else + mode = DWC3_MODE_DRD; switch (mode) { case DWC3_MODE_DEVICE: @@ -488,7 +529,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); - goto err1; + goto err2; } break; case DWC3_MODE_HOST: @@ -496,7 +537,7 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); - goto err1; + goto err2; } break; case DWC3_MODE_DRD: @@ -504,32 +545,32 @@ static int dwc3_probe(struct platform_device *pdev) ret = dwc3_host_init(dwc); if (ret) { dev_err(dev, "failed to initialize host\n"); - goto err1; + goto err2; } ret = dwc3_gadget_init(dwc); if (ret) { dev_err(dev, "failed to initialize gadget\n"); - goto err1; + goto err2; } break; default: dev_err(dev, "Unsupported mode of operation %d\n", mode); - goto err1; + goto err2; } dwc->mode = mode; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); - goto err2; + goto err3; } pm_runtime_allow(dev); return 0; -err2: +err3: switch (mode) { case DWC3_MODE_DEVICE: dwc3_gadget_exit(dwc); @@ -546,6 +587,9 @@ err2: break; } +err2: + dwc3_event_buffers_cleanup(dwc); + err1: dwc3_core_exit(dwc); @@ -583,12 +627,130 @@ static int dwc3_remove(struct platform_device *pdev) break; } + dwc3_event_buffers_cleanup(dwc); dwc3_free_event_buffers(dwc); dwc3_core_exit(dwc); return 0; } +#ifdef CONFIG_PM_SLEEP +static int dwc3_prepare(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_prepare(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + dwc3_event_buffers_cleanup(dwc); + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static void dwc3_complete(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_complete(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + dwc3_event_buffers_setup(dwc); + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); +} + +static int dwc3_suspend(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_suspend(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + /* do nothing */ + break; + } + + dwc->gctl = dwc3_readl(dwc->regs, DWC3_GCTL); + spin_unlock_irqrestore(&dwc->lock, flags); + + usb_phy_shutdown(dwc->usb3_phy); + usb_phy_shutdown(dwc->usb2_phy); + + return 0; +} + +static int dwc3_resume(struct device *dev) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + unsigned long flags; + + usb_phy_init(dwc->usb3_phy); + usb_phy_init(dwc->usb2_phy); + msleep(100); + + spin_lock_irqsave(&dwc->lock, flags); + + dwc3_writel(dwc->regs, DWC3_GCTL, dwc->gctl); + + switch (dwc->mode) { + case DWC3_MODE_DEVICE: + case DWC3_MODE_DRD: + dwc3_gadget_resume(dwc); + /* FALLTHROUGH */ + case DWC3_MODE_HOST: + default: + /* do nothing */ + break; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static const struct dev_pm_ops dwc3_dev_pm_ops = { + .prepare = dwc3_prepare, + .complete = dwc3_complete, + + SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume) +}; + +#define DWC3_PM_OPS &(dwc3_dev_pm_ops) +#else +#define DWC3_PM_OPS NULL +#endif + #ifdef CONFIG_OF static const struct of_device_id of_dwc3_match[] = { { @@ -605,6 +767,7 @@ static struct platform_driver dwc3_driver = { .driver = { .name = "dwc3", .of_match_table = of_match_ptr(of_dwc3_match), + .pm = DWC3_PM_OPS, }, }; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index b41750660235..b69d322e3cab 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -154,8 +154,9 @@ /* OTG Registers */ #define DWC3_OCFG 0xcc00 #define DWC3_OCTL 0xcc04 -#define DWC3_OEVTEN 0xcc08 -#define DWC3_OSTS 0xcc0C +#define DWC3_OEVT 0xcc08 +#define DWC3_OEVTEN 0xcc0C +#define DWC3_OSTS 0xcc10 /* Bit fields */ @@ -369,6 +370,9 @@ struct dwc3_trb; * @list: a list of event buffers * @buf: _THE_ buffer * @length: size of this buffer + * @lpos: event offset + * @count: cache of last read event count register + * @flags: flags related to this event buffer * @dma: dma_addr_t * @dwc: pointer to DWC controller */ @@ -376,6 +380,10 @@ struct dwc3_event_buffer { void *buf; unsigned length; unsigned int lpos; + unsigned int count; + unsigned int flags; + +#define DWC3_EVENT_PENDING BIT(0) dma_addr_t dma; @@ -487,12 +495,6 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; -enum dwc3_device_state { - DWC3_DEFAULT_STATE, - DWC3_ADDRESS_STATE, - DWC3_CONFIGURED_STATE, -}; - /* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) @@ -574,6 +576,14 @@ struct dwc3_hwparams { /* HWPARAMS1 */ #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) +/* HWPARAMS3 */ +#define DWC3_NUM_IN_EPS_MASK (0x1f << 18) +#define DWC3_NUM_EPS_MASK (0x3f << 12) +#define DWC3_NUM_EPS(p) (((p)->hwparams3 & \ + (DWC3_NUM_EPS_MASK)) >> 12) +#define DWC3_NUM_IN_EPS(p) (((p)->hwparams3 & \ + (DWC3_NUM_IN_EPS_MASK)) >> 18) + /* HWPARAMS7 */ #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) @@ -618,7 +628,6 @@ struct dwc3_scratchpad_array { * @gadget_driver: pointer to the gadget driver * @regs: base address for our registers * @regs_size: address space size - * @irq: IRQ number * @num_event_buffers: calculated number of event buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) @@ -626,6 +635,8 @@ struct dwc3_scratchpad_array { * @mode: mode of operation * @usb2_phy: pointer to USB2 PHY * @usb3_phy: pointer to USB3 PHY + * @dcfg: saved contents of DCFG register + * @gctl: saved contents of GCTL register * @is_selfpowered: true when we are selfpowered * @three_stage_setup: set if we perform a three phase setup * @ep0_bounced: true when we used bounce buffer @@ -639,6 +650,8 @@ struct dwc3_scratchpad_array { * @u2pel: parameter from Set SEL request. * @u1sel: parameter from Set SEL request. * @u1pel: parameter from Set SEL request. + * @num_out_eps: number of out endpoints + * @num_in_eps: number of in endpoints * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state @@ -656,8 +669,10 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t ep0_bounce_addr; struct dwc3_request ep0_usb_req; + /* device lock */ spinlock_t lock; + struct device *dev; struct platform_device *xhci; @@ -675,6 +690,10 @@ struct dwc3 { void __iomem *regs; size_t regs_size; + /* used for suspend/resume */ + u32 dcfg; + u32 gctl; + u32 num_event_buffers; u32 u1u2; u32 maximum_speed; @@ -694,6 +713,9 @@ struct dwc3 { #define DWC3_REVISION_202A 0x5533202a #define DWC3_REVISION_210A 0x5533210a #define DWC3_REVISION_220A 0x5533220a +#define DWC3_REVISION_230A 0x5533230a +#define DWC3_REVISION_240A 0x5533240a +#define DWC3_REVISION_250A 0x5533250a unsigned is_selfpowered:1; unsigned three_stage_setup:1; @@ -704,11 +726,11 @@ struct dwc3 { unsigned delayed_status:1; unsigned needs_fifo_resize:1; unsigned resize_fifos:1; + unsigned pullups_connected:1; enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; enum dwc3_link_state link_state; - enum dwc3_device_state dev_state; u16 isoch_delay; u16 u2sel; @@ -718,6 +740,9 @@ struct dwc3 { u8 speed; + u8 num_out_eps; + u8 num_in_eps; + void *mem; struct dwc3_hwparams hwparams; @@ -884,4 +909,31 @@ static inline void dwc3_gadget_exit(struct dwc3 *dwc) { } #endif +/* power management interface */ +#if !IS_ENABLED(CONFIG_USB_DWC3_HOST) +int dwc3_gadget_prepare(struct dwc3 *dwc); +void dwc3_gadget_complete(struct dwc3 *dwc); +int dwc3_gadget_suspend(struct dwc3 *dwc); +int dwc3_gadget_resume(struct dwc3 *dwc); +#else +static inline int dwc3_gadget_prepare(struct dwc3 *dwc) +{ + return 0; +} + +static inline void dwc3_gadget_complete(struct dwc3 *dwc) +{ +} + +static inline int dwc3_gadget_suspend(struct dwc3 *dwc) +{ + return 0; +} + +static inline int dwc3_gadget_resume(struct dwc3 *dwc) +{ + return 0; +} +#endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */ + #endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 4a752e730c5f..9e9f122162f2 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -59,7 +59,7 @@ .offset = DWC3_ ##nm - DWC3_GLOBALS_REGS_START, \ } -static struct debugfs_reg32 dwc3_regs[] = { +static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GSBUSCFG0), dump_register(GSBUSCFG1), dump_register(GTXTHRCFG), @@ -372,6 +372,7 @@ static struct debugfs_reg32 dwc3_regs[] = { dump_register(OCFG), dump_register(OCTL), + dump_register(OEVT), dump_register(OEVTEN), dump_register(OSTS), }; @@ -577,8 +578,14 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused) case DWC3_LINK_STATE_LPBK: seq_printf(s, "Loopback\n"); break; + case DWC3_LINK_STATE_RESET: + seq_printf(s, "Reset\n"); + break; + case DWC3_LINK_STATE_RESUME: + seq_printf(s, "Resume\n"); + break; default: - seq_printf(s, "UNKNOWN %d\n", reg); + seq_printf(s, "UNKNOWN %d\n", state); } return 0; @@ -661,28 +668,31 @@ int dwc3_debugfs_init(struct dwc3 *dwc) goto err1; } -#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) - file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_mode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_testmode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; + if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) { + file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_mode_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } } - file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_link_state_fops); - if (!file) { - ret = -ENOMEM; - goto err1; + if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) || + IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { + file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_testmode_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } + + file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, + dwc, &dwc3_link_state_fops); + if (!file) { + ret = -ENOMEM; + goto err1; + } } -#endif return 0; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index b082bec7343e..a8afe6e26621 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -22,9 +22,9 @@ #include <linux/usb/otg.h> #include <linux/usb/nop-usb-xceiv.h> #include <linux/of.h> +#include <linux/of_platform.h> struct dwc3_exynos { - struct platform_device *dwc3; struct platform_device *usb2_phy; struct platform_device *usb3_phy; struct device *dev; @@ -86,21 +86,30 @@ err1: return ret; } +static int dwc3_exynos_remove_child(struct device *dev, void *unused) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32); static int dwc3_exynos_probe(struct platform_device *pdev) { - struct platform_device *dwc3; struct dwc3_exynos *exynos; struct clk *clk; struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; int ret = -ENOMEM; exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL); if (!exynos) { dev_err(dev, "not enough memory\n"); - return -ENOMEM; + goto err1; } /* @@ -108,21 +117,15 @@ static int dwc3_exynos_probe(struct platform_device *pdev) * Since shared usb code relies on it, set it here for now. * Once we move to full device tree support this will vanish off. */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &dwc3_exynos_dma_mask; + if (!dev->dma_mask) + dev->dma_mask = &dwc3_exynos_dma_mask; platform_set_drvdata(pdev, exynos); ret = dwc3_exynos_register_phys(exynos); if (ret) { dev_err(dev, "couldn't register PHYs\n"); - return ret; - } - - dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); - if (!dwc3) { - dev_err(dev, "couldn't allocate dwc3 device\n"); - return -ENOMEM; + goto err1; } clk = devm_clk_get(dev, "usbdrd30"); @@ -132,37 +135,28 @@ static int dwc3_exynos_probe(struct platform_device *pdev) goto err1; } - dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - - dwc3->dev.parent = dev; - dwc3->dev.dma_mask = dev->dma_mask; - dwc3->dev.dma_parms = dev->dma_parms; - exynos->dwc3 = dwc3; exynos->dev = dev; exynos->clk = clk; - clk_enable(exynos->clk); - - ret = platform_device_add_resources(dwc3, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; - } - - ret = platform_device_add(dwc3); - if (ret) { - dev_err(dev, "failed to register dwc3 device\n"); + clk_prepare_enable(exynos->clk); + + if (node) { + ret = of_platform_populate(node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to add dwc3 core\n"); + goto err2; + } + } else { + dev_err(dev, "no device node, failed to add dwc3 core\n"); + ret = -ENODEV; goto err2; } return 0; err2: - clk_disable(clk); + clk_disable_unprepare(clk); err1: - platform_device_put(dwc3); - return ret; } @@ -170,11 +164,11 @@ static int dwc3_exynos_remove(struct platform_device *pdev) { struct dwc3_exynos *exynos = platform_get_drvdata(pdev); - platform_device_unregister(exynos->dwc3); platform_device_unregister(exynos->usb2_phy); platform_device_unregister(exynos->usb3_phy); + device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child); - clk_disable(exynos->clk); + clk_disable_unprepare(exynos->clk); return 0; } @@ -187,12 +181,46 @@ static const struct of_device_id exynos_dwc3_match[] = { MODULE_DEVICE_TABLE(of, exynos_dwc3_match); #endif +#ifdef CONFIG_PM_SLEEP +static int dwc3_exynos_suspend(struct device *dev) +{ + struct dwc3_exynos *exynos = dev_get_drvdata(dev); + + clk_disable(exynos->clk); + + return 0; +} + +static int dwc3_exynos_resume(struct device *dev) +{ + struct dwc3_exynos *exynos = dev_get_drvdata(dev); + + clk_enable(exynos->clk); + + /* runtime set active to reflect active state. */ + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static const struct dev_pm_ops dwc3_exynos_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_exynos_suspend, dwc3_exynos_resume) +}; + +#define DEV_PM_OPS (&dwc3_exynos_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver dwc3_exynos_driver = { .probe = dwc3_exynos_probe, .remove = dwc3_exynos_remove, .driver = { .name = "exynos-dwc3", .of_match_table = of_match_ptr(exynos_dwc3_match), + .pm = DEV_PM_OPS, }, }; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index afa05e3c9cf4..34638b92500d 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -52,7 +52,6 @@ #include <linux/of_platform.h> #include <linux/usb/otg.h> -#include <linux/usb/nop-usb-xceiv.h> /* * All these registers belong to OMAP's Wrapper around the @@ -117,20 +116,17 @@ struct dwc3_omap { /* device lock */ spinlock_t lock; - struct platform_device *usb2_phy; - struct platform_device *usb3_phy; struct device *dev; int irq; void __iomem *base; - void *context; - u32 resource_size; + u32 utmi_otg_status; u32 dma_status:1; }; -struct dwc3_omap *_omap; +static struct dwc3_omap *_omap; static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) { @@ -142,11 +138,14 @@ static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value) writel(value, base + offset); } -void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) +int dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) { u32 val; struct dwc3_omap *omap = _omap; + if (!omap) + return -EPROBE_DEFER; + switch (status) { case OMAP_DWC3_ID_GROUND: dev_dbg(omap->dev, "ID GND\n"); @@ -189,63 +188,9 @@ void dwc3_omap_mailbox(enum omap_dwc3_vbus_id_status status) dev_dbg(omap->dev, "ID float\n"); } - return; -} -EXPORT_SYMBOL_GPL(dwc3_omap_mailbox); - -static int dwc3_omap_register_phys(struct dwc3_omap *omap) -{ - struct nop_usb_xceiv_platform_data pdata; - struct platform_device *pdev; - int ret; - - memset(&pdata, 0x00, sizeof(pdata)); - - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); - if (!pdev) - return -ENOMEM; - - omap->usb2_phy = pdev; - pdata.type = USB_PHY_TYPE_USB2; - - ret = platform_device_add_data(omap->usb2_phy, &pdata, sizeof(pdata)); - if (ret) - goto err1; - - pdev = platform_device_alloc("nop_usb_xceiv", PLATFORM_DEVID_AUTO); - if (!pdev) { - ret = -ENOMEM; - goto err1; - } - - omap->usb3_phy = pdev; - pdata.type = USB_PHY_TYPE_USB3; - - ret = platform_device_add_data(omap->usb3_phy, &pdata, sizeof(pdata)); - if (ret) - goto err2; - - ret = platform_device_add(omap->usb2_phy); - if (ret) - goto err2; - - ret = platform_device_add(omap->usb3_phy); - if (ret) - goto err3; - return 0; - -err3: - platform_device_del(omap->usb2_phy); - -err2: - platform_device_put(omap->usb3_phy); - -err1: - platform_device_put(omap->usb2_phy); - - return ret; } +EXPORT_SYMBOL_GPL(dwc3_omap_mailbox); static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) { @@ -307,24 +252,57 @@ static int dwc3_omap_remove_core(struct device *dev, void *c) return 0; } +static void dwc3_omap_enable_irqs(struct dwc3_omap *omap) +{ + u32 reg; + + /* enable all IRQs */ + reg = USBOTGSS_IRQO_COREIRQ_ST; + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); + + reg = (USBOTGSS_IRQ1_OEVT | + USBOTGSS_IRQ1_DRVVBUS_RISE | + USBOTGSS_IRQ1_CHRGVBUS_RISE | + USBOTGSS_IRQ1_DISCHRGVBUS_RISE | + USBOTGSS_IRQ1_IDPULLUP_RISE | + USBOTGSS_IRQ1_DRVVBUS_FALL | + USBOTGSS_IRQ1_CHRGVBUS_FALL | + USBOTGSS_IRQ1_DISCHRGVBUS_FALL | + USBOTGSS_IRQ1_IDPULLUP_FALL); + + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); +} + +static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) +{ + /* disable all IRQs */ + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, 0x00); + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x00); +} + +static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); + static int dwc3_omap_probe(struct platform_device *pdev) { - struct dwc3_omap_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; struct dwc3_omap *omap; struct resource *res; struct device *dev = &pdev->dev; - int size; int ret = -ENOMEM; int irq; - const u32 *utmi_mode; + int utmi_mode = 0; + u32 reg; void __iomem *base; - void *context; + + if (!node) { + dev_err(dev, "device node not found\n"); + return -EINVAL; + } omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); if (!omap) { @@ -334,13 +312,13 @@ static int dwc3_omap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, omap); - irq = platform_get_irq(pdev, 1); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "missing IRQ resource\n"); return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory base resource\n"); return -EINVAL; @@ -352,25 +330,12 @@ static int dwc3_omap_probe(struct platform_device *pdev) return -ENOMEM; } - ret = dwc3_omap_register_phys(omap); - if (ret) { - dev_err(dev, "couldn't register PHYs\n"); - return ret; - } - - context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL); - if (!context) { - dev_err(dev, "couldn't allocate dwc3 context memory\n"); - return -ENOMEM; - } - spin_lock_init(&omap->lock); - omap->resource_size = resource_size(res); - omap->context = context; omap->dev = dev; omap->irq = irq; omap->base = base; + dev->dma_mask = &dwc3_omap_dma_mask; /* * REVISIT if we ever have two instances of the wrapper, we will be @@ -387,25 +352,17 @@ static int dwc3_omap_probe(struct platform_device *pdev) reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); - utmi_mode = of_get_property(node, "utmi-mode", &size); - if (utmi_mode && size == sizeof(*utmi_mode)) { - reg |= *utmi_mode; - } else { - if (!pdata) { - dev_dbg(dev, "missing platform data\n"); - } else { - switch (pdata->utmi_mode) { - case DWC3_OMAP_UTMI_MODE_SW: - reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - case DWC3_OMAP_UTMI_MODE_HW: - reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - default: - dev_dbg(dev, "UNKNOWN utmi mode %d\n", - pdata->utmi_mode); - } - } + of_property_read_u32(node, "utmi-mode", &utmi_mode); + + switch (utmi_mode) { + case DWC3_OMAP_UTMI_MODE_SW: + reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + case DWC3_OMAP_UTMI_MODE_HW: + reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + default: + dev_dbg(dev, "UNKNOWN utmi mode %d\n", utmi_mode); } dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); @@ -422,29 +379,12 @@ static int dwc3_omap_probe(struct platform_device *pdev) return ret; } - /* enable all IRQs */ - reg = USBOTGSS_IRQO_COREIRQ_ST; - dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); + dwc3_omap_enable_irqs(omap); - reg = (USBOTGSS_IRQ1_OEVT | - USBOTGSS_IRQ1_DRVVBUS_RISE | - USBOTGSS_IRQ1_CHRGVBUS_RISE | - USBOTGSS_IRQ1_DISCHRGVBUS_RISE | - USBOTGSS_IRQ1_IDPULLUP_RISE | - USBOTGSS_IRQ1_DRVVBUS_FALL | - USBOTGSS_IRQ1_CHRGVBUS_FALL | - USBOTGSS_IRQ1_DISCHRGVBUS_FALL | - USBOTGSS_IRQ1_IDPULLUP_FALL); - - dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); - - if (node) { - ret = of_platform_populate(node, NULL, NULL, dev); - if (ret) { - dev_err(&pdev->dev, - "failed to add create dwc3 core\n"); - return ret; - } + ret = of_platform_populate(node, NULL, NULL, dev); + if (ret) { + dev_err(&pdev->dev, "failed to create dwc3 core\n"); + return ret; } return 0; @@ -454,8 +394,7 @@ static int dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - platform_device_unregister(omap->usb2_phy); - platform_device_unregister(omap->usb3_phy); + dwc3_omap_disable_irqs(omap); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); device_for_each_child(&pdev->dev, NULL, dwc3_omap_remove_core); @@ -465,18 +404,72 @@ static int dwc3_omap_remove(struct platform_device *pdev) static const struct of_device_id of_dwc3_match[] = { { - "ti,dwc3", + .compatible = "ti,dwc3" }, { }, }; MODULE_DEVICE_TABLE(of, of_dwc3_match); +#ifdef CONFIG_PM_SLEEP +static int dwc3_omap_prepare(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + dwc3_omap_disable_irqs(omap); + + return 0; +} + +static void dwc3_omap_complete(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + dwc3_omap_enable_irqs(omap); +} + +static int dwc3_omap_suspend(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + omap->utmi_otg_status = dwc3_omap_readl(omap->base, + USBOTGSS_UTMI_OTG_STATUS); + + return 0; +} + +static int dwc3_omap_resume(struct device *dev) +{ + struct dwc3_omap *omap = dev_get_drvdata(dev); + + dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, + omap->utmi_otg_status); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + +static const struct dev_pm_ops dwc3_omap_dev_pm_ops = { + .prepare = dwc3_omap_prepare, + .complete = dwc3_omap_complete, + + SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume) +}; + +#define DEV_PM_OPS (&dwc3_omap_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver dwc3_omap_driver = { .probe = dwc3_omap_probe, .remove = dwc3_omap_remove, .driver = { .name = "omap-dwc3", .of_match_table = of_dwc3_match, + .pm = DEV_PM_OPS, }, }; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index e8d77689a322..227d4a7acad7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -212,11 +212,49 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); +#ifdef CONFIG_PM +static int dwc3_pci_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + + pci_disable_device(pci); + + return 0; +} + +static int dwc3_pci_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + int ret; + + ret = pci_enable_device(pci); + if (ret) { + dev_err(dev, "can't re-enable device --> %d\n", ret); + return ret; + } + + pci_set_master(pci); + + return 0; +} + +static const struct dev_pm_ops dwc3_pci_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume) +}; + +#define DEV_PM_OPS (&dwc3_pci_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + static struct pci_driver dwc3_pci_driver = { .name = "dwc3-pci", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = dwc3_pci_remove, + .driver = { + .pm = DEV_PM_OPS, + }, }; MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 1d139ca05ef1..5acbb948b704 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -394,10 +394,13 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, u32 wIndex; u32 reg; int ret; + enum usb_device_state state; wValue = le16_to_cpu(ctrl->wValue); wIndex = le16_to_cpu(ctrl->wIndex); recip = ctrl->bRequestType & USB_RECIP_MASK; + state = dwc->gadget.state; + switch (recip) { case USB_RECIP_DEVICE: @@ -409,7 +412,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, * default control pipe */ case USB_DEVICE_U1_ENABLE: - if (dwc->dev_state != DWC3_CONFIGURED_STATE) + if (state != USB_STATE_CONFIGURED) return -EINVAL; if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; @@ -423,7 +426,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, break; case USB_DEVICE_U2_ENABLE: - if (dwc->dev_state != DWC3_CONFIGURED_STATE) + if (state != USB_STATE_CONFIGURED) return -EINVAL; if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; @@ -493,6 +496,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + enum usb_device_state state = dwc->gadget.state; u32 addr; u32 reg; @@ -502,7 +506,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; } - if (dwc->dev_state == DWC3_CONFIGURED_STATE) { + if (state == USB_STATE_CONFIGURED) { dev_dbg(dwc->dev, "trying to set address when configured\n"); return -EINVAL; } @@ -513,9 +517,9 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc3_writel(dwc->regs, DWC3_DCFG, reg); if (addr) - dwc->dev_state = DWC3_ADDRESS_STATE; + usb_gadget_set_state(&dwc->gadget, USB_STATE_ADDRESS); else - dwc->dev_state = DWC3_DEFAULT_STATE; + usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); return 0; } @@ -532,6 +536,7 @@ static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { + enum usb_device_state state = dwc->gadget.state; u32 cfg; int ret; u32 reg; @@ -539,16 +544,18 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); - switch (dwc->dev_state) { - case DWC3_DEFAULT_STATE: + switch (state) { + case USB_STATE_DEFAULT: return -EINVAL; break; - case DWC3_ADDRESS_STATE: + case USB_STATE_ADDRESS: ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { - dwc->dev_state = DWC3_CONFIGURED_STATE; + usb_gadget_set_state(&dwc->gadget, + USB_STATE_CONFIGURED); + /* * Enable transition to U1/U2 state when * nothing is pending from application. @@ -562,10 +569,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) } break; - case DWC3_CONFIGURED_STATE: + case USB_STATE_CONFIGURED: ret = dwc3_ep0_delegate_req(dwc, ctrl); if (!cfg) - dwc->dev_state = DWC3_ADDRESS_STATE; + usb_gadget_set_state(&dwc->gadget, + USB_STATE_ADDRESS); break; default: ret = -EINVAL; @@ -620,10 +628,11 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { struct dwc3_ep *dep; + enum usb_device_state state = dwc->gadget.state; u16 wLength; u16 wValue; - if (dwc->dev_state == DWC3_DEFAULT_STATE) + if (state == USB_STATE_DEFAULT) return -EINVAL; wValue = le16_to_cpu(ctrl->wValue); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 82e160e96fca..2b6e7e001207 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1425,8 +1425,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) if (dwc->revision >= DWC3_REVISION_194A) reg &= ~DWC3_DCTL_KEEP_CONNECT; reg |= DWC3_DCTL_RUN_STOP; + dwc->pullups_connected = true; } else { reg &= ~DWC3_DCTL_RUN_STOP; + dwc->pullups_connected = false; } dwc3_writel(dwc->regs, DWC3_DCTL, reg); @@ -1469,6 +1471,33 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) return ret; } +static void dwc3_gadget_enable_irq(struct dwc3 *dwc) +{ + u32 reg; + + /* Enable all but Start and End of Frame IRQs */ + reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | + DWC3_DEVTEN_EVNTOVERFLOWEN | + DWC3_DEVTEN_CMDCMPLTEN | + DWC3_DEVTEN_ERRTICERREN | + DWC3_DEVTEN_WKUPEVTEN | + DWC3_DEVTEN_ULSTCNGEN | + DWC3_DEVTEN_CONNECTDONEEN | + DWC3_DEVTEN_USBRSTEN | + DWC3_DEVTEN_DISCONNEVTEN); + + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); +} + +static void dwc3_gadget_disable_irq(struct dwc3 *dwc) +{ + /* mask all interrupts */ + dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); +} + +static irqreturn_t dwc3_interrupt(int irq, void *_dwc); +static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc); + static int dwc3_gadget_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { @@ -1476,6 +1505,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, struct dwc3_ep *dep; unsigned long flags; int ret = 0; + int irq; u32 reg; spin_lock_irqsave(&dwc->lock, flags); @@ -1489,7 +1519,6 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc->gadget_driver = driver; - dwc->gadget.dev.driver = &driver->driver; reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); @@ -1536,6 +1565,17 @@ static int dwc3_gadget_start(struct usb_gadget *g, dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, + IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); + if (ret) { + dev_err(dwc->dev, "failed to request irq #%d --> %d\n", + irq, ret); + goto err1; + } + + dwc3_gadget_enable_irq(dwc); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; @@ -1554,14 +1594,18 @@ static int dwc3_gadget_stop(struct usb_gadget *g, { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long flags; + int irq; spin_lock_irqsave(&dwc->lock, flags); + dwc3_gadget_disable_irq(dwc); + irq = platform_get_irq(to_platform_device(dwc->dev), 0); + free_irq(irq, dwc); + __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); dwc->gadget_driver = NULL; - dwc->gadget.dev.driver = NULL; spin_unlock_irqrestore(&dwc->lock, flags); @@ -1579,14 +1623,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = { /* -------------------------------------------------------------------------- */ -static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) +static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, + u8 num, u32 direction) { struct dwc3_ep *dep; - u8 epnum; + u8 i; - INIT_LIST_HEAD(&dwc->gadget.ep_list); + for (i = 0; i < num; i++) { + u8 epnum = (i << 1) | (!!direction); - for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { dep = kzalloc(sizeof(*dep), GFP_KERNEL); if (!dep) { dev_err(dwc->dev, "can't allocate endpoint %d\n", @@ -1600,6 +1645,7 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, (epnum & 1) ? "in" : "out"); + dep->endpoint.name = dep->name; dep->direction = (epnum & 1); @@ -1630,6 +1676,27 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) return 0; } +static int dwc3_gadget_init_endpoints(struct dwc3 *dwc) +{ + int ret; + + INIT_LIST_HEAD(&dwc->gadget.ep_list); + + ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0); + if (ret < 0) { + dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n"); + return ret; + } + + ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1); + if (ret < 0) { + dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n"); + return ret; + } + + return 0; +} + static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) { struct dwc3_ep *dep; @@ -1637,6 +1704,9 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { dep = dwc->eps[epnum]; + if (!dep) + continue; + dwc3_free_trb_pool(dep); if (epnum != 0 && epnum != 1) @@ -1646,12 +1716,8 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) } } -static void dwc3_gadget_release(struct device *dev) -{ - dev_dbg(dev, "%s\n", __func__); -} - /* -------------------------------------------------------------------------- */ + static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3_trb *trb, const struct dwc3_event_depevt *event, int status) @@ -1975,6 +2041,9 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) struct dwc3_ep *dep; dep = dwc->eps[epnum]; + if (!dep) + continue; + if (!(dep->flags & DWC3_EP_ENABLED)) continue; @@ -1992,6 +2061,8 @@ static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) int ret; dep = dwc->eps[epnum]; + if (!dep) + continue; if (!(dep->flags & DWC3_EP_STALL)) continue; @@ -2091,7 +2162,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) } /* after reset -> Default State */ - dwc->dev_state = DWC3_DEFAULT_STATE; + usb_gadget_set_state(&dwc->gadget, USB_STATE_DEFAULT); /* Recent versions support automatic phy suspend and don't need this */ if (dwc->revision < DWC3_REVISION_194A) { @@ -2277,6 +2348,34 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; + unsigned int pwropt; + + /* + * WORKAROUND: DWC3 < 2.50a have an issue when configured without + * Hibernation mode enabled which would show up when device detects + * host-initiated U3 exit. + * + * In that case, device will generate a Link State Change Interrupt + * from U3 to RESUME which is only necessary if Hibernation is + * configured in. + * + * There are no functional changes due to such spurious event and we + * just need to ignore it. + * + * Refers to: + * + * STAR#9000570034 RTL: SS Resume event generated in non-Hibernation + * operational mode + */ + pwropt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1); + if ((dwc->revision < DWC3_REVISION_250A) && + (pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) { + if ((dwc->link_state == DWC3_LINK_STATE_U3) && + (next == DWC3_LINK_STATE_RESUME)) { + dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n"); + return; + } + } /* * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending @@ -2387,40 +2486,73 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } +static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) +{ + struct dwc3 *dwc = _dwc; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + int i; + + spin_lock_irqsave(&dwc->lock, flags); + + for (i = 0; i < dwc->num_event_buffers; i++) { + struct dwc3_event_buffer *evt; + int left; + + evt = dwc->ev_buffs[i]; + left = evt->count; + + if (!(evt->flags & DWC3_EVENT_PENDING)) + continue; + + while (left > 0) { + union dwc3_event event; + + event.raw = *(u32 *) (evt->buf + evt->lpos); + + dwc3_process_event_entry(dwc, &event); + + /* + * FIXME we wrap around correctly to the next entry as + * almost all entries are 4 bytes in size. There is one + * entry which has 12 bytes which is a regular entry + * followed by 8 bytes data. ATM I don't know how + * things are organized if we get next to the a + * boundary so I worry about that once we try to handle + * that. + */ + evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; + left -= 4; + + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(i), 4); + } + + evt->count = 0; + evt->flags &= ~DWC3_EVENT_PENDING; + ret = IRQ_HANDLED; + } + + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) { struct dwc3_event_buffer *evt; - int left; u32 count; + evt = dwc->ev_buffs[buf]; + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) return IRQ_NONE; - evt = dwc->ev_buffs[buf]; - left = count; - - while (left > 0) { - union dwc3_event event; - - event.raw = *(u32 *) (evt->buf + evt->lpos); + evt->count = count; + evt->flags |= DWC3_EVENT_PENDING; - dwc3_process_event_entry(dwc, &event); - /* - * XXX we wrap around correctly to the next entry as almost all - * entries are 4 bytes in size. There is one entry which has 12 - * bytes which is a regular entry followed by 8 bytes data. ATM - * I don't know how things are organized if were get next to the - * a boundary so I worry about that once we try to handle that. - */ - evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; - left -= 4; - - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); - } - - return IRQ_HANDLED; + return IRQ_WAKE_THREAD; } static irqreturn_t dwc3_interrupt(int irq, void *_dwc) @@ -2435,7 +2567,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) irqreturn_t status; status = dwc3_process_event_buf(dwc, i); - if (status == IRQ_HANDLED) + if (status == IRQ_WAKE_THREAD) ret = status; } @@ -2454,7 +2586,6 @@ int dwc3_gadget_init(struct dwc3 *dwc) { u32 reg; int ret; - int irq; dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); @@ -2488,19 +2619,10 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err3; } - dev_set_name(&dwc->gadget.dev, "gadget"); - dwc->gadget.ops = &dwc3_gadget_ops; dwc->gadget.max_speed = USB_SPEED_SUPER; dwc->gadget.speed = USB_SPEED_UNKNOWN; - dwc->gadget.dev.parent = dwc->dev; dwc->gadget.sg_supported = true; - - dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask); - - dwc->gadget.dev.dma_parms = dwc->dev->dma_parms; - dwc->gadget.dev.dma_mask = dwc->dev->dma_mask; - dwc->gadget.dev.release = dwc3_gadget_release; dwc->gadget.name = "dwc3-gadget"; /* @@ -2512,60 +2634,24 @@ int dwc3_gadget_init(struct dwc3 *dwc) if (ret) goto err4; - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - - ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, - "dwc3", dwc); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err5; - } - reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg |= DWC3_DCFG_LPM_CAP; dwc3_writel(dwc->regs, DWC3_DCFG, reg); - /* Enable all but Start and End of Frame IRQs */ - reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | - DWC3_DEVTEN_EVNTOVERFLOWEN | - DWC3_DEVTEN_CMDCMPLTEN | - DWC3_DEVTEN_ERRTICERREN | - DWC3_DEVTEN_WKUPEVTEN | - DWC3_DEVTEN_ULSTCNGEN | - DWC3_DEVTEN_CONNECTDONEEN | - DWC3_DEVTEN_USBRSTEN | - DWC3_DEVTEN_DISCONNEVTEN); - dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); - - /* automatic phy suspend only on recent versions */ + /* Enable USB2 LPM and automatic phy suspend only on recent versions */ if (dwc->revision >= DWC3_REVISION_194A) { dwc3_gadget_usb2_phy_suspend(dwc, false); dwc3_gadget_usb3_phy_suspend(dwc, false); } - ret = device_register(&dwc->gadget.dev); - if (ret) { - dev_err(dwc->dev, "failed to register gadget device\n"); - put_device(&dwc->gadget.dev); - goto err6; - } - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err7; + goto err5; } return 0; -err7: - device_unregister(&dwc->gadget.dev); - -err6: - dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); - err5: dwc3_gadget_free_endpoints(dwc); @@ -2588,15 +2674,11 @@ err0: return ret; } +/* -------------------------------------------------------------------------- */ + void dwc3_gadget_exit(struct dwc3 *dwc) { - int irq; - usb_del_gadget_udc(&dwc->gadget); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - - dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); dwc3_gadget_free_endpoints(dwc); @@ -2610,6 +2692,63 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), dwc->ctrl_req, dwc->ctrl_req_addr); +} - device_unregister(&dwc->gadget.dev); +int dwc3_gadget_prepare(struct dwc3 *dwc) +{ + if (dwc->pullups_connected) + dwc3_gadget_disable_irq(dwc); + + return 0; +} + +void dwc3_gadget_complete(struct dwc3 *dwc) +{ + if (dwc->pullups_connected) { + dwc3_gadget_enable_irq(dwc); + dwc3_gadget_run_stop(dwc, true); + } +} + +int dwc3_gadget_suspend(struct dwc3 *dwc) +{ + __dwc3_gadget_ep_disable(dwc->eps[0]); + __dwc3_gadget_ep_disable(dwc->eps[1]); + + dwc->dcfg = dwc3_readl(dwc->regs, DWC3_DCFG); + + return 0; +} + +int dwc3_gadget_resume(struct dwc3 *dwc) +{ + struct dwc3_ep *dep; + int ret; + + /* Start with SuperSpeed Default */ + dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); + + dep = dwc->eps[0]; + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); + if (ret) + goto err0; + + dep = dwc->eps[1]; + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); + if (ret) + goto err1; + + /* begin to receive SETUP packets */ + dwc->ep0state = EP0_SETUP_PHASE; + dwc3_ep0_out_start(dwc); + + dwc3_writel(dwc->regs, DWC3_DCFG, dwc->dcfg); + + return 0; + +err1: + __dwc3_gadget_ep_disable(dwc->eps[0]); + +err0: + return ret; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c7525b1cad74..83300d94a893 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -144,6 +144,7 @@ config USB_AT91 config USB_LPC32XX tristate "LPC32XX USB Peripheral Controller" depends on ARCH_LPC32XX + depends on USB_PHY select USB_ISP1301 select USB_OTG_UTILS help @@ -195,8 +196,8 @@ config USB_FUSB300 config USB_OMAP tristate "OMAP USB Device Controller" depends on ARCH_OMAP1 + depends on USB_PHY select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG - select USB_OTG_UTILS if ARCH_OMAP help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 @@ -211,7 +212,6 @@ config USB_OMAP config USB_PXA25X tristate "PXA 25x or IXP 4xx" depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX - select USB_OTG_UTILS help Intel's PXA 25x series XScale ARM-5TE processors include an integrated full speed USB 1.1 device controller. The @@ -259,8 +259,6 @@ config USB_RENESAS_USBHS_UDC config USB_PXA27X tristate "PXA 27x" - depends on ARCH_PXA && (PXA27x || PXA3xx) - select USB_OTG_UTILS help Intel's PXA 27x series XScale ARM v5TE processors include an integrated full speed USB 1.1 device controller. @@ -329,9 +327,6 @@ config USB_MV_UDC config USB_MV_U3D tristate "MARVELL PXA2128 USB 3.0 controller" - depends on CPU_MMP3 - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED help MARVELL PXA2128 Processor series include a super speed USB3.0 device controller, which support super speed USB peripheral. @@ -501,6 +496,7 @@ endmenu # composite based drivers config USB_LIBCOMPOSITE tristate + select CONFIGFS_FS depends on USB_GADGET config USB_F_ACM @@ -512,6 +508,12 @@ config USB_F_SS_LB config USB_U_SERIAL tristate +config USB_F_SERIAL + tristate + +config USB_F_OBEX + tristate + choice tristate "USB Gadget Drivers" default USB_ETH @@ -766,6 +768,8 @@ config USB_G_SERIAL depends on TTY select USB_U_SERIAL select USB_F_ACM + select USB_F_SERIAL + select USB_F_OBEX select USB_LIBCOMPOSITE help The Serial Gadget talks to the Linux-USB generic serial driver. @@ -839,6 +843,7 @@ config USB_G_NOKIA depends on PHONET select USB_LIBCOMPOSITE select USB_U_SERIAL + select USB_F_ACM help The Nokia composite gadget provides support for acm, obex and phonet in only one composite gadget driver. @@ -957,6 +962,7 @@ config USB_G_WEBCAM tristate "USB Webcam Gadget" depends on VIDEO_DEV select USB_LIBCOMPOSITE + select VIDEOBUF2_VMALLOC help The Webcam Gadget acts as a composite USB Audio and Video Class device. It provides a userspace API to process UVC control requests diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 82fb22511356..6afd16659e78 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG obj-$(CONFIG_USB_GADGET) += udc-core.o obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o libcomposite-y := usbstring.o config.o epautoconf.o -libcomposite-y += composite.o functions.o +libcomposite-y += composite.o functions.o configfs.o obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2272) += net2272.o obj-$(CONFIG_USB_NET2280) += net2280.o @@ -36,10 +36,15 @@ obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o # USB Functions -obj-$(CONFIG_USB_F_ACM) += f_acm.o -f_ss_lb-y := f_loopback.o f_sourcesink.o -obj-$(CONFIG_USB_F_SS_LB) += f_ss_lb.o +usb_f_acm-y := f_acm.o +obj-$(CONFIG_USB_F_ACM) += usb_f_acm.o +usb_f_ss_lb-y := f_loopback.o f_sourcesink.o +obj-$(CONFIG_USB_F_SS_LB) += usb_f_ss_lb.o obj-$(CONFIG_USB_U_SERIAL) += u_serial.o +usb_f_serial-y := f_serial.o +obj-$(CONFIG_USB_F_SERIAL) += usb_f_serial.o +usb_f_obex-y := f_obex.o +obj-$(CONFIG_USB_F_OBEX) += usb_f_obex.o # # USB gadget drivers diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 8f2b0e391534..4b947bb50f62 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -109,7 +109,6 @@ FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); static struct fsg_common fsg_common; /*-------------------------------------------------------------------------*/ -static unsigned char tty_line; static struct usb_function *f_acm; static struct usb_function_instance *f_acm_inst; /* @@ -117,7 +116,6 @@ static struct usb_function_instance *f_acm_inst; */ static int __init acm_ms_do_config(struct usb_configuration *c) { - struct f_serial_opts *opts; int status; if (gadget_is_otg(c->cdev->gadget)) { @@ -129,9 +127,6 @@ static int __init acm_ms_do_config(struct usb_configuration *c) if (IS_ERR(f_acm_inst)) return PTR_ERR(f_acm_inst); - opts = container_of(f_acm_inst, struct f_serial_opts, func_inst); - opts->port_num = tty_line; - f_acm = usb_get_function(f_acm_inst); if (IS_ERR(f_acm)) { status = PTR_ERR(f_acm); @@ -171,16 +166,11 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) int status; void *retp; - /* set up serial link layer */ - status = gserial_alloc_line(&tty_line); - if (status < 0) - return status; - /* set up mass storage function */ retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); if (IS_ERR(retp)) { status = PTR_ERR(retp); - goto fail0; + return PTR_ERR(retp); } /* @@ -207,8 +197,6 @@ static int __init acm_ms_bind(struct usb_composite_dev *cdev) /* error recovery */ fail1: fsg_common_put(&fsg_common); -fail0: - gserial_free_line(tty_line); return status; } @@ -216,7 +204,6 @@ static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(f_acm_inst); - gserial_free_line(tty_line); return 0; } diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 75973f33a4c8..f52dcfe8f545 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1922,7 +1922,6 @@ static int amd5536_udc_start(struct usb_gadget *g, driver->driver.bus = NULL; dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; /* Some gadget drivers use both ep0 directions. * NOTE: to gadget driver, ep0 is just one endpoint... @@ -1973,7 +1972,6 @@ static int amd5536_udc_stop(struct usb_gadget *g, shutdown(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - dev->gadget.dev.driver = NULL; dev->driver = NULL; /* set SD */ @@ -3080,7 +3078,6 @@ static void udc_pci_remove(struct pci_dev *pdev) if (dev->active) pci_disable_device(pdev); - device_unregister(&dev->gadget.dev); pci_set_drvdata(pdev, NULL); udc_remove(dev); @@ -3245,8 +3242,6 @@ static int udc_pci_probe( dev->phys_addr = resource; dev->irq = pdev->irq; dev->pdev = pdev; - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; /* general probing */ if (udc_probe(dev) == 0) @@ -3273,7 +3268,6 @@ static int udc_probe(struct udc *dev) dev->gadget.ops = &udc_ops; dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.release = gadget_release; dev->gadget.name = name; dev->gadget.max_speed = USB_SPEED_HIGH; @@ -3297,17 +3291,11 @@ static int udc_probe(struct udc *dev) "driver version: %s(for Geode5536 B1)\n", tmp); udc = dev; - retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget); + retval = usb_add_gadget_udc_release(&udc->pdev->dev, &dev->gadget, + gadget_release); if (retval) goto finished; - retval = device_register(&dev->gadget.dev); - if (retval) { - usb_del_gadget_udc(&dev->gadget); - put_device(&dev->gadget.dev); - goto finished; - } - /* timer init */ init_timer(&udc_timer); udc_timer.function = udc_timer_function; diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index f1bf32e6b8d8..6744d3b83109 100644 --- a/drivers/usb/gadget/amd5536udc.h +++ b/drivers/usb/gadget/amd5536udc.h @@ -472,7 +472,6 @@ struct udc_request { /* flags */ unsigned dma_going : 1, - dma_mapping : 1, dma_done : 1; /* phys. address */ dma_addr_t td_phys; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 45dd2929a671..a690d64217f4 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1631,7 +1631,6 @@ static int at91_start(struct usb_gadget *gadget, udc = container_of(gadget, struct at91_udc, gadget); udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; udc->gadget.dev.of_node = udc->pdev->dev.of_node; udc->enabled = 1; udc->selfpowered = 1; @@ -1652,7 +1651,6 @@ static int at91_stop(struct usb_gadget *gadget, at91_udp_write(udc, AT91_UDP_IDR, ~0); spin_unlock_irqrestore(&udc->lock, flags); - udc->gadget.dev.driver = NULL; udc->driver = NULL; DBG("unbound from %s\n", driver->driver.name); @@ -1780,13 +1778,7 @@ static int at91udc_probe(struct platform_device *pdev) DBG("clocks missing\n"); retval = -ENODEV; /* NOTE: we "know" here that refcounts on these are NOPs */ - goto fail0b; - } - - retval = device_register(&udc->gadget.dev); - if (retval < 0) { - put_device(&udc->gadget.dev); - goto fail0b; + goto fail1; } /* don't do anything until we have both gadget driver and VBUS */ @@ -1857,8 +1849,6 @@ fail3: fail2: free_irq(udc->udp_irq, udc); fail1: - device_unregister(&udc->gadget.dev); -fail0b: iounmap(udc->udp_baseaddr); fail0a: if (cpu_is_at91rm9200()) @@ -1892,8 +1882,6 @@ static int __exit at91udc_remove(struct platform_device *pdev) gpio_free(udc->board.vbus_pin); } free_irq(udc->udp_irq, udc); - device_unregister(&udc->gadget.dev); - iounmap(udc->udp_baseaddr); if (cpu_is_at91rm9200()) diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index b66130c97269..f2a970f75bfa 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -489,13 +489,8 @@ request_complete(struct usba_ep *ep, struct usba_request *req, int status) if (req->req.status == -EINPROGRESS) req->req.status = status; - if (req->mapped) { - dma_unmap_single( - &udc->pdev->dev, req->req.dma, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } + if (req->using_dma) + usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in); DBG(DBG_GADGET | DBG_REQ, "%s: req %p complete: status %d, actual %u\n", @@ -684,7 +679,6 @@ usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) return NULL; INIT_LIST_HEAD(&req->queue); - req->req.dma = DMA_ADDR_INVALID; return &req->req; } @@ -717,20 +711,11 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, return -EINVAL; } - req->using_dma = 1; - - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single( - &udc->pdev->dev, req->req.buf, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device( - &udc->pdev->dev, req->req.dma, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 0; - } + ret = usb_gadget_map_request(&udc->gadget, &req->req, ep->is_in); + if (ret) + return ret; + req->using_dma = 1; req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; @@ -1799,7 +1784,6 @@ static int atmel_usba_start(struct usb_gadget *gadget, udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); clk_enable(udc->pclk); @@ -1841,7 +1825,6 @@ static int atmel_usba_stop(struct usb_gadget *gadget, toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - udc->gadget.dev.driver = NULL; udc->driver = NULL; clk_disable(udc->hclk); @@ -1900,10 +1883,6 @@ static int __init usba_udc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", (unsigned long)fifo->start, udc->fifo); - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = pdev->dev.dma_mask; - platform_set_drvdata(pdev, udc); /* Make sure we start from a clean slate */ @@ -1962,12 +1941,6 @@ static int __init usba_udc_probe(struct platform_device *pdev) } udc->irq = irq; - ret = device_add(&udc->gadget.dev); - if (ret) { - dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); - goto err_device_add; - } - if (gpio_is_valid(pdata->vbus_pin)) { if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { udc->vbus_pin = pdata->vbus_pin; @@ -2007,9 +1980,6 @@ err_add_udc: gpio_free(udc->vbus_pin); } - device_unregister(&udc->gadget.dev); - -err_device_add: free_irq(irq, udc); err_request_irq: kfree(usba_ep); @@ -2053,8 +2023,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev) clk_put(udc->hclk); clk_put(udc->pclk); - device_unregister(&udc->gadget.dev); - return 0; } diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 9791259cbda7..d65a61851d3d 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -216,12 +216,6 @@ #define EP0_EPT_SIZE USBA_EPT_SIZE_64 #define EP0_NR_BANKS 1 -/* - * REVISIT: Try to eliminate this value. Can we rely on req->mapped to - * provide this information? - */ -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - #define FIFO_IOMEM_ID 0 #define CTRL_IOMEM_ID 1 diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index 8cc8253f1100..6e6518264c42 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -1819,7 +1819,6 @@ static int bcm63xx_udc_start(struct usb_gadget *gadget, udc->driver = driver; driver->driver.bus = NULL; - udc->gadget.dev.driver = &driver->driver; udc->gadget.dev.of_node = udc->dev->of_node; spin_unlock_irqrestore(&udc->lock, flags); @@ -1841,7 +1840,6 @@ static int bcm63xx_udc_stop(struct usb_gadget *gadget, spin_lock_irqsave(&udc->lock, flags); udc->driver = NULL; - udc->gadget.dev.driver = NULL; /* * If we switch the PHY too abruptly after dropping D+, the host @@ -2306,17 +2304,6 @@ static void bcm63xx_udc_cleanup_debugfs(struct bcm63xx_udc *udc) ***********************************************************************/ /** - * bcm63xx_udc_gadget_release - Called from device_release(). - * @dev: Unused. - * - * We get a warning if this function doesn't exist, but it's empty because - * we don't have to free any of the memory allocated with the devm_* APIs. - */ -static void bcm63xx_udc_gadget_release(struct device *dev) -{ -} - -/** * bcm63xx_udc_probe - Initialize a new instance of the UDC. * @pdev: Platform device struct from the bcm63xx BSP code. * @@ -2368,13 +2355,9 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) spin_lock_init(&udc->lock); INIT_WORK(&udc->ep0_wq, bcm63xx_ep0_process); - dev_set_name(&udc->gadget.dev, "gadget"); udc->gadget.ops = &bcm63xx_udc_ops; udc->gadget.name = dev_name(dev); - udc->gadget.dev.parent = dev; - udc->gadget.dev.release = bcm63xx_udc_gadget_release; - udc->gadget.dev.dma_mask = dev->dma_mask; if (!pd->use_fullspeed && !use_fullspeed) udc->gadget.max_speed = USB_SPEED_HIGH; @@ -2414,17 +2397,12 @@ static int bcm63xx_udc_probe(struct platform_device *pdev) } } - rc = device_register(&udc->gadget.dev); - if (rc) - goto out_uninit; - bcm63xx_udc_init_debugfs(udc); rc = usb_add_gadget_udc(dev, &udc->gadget); if (!rc) return 0; bcm63xx_udc_cleanup_debugfs(udc); - device_unregister(&udc->gadget.dev); out_uninit: bcm63xx_uninit_udc_hw(udc); return rc; @@ -2440,7 +2418,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev) bcm63xx_udc_cleanup_debugfs(udc); usb_del_gadget_udc(&udc->gadget); - device_unregister(&udc->gadget.dev); BUG_ON(udc->driver); platform_set_drvdata(pdev, NULL); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index a7d6f7026757..2c5255182769 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -103,18 +103,16 @@ static struct usb_gadget_strings *dev_strings[] = { }; static u8 hostaddr[ETH_ALEN]; - +static struct eth_dev *the_dev; /*-------------------------------------------------------------------------*/ static struct usb_function *f_acm; static struct usb_function_instance *fi_serial; -static unsigned char tty_line; /* * We _always_ have both CDC ECM and CDC ACM functions. */ static int __init cdc_do_config(struct usb_configuration *c) { - struct f_serial_opts *opts; int status; if (gadget_is_otg(c->cdev->gadget)) { @@ -122,7 +120,7 @@ static int __init cdc_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - status = ecm_bind_config(c, hostaddr); + status = ecm_bind_config(c, hostaddr, the_dev); if (status < 0) return status; @@ -130,12 +128,11 @@ static int __init cdc_do_config(struct usb_configuration *c) if (IS_ERR(fi_serial)) return PTR_ERR(fi_serial); - opts = container_of(fi_serial, struct f_serial_opts, func_inst); - opts->port_num = tty_line; - f_acm = usb_get_function(fi_serial); - if (IS_ERR(f_acm)) + if (IS_ERR(f_acm)) { + status = PTR_ERR(f_acm); goto err_func_acm; + } status = usb_add_function(c, f_acm); if (status) @@ -169,14 +166,9 @@ static int __init cdc_bind(struct usb_composite_dev *cdev) } /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; - - /* set up serial link layer */ - status = gserial_alloc_line(&tty_line); - if (status < 0) - goto fail0; + the_dev = gether_setup(cdev->gadget, hostaddr); + if (IS_ERR(the_dev)) + return PTR_ERR(the_dev); /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -200,9 +192,7 @@ static int __init cdc_bind(struct usb_composite_dev *cdev) return 0; fail1: - gserial_free_line(tty_line); -fail0: - gether_cleanup(); + gether_cleanup(the_dev); return status; } @@ -210,8 +200,7 @@ static int __exit cdc_unbind(struct usb_composite_dev *cdev) { usb_put_function(f_acm); usb_put_function_instance(fi_serial); - gserial_free_line(tty_line); - gether_cleanup(); + gether_cleanup(the_dev); return 0; } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c0d62b278610..55f4df60f327 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) kfree(cdev->req->buf); usb_ep_free_request(cdev->gadget->ep0, cdev->req); } + cdev->next_string_id = 0; device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); } diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c new file mode 100644 index 000000000000..3d5cfc9c2c78 --- /dev/null +++ b/drivers/usb/gadget/configfs.c @@ -0,0 +1,1003 @@ +#include <linux/configfs.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/usb/composite.h> +#include <linux/usb/gadget_configfs.h> + +int check_user_usb_string(const char *name, + struct usb_gadget_strings *stringtab_dev) +{ + unsigned primary_lang; + unsigned sub_lang; + u16 num; + int ret; + + ret = kstrtou16(name, 0, &num); + if (ret) + return ret; + + primary_lang = num & 0x3ff; + sub_lang = num >> 10; + + /* simple sanity check for valid langid */ + switch (primary_lang) { + case 0: + case 0x62 ... 0xfe: + case 0x100 ... 0x3ff: + return -EINVAL; + } + if (!sub_lang) + return -EINVAL; + + stringtab_dev->language = num; + return 0; +} + +#define MAX_NAME_LEN 40 +#define MAX_USB_STRING_LANGS 2 + +struct gadget_info { + struct config_group group; + struct config_group functions_group; + struct config_group configs_group; + struct config_group strings_group; + struct config_group *default_groups[4]; + + struct mutex lock; + struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; + struct list_head string_list; + struct list_head available_func; + + const char *udc_name; +#ifdef CONFIG_USB_OTG + struct usb_otg_descriptor otg; +#endif + struct usb_composite_driver composite; + struct usb_composite_dev cdev; +}; + +struct config_usb_cfg { + struct config_group group; + struct config_group strings_group; + struct config_group *default_groups[2]; + struct list_head string_list; + struct usb_configuration c; + struct list_head func_list; + struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; +}; + +struct gadget_strings { + struct usb_gadget_strings stringtab_dev; + struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; + char *manufacturer; + char *product; + char *serialnumber; + + struct config_group group; + struct list_head list; +}; + +struct gadget_config_name { + struct usb_gadget_strings stringtab_dev; + struct usb_string strings; + char *configuration; + + struct config_group group; + struct list_head list; +}; + +static int usb_string_copy(const char *s, char **s_copy) +{ + int ret; + char *str; + char *copy = *s_copy; + ret = strlen(s); + if (ret > 126) + return -EOVERFLOW; + + str = kstrdup(s, GFP_KERNEL); + if (!str) + return -ENOMEM; + if (str[ret - 1] == '\n') + str[ret - 1] = '\0'; + kfree(copy); + *s_copy = str; + return 0; +} + +CONFIGFS_ATTR_STRUCT(gadget_info); +CONFIGFS_ATTR_STRUCT(config_usb_cfg); + +#define GI_DEVICE_DESC_ITEM_ATTR(name) \ + static struct gadget_info_attribute gadget_cdev_desc_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ + gadget_dev_desc_##name##_show, \ + gadget_dev_desc_##name##_store) + +#define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \ + static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ + char *page) \ +{ \ + return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \ +} + +#define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \ + static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ + char *page) \ +{ \ + return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \ +} + + +#define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ + static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ + const char *page, size_t len) \ +{ \ + u8 val; \ + int ret; \ + ret = kstrtou8(page, 0, &val); \ + if (ret) \ + return ret; \ + gi->cdev.desc._name = val; \ + return len; \ +} + +#define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \ + static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ + const char *page, size_t len) \ +{ \ + u16 val; \ + int ret; \ + ret = kstrtou16(page, 0, &val); \ + if (ret) \ + return ret; \ + gi->cdev.desc._name = cpu_to_le16p(&val); \ + return len; \ +} + +#define GI_DEVICE_DESC_SIMPLE_RW(_name, _type) \ + GI_DEVICE_DESC_SIMPLE_R_##_type(_name) \ + GI_DEVICE_DESC_SIMPLE_W_##_type(_name) + +GI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB); +GI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8); +GI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8); +GI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8); +GI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8); +GI_DEVICE_DESC_SIMPLE_RW(idVendor, u16); +GI_DEVICE_DESC_SIMPLE_RW(idProduct, u16); +GI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice); + +static ssize_t is_valid_bcd(u16 bcd_val) +{ + if ((bcd_val & 0xf) > 9) + return -EINVAL; + if (((bcd_val >> 4) & 0xf) > 9) + return -EINVAL; + if (((bcd_val >> 8) & 0xf) > 9) + return -EINVAL; + if (((bcd_val >> 12) & 0xf) > 9) + return -EINVAL; + return 0; +} + +static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, + const char *page, size_t len) +{ + u16 bcdDevice; + int ret; + + ret = kstrtou16(page, 0, &bcdDevice); + if (ret) + return ret; + ret = is_valid_bcd(bcdDevice); + if (ret) + return ret; + + gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); + return len; +} + +static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, + const char *page, size_t len) +{ + u16 bcdUSB; + int ret; + + ret = kstrtou16(page, 0, &bcdUSB); + if (ret) + return ret; + ret = is_valid_bcd(bcdUSB); + if (ret) + return ret; + + gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB); + return len; +} + +static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) +{ + return sprintf(page, "%s\n", gi->udc_name ?: ""); +} + +static int unregister_gadget(struct gadget_info *gi) +{ + int ret; + + if (!gi->udc_name) + return -ENODEV; + + ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver); + if (ret) + return ret; + kfree(gi->udc_name); + gi->udc_name = NULL; + return 0; +} + +static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, + const char *page, size_t len) +{ + char *name; + int ret; + + name = kstrdup(page, GFP_KERNEL); + if (!name) + return -ENOMEM; + if (name[len - 1] == '\n') + name[len - 1] = '\0'; + + mutex_lock(&gi->lock); + + if (!strlen(name)) { + ret = unregister_gadget(gi); + if (ret) + goto err; + } else { + if (gi->udc_name) { + ret = -EBUSY; + goto err; + } + ret = udc_attach_driver(name, &gi->composite.gadget_driver); + if (ret) + goto err; + gi->udc_name = name; + } + mutex_unlock(&gi->lock); + return len; +err: + kfree(name); + mutex_unlock(&gi->lock); + return ret; +} + +GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass); +GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass); +GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol); +GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0); +GI_DEVICE_DESC_ITEM_ATTR(idVendor); +GI_DEVICE_DESC_ITEM_ATTR(idProduct); +GI_DEVICE_DESC_ITEM_ATTR(bcdDevice); +GI_DEVICE_DESC_ITEM_ATTR(bcdUSB); +GI_DEVICE_DESC_ITEM_ATTR(UDC); + +static struct configfs_attribute *gadget_root_attrs[] = { + &gadget_cdev_desc_bDeviceClass.attr, + &gadget_cdev_desc_bDeviceSubClass.attr, + &gadget_cdev_desc_bDeviceProtocol.attr, + &gadget_cdev_desc_bMaxPacketSize0.attr, + &gadget_cdev_desc_idVendor.attr, + &gadget_cdev_desc_idProduct.attr, + &gadget_cdev_desc_bcdDevice.attr, + &gadget_cdev_desc_bcdUSB.attr, + &gadget_cdev_desc_UDC.attr, + NULL, +}; + +static inline struct gadget_info *to_gadget_info(struct config_item *item) +{ + return container_of(to_config_group(item), struct gadget_info, group); +} + +static inline struct gadget_strings *to_gadget_strings(struct config_item *item) +{ + return container_of(to_config_group(item), struct gadget_strings, + group); +} + +static inline struct gadget_config_name *to_gadget_config_name( + struct config_item *item) +{ + return container_of(to_config_group(item), struct gadget_config_name, + group); +} + +static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) +{ + return container_of(to_config_group(item), struct config_usb_cfg, + group); +} + +static inline struct usb_function_instance *to_usb_function_instance( + struct config_item *item) +{ + return container_of(to_config_group(item), + struct usb_function_instance, group); +} + +static void gadget_info_attr_release(struct config_item *item) +{ + struct gadget_info *gi = to_gadget_info(item); + + WARN_ON(!list_empty(&gi->cdev.configs)); + WARN_ON(!list_empty(&gi->string_list)); + WARN_ON(!list_empty(&gi->available_func)); + kfree(gi->composite.gadget_driver.function); + kfree(gi); +} + +CONFIGFS_ATTR_OPS(gadget_info); + +static struct configfs_item_operations gadget_root_item_ops = { + .release = gadget_info_attr_release, + .show_attribute = gadget_info_attr_show, + .store_attribute = gadget_info_attr_store, +}; + +static void gadget_config_attr_release(struct config_item *item) +{ + struct config_usb_cfg *cfg = to_config_usb_cfg(item); + + WARN_ON(!list_empty(&cfg->c.functions)); + list_del(&cfg->c.list); + kfree(cfg->c.label); + kfree(cfg); +} + +static int config_usb_cfg_link( + struct config_item *usb_cfg_ci, + struct config_item *usb_func_ci) +{ + struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); + struct usb_composite_dev *cdev = cfg->c.cdev; + struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + + struct config_group *group = to_config_group(usb_func_ci); + struct usb_function_instance *fi = container_of(group, + struct usb_function_instance, group); + struct usb_function_instance *a_fi; + struct usb_function *f; + int ret; + + mutex_lock(&gi->lock); + /* + * Make sure this function is from within our _this_ gadget and not + * from another gadget or a random directory. + * Also a function instance can only be linked once. + */ + list_for_each_entry(a_fi, &gi->available_func, cfs_list) { + if (a_fi == fi) + break; + } + if (a_fi != fi) { + ret = -EINVAL; + goto out; + } + + list_for_each_entry(f, &cfg->func_list, list) { + if (f->fi == fi) { + ret = -EEXIST; + goto out; + } + } + + f = usb_get_function(fi); + if (IS_ERR(f)) { + ret = PTR_ERR(f); + goto out; + } + + /* stash the function until we bind it to the gadget */ + list_add_tail(&f->list, &cfg->func_list); + ret = 0; +out: + mutex_unlock(&gi->lock); + return ret; +} + +static int config_usb_cfg_unlink( + struct config_item *usb_cfg_ci, + struct config_item *usb_func_ci) +{ + struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); + struct usb_composite_dev *cdev = cfg->c.cdev; + struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + + struct config_group *group = to_config_group(usb_func_ci); + struct usb_function_instance *fi = container_of(group, + struct usb_function_instance, group); + struct usb_function *f; + + /* + * ideally I would like to forbid to unlink functions while a gadget is + * bound to an UDC. Since this isn't possible at the moment, we simply + * force an unbind, the function is available here and then we can + * remove the function. + */ + mutex_lock(&gi->lock); + if (gi->udc_name) + unregister_gadget(gi); + WARN_ON(gi->udc_name); + + list_for_each_entry(f, &cfg->func_list, list) { + if (f->fi == fi) { + list_del(&f->list); + usb_put_function(f); + mutex_unlock(&gi->lock); + return 0; + } + } + mutex_unlock(&gi->lock); + WARN(1, "Unable to locate function to unbind\n"); + return 0; +} + +CONFIGFS_ATTR_OPS(config_usb_cfg); + +static struct configfs_item_operations gadget_config_item_ops = { + .release = gadget_config_attr_release, + .show_attribute = config_usb_cfg_attr_show, + .store_attribute = config_usb_cfg_attr_store, + .allow_link = config_usb_cfg_link, + .drop_link = config_usb_cfg_unlink, +}; + + +static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg, + char *page) +{ + return sprintf(page, "%u\n", cfg->c.MaxPower); +} + +static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg, + const char *page, size_t len) +{ + u16 val; + int ret; + ret = kstrtou16(page, 0, &val); + if (ret) + return ret; + if (DIV_ROUND_UP(val, 8) > 0xff) + return -ERANGE; + cfg->c.MaxPower = val; + return len; +} + +static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg, + char *page) +{ + return sprintf(page, "0x%02x\n", cfg->c.bmAttributes); +} + +static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, + const char *page, size_t len) +{ + u8 val; + int ret; + ret = kstrtou8(page, 0, &val); + if (ret) + return ret; + if (!(val & USB_CONFIG_ATT_ONE)) + return -EINVAL; + if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER | + USB_CONFIG_ATT_WAKEUP)) + return -EINVAL; + cfg->c.bmAttributes = val; + return len; +} + +#define CFG_CONFIG_DESC_ITEM_ATTR(name) \ + static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \ + __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ + gadget_config_desc_##name##_show, \ + gadget_config_desc_##name##_store) + +CFG_CONFIG_DESC_ITEM_ATTR(MaxPower); +CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes); + +static struct configfs_attribute *gadget_config_attrs[] = { + &gadget_usb_cfg_MaxPower.attr, + &gadget_usb_cfg_bmAttributes.attr, + NULL, +}; + +static struct config_item_type gadget_config_type = { + .ct_item_ops = &gadget_config_item_ops, + .ct_attrs = gadget_config_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_item_type gadget_root_type = { + .ct_item_ops = &gadget_root_item_ops, + .ct_attrs = gadget_root_attrs, + .ct_owner = THIS_MODULE, +}; + +static void composite_init_dev(struct usb_composite_dev *cdev) +{ + spin_lock_init(&cdev->lock); + INIT_LIST_HEAD(&cdev->configs); + INIT_LIST_HEAD(&cdev->gstrings); +} + +static struct config_group *function_make( + struct config_group *group, + const char *name) +{ + struct gadget_info *gi; + struct usb_function_instance *fi; + char buf[MAX_NAME_LEN]; + char *func_name; + char *instance_name; + int ret; + + ret = snprintf(buf, MAX_NAME_LEN, "%s", name); + if (ret >= MAX_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + func_name = buf; + instance_name = strchr(func_name, '.'); + if (!instance_name) { + pr_err("Unable to locate . in FUNC.INSTANCE\n"); + return ERR_PTR(-EINVAL); + } + *instance_name = '\0'; + instance_name++; + + fi = usb_get_function_instance(func_name); + if (IS_ERR(fi)) + return ERR_PTR(PTR_ERR(fi)); + + ret = config_item_set_name(&fi->group.cg_item, name); + if (ret) { + usb_put_function_instance(fi); + return ERR_PTR(ret); + } + + gi = container_of(group, struct gadget_info, functions_group); + + mutex_lock(&gi->lock); + list_add_tail(&fi->cfs_list, &gi->available_func); + mutex_unlock(&gi->lock); + return &fi->group; +} + +static void function_drop( + struct config_group *group, + struct config_item *item) +{ + struct usb_function_instance *fi = to_usb_function_instance(item); + struct gadget_info *gi; + + gi = container_of(group, struct gadget_info, functions_group); + + mutex_lock(&gi->lock); + list_del(&fi->cfs_list); + mutex_unlock(&gi->lock); + config_item_put(item); +} + +static struct configfs_group_operations functions_ops = { + .make_group = &function_make, + .drop_item = &function_drop, +}; + +static struct config_item_type functions_type = { + .ct_group_ops = &functions_ops, + .ct_owner = THIS_MODULE, +}; + +CONFIGFS_ATTR_STRUCT(gadget_config_name); +GS_STRINGS_RW(gadget_config_name, configuration); + +static struct configfs_attribute *gadget_config_name_langid_attrs[] = { + &gadget_config_name_configuration.attr, + NULL, +}; + +static void gadget_config_name_attr_release(struct config_item *item) +{ + struct gadget_config_name *cn = to_gadget_config_name(item); + + kfree(cn->configuration); + + list_del(&cn->list); + kfree(cn); +} + +USB_CONFIG_STRING_RW_OPS(gadget_config_name); +USB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg); + +static struct config_group *config_desc_make( + struct config_group *group, + const char *name) +{ + struct gadget_info *gi; + struct config_usb_cfg *cfg; + char buf[MAX_NAME_LEN]; + char *num_str; + u8 num; + int ret; + + gi = container_of(group, struct gadget_info, configs_group); + ret = snprintf(buf, MAX_NAME_LEN, "%s", name); + if (ret >= MAX_NAME_LEN) + return ERR_PTR(-ENAMETOOLONG); + + num_str = strchr(buf, '.'); + if (!num_str) { + pr_err("Unable to locate . in name.bConfigurationValue\n"); + return ERR_PTR(-EINVAL); + } + + *num_str = '\0'; + num_str++; + + if (!strlen(buf)) + return ERR_PTR(-EINVAL); + + ret = kstrtou8(num_str, 0, &num); + if (ret) + return ERR_PTR(ret); + + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return ERR_PTR(-ENOMEM); + cfg->c.label = kstrdup(buf, GFP_KERNEL); + if (!cfg->c.label) { + ret = -ENOMEM; + goto err; + } + cfg->c.bConfigurationValue = num; + cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW; + cfg->c.bmAttributes = USB_CONFIG_ATT_ONE; + INIT_LIST_HEAD(&cfg->string_list); + INIT_LIST_HEAD(&cfg->func_list); + + cfg->group.default_groups = cfg->default_groups; + cfg->default_groups[0] = &cfg->strings_group; + + config_group_init_type_name(&cfg->group, name, + &gadget_config_type); + config_group_init_type_name(&cfg->strings_group, "strings", + &gadget_config_name_strings_type); + + ret = usb_add_config_only(&gi->cdev, &cfg->c); + if (ret) + goto err; + + return &cfg->group; +err: + kfree(cfg->c.label); + kfree(cfg); + return ERR_PTR(ret); +} + +static void config_desc_drop( + struct config_group *group, + struct config_item *item) +{ + config_item_put(item); +} + +static struct configfs_group_operations config_desc_ops = { + .make_group = &config_desc_make, + .drop_item = &config_desc_drop, +}; + +static struct config_item_type config_desc_type = { + .ct_group_ops = &config_desc_ops, + .ct_owner = THIS_MODULE, +}; + +CONFIGFS_ATTR_STRUCT(gadget_strings); +GS_STRINGS_RW(gadget_strings, manufacturer); +GS_STRINGS_RW(gadget_strings, product); +GS_STRINGS_RW(gadget_strings, serialnumber); + +static struct configfs_attribute *gadget_strings_langid_attrs[] = { + &gadget_strings_manufacturer.attr, + &gadget_strings_product.attr, + &gadget_strings_serialnumber.attr, + NULL, +}; + +static void gadget_strings_attr_release(struct config_item *item) +{ + struct gadget_strings *gs = to_gadget_strings(item); + + kfree(gs->manufacturer); + kfree(gs->product); + kfree(gs->serialnumber); + + list_del(&gs->list); + kfree(gs); +} + +USB_CONFIG_STRING_RW_OPS(gadget_strings); +USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); + +static int configfs_do_nothing(struct usb_composite_dev *cdev) +{ + WARN_ON(1); + return -EINVAL; +} + +int composite_dev_prepare(struct usb_composite_driver *composite, + struct usb_composite_dev *dev); + +static void purge_configs_funcs(struct gadget_info *gi) +{ + struct usb_configuration *c; + + list_for_each_entry(c, &gi->cdev.configs, list) { + struct usb_function *f, *tmp; + struct config_usb_cfg *cfg; + + cfg = container_of(c, struct config_usb_cfg, c); + + list_for_each_entry_safe(f, tmp, &c->functions, list) { + + list_move_tail(&f->list, &cfg->func_list); + if (f->unbind) { + dev_err(&gi->cdev.gadget->dev, "unbind function" + " '%s'/%p\n", f->name, f); + f->unbind(c, f); + } + } + c->next_interface_id = 0; + c->superspeed = 0; + c->highspeed = 0; + c->fullspeed = 0; + } +} + +static int configfs_composite_bind(struct usb_gadget *gadget, + struct usb_gadget_driver *gdriver) +{ + struct usb_composite_driver *composite = to_cdriver(gdriver); + struct gadget_info *gi = container_of(composite, + struct gadget_info, composite); + struct usb_composite_dev *cdev = &gi->cdev; + struct usb_configuration *c; + struct usb_string *s; + unsigned i; + int ret; + + /* the gi->lock is hold by the caller */ + cdev->gadget = gadget; + set_gadget_data(gadget, cdev); + ret = composite_dev_prepare(composite, cdev); + if (ret) + return ret; + /* and now the gadget bind */ + ret = -EINVAL; + + if (list_empty(&gi->cdev.configs)) { + pr_err("Need atleast one configuration in %s.\n", + gi->composite.name); + goto err_comp_cleanup; + } + + + list_for_each_entry(c, &gi->cdev.configs, list) { + struct config_usb_cfg *cfg; + + cfg = container_of(c, struct config_usb_cfg, c); + if (list_empty(&cfg->func_list)) { + pr_err("Config %s/%d of %s needs atleast one function.\n", + c->label, c->bConfigurationValue, + gi->composite.name); + goto err_comp_cleanup; + } + } + + /* init all strings */ + if (!list_empty(&gi->string_list)) { + struct gadget_strings *gs; + + i = 0; + list_for_each_entry(gs, &gi->string_list, list) { + + gi->gstrings[i] = &gs->stringtab_dev; + gs->stringtab_dev.strings = gs->strings; + gs->strings[USB_GADGET_MANUFACTURER_IDX].s = + gs->manufacturer; + gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product; + gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber; + i++; + } + gi->gstrings[i] = NULL; + s = usb_gstrings_attach(&gi->cdev, gi->gstrings, + USB_GADGET_FIRST_AVAIL_IDX); + if (IS_ERR(s)) + goto err_comp_cleanup; + + gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id; + gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id; + gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; + } + + /* Go through all configs, attach all functions */ + list_for_each_entry(c, &gi->cdev.configs, list) { + struct config_usb_cfg *cfg; + struct usb_function *f; + struct usb_function *tmp; + struct gadget_config_name *cn; + + cfg = container_of(c, struct config_usb_cfg, c); + if (!list_empty(&cfg->string_list)) { + i = 0; + list_for_each_entry(cn, &cfg->string_list, list) { + cfg->gstrings[i] = &cn->stringtab_dev; + cn->stringtab_dev.strings = &cn->strings; + cn->strings.s = cn->configuration; + i++; + } + cfg->gstrings[i] = NULL; + s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1); + if (IS_ERR(s)) + goto err_comp_cleanup; + c->iConfiguration = s[0].id; + } + + list_for_each_entry_safe(f, tmp, &cfg->func_list, list) { + list_del(&f->list); + ret = usb_add_function(c, f); + if (ret) + goto err_purge_funcs; + } + usb_ep_autoconfig_reset(cdev->gadget); + } + usb_ep_autoconfig_reset(cdev->gadget); + return 0; + +err_purge_funcs: + purge_configs_funcs(gi); +err_comp_cleanup: + composite_dev_cleanup(cdev); + return ret; +} + +static void configfs_composite_unbind(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev; + struct gadget_info *gi; + + /* the gi->lock is hold by the caller */ + + cdev = get_gadget_data(gadget); + gi = container_of(cdev, struct gadget_info, cdev); + + purge_configs_funcs(gi); + composite_dev_cleanup(cdev); + usb_ep_autoconfig_reset(cdev->gadget); + cdev->gadget = NULL; + set_gadget_data(gadget, NULL); +} + +static const struct usb_gadget_driver configfs_driver_template = { + .bind = configfs_composite_bind, + .unbind = configfs_composite_unbind, + + .setup = composite_setup, + .disconnect = composite_disconnect, + + .max_speed = USB_SPEED_SUPER, + .driver = { + .owner = THIS_MODULE, + .name = "configfs-gadget", + }, +}; + +static struct config_group *gadgets_make( + struct config_group *group, + const char *name) +{ + struct gadget_info *gi; + + gi = kzalloc(sizeof(*gi), GFP_KERNEL); + if (!gi) + return ERR_PTR(-ENOMEM); + + gi->group.default_groups = gi->default_groups; + gi->group.default_groups[0] = &gi->functions_group; + gi->group.default_groups[1] = &gi->configs_group; + gi->group.default_groups[2] = &gi->strings_group; + + config_group_init_type_name(&gi->functions_group, "functions", + &functions_type); + config_group_init_type_name(&gi->configs_group, "configs", + &config_desc_type); + config_group_init_type_name(&gi->strings_group, "strings", + &gadget_strings_strings_type); + + gi->composite.bind = configfs_do_nothing; + gi->composite.unbind = configfs_do_nothing; + gi->composite.suspend = NULL; + gi->composite.resume = NULL; + gi->composite.max_speed = USB_SPEED_SUPER; + + mutex_init(&gi->lock); + INIT_LIST_HEAD(&gi->string_list); + INIT_LIST_HEAD(&gi->available_func); + + composite_init_dev(&gi->cdev); + gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE; + gi->cdev.desc.bDescriptorType = USB_DT_DEVICE; + gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice()); + + gi->composite.gadget_driver = configfs_driver_template; + + gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL); + gi->composite.name = gi->composite.gadget_driver.function; + + if (!gi->composite.gadget_driver.function) + goto err; + +#ifdef CONFIG_USB_OTG + gi->otg.bLength = sizeof(struct usb_otg_descriptor); + gi->otg.bDescriptorType = USB_DT_OTG; + gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP; +#endif + + config_group_init_type_name(&gi->group, name, + &gadget_root_type); + return &gi->group; +err: + kfree(gi); + return ERR_PTR(-ENOMEM); +} + +static void gadgets_drop(struct config_group *group, struct config_item *item) +{ + config_item_put(item); +} + +static struct configfs_group_operations gadgets_ops = { + .make_group = &gadgets_make, + .drop_item = &gadgets_drop, +}; + +static struct config_item_type gadgets_type = { + .ct_group_ops = &gadgets_ops, + .ct_owner = THIS_MODULE, +}; + +static struct configfs_subsystem gadget_subsys = { + .su_group = { + .cg_item = { + .ci_namebuf = "usb_gadget", + .ci_type = &gadgets_type, + }, + }, + .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex), +}; + +static int __init gadget_cfs_init(void) +{ + int ret; + + config_group_init(&gadget_subsys.su_group); + + ret = configfs_register_subsystem(&gadget_subsys); + return ret; +} +module_init(gadget_cfs_init); + +static void __exit gadget_cfs_exit(void) +{ + configfs_unregister_subsystem(&gadget_subsys); +} +module_exit(gadget_cfs_exit); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 8cf0c0f6fa1f..a792e322f4f1 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -912,7 +912,6 @@ static int dummy_udc_start(struct usb_gadget *g, dum->devstatus = 0; dum->driver = driver; - dum->gadget.dev.driver = &driver->driver; dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); return 0; @@ -927,7 +926,6 @@ static int dummy_udc_stop(struct usb_gadget *g, dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", driver->driver.name); - dum->gadget.dev.driver = NULL; dum->driver = NULL; return 0; @@ -937,11 +935,6 @@ static int dummy_udc_stop(struct usb_gadget *g, /* The gadget structure is stored inside the hcd structure and will be * released along with it. */ -static void dummy_gadget_release(struct device *dev) -{ - return; -} - static void init_dummy_udc_hw(struct dummy *dum) { int i; @@ -984,15 +977,7 @@ static int dummy_udc_probe(struct platform_device *pdev) dum->gadget.ops = &dummy_ops; dum->gadget.max_speed = USB_SPEED_SUPER; - dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; - dum->gadget.dev.release = dummy_gadget_release; - rc = device_register(&dum->gadget.dev); - if (rc < 0) { - put_device(&dum->gadget.dev); - return rc; - } - init_dummy_udc_hw(dum); rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); @@ -1008,7 +993,6 @@ static int dummy_udc_probe(struct platform_device *pdev) err_dev: usb_del_gadget_udc(&dum->gadget); err_udc: - device_unregister(&dum->gadget.dev); return rc; } @@ -1019,7 +1003,6 @@ static int dummy_udc_remove(struct platform_device *pdev) usb_del_gadget_udc(&dum->gadget); platform_set_drvdata(pdev, NULL); device_remove_file(&dum->gadget.dev, &dev_attr_function); - device_unregister(&dum->gadget.dev); return 0; } @@ -1923,7 +1906,7 @@ done: } /* usb 3.0 root hub device descriptor */ -struct { +static struct { struct usb_bos_descriptor bos; struct usb_ss_cap_descriptor ss_cap; } __packed usb3_bos_desc = { diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 18c3f423706e..56c8ecae9bc3 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -207,7 +207,7 @@ static struct usb_gadget_strings *dev_strings[] = { }; static u8 hostaddr[ETH_ALEN]; - +static struct eth_dev *the_dev; /*-------------------------------------------------------------------------*/ /* @@ -224,7 +224,7 @@ static int __init rndis_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return rndis_bind_config(c, hostaddr); + return rndis_bind_config(c, hostaddr, the_dev); } static struct usb_configuration rndis_config_driver = { @@ -257,11 +257,11 @@ static int __init eth_do_config(struct usb_configuration *c) } if (use_eem) - return eem_bind_config(c); + return eem_bind_config(c, the_dev); else if (can_support_ecm(c->cdev->gadget)) - return ecm_bind_config(c, hostaddr); + return ecm_bind_config(c, hostaddr, the_dev); else - return geth_bind_config(c, hostaddr); + return geth_bind_config(c, hostaddr, the_dev); } static struct usb_configuration eth_config_driver = { @@ -279,9 +279,9 @@ static int __init eth_bind(struct usb_composite_dev *cdev) int status; /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; + the_dev = gether_setup(cdev->gadget, hostaddr); + if (IS_ERR(the_dev)) + return PTR_ERR(the_dev); /* set up main config label and device descriptor */ if (use_eem) { @@ -338,13 +338,13 @@ static int __init eth_bind(struct usb_composite_dev *cdev) return 0; fail: - gether_cleanup(); + gether_cleanup(the_dev); return status; } static int __exit eth_unbind(struct usb_composite_dev *cdev) { - gether_cleanup(); + gether_cleanup(the_dev); return 0; } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 1ae180baa597..4b7e33e5d9c6 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -715,13 +715,31 @@ fail: return status; } -static struct f_acm *acm_alloc_basic_func(void) +static void acm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + acm_string_defs[0].id = 0; + usb_free_all_descriptors(f); + if (acm->notify_req) + gs_free_req(acm->notify, acm->notify_req); +} + +static void acm_free_func(struct usb_function *f) +{ + struct f_acm *acm = func_to_acm(f); + + kfree(acm); +} + +static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) { - struct f_acm *acm; + struct f_serial_opts *opts; + struct f_acm *acm; acm = kzalloc(sizeof(*acm), GFP_KERNEL); if (!acm) - return NULL; + return ERR_PTR(-ENOMEM); spin_lock_init(&acm->lock); @@ -730,109 +748,100 @@ static struct f_acm *acm_alloc_basic_func(void) acm->port.send_break = acm_send_break; acm->port.func.name = "acm"; + acm->port.func.strings = acm_strings; /* descriptors are per-instance copies */ acm->port.func.bind = acm_bind; acm->port.func.set_alt = acm_set_alt; acm->port.func.setup = acm_setup; acm->port.func.disable = acm_disable; - return acm; + opts = container_of(fi, struct f_serial_opts, func_inst); + acm->port_num = opts->port_num; + acm->port.func.unbind = acm_unbind; + acm->port.func.free_func = acm_free_func; + + return &acm->port.func; } -#ifdef USB_FACM_INCLUDED -static void -acm_old_unbind(struct usb_configuration *c, struct usb_function *f) +static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) { - struct f_acm *acm = func_to_acm(f); - - usb_free_all_descriptors(f); - if (acm->notify_req) - gs_free_req(acm->notify, acm->notify_req); - kfree(acm); + return container_of(to_config_group(item), struct f_serial_opts, + func_inst.group); } -/** - * acm_bind_config - add a CDC ACM function to a configuration - * @c: the configuration to support the CDC ACM instance - * @port_num: /dev/ttyGS* port this interface will use - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - */ -int acm_bind_config(struct usb_configuration *c, u8 port_num) +CONFIGFS_ATTR_STRUCT(f_serial_opts); +static ssize_t f_acm_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) { - struct f_acm *acm; - int status; - - /* allocate and initialize one new instance */ - acm = acm_alloc_basic_func(); - if (!acm) - return -ENOMEM; - - acm->port_num = port_num; - acm->port.func.unbind = acm_old_unbind; - - status = usb_add_function(c, &acm->port.func); - if (status) - kfree(acm); - return status; + struct f_serial_opts *opts = to_f_serial_opts(item); + struct f_serial_opts_attribute *f_serial_opts_attr = + container_of(attr, struct f_serial_opts_attribute, attr); + ssize_t ret = 0; + + if (f_serial_opts_attr->show) + ret = f_serial_opts_attr->show(opts, page); + return ret; } -#else - -static void acm_unbind(struct usb_configuration *c, struct usb_function *f) +static void acm_attr_release(struct config_item *item) { - struct f_acm *acm = func_to_acm(f); + struct f_serial_opts *opts = to_f_serial_opts(item); - acm_string_defs[0].id = 0; - usb_free_all_descriptors(f); - if (acm->notify_req) - gs_free_req(acm->notify, acm->notify_req); + usb_put_function_instance(&opts->func_inst); } -static void acm_free_func(struct usb_function *f) -{ - struct f_acm *acm = func_to_acm(f); +static struct configfs_item_operations acm_item_ops = { + .release = acm_attr_release, + .show_attribute = f_acm_attr_show, +}; - kfree(acm); +static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page) +{ + return sprintf(page, "%u\n", opts->port_num); } -static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) -{ - struct f_serial_opts *opts; - struct f_acm *acm; +static struct f_serial_opts_attribute f_acm_port_num = + __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show); - acm = acm_alloc_basic_func(); - if (!acm) - return ERR_PTR(-ENOMEM); - opts = container_of(fi, struct f_serial_opts, func_inst); - acm->port_num = opts->port_num; - acm->port.func.unbind = acm_unbind; - acm->port.func.free_func = acm_free_func; +static struct configfs_attribute *acm_attrs[] = { + &f_acm_port_num.attr, + NULL, +}; - return &acm->port.func; -} +static struct config_item_type acm_func_type = { + .ct_item_ops = &acm_item_ops, + .ct_attrs = acm_attrs, + .ct_owner = THIS_MODULE, +}; static void acm_free_instance(struct usb_function_instance *fi) { struct f_serial_opts *opts; opts = container_of(fi, struct f_serial_opts, func_inst); + gserial_free_line(opts->port_num); kfree(opts); } static struct usb_function_instance *acm_alloc_instance(void) { struct f_serial_opts *opts; + int ret; opts = kzalloc(sizeof(*opts), GFP_KERNEL); if (!opts) return ERR_PTR(-ENOMEM); opts->func_inst.free_func_inst = acm_free_instance; + ret = gserial_alloc_line(&opts->port_num); + if (ret) { + kfree(opts); + return ERR_PTR(ret); + } + config_group_init_type_name(&opts->func_inst.group, "", + &acm_func_type); return &opts->func_inst; } DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); MODULE_LICENSE("GPL"); -#endif diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 83420a310fb7..d893d6929079 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -824,7 +824,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f) * for calling @gether_cleanup() before module unload. */ int -ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev) { struct f_ecm *ecm; int status; @@ -852,6 +853,7 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr); ecm_string_defs[1].s = ecm->ethaddr; + ecm->port.ioport = dev; ecm->port.cdc_filter = DEFAULT_FILTER; ecm->port.func.name = "cdc_ethernet"; diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index cf0ebee85563..f4e0bbef602a 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -528,7 +528,7 @@ error: * Caller must have called @gether_setup(). Caller is also responsible * for calling @gether_cleanup() before module unload. */ -int __init eem_bind_config(struct usb_configuration *c) +int __init eem_bind_config(struct usb_configuration *c, struct eth_dev *dev) { struct f_eem *eem; int status; @@ -549,6 +549,7 @@ int __init eem_bind_config(struct usb_configuration *c) if (!eem) return -ENOMEM; + eem->port.ioport = dev; eem->port.cdc_filter = DEFAULT_FILTER; eem->port.func.name = "cdc_eem"; diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 5e7557e23ecc..ee19bc8d0040 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1287,7 +1287,8 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f) * Caller must have called @gether_setup(). Caller is also responsible * for calling @gether_cleanup() before module unload. */ -int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev) { struct f_ncm *ncm; int status; @@ -1321,6 +1322,7 @@ int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) spin_lock_init(&ncm->lock); ncm_reset_values(ncm); + ncm->port.ioport = dev; ncm->port.is_fixed = true; ncm->port.func.name = "cdc_network"; diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 36a004563b82..8aa2be5329bc 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = { /*-------------------------------------------------------------------------*/ -static struct usb_interface_descriptor obex_control_intf __initdata = { +static struct usb_interface_descriptor obex_control_intf = { .bLength = sizeof(obex_control_intf), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, @@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = { .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, }; -static struct usb_interface_descriptor obex_data_nop_intf __initdata = { +static struct usb_interface_descriptor obex_data_nop_intf = { .bLength = sizeof(obex_data_nop_intf), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 1, @@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = { .bInterfaceClass = USB_CLASS_CDC_DATA, }; -static struct usb_interface_descriptor obex_data_intf __initdata = { +static struct usb_interface_descriptor obex_data_intf = { .bLength = sizeof(obex_data_intf), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 2, @@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = { .bInterfaceClass = USB_CLASS_CDC_DATA, }; -static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = { +static struct usb_cdc_header_desc obex_cdc_header_desc = { .bLength = sizeof(obex_cdc_header_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_HEADER_TYPE, .bcdCDC = cpu_to_le16(0x0120), }; -static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { +static struct usb_cdc_union_desc obex_cdc_union_desc = { .bLength = sizeof(obex_cdc_union_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_UNION_TYPE, @@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { .bSlaveInterface0 = 2, }; -static struct usb_cdc_obex_desc obex_desc __initdata = { +static struct usb_cdc_obex_desc obex_desc = { .bLength = sizeof(obex_desc), .bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorSubType = USB_CDC_OBEX_TYPE, @@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = { /* High-Speed Support */ -static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { +static struct usb_endpoint_descriptor obex_hs_ep_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { +static struct usb_endpoint_descriptor obex_hs_ep_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_descriptor_header *hs_function[] __initdata = { +static struct usb_descriptor_header *hs_function[] = { (struct usb_descriptor_header *) &obex_control_intf, (struct usb_descriptor_header *) &obex_cdc_header_desc, (struct usb_descriptor_header *) &obex_desc, @@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = { /* Full-Speed Support */ -static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { +static struct usb_endpoint_descriptor obex_fs_ep_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { +static struct usb_endpoint_descriptor obex_fs_ep_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, @@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *fs_function[] __initdata = { +static struct usb_descriptor_header *fs_function[] = { (struct usb_descriptor_header *) &obex_control_intf, (struct usb_descriptor_header *) &obex_cdc_header_desc, (struct usb_descriptor_header *) &obex_desc, @@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g) /*-------------------------------------------------------------------------*/ -static int __init -obex_bind(struct usb_configuration *c, struct usb_function *f) +/* Some controllers can't support CDC OBEX ... */ +static inline bool can_support_obex(struct usb_configuration *c) +{ + /* Since the first interface is a NOP, we can ignore the + * issue of multi-interface support on most controllers. + * + * Altsettings are mandatory, however... + */ + if (!gadget_supports_altsettings(c->cdev->gadget)) + return false; + + /* everything else is *probably* fine ... */ + return true; +} + +static int obex_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_obex *obex = func_to_obex(f); int status; struct usb_ep *ep; + if (!can_support_obex(c)) + return -EINVAL; + + if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { + status = usb_string_ids_tab(c->cdev, obex_string_defs); + if (status < 0) + return status; + obex_control_intf.iInterface = + obex_string_defs[OBEX_CTRL_IDX].id; + + status = obex_string_defs[OBEX_DATA_IDX].id; + obex_data_nop_intf.iInterface = status; + obex_data_intf.iInterface = status; + } + /* allocate instance-specific interface IDs, and patch descriptors */ status = usb_interface_id(c, f); @@ -319,6 +348,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific endpoints */ + status = -ENODEV; ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc); if (!ep) goto fail; @@ -376,29 +406,16 @@ fail: return status; } +#ifdef USBF_OBEX_INCLUDED + static void -obex_unbind(struct usb_configuration *c, struct usb_function *f) +obex_old_unbind(struct usb_configuration *c, struct usb_function *f) { obex_string_defs[OBEX_CTRL_IDX].id = 0; usb_free_all_descriptors(f); kfree(func_to_obex(f)); } -/* Some controllers can't support CDC OBEX ... */ -static inline bool can_support_obex(struct usb_configuration *c) -{ - /* Since the first interface is a NOP, we can ignore the - * issue of multi-interface support on most controllers. - * - * Altsettings are mandatory, however... - */ - if (!gadget_supports_altsettings(c->cdev->gadget)) - return false; - - /* everything else is *probably* fine ... */ - return true; -} - /** * obex_bind_config - add a CDC OBEX function to a configuration * @c: the configuration to support the CDC OBEX instance @@ -412,21 +429,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) struct f_obex *obex; int status; - if (!can_support_obex(c)) - return -EINVAL; - - if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { - status = usb_string_ids_tab(c->cdev, obex_string_defs); - if (status < 0) - return status; - obex_control_intf.iInterface = - obex_string_defs[OBEX_CTRL_IDX].id; - - status = obex_string_defs[OBEX_DATA_IDX].id; - obex_data_nop_intf.iInterface = status; - obex_data_intf.iInterface = status; - } - /* allocate and initialize one new instance */ obex = kzalloc(sizeof *obex, GFP_KERNEL); if (!obex) @@ -441,7 +443,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) obex->port.func.strings = obex_strings; /* descriptors are per-instance copies */ obex->port.func.bind = obex_bind; - obex->port.func.unbind = obex_unbind; + obex->port.func.unbind = obex_old_unbind; obex->port.func.set_alt = obex_set_alt; obex->port.func.get_alt = obex_get_alt; obex->port.func.disable = obex_disable; @@ -453,5 +455,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) return status; } +#else + +static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) +{ + return container_of(to_config_group(item), struct f_serial_opts, + func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_serial_opts); +static ssize_t f_obex_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) +{ + struct f_serial_opts *opts = to_f_serial_opts(item); + struct f_serial_opts_attribute *f_serial_opts_attr = + container_of(attr, struct f_serial_opts_attribute, attr); + ssize_t ret = 0; + + if (f_serial_opts_attr->show) + ret = f_serial_opts_attr->show(opts, page); + + return ret; +} + +static void obex_attr_release(struct config_item *item) +{ + struct f_serial_opts *opts = to_f_serial_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations obex_item_ops = { + .release = obex_attr_release, + .show_attribute = f_obex_attr_show, +}; + +static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page) +{ + return sprintf(page, "%u\n", opts->port_num); +} + +static struct f_serial_opts_attribute f_obex_port_num = + __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show); + +static struct configfs_attribute *acm_attrs[] = { + &f_obex_port_num.attr, + NULL, +}; + +static struct config_item_type obex_func_type = { + .ct_item_ops = &obex_item_ops, + .ct_attrs = acm_attrs, + .ct_owner = THIS_MODULE, +}; + +static void obex_free_inst(struct usb_function_instance *f) +{ + struct f_serial_opts *opts; + + opts = container_of(f, struct f_serial_opts, func_inst); + gserial_free_line(opts->port_num); + kfree(opts); +} + +static struct usb_function_instance *obex_alloc_inst(void) +{ + struct f_serial_opts *opts; + int ret; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = obex_free_inst; + ret = gserial_alloc_line(&opts->port_num); + if (ret) { + kfree(opts); + return ERR_PTR(ret); + } + config_group_init_type_name(&opts->func_inst.group, "", + &obex_func_type); + + return &opts->func_inst; +} + +static void obex_free(struct usb_function *f) +{ + struct f_obex *obex; + + obex = func_to_obex(f); + kfree(obex); +} + +static void obex_unbind(struct usb_configuration *c, struct usb_function *f) +{ + obex_string_defs[OBEX_CTRL_IDX].id = 0; + usb_free_all_descriptors(f); +} + +struct usb_function *obex_alloc(struct usb_function_instance *fi) +{ + struct f_obex *obex; + struct f_serial_opts *opts; + + /* allocate and initialize one new instance */ + obex = kzalloc(sizeof(*obex), GFP_KERNEL); + if (!obex) + return ERR_PTR(-ENOMEM); + + opts = container_of(fi, struct f_serial_opts, func_inst); + + obex->port_num = opts->port_num; + + obex->port.connect = obex_connect; + obex->port.disconnect = obex_disconnect; + + obex->port.func.name = "obex"; + obex->port.func.strings = obex_strings; + /* descriptors are per-instance copies */ + obex->port.func.bind = obex_bind; + obex->port.func.unbind = obex_unbind; + obex->port.func.set_alt = obex_set_alt; + obex->port.func.get_alt = obex_get_alt; + obex->port.func.disable = obex_disable; + obex->port.func.free_func = obex_free; + + return &obex->port.func; +} + +DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc); + +#endif + MODULE_AUTHOR("Felipe Balbi"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index cc9c49c57c80..36e8c44d8e5e 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -813,7 +813,7 @@ static inline bool can_support_rndis(struct usb_configuration *c) int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer) + u32 vendorID, const char *manufacturer, struct eth_dev *dev) { struct f_rndis *rndis; int status; @@ -846,6 +846,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], rndis->vendorID = vendorID; rndis->manufacturer = manufacturer; + rndis->port.ioport = dev; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index da33cfb3031d..981113c9924d 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/device.h> #include "u_serial.h" @@ -42,7 +43,7 @@ static inline struct f_gser *func_to_gser(struct usb_function *f) /* interface descriptor: */ -static struct usb_interface_descriptor gser_interface_desc __initdata = { +static struct usb_interface_descriptor gser_interface_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, /* .bInterfaceNumber = DYNAMIC */ @@ -55,21 +56,21 @@ static struct usb_interface_descriptor gser_interface_desc __initdata = { /* full speed support: */ -static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = { +static struct usb_endpoint_descriptor gser_fs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = { +static struct usb_endpoint_descriptor gser_fs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, }; -static struct usb_descriptor_header *gser_fs_function[] __initdata = { +static struct usb_descriptor_header *gser_fs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_fs_in_desc, (struct usb_descriptor_header *) &gser_fs_out_desc, @@ -78,47 +79,47 @@ static struct usb_descriptor_header *gser_fs_function[] __initdata = { /* high speed support: */ -static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = { +static struct usb_endpoint_descriptor gser_hs_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = { +static struct usb_endpoint_descriptor gser_hs_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }; -static struct usb_descriptor_header *gser_hs_function[] __initdata = { +static struct usb_descriptor_header *gser_hs_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_hs_in_desc, (struct usb_descriptor_header *) &gser_hs_out_desc, NULL, }; -static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = { +static struct usb_endpoint_descriptor gser_ss_in_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = { +static struct usb_endpoint_descriptor gser_ss_out_desc = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }; -static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = { +static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = { .bLength = sizeof gser_ss_bulk_comp_desc, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, }; -static struct usb_descriptor_header *gser_ss_function[] __initdata = { +static struct usb_descriptor_header *gser_ss_function[] = { (struct usb_descriptor_header *) &gser_interface_desc, (struct usb_descriptor_header *) &gser_ss_in_desc, (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc, @@ -183,14 +184,25 @@ static void gser_disable(struct usb_function *f) /* serial function driver setup/binding */ -static int __init -gser_bind(struct usb_configuration *c, struct usb_function *f) +static int gser_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct f_gser *gser = func_to_gser(f); int status; struct usb_ep *ep; + /* REVISIT might want instance-specific strings to help + * distinguish instances ... + */ + + /* maybe allocate device-global string ID */ + if (gser_string_defs[0].id == 0) { + status = usb_string_id(c->cdev); + if (status < 0) + return status; + gser_string_defs[0].id = status; + } + /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) @@ -246,44 +258,115 @@ fail: return status; } -static void -gser_unbind(struct usb_configuration *c, struct usb_function *f) +static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) { - usb_free_all_descriptors(f); - kfree(func_to_gser(f)); + return container_of(to_config_group(item), struct f_serial_opts, + func_inst.group); } -/** - * gser_bind_config - add a generic serial function to a configuration - * @c: the configuration to support the serial instance - * @port_num: /dev/ttyGS* port this interface will use - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - */ -int __init gser_bind_config(struct usb_configuration *c, u8 port_num) +CONFIGFS_ATTR_STRUCT(f_serial_opts); +static ssize_t f_serial_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *page) { - struct f_gser *gser; - int status; + struct f_serial_opts *opts = to_f_serial_opts(item); + struct f_serial_opts_attribute *f_serial_opts_attr = + container_of(attr, struct f_serial_opts_attribute, attr); + ssize_t ret = 0; - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ + if (f_serial_opts_attr->show) + ret = f_serial_opts_attr->show(opts, page); - /* maybe allocate device-global string ID */ - if (gser_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - gser_string_defs[0].id = status; + return ret; +} + +static void serial_attr_release(struct config_item *item) +{ + struct f_serial_opts *opts = to_f_serial_opts(item); + + usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations serial_item_ops = { + .release = serial_attr_release, + .show_attribute = f_serial_attr_show, +}; + +static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page) +{ + return sprintf(page, "%u\n", opts->port_num); +} + +static struct f_serial_opts_attribute f_serial_port_num = + __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show); + +static struct configfs_attribute *acm_attrs[] = { + &f_serial_port_num.attr, + NULL, +}; + +static struct config_item_type serial_func_type = { + .ct_item_ops = &serial_item_ops, + .ct_attrs = acm_attrs, + .ct_owner = THIS_MODULE, +}; + +static void gser_free_inst(struct usb_function_instance *f) +{ + struct f_serial_opts *opts; + + opts = container_of(f, struct f_serial_opts, func_inst); + gserial_free_line(opts->port_num); + kfree(opts); +} + +static struct usb_function_instance *gser_alloc_inst(void) +{ + struct f_serial_opts *opts; + int ret; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = gser_free_inst; + ret = gserial_alloc_line(&opts->port_num); + if (ret) { + kfree(opts); + return ERR_PTR(ret); } + config_group_init_type_name(&opts->func_inst.group, "", + &serial_func_type); + + return &opts->func_inst; +} + +static void gser_free(struct usb_function *f) +{ + struct f_gser *serial; + + serial = func_to_gser(f); + kfree(serial); +} + +static void gser_unbind(struct usb_configuration *c, struct usb_function *f) +{ + usb_free_all_descriptors(f); +} + +struct usb_function *gser_alloc(struct usb_function_instance *fi) +{ + struct f_gser *gser; + struct f_serial_opts *opts; /* allocate and initialize one new instance */ - gser = kzalloc(sizeof *gser, GFP_KERNEL); + gser = kzalloc(sizeof(*gser), GFP_KERNEL); if (!gser) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - gser->port_num = port_num; + opts = container_of(fi, struct f_serial_opts, func_inst); + + gser->port_num = opts->port_num; gser->port.func.name = "gser"; gser->port.func.strings = gser_strings; @@ -291,9 +374,12 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num) gser->port.func.unbind = gser_unbind; gser->port.func.set_alt = gser_set_alt; gser->port.func.disable = gser_disable; + gser->port.func.free_func = gser_free; - status = usb_add_function(c, &gser->port.func); - if (status) - kfree(gser); - return status; + return &gser->port.func; } + +DECLARE_USB_FUNCTION_INIT(gser, gser_alloc_inst, gser_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Al Borchers"); +MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 41adf3ef96c2..a8895859a221 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -898,7 +898,7 @@ static struct usb_function *source_sink_alloc_func( return &ss->function; } -static void acm_free_instance(struct usb_function_instance *fi) +static void source_sink_free_instance(struct usb_function_instance *fi) { struct f_ss_opts *ss_opts; @@ -913,7 +913,7 @@ static struct usb_function_instance *source_sink_alloc_inst(void) ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL); if (!ss_opts) return ERR_PTR(-ENOMEM); - ss_opts->func_inst.free_func_inst = acm_free_instance; + ss_opts->func_inst.free_func_inst = source_sink_free_instance; return &ss_opts->func_inst; } DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index f172bd152fbb..185d6f5e4e4d 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -380,7 +380,8 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f) * Caller must have called @gether_setup(). Caller is also responsible * for calling @gether_cleanup() before module unload. */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev) { struct f_gether *geth; int status; @@ -406,6 +407,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr); geth_string_defs[1].s = geth->ethaddr; + geth->port.ioport = dev; geth->port.cdc_filter = DEFAULT_FILTER; geth->port.func.name = "cdc_subset"; diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c index 92efd6ec48af..38dcedddc52c 100644 --- a/drivers/usb/gadget/f_uvc.c +++ b/drivers/usb/gadget/f_uvc.c @@ -33,19 +33,15 @@ unsigned int uvc_gadget_trace_param; /*-------------------------------------------------------------------------*/ /* module parameters specific to the Video streaming endpoint */ -static unsigned streaming_interval = 1; +static unsigned int streaming_interval = 1; module_param(streaming_interval, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(streaming_interval, "1 - 16"); -static unsigned streaming_maxpacket = 1024; +static unsigned int streaming_maxpacket = 1024; module_param(streaming_maxpacket, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(streaming_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); +MODULE_PARM_DESC(streaming_maxpacket, "1 - 1023 (FS), 1 - 3072 (hs/ss)"); -static unsigned streaming_mult; -module_param(streaming_mult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(streaming_mult, "0 - 2 (hs/ss only)"); - -static unsigned streaming_maxburst; +static unsigned int streaming_maxburst; module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); @@ -55,13 +51,11 @@ MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); /* string IDs are assigned dynamically */ -#define UVC_STRING_ASSOCIATION_IDX 0 -#define UVC_STRING_CONTROL_IDX 1 -#define UVC_STRING_STREAMING_IDX 2 +#define UVC_STRING_CONTROL_IDX 0 +#define UVC_STRING_STREAMING_IDX 1 static struct usb_string uvc_en_us_strings[] = { - [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera", - [UVC_STRING_CONTROL_IDX].s = "Video Control", + [UVC_STRING_CONTROL_IDX].s = "UVC Camera", [UVC_STRING_STREAMING_IDX].s = "Video Streaming", { } }; @@ -79,7 +73,7 @@ static struct usb_gadget_strings *uvc_function_strings[] = { #define UVC_INTF_VIDEO_CONTROL 0 #define UVC_INTF_VIDEO_STREAMING 1 -#define STATUS_BYTECOUNT 16 /* 16 bytes status */ +#define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */ static struct usb_interface_assoc_descriptor uvc_iad __initdata = { .bLength = sizeof(uvc_iad), @@ -104,20 +98,29 @@ static struct usb_interface_descriptor uvc_control_intf __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_fs_control_ep __initdata = { +static struct usb_endpoint_descriptor uvc_control_ep __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), + .wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), .bInterval = 8, }; +static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { + .bLength = sizeof(uvc_ss_control_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* The following 3 values can be tweaked if necessary. */ + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), +}; + static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, .bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorSubType = UVC_EP_INTERRUPT, - .wMaxTransferSize = cpu_to_le16(STATUS_BYTECOUNT), + .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), }; static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { @@ -144,63 +147,53 @@ static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { .iInterface = 0, }; -static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { +static struct usb_endpoint_descriptor uvc_fs_streaming_ep __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, + .bmAttributes = USB_ENDPOINT_SYNC_ASYNC + | USB_ENDPOINT_XFER_ISOC, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ + .wMaxPacketSize = 0, + .bInterval = 0, }; -static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { +static struct usb_endpoint_descriptor uvc_hs_streaming_ep __initdata = { .bLength = USB_DT_ENDPOINT_SIZE, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = 1, -}; - -/* super speed support */ -static struct usb_endpoint_descriptor uvc_ss_control_ep __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = 8, -}; - -static struct usb_ss_ep_comp_descriptor uvc_ss_control_comp __initdata = { - .bLength = sizeof uvc_ss_control_comp, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 3 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ - .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), + .bmAttributes = USB_ENDPOINT_SYNC_ASYNC + | USB_ENDPOINT_XFER_ISOC, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ + .wMaxPacketSize = 0, + .bInterval = 0, }; static struct usb_endpoint_descriptor uvc_ss_streaming_ep __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = cpu_to_le16(1024), - .bInterval = 4, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_SYNC_ASYNC + | USB_ENDPOINT_XFER_ISOC, + /* The wMaxPacketSize and bInterval values will be initialized from + * module parameters. + */ + .wMaxPacketSize = 0, + .bInterval = 0, }; -static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { - .bLength = sizeof uvc_ss_streaming_comp, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 3 values can be tweaked if necessary */ - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = cpu_to_le16(1024), +static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp __initdata = { + .bLength = sizeof(uvc_ss_streaming_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + /* The following 3 values can be tweaked if necessary. */ + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(1024), }; static const struct usb_descriptor_header * const uvc_fs_streaming[] = { @@ -273,6 +266,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) return 0; } +void uvc_function_setup_continue(struct uvc_device *uvc) +{ + struct usb_composite_dev *cdev = uvc->func.config->cdev; + + usb_composite_setup_continue(cdev); +} + static int uvc_function_get_alt(struct usb_function *f, unsigned interface) { @@ -335,7 +335,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) v4l2_event_queue(uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; - break; + return 0; case 1: if (uvc->state != UVC_STATE_CONNECTED) @@ -352,15 +352,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event_queue(uvc->vdev, &v4l2_event); - - uvc->state = UVC_STATE_STREAMING; - break; + return USB_GADGET_DELAYED_STATUS; default: return -EINVAL; } - - return 0; } static void @@ -454,7 +450,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) const struct uvc_descriptor_header * const *uvc_streaming_cls; const struct usb_descriptor_header * const *uvc_streaming_std; const struct usb_descriptor_header * const *src; - static struct usb_endpoint_descriptor *uvc_control_ep; struct usb_descriptor_header **dst; struct usb_descriptor_header **hdr; unsigned int control_size; @@ -468,14 +463,12 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) uvc_control_desc = uvc->desc.ss_control; uvc_streaming_cls = uvc->desc.ss_streaming; uvc_streaming_std = uvc_ss_streaming; - uvc_control_ep = &uvc_ss_control_ep; break; case USB_SPEED_HIGH: uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.hs_streaming; uvc_streaming_std = uvc_hs_streaming; - uvc_control_ep = &uvc_fs_control_ep; break; case USB_SPEED_FULL: @@ -483,7 +476,6 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.fs_streaming; uvc_streaming_std = uvc_fs_streaming; - uvc_control_ep = &uvc_fs_control_ep; break; } @@ -494,6 +486,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) * Class-specific UVC control descriptors * uvc_control_ep * uvc_control_cs_ep + * uvc_ss_control_comp (for SS only) * uvc_streaming_intf_alt0 * Class-specific UVC streaming descriptors * uvc_{fs|hs}_streaming @@ -503,7 +496,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) control_size = 0; streaming_size = 0; bytes = uvc_iad.bLength + uvc_control_intf.bLength - + uvc_control_ep->bLength + uvc_control_cs_ep.bLength + + uvc_control_ep.bLength + uvc_control_cs_ep.bLength + uvc_streaming_intf_alt0.bLength; if (speed == USB_SPEED_SUPER) { @@ -514,13 +507,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) } for (src = (const struct usb_descriptor_header **)uvc_control_desc; - *src; ++src) { + *src; ++src) { control_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; } for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; - *src; ++src) { + *src; ++src) { streaming_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; @@ -549,7 +542,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) uvc_control_header->bInCollection = 1; uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; - UVC_COPY_DESCRIPTOR(mem, dst, uvc_control_ep); + UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); if (speed == USB_SPEED_SUPER) UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp); @@ -560,8 +553,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header**)uvc_streaming_cls); uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); - uvc_streaming_header->bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; + uvc_streaming_header->bEndpointAddress = uvc->video.ep->address; UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); @@ -581,7 +573,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) uvc->control_ep->driver_data = NULL; uvc->video.ep->driver_data = NULL; - uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = 0; + uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = 0; usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); kfree(uvc->control_buf); @@ -595,31 +587,52 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); + unsigned int max_packet_mult; + unsigned int max_packet_size; struct usb_ep *ep; int ret = -EINVAL; INFO(cdev, "uvc_function_bind\n"); - /* sanity check the streaming endpoint module parameters */ - if (streaming_interval < 1) - streaming_interval = 1; - if (streaming_interval > 16) - streaming_interval = 16; - if (streaming_mult > 2) - streaming_mult = 2; - if (streaming_maxburst > 15) - streaming_maxburst = 15; - - /* - * fill in the FS video streaming specific descriptors from the - * module parameters + /* Sanity check the streaming endpoint module parameters. */ - uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ? - 1023 : streaming_maxpacket; + streaming_interval = clamp(streaming_interval, 1U, 16U); + streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U); + streaming_maxburst = min(streaming_maxburst, 15U); + + /* Fill in the FS/HS/SS Video Streaming specific descriptors from the + * module parameters. + * + * NOTE: We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + if (streaming_maxpacket <= 1024) { + max_packet_mult = 1; + max_packet_size = streaming_maxpacket; + } else if (streaming_maxpacket <= 2048) { + max_packet_mult = 2; + max_packet_size = streaming_maxpacket / 2; + } else { + max_packet_mult = 3; + max_packet_size = streaming_maxpacket / 3; + } + + uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U); uvc_fs_streaming_ep.bInterval = streaming_interval; + uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size; + uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11); + uvc_hs_streaming_ep.bInterval = streaming_interval; + + uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size; + uvc_ss_streaming_ep.bInterval = streaming_interval; + uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; + uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; + uvc_ss_streaming_comp.wBytesPerInterval = + max_packet_size * max_packet_mult * streaming_maxburst; + /* Allocate endpoints. */ - ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep); + ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); if (!ep) { INFO(cdev, "Unable to allocate control EP\n"); goto error; @@ -627,7 +640,14 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc->control_ep = ep; ep->driver_data = uvc; - ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); + if (gadget_is_superspeed(c->cdev->gadget)) + ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep, + &uvc_ss_streaming_comp); + else if (gadget_is_dualspeed(cdev->gadget)) + ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep); + else + ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); + if (!ep) { INFO(cdev, "Unable to allocate streaming EP\n"); goto error; @@ -635,6 +655,10 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc->video.ep = ep; ep->driver_data = uvc; + uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address; + uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; + uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; + /* Allocate interface IDs. */ if ((ret = usb_interface_id(c, f)) < 0) goto error; @@ -648,37 +672,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvc_streaming_intf_alt1.bInterfaceNumber = ret; uvc->streaming_intf = ret; - /* sanity check the streaming endpoint module parameters */ - if (streaming_maxpacket > 1024) - streaming_maxpacket = 1024; - /* - * Fill in the HS descriptors from the module parameters for the Video - * Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11; - uvc_hs_streaming_ep.bInterval = streaming_interval; - uvc_hs_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - - /* - * Fill in the SS descriptors from the module parameters for the Video - * Streaming endpoint. - * NOTE: We assume that the user knows what they are doing and won't - * give parameters that their UDC doesn't support. - */ - uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket; - uvc_ss_streaming_ep.bInterval = streaming_interval; - uvc_ss_streaming_comp.bmAttributes = streaming_mult; - uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst; - uvc_ss_streaming_comp.wBytesPerInterval = - streaming_maxpacket * (streaming_mult + 1) * - (streaming_maxburst + 1); - uvc_ss_streaming_ep.bEndpointAddress = - uvc_fs_streaming_ep.bEndpointAddress; - /* Copy descriptors */ f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); if (gadget_is_dualspeed(cdev->gadget)) @@ -775,23 +768,23 @@ uvc_bind_config(struct usb_configuration *c, /* Validate the descriptors. */ if (fs_control == NULL || fs_control[0] == NULL || - fs_control[0]->bDescriptorSubType != UVC_VC_HEADER) + fs_control[0]->bDescriptorSubType != UVC_VC_HEADER) goto error; if (ss_control == NULL || ss_control[0] == NULL || - ss_control[0]->bDescriptorSubType != UVC_VC_HEADER) + ss_control[0]->bDescriptorSubType != UVC_VC_HEADER) goto error; if (fs_streaming == NULL || fs_streaming[0] == NULL || - fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) + fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) goto error; if (hs_streaming == NULL || hs_streaming[0] == NULL || - hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) + hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) goto error; if (ss_streaming == NULL || ss_streaming[0] == NULL || - ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) + ss_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) goto error; uvc->desc.fs_control = fs_control; @@ -800,13 +793,16 @@ uvc_bind_config(struct usb_configuration *c, uvc->desc.hs_streaming = hs_streaming; uvc->desc.ss_streaming = ss_streaming; - /* Allocate string descriptor numbers. */ - if (uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id == 0) { + /* String descriptors are global, we only need to allocate string IDs + * for the first UVC function. UVC functions beyond the first (if any) + * will reuse the same IDs. + */ + if (uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id == 0) { ret = usb_string_ids_tab(c->cdev, uvc_en_us_strings); if (ret) goto error; uvc_iad.iFunction = - uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id; + uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; uvc_control_intf.iInterface = uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id; ret = uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id; diff --git a/drivers/usb/gadget/f_uvc.h b/drivers/usb/gadget/f_uvc.h index c3d258d30188..ec52752f7326 100644 --- a/drivers/usb/gadget/f_uvc.h +++ b/drivers/usb/gadget/f_uvc.h @@ -16,12 +16,12 @@ #include <linux/usb/composite.h> #include <linux/usb/video.h> -extern int uvc_bind_config(struct usb_configuration *c, - const struct uvc_descriptor_header * const *fs_control, - const struct uvc_descriptor_header * const *hs_control, - const struct uvc_descriptor_header * const *fs_streaming, - const struct uvc_descriptor_header * const *hs_streaming, - const struct uvc_descriptor_header * const *ss_streaming); +int uvc_bind_config(struct usb_configuration *c, + const struct uvc_descriptor_header * const *fs_control, + const struct uvc_descriptor_header * const *hs_control, + const struct uvc_descriptor_header * const *fs_streaming, + const struct uvc_descriptor_header * const *hs_streaming, + const struct uvc_descriptor_header * const *ss_streaming); #endif /* _F_UVC_H_ */ diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 034477ce77c6..9a7ee3347e4d 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2296,7 +2296,6 @@ static int fsl_qe_start(struct usb_gadget *gadget, driver->driver.bus = NULL; /* hook up the driver */ udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; udc->gadget.speed = driver->max_speed; /* Enable IRQ reg and Set usbcmd reg EN bit */ @@ -2338,7 +2337,6 @@ static int fsl_qe_stop(struct usb_gadget *gadget, nuke(loop_ep, -ESHUTDOWN); spin_unlock_irqrestore(&udc->lock, flags); - udc->gadget.dev.driver = NULL; udc->driver = NULL; dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", @@ -2523,12 +2521,6 @@ static int qe_udc_probe(struct platform_device *ofdev) /* name: Identifies the controller hardware type. */ udc->gadget.name = driver_name; - - device_initialize(&udc->gadget.dev); - - dev_set_name(&udc->gadget.dev, "gadget"); - - udc->gadget.dev.release = qe_udc_release; udc->gadget.dev.parent = &ofdev->dev; /* initialize qe_ep struct */ @@ -2592,22 +2584,17 @@ static int qe_udc_probe(struct platform_device *ofdev) goto err5; } - ret = device_add(&udc->gadget.dev); + ret = usb_add_gadget_udc_release(&ofdev->dev, &udc->gadget, + qe_udc_release); if (ret) goto err6; - ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget); - if (ret) - goto err7; - dev_set_drvdata(&ofdev->dev, udc); dev_info(udc->dev, "%s USB controller initialized as device\n", (udc->soc_type == PORT_QE) ? "QE" : "CPM"); return 0; -err7: - device_unregister(&udc->gadget.dev); err6: free_irq(udc->usb_irq, udc); err5: @@ -2702,7 +2689,6 @@ static int qe_udc_remove(struct platform_device *ofdev) iounmap(udc->usb_regs); - device_unregister(&udc->gadget.dev); /* wait for release() of gadget.dev to free udc */ wait_for_completion(&done); diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 04d5fef1440c..7c2a101d19ac 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -185,20 +185,7 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status) dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); } - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); + usb_gadget_unmap_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); if (status && (status != -ESHUTDOWN)) VDBG("complete %s req %p stat %d len %u/%u", @@ -888,6 +875,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) struct fsl_req *req = container_of(_req, struct fsl_req, req); struct fsl_udc *udc; unsigned long flags; + int ret; /* catch various bogus parameters */ if (!_req || !req->req.complete || !req->req.buf @@ -910,22 +898,9 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req->ep = ep; - /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } + ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); + if (ret) + return ret; req->req.status = -EINPROGRESS; req->req.actual = 0; @@ -1290,6 +1265,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) { struct fsl_req *req = udc->status_req; struct fsl_ep *ep; + int ret; if (direction == EP_DIR_IN) udc->ep0_dir = USB_DIR_IN; @@ -1307,10 +1283,9 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) req->req.complete = NULL; req->dtd_count = 0; - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; + ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); + if (ret) + return ret; if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0) fsl_queue_td(ep, req); @@ -1353,6 +1328,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, u16 tmp = 0; /* Status, cpu endian */ struct fsl_req *req; struct fsl_ep *ep; + int ret; ep = &udc->eps[0]; @@ -1390,10 +1366,9 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->req.complete = NULL; req->dtd_count = 0; - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; + ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); + if (ret) + goto stall; /* prime the data phase */ if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0)) @@ -1964,7 +1939,6 @@ static int fsl_udc_start(struct usb_gadget *g, driver->driver.bus = NULL; /* hook up the driver */ udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); if (!IS_ERR_OR_NULL(udc_controller->transceiver)) { @@ -1980,7 +1954,6 @@ static int fsl_udc_start(struct usb_gadget *g, if (retval < 0) { ERR("can't bind to transceiver\n"); driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; udc_controller->driver = 0; return retval; } @@ -2023,7 +1996,6 @@ static int fsl_udc_stop(struct usb_gadget *g, nuke(loop_ep, -ESHUTDOWN); spin_unlock_irqrestore(&udc_controller->lock, flags); - udc_controller->gadget.dev.driver = NULL; udc_controller->driver = NULL; return 0; @@ -2521,12 +2493,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) /* Setup gadget.dev and register with kernel */ dev_set_name(&udc_controller->gadget.dev, "gadget"); - udc_controller->gadget.dev.release = fsl_udc_release; - udc_controller->gadget.dev.parent = &pdev->dev; udc_controller->gadget.dev.of_node = pdev->dev.of_node; - ret = device_register(&udc_controller->gadget.dev); - if (ret < 0) - goto err_free_irq; if (!IS_ERR_OR_NULL(udc_controller->transceiver)) udc_controller->gadget.is_otg = 1; @@ -2559,10 +2526,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev) DTD_ALIGNMENT, UDC_DMA_BOUNDARY); if (udc_controller->td_pool == NULL) { ret = -ENOMEM; - goto err_unregister; + goto err_free_irq; } - ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); + ret = usb_add_gadget_udc_release(&pdev->dev, &udc_controller->gadget, + fsl_udc_release); if (ret) goto err_del_udc; @@ -2571,8 +2539,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) err_del_udc: dma_pool_destroy(udc_controller->td_pool); -err_unregister: - device_unregister(&udc_controller->gadget.dev); err_free_irq: free_irq(udc_controller->irq, udc_controller); err_iounmap: @@ -2622,7 +2588,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (pdata->operating_mode == FSL_USB2_DR_DEVICE) release_mem_region(res->start, resource_size(res)); - device_unregister(&udc_controller->gadget.dev); /* free udc --wait for the release() finished */ wait_for_completion(&done); @@ -2747,21 +2712,7 @@ static struct platform_driver udc_driver = { }, }; -static int __init udc_init(void) -{ - printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, fsl_udc_probe); -} - -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); - printk(KERN_WARNING "%s unregistered\n", driver_desc); -} - -module_exit(udc_exit); +module_platform_driver_probe(udc_driver, fsl_udc_probe); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 066cb89376de..cec8871b77f9 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -394,7 +394,7 @@ static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep) if (reg & FUSB300_EPSET0_STL) { printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); - reg &= ~FUSB300_EPSET0_STL; + reg |= FUSB300_EPSET0_STL_CLR; iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); } } @@ -930,33 +930,33 @@ static void fusb300_wait_idma_finished(struct fusb300_ep *ep) fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); + return; + IDMA_RESET: - fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); + reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGER0); + reg &= ~FUSB300_IGER0_EEPn_PRD_INT(ep->epnum); + iowrite32(reg, ep->fusb300->reg + FUSB300_OFFSET_IGER0); } -static void fusb300_set_idma(struct fusb300_ep *ep, +static void fusb300_set_idma(struct fusb300_ep *ep, struct fusb300_request *req) { - dma_addr_t d; - - d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE); + int ret; - if (dma_mapping_error(NULL, d)) { - printk(KERN_DEBUG "dma_mapping_error\n"); + ret = usb_gadget_map_request(&ep->fusb300->gadget, + &req->req, DMA_TO_DEVICE); + if (ret) return; - } - - dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE); fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); - fusb300_fill_idma_prdtbl(ep, d, req->req.length); + fusb300_fill_idma_prdtbl(ep, req->req.dma, req->req.length); /* check idma is done */ fusb300_wait_idma_finished(ep); - dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); + usb_gadget_unmap_request(&ep->fusb300->gadget, + &req->req, DMA_TO_DEVICE); } static void in_ep_fifo_handler(struct fusb300_ep *ep) @@ -1316,7 +1316,6 @@ static int fusb300_udc_start(struct usb_gadget *g, /* hook up the driver */ driver->driver.bus = NULL; fusb300->driver = driver; - fusb300->gadget.dev.driver = &driver->driver; return 0; } @@ -1327,7 +1326,6 @@ static int fusb300_udc_stop(struct usb_gadget *g, struct fusb300 *fusb300 = to_fusb300(g); driver->unbind(&fusb300->gadget); - fusb300->gadget.dev.driver = NULL; init_controller(fusb300); fusb300->driver = NULL; @@ -1422,14 +1420,7 @@ static int __init fusb300_probe(struct platform_device *pdev) fusb300->gadget.ops = &fusb300_gadget_ops; - device_initialize(&fusb300->gadget.dev); - - dev_set_name(&fusb300->gadget.dev, "gadget"); - fusb300->gadget.max_speed = USB_SPEED_HIGH; - fusb300->gadget.dev.parent = &pdev->dev; - fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; - fusb300->gadget.dev.release = pdev->dev.release; fusb300->gadget.name = udc_name; fusb300->reg = reg; @@ -1478,19 +1469,10 @@ static int __init fusb300_probe(struct platform_device *pdev) if (ret) goto err_add_udc; - ret = device_add(&fusb300->gadget.dev); - if (ret) { - pr_err("device_add error (%d)\n", ret); - goto err_add_device; - } - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; -err_add_device: - usb_del_gadget_udc(&fusb300->gadget); - err_add_udc: fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h index 6ba444ae8dd5..ae811d8d38b4 100644 --- a/drivers/usb/gadget/fusb300_udc.h +++ b/drivers/usb/gadget/fusb300_udc.h @@ -111,8 +111,8 @@ /* * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 ) * */ +#define FUSB300_EPSET0_STL_CLR (1 << 3) #define FUSB300_EPSET0_CLRSEQNUM (1 << 2) -#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1) #define FUSB300_EPSET0_STL (1 << 0) /* diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 3b343b23e4b0..787a78e92aa2 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -13,7 +13,6 @@ #define pr_fmt(fmt) "g_ffs: " fmt #include <linux/module.h> - /* * kbuild is not very cooperative with respect to linking separately * compiled library objects into one module. So for now we won't use @@ -38,13 +37,16 @@ # include "u_ether.c" static u8 gfs_hostaddr[ETH_ALEN]; +static struct eth_dev *the_dev; # ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev); # endif #else -# define gether_cleanup() do { } while (0) -# define gether_setup(gadget, hostaddr) ((int)0) +# define the_dev NULL +# define gether_cleanup(dev) do { } while (0) # define gfs_hostaddr NULL +struct eth_dev; #endif #include "f_fs.c" @@ -137,7 +139,8 @@ static struct usb_gadget_strings *gfs_dev_strings[] = { struct gfs_configuration { struct usb_configuration c; - int (*eth)(struct usb_configuration *c, u8 *ethaddr); + int (*eth)(struct usb_configuration *c, u8 *ethaddr, + struct eth_dev *dev); } gfs_configurations[] = { #ifdef CONFIG_USB_FUNCTIONFS_RNDIS { @@ -346,10 +349,13 @@ static int gfs_bind(struct usb_composite_dev *cdev) if (missing_funcs) return -ENODEV; - - ret = gether_setup(cdev->gadget, gfs_hostaddr); - if (unlikely(ret < 0)) +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS + the_dev = gether_setup(cdev->gadget, gfs_hostaddr); +#endif + if (IS_ERR(the_dev)) { + ret = PTR_ERR(the_dev); goto error_quick; + } gfs_ether_setup = true; ret = usb_string_ids_tab(cdev, gfs_strings); @@ -386,7 +392,7 @@ error_unbind: for (i = 0; i < func_num; i++) functionfs_unbind(ffs_tab[i].ffs_data); error: - gether_cleanup(); + gether_cleanup(the_dev); error_quick: gfs_ether_setup = false; return ret; @@ -410,7 +416,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev) * do...? */ if (gfs_ether_setup) - gether_cleanup(); + gether_cleanup(the_dev); gfs_ether_setup = false; for (i = func_num; i--; ) @@ -440,7 +446,7 @@ static int gfs_do_config(struct usb_configuration *c) } if (gc->eth) { - ret = gc->eth(c, gfs_hostaddr); + ret = gc->eth(c, gfs_hostaddr, the_dev); if (unlikely(ret < 0)) return ret; } @@ -469,11 +475,12 @@ static int gfs_do_config(struct usb_configuration *c) #ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev) { return can_support_ecm(c->cdev->gadget) - ? ecm_bind_config(c, ethaddr) - : geth_bind_config(c, ethaddr); + ? ecm_bind_config(c, ethaddr, dev) + : geth_bind_config(c, ethaddr, dev); } #endif diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 85742d4c67df..991aba390d9d 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -51,8 +51,6 @@ #define DRIVER_DESC "TC86C001 USB Device Controller" #define DRIVER_VERSION "30-Oct 2003" -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - static const char driver_name [] = "goku_udc"; static const char driver_desc [] = DRIVER_DESC; @@ -275,7 +273,6 @@ goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) if (!req) return NULL; - req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); return &req->req; } @@ -1354,7 +1351,6 @@ static int goku_udc_start(struct usb_gadget *g, /* hook up the driver */ driver->driver.bus = NULL; dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; /* * then enable host detection and ep0; and we're ready @@ -1394,7 +1390,6 @@ static int goku_udc_stop(struct usb_gadget *g, dev->driver = NULL; stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - dev->gadget.dev.driver = NULL; return 0; } @@ -1716,8 +1711,6 @@ static void goku_remove(struct pci_dev *pdev) pci_resource_len (pdev, 0)); if (dev->enabled) pci_disable_device(pdev); - if (dev->registered) - device_unregister(&dev->gadget.dev); pci_set_drvdata(pdev, NULL); dev->regs = NULL; @@ -1756,10 +1749,6 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev->gadget.max_speed = USB_SPEED_FULL; /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; dev->gadget.name = driver_name; /* now all the pci goodies ... */ @@ -1810,13 +1799,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev); #endif - retval = device_register(&dev->gadget.dev); - if (retval) { - put_device(&dev->gadget.dev); - goto err; - } - dev->registered = 1; - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, + gadget_release); if (retval) goto err; diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h index b4470d2b1d86..86d2adafe149 100644 --- a/drivers/usb/gadget/goku_udc.h +++ b/drivers/usb/gadget/goku_udc.h @@ -250,8 +250,7 @@ struct goku_udc { got_region:1, req_config:1, configured:1, - enabled:1, - registered:1; + enabled:1; /* pci state used to access those endpoints */ struct pci_dev *pdev; diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 5bd930d779b9..b5cebd6b0d7a 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1338,7 +1338,6 @@ static int imx_udc_start(struct usb_gadget *gadget, imx_usb = container_of(gadget, struct imx_udc_struct, gadget); /* first hook up the driver ... */ imx_usb->driver = driver; - imx_usb->gadget.dev.driver = &driver->driver; D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", __func__, driver->driver.name); @@ -1358,7 +1357,6 @@ static int imx_udc_stop(struct usb_gadget *gadget, imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); - imx_usb->gadget.dev.driver = NULL; imx_usb->driver = NULL; D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", @@ -1461,15 +1459,6 @@ static int __init imx_udc_probe(struct platform_device *pdev) imx_usb->clk = clk; imx_usb->dev = &pdev->dev; - device_initialize(&imx_usb->gadget.dev); - - imx_usb->gadget.dev.parent = &pdev->dev; - imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask; - - ret = device_add(&imx_usb->gadget.dev); - if (retval) - goto fail4; - platform_set_drvdata(pdev, imx_usb); usb_init_data(imx_usb); @@ -1481,11 +1470,9 @@ static int __init imx_udc_probe(struct platform_device *pdev) ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); if (ret) - goto fail5; + goto fail4; return 0; -fail5: - device_unregister(&imx_usb->gadget.dev); fail4: for (i = 0; i < IMX_USB_NB_EP + 1; i++) free_irq(imx_usb->usbd_int[i], imx_usb); @@ -1509,7 +1496,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev) int i; usb_del_gadget_udc(&imx_usb->gadget); - device_unregister(&imx_usb->gadget.dev); imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index aa04089d6899..b943d8cdfbf7 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -1469,23 +1469,7 @@ static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status) status = req->req.status; if (ep->lep) { - enum dma_data_direction direction; - - if (ep->is_in) - direction = DMA_TO_DEVICE; - else - direction = DMA_FROM_DEVICE; - - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - direction); - req->req.dma = 0; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - direction); + usb_gadget_unmap_request(&udc->gadget, &req->req, ep->is_in); /* Free DDs */ udc_dd_free(udc, req->dd_desc_ptr); @@ -1841,26 +1825,11 @@ static int lpc32xx_ep_queue(struct usb_ep *_ep, } if (ep->lep) { - enum dma_data_direction direction; struct lpc32xx_usbd_dd_gad *dd; - /* Map DMA pointer */ - if (ep->is_in) - direction = DMA_TO_DEVICE; - else - direction = DMA_FROM_DEVICE; - - if (req->req.dma == 0) { - req->req.dma = dma_map_single( - ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, direction); - req->mapped = 1; - } else { - dma_sync_single_for_device( - ep->udc->gadget.dev.parent, req->req.dma, - req->req.length, direction); - req->mapped = 0; - } + status = usb_gadget_map_request(&udc->gadget, _req, ep->is_in); + if (status) + return status; /* For the request, build a list of DDs */ dd = udc_dd_alloc(udc); @@ -2977,7 +2946,6 @@ static int lpc32xx_start(struct usb_gadget *gadget, } udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; udc->gadget.dev.of_node = udc->dev->of_node; udc->enabled = 1; udc->selfpowered = 1; @@ -3026,7 +2994,6 @@ static int lpc32xx_stop(struct usb_gadget *gadget, } udc->enabled = 0; - udc->gadget.dev.driver = NULL; udc->driver = NULL; return 0; @@ -3248,12 +3215,6 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev) udc_disable(udc); udc_reinit(udc); - retval = device_register(&udc->gadget.dev); - if (retval < 0) { - dev_err(udc->dev, "Device registration failure\n"); - goto dev_register_fail; - } - /* Request IRQs - low and high priority USB device IRQs are routed to * the same handler, while the DMA interrupt is routed elsewhere */ retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, @@ -3320,8 +3281,6 @@ irq_dev_fail: irq_hp_fail: free_irq(udc->udp_irq[IRQ_USB_LP], udc); irq_lp_fail: - device_unregister(&udc->gadget.dev); -dev_register_fail: dma_pool_destroy(udc->dd_cache); dma_alloc_fail: dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, @@ -3376,8 +3335,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev) free_irq(udc->udp_irq[IRQ_USB_HP], udc); free_irq(udc->udp_irq[IRQ_USB_LP], udc); - device_unregister(&udc->gadget.dev); - clk_disable(udc->usb_otg_clk); clk_put(udc->usb_otg_clk); clk_disable(udc->usb_slv_clk); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index c1b8c2dd808d..866ef0999247 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1471,7 +1471,6 @@ static int m66592_udc_start(struct usb_gadget *g, /* hook up the driver */ driver->driver.bus = NULL; m66592->driver = driver; - m66592->gadget.dev.driver = &driver->driver; m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { @@ -1494,7 +1493,6 @@ static int m66592_udc_stop(struct usb_gadget *g, m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); driver->unbind(&m66592->gadget); - m66592->gadget.dev.driver = NULL; init_controller(m66592); disable_controller(m66592); @@ -1538,7 +1536,6 @@ static int __exit m66592_remove(struct platform_device *pdev) struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); usb_del_gadget_udc(&m66592->gadget); - device_del(&m66592->gadget.dev); del_timer_sync(&m66592->timer); iounmap(m66592->reg); @@ -1608,12 +1605,7 @@ static int __init m66592_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, m66592); m66592->gadget.ops = &m66592_gadget_ops; - device_initialize(&m66592->gadget.dev); - dev_set_name(&m66592->gadget.dev, "gadget"); m66592->gadget.max_speed = USB_SPEED_HIGH; - m66592->gadget.dev.parent = &pdev->dev; - m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; - m66592->gadget.dev.release = pdev->dev.release; m66592->gadget.name = udc_name; init_timer(&m66592->timer); @@ -1674,12 +1666,6 @@ static int __init m66592_probe(struct platform_device *pdev) init_controller(m66592); - ret = device_add(&m66592->gadget.dev); - if (ret) { - pr_err("device_add error (%d)\n", ret); - goto err_device_add; - } - ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); if (ret) goto err_add_udc; @@ -1688,9 +1674,6 @@ static int __init m66592_probe(struct platform_device *pdev) return 0; err_add_udc: - device_del(&m66592->gadget.dev); - -err_device_add: m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); clean_up3: diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 20bbbf917fc2..4a45e80c6e38 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -135,8 +135,8 @@ static struct fsg_common fsg_common; static u8 hostaddr[ETH_ALEN]; -static unsigned char tty_line; static struct usb_function_instance *fi_acm; +static struct eth_dev *the_dev; /********** RNDIS **********/ @@ -152,13 +152,15 @@ static __init int rndis_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - ret = rndis_bind_config(c, hostaddr); + ret = rndis_bind_config(c, hostaddr, the_dev); if (ret < 0) return ret; f_acm_rndis = usb_get_function(fi_acm); - if (IS_ERR(f_acm_rndis)) + if (IS_ERR(f_acm_rndis)) { + ret = PTR_ERR(f_acm_rndis); goto err_func_acm; + } ret = usb_add_function(c, f_acm_rndis); if (ret) @@ -214,7 +216,7 @@ static __init int cdc_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - ret = ecm_bind_config(c, hostaddr); + ret = ecm_bind_config(c, hostaddr, the_dev); if (ret < 0) return ret; @@ -269,7 +271,6 @@ static int cdc_config_register(struct usb_composite_dev *cdev) static int __ref multi_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; - struct f_serial_opts *opts; int status; if (!can_support_ecm(cdev->gadget)) { @@ -279,24 +280,17 @@ static int __ref multi_bind(struct usb_composite_dev *cdev) } /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; + the_dev = gether_setup(cdev->gadget, hostaddr); + if (IS_ERR(the_dev)) + return PTR_ERR(the_dev); /* set up serial link layer */ - status = gserial_alloc_line(&tty_line); - if (status < 0) - goto fail0; - fi_acm = usb_get_function_instance("acm"); if (IS_ERR(fi_acm)) { status = PTR_ERR(fi_acm); - goto fail0dot5; + goto fail0; } - opts = container_of(fi_acm, struct f_serial_opts, func_inst); - opts->port_num = tty_line; - /* set up mass storage function */ { void *retp; @@ -334,10 +328,8 @@ fail2: fsg_common_put(&fsg_common); fail1: usb_put_function_instance(fi_acm); -fail0dot5: - gserial_free_line(tty_line); fail0: - gether_cleanup(); + gether_cleanup(the_dev); return status; } @@ -350,8 +342,7 @@ static int __exit multi_unbind(struct usb_composite_dev *cdev) usb_put_function(f_acm_rndis); #endif usb_put_function_instance(fi_acm); - gserial_free_line(tty_line); - gether_cleanup(); + gether_cleanup(the_dev); return 0; } diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index b5cea273c957..58288e9cf728 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -30,9 +30,6 @@ #include <linux/platform_device.h> #include <linux/platform_data/mv_usb.h> #include <linux/clk.h> -#include <asm/system.h> -#include <asm/unaligned.h> -#include <asm/byteorder.h> #include "mv_u3d.h" @@ -125,7 +122,7 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index, struct mv_u3d_trb *curr_trb; dma_addr_t cur_deq_lo; struct mv_u3d_ep_context *curr_ep_context; - int trb_complete, actual, remaining_length; + int trb_complete, actual, remaining_length = 0; int direction, ep_num; int retval = 0; u32 tmp, status, length; @@ -189,6 +186,8 @@ static int mv_u3d_process_ep_req(struct mv_u3d *u3d, int index, */ static void mv_u3d_done(struct mv_u3d_ep *ep, struct mv_u3d_req *req, int status) + __releases(&ep->udc->lock) + __acquires(&ep->udc->lock) { struct mv_u3d *u3d = (struct mv_u3d *)ep->u3d; @@ -812,19 +811,19 @@ mv_u3d_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) return 0; } - dev_dbg(u3d->dev, "%s: %s, req: 0x%x\n", - __func__, _ep->name, (u32)req); + dev_dbg(u3d->dev, "%s: %s, req: 0x%p\n", + __func__, _ep->name, req); /* catch various bogus parameters */ if (!req->req.complete || !req->req.buf || !list_empty(&req->queue)) { dev_err(u3d->dev, - "%s, bad params, _req: 0x%x," - "req->req.complete: 0x%x, req->req.buf: 0x%x," + "%s, bad params, _req: 0x%p," + "req->req.complete: 0x%p, req->req.buf: 0x%p," "list_empty: 0x%x\n", - __func__, (u32)_req, - (u32)req->req.complete, (u32)req->req.buf, - (u32)list_empty(&req->queue)); + __func__, _req, + req->req.complete, req->req.buf, + list_empty(&req->queue)); return -EINVAL; } if (unlikely(!ep->ep.desc)) { @@ -905,7 +904,7 @@ static int mv_u3d_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) struct mv_u3d_req, queue); /* Point first TRB of next request to the EP context. */ - iowrite32((u32) next_req->trb_head, + iowrite32((unsigned long) next_req->trb_head, &ep_context->trb_addr_lo); } else { struct mv_u3d_ep_context *ep_context; @@ -1264,7 +1263,6 @@ static int mv_u3d_start(struct usb_gadget *g, /* hook up the driver ... */ driver->driver.bus = NULL; u3d->driver = driver; - u3d->gadget.dev.driver = &driver->driver; u3d->ep0_dir = USB_DIR_OUT; @@ -1302,7 +1300,6 @@ static int mv_u3d_stop(struct usb_gadget *g, spin_unlock_irqrestore(&u3d->lock, flags); - u3d->gadget.dev.driver = NULL; u3d->driver = NULL; return 0; @@ -1525,6 +1522,8 @@ static int mv_u3d_is_set_configuration(struct usb_ctrlrequest *setup) static void mv_u3d_handle_setup_packet(struct mv_u3d *u3d, u8 ep_num, struct usb_ctrlrequest *setup) + __releases(&u3c->lock) + __acquires(&u3c->lock) { bool delegate = false; @@ -1758,11 +1757,6 @@ static irqreturn_t mv_u3d_irq(int irq, void *dev) return IRQ_HANDLED; } -static void mv_u3d_gadget_release(struct device *dev) -{ - dev_dbg(dev, "%s\n", __func__); -} - static int mv_u3d_remove(struct platform_device *dev) { struct mv_u3d *u3d = platform_get_drvdata(dev); @@ -1792,8 +1786,6 @@ static int mv_u3d_remove(struct platform_device *dev) clk_put(u3d->clk); - device_unregister(&u3d->gadget.dev); - platform_set_drvdata(dev, NULL); kfree(u3d); @@ -1829,7 +1821,7 @@ static int mv_u3d_probe(struct platform_device *dev) u3d->dev = &dev->dev; u3d->vbus = pdata->vbus; - u3d->clk = clk_get(&dev->dev, pdata->clkname[0]); + u3d->clk = clk_get(&dev->dev, NULL); if (IS_ERR(u3d->clk)) { retval = PTR_ERR(u3d->clk); goto err_get_clk; @@ -1849,8 +1841,9 @@ static int mv_u3d_probe(struct platform_device *dev) retval = -EBUSY; goto err_map_cap_regs; } else { - dev_dbg(&dev->dev, "cap_regs address: 0x%x/0x%x\n", - (unsigned int)r->start, (unsigned int)u3d->cap_regs); + dev_dbg(&dev->dev, "cap_regs address: 0x%lx/0x%lx\n", + (unsigned long) r->start, + (unsigned long) u3d->cap_regs); } /* we will access controller register, so enable the u3d controller */ @@ -1864,10 +1857,10 @@ static int mv_u3d_probe(struct platform_device *dev) } } - u3d->op_regs = (struct mv_u3d_op_regs __iomem *)((u32)u3d->cap_regs + u3d->op_regs = (struct mv_u3d_op_regs __iomem *)(u3d->cap_regs + MV_U3D_USB3_OP_REGS_OFFSET); - u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)((u32)u3d->cap_regs + u3d->vuc_regs = (struct mv_u3d_vuc_regs __iomem *)(u3d->cap_regs + ioread32(&u3d->cap_regs->vuoff)); u3d->max_eps = 16; @@ -1957,16 +1950,8 @@ static int mv_u3d_probe(struct platform_device *dev) u3d->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&u3d->gadget.dev, "gadget"); - u3d->gadget.dev.parent = &dev->dev; - u3d->gadget.dev.dma_mask = dev->dev.dma_mask; - u3d->gadget.dev.release = mv_u3d_gadget_release; u3d->gadget.name = driver_name; /* gadget name */ - retval = device_register(&u3d->gadget.dev); - if (retval) - goto err_register_gadget_device; - mv_u3d_eps_init(u3d); /* external vbus detection */ @@ -1991,8 +1976,6 @@ static int mv_u3d_probe(struct platform_device *dev) return 0; err_unregister: - device_unregister(&u3d->gadget.dev); -err_register_gadget_device: free_irq(u3d->irq, &dev->dev); err_request_irq: err_get_irq: @@ -2021,7 +2004,7 @@ err_pdata: return retval; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int mv_u3d_suspend(struct device *dev) { struct mv_u3d *u3d = dev_get_drvdata(dev); @@ -2064,10 +2047,10 @@ static int mv_u3d_resume(struct device *dev) return 0; } - -SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume); #endif +static SIMPLE_DEV_PM_OPS(mv_u3d_pm_ops, mv_u3d_suspend, mv_u3d_resume); + static void mv_u3d_shutdown(struct platform_device *dev) { struct mv_u3d *u3d = dev_get_drvdata(&dev->dev); @@ -2080,14 +2063,12 @@ static void mv_u3d_shutdown(struct platform_device *dev) static struct platform_driver mv_u3d_driver = { .probe = mv_u3d_probe, - .remove = __exit_p(mv_u3d_remove), + .remove = mv_u3d_remove, .shutdown = mv_u3d_shutdown, .driver = { .owner = THIS_MODULE, .name = "mv-u3d", -#ifdef CONFIG_PM .pm = &mv_u3d_pm_ops, -#endif }, }; diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index 9073436d8b24..be77f207dbaf 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -222,8 +222,7 @@ struct mv_udc { struct mv_usb_platform_data *pdata; /* some SOC has mutiple clock sources for USB*/ - unsigned int clknum; - struct clk *clk[0]; + struct clk *clk; }; /* endpoint data structure */ diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index c8cf959057fe..c2a57023e467 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -212,6 +212,8 @@ static int process_ep_req(struct mv_udc *udc, int index, * request is still in progress. */ static void done(struct mv_ep *ep, struct mv_req *req, int status) + __releases(&ep->udc->lock) + __acquires(&ep->udc->lock) { struct mv_udc *udc = NULL; unsigned char stopped = ep->stopped; @@ -237,18 +239,7 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status) dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma); } - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); + usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep)); if (status && (status != -ESHUTDOWN)) dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u", @@ -732,21 +723,9 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req->ep = ep; /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, ep_dir(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_dir(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } + retval = usb_gadget_map_request(&udc->gadget, _req, ep_dir(ep)); + if (retval) + return retval; req->req.status = -EINPROGRESS; req->req.actual = 0; @@ -780,18 +759,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) return 0; err_unmap_dma: - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); + usb_gadget_unmap_request(&udc->gadget, _req, ep_dir(ep)); return retval; } @@ -1006,18 +974,12 @@ static struct usb_ep_ops mv_ep_ops = { static void udc_clock_enable(struct mv_udc *udc) { - unsigned int i; - - for (i = 0; i < udc->clknum; i++) - clk_prepare_enable(udc->clk[i]); + clk_prepare_enable(udc->clk); } static void udc_clock_disable(struct mv_udc *udc) { - unsigned int i; - - for (i = 0; i < udc->clknum; i++) - clk_disable_unprepare(udc->clk[i]); + clk_disable_unprepare(udc->clk); } static void udc_stop(struct mv_udc *udc) @@ -1386,7 +1348,6 @@ static int mv_udc_start(struct usb_gadget *gadget, /* hook up the driver ... */ driver->driver.bus = NULL; udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; udc->usb_state = USB_STATE_ATTACHED; udc->ep0_state = WAIT_FOR_SETUP; @@ -1401,7 +1362,6 @@ static int mv_udc_start(struct usb_gadget *gadget, dev_err(&udc->dev->dev, "unable to register peripheral to otg\n"); udc->driver = NULL; - udc->gadget.dev.driver = NULL; return retval; } } @@ -1437,7 +1397,6 @@ static int mv_udc_stop(struct usb_gadget *gadget, spin_unlock_irqrestore(&udc->lock, flags); /* unbind gadget driver */ - udc->gadget.dev.driver = NULL; udc->driver = NULL; return 0; @@ -1528,14 +1487,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) return 0; out: - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } + usb_gadget_unmap_request(&udc->gadget, &req->req, ep_dir(ep)); return retval; } @@ -1695,6 +1647,8 @@ out: static void handle_setup_packet(struct mv_udc *udc, u8 ep_num, struct usb_ctrlrequest *setup) + __releases(&ep->udc->lock) + __acquires(&ep->udc->lock) { bool delegate = false; @@ -1891,7 +1845,7 @@ static void irq_process_tr_complete(struct mv_udc *udc) } } -void irq_process_reset(struct mv_udc *udc) +static void irq_process_reset(struct mv_udc *udc) { u32 tmp; unsigned int loops; @@ -2138,8 +2092,6 @@ static int mv_udc_remove(struct platform_device *pdev) mv_udc_disable(udc); - device_unregister(&udc->gadget.dev); - /* free dev, wait for the release() finished */ wait_for_completion(udc->done); @@ -2151,7 +2103,6 @@ static int mv_udc_probe(struct platform_device *pdev) struct mv_usb_platform_data *pdata = pdev->dev.platform_data; struct mv_udc *udc; int retval = 0; - int clk_i = 0; struct resource *r; size_t size; @@ -2160,8 +2111,7 @@ static int mv_udc_probe(struct platform_device *pdev) return -ENODEV; } - size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; - udc = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); if (udc == NULL) { dev_err(&pdev->dev, "failed to allocate memory for udc\n"); return -ENOMEM; @@ -2173,26 +2123,24 @@ static int mv_udc_probe(struct platform_device *pdev) udc->dev = pdev; -#ifdef CONFIG_USB_OTG_UTILS if (pdata->mode == MV_USB_MODE_OTG) { udc->transceiver = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(udc->transceiver)) { + if (IS_ERR(udc->transceiver)) { + retval = PTR_ERR(udc->transceiver); + + if (retval == -ENXIO) + return retval; + udc->transceiver = NULL; - return -ENODEV; + return -EPROBE_DEFER; } } -#endif - udc->clknum = pdata->clknum; - for (clk_i = 0; clk_i < udc->clknum; clk_i++) { - udc->clk[clk_i] = devm_clk_get(&pdev->dev, - pdata->clkname[clk_i]); - if (IS_ERR(udc->clk[clk_i])) { - retval = PTR_ERR(udc->clk[clk_i]); - return retval; - } - } + /* udc only have one sysclk. */ + udc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(udc->clk)) + return PTR_ERR(udc->clk); r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); if (r == NULL) { @@ -2311,16 +2259,8 @@ static int mv_udc_probe(struct platform_device *pdev) udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = pdev->dev.dma_mask; - udc->gadget.dev.release = gadget_release; udc->gadget.name = driver_name; /* gadget name */ - retval = device_register(&udc->gadget.dev); - if (retval) - goto err_destroy_dma; - eps_init(udc); /* VBUS detect: we can disable/enable clock on demand.*/ @@ -2342,7 +2282,7 @@ static int mv_udc_probe(struct platform_device *pdev) if (!udc->qwork) { dev_err(&pdev->dev, "cannot create workqueue\n"); retval = -ENOMEM; - goto err_unregister; + goto err_destroy_dma; } INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); @@ -2358,7 +2298,8 @@ static int mv_udc_probe(struct platform_device *pdev) else udc->vbus_active = 1; - retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + retval = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget, + gadget_release); if (retval) goto err_create_workqueue; @@ -2370,8 +2311,6 @@ static int mv_udc_probe(struct platform_device *pdev) err_create_workqueue: destroy_workqueue(udc->qwork); -err_unregister: - device_unregister(&udc->gadget.dev); err_destroy_dma: dma_pool_destroy(udc->dtd_pool); err_free_dma: diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c index a22ad9af0565..3b02fd4649ce 100644 --- a/drivers/usb/gadget/ncm.c +++ b/drivers/usb/gadget/ncm.c @@ -111,6 +111,7 @@ static struct usb_gadget_strings *dev_strings[] = { NULL, }; +struct eth_dev *the_dev; static u8 hostaddr[ETH_ALEN]; /*-------------------------------------------------------------------------*/ @@ -124,7 +125,7 @@ static int __init ncm_do_config(struct usb_configuration *c) c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; } - return ncm_bind_config(c, hostaddr); + return ncm_bind_config(c, hostaddr, the_dev); } static struct usb_configuration ncm_config_driver = { @@ -143,9 +144,9 @@ static int __init gncm_bind(struct usb_composite_dev *cdev) int status; /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; + the_dev = gether_setup(cdev->gadget, hostaddr); + if (IS_ERR(the_dev)) + return PTR_ERR(the_dev); /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -168,13 +169,13 @@ static int __init gncm_bind(struct usb_composite_dev *cdev) return 0; fail: - gether_cleanup(); + gether_cleanup(the_dev); return status; } static int __exit gncm_unbind(struct usb_composite_dev *cdev) { - gether_cleanup(); + gether_cleanup(the_dev); return 0; } diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index 32524b631959..f1e50a3e322d 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -58,7 +58,6 @@ static const char * const ep_name[] = { "ep-a", "ep-b", "ep-c", }; -#define DMA_ADDR_INVALID (~(dma_addr_t)0) #ifdef CONFIG_USB_NET2272_DMA /* * use_dma: the NET2272 can use an external DMA controller. @@ -341,7 +340,6 @@ net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) if (!req) return NULL; - req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&req->queue); return &req->req; @@ -913,7 +911,7 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } } } - if (likely(req != 0)) + if (likely(req)) list_add_tail(&req->queue, &ep->queue); if (likely(!list_empty(&ep->queue))) @@ -1467,7 +1465,6 @@ static int net2272_start(struct usb_gadget *_gadget, dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -1517,7 +1514,6 @@ static int net2272_stop(struct usb_gadget *_gadget, stop_activity(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); - dev->gadget.dev.driver = NULL; dev->driver = NULL; dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); @@ -1549,7 +1545,7 @@ net2272_handle_dma(struct net2272_ep *ep) | (ep->dev->dma_eot_polarity << EOT_POLARITY) | (ep->dev->dma_dack_polarity << DACK_POLARITY) | (ep->dev->dma_dreq_polarity << DREQ_POLARITY) - | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT)); + | (ep->dma << DMA_ENDPOINT_SELECT)); ep->dev->dma_busy = 0; @@ -1622,7 +1618,7 @@ net2272_handle_ep(struct net2272_ep *ep) ep->irqs++; dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", - ep->ep.name, stat0, stat1, req ? &req->req : 0); + ep->ep.name, stat0, stat1, req ? &req->req : NULL); net2272_ep_write(ep, EP_STAT0, stat0 & ~((1 << NAK_OUT_PACKETS) @@ -2216,7 +2212,6 @@ net2272_remove(struct net2272 *dev) free_irq(dev->irq, dev); iounmap(dev->base_addr); - device_unregister(&dev->gadget.dev); device_remove_file(dev->dev, &dev_attr_registers); dev_info(dev->dev, "unbind\n"); @@ -2243,10 +2238,6 @@ static struct net2272 *net2272_probe_init(struct device *dev, unsigned int irq) ret->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&ret->gadget.dev, "gadget"); - ret->gadget.dev.parent = dev; - ret->gadget.dev.dma_mask = dev->dma_mask; - ret->gadget.dev.release = net2272_gadget_release; ret->gadget.name = driver_name; return ret; @@ -2282,14 +2273,12 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) dma_mode_string()); dev_info(dev->dev, "version: %s\n", driver_vers); - ret = device_register(&dev->gadget.dev); - if (ret) - goto err_irq; ret = device_create_file(dev->dev, &dev_attr_registers); if (ret) - goto err_dev_reg; + goto err_irq; - ret = usb_add_gadget_udc(dev->dev, &dev->gadget); + ret = usb_add_gadget_udc_release(dev->dev, &dev->gadget, + net2272_gadget_release); if (ret) goto err_add_udc; @@ -2297,8 +2286,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) err_add_udc: device_remove_file(dev->dev, &dev_attr_registers); - err_dev_reg: - device_unregister(&dev->gadget.dev); err_irq: free_irq(dev->irq, dev); err: diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 3bd0f992fb49..fbd006ab31d3 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -65,7 +65,6 @@ #define DRIVER_DESC "PLX NET228x USB Peripheral Controller" #define DRIVER_VERSION "2005 Sept 27" -#define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ #define USE_RDK_LEDS /* GPIO pins control three LEDs */ @@ -406,7 +405,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) if (!req) return NULL; - req->req.dma = DMA_ADDR_INVALID; INIT_LIST_HEAD (&req->queue); /* this dma descriptor may be swapped with the previous dummy */ @@ -420,7 +418,6 @@ net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) return NULL; } td->dmacount = 0; /* not VALID */ - td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID); td->dmadesc = td->dmaaddr; req->td = td; } @@ -1896,7 +1893,6 @@ static int net2280_start(struct usb_gadget *_gadget, dev->softconnect = 1; driver->driver.bus = NULL; dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; retval = device_create_file (&dev->pdev->dev, &dev_attr_function); if (retval) goto err_unbind; @@ -1924,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget, err_func: device_remove_file (&dev->pdev->dev, &dev_attr_function); err_unbind: - dev->gadget.dev.driver = NULL; dev->driver = NULL; return retval; } @@ -1967,7 +1962,6 @@ static int net2280_stop(struct usb_gadget *_gadget, stop_activity (dev, driver); spin_unlock_irqrestore (&dev->lock, flags); - dev->gadget.dev.driver = NULL; dev->driver = NULL; net2280_led_active (dev, 0); @@ -2072,7 +2066,7 @@ static void handle_ep_small (struct net2280_ep *ep) return; /* manual DMA queue advance after short OUT */ - if (likely (ep->dma != 0)) { + if (likely (ep->dma)) { if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { u32 count; int stopped = ep->stopped; @@ -2330,7 +2324,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* hw handles device and interface status */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) goto delegate; - if ((e = get_ep_by_addr (dev, w_index)) == 0 + if ((e = get_ep_by_addr (dev, w_index)) == NULL || w_length > 2) goto do_stall; @@ -2358,7 +2352,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == NULL) goto do_stall; if (e->wedged) { VDEBUG(dev, "%s wedged, halt not cleared\n", @@ -2380,7 +2374,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == 0) + if ((e = get_ep_by_addr (dev, w_index)) == NULL) goto do_stall; if (e->ep.name == ep0name) goto do_stall; @@ -2685,7 +2679,6 @@ static void net2280_remove (struct pci_dev *pdev) pci_resource_len (pdev, 0)); if (dev->enabled) pci_disable_device (pdev); - device_unregister (&dev->gadget.dev); device_remove_file (&pdev->dev, &dev_attr_registers); pci_set_drvdata (pdev, NULL); @@ -2717,10 +2710,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) dev->gadget.max_speed = USB_SPEED_HIGH; /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; dev->gadget.name = driver_name; /* now all the pci goodies ... */ @@ -2802,7 +2791,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) goto done; } td->dmacount = 0; /* not VALID */ - td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID); td->dmadesc = td->dmaaddr; dev->ep [i].dummy = td; } @@ -2829,12 +2817,11 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) use_dma ? (use_dma_chaining ? "chaining" : "enabled") : "disabled"); - retval = device_register (&dev->gadget.dev); - if (retval) goto done; retval = device_create_file (&pdev->dev, &dev_attr_registers); if (retval) goto done; - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, + gadget_release); if (retval) goto done; return 0; diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index def37403989a..3b344b41a167 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -37,11 +37,9 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ -#define USB_FACM_INCLUDED -#include "f_acm.c" +#define USBF_OBEX_INCLUDED #include "f_ecm.c" #include "f_obex.c" -#include "f_serial.c" #include "f_phonet.c" #include "u_ether.c" @@ -98,20 +96,40 @@ MODULE_AUTHOR("Felipe Balbi"); MODULE_LICENSE("GPL"); /*-------------------------------------------------------------------------*/ - +static struct usb_function *f_acm_cfg1; +static struct usb_function *f_acm_cfg2; static u8 hostaddr[ETH_ALEN]; +static struct eth_dev *the_dev; enum { TTY_PORT_OBEX0, TTY_PORT_OBEX1, - TTY_PORT_ACM, TTY_PORTS_MAX, }; static unsigned char tty_lines[TTY_PORTS_MAX]; +static struct usb_configuration nokia_config_500ma_driver = { + .label = "Bus Powered", + .bConfigurationValue = 1, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_ONE, + .MaxPower = 500, +}; + +static struct usb_configuration nokia_config_100ma_driver = { + .label = "Self Powered", + .bConfigurationValue = 2, + /* .iConfiguration = DYNAMIC */ + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, + .MaxPower = 100, +}; + +static struct usb_function_instance *fi_acm; + static int __init nokia_bind_config(struct usb_configuration *c) { + struct usb_function *f_acm; int status = 0; status = phonet_bind_config(c); @@ -126,33 +144,32 @@ static int __init nokia_bind_config(struct usb_configuration *c) if (status) printk(KERN_DEBUG "could not bind obex config %d\n", 0); - status = acm_bind_config(c, tty_lines[TTY_PORT_ACM]); - if (status) - printk(KERN_DEBUG "could not bind acm config\n"); + f_acm = usb_get_function(fi_acm); + if (IS_ERR(f_acm)) + return PTR_ERR(f_acm); - status = ecm_bind_config(c, hostaddr); + status = usb_add_function(c, f_acm); if (status) - printk(KERN_DEBUG "could not bind ecm config\n"); + goto err_conf; + + status = ecm_bind_config(c, hostaddr, the_dev); + if (status) { + pr_debug("could not bind ecm config %d\n", status); + goto err_ecm; + } + if (c == &nokia_config_500ma_driver) + f_acm_cfg1 = f_acm; + else + f_acm_cfg2 = f_acm; return status; +err_ecm: + usb_remove_function(c, f_acm); +err_conf: + usb_put_function(f_acm); + return status; } -static struct usb_configuration nokia_config_500ma_driver = { - .label = "Bus Powered", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_ONE, - .MaxPower = 500, -}; - -static struct usb_configuration nokia_config_100ma_driver = { - .label = "Self Powered", - .bConfigurationValue = 2, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .MaxPower = 100, -}; - static int __init nokia_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; @@ -169,9 +186,11 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) goto err_ether; } - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) + the_dev = gether_setup(cdev->gadget, hostaddr); + if (IS_ERR(the_dev)) { + status = PTR_ERR(the_dev); goto err_ether; + } status = usb_string_ids_tab(cdev, strings_dev); if (status < 0) @@ -185,24 +204,32 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) if (!gadget_supports_altsettings(gadget)) goto err_usb; + fi_acm = usb_get_function_instance("acm"); + if (IS_ERR(fi_acm)) + goto err_usb; + /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) - goto err_usb; + goto err_acm_inst; status = usb_add_config(cdev, &nokia_config_100ma_driver, nokia_bind_config); if (status < 0) - goto err_usb; + goto err_put_cfg1; usb_composite_overwrite_options(cdev, &coverwrite); dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); return 0; +err_put_cfg1: + usb_put_function(f_acm_cfg1); +err_acm_inst: + usb_put_function_instance(fi_acm); err_usb: - gether_cleanup(); + gether_cleanup(the_dev); err_ether: cur_line--; while (cur_line >= 0) @@ -217,12 +244,15 @@ static int __exit nokia_unbind(struct usb_composite_dev *cdev) { int i; + usb_put_function(f_acm_cfg1); + usb_put_function(f_acm_cfg2); + usb_put_function_instance(fi_acm); gphonet_cleanup(); for (i = 0; i < TTY_PORTS_MAX; i++) gserial_free_line(tty_lines[i]); - gether_cleanup(); + gether_cleanup(the_dev); return 0; } @@ -247,4 +277,3 @@ static void __exit nokia_cleanup(void) usb_composite_unregister(&nokia_driver); } module_exit(nokia_cleanup); - diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index f8445653577f..b8ed74a823cb 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2067,7 +2067,6 @@ static int omap_udc_start(struct usb_gadget *g, /* hook up the driver */ driver->driver.bus = NULL; udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); if (udc->dc_clk != NULL) @@ -2083,7 +2082,6 @@ static int omap_udc_start(struct usb_gadget *g, ERR("can't bind to transceiver\n"); if (driver->unbind) { driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; udc->driver = NULL; } goto done; @@ -2129,7 +2127,6 @@ static int omap_udc_stop(struct usb_gadget *g, udc_quiesce(udc); spin_unlock_irqrestore(&udc->lock, flags); - udc->gadget.dev.driver = NULL; udc->driver = NULL; if (udc->dc_clk != NULL) @@ -2631,14 +2628,6 @@ omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) udc->gadget.speed = USB_SPEED_UNKNOWN; udc->gadget.max_speed = USB_SPEED_FULL; udc->gadget.name = driver_name; - - device_initialize(&udc->gadget.dev); - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.release = omap_udc_release; - udc->gadget.dev.parent = &odev->dev; - if (use_dma) - udc->gadget.dev.dma_mask = odev->dev.dma_mask; - udc->transceiver = xceiv; /* ep0 is special; put it right after the SETUP buffer */ @@ -2912,14 +2901,13 @@ bad_on_1710: } create_proc_file(); - status = device_add(&udc->gadget.dev); + status = usb_add_gadget_udc_release(&pdev->dev, &udc->gadget, + omap_udc_release); if (status) goto cleanup4; - status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (!status) - return status; - /* If fail, fall through */ + return 0; + cleanup4: remove_proc_file(); @@ -2990,7 +2978,6 @@ static int omap_udc_remove(struct platform_device *pdev) release_mem_region(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1); - device_unregister(&udc->gadget.dev); wait_for_completion(&done); return 0; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index a787a8ef672b..24174e1d1564 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -358,7 +358,6 @@ struct pch_udc_dev { prot_stall:1, irq_registered:1, mem_region:1, - registered:1, suspended:1, connected:1, vbus_session:1, @@ -1441,6 +1440,8 @@ static void pch_vbus_gpio_free(struct pch_udc_dev *dev) */ static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, int status) + __releases(&dev->lock) + __acquires(&dev->lock) { struct pch_udc_dev *dev; unsigned halted = ep->halted; @@ -2382,6 +2383,8 @@ static void pch_udc_svc_control_in(struct pch_udc_dev *dev) * @dev: Reference to the device structure */ static void pch_udc_svc_control_out(struct pch_udc_dev *dev) + __releases(&dev->lock) + __acquires(&dev->lock) { u32 stat; int setup_supported; @@ -2989,7 +2992,6 @@ static int pch_udc_start(struct usb_gadget *g, driver->driver.bus = NULL; dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; /* get ready for ep0 traffic */ pch_udc_setup_ep0(dev); @@ -3010,7 +3012,6 @@ static int pch_udc_stop(struct usb_gadget *g, pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); /* Assures that there are no pending requests with this driver */ - dev->gadget.dev.driver = NULL; dev->driver = NULL; dev->connected = 0; @@ -3078,8 +3079,6 @@ static void pch_udc_remove(struct pci_dev *pdev) pci_resource_len(pdev, PCH_UDC_PCI_BAR)); if (dev->active) pci_disable_device(pdev); - if (dev->registered) - device_unregister(&dev->gadget.dev); kfree(dev); pci_set_drvdata(pdev, NULL); } @@ -3196,21 +3195,13 @@ static int pch_udc_probe(struct pci_dev *pdev, if (retval) goto finished; - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; dev->gadget.name = KBUILD_MODNAME; dev->gadget.max_speed = USB_SPEED_HIGH; - retval = device_register(&dev->gadget.dev); - if (retval) - goto finished; - dev->registered = 1; - /* Put the device in disconnected state till a driver is bound */ pch_udc_set_disconnect(dev); - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); + retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, + gadget_release); if (retval) goto finished; return 0; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index d0f37484b6b0..ef47495dec8f 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1263,7 +1263,6 @@ static int pxa25x_udc_start(struct usb_gadget *g, /* first hook up the driver ... */ dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; dev->pullup = 1; /* ... then enable host detection and ep0; and we're ready @@ -1325,7 +1324,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g, if (!IS_ERR_OR_NULL(dev->transceiver)) (void) otg_set_peripheral(dev->transceiver->otg, NULL); - dev->gadget.dev.driver = NULL; dev->driver = NULL; dump_state(dev); @@ -2138,17 +2136,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) dev->timer.function = udc_watchdog; dev->timer.data = (unsigned long) dev; - device_initialize(&dev->gadget.dev); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - - retval = device_add(&dev->gadget.dev); - if (retval) { - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - goto err_device_add; - } - the_controller = dev; platform_set_drvdata(pdev, dev); @@ -2199,8 +2186,6 @@ lubbock_fail0: free_irq(irq, dev); #endif err_irq1: - device_unregister(&dev->gadget.dev); - err_device_add: if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); err_gpio_pullup: @@ -2226,7 +2211,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) return -EBUSY; usb_del_gadget_udc(&dev->gadget); - device_unregister(&dev->gadget.dev); dev->pullup = 0; pullup(dev); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 2fc867652ef5..6b4c7d95853f 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -24,14 +24,12 @@ #include <linux/gpio.h> #include <linux/slab.h> #include <linux/prefetch.h> - -#include <asm/byteorder.h> -#include <mach/hardware.h> +#include <linux/byteorder/generic.h> +#include <linux/platform_data/pxa2xx_udc.h> #include <linux/usb.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> -#include <mach/udc.h> #include "pxa27x_udc.h" @@ -611,7 +609,7 @@ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in) * * Find the physical pxa27x ep, and setup its UDCCR */ -static __init void pxa_ep_setup(struct pxa_ep *ep) +static void pxa_ep_setup(struct pxa_ep *ep) { u32 new_udccr; @@ -633,7 +631,7 @@ static __init void pxa_ep_setup(struct pxa_ep *ep) * * Setup all pxa physical endpoints, except ep0 */ -static __init void pxa_eps_setup(struct pxa_udc *dev) +static void pxa_eps_setup(struct pxa_udc *dev) { unsigned int i; @@ -1718,7 +1716,7 @@ static void udc_disable(struct pxa_udc *udc) * Initializes gadget endpoint list, endpoints locks. No action is taken * on the hardware. */ -static __init void udc_init_data(struct pxa_udc *dev) +static void udc_init_data(struct pxa_udc *dev) { int i; struct pxa_ep *ep; @@ -1811,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g, /* first hook up the driver ... */ udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; dplus_pullup(udc, 1); if (!IS_ERR_OR_NULL(udc->transceiver)) { @@ -1829,7 +1826,6 @@ static int pxa27x_udc_start(struct usb_gadget *g, fail: udc->driver = NULL; - udc->gadget.dev.driver = NULL; return retval; } @@ -1871,7 +1867,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g, udc->driver = NULL; - if (!IS_ERR_OR_NULL(udc->transceiver)) return otg_set_peripheral(udc->transceiver->otg, NULL); return 0; @@ -2413,7 +2408,7 @@ static struct pxa_udc memory = { * Perform basic init : allocates udc clock, creates sysfs files, requests * irq. */ -static int __init pxa_udc_probe(struct platform_device *pdev) +static int pxa_udc_probe(struct platform_device *pdev) { struct resource *regs; struct pxa_udc *udc = &memory; @@ -2456,9 +2451,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev) goto err_map; } - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = NULL; udc->vbus_sensed = 0; the_controller = udc; @@ -2475,12 +2467,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev) goto err_irq; } - retval = device_add(&udc->gadget.dev); - if (retval) { - dev_err(udc->dev, "device_add error %d\n", retval); - goto err_dev_add; - } - retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); if (retval) goto err_add_udc; @@ -2490,8 +2476,6 @@ static int __init pxa_udc_probe(struct platform_device *pdev) return 0; err_add_udc: - device_unregister(&udc->gadget.dev); -err_dev_add: free_irq(udc->irq, udc); err_irq: iounmap(udc->regs); @@ -2506,13 +2490,12 @@ err_clk: * pxa_udc_remove - removes the udc device driver * @_dev: platform device */ -static int __exit pxa_udc_remove(struct platform_device *_dev) +static int pxa_udc_remove(struct platform_device *_dev) { struct pxa_udc *udc = platform_get_drvdata(_dev); int gpio = udc->mach->gpio_pullup; usb_del_gadget_udc(&udc->gadget); - device_del(&udc->gadget.dev); usb_gadget_unregister_driver(udc->driver); free_irq(udc->irq, udc); pxa_cleanup_debugfs(udc); @@ -2625,7 +2608,8 @@ static struct platform_driver udc_driver = { .name = "pxa27x-udc", .owner = THIS_MODULE, }, - .remove = __exit_p(pxa_udc_remove), + .probe = pxa_udc_probe, + .remove = pxa_udc_remove, .shutdown = pxa_udc_shutdown, #ifdef CONFIG_PM .suspend = pxa_udc_suspend, @@ -2633,22 +2617,7 @@ static struct platform_driver udc_driver = { #endif }; -static int __init udc_init(void) -{ - if (!cpu_is_pxa27x() && !cpu_is_pxa3xx()) - return -ENODEV; - - printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, pxa_udc_probe); -} -module_init(udc_init); - - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); +module_platform_driver(udc_driver); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Robert Jarzmik"); diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index f46a1b77ce3e..0b742d171843 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1837,7 +1837,6 @@ static int __exit r8a66597_remove(struct platform_device *pdev) clk_put(r8a66597->clk); } - device_unregister(&r8a66597->gadget.dev); kfree(r8a66597); return 0; } @@ -1915,17 +1914,8 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->gadget.ops = &r8a66597_gadget_ops; - dev_set_name(&r8a66597->gadget.dev, "gadget"); r8a66597->gadget.max_speed = USB_SPEED_HIGH; - r8a66597->gadget.dev.parent = &pdev->dev; - r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; - r8a66597->gadget.dev.release = pdev->dev.release; r8a66597->gadget.name = udc_name; - ret = device_register(&r8a66597->gadget.dev); - if (ret < 0) { - dev_err(&pdev->dev, "device_register failed\n"); - goto clean_up; - } init_timer(&r8a66597->timer); r8a66597->timer.function = r8a66597_timer; @@ -1939,7 +1929,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(r8a66597->clk); - goto clean_up_dev; + goto clean_up; } clk_enable(r8a66597->clk); } @@ -2007,8 +1997,6 @@ clean_up2: clk_disable(r8a66597->clk); clk_put(r8a66597->clk); } -clean_up_dev: - device_unregister(&r8a66597->gadget.dev); clean_up: if (r8a66597) { if (r8a66597->sudmac_reg) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index c26564f29a2c..a3cdc32115d5 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -39,8 +39,6 @@ #include "s3c-hsotg.h" -#define DMA_ADDR_INVALID (~((dma_addr_t)0)) - static const char * const s3c_hsotg_supply_names[] = { "vusb_d", /* digital USB supply, 1.2V */ "vusb_a", /* analog USB supply, 1.1V */ @@ -405,7 +403,6 @@ static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, INIT_LIST_HEAD(&req->queue); - req->req.dma = DMA_ADDR_INVALID; return &req->req; } @@ -435,24 +432,12 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_req *hs_req) { struct usb_request *req = &hs_req->req; - enum dma_data_direction dir; - - dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; /* ignore this if we're not moving any data */ if (hs_req->req.length == 0) return; - if (hs_req->mapped) { - /* we mapped this, so unmap and remove the dma */ - - dma_unmap_single(hsotg->dev, req->dma, req->length, dir); - - req->dma = DMA_ADDR_INVALID; - hs_req->mapped = 0; - } else { - dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); - } + usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in); } /** @@ -852,37 +837,16 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct usb_request *req) { - enum dma_data_direction dir; struct s3c_hsotg_req *hs_req = our_req(req); - - dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + int ret; /* if the length is zero, ignore the DMA data */ if (hs_req->req.length == 0) return 0; - if (req->dma == DMA_ADDR_INVALID) { - dma_addr_t dma; - - dma = dma_map_single(hsotg->dev, req->buf, req->length, dir); - - if (unlikely(dma_mapping_error(hsotg->dev, dma))) - goto dma_error; - - if (dma & 3) { - dev_err(hsotg->dev, "%s: unaligned dma buffer\n", - __func__); - - dma_unmap_single(hsotg->dev, dma, req->length, dir); - return -EINVAL; - } - - hs_req->mapped = 1; - req->dma = dma; - } else { - dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); - hs_req->mapped = 0; - } + ret = usb_gadget_map_request(&hsotg->gadget, req, hs_ep->dir_in); + if (ret) + goto dma_error; return 0; @@ -2961,9 +2925,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, driver->driver.bus = NULL; hsotg->driver = driver; - hsotg->gadget.dev.driver = &driver->driver; hsotg->gadget.dev.of_node = hsotg->dev->of_node; - hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask; hsotg->gadget.speed = USB_SPEED_UNKNOWN; ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), @@ -2979,7 +2941,6 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget, err: hsotg->driver = NULL; - hsotg->gadget.dev.driver = NULL; return ret; } @@ -3014,7 +2975,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, hsotg->driver = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; - hsotg->gadget.dev.driver = NULL; spin_unlock_irqrestore(&hsotg->lock, flags); @@ -3484,16 +3444,6 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) } /** - * s3c_hsotg_release - release callback for hsotg device - * @dev: Device to for which release is called - * - * Nothing to do as the resource is allocated using devm_ API. - */ -static void s3c_hsotg_release(struct device *dev) -{ -} - -/** * s3c_hsotg_probe - probe function for hsotg driver * @pdev: The platform information for the driver */ @@ -3517,7 +3467,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev) } phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(phy)) { + if (IS_ERR(phy)) { /* Fallback for pdata */ plat = pdev->dev.platform_data; if (!plat) { @@ -3567,18 +3517,10 @@ static int s3c_hsotg_probe(struct platform_device *pdev) dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); - device_initialize(&hsotg->gadget.dev); - - dev_set_name(&hsotg->gadget.dev, "gadget"); - hsotg->gadget.max_speed = USB_SPEED_HIGH; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); - hsotg->gadget.dev.parent = dev; - hsotg->gadget.dev.dma_mask = dev->dma_mask; - hsotg->gadget.dev.release = s3c_hsotg_release; - /* reset the system */ clk_prepare_enable(hsotg->clk); @@ -3658,12 +3600,6 @@ static int s3c_hsotg_probe(struct platform_device *pdev) s3c_hsotg_phy_disable(hsotg); - ret = device_add(&hsotg->gadget.dev); - if (ret) { - put_device(&hsotg->gadget.dev); - goto err_ep_mem; - } - ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); if (ret) goto err_ep_mem; @@ -3702,10 +3638,8 @@ static int s3c_hsotg_remove(struct platform_device *pdev) } s3c_hsotg_phy_disable(hsotg); - clk_disable_unprepare(hsotg->clk); - device_unregister(&hsotg->gadget.dev); return 0; } diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 458965a1b138..b1f0771fbd3d 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -283,7 +283,6 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status) /** * s3c_hsudc_stop_activity - Stop activity on all endpoints. * @hsudc: Device controller for which EP activity is to be stopped. - * @driver: Reference to the gadget driver which is currently active. * * All the endpoints are stopped and any pending transfer requests if any on * the endpoint are terminated. @@ -1154,7 +1153,6 @@ static int s3c_hsudc_start(struct usb_gadget *gadget, return -EBUSY; hsudc->driver = driver; - hsudc->gadget.dev.driver = &driver->driver; ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); @@ -1190,7 +1188,6 @@ err_otg: regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); err_supplies: hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; return ret; } @@ -1208,7 +1205,6 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget, spin_lock_irqsave(&hsudc->lock, flags); hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; hsudc->gadget.speed = USB_SPEED_UNKNOWN; s3c_hsudc_uninit_phy(); @@ -1303,15 +1299,10 @@ static int s3c_hsudc_probe(struct platform_device *pdev) spin_lock_init(&hsudc->lock); - dev_set_name(&hsudc->gadget.dev, "gadget"); - hsudc->gadget.max_speed = USB_SPEED_HIGH; hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.name = dev_name(dev); - hsudc->gadget.dev.parent = dev; - hsudc->gadget.dev.dma_mask = dev->dma_mask; hsudc->gadget.ep0 = &hsudc->ep[0].ep; - hsudc->gadget.is_otg = 0; hsudc->gadget.is_a_peripheral = 0; hsudc->gadget.speed = USB_SPEED_UNKNOWN; @@ -1345,12 +1336,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev) disable_irq(hsudc->irq); local_irq_enable(); - ret = device_register(&hsudc->gadget.dev); - if (ret) { - put_device(&hsudc->gadget.dev); - goto err_add_device; - } - ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); if (ret) goto err_add_udc; @@ -1359,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev) return 0; err_add_udc: - device_unregister(&hsudc->gadget.dev); err_add_device: clk_disable(hsudc->uclk); err_res: diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 08f89652533b..d0e75e1b3ccb 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1674,7 +1674,6 @@ static int s3c2410_udc_start(struct usb_gadget *g, /* Hook the driver */ udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; /* Enable udc */ s3c2410_udc_enable(udc); @@ -1824,17 +1823,6 @@ static int s3c2410_udc_probe(struct platform_device *pdev) goto err_mem; } - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = pdev->dev.dma_mask; - - /* Bind the driver */ - retval = device_add(&udc->gadget.dev); - if (retval) { - dev_err(&udc->gadget.dev, "Error in device_add() : %d\n", retval); - goto err_device_add; - } - the_controller = udc; platform_set_drvdata(pdev, udc); @@ -1923,8 +1911,6 @@ err_gpio_claim: err_int: free_irq(IRQ_USBD, udc); err_map: - device_unregister(&udc->gadget.dev); -err_device_add: iounmap(base_addr); err_mem: release_mem_region(rsrc_start, rsrc_len); @@ -1946,7 +1932,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev) return -EBUSY; usb_del_gadget_udc(&udc->gadget); - device_unregister(&udc->gadget.dev); debugfs_remove(udc->regs_info); if (udc_info && !udc_info->udc_command && diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 68d7bb06ebcb..1f5f978d35d5 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -28,18 +29,6 @@ #define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR /*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module. So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "f_obex.c" -#include "f_serial.c" - -/*-------------------------------------------------------------------------*/ USB_GADGET_COMPOSITE_OPTIONS(); /* Thanks to NetChip Technologies for donating this product ID. @@ -126,27 +115,6 @@ module_param(n_ports, uint, 0); MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); /*-------------------------------------------------------------------------*/ -static unsigned char tty_lines[MAX_U_SERIAL_PORTS]; - -static int __init serial_bind_obex_config(struct usb_configuration *c) -{ - unsigned i; - int status = 0; - - for (i = 0; i < n_ports && status == 0; i++) - status = obex_bind_config(c, tty_lines[i]); - return status; -} - -static int __init serial_bind_gser_config(struct usb_configuration *c) -{ - unsigned i; - int status = 0; - - for (i = 0; i < n_ports && status == 0; i++) - status = gser_bind_config(c, tty_lines[i]); - return status; -} static struct usb_configuration serial_config_driver = { /* .label = f(use_acm) */ @@ -169,15 +137,12 @@ static int serial_register_ports(struct usb_composite_dev *cdev, goto out; for (i = 0; i < n_ports; i++) { - struct f_serial_opts *opts; fi_serial[i] = usb_get_function_instance(f_name); if (IS_ERR(fi_serial[i])) { ret = PTR_ERR(fi_serial[i]); goto fail; } - opts = container_of(fi_serial[i], struct f_serial_opts, func_inst); - opts->port_num = tty_lines[i]; f_serial[i] = usb_get_function(fi_serial[i]); if (IS_ERR(f_serial[i])) { @@ -212,13 +177,6 @@ out: static int __init gs_bind(struct usb_composite_dev *cdev) { int status; - int cur_line; - - for (cur_line = 0; cur_line < n_ports; cur_line++) { - status = gserial_alloc_line(&tty_lines[cur_line]); - if (status) - goto fail; - } /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue. @@ -243,11 +201,12 @@ static int __init gs_bind(struct usb_composite_dev *cdev) "acm"); usb_ep_autoconfig_reset(cdev->gadget); } else if (use_obex) - status = usb_add_config(cdev, &serial_config_driver, - serial_bind_obex_config); - else - status = usb_add_config(cdev, &serial_config_driver, - serial_bind_gser_config); + status = serial_register_ports(cdev, &serial_config_driver, + "obex"); + else { + status = serial_register_ports(cdev, &serial_config_driver, + "gser"); + } if (status < 0) goto fail; @@ -257,9 +216,6 @@ static int __init gs_bind(struct usb_composite_dev *cdev) return 0; fail: - cur_line--; - while (cur_line >= 0) - gserial_free_line(tty_lines[cur_line--]); return status; } @@ -270,7 +226,6 @@ static int gs_unbind(struct usb_composite_dev *cdev) for (i = 0; i < n_ports; i++) { usb_put_function(f_serial[i]); usb_put_function_instance(fi_serial[i]); - gserial_free_line(tty_lines[i]); } return 0; } diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index a0aa721d8b21..4b76124ce96b 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -50,7 +50,6 @@ struct eth_dev { /* lock is held while accessing port_usb - * or updating its backlink port_usb->ioport */ spinlock_t lock; struct gether *port_usb; @@ -729,8 +728,6 @@ static int get_ether_addr(const char *str, u8 *dev_addr) return 1; } -static struct eth_dev *the_dev; - static const struct net_device_ops eth_netdev_ops = { .ndo_open = eth_open, .ndo_stop = eth_stop, @@ -758,19 +755,16 @@ static struct device_type gadget_type = { * * Returns negative errno, or zero on success */ -int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], +struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], const char *netname) { struct eth_dev *dev; struct net_device *net; int status; - if (the_dev) - return -EBUSY; - net = alloc_etherdev(sizeof *dev); if (!net) - return -ENOMEM; + return ERR_PTR(-ENOMEM); dev = netdev_priv(net); spin_lock_init(&dev->lock); @@ -807,12 +801,11 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], if (status < 0) { dev_dbg(&g->dev, "register_netdev failed, %d\n", status); free_netdev(net); + dev = ERR_PTR(status); } else { INFO(dev, "MAC %pM\n", net->dev_addr); INFO(dev, "HOST MAC %pM\n", dev->host_mac); - the_dev = dev; - /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" @@ -820,7 +813,7 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], netif_carrier_off(net); } - return status; + return dev; } /** @@ -829,19 +822,16 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], * * This is called to free all resources allocated by @gether_setup(). */ -void gether_cleanup(void) +void gether_cleanup(struct eth_dev *dev) { - if (!the_dev) + if (!dev) return; - unregister_netdev(the_dev->net); - flush_work(&the_dev->work); - free_netdev(the_dev->net); - - the_dev = NULL; + unregister_netdev(dev->net); + flush_work(&dev->work); + free_netdev(dev->net); } - /** * gether_connect - notify network layer that USB link is active * @link: the USB link, set up with endpoints, descriptors matching @@ -860,7 +850,7 @@ void gether_cleanup(void) */ struct net_device *gether_connect(struct gether *link) { - struct eth_dev *dev = the_dev; + struct eth_dev *dev = link->ioport; int result = 0; if (!dev) @@ -895,7 +885,6 @@ struct net_device *gether_connect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = link; - link->ioport = dev; if (netif_running(dev->net)) { if (link->open) link->open(link); @@ -989,6 +978,5 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; - link->ioport = NULL; spin_unlock(&dev->lock); } diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 6f4a1623d854..02522338a708 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -21,6 +21,7 @@ #include "gadget_chips.h" +struct eth_dev; /* * This represents the USB side of an "ethernet" link, managed by a USB @@ -70,7 +71,7 @@ struct gether { |USB_CDC_PACKET_TYPE_DIRECTED) /* variant of gether_setup that allows customizing network device name */ -int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], +struct eth_dev *gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], const char *netname); /* netdev setup/teardown as directed by the gadget driver */ @@ -86,12 +87,13 @@ int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], * * Returns negative errno, or zero on success */ -static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +static inline struct eth_dev *gether_setup(struct usb_gadget *g, + u8 ethaddr[ETH_ALEN]) { return gether_setup_name(g, ethaddr, "usb"); } -void gether_cleanup(void); +void gether_cleanup(struct eth_dev *dev); /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); @@ -111,21 +113,24 @@ static inline bool can_support_ecm(struct usb_gadget *gadget) } /* each configuration may bind one instance of an ethernet link */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int eem_bind_config(struct usb_configuration *c); +int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev); +int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev); +int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + struct eth_dev *dev); +int eem_bind_config(struct usb_configuration *c, struct eth_dev *dev); #ifdef USB_ETH_RNDIS int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer); + u32 vendorID, const char *manufacturer, struct eth_dev *dev); #else static inline int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer) + u32 vendorID, const char *manufacturer, struct eth_dev *dev) { return 0; } @@ -145,9 +150,9 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], * for calling @gether_cleanup() before module unload. */ static inline int rndis_bind_config(struct usb_configuration *c, - u8 ethaddr[ETH_ALEN]) + u8 ethaddr[ETH_ALEN], struct eth_dev *dev) { - return rndis_bind_config_vendor(c, ethaddr, 0, NULL); + return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev); } diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h index 66ce73a00509..c20210c0babd 100644 --- a/drivers/usb/gadget/u_serial.h +++ b/drivers/usb/gadget/u_serial.h @@ -65,7 +65,6 @@ int gserial_connect(struct gserial *, u8 port_num); void gserial_disconnect(struct gserial *); /* functions are bound to configurations by a config or gadget driver */ -int acm_bind_config(struct usb_configuration *c, u8 port_num); int gser_bind_config(struct usb_configuration *c, u8 port_num); int obex_bind_config(struct usb_configuration *c, u8 port_num); diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index f8f62c3ed65e..ffd8fa541101 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -101,6 +101,16 @@ EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); /* ------------------------------------------------------------------------- */ +void usb_gadget_set_state(struct usb_gadget *gadget, + enum usb_device_state state) +{ + gadget->state = state; + sysfs_notify(&gadget->dev.kobj, NULL, "status"); +} +EXPORT_SYMBOL_GPL(usb_gadget_set_state); + +/* ------------------------------------------------------------------------- */ + /** * usb_gadget_udc_start - tells usb device controller to start up * @gadget: The gadget we want to get started @@ -156,15 +166,23 @@ static void usb_udc_release(struct device *dev) } static const struct attribute_group *usb_udc_attr_groups[]; + +static void usb_udc_nop_release(struct device *dev) +{ + dev_vdbg(dev, "%s\n", __func__); +} + /** - * usb_add_gadget_udc - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller - * driver's device. - * @gadget: the gadget to be added to the list + * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller driver's + * device. + * @gadget: the gadget to be added to the list. + * @release: a gadget release function. * * Returns zero on success, negative errno otherwise. */ -int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, + void (*release)(struct device *dev)) { struct usb_udc *udc; int ret = -ENOMEM; @@ -173,6 +191,22 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) if (!udc) goto err1; + dev_set_name(&gadget->dev, "gadget"); + gadget->dev.parent = parent; + + dma_set_coherent_mask(&gadget->dev, parent->coherent_dma_mask); + gadget->dev.dma_parms = parent->dma_parms; + gadget->dev.dma_mask = parent->dma_mask; + + if (release) + gadget->dev.release = release; + else + gadget->dev.release = usb_udc_nop_release; + + ret = device_register(&gadget->dev); + if (ret) + goto err2; + device_initialize(&udc->dev); udc->dev.release = usb_udc_release; udc->dev.class = udc_class; @@ -180,7 +214,7 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) udc->dev.parent = parent; ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); if (ret) - goto err2; + goto err3; udc->gadget = gadget; @@ -189,21 +223,42 @@ int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) ret = device_add(&udc->dev); if (ret) - goto err3; + goto err4; + + usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); mutex_unlock(&udc_lock); return 0; -err3: + +err4: list_del(&udc->list); mutex_unlock(&udc_lock); -err2: +err3: put_device(&udc->dev); +err2: + put_device(&gadget->dev); + kfree(udc); + err1: return ret; } +EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); + +/** + * usb_add_gadget_udc - adds a new gadget to the udc class driver list + * @parent: the parent device to this udc. Usually the controller + * driver's device. + * @gadget: the gadget to be added to the list + * + * Returns zero on success, negative errno otherwise. + */ +int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) +{ + return usb_add_gadget_udc_release(parent, gadget, NULL); +} EXPORT_SYMBOL_GPL(usb_add_gadget_udc); static void usb_gadget_remove_driver(struct usb_udc *udc) @@ -220,6 +275,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) udc->driver = NULL; udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; } /** @@ -254,6 +310,7 @@ found: kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); device_unregister(&udc->dev); + device_unregister(&gadget->dev); } EXPORT_SYMBOL_GPL(usb_del_gadget_udc); @@ -268,6 +325,7 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri udc->driver = driver; udc->dev.driver = &driver->driver; + udc->gadget->dev.driver = &driver->driver; ret = driver->bind(udc->gadget, driver); if (ret) @@ -286,6 +344,7 @@ err1: udc->driver->function, ret); udc->driver = NULL; udc->dev.driver = NULL; + udc->gadget->dev.driver = NULL; return ret; } @@ -395,6 +454,16 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); +static ssize_t usb_gadget_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); + struct usb_gadget *gadget = udc->gadget; + + return sprintf(buf, "%s\n", usb_state_string(gadget->state)); +} +static DEVICE_ATTR(state, S_IRUGO, usb_gadget_state_show, NULL); + #define USB_UDC_SPEED_ATTR(name, param) \ ssize_t usb_udc_##param##_show(struct device *dev, \ struct device_attribute *attr, char *buf) \ @@ -403,7 +472,7 @@ ssize_t usb_udc_##param##_show(struct device *dev, \ return snprintf(buf, PAGE_SIZE, "%s\n", \ usb_speed_string(udc->gadget->param)); \ } \ -static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) +static DEVICE_ATTR(name, S_IRUGO, usb_udc_##param##_show, NULL) static USB_UDC_SPEED_ATTR(current_speed, speed); static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); @@ -428,6 +497,7 @@ static USB_UDC_ATTR(a_alt_hnp_support); static struct attribute *usb_udc_attrs[] = { &dev_attr_srp.attr, &dev_attr_soft_connect.attr, + &dev_attr_state.attr, &dev_attr_current_speed.attr, &dev_attr_maximum_speed.attr, diff --git a/drivers/usb/gadget/uvc.h b/drivers/usb/gadget/uvc.h index 93b0c1191115..817e9e19cecf 100644 --- a/drivers/usb/gadget/uvc.h +++ b/drivers/usb/gadget/uvc.h @@ -98,8 +98,6 @@ extern unsigned int uvc_gadget_trace_param; #define DRIVER_VERSION "0.1.0" #define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0) -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - #define UVC_NUM_REQUESTS 4 #define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_EVENTS 4 @@ -190,6 +188,7 @@ struct uvc_file_handle * Functions */ +extern void uvc_function_setup_continue(struct uvc_device *uvc); extern void uvc_endpoint_stream(struct uvc_device *dev); extern void uvc_function_connect(struct uvc_device *uvc); diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 104ae9c81251..7ce27e35550b 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -10,6 +10,7 @@ * (at your option) any later version. */ +#include <linux/atomic.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/list.h> @@ -18,7 +19,8 @@ #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> -#include <linux/atomic.h> + +#include <media/videobuf2-vmalloc.h> #include "uvc.h" @@ -28,330 +30,175 @@ * Video queues is initialized by uvc_queue_init(). The function performs * basic initialization of the uvc_video_queue struct and never fails. * - * Video buffer allocation and freeing are performed by uvc_alloc_buffers and - * uvc_free_buffers respectively. The former acquires the video queue lock, - * while the later must be called with the lock held (so that allocation can - * free previously allocated buffers). Trying to free buffers that are mapped - * to user space will return -EBUSY. - * - * Video buffers are managed using two queues. However, unlike most USB video - * drivers that use an in queue and an out queue, we use a main queue to hold - * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to - * hold empty buffers. This design (copied from video-buf) minimizes locking - * in interrupt, as only one queue is shared between interrupt and user - * contexts. - * - * Use cases - * --------- - * - * Unless stated otherwise, all operations that modify the irq buffers queue - * are protected by the irq spinlock. - * - * 1. The user queues the buffers, starts streaming and dequeues a buffer. - * - * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the later is protected by the irq - * spinlock as well. - * - * The completion handler fetches a buffer from the irq queue and fills it - * with video data. If no buffer is available (irq queue empty), the handler - * returns immediately. - * - * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue. - * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked ready, the - * dequeing will succeed immediately. - * - * 2. Buffers are queued, user is waiting on a buffer and the device gets - * disconnected. - * - * When the device is disconnected, the kernel calls the completion handler - * with an appropriate status code. The handler marks all buffers in the - * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so - * that any process waiting on a buffer gets woken up. - * - * Waking up up the first buffer on the irq list is not enough, as the - * process waiting on the buffer might restart the dequeue operation - * immediately. - * + * Video buffers are managed by videobuf2. The driver uses a mutex to protect + * the videobuf2 queue operations by serializing calls to videobuf2 and a + * spinlock to protect the IRQ queue that holds the buffers to be processed by + * the driver. */ -static void -uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - mutex_init(&queue->mutex); - spin_lock_init(&queue->irqlock); - INIT_LIST_HEAD(&queue->mainqueue); - INIT_LIST_HEAD(&queue->irqqueue); - queue->type = type; -} - -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations */ -static int uvc_free_buffers(struct uvc_video_queue *queue) + +static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - unsigned int i; + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); + struct uvc_video *video = container_of(queue, struct uvc_video, queue); - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } + if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) + *nbuffers = UVC_MAX_VIDEO_BUFFERS; - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } + *nplanes = 1; + + sizes[0] = video->imagesize; return 0; } -/* - * Allocate the video buffers. - * - * Pages are reserved to make sure they will not be swapped, as they will be - * filled in the URB completion handler. - * - * Buffers will be individually mapped, so they must all be page aligned. - */ -static int -uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) +static int uvc_buffer_prepare(struct vb2_buffer *vb) { - unsigned int bufsize = PAGE_ALIGN(buflength); - unsigned int i; - void *mem = NULL; - int ret; + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - if (nbuffers > UVC_MAX_VIDEO_BUFFERS) - nbuffers = UVC_MAX_VIDEO_BUFFERS; + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { + uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); + return -EINVAL; + } - mutex_lock(&queue->mutex); + if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED)) + return -ENODEV; - if ((ret = uvc_free_buffers(queue)) < 0) - goto done; + buf->state = UVC_BUF_STATE_QUEUED; + buf->mem = vb2_plane_vaddr(vb, 0); + buf->length = vb2_plane_size(vb, 0); + if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf->bytesused = 0; + else + buf->bytesused = vb2_get_plane_payload(vb, 0); - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - goto done; + return 0; +} - /* Decrement the number of buffers until allocation succeeds. */ - for (; nbuffers > 0; --nbuffers) { - mem = vmalloc_32(nbuffers * bufsize); - if (mem != NULL) - break; - } +static void uvc_buffer_queue(struct vb2_buffer *vb) +{ + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); + struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); + unsigned long flags; - if (mem == NULL) { - ret = -ENOMEM; - goto done; - } + spin_lock_irqsave(&queue->irqlock, flags); - for (i = 0; i < nbuffers; ++i) { - memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); - queue->buffer[i].buf.index = i; - queue->buffer[i].buf.m.offset = i * bufsize; - queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = queue->type; - queue->buffer[i].buf.sequence = 0; - queue->buffer[i].buf.field = V4L2_FIELD_NONE; - queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; - queue->buffer[i].buf.flags = 0; - init_waitqueue_head(&queue->buffer[i].wait); + if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) { + list_add_tail(&buf->queue, &queue->irqqueue); + } else { + /* If the device is disconnected return the buffer to userspace + * directly. The next QBUF call will fail with -ENODEV. + */ + buf->state = UVC_BUF_STATE_ERROR; + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); } - queue->mem = mem; - queue->count = nbuffers; - queue->buf_size = bufsize; - ret = nbuffers; - -done: - mutex_unlock(&queue->mutex); - return ret; + spin_unlock_irqrestore(&queue->irqlock, flags); } -static void __uvc_query_buffer(struct uvc_buffer *buf, - struct v4l2_buffer *v4l2_buf) -{ - memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); - - if (buf->vma_use_count) - v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - case UVC_BUF_STATE_DONE: - v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; - break; - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case UVC_BUF_STATE_IDLE: - default: - break; - } -} +static struct vb2_ops uvc_queue_qops = { + .queue_setup = uvc_queue_setup, + .buf_prepare = uvc_buffer_prepare, + .buf_queue = uvc_buffer_queue, +}; -static int -uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) +static int uvc_queue_init(struct uvc_video_queue *queue, + enum v4l2_buf_type type) { - int ret = 0; + int ret; - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - ret = -EINVAL; - goto done; - } + queue->queue.type = type; + queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; + queue->queue.drv_priv = queue; + queue->queue.buf_struct_size = sizeof(struct uvc_buffer); + queue->queue.ops = &uvc_queue_qops; + queue->queue.mem_ops = &vb2_vmalloc_memops; + ret = vb2_queue_init(&queue->queue); + if (ret) + return ret; + + mutex_init(&queue->mutex); + spin_lock_init(&queue->irqlock); + INIT_LIST_HEAD(&queue->irqqueue); + queue->flags = 0; - __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); + return 0; +} -done: +/* + * Free the video buffers. + */ +static void uvc_free_buffers(struct uvc_video_queue *queue) +{ + mutex_lock(&queue->mutex); + vb2_queue_release(&queue->queue); mutex_unlock(&queue->mutex); - return ret; } /* - * Queue a video buffer. Attempting to queue a buffer that has already been - * queued will return -EINVAL. + * Allocate the video buffers. */ -static int -uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) +static int uvc_alloc_buffers(struct uvc_video_queue *queue, + struct v4l2_requestbuffers *rb) { - struct uvc_buffer *buf; - unsigned long flags; - int ret = 0; + int ret; - uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); + mutex_lock(&queue->mutex); + ret = vb2_reqbufs(&queue->queue, rb); + mutex_unlock(&queue->mutex); - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + return ret ? ret : rb->count; +} - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); - ret = -EINVAL; - goto done; - } +static int uvc_query_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *buf) +{ + int ret; - buf = &queue->buffer[v4l2_buf->index]; - if (buf->state != UVC_BUF_STATE_IDLE) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state " - "(%u).\n", buf->state); - ret = -EINVAL; - goto done; - } + mutex_lock(&queue->mutex); + ret = vb2_querybuf(&queue->queue, buf); + mutex_unlock(&queue->mutex); - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - v4l2_buf->bytesused > buf->buf.length) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); - ret = -EINVAL; - goto done; - } + return ret; +} - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - buf->buf.bytesused = 0; - else - buf->buf.bytesused = v4l2_buf->bytesused; +static int uvc_queue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *buf) +{ + unsigned long flags; + int ret; + mutex_lock(&queue->mutex); + ret = vb2_qbuf(&queue->queue, buf); spin_lock_irqsave(&queue->irqlock, flags); - if (queue->flags & UVC_QUEUE_DISCONNECTED) { - spin_unlock_irqrestore(&queue->irqlock, flags); - ret = -ENODEV; - goto done; - } - buf->state = UVC_BUF_STATE_QUEUED; - ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; queue->flags &= ~UVC_QUEUE_PAUSED; - - list_add_tail(&buf->stream, &queue->mainqueue); - list_add_tail(&buf->queue, &queue->irqqueue); spin_unlock_irqrestore(&queue->irqlock, flags); - -done: mutex_unlock(&queue->mutex); - return ret; -} -static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE); + return ret; } /* * Dequeue a video buffer. If nonblocking is false, block until a buffer is * available. */ -static int -uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf, - int nonblocking) +static int uvc_dequeue_buffer(struct uvc_video_queue *queue, + struct v4l2_buffer *buf, int nonblocking) { - struct uvc_buffer *buf; - int ret = 0; - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } + int ret; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n"); - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0) - goto done; - - uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n", - buf->buf.index, buf->state, buf->buf.bytesused); - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data " - "(transmission error).\n"); - ret = -EIO; - case UVC_BUF_STATE_DONE: - buf->state = UVC_BUF_STATE_IDLE; - break; - - case UVC_BUF_STATE_IDLE: - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - default: - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " - "(driver bug?).\n", buf->state); - ret = -EINVAL; - goto done; - } - - list_del(&buf->stream); - __uvc_query_buffer(buf, v4l2_buf); - -done: + ret = vb2_dqbuf(&queue->queue, buf, nonblocking); mutex_unlock(&queue->mutex); + return ret; } @@ -361,105 +208,47 @@ done: * This function implements video queue polling and is intended to be used by * the device poll handler. */ -static unsigned int -uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) +static unsigned int uvc_queue_poll(struct uvc_video_queue *queue, + struct file *file, poll_table *wait) { - struct uvc_buffer *buf; - unsigned int mask = 0; + unsigned int ret; mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) - goto done; - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) - mask |= POLLOUT | POLLWRNORM; - -done: + ret = vb2_poll(&queue->queue, file, wait); mutex_unlock(&queue->mutex); - return mask; -} -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; + return ret; } -static void uvc_vm_close(struct vm_area_struct *vma) +static int uvc_queue_mmap(struct uvc_video_queue *queue, + struct vm_area_struct *vma) { - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; -} + int ret; -static struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; + mutex_lock(&queue->mutex); + ret = vb2_mmap(&queue->queue, vma); + mutex_unlock(&queue->mutex); + + return ret; +} +#ifndef CONFIG_MMU /* - * Memory-map a buffer. + * Get unmapped area. * - * This function implements video buffer memory mapping and is intended to be - * used by the device mmap handler. + * NO-MMU arch need this function to make mmap() work correctly. */ -static int -uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) +static unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, + unsigned long pgoff) { - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; + unsigned long ret; mutex_lock(&queue->mutex); - - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || size != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); - -done: + ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); mutex_unlock(&queue->mutex); return ret; } +#endif /* * Cancel the video buffers queue. @@ -484,7 +273,7 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) queue); list_del(&buf->queue); buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); } /* This must be protected by the irqlock spinlock to avoid race * conditions between uvc_queue_buffer and the disconnection event that @@ -516,26 +305,33 @@ static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) */ static int uvc_queue_enable(struct uvc_video_queue *queue, int enable) { - unsigned int i; + unsigned long flags; int ret = 0; mutex_lock(&queue->mutex); if (enable) { - if (uvc_queue_streaming(queue)) { - ret = -EBUSY; + ret = vb2_streamon(&queue->queue, queue->queue.type); + if (ret < 0) goto done; - } + queue->sequence = 0; - queue->flags |= UVC_QUEUE_STREAMING; queue->buf_used = 0; } else { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); + ret = vb2_streamoff(&queue->queue, queue->queue.type); + if (ret < 0) + goto done; - for (i = 0; i < queue->count; ++i) - queue->buffer[i].state = UVC_BUF_STATE_IDLE; + spin_lock_irqsave(&queue->irqlock, flags); + INIT_LIST_HEAD(&queue->irqqueue); - queue->flags &= ~UVC_QUEUE_STREAMING; + /* + * FIXME: We need to clear the DISCONNECTED flag to ensure that + * applications will be able to queue buffers for the next + * streaming run. However, clearing it here doesn't guarantee + * that the device will be reconnected in the meantime. + */ + queue->flags &= ~UVC_QUEUE_DISCONNECTED; + spin_unlock_irqrestore(&queue->irqlock, flags); } done: @@ -544,15 +340,15 @@ done: } /* called with &queue_irqlock held.. */ -static struct uvc_buffer * -uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) +static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, + struct uvc_buffer *buf) { struct uvc_buffer *nextbuf; if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) && - buf->buf.length != buf->buf.bytesused) { + buf->length != buf->bytesused) { buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; + vb2_set_plane_payload(&buf->buf, 0, 0); return buf; } @@ -563,10 +359,18 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) else nextbuf = NULL; - buf->buf.sequence = queue->sequence++; - do_gettimeofday(&buf->buf.timestamp); + /* + * FIXME: with videobuf2, the sequence number or timestamp fields + * are valid only for video capture devices and the UVC gadget usually + * is a video output device. Keeping these until the specs are clear on + * this aspect. + */ + buf->buf.v4l2_buf.sequence = queue->sequence++; + do_gettimeofday(&buf->buf.v4l2_buf.timestamp); + + vb2_set_plane_payload(&buf->buf, 0, buf->bytesused); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); - wake_up(&buf->wait); return nextbuf; } diff --git a/drivers/usb/gadget/uvc_queue.h b/drivers/usb/gadget/uvc_queue.h index 1812a8ecc5d0..8e76ce982f1e 100644 --- a/drivers/usb/gadget/uvc_queue.h +++ b/drivers/usb/gadget/uvc_queue.h @@ -6,6 +6,7 @@ #include <linux/kernel.h> #include <linux/poll.h> #include <linux/videodev2.h> +#include <media/videobuf2-core.h> /* Maximum frame size in bytes, for sanity checking. */ #define UVC_MAX_FRAME_SIZE (16*1024*1024) @@ -25,42 +26,35 @@ enum uvc_buffer_state { }; struct uvc_buffer { - unsigned long vma_use_count; - struct list_head stream; - - /* Touched by interrupt handler. */ - struct v4l2_buffer buf; + struct vb2_buffer buf; struct list_head queue; - wait_queue_head_t wait; + enum uvc_buffer_state state; + void *mem; + unsigned int length; + unsigned int bytesused; }; -#define UVC_QUEUE_STREAMING (1 << 0) -#define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) -#define UVC_QUEUE_PAUSED (1 << 3) +#define UVC_QUEUE_DISCONNECTED (1 << 0) +#define UVC_QUEUE_DROP_INCOMPLETE (1 << 1) +#define UVC_QUEUE_PAUSED (1 << 2) struct uvc_video_queue { - enum v4l2_buf_type type; + struct vb2_queue queue; + struct mutex mutex; /* Protects queue */ - void *mem; unsigned int flags; __u32 sequence; - unsigned int count; - unsigned int buf_size; unsigned int buf_used; - struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; - struct mutex mutex; /* protects buffers and mainqueue */ - spinlock_t irqlock; /* protects irqqueue */ - struct list_head mainqueue; + spinlock_t irqlock; /* Protects flags and irqqueue */ struct list_head irqqueue; }; static inline int uvc_queue_streaming(struct uvc_video_queue *queue) { - return queue->flags & UVC_QUEUE_STREAMING; + return vb2_is_streaming(&queue->queue); } #endif /* __KERNEL__ */ diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c index 2ca9386d655b..ad48e81155e2 100644 --- a/drivers/usb/gadget/uvc_v4l2.c +++ b/drivers/usb/gadget/uvc_v4l2.c @@ -41,9 +41,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) req->length = min_t(unsigned int, uvc->event_length, data->length); req->zero = data->length < uvc->event_length; - req->dma = DMA_ADDR_INVALID; - memcpy(req->buf, data->data, data->length); + memcpy(req->buf, data->data, req->length); return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL); } @@ -148,16 +147,13 @@ uvc_v4l2_release(struct file *file) uvc_function_disconnect(uvc); uvc_video_enable(video, 0); - mutex_lock(&video->queue.mutex); - if (uvc_free_buffers(&video->queue) < 0) - printk(KERN_ERR "uvc_v4l2_release: Unable to free " - "buffers.\n"); - mutex_unlock(&video->queue.mutex); + uvc_free_buffers(&video->queue); file->private_data = NULL; v4l2_fh_del(&handle->vfh); v4l2_fh_exit(&handle->vfh); kfree(handle); + return 0; } @@ -178,9 +174,9 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_capability *cap = arg; memset(cap, 0, sizeof *cap); - strncpy(cap->driver, "g_uvc", sizeof(cap->driver)); - strncpy(cap->card, cdev->gadget->name, sizeof(cap->card)); - strncpy(cap->bus_info, dev_name(&cdev->gadget->dev), + strlcpy(cap->driver, "g_uvc", sizeof(cap->driver)); + strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; @@ -192,7 +188,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_format *fmt = arg; - if (fmt->type != video->queue.type) + if (fmt->type != video->queue.queue.type) return -EINVAL; return uvc_v4l2_get_format(video, fmt); @@ -202,7 +198,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_format *fmt = arg; - if (fmt->type != video->queue.type) + if (fmt->type != video->queue.queue.type) return -EINVAL; return uvc_v4l2_set_format(video, fmt); @@ -213,16 +209,13 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_requestbuffers *rb = arg; - if (rb->type != video->queue.type || - rb->memory != V4L2_MEMORY_MMAP) + if (rb->type != video->queue.queue.type) return -EINVAL; - ret = uvc_alloc_buffers(&video->queue, rb->count, - video->imagesize); + ret = uvc_alloc_buffers(&video->queue, rb); if (ret < 0) return ret; - rb->count = ret; ret = 0; break; } @@ -231,9 +224,6 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_buffer *buf = arg; - if (buf->type != video->queue.type) - return -EINVAL; - return uvc_query_buffer(&video->queue, buf); } @@ -251,24 +241,36 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { int *type = arg; - if (*type != video->queue.type) + if (*type != video->queue.queue.type) return -EINVAL; - return uvc_video_enable(video, 1); + /* Enable UVC video. */ + ret = uvc_video_enable(video, 1); + if (ret < 0) + return ret; + + /* + * Complete the alternate setting selection setup phase now that + * userspace is ready to provide video frames. + */ + uvc_function_setup_continue(uvc); + uvc->state = UVC_STATE_STREAMING; + + return 0; } case VIDIOC_STREAMOFF: { int *type = arg; - if (*type != video->queue.type) + if (*type != video->queue.queue.type) return -EINVAL; return uvc_video_enable(video, 0); } /* Events */ - case VIDIOC_DQEVENT: + case VIDIOC_DQEVENT: { struct v4l2_event *event = arg; @@ -333,17 +335,21 @@ uvc_v4l2_poll(struct file *file, poll_table *wait) { struct video_device *vdev = video_devdata(file); struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); - unsigned int mask = 0; - poll_wait(file, &handle->vfh.wait, wait); - if (v4l2_event_pending(&handle->vfh)) - mask |= POLLPRI; + return uvc_queue_poll(&uvc->video.queue, file, wait); +} - mask |= uvc_queue_poll(&uvc->video.queue, file, wait); +#ifndef CONFIG_MMU +static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, + unsigned long addr, unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); - return mask; + return uvc_queue_get_unmapped_area(&uvc->video.queue, pgoff); } +#endif static struct v4l2_file_operations uvc_v4l2_fops = { .owner = THIS_MODULE, @@ -352,5 +358,8 @@ static struct v4l2_file_operations uvc_v4l2_fops = { .ioctl = uvc_v4l2_ioctl, .mmap = uvc_v4l2_mmap, .poll = uvc_v4l2_poll, +#ifndef CONFIG_MMU + .get_unmapped_area = uvc_v4l2_get_unmapped_area, +#endif }; diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c index b0e53a8ea4f7..71e896d4c5ae 100644 --- a/drivers/usb/gadget/uvc_video.c +++ b/drivers/usb/gadget/uvc_video.c @@ -32,7 +32,7 @@ uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf, data[0] = 2; data[1] = UVC_STREAM_EOH | video->fid; - if (buf->buf.bytesused - video->queue.buf_used <= len - 2) + if (buf->bytesused - video->queue.buf_used <= len - 2) data[1] |= UVC_STREAM_EOF; return 2; @@ -47,8 +47,8 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf, void *mem; /* Copy video data to the USB buffer. */ - mem = queue->mem + buf->buf.m.offset + queue->buf_used; - nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); + mem = buf->mem + queue->buf_used; + nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used); memcpy(data, mem, nbytes); queue->buf_used += nbytes; @@ -82,7 +82,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, req->length = video->req_size - len; req->zero = video->payload_size == video->max_payload_size; - if (buf->buf.bytesused == video->queue.buf_used) { + if (buf->bytesused == video->queue.buf_used) { video->queue.buf_used = 0; buf->state = UVC_BUF_STATE_DONE; uvc_queue_next_buffer(&video->queue, buf); @@ -92,7 +92,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, } if (video->payload_size == video->max_payload_size || - buf->buf.bytesused == video->queue.buf_used) + buf->bytesused == video->queue.buf_used) video->payload_size = 0; } @@ -115,7 +115,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, req->length = video->req_size - len; - if (buf->buf.bytesused == video->queue.buf_used) { + if (buf->bytesused == video->queue.buf_used) { video->queue.buf_used = 0; buf->state = UVC_BUF_STATE_DONE; uvc_queue_next_buffer(&video->queue, buf); @@ -161,6 +161,7 @@ static void uvc_video_complete(struct usb_ep *ep, struct usb_request *req) { struct uvc_video *video = req->context; + struct uvc_video_queue *queue = &video->queue; struct uvc_buffer *buf; unsigned long flags; int ret; @@ -169,13 +170,15 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) case 0: break; - case -ESHUTDOWN: + case -ESHUTDOWN: /* disconnect from host. */ printk(KERN_INFO "VS request cancelled.\n"); + uvc_queue_cancel(queue, 1); goto requeue; default: printk(KERN_INFO "VS request completed with status %d.\n", req->status); + uvc_queue_cancel(queue, 0); goto requeue; } @@ -229,13 +232,18 @@ uvc_video_free_requests(struct uvc_video *video) static int uvc_video_alloc_requests(struct uvc_video *video) { + unsigned int req_size; unsigned int i; int ret = -ENOMEM; BUG_ON(video->req_size); + req_size = video->ep->maxpacket + * max_t(unsigned int, video->ep->maxburst, 1) + * (video->ep->mult + 1); + for (i = 0; i < UVC_NUM_REQUESTS; ++i) { - video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL); + video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL); if (video->req_buffer[i] == NULL) goto error; @@ -245,14 +253,14 @@ uvc_video_alloc_requests(struct uvc_video *video) video->req[i]->buf = video->req_buffer[i]; video->req[i]->length = 0; - video->req[i]->dma = DMA_ADDR_INVALID; video->req[i]->complete = uvc_video_complete; video->req[i]->context = video; list_add_tail(&video->req[i]->list, &video->req_free); } - video->req_size = video->ep->maxpacket; + video->req_size = req_size; + return 0; error: @@ -309,7 +317,8 @@ uvc_video_pump(struct uvc_video *video) video->encode(req, video, buf); /* Queue the USB request */ - if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) { + ret = usb_ep_queue(video->ep, req, GFP_ATOMIC); + if (ret < 0) { printk(KERN_INFO "Failed to queue request (%d)\n", ret); usb_ep_set_halt(video->ep); spin_unlock_irqrestore(&video->queue.irqlock, flags); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 685fa681cb65..2cd6262e8b71 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -368,8 +368,10 @@ static int zero_unbind(struct usb_composite_dev *cdev) del_timer_sync(&autoresume_timer); if (!IS_ERR_OR_NULL(func_ss)) usb_put_function(func_ss); + usb_put_function_instance(func_inst_ss); if (!IS_ERR_OR_NULL(func_lb)) usb_put_function(func_lb); + usb_put_function_instance(func_inst_lb); return 0; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index c59a1126926f..de94f2699063 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -2,11 +2,9 @@ # USB Host Controller Drivers # comment "USB Host Controller Drivers" - depends on USB config USB_C67X00_HCD tristate "Cypress C67x00 HCD support" - depends on USB help The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role host/peripheral/OTG USB controllers. @@ -19,7 +17,7 @@ config USB_C67X00_HCD config USB_XHCI_HCD tristate "xHCI HCD (USB 3.0) support" - depends on USB && USB_ARCH_HAS_XHCI + depends on USB_ARCH_HAS_XHCI ---help--- The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 "SuperSpeed" host controller hardware. @@ -27,13 +25,13 @@ config USB_XHCI_HCD To compile this driver as a module, choose M here: the module will be called xhci-hcd. +if USB_XHCI_HCD + config USB_XHCI_PLATFORM tristate - depends on USB_XHCI_HCD config USB_XHCI_HCD_DEBUGGING bool "Debugging for the xHCI host controller" - depends on USB_XHCI_HCD ---help--- Say 'Y' to turn on debugging for the xHCI host controller driver. This will spew debugging output, even in interrupt context. @@ -41,9 +39,11 @@ config USB_XHCI_HCD_DEBUGGING If unsure, say N. +endif # USB_XHCI_HCD + config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" - depends on USB && USB_ARCH_HAS_EHCI + depends on USB_ARCH_HAS_EHCI ---help--- The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. @@ -95,14 +95,19 @@ config USB_EHCI_TT_NEWSCHED If unsure, say Y. +config USB_FSL_MPH_DR_OF + tristate + +if USB_EHCI_HCD + config USB_EHCI_PCI tristate - depends on USB_EHCI_HCD && PCI + depends on PCI default y config USB_EHCI_HCD_PMC_MSP tristate "EHCI support for on-chip PMC MSP71xx USB controller" - depends on USB_EHCI_HCD && MSP_HAS_USB + depends on MSP_HAS_USB default n select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO @@ -112,22 +117,13 @@ config USB_EHCI_HCD_PMC_MSP config USB_EHCI_BIG_ENDIAN_MMIO bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \ - ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || CPU_CAVIUM_OCTEON || \ - PMC_MSP || SPARC_LEON || MIPS_SEAD3) - default y config USB_EHCI_BIG_ENDIAN_DESC bool - depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || PMC_MSP || SPARC_LEON || \ - MIPS_SEAD3) - default y config XPS_USB_HCD_XILINX bool "Use Xilinx usb host EHCI controller core" - depends on USB_EHCI_HCD && (PPC32 || MICROBLAZE) + depends on (PPC32 || MICROBLAZE) select USB_EHCI_BIG_ENDIAN_DESC select USB_EHCI_BIG_ENDIAN_MMIO ---help--- @@ -136,12 +132,9 @@ config XPS_USB_HCD_XILINX support both high speed and full speed devices, or high speed devices only. -config USB_FSL_MPH_DR_OF - tristate - config USB_EHCI_FSL bool "Support for Freescale PPC on-chip EHCI USB controller" - depends on USB_EHCI_HCD && FSL_SOC + depends on FSL_SOC select USB_EHCI_ROOT_HUB_TT select USB_FSL_MPH_DR_OF if OF ---help--- @@ -149,22 +142,53 @@ config USB_EHCI_FSL config USB_EHCI_MXC tristate "Support for Freescale i.MX on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_MXC + depends on ARCH_MXC select USB_EHCI_ROOT_HUB_TT ---help--- Variation of ARC USB block used in some Freescale chips. config USB_EHCI_HCD_OMAP - bool "EHCI support for OMAP3 and later chips" - depends on USB_EHCI_HCD && ARCH_OMAP + tristate "EHCI support for OMAP3 and later chips" + depends on ARCH_OMAP default y ---help--- Enables support for the on-chip EHCI controller on OMAP3 and later chips. + If your system uses a PHY on the USB port, you will need to + enable USB_PHY and the appropriate PHY driver as well. Most + boards need the NOP_USB_XCEIV PHY driver. + +config USB_EHCI_HCD_ORION + tristate "Support for Marvell EBU on-chip EHCI USB controller" + depends on USB_EHCI_HCD && PLAT_ORION + default y + ---help--- + Enables support for the on-chip EHCI controller on Marvell's + embedded ARM SoCs, including Orion, Kirkwood, Dove, Armada XP, + Armada 370. This is different from the EHCI implementation + on Marvell's mobile PXA and MMP SoC, see "EHCI support for + Marvell PXA/MMP USB controller" for those. + +config USB_EHCI_HCD_SPEAR + tristate "Support for ST SPEAr on-chip EHCI USB controller" + depends on USB_EHCI_HCD && PLAT_SPEAR + default y + ---help--- + Enables support for the on-chip EHCI controller on + ST SPEAr chips. + +config USB_EHCI_HCD_AT91 + tristate "Support for Atmel on-chip EHCI USB controller" + depends on USB_EHCI_HCD && ARCH_AT91 + default y + ---help--- + Enables support for the on-chip EHCI controller on + Atmel chips. config USB_EHCI_MSM - bool "Support for MSM on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_MSM + tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" + depends on ARCH_MSM + depends on USB_PHY select USB_EHCI_ROOT_HUB_TT select USB_MSM_OTG ---help--- @@ -177,15 +201,16 @@ config USB_EHCI_MSM config USB_EHCI_TEGRA boolean "NVIDIA Tegra HCD support" - depends on USB_EHCI_HCD && ARCH_TEGRA + depends on ARCH_TEGRA select USB_EHCI_ROOT_HUB_TT + select USB_PHY help This driver enables support for the internal USB Host Controllers found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. config USB_EHCI_HCD_PPC_OF bool "EHCI support for PPC USB controller on OF platform bus" - depends on USB_EHCI_HCD && PPC_OF + depends on PPC_OF default y ---help--- Enables support for the USB controller present on the PowerPC @@ -193,35 +218,40 @@ config USB_EHCI_HCD_PPC_OF config USB_EHCI_SH bool "EHCI support for SuperH USB controller" - depends on USB_EHCI_HCD && SUPERH + depends on SUPERH ---help--- Enables support for the on-chip EHCI controller on the SuperH. If you use the PCI EHCI controller, this option is not necessary. config USB_EHCI_S5P - boolean "S5P EHCI support" - depends on USB_EHCI_HCD && PLAT_S5P + tristate "EHCI support for Samsung S5P/EXYNOS SoC Series" + depends on PLAT_S5P help - Enable support for the S5P SOC's on-chip EHCI controller. + Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's + on-chip EHCI controller. config USB_EHCI_MV - bool "EHCI support for Marvell on-chip controller" - depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP) + bool "EHCI support for Marvell PXA/MMP USB controller" + depends on (ARCH_PXA || ARCH_MMP) select USB_EHCI_ROOT_HUB_TT ---help--- Enables support for Marvell (including PXA and MMP series) on-chip USB SPH and OTG controller. SPH is a single port host, and it can only be EHCI host. OTG is controller that can switch to host mode. + Note that this driver will not work on Marvell's other EHCI + controller used by the EBU-type SoCs including Orion, Kirkwood, + Dova, Armada 370 and Armada XP. See "Support for Marvell EBU + on-chip EHCI USB controller" for those. config USB_W90X900_EHCI bool "W90X900(W90P910) EHCI support" - depends on USB_EHCI_HCD && ARCH_W90X900 + depends on ARCH_W90X900 ---help--- Enables support for the W90X900 USB controller config USB_CNS3XXX_EHCI bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" - depends on USB_EHCI_HCD && ARCH_CNS3XXX + depends on ARCH_CNS3XXX select USB_EHCI_HCD_PLATFORM ---help--- This option is deprecated now and the driver was removed, use @@ -233,7 +263,7 @@ config USB_CNS3XXX_EHCI config USB_EHCI_ATH79 bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)" - depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) + depends on (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) select USB_EHCI_ROOT_HUB_TT select USB_EHCI_HCD_PLATFORM default y @@ -244,9 +274,31 @@ config USB_EHCI_ATH79 Enables support for the built-in EHCI controller present on the Atheros AR7XXX/AR9XXX SoCs. +config USB_EHCI_HCD_PLATFORM + tristate "Generic EHCI driver for a platform device" + default n + ---help--- + Adds an EHCI host driver for a generic platform device, which + provides a memory space and an irq. + + If unsure, say N. + +config USB_OCTEON_EHCI + bool "Octeon on-chip EHCI support" + depends on CPU_CAVIUM_OCTEON + default n + select USB_EHCI_BIG_ENDIAN_MMIO + help + Enable support for the Octeon II SOC's on-chip EHCI + controller. It is needed for high-speed (480Mbit/sec) + USB 2.0 device support. All CN6XXX based chips with USB are + supported. + +endif # USB_EHCI_HCD + config USB_OXU210HP_HCD tristate "OXU210HP HCD support" - depends on USB && GENERIC_HARDIRQS + depends on GENERIC_HARDIRQS ---help--- The OXU210HP is an USB host/OTG/device controller. Enable this option if your board has this chip. If unsure, say N. @@ -259,7 +311,6 @@ config USB_OXU210HP_HCD config USB_ISP116X_HCD tristate "ISP116X HCD support" - depends on USB ---help--- The ISP1160 and ISP1161 chips are USB host controllers. Enable this option if your board has this chip. If unsure, say N. @@ -271,7 +322,6 @@ config USB_ISP116X_HCD config USB_ISP1760_HCD tristate "ISP 1760 HCD support" - depends on USB ---help--- The ISP1760 chip is a USB 2.0 host controller. @@ -286,7 +336,6 @@ config USB_ISP1760_HCD config USB_ISP1362_HCD tristate "ISP1362 HCD support" - depends on USB default N ---help--- Supports the Philips ISP1362 chip as a host controller @@ -298,9 +347,8 @@ config USB_ISP1362_HCD config USB_OHCI_HCD tristate "OHCI HCD support" - depends on USB && USB_ARCH_HAS_OHCI + depends on USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 - select USB_OTG_UTILS if ARCH_OMAP depends on USB_ISP1301 || !ARCH_LPC32XX ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing @@ -315,16 +363,18 @@ config USB_OHCI_HCD To compile this driver as a module, choose M here: the module will be called ohci-hcd. +if USB_OHCI_HCD + config USB_OHCI_HCD_OMAP1 bool "OHCI support for OMAP1/2 chips" - depends on USB_OHCI_HCD && ARCH_OMAP1 + depends on ARCH_OMAP1 default y ---help--- Enables support for the OHCI controller on OMAP1/2 chips. config USB_OHCI_HCD_OMAP3 bool "OHCI support for OMAP3 and later chips" - depends on USB_OHCI_HCD && (ARCH_OMAP3 || ARCH_OMAP4) + depends on (ARCH_OMAP3 || ARCH_OMAP4) default y ---help--- Enables support for the on-chip OHCI controller on @@ -332,7 +382,7 @@ config USB_OHCI_HCD_OMAP3 config USB_OHCI_ATH79 bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" - depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X) + depends on (SOC_AR71XX || SOC_AR724X) select USB_OHCI_HCD_PLATFORM default y help @@ -344,7 +394,7 @@ config USB_OHCI_ATH79 config USB_OHCI_HCD_PPC_OF_BE bool "OHCI support for OF platform bus (big endian)" - depends on USB_OHCI_HCD && PPC_OF + depends on PPC_OF select USB_OHCI_BIG_ENDIAN_DESC select USB_OHCI_BIG_ENDIAN_MMIO ---help--- @@ -353,7 +403,7 @@ config USB_OHCI_HCD_PPC_OF_BE config USB_OHCI_HCD_PPC_OF_LE bool "OHCI support for OF platform bus (little endian)" - depends on USB_OHCI_HCD && PPC_OF + depends on PPC_OF select USB_OHCI_LITTLE_ENDIAN ---help--- Enables support for little-endian USB controllers present on the @@ -361,12 +411,12 @@ config USB_OHCI_HCD_PPC_OF_LE config USB_OHCI_HCD_PPC_OF bool - depends on USB_OHCI_HCD && PPC_OF + depends on PPC_OF default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE config USB_OHCI_HCD_PCI bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) + depends on PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) default y select USB_OHCI_LITTLE_ENDIAN ---help--- @@ -375,7 +425,7 @@ config USB_OHCI_HCD_PCI config USB_OHCI_HCD_SSB bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)" - depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) + depends on (SSB = y || SSB = USB_OHCI_HCD) select USB_HCD_SSB select USB_OHCI_HCD_PLATFORM default n @@ -393,7 +443,7 @@ config USB_OHCI_HCD_SSB config USB_OHCI_SH bool "OHCI support for SuperH USB controller (DEPRECATED)" - depends on USB_OHCI_HCD && SUPERH + depends on SUPERH select USB_OHCI_HCD_PLATFORM ---help--- This option is deprecated now and the driver was removed, use @@ -404,13 +454,13 @@ config USB_OHCI_SH config USB_OHCI_EXYNOS boolean "OHCI support for Samsung EXYNOS SoC Series" - depends on USB_OHCI_HCD && ARCH_EXYNOS + depends on ARCH_EXYNOS help Enable support for the Samsung Exynos SOC's on-chip OHCI controller. config USB_CNS3XXX_OHCI bool "Cavium CNS3XXX OHCI Module (DEPRECATED)" - depends on USB_OHCI_HCD && ARCH_CNS3XXX + depends on ARCH_CNS3XXX select USB_OHCI_HCD_PLATFORM ---help--- This option is deprecated now and the driver was removed, use @@ -421,7 +471,6 @@ config USB_CNS3XXX_OHCI config USB_OHCI_HCD_PLATFORM bool "Generic OHCI driver for a platform device" - depends on USB_OHCI_HCD default n ---help--- Adds an OHCI host driver for a generic platform device, which @@ -429,35 +478,36 @@ config USB_OHCI_HCD_PLATFORM If unsure, say N. -config USB_EHCI_HCD_PLATFORM - tristate "Generic EHCI driver for a platform device" - depends on USB_EHCI_HCD - default n - ---help--- - Adds an EHCI host driver for a generic platform device, which - provides a memory space and an irq. +config USB_OCTEON_OHCI + bool "Octeon on-chip OHCI support" + depends on CPU_CAVIUM_OCTEON + default USB_OCTEON_EHCI + select USB_OHCI_BIG_ENDIAN_MMIO + select USB_OHCI_LITTLE_ENDIAN + help + Enable support for the Octeon II SOC's on-chip OHCI + controller. It is needed for low-speed USB 1.0 device + support. All CN6XXX based chips with USB are supported. - If unsure, say N. config USB_OHCI_BIG_ENDIAN_DESC bool - depends on USB_OHCI_HCD default n config USB_OHCI_BIG_ENDIAN_MMIO bool - depends on USB_OHCI_HCD default n config USB_OHCI_LITTLE_ENDIAN bool - depends on USB_OHCI_HCD default n if STB03xxx || PPC_MPC52xx default y +endif # USB_OHCI_HCD + config USB_UHCI_HCD tristate "UHCI HCD (most Intel and VIA) support" - depends on USB && (PCI || SPARC_LEON || ARCH_VT8500) + depends on PCI || SPARC_LEON || ARCH_VT8500 ---help--- The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB @@ -497,7 +547,7 @@ config USB_UHCI_BIG_ENDIAN_DESC config USB_FHCI_HCD tristate "Freescale QE USB Host Controller support" - depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE + depends on OF_GPIO && QE_GPIO && QUICC_ENGINE select FSL_GTM select QE_USB help @@ -514,7 +564,7 @@ config FHCI_DEBUG config USB_U132_HCD tristate "Elan U132 Adapter Host Controller" - depends on USB && USB_FTDI_ELAN + depends on USB_FTDI_ELAN default M help The U132 adapter is a USB to CardBus adapter specifically designed @@ -542,7 +592,6 @@ config USB_U132_HCD config USB_SL811_HCD tristate "SL811HS HCD support" - depends on USB help The SL811HS is a single-port USB controller that supports either host side or peripheral side roles. Enable this option if your @@ -574,7 +623,6 @@ config USB_SL811_CS config USB_R8A66597_HCD tristate "R8A66597 HCD support" - depends on USB help The R8A66597 is a USB 2.0 host and peripheral controller. @@ -586,7 +634,6 @@ config USB_R8A66597_HCD config USB_RENESAS_USBHS_HCD tristate "Renesas USBHS HCD support" - depends on USB depends on USB_RENESAS_USBHS help The Renesas USBHS is a USB 2.0 host and peripheral controller. @@ -611,7 +658,7 @@ config USB_WHCI_HCD config USB_HWA_HCD tristate "Host Wire Adapter (HWA) driver" - depends on USB && UWB + depends on UWB select USB_WUSB select UWB_HWA help @@ -625,7 +672,7 @@ config USB_HWA_HCD config USB_IMX21_HCD tristate "i.MX21 HCD support" - depends on USB && ARM && ARCH_MXC + depends on ARM && ARCH_MXC help This driver enables support for the on-chip USB host in the i.MX21 processor. @@ -633,27 +680,7 @@ config USB_IMX21_HCD To compile this driver as a module, choose M here: the module will be called "imx21-hcd". -config USB_OCTEON_EHCI - bool "Octeon on-chip EHCI support" - depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON - default n - select USB_EHCI_BIG_ENDIAN_MMIO - help - Enable support for the Octeon II SOC's on-chip EHCI - controller. It is needed for high-speed (480Mbit/sec) - USB 2.0 device support. All CN6XXX based chips with USB are - supported. -config USB_OCTEON_OHCI - bool "Octeon on-chip OHCI support" - depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON - default USB_OCTEON_EHCI - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_OHCI_LITTLE_ENDIAN - help - Enable support for the Octeon II SOC's on-chip OHCI - controller. It is needed for low-speed USB 1.0 device - support. All CN6XXX based chips with USB are supported. config USB_OCTEON2_COMMON bool diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 001fbff2fdef..4fb73c156d72 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -27,6 +27,12 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o +obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o +obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o +obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o +obj-$(CONFIG_USB_EHCI_S5P) += ehci-s5p.o +obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o +obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index f3beac4d06b8..66420097c242 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -12,9 +12,22 @@ */ #include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h" + +#define DRIVER_DESC "EHCI Atmel driver" + +static const char hcd_name[] = "ehci-atmel"; +static struct hc_driver __read_mostly ehci_atmel_hc_driver; /* interface and function clocks */ static struct clk *iclk, *fclk; @@ -50,51 +63,6 @@ static void atmel_stop_ehci(struct platform_device *pdev) /*-------------------------------------------------------------------------*/ -static int ehci_atmel_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - /* registers start at offset 0x0 */ - ehci->caps = hcd->regs; - - return ehci_setup(hcd); -} - -static const struct hc_driver ehci_atmel_hc_driver = { - .description = hcd_name, - .product_desc = "Atmel EHCI UHP HS", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* generic hardware linkage */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* basic lifecycle operations */ - .reset = ehci_atmel_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* scheduling support */ - .get_frame_number = ehci_get_frame, - - /* root hub support */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32); static int ehci_atmel_drv_probe(struct platform_device *pdev) @@ -102,6 +70,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) struct usb_hcd *hcd; const struct hc_driver *driver = &ehci_atmel_hc_driver; struct resource *res; + struct ehci_hcd *ehci; int irq; int retval; @@ -162,6 +131,10 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev) goto fail_request_resource; } + ehci = hcd_to_ehci(hcd); + /* registers start at offset 0x0 */ + ehci->caps = hcd->regs; + atmel_start_ehci(pdev); retval = usb_add_hcd(hcd, irq, IRQF_SHARED); @@ -185,7 +158,6 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - ehci_shutdown(hcd); usb_remove_hcd(hcd); usb_put_hcd(hcd); @@ -213,3 +185,25 @@ static struct platform_driver ehci_atmel_driver = { .of_match_table = of_match_ptr(atmel_ehci_dt_ids), }, }; + +static int __init ehci_atmel_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ehci_init_driver(&ehci_atmel_hc_driver, NULL); + return platform_driver_register(&ehci_atmel_driver); +} +module_init(ehci_atmel_init); + +static void __exit ehci_atmel_cleanup(void) +{ + platform_driver_unregister(&ehci_atmel_driver); +} +module_exit(ehci_atmel_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:atmel-ehci"); +MODULE_AUTHOR("Nicolas Ferre"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 70b496dc18a0..5429d2645bbc 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf) spin_lock_irqsave (&ehci->lock, flags); for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh) qh_lines (ehci, qh, &next, &size); - if (ehci->async_unlink && size > 0) { + if (!list_empty(&ehci->async_unlink) && size > 0) { temp = scnprintf(next, size, "\nunlink =\n"); size -= temp; next += temp; - for (qh = ehci->async_unlink; size > 0 && qh; - qh = qh->unlink_next) - qh_lines (ehci, qh, &next, &size); + list_for_each_entry(qh, &ehci->async_unlink, unlink_node) { + if (size <= 0) + break; + qh_lines(ehci, qh, &next, &size); + } } spin_unlock_irqrestore (&ehci->lock, flags); @@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) } } - if (ehci->async_unlink) { + if (!list_empty(&ehci->async_unlink)) { temp = scnprintf(next, size, "async unlink qh %p\n", - ehci->async_unlink); + list_first_entry(&ehci->async_unlink, + struct ehci_qh, unlink_node)); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index d81d2fcbff18..3be3df233a0e 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -370,6 +370,15 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) /* EHCI registers start at offset 0x100 */ ehci->caps = hcd->regs + 0x100; +#ifdef CONFIG_PPC_83xx + /* + * Deal with MPC834X that need port power to be cycled after the power + * fault condition is removed. Otherwise the state machine does not + * reflect PORTSC[CSC] correctly. + */ + ehci->need_oc_pp_cycle = 1; +#endif + hcd->has_tt = 1; retval = ehci_setup(hcd); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 416a6dce5e11..312fc10da3c7 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -482,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd) * periodic_size can shrink by USBCMD update if hcc_params allows. */ ehci->periodic_size = DEFAULT_I_TDPS; + INIT_LIST_HEAD(&ehci->async_unlink); + INIT_LIST_HEAD(&ehci->async_idle); + INIT_LIST_HEAD(&ehci->intr_unlink); INIT_LIST_HEAD(&ehci->intr_qh_list); INIT_LIST_HEAD(&ehci->cached_itd_list); INIT_LIST_HEAD(&ehci->cached_sitd_list); @@ -670,9 +673,6 @@ int ehci_setup(struct usb_hcd *hcd) if (retval) return retval; - if (ehci_is_TDI(ehci)) - tdi_reset(ehci); - ehci_reset(ehci); return 0; @@ -749,7 +749,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* guard against (alleged) silicon errata */ if (cmd & CMD_IAAD) ehci_dbg(ehci, "IAA with IAAD still set?\n"); - if (ehci->async_iaa) + if (ehci->iaa_in_progress) COUNT(ehci->stats.iaa); end_unlink_async(ehci); } @@ -757,7 +757,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); - u32 ppcd = 0; + u32 ppcd = ~0; /* kick root hub later */ pcd_status = status; @@ -774,7 +774,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) int pstatus; /* leverage per-port change bits feature */ - if (ehci->has_ppcd && !(ppcd & (1 << i))) + if (!(ppcd & (1 << i))) continue; pstatus = ehci_readl(ehci, &ehci->regs->port_status[i]); @@ -896,17 +896,24 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (rc) goto done; - switch (usb_pipetype (urb->pipe)) { - // case PIPE_CONTROL: - // case PIPE_BULK: - default: + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + /* + * We don't expedite dequeue for isochronous URBs. + * Just wait until they complete normally or their + * time slot expires. + */ + } else { qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; + qh->exception = 1; switch (qh->qh_state) { case QH_STATE_LINKED: + if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) + start_unlink_intr(ehci, qh); + else + start_unlink_async(ehci, qh); + break; case QH_STATE_COMPLETING: - start_unlink_async(ehci, qh); + qh->dequeue_during_giveback = 1; break; case QH_STATE_UNLINK: case QH_STATE_UNLINK_WAIT: @@ -917,33 +924,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) qh_completions(ehci, qh); break; } - break; - - case PIPE_INTERRUPT: - qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - start_unlink_intr(ehci, qh); - break; - case QH_STATE_IDLE: - qh_completions (ehci, qh); - break; - default: - ehci_dbg (ehci, "bogus qh %p state %d\n", - qh, qh->qh_state); - goto done; - } - break; - - case PIPE_ISOCHRONOUS: - // itd or sitd ... - - // wait till next completion, do it then. - // completion irqs can wait up to 1024 msec, - break; } done: spin_unlock_irqrestore (&ehci->lock, flags); @@ -984,6 +964,7 @@ rescan: goto done; } + qh->exception = 1; if (ehci->rh_state < EHCI_RH_RUNNING) qh->qh_state = QH_STATE_IDLE; switch (qh->qh_state) { @@ -1052,13 +1033,12 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) usb_settoggle(qh->dev, epnum, is_out, 0); if (!list_empty(&qh->qtd_list)) { WARN_ONCE(1, "clear_halt for a busy endpoint\n"); - } else if (qh->qh_state == QH_STATE_LINKED || - qh->qh_state == QH_STATE_COMPLETING) { - + } else { /* The toggle value in the QH can't be updated * while the QH is active. Unlink it now; * re-linking will call qh_refresh(). */ + qh->exception = 1; if (eptype == USB_ENDPOINT_XFER_BULK) start_unlink_async(ehci, qh); else @@ -1251,11 +1231,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_hcd_sh_driver #endif -#ifdef CONFIG_USB_EHCI_HCD_OMAP -#include "ehci-omap.c" -#define PLATFORM_DRIVER ehci_hcd_omap_driver -#endif - #ifdef CONFIG_PPC_PS3 #include "ehci-ps3.c" #define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver @@ -1271,41 +1246,16 @@ MODULE_LICENSE ("GPL"); #define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver #endif -#ifdef CONFIG_PLAT_ORION -#include "ehci-orion.c" -#define PLATFORM_DRIVER ehci_orion_driver -#endif - #ifdef CONFIG_USB_W90X900_EHCI #include "ehci-w90x900.c" #define PLATFORM_DRIVER ehci_hcd_w90x900_driver #endif -#ifdef CONFIG_ARCH_AT91 -#include "ehci-atmel.c" -#define PLATFORM_DRIVER ehci_atmel_driver -#endif - #ifdef CONFIG_USB_OCTEON_EHCI #include "ehci-octeon.c" #define PLATFORM_DRIVER ehci_octeon_driver #endif -#ifdef CONFIG_ARCH_VT8500 -#include "ehci-vt8500.c" -#define PLATFORM_DRIVER vt8500_ehci_driver -#endif - -#ifdef CONFIG_PLAT_SPEAR -#include "ehci-spear.c" -#define PLATFORM_DRIVER spear_ehci_hcd_driver -#endif - -#ifdef CONFIG_USB_EHCI_MSM -#include "ehci-msm.c" -#define PLATFORM_DRIVER ehci_msm_driver -#endif - #ifdef CONFIG_TILE_USB #include "ehci-tilegx.c" #define PLATFORM_DRIVER ehci_hcd_tilegx_driver @@ -1321,11 +1271,6 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER tegra_ehci_driver #endif -#ifdef CONFIG_USB_EHCI_S5P -#include "ehci-s5p.c" -#define PLATFORM_DRIVER s5p_ehci_driver -#endif - #ifdef CONFIG_SPARC_LEON #include "ehci-grlib.c" #define PLATFORM_DRIVER ehci_grlib_driver @@ -1345,6 +1290,12 @@ MODULE_LICENSE ("GPL"); !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \ !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \ !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \ + !IS_ENABLED(CONFIG_USB_EHCI_S5P) && \ + !IS_ENABLED(CONFIG_USB_EHCI_HCD_AT91) && \ + !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \ !defined(PLATFORM_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && \ !defined(OF_PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 7d06e77f6c4f..9ab4a4d9768a 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -464,7 +464,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) while (i--) { temp = ehci_readl(ehci, &ehci->regs->port_status [i]); if (test_bit(i, &resume_needed)) { - temp &= ~(PORT_RWC_BITS | PORT_RESUME); + temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME); ehci_writel(ehci, temp, &ehci->regs->port_status [i]); ehci_vdbg (ehci, "resumed port %d\n", i + 1); } @@ -590,7 +590,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) u32 mask; int ports, i, retval = 1; unsigned long flags; - u32 ppcd = 0; + u32 ppcd = ~0; /* init status to no-changes */ buf [0] = 0; @@ -628,9 +628,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) for (i = 0; i < ports; i++) { /* leverage per-port change bits feature */ - if (ehci->has_ppcd && !(ppcd & (1 << i))) - continue; - temp = ehci_readl(ehci, &ehci->regs->port_status [i]); + if (ppcd & (1 << i)) + temp = ehci_readl(ehci, &ehci->regs->port_status[i]); + else + temp = 0; /* * Return status information even for ports with OWNER set. @@ -839,7 +840,8 @@ static int ehci_hub_control ( * power switching; they're allowed to just limit the * current. khubd will turn the power back on. */ - if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { + if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle)) + && HCS_PPC(ehci->hcs_params)) { ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_POWER), status_reg); @@ -870,10 +872,9 @@ static int ehci_hub_control ( usb_hcd_end_port_resume(&hcd->self, wIndex); /* stop resume signaling */ - temp = ehci_readl(ehci, status_reg); - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_RESUME), - status_reg); + temp &= ~(PORT_RWC_BITS | + PORT_SUSPEND | PORT_RESUME); + ehci_writel(ehci, temp, status_reg); clear_bit(wIndex, &ehci->resuming_ports); retval = handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); @@ -883,7 +884,7 @@ static int ehci_hub_control ( wIndex + 1, retval); goto error; } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + temp = ehci_readl(ehci, status_reg); } } diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 88a49c87e748..0f717dc688b7 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -22,16 +22,26 @@ * along with this program; if not, you can find it at http://www.fsf.org */ -#include <linux/platform_device.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> - #include <linux/usb/otg.h> #include <linux/usb/msm_hsusb_hw.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h" #define MSM_USB_BASE (hcd->regs) +#define DRIVER_DESC "Qualcomm On-Chip EHCI Host Controller" + +static const char hcd_name[] = "ehci-msm"; +static struct hc_driver __read_mostly msm_hc_driver; static struct usb_phy *phy; static int ehci_msm_reset(struct usb_hcd *hcd) @@ -56,52 +66,6 @@ static int ehci_msm_reset(struct usb_hcd *hcd) return 0; } -static struct hc_driver msm_hc_driver = { - .description = hcd_name, - .product_desc = "Qualcomm On-Chip EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - - .reset = ehci_msm_reset, - .start = ehci_run, - - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * PM support - */ - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -}; - static int ehci_msm_probe(struct platform_device *pdev) { struct usb_hcd *hcd; @@ -145,7 +109,7 @@ static int ehci_msm_probe(struct platform_device *pdev) * management. */ phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(phy)) { + if (IS_ERR(phy)) { dev_err(&pdev->dev, "unable to find transceiver\n"); ret = -ENODEV; goto put_hcd; @@ -165,6 +129,8 @@ static int ehci_msm_probe(struct platform_device *pdev) pm_runtime_no_callbacks(&pdev->dev); pm_runtime_enable(&pdev->dev); + /* FIXME: need to call usb_add_hcd() here? */ + return 0; put_hcd: @@ -183,6 +149,8 @@ static int ehci_msm_remove(struct platform_device *pdev) otg_set_host(phy->otg, NULL); + /* FIXME: need to call usb_remove_hcd() here? */ + usb_put_hcd(hcd); return 0; @@ -226,3 +194,28 @@ static struct platform_driver ehci_msm_driver = { .pm = &ehci_msm_dev_pm_ops, }, }; + +static const struct ehci_driver_overrides msm_overrides __initdata = { + .reset = ehci_msm_reset, +}; + +static int __init ehci_msm_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ehci_init_driver(&msm_hc_driver, &msm_overrides); + return platform_driver_register(&ehci_msm_driver); +} +module_init(ehci_msm_init); + +static void __exit ehci_msm_cleanup(void) +{ + platform_driver_unregister(&ehci_msm_driver); +} +module_exit(ehci_msm_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:msm-ehci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 3065809546b1..402062973f03 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -33,25 +33,17 @@ struct ehci_hcd_mv { struct mv_usb_platform_data *pdata; - /* clock source and total clock number */ - unsigned int clknum; - struct clk *clk[0]; + struct clk *clk; }; static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) { - unsigned int i; - - for (i = 0; i < ehci_mv->clknum; i++) - clk_prepare_enable(ehci_mv->clk[i]); + clk_prepare_enable(ehci_mv->clk); } static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) { - unsigned int i; - - for (i = 0; i < ehci_mv->clknum; i++) - clk_disable_unprepare(ehci_mv->clk[i]); + clk_disable_unprepare(ehci_mv->clk); } static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) @@ -144,9 +136,8 @@ static int mv_ehci_probe(struct platform_device *pdev) struct ehci_hcd *ehci; struct ehci_hcd_mv *ehci_mv; struct resource *r; - int clk_i, retval = -ENODEV; + int retval = -ENODEV; u32 offset; - size_t size; if (!pdata) { dev_err(&pdev->dev, "missing platform_data\n"); @@ -160,8 +151,7 @@ static int mv_ehci_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; - size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; - ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + ehci_mv = devm_kzalloc(&pdev->dev, sizeof(*ehci_mv), GFP_KERNEL); if (ehci_mv == NULL) { dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); retval = -ENOMEM; @@ -172,16 +162,11 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv->pdata = pdata; ehci_mv->hcd = hcd; - ehci_mv->clknum = pdata->clknum; - for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { - ehci_mv->clk[clk_i] = - devm_clk_get(&pdev->dev, pdata->clkname[clk_i]); - if (IS_ERR(ehci_mv->clk[clk_i])) { - dev_err(&pdev->dev, "error get clck \"%s\"\n", - pdata->clkname[clk_i]); - retval = PTR_ERR(ehci_mv->clk[clk_i]); - goto err_clear_drvdata; - } + ehci_mv->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ehci_mv->clk)) { + dev_err(&pdev->dev, "error getting clock\n"); + retval = PTR_ERR(ehci_mv->clk); + goto err_clear_drvdata; } r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); @@ -225,7 +210,7 @@ static int mv_ehci_probe(struct platform_device *pdev) (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); hcd->rsrc_start = r->start; - hcd->rsrc_len = r->end - r->start + 1; + hcd->rsrc_len = resource_size(r); hcd->regs = ehci_mv->op_regs; hcd->irq = platform_get_irq(pdev, 0); @@ -240,12 +225,16 @@ static int mv_ehci_probe(struct platform_device *pdev) ehci_mv->mode = pdata->mode; if (ehci_mv->mode == MV_USB_MODE_OTG) { -#ifdef CONFIG_USB_OTG_UTILS ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(ehci_mv->otg)) { - dev_err(&pdev->dev, - "unable to find transceiver\n"); - retval = -ENODEV; + if (IS_ERR(ehci_mv->otg)) { + retval = PTR_ERR(ehci_mv->otg); + + if (retval == -ENXIO) + dev_info(&pdev->dev, "MV_USB_MODE_OTG " + "must have CONFIG_USB_PHY enabled\n"); + else + dev_err(&pdev->dev, + "unable to find transceiver\n"); goto err_disable_clk; } @@ -258,11 +247,6 @@ static int mv_ehci_probe(struct platform_device *pdev) } /* otg will enable clock before use as host */ mv_ehci_disable(ehci_mv); -#else - dev_info(&pdev->dev, "MV_USB_MODE_OTG " - "must have CONFIG_USB_OTG_UTILS enabled\n"); - goto err_disable_clk; -#endif } else { if (pdata->set_vbus) pdata->set_vbus(1); diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index e9301fb97eaa..c369767b00e2 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -28,11 +28,7 @@ #include <linux/slab.h> #include <linux/usb.h> #include <linux/usb/hcd.h> - #include <linux/platform_data/usb-ehci-mxc.h> - -#include <asm/mach-types.h> - #include "ehci.h" #define DRIVER_DESC "Freescale On-Chip EHCI Host driver" @@ -47,7 +43,7 @@ struct ehci_mxc_priv { static struct hc_driver __read_mostly ehci_mxc_hc_driver; -static const struct ehci_driver_overrides ehci_mxc_overrides __initdata = { +static const struct ehci_driver_overrides ehci_mxc_overrides __initconst = { .extra_priv_size = sizeof(struct ehci_mxc_priv), }; @@ -61,8 +57,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct ehci_hcd *ehci; - dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); - if (!pdata) { dev_err(dev, "No platform data given, bailing out.\n"); return -EINVAL; @@ -178,7 +172,7 @@ err_alloc: return ret; } -static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) +static int ehci_mxc_drv_remove(struct platform_device *pdev) { struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; struct usb_hcd *hcd = platform_get_drvdata(pdev); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 0555ee42d7cb..3d1491b5f360 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -4,10 +4,11 @@ * Bus Glue for the EHCI controllers in OMAP3/4 * Tested on several OMAP3 boards, and OMAP4 Pandaboard * - * Copyright (C) 2007-2011 Texas Instruments, Inc. + * Copyright (C) 2007-2013 Texas Instruments, Inc. * Author: Vikram Pandita <vikram.pandita@ti.com> * Author: Anand Gadiyar <gadiyar@ti.com> * Author: Keshava Munegowda <keshava_mgowda@ti.com> + * Author: Roger Quadros <rogerq@ti.com> * * Copyright (C) 2009 Nokia Corporation * Contact: Felipe Balbi <felipe.balbi@nokia.com> @@ -28,21 +29,23 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * TODO (last updated Feb 27, 2010): - * - add kernel-doc - * - enable AUTOIDLE - * - add suspend/resume - * - add HSIC and TLL support - * - convert to use hwmod and runtime PM */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/usb/ulpi.h> -#include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> #include <linux/gpio.h> #include <linux/clk.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> + +#include "ehci.h" #include <linux/platform_data/usb-omap.h> @@ -57,10 +60,16 @@ #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 -/*-------------------------------------------------------------------------*/ +#define DRIVER_DESC "OMAP-EHCI Host Controller driver" + +static const char hcd_name[] = "ehci-omap"; -static const struct hc_driver ehci_omap_hc_driver; +/*-------------------------------------------------------------------------*/ +struct omap_hcd { + struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */ + int nports; +}; static inline void ehci_write(void __iomem *base, u32 reg, u32 val) { @@ -72,99 +81,16 @@ static inline u32 ehci_read(void __iomem *base, u32 reg) return __raw_readl(base + reg); } +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ -static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - unsigned reg = 0; - - reg = ULPI_FUNC_CTRL_RESET - /* FUNCTION_CTRL_SET register */ - | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT) - /* Write */ - | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) - /* PORTn */ - | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) - /* start ULPI access*/ - | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); - - ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg); - - /* Wait for ULPI access completion */ - while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI) - & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_dbg(hcd->self.controller, - "phy reset operation timed out\n"); - break; - } - } -} - -static int omap_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc; - struct usbhs_omap_platform_data *pdata; - - pdata = hcd->self.controller->platform_data; - - /* Hold PHYs in reset while initializing EHCI controller */ - if (pdata->phy_reset) { - if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0); - - if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0); - - /* Hold the PHY in RESET for enough time till DIR is high */ - udelay(10); - } - - /* Soft reset the PHY using PHY reset command over ULPI */ - if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) - omap_ehci_soft_phy_reset(hcd, 0); - if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) - omap_ehci_soft_phy_reset(hcd, 1); - - /* we know this is the memory we want, no need to ioremap again */ - ehci->caps = hcd->regs; - - rc = ehci_setup(hcd); - - if (pdata->phy_reset) { - /* Hold the PHY in RESET for enough time till - * PHY is settled and ready - */ - udelay(10); - - if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1); - - if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); - } - - return rc; -} +static struct hc_driver __read_mostly ehci_omap_hc_driver; -static void disable_put_regulator( - struct usbhs_omap_platform_data *pdata) -{ - int i; - - for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { - if (pdata->regulator[i]) { - regulator_disable(pdata->regulator[i]); - regulator_put(pdata->regulator[i]); - } - } -} +static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { + .extra_priv_size = sizeof(struct omap_hcd), +}; -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ +static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32); /** * ehci_hcd_omap_probe - initialize TI-based HCDs @@ -175,15 +101,15 @@ static void disable_put_regulator( */ static int ehci_hcd_omap_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; - struct resource *res; - struct usb_hcd *hcd; - void __iomem *regs; - int ret = -ENODEV; - int irq; - int i; - char supply[7]; + struct device *dev = &pdev->dev; + struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct resource *res; + struct usb_hcd *hcd; + void __iomem *regs; + int ret = -ENODEV; + int irq; + int i; + struct omap_hcd *omap; if (usb_disabled()) return -ENODEV; @@ -193,52 +119,74 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_irq_byname(pdev, "ehci-irq"); - if (irq < 0) { - dev_err(dev, "EHCI irq failed\n"); - return -ENODEV; + /* For DT boot, get platform data from parent. i.e. usbhshost */ + if (dev->of_node) { + pdata = dev->parent->platform_data; + dev->platform_data = pdata; } - res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "ehci"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); + if (!pdata) { + dev_err(dev, "Missing platform data\n"); return -ENODEV; } - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "UHH EHCI ioremap failed\n"); - return -ENOMEM; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "EHCI irq failed\n"); + return -ENODEV; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &omap_ehci_dma_mask; + hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, dev_name(dev)); if (!hcd) { - dev_err(dev, "failed to create hcd with err %d\n", ret); - ret = -ENOMEM; - goto err_io; + dev_err(dev, "Failed to create HCD\n"); + return -ENOMEM; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = regs; - - /* get ehci regulator and enable */ - for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { - if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { - pdata->regulator[i] = NULL; - continue; - } - snprintf(supply, sizeof(supply), "hsusb%d", i); - pdata->regulator[i] = regulator_get(dev, supply); - if (IS_ERR(pdata->regulator[i])) { - pdata->regulator[i] = NULL; - dev_dbg(dev, - "failed to get ehci port%d regulator\n", i); - } else { - regulator_enable(pdata->regulator[i]); + hcd_to_ehci(hcd)->caps = regs; + + omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; + omap->nports = pdata->nports; + + platform_set_drvdata(pdev, hcd); + + /* get the PHY devices if needed */ + for (i = 0 ; i < omap->nports ; i++) { + struct usb_phy *phy; + + /* get the PHY device */ + if (dev->of_node) + phy = devm_usb_get_phy_by_phandle(dev, "phys", i); + else + phy = devm_usb_get_phy_dev(dev, i); + if (IS_ERR(phy)) { + /* Don't bail out if PHY is not absolutely necessary */ + if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) + continue; + + ret = PTR_ERR(phy); + dev_err(dev, "Can't get PHY device for port %d: %d\n", + i, ret); + goto err_phy; } + + omap->phy[i] = phy; } pm_runtime_enable(dev); @@ -262,16 +210,34 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) goto err_pm_runtime; } + /* + * Bring PHYs out of reset. + * Even though HSIC mode is a PHY-less mode, the reset + * line exists between the chips and can be modelled + * as a PHY device for reset control. + */ + for (i = 0; i < omap->nports; i++) { + if (!omap->phy[i]) + continue; + + usb_phy_init(omap->phy[i]); + /* bring PHY out of suspend */ + usb_phy_set_suspend(omap->phy[i], 0); + } return 0; err_pm_runtime: - disable_put_regulator(pdata); pm_runtime_put_sync(dev); + +err_phy: + for (i = 0; i < omap->nports; i++) { + if (omap->phy[i]) + usb_phy_shutdown(omap->phy[i]); + } + usb_put_hcd(hcd); -err_io: - iounmap(regs); return ret; } @@ -286,14 +252,19 @@ err_io: */ static int ehci_hcd_omap_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = dev_get_drvdata(dev); + struct device *dev = &pdev->dev; + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; + int i; usb_remove_hcd(hcd); - disable_put_regulator(dev->platform_data); - iounmap(hcd->regs); - usb_put_hcd(hcd); + for (i = 0; i < omap->nports; i++) { + if (omap->phy[i]) + usb_phy_shutdown(omap->phy[i]); + } + + usb_put_hcd(hcd); pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -308,6 +279,13 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } +static const struct of_device_id omap_ehci_dt_ids[] = { + { .compatible = "ti,ehci-omap" }, + { } +}; + +MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); + static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, .remove = ehci_hcd_omap_remove, @@ -315,56 +293,35 @@ static struct platform_driver ehci_hcd_omap_driver = { /*.suspend = ehci_hcd_omap_suspend, */ /*.resume = ehci_hcd_omap_resume, */ .driver = { - .name = "ehci-omap", + .name = hcd_name, + .of_match_table = of_match_ptr(omap_ehci_dt_ids), } }; /*-------------------------------------------------------------------------*/ -static const struct hc_driver ehci_omap_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP-EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = omap_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, +static int __init ehci_omap_init(void) +{ + if (usb_disabled()) + return -ENODEV; - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, + pr_info("%s: " DRIVER_DESC "\n", hcd_name); - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, + ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides); + return platform_driver_register(&ehci_hcd_omap_driver); +} +module_init(ehci_omap_init); - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; +static void __exit ehci_omap_cleanup(void) +{ + platform_driver_unregister(&ehci_hcd_omap_driver); +} +module_exit(ehci_omap_cleanup); MODULE_ALIAS("platform:ehci-omap"); MODULE_AUTHOR("Texas Instruments, Inc."); MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); +MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 914a3ecfb5d3..54c579485150 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -17,6 +17,12 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_irq.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> + +#include "ehci.h" #define rdl(off) __raw_readl(hcd->regs + (off)) #define wrl(off, val) __raw_writel((val), hcd->regs + (off)) @@ -34,6 +40,12 @@ #define USB_PHY_IVREF_CTRL 0x440 #define USB_PHY_TST_GRP_CTRL 0x450 +#define DRIVER_DESC "EHCI orion driver" + +static const char hcd_name[] = "ehci-orion"; + +static struct hc_driver __read_mostly ehci_orion_hc_driver; + /* * Implement Orion USB controller specification guidelines */ @@ -104,51 +116,6 @@ static void orion_usb_phy_v1_setup(struct usb_hcd *hcd) wrl(USB_MODE, 0x13); } -static const struct hc_driver ehci_orion_hc_driver = { - .description = hcd_name, - .product_desc = "Marvell Orion EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - static void ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, const struct mbus_dram_target_info *dram) @@ -305,7 +272,7 @@ err1: return err; } -static int __exit ehci_orion_drv_remove(struct platform_device *pdev) +static int ehci_orion_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct clk *clk; @@ -323,8 +290,6 @@ static int __exit ehci_orion_drv_remove(struct platform_device *pdev) return 0; } -MODULE_ALIAS("platform:orion-ehci"); - static const struct of_device_id ehci_orion_dt_ids[] = { { .compatible = "marvell,orion-ehci", }, {}, @@ -333,7 +298,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids); static struct platform_driver ehci_orion_driver = { .probe = ehci_orion_drv_probe, - .remove = __exit_p(ehci_orion_drv_remove), + .remove = ehci_orion_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "orion-ehci", @@ -341,3 +306,26 @@ static struct platform_driver ehci_orion_driver = { .of_match_table = of_match_ptr(ehci_orion_dt_ids), }, }; + +static int __init ehci_orion_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_orion_hc_driver, NULL); + return platform_driver_register(&ehci_orion_driver); +} +module_init(ehci_orion_init); + +static void __exit ehci_orion_cleanup(void) +{ + platform_driver_unregister(&ehci_orion_driver); +} +module_exit(ehci_orion_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:orion-ehci"); +MODULE_AUTHOR("Tzachi Perelstein"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 170b9399e09f..595d210655b6 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -292,17 +292,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) } } -#ifdef CONFIG_USB_SUSPEND - /* REVISIT: the controller works fine for wakeup iff the root hub - * itself is "globally" suspended, but usbcore currently doesn't - * understand such things. - * - * System suspend currently expects to be able to suspend the entire - * device tree, device-at-a-time. If we failed selective suspend - * reports, system suspend would fail; so the root hub code must claim - * success. That's lying to usbcore, and it matters for runtime - * PM scenarios with selective suspend and remote wakeup... - */ +#ifdef CONFIG_PM_RUNTIME if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev)) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif @@ -385,7 +375,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated) static struct hc_driver __read_mostly ehci_pci_hc_driver; -static const struct ehci_driver_overrides pci_overrides __initdata = { +static const struct ehci_driver_overrides pci_overrides __initconst = { .reset = ehci_pci_setup, }; diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index ca7506390542..f47f2594c9d4 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -18,11 +18,13 @@ * * Licensed under the GNU/GPL. See COPYING for details. */ +#include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/hrtimer.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/usb.h> #include <linux/usb/hcd.h> @@ -58,26 +60,36 @@ static int ehci_platform_reset(struct usb_hcd *hcd) static struct hc_driver __read_mostly ehci_platform_hc_driver; -static const struct ehci_driver_overrides platform_overrides __initdata = { +static const struct ehci_driver_overrides platform_overrides __initconst = { .reset = ehci_platform_reset, }; +static struct usb_ehci_pdata ehci_platform_defaults; + static int ehci_platform_probe(struct platform_device *dev) { struct usb_hcd *hcd; struct resource *res_mem; - struct usb_ehci_pdata *pdata = dev->dev.platform_data; + struct usb_ehci_pdata *pdata; int irq; int err = -ENOMEM; - if (!pdata) { - WARN_ON(1); - return -ENODEV; - } - if (usb_disabled()) return -ENODEV; + /* + * use reasonable defaults so platforms don't have to provide these. + * with DT probing on ARM, none of these are set. + */ + if (!dev->dev.platform_data) + dev->dev.platform_data = &ehci_platform_defaults; + if (!dev->dev.dma_mask) + dev->dev.dma_mask = &dev->dev.coherent_dma_mask; + if (!dev->dev.coherent_dma_mask) + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + pdata = dev->dev.platform_data; + irq = platform_get_irq(dev, 0); if (irq < 0) { dev_err(&dev->dev, "no irq provided"); @@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev) if (pdata->power_off) pdata->power_off(dev); + if (pdata == &ehci_platform_defaults) + dev->dev.platform_data = NULL; + return 0; } @@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev) #define ehci_platform_resume NULL #endif /* CONFIG_PM */ +static const struct of_device_id vt8500_ehci_ids[] = { + { .compatible = "via,vt8500-ehci", }, + { .compatible = "wm,prizm-ehci", }, + {} +}; + static const struct platform_device_id ehci_platform_table[] = { { "ehci-platform", 0 }, { } @@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = { .owner = THIS_MODULE, .name = "ehci-platform", .pm = &ehci_platform_pm_ops, + .of_match_table = of_match_ptr(vt8500_ehci_ids), } }; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index df5925a4f0db..fd983771b025 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -221,7 +221,6 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) tmp = hcd->irq; - ehci_shutdown(hcd); usb_remove_hcd(hcd); ps3_system_bus_set_drvdata(dev, NULL); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 23d136904285..d34b399b78e2 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) struct ehci_qh_hw *hw = qh->hw; /* writes to an active overlay are unsafe */ - BUG_ON(qh->qh_state != QH_STATE_IDLE); + WARN_ON(qh->qh_state != QH_STATE_IDLE); hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); hw->hw_alt_next = EHCI_LIST_END(ehci); @@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) { struct ehci_qtd *qtd; - if (list_empty (&qh->qtd_list)) - qtd = qh->dummy; - else { - qtd = list_entry (qh->qtd_list.next, - struct ehci_qtd, qtd_list); - /* - * first qtd may already be partially processed. - * If we come here during unlink, the QH overlay region - * might have reference to the just unlinked qtd. The - * qtd is updated in qh_completions(). Update the QH - * overlay here. - */ - if (qh->hw->hw_token & ACTIVE_BIT(ehci)) { - qh->hw->hw_qtd_next = qtd->hw_next; - qtd = NULL; - } - } + qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list); - if (qtd) - qh_update (ehci, qh, qtd); + /* + * first qtd may already be partially processed. + * If we come here during unlink, the QH overlay region + * might have reference to the just unlinked qtd. The + * qtd is updated in qh_completions(). Update the QH + * overlay here. + */ + if (qh->hw->hw_token & ACTIVE_BIT(ehci)) + qh->hw->hw_qtd_next = qtd->hw_next; + else + qh_update(ehci, qh, qtd); } /*-------------------------------------------------------------------------*/ @@ -299,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); /* * Process and free completed qtds for a qh, returning URBs to drivers. - * Chases up to qh->hw_current. Returns number of completions called, - * indicating how much "real" work we did. + * Chases up to qh->hw_current. Returns nonzero if the caller should + * unlink qh. */ static unsigned qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) @@ -309,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct list_head *entry, *tmp; int last_status; int stopped; - unsigned count = 0; u8 state; struct ehci_qh_hw *hw = qh->hw; - if (unlikely (list_empty (&qh->qtd_list))) - return count; - /* completions (or tasks on other cpus) must never clobber HALT * till we've gone through and cleaned everything up, even when * they add urbs to this qh's queue or mark them for unlinking. @@ -333,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) rescan: last = NULL; last_status = -EINPROGRESS; - qh->needs_rescan = 0; + qh->dequeue_during_giveback = 0; /* remove de-activated QTDs from front of queue. * after faults (including short reads), cleanup this urb @@ -352,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) if (last) { if (likely (last->urb != urb)) { ehci_urb_done(ehci, last->urb, last_status); - count++; last_status = -EINPROGRESS; } ehci_qtd_free (ehci, last); @@ -526,23 +514,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* last urb's completion might still need calling */ if (likely (last != NULL)) { ehci_urb_done(ehci, last->urb, last_status); - count++; ehci_qtd_free (ehci, last); } /* Do we need to rescan for URBs dequeued during a giveback? */ - if (unlikely(qh->needs_rescan)) { + if (unlikely(qh->dequeue_during_giveback)) { /* If the QH is already unlinked, do the rescan now. */ if (state == QH_STATE_IDLE) goto rescan; - /* Otherwise we have to wait until the QH is fully unlinked. - * Our caller will start an unlink if qh->needs_rescan is - * set. But if an unlink has already started, nothing needs - * to be done. - */ - if (state != QH_STATE_LINKED) - qh->needs_rescan = 0; + /* Otherwise the caller must unlink the QH. */ } /* restore original state; caller must unlink or relink */ @@ -551,33 +532,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* be sure the hardware's done with the qh before refreshing * it after fault cleanup, or recovering from silicon wrongly * overlaying the dummy qtd (which reduces DMA chatter). + * + * We won't refresh a QH that's linked (after the HC + * stopped the queue). That avoids a race: + * - HC reads first part of QH; + * - CPU updates that first part and the token; + * - HC reads rest of that QH, including token + * Result: HC gets an inconsistent image, and then + * DMAs to/from the wrong memory (corrupting it). + * + * That should be rare for interrupt transfers, + * except maybe high bandwidth ... */ - if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) { - switch (state) { - case QH_STATE_IDLE: - qh_refresh(ehci, qh); - break; - case QH_STATE_LINKED: - /* We won't refresh a QH that's linked (after the HC - * stopped the queue). That avoids a race: - * - HC reads first part of QH; - * - CPU updates that first part and the token; - * - HC reads rest of that QH, including token - * Result: HC gets an inconsistent image, and then - * DMAs to/from the wrong memory (corrupting it). - * - * That should be rare for interrupt transfers, - * except maybe high bandwidth ... - */ + if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) + qh->exception = 1; - /* Tell the caller to start an unlink */ - qh->needs_rescan = 1; - break; - /* otherwise, unlink already started */ - } - } - - return count; + /* Let the caller know if the QH needs to be unlinked. */ + return qh->exception; } /*-------------------------------------------------------------------------*/ @@ -957,14 +928,13 @@ done: /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ - /* init as live, toggle clear, advance to dummy */ + /* init as live, toggle clear */ qh->qh_state = QH_STATE_IDLE; hw = qh->hw; hw->hw_info1 = cpu_to_hc32(ehci, info1); hw->hw_info2 = cpu_to_hc32(ehci, info2); qh->is_out = !is_input; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); - qh_refresh (ehci, qh); return qh; } @@ -988,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci) if (--ehci->async_count) return; - /* The async schedule and async_unlink list are supposed to be empty */ - WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink); + /* The async schedule and unlink lists are supposed to be empty */ + WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) || + !list_empty(&ehci->async_idle)); /* Don't turn off the schedule until ASS is 1 */ ehci_poll_ASS(ehci); @@ -1020,8 +991,9 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->qh_next.qh = qh; head->hw->hw_next = dma; - qh->xacterrs = 0; qh->qh_state = QH_STATE_LINKED; + qh->xacterrs = 0; + qh->exception = 0; /* qtd completions reported later by interrupt */ enable_async(ehci); @@ -1179,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) /* Add to the end of the list of QHs waiting for the next IAAD */ qh->qh_state = QH_STATE_UNLINK_WAIT; - if (ehci->async_unlink) - ehci->async_unlink_last->unlink_next = qh; - else - ehci->async_unlink = qh; - ehci->async_unlink_last = qh; + list_add_tail(&qh->unlink_node, &ehci->async_unlink); /* Unlink it from the schedule */ prev = ehci->async; @@ -1196,44 +1164,19 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) ehci->qh_scan_next = qh->qh_next.qh; } -static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested) +static void start_iaa_cycle(struct ehci_hcd *ehci) { - /* - * Do nothing if an IAA cycle is already running or - * if one will be started shortly. - */ - if (ehci->async_iaa || ehci->async_unlinking) + /* Do nothing if an IAA cycle is already running */ + if (ehci->iaa_in_progress) return; + ehci->iaa_in_progress = true; /* If the controller isn't running, we don't have to wait for it */ if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) { - - /* Do all the waiting QHs */ - ehci->async_iaa = ehci->async_unlink; - ehci->async_unlink = NULL; - - if (!nested) /* Avoid recursion */ - end_unlink_async(ehci); + end_unlink_async(ehci); /* Otherwise start a new IAA cycle */ } else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) { - struct ehci_qh *qh; - - /* Do only the first waiting QH (nVidia bug?) */ - qh = ehci->async_unlink; - - /* - * Intel (?) bug: The HC can write back the overlay region - * even after the IAA interrupt occurs. In self-defense, - * always go through two IAA cycles for each QH. - */ - if (qh->qh_state == QH_STATE_UNLINK_WAIT) { - qh->qh_state = QH_STATE_UNLINK; - } else { - ehci->async_iaa = qh; - ehci->async_unlink = qh->unlink_next; - qh->unlink_next = NULL; - } /* Make sure the unlinks are all visible to the hardware */ wmb(); @@ -1250,36 +1193,73 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested) static void end_unlink_async(struct ehci_hcd *ehci) { struct ehci_qh *qh; + bool early_exit; if (ehci->has_synopsys_hc_bug) ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); + /* The current IAA cycle has ended */ + ehci->iaa_in_progress = false; + + if (list_empty(&ehci->async_unlink)) + return; + qh = list_first_entry(&ehci->async_unlink, struct ehci_qh, + unlink_node); /* QH whose IAA cycle just ended */ + + /* + * If async_unlinking is set then this routine is already running, + * either on the stack or on another CPU. + */ + early_exit = ehci->async_unlinking; + + /* If the controller isn't running, process all the waiting QHs */ + if (ehci->rh_state < EHCI_RH_RUNNING) + list_splice_tail_init(&ehci->async_unlink, &ehci->async_idle); + + /* + * Intel (?) bug: The HC can write back the overlay region even + * after the IAA interrupt occurs. In self-defense, always go + * through two IAA cycles for each QH. + */ + else if (qh->qh_state == QH_STATE_UNLINK_WAIT) { + qh->qh_state = QH_STATE_UNLINK; + early_exit = true; + } + + /* Otherwise process only the first waiting QH (NVIDIA bug?) */ + else + list_move_tail(&qh->unlink_node, &ehci->async_idle); + + /* Start a new IAA cycle if any QHs are waiting for it */ + if (!list_empty(&ehci->async_unlink)) + start_iaa_cycle(ehci); + + /* + * Don't allow nesting or concurrent calls, + * or wait for the second IAA cycle for the next QH. + */ + if (early_exit) + return; + /* Process the idle QHs */ - restart: ehci->async_unlinking = true; - while (ehci->async_iaa) { - qh = ehci->async_iaa; - ehci->async_iaa = qh->unlink_next; - qh->unlink_next = NULL; + while (!list_empty(&ehci->async_idle)) { + qh = list_first_entry(&ehci->async_idle, struct ehci_qh, + unlink_node); + list_del(&qh->unlink_node); qh->qh_state = QH_STATE_IDLE; qh->qh_next.qh = NULL; - qh_completions(ehci, qh); + if (!list_empty(&qh->qtd_list)) + qh_completions(ehci, qh); if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) qh_link_async(ehci, qh); disable_async(ehci); } ehci->async_unlinking = false; - - /* Start a new IAA cycle if any QHs are waiting for it */ - if (ehci->async_unlink) { - start_iaa_cycle(ehci, true); - if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) - goto restart; - } } static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -1288,7 +1268,6 @@ static void unlink_empty_async(struct ehci_hcd *ehci) { struct ehci_qh *qh; struct ehci_qh *qh_to_unlink = NULL; - bool check_unlinks_later = false; int count = 0; /* Find the last async QH which has been empty for a timer cycle */ @@ -1296,15 +1275,13 @@ static void unlink_empty_async(struct ehci_hcd *ehci) if (list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED) { ++count; - if (qh->unlink_cycle == ehci->async_unlink_cycle) - check_unlinks_later = true; - else + if (qh->unlink_cycle != ehci->async_unlink_cycle) qh_to_unlink = qh; } } /* If nothing else is being unlinked, unlink the last empty QH */ - if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) { + if (list_empty(&ehci->async_unlink) && qh_to_unlink) { start_unlink_async(ehci, qh_to_unlink); --count; } @@ -1317,7 +1294,7 @@ static void unlink_empty_async(struct ehci_hcd *ehci) } /* The root hub is suspended; unlink all the async QHs */ -static void unlink_empty_async_suspended(struct ehci_hcd *ehci) +static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci) { struct ehci_qh *qh; @@ -1326,7 +1303,7 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci) WARN_ON(!list_empty(&qh->qtd_list)); single_unlink_async(ehci, qh); } - start_iaa_cycle(ehci, false); + start_iaa_cycle(ehci); } /* makes sure the async qh will become idle */ @@ -1334,19 +1311,12 @@ static void unlink_empty_async_suspended(struct ehci_hcd *ehci) static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* - * If the QH isn't linked then there's nothing we can do - * unless we were called during a giveback, in which case - * qh_completions() has to deal with it. - */ - if (qh->qh_state != QH_STATE_LINKED) { - if (qh->qh_state == QH_STATE_COMPLETING) - qh->needs_rescan = 1; + /* If the QH isn't linked then there's nothing we can do. */ + if (qh->qh_state != QH_STATE_LINKED) return; - } single_unlink_async(ehci, qh); - start_iaa_cycle(ehci, false); + start_iaa_cycle(ehci); } /*-------------------------------------------------------------------------*/ @@ -1360,7 +1330,7 @@ static void scan_async (struct ehci_hcd *ehci) while (ehci->qh_scan_next) { qh = ehci->qh_scan_next; ehci->qh_scan_next = qh->qh_next.qh; - rescan: + /* clean any finished work for this qh */ if (!list_empty(&qh->qtd_list)) { int temp; @@ -1373,14 +1343,13 @@ static void scan_async (struct ehci_hcd *ehci) * in single_unlink_async(). */ temp = qh_completions(ehci, qh); - if (qh->needs_rescan) { + if (unlikely(temp)) { start_unlink_async(ehci, qh); } else if (list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED) { qh->unlink_cycle = ehci->async_unlink_cycle; check_unlinks_later = true; - } else if (temp != 0) - goto rescan; + } } } diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 20ebf6a8b7f4..635775278c7f 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -13,13 +13,23 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/of_gpio.h> +#include <linux/platform_device.h> #include <linux/platform_data/usb-ehci-s5p.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> -#include <plat/usb-phy.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include "ehci.h" + +#define DRIVER_DESC "EHCI s5p driver" #define EHCI_INSNREG00(base) (base + 0x90) #define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) @@ -30,82 +40,35 @@ (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) +static const char hcd_name[] = "ehci-s5p"; +static struct hc_driver __read_mostly s5p_ehci_hc_driver; + struct s5p_ehci_hcd { - struct device *dev; - struct usb_hcd *hcd; struct clk *clk; struct usb_phy *phy; struct usb_otg *otg; struct s5p_ehci_platdata *pdata; }; -static const struct hc_driver s5p_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "S5P EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - .reset = ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .get_frame_number = ehci_get_frame, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci) -{ - struct platform_device *pdev = to_platform_device(s5p_ehci->dev); - - if (s5p_ehci->phy) - usb_phy_init(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_init) - s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); -} - -static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci) -{ - struct platform_device *pdev = to_platform_device(s5p_ehci->dev); - - if (s5p_ehci->phy) - usb_phy_shutdown(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_exit) - s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); -} +#define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv) static void s5p_setup_vbus_gpio(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int err; int gpio; - if (!pdev->dev.of_node) + if (!dev->of_node) return; - gpio = of_get_named_gpio(pdev->dev.of_node, - "samsung,vbus-gpio", 0); + gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); if (!gpio_is_valid(gpio)) return; - err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio"); + err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, + "ehci_vbus_gpio"); if (err) - dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio); + dev_err(dev, "can't request ehci vbus gpio %d", gpio); } static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32); @@ -133,13 +96,15 @@ static int s5p_ehci_probe(struct platform_device *pdev) s5p_setup_vbus_gpio(pdev); - s5p_ehci = devm_kzalloc(&pdev->dev, sizeof(struct s5p_ehci_hcd), - GFP_KERNEL); - if (!s5p_ehci) + hcd = usb_create_hcd(&s5p_ehci_hc_driver, + &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); return -ENOMEM; - + } + s5p_ehci = to_s5p_ehci(hcd); phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(phy)) { + if (IS_ERR(phy)) { /* Fallback to pdata */ if (!pdata) { dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); @@ -152,16 +117,6 @@ static int s5p_ehci_probe(struct platform_device *pdev) s5p_ehci->otg = phy->otg; } - s5p_ehci->dev = &pdev->dev; - - hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - return -ENOMEM; - } - - s5p_ehci->hcd = hcd; s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(s5p_ehci->clk)) { @@ -198,9 +153,12 @@ static int s5p_ehci_probe(struct platform_device *pdev) } if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - s5p_ehci_phy_enable(s5p_ehci); + if (s5p_ehci->phy) + usb_phy_init(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_init) + s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -214,12 +172,15 @@ static int s5p_ehci_probe(struct platform_device *pdev) goto fail_add_hcd; } - platform_set_drvdata(pdev, s5p_ehci); + platform_set_drvdata(pdev, hcd); return 0; fail_add_hcd: - s5p_ehci_phy_disable(s5p_ehci); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); fail_io: clk_disable_unprepare(s5p_ehci->clk); fail_clk: @@ -229,15 +190,18 @@ fail_clk: static int s5p_ehci_remove(struct platform_device *pdev) { - struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = s5p_ehci->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); usb_remove_hcd(hcd); if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - s5p_ehci_phy_disable(s5p_ehci); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(s5p_ehci->clk); @@ -248,8 +212,7 @@ static int s5p_ehci_remove(struct platform_device *pdev) static void s5p_ehci_shutdown(struct platform_device *pdev) { - struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = s5p_ehci->hcd; + struct usb_hcd *hcd = platform_get_drvdata(pdev); if (hcd->driver->shutdown) hcd->driver->shutdown(hcd); @@ -258,17 +221,22 @@ static void s5p_ehci_shutdown(struct platform_device *pdev) #ifdef CONFIG_PM static int s5p_ehci_suspend(struct device *dev) { - struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); - struct usb_hcd *hcd = s5p_ehci->hcd; + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); + bool do_wakeup = device_may_wakeup(dev); int rc; rc = ehci_suspend(hcd, do_wakeup); if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - s5p_ehci_phy_disable(s5p_ehci); + if (s5p_ehci->phy) + usb_phy_shutdown(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_exit) + s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(s5p_ehci->clk); @@ -277,15 +245,19 @@ static int s5p_ehci_suspend(struct device *dev) static int s5p_ehci_resume(struct device *dev) { - struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); - struct usb_hcd *hcd = s5p_ehci->hcd; + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); + struct platform_device *pdev = to_platform_device(dev); clk_prepare_enable(s5p_ehci->clk); if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); + s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - s5p_ehci_phy_enable(s5p_ehci); + if (s5p_ehci->phy) + usb_phy_init(s5p_ehci->phy); + else if (s5p_ehci->pdata->phy_init) + s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); /* DMA burst Enable */ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); @@ -322,5 +294,29 @@ static struct platform_driver s5p_ehci_driver = { .of_match_table = of_match_ptr(exynos_ehci_match), } }; +static const struct ehci_driver_overrides s5p_overrides __initdata = { + .extra_priv_size = sizeof(struct s5p_ehci_hcd), +}; + +static int __init ehci_s5p_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides); + return platform_driver_register(&s5p_ehci_driver); +} +module_init(ehci_s5p_init); + +static void __exit ehci_s5p_cleanup(void) +{ + platform_driver_unregister(&s5p_ehci_driver); +} +module_exit(ehci_s5p_cleanup); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:s5p-ehci"); +MODULE_AUTHOR("Jingoo Han"); +MODULE_AUTHOR("Joonyoung Shim"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 010f686d8881..acff5b8f6e89 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) } qh->qh_state = QH_STATE_LINKED; qh->xacterrs = 0; + qh->exception = 0; /* update per-qh bandwidth for usbfs */ ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period @@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) { - /* If the QH isn't linked then there's nothing we can do - * unless we were called during a giveback, in which case - * qh_completions() has to deal with it. - */ - if (qh->qh_state != QH_STATE_LINKED) { - if (qh->qh_state == QH_STATE_COMPLETING) - qh->needs_rescan = 1; + /* If the QH isn't linked then there's nothing we can do. */ + if (qh->qh_state != QH_STATE_LINKED) return; - } qh_unlink_periodic (ehci, qh); @@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) qh->unlink_cycle = ehci->intr_unlink_cycle; /* New entries go at the end of the intr_unlink list */ - if (ehci->intr_unlink) - ehci->intr_unlink_last->unlink_next = qh; - else - ehci->intr_unlink = qh; - ehci->intr_unlink_last = qh; + list_add_tail(&qh->unlink_node, &ehci->intr_unlink); if (ehci->intr_unlinking) ; /* Avoid recursive calls */ else if (ehci->rh_state < EHCI_RH_RUNNING) ehci_handle_intr_unlinks(ehci); - else if (ehci->intr_unlink == qh) { + else if (ehci->intr_unlink.next == &qh->unlink_node) { ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); ++ehci->intr_unlink_cycle; } @@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_IDLE; hw->hw_next = EHCI_LIST_END(ehci); - qh_completions(ehci, qh); + if (!list_empty(&qh->qtd_list)) + qh_completions(ehci, qh); /* reschedule QH iff another request is queued */ if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { @@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ struct ehci_qh_hw *hw = qh->hw; - qh_refresh(ehci, qh); hw->hw_next = EHCI_LIST_END(ehci); frame = qh->start; @@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) } else ehci_dbg (ehci, "reused qh %p schedule\n", qh); - /* stuff into the periodic schedule */ - qh_link_periodic(ehci, qh); done: return status; } @@ -891,6 +880,12 @@ static int intr_submit ( qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); BUG_ON (qh == NULL); + /* stuff into the periodic schedule */ + if (qh->qh_state == QH_STATE_IDLE) { + qh_refresh(ehci, qh); + qh_link_periodic(ehci, qh); + } + /* ... update usbfs periodic stats */ ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; @@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci) list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list, intr_node) { - rescan: + /* clean any finished work for this qh */ if (!list_empty(&qh->qtd_list)) { int temp; @@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci) * in qh_unlink_periodic(). */ temp = qh_completions(ehci, qh); - if (unlikely(qh->needs_rescan || - (list_empty(&qh->qtd_list) && - qh->qh_state == QH_STATE_LINKED))) + if (unlikely(temp || (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED))) start_unlink_intr(ehci, qh); - else if (temp != 0) - goto rescan; } } } diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 3565a300f401..b44d716ddc82 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -77,7 +77,6 @@ static const struct hc_driver ehci_sh_hc_driver = { static int ehci_hcd_sh_probe(struct platform_device *pdev) { - const struct hc_driver *driver = &ehci_sh_hc_driver; struct resource *res; struct ehci_sh_priv *priv; struct ehci_sh_platdata *pdata; @@ -170,7 +169,7 @@ fail_create_hcd: return ret; } -static int __exit ehci_hcd_sh_remove(struct platform_device *pdev) +static int ehci_hcd_sh_remove(struct platform_device *pdev) { struct ehci_sh_priv *priv = platform_get_drvdata(pdev); struct usb_hcd *hcd = priv->hcd; @@ -196,7 +195,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev) static struct platform_driver ehci_hcd_sh_driver = { .probe = ehci_hcd_sh_probe, - .remove = __exit_p(ehci_hcd_sh_remove), + .remove = ehci_hcd_sh_remove, .shutdown = ehci_hcd_sh_shutdown, .driver = { .name = "sh_ehci", diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 466c1bb5b967..61ecfb3d52f5 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -1,5 +1,5 @@ /* -* Driver for EHCI HCD on SPEAR SOC +* Driver for EHCI HCD on SPEAr SOC * * Copyright (C) 2010 ST Micro Electronics, * Deepak Sikri <deepak.sikri@st.com> @@ -12,73 +12,32 @@ */ #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> #include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> -struct spear_ehci { - struct ehci_hcd ehci; - struct clk *clk; -}; - -#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd) +#include "ehci.h" -static void spear_start_ehci(struct spear_ehci *ehci) -{ - clk_prepare_enable(ehci->clk); -} +#define DRIVER_DESC "EHCI SPEAr driver" -static void spear_stop_ehci(struct spear_ehci *ehci) -{ - clk_disable_unprepare(ehci->clk); -} +static const char hcd_name[] = "SPEAr-ehci"; -static int ehci_spear_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - /* registers start at offset 0x0 */ - ehci->caps = hcd->regs; +struct spear_ehci { + struct clk *clk; +}; - return ehci_setup(hcd); -} +#define to_spear_ehci(hcd) (struct spear_ehci *)(hcd_to_ehci(hcd)->priv) -static const struct hc_driver ehci_spear_hc_driver = { - .description = hcd_name, - .product_desc = "SPEAr EHCI", - .hcd_priv_size = sizeof(struct spear_ehci), - - /* generic hardware linkage */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* basic lifecycle operations */ - .reset = ehci_spear_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* scheduling support */ - .get_frame_number = ehci_get_frame, - - /* root hub support */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; +static struct hc_driver __read_mostly ehci_spear_hc_driver; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ehci_spear_drv_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -94,7 +53,7 @@ static int ehci_spear_drv_resume(struct device *dev) ehci_resume(hcd, false); return 0; } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); @@ -104,7 +63,7 @@ static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32); static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd ; - struct spear_ehci *ehci; + struct spear_ehci *sehci; struct resource *res; struct clk *usbh_clk; const struct hc_driver *driver = &ehci_spear_hc_driver; @@ -161,10 +120,13 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) goto err_put_hcd; } - ehci = (struct spear_ehci *)hcd_to_ehci(hcd); - ehci->clk = usbh_clk; + sehci = to_spear_ehci(hcd); + sehci->clk = usbh_clk; + + /* registers start at offset 0x0 */ + hcd_to_ehci(hcd)->caps = hcd->regs; - spear_start_ehci(ehci); + clk_prepare_enable(sehci->clk); retval = usb_add_hcd(hcd, irq, IRQF_SHARED); if (retval) goto err_stop_ehci; @@ -172,7 +134,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) return retval; err_stop_ehci: - spear_stop_ehci(ehci); + clk_disable_unprepare(sehci->clk); err_put_hcd: usb_put_hcd(hcd); fail: @@ -184,7 +146,7 @@ fail: static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct spear_ehci *ehci_p = to_spear_ehci(hcd); + struct spear_ehci *sehci = to_spear_ehci(hcd); if (!hcd) return 0; @@ -192,8 +154,8 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) BUG(); usb_remove_hcd(hcd); - if (ehci_p->clk) - spear_stop_ehci(ehci_p); + if (sehci->clk) + clk_disable_unprepare(sehci->clk); usb_put_hcd(hcd); return 0; @@ -216,4 +178,29 @@ static struct platform_driver spear_ehci_hcd_driver = { } }; +static const struct ehci_driver_overrides spear_overrides __initdata = { + .extra_priv_size = sizeof(struct spear_ehci), +}; + +static int __init ehci_spear_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + pr_info("%s: " DRIVER_DESC "\n", hcd_name); + + ehci_init_driver(&ehci_spear_hc_driver, &spear_overrides); + return platform_driver_register(&spear_ehci_hcd_driver); +} +module_init(ehci_spear_init); + +static void __exit ehci_spear_cleanup(void) +{ + platform_driver_unregister(&spear_ehci_hcd_driver); +} +module_exit(ehci_spear_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_ALIAS("platform:spear-ehci"); +MODULE_AUTHOR("Deepak Sikri"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 568aecc7075b..e3eddc31ac83 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -28,6 +28,7 @@ #include <linux/pm_runtime.h> #include <linux/usb/ehci_def.h> #include <linux/usb/tegra_usb_phy.h> +#include <linux/clk/tegra.h> #define TEGRA_USB_BASE 0xC5000000 #define TEGRA_USB2_BASE 0xC5004000 @@ -610,7 +611,7 @@ static const struct dev_pm_ops tegra_ehci_pm_ops = { /* Bits of PORTSC1, which will get cleared by writing 1 into them */ #define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) -void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) +static void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) { unsigned long val; struct usb_hcd *hcd = bus_to_hcd(x->otg->host); @@ -621,9 +622,8 @@ void tegra_ehci_set_pts(struct usb_phy *x, u8 pts_val) val |= TEGRA_USB_PORTSC1_PTS(pts_val & 3); writel(val, base + TEGRA_USB_PORTSC1); } -EXPORT_SYMBOL_GPL(tegra_ehci_set_pts); -void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) +static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) { unsigned long val; struct usb_hcd *hcd = bus_to_hcd(x->otg->host); @@ -636,7 +636,6 @@ void tegra_ehci_set_phcd(struct usb_phy *x, bool enable) val &= ~TEGRA_USB_PORTSC1_PHCD; writel(val, base + TEGRA_USB_PORTSC1); } -EXPORT_SYMBOL_GPL(tegra_ehci_set_phcd); static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); @@ -691,6 +690,10 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (err) goto fail_clk; + tegra_periph_reset_assert(tegra->clk); + udelay(1); + tegra_periph_reset_deassert(tegra->clk); + tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, "nvidia,needs-double-reset"); @@ -733,7 +736,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs, pdata->phy_config, - TEGRA_USB_PHY_MODE_HOST); + TEGRA_USB_PHY_MODE_HOST, + tegra_ehci_set_pts, + tegra_ehci_set_phcd); if (IS_ERR(tegra->phy)) { dev_err(&pdev->dev, "Failed to open USB phy\n"); err = -ENXIO; @@ -755,7 +760,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) err = usb_phy_set_suspend(hcd->phy, 0); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); - goto fail; + goto fail_phy; } tegra->host_resumed = 1; @@ -765,17 +770,17 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!irq) { dev_err(&pdev->dev, "Failed to get IRQ\n"); err = -ENODEV; - goto fail; + goto fail_phy; } -#ifdef CONFIG_USB_OTG_UTILS if (pdata->operating_mode == TEGRA_USB_OTG) { tegra->transceiver = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (!IS_ERR_OR_NULL(tegra->transceiver)) + if (!IS_ERR(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, &hcd->self); + } else { + tegra->transceiver = ERR_PTR(-ENODEV); } -#endif err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) { @@ -794,10 +799,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) return err; fail: -#ifdef CONFIG_USB_OTG_UTILS - if (!IS_ERR_OR_NULL(tegra->transceiver)) + if (!IS_ERR(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); -#endif +fail_phy: usb_phy_shutdown(hcd->phy); fail_io: clk_disable_unprepare(tegra->clk); @@ -815,10 +819,8 @@ static int tegra_ehci_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); -#ifdef CONFIG_USB_OTG_UTILS - if (!IS_ERR_OR_NULL(tegra->transceiver)) + if (!IS_ERR(tegra->transceiver)) otg_set_host(tegra->transceiver->otg, NULL); -#endif usb_phy_shutdown(hcd->phy); usb_remove_hcd(hcd); diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index c3fa1305f830..11e5b32f73e9 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci) if (want != actual) { - /* Poll again later, but give up after about 20 ms */ - if (ehci->ASS_poll_count++ < 20) { + /* Poll again later, but give up after about 2-4 ms */ + if (ehci->ASS_poll_count++ < 2) { ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); return; } @@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) if (want != actual) { - /* Poll again later, but give up after about 20 ms */ - if (ehci->PSS_poll_count++ < 20) { + /* Poll again later, but give up after about 2-4 ms */ + if (ehci->PSS_poll_count++ < 2) { ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); return; } @@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) * process all the QHs on the list. */ ehci->intr_unlinking = true; - while (ehci->intr_unlink) { - struct ehci_qh *qh = ehci->intr_unlink; + while (!list_empty(&ehci->intr_unlink)) { + struct ehci_qh *qh; + qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh, + unlink_node); if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) break; - ehci->intr_unlink = qh->unlink_next; - qh->unlink_next = NULL; + list_del(&qh->unlink_node); end_unlink_intr(ehci, qh); } /* Handle remaining entries later */ - if (ehci->intr_unlink) { + if (!list_empty(&ehci->intr_unlink)) { ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); ++ehci->intr_unlink_cycle; } @@ -295,8 +296,7 @@ static void end_free_itds(struct ehci_hcd *ehci) /* Handle lost (or very late) IAA interrupts */ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) { - if (ehci->rh_state != EHCI_RH_RUNNING) - return; + u32 cmd, status; /* * Lost IAA irqs wedge things badly; seen first with a vt8235. @@ -304,34 +304,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) * (a) SMP races against real IAA firing and retriggering, and * (b) clean HC shutdown, when IAA watchdog was pending. */ - if (1) { - u32 cmd, status; - - /* If we get here, IAA is *REALLY* late. It's barely - * conceivable that the system is so busy that CMD_IAAD - * is still legitimately set, so let's be sure it's - * clear before we read STS_IAA. (The HC should clear - * CMD_IAAD when it sets STS_IAA.) - */ - cmd = ehci_readl(ehci, &ehci->regs->command); - - /* - * If IAA is set here it either legitimately triggered - * after the watchdog timer expired (_way_ late, so we'll - * still count it as lost) ... or a silicon erratum: - * - VIA seems to set IAA without triggering the IRQ; - * - IAAD potentially cleared without setting IAA. - */ - status = ehci_readl(ehci, &ehci->regs->status); - if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { - COUNT(ehci->stats.lost_iaa); - ehci_writel(ehci, STS_IAA, &ehci->regs->status); - } + if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING) + return; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = ehci_readl(ehci, &ehci->regs->command); - ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", - status, cmd); - end_unlink_async(ehci); + /* + * If IAA is set here it either legitimately triggered + * after the watchdog timer expired (_way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = ehci_readl(ehci, &ehci->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { + COUNT(ehci->stats.lost_iaa); + ehci_writel(ehci, STS_IAA, &ehci->regs->status); } + + ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); + end_unlink_async(ehci); } diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c deleted file mode 100644 index 7ecf709610ba..000000000000 --- a/drivers/usb/host/ehci-vt8500.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * drivers/usb/host/ehci-vt8500.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * Based on ehci-au1xxx.c - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/err.h> -#include <linux/of.h> -#include <linux/platform_device.h> - -static const struct hc_driver vt8500_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "VT8500 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32); - -static int vt8500_ehci_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - /* - * Right now device-tree probed devices don't get dma_mask set. - * Since shared usb code relies on it, set it here for now. - * Once we have dma capability bindings this can go away. - */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &vt8500_ehci_dma_mask; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - hcd->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(hcd->regs)) { - ret = PTR_ERR(hcd->regs); - goto err1; - } - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - -err1: - usb_put_hcd(hcd); - return ret; -} - -static int vt8500_ehci_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static const struct of_device_id vt8500_ehci_ids[] = { - { .compatible = "via,vt8500-ehci", }, - { .compatible = "wm,prizm-ehci", }, - {} -}; - -static struct platform_driver vt8500_ehci_driver = { - .probe = vt8500_ehci_drv_probe, - .remove = vt8500_ehci_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "vt8500-ehci", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(vt8500_ehci_ids), - } -}; - -MODULE_ALIAS("platform:vt8500-ehci"); -MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 36c3a8210595..7c978b23520d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -121,6 +121,7 @@ struct ehci_hcd { /* one per controller */ bool scanning:1; bool need_rescan:1; bool intr_unlinking:1; + bool iaa_in_progress:1; bool async_unlinking:1; bool shutdown:1; struct ehci_qh *qh_scan_next; @@ -128,9 +129,8 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *dummy; /* For AMD quirk use */ - struct ehci_qh *async_unlink; - struct ehci_qh *async_unlink_last; - struct ehci_qh *async_iaa; + struct list_head async_unlink; + struct list_head async_idle; unsigned async_unlink_cycle; unsigned async_count; /* async activity count */ @@ -143,8 +143,7 @@ struct ehci_hcd { /* one per controller */ unsigned i_thresh; /* uframes HC might cache */ union ehci_shadow *pshadow; /* mirror hw periodic table */ - struct ehci_qh *intr_unlink; - struct ehci_qh *intr_unlink_last; + struct list_head intr_unlink; unsigned intr_unlink_cycle; unsigned now_frame; /* frame from HC hardware */ unsigned last_iso_frame; /* last frame scanned for iso */ @@ -200,6 +199,7 @@ struct ehci_hcd { /* one per controller */ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned need_oc_pp_cycle:1; /* MPC834X port power */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) @@ -380,11 +380,10 @@ struct ehci_qh { struct list_head qtd_list; /* sw qtd list */ struct list_head intr_node; /* list of intr QHs */ struct ehci_qtd *dummy; - struct ehci_qh *unlink_next; /* next on unlink list */ + struct list_head unlink_node; unsigned unlink_cycle; - u8 needs_rescan; /* Dequeue during giveback */ u8 qh_state; #define QH_STATE_LINKED 1 /* HC sees this */ #define QH_STATE_UNLINK 2 /* HC may still see this */ @@ -407,6 +406,9 @@ struct ehci_qh { struct usb_device *dev; /* access to TT */ unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ + unsigned dequeue_during_giveback:1; + unsigned exception:1; /* got a fault, or an unlink + was requested */ }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index e3b7e85120e4..114583a8e92b 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -17,7 +17,6 @@ #include <linux/platform_data/usb-exynos.h> #include <linux/usb/phy.h> #include <linux/usb/samsung_usb_phy.h> -#include <plat/usb-phy.h> struct exynos_ohci_hcd { struct device *dev; @@ -34,7 +33,7 @@ static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) if (exynos_ohci->phy) usb_phy_init(exynos_ohci->phy); - else if (exynos_ohci->pdata->phy_init) + else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init) exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); } @@ -44,7 +43,7 @@ static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) if (exynos_ohci->phy) usb_phy_shutdown(exynos_ohci->phy); - else if (exynos_ohci->pdata->phy_exit) + else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit) exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); } @@ -127,8 +126,12 @@ static int exynos_ohci_probe(struct platform_device *pdev) if (!exynos_ohci) return -ENOMEM; + if (of_device_is_compatible(pdev->dev.of_node, + "samsung,exynos5440-ohci")) + goto skip_phy; + phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); - if (IS_ERR_OR_NULL(phy)) { + if (IS_ERR(phy)) { /* Fallback to pdata */ if (!pdata) { dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); @@ -141,6 +144,8 @@ static int exynos_ohci_probe(struct platform_device *pdev) exynos_ohci->otg = phy->otg; } +skip_phy: + exynos_ohci->dev = &pdev->dev; hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, @@ -311,6 +316,7 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id exynos_ohci_match[] = { { .compatible = "samsung,exynos4210-ohci" }, + { .compatible = "samsung,exynos5440-ohci" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_ohci_match); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 180a2b01db56..9e6de9586ae4 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1102,12 +1102,12 @@ MODULE_LICENSE ("GPL"); #if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) #include "ohci-s3c2410.c" -#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver +#define S3C2410_PLATFORM_DRIVER ohci_hcd_s3c2410_driver #endif #ifdef CONFIG_USB_OHCI_EXYNOS #include "ohci-exynos.c" -#define PLATFORM_DRIVER exynos_ohci_driver +#define EXYNOS_PLATFORM_DRIVER exynos_ohci_driver #endif #ifdef CONFIG_USB_OHCI_HCD_OMAP1 @@ -1127,25 +1127,24 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_ARCH_EP93XX #include "ohci-ep93xx.c" -#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver +#define EP93XX_PLATFORM_DRIVER ohci_hcd_ep93xx_driver #endif #ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" -#define PLATFORM_DRIVER ohci_hcd_at91_driver +#define AT91_PLATFORM_DRIVER ohci_hcd_at91_driver #endif #ifdef CONFIG_ARCH_LPC32XX #include "ohci-nxp.c" -#define PLATFORM_DRIVER usb_hcd_nxp_driver +#define NXP_PLATFORM_DRIVER usb_hcd_nxp_driver #endif #ifdef CONFIG_ARCH_DAVINCI_DA8XX #include "ohci-da8xx.c" -#define PLATFORM_DRIVER ohci_hcd_da8xx_driver +#define DAVINCI_PLATFORM_DRIVER ohci_hcd_da8xx_driver #endif - #ifdef CONFIG_USB_OHCI_HCD_PPC_OF #include "ohci-ppc-of.c" #define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver @@ -1153,7 +1152,7 @@ MODULE_LICENSE ("GPL"); #ifdef CONFIG_PLAT_SPEAR #include "ohci-spear.c" -#define PLATFORM_DRIVER spear_ohci_hcd_driver +#define SPEAR_PLATFORM_DRIVER spear_ohci_hcd_driver #endif #ifdef CONFIG_PPC_PS3 @@ -1199,7 +1198,14 @@ MODULE_LICENSE ("GPL"); !defined(SA1111_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && \ !defined(SM501_OHCI_DRIVER) && \ - !defined(TMIO_OHCI_DRIVER) + !defined(TMIO_OHCI_DRIVER) && \ + !defined(S3C2410_PLATFORM_DRIVER) && \ + !defined(EXYNOS_PLATFORM_DRIVER) && \ + !defined(EP93XX_PLATFORM_DRIVER) && \ + !defined(AT91_PLATFORM_DRIVER) && \ + !defined(NXP_PLATFORM_DRIVER) && \ + !defined(DAVINCI_PLATFORM_DRIVER) && \ + !defined(SPEAR_PLATFORM_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1277,9 +1283,79 @@ static int __init ohci_hcd_mod_init(void) goto error_tmio; #endif +#ifdef S3C2410_PLATFORM_DRIVER + retval = platform_driver_register(&S3C2410_PLATFORM_DRIVER); + if (retval < 0) + goto error_s3c2410; +#endif + +#ifdef EXYNOS_PLATFORM_DRIVER + retval = platform_driver_register(&EXYNOS_PLATFORM_DRIVER); + if (retval < 0) + goto error_exynos; +#endif + +#ifdef EP93XX_PLATFORM_DRIVER + retval = platform_driver_register(&EP93XX_PLATFORM_DRIVER); + if (retval < 0) + goto error_ep93xx; +#endif + +#ifdef AT91_PLATFORM_DRIVER + retval = platform_driver_register(&AT91_PLATFORM_DRIVER); + if (retval < 0) + goto error_at91; +#endif + +#ifdef NXP_PLATFORM_DRIVER + retval = platform_driver_register(&NXP_PLATFORM_DRIVER); + if (retval < 0) + goto error_nxp; +#endif + +#ifdef DAVINCI_PLATFORM_DRIVER + retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER); + if (retval < 0) + goto error_davinci; +#endif + +#ifdef SPEAR_PLATFORM_DRIVER + retval = platform_driver_register(&SPEAR_PLATFORM_DRIVER); + if (retval < 0) + goto error_spear; +#endif + return retval; /* Error path */ +#ifdef SPEAR_PLATFORM_DRIVER + platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); + error_spear: +#endif +#ifdef DAVINCI_PLATFORM_DRIVER + platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); + error_davinci: +#endif +#ifdef NXP_PLATFORM_DRIVER + platform_driver_unregister(&NXP_PLATFORM_DRIVER); + error_nxp: +#endif +#ifdef AT91_PLATFORM_DRIVER + platform_driver_unregister(&AT91_PLATFORM_DRIVER); + error_at91: +#endif +#ifdef EP93XX_PLATFORM_DRIVER + platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); + error_ep93xx: +#endif +#ifdef EXYNOS_PLATFORM_DRIVER + platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); + error_exynos: +#endif +#ifdef S3C2410_PLATFORM_DRIVER + platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); + error_s3c2410: +#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); error_tmio: @@ -1300,17 +1376,17 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&OF_PLATFORM_DRIVER); error_of_platform: #endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); - error_platform: +#ifdef OMAP3_PLATFORM_DRIVER + platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); + error_omap3_platform: #endif #ifdef OMAP1_PLATFORM_DRIVER platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); error_omap1_platform: #endif -#ifdef OMAP3_PLATFORM_DRIVER - platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); - error_omap3_platform: +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); + error_platform: #endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); @@ -1329,6 +1405,27 @@ module_init(ohci_hcd_mod_init); static void __exit ohci_hcd_mod_exit(void) { +#ifdef SPEAR_PLATFORM_DRIVER + platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); +#endif +#ifdef DAVINCI_PLATFORM_DRIVER + platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER); +#endif +#ifdef NXP_PLATFORM_DRIVER + platform_driver_unregister(&NXP_PLATFORM_DRIVER); +#endif +#ifdef AT91_PLATFORM_DRIVER + platform_driver_unregister(&AT91_PLATFORM_DRIVER); +#endif +#ifdef EP93XX_PLATFORM_DRIVER + platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); +#endif +#ifdef EXYNOS_PLATFORM_DRIVER + platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); +#endif +#ifdef S3C2410_PLATFORM_DRIVER + platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); +#endif #ifdef TMIO_OHCI_DRIVER platform_driver_unregister(&TMIO_OHCI_DRIVER); #endif @@ -1344,12 +1441,15 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef OF_PLATFORM_DRIVER platform_driver_unregister(&OF_PLATFORM_DRIVER); #endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif #ifdef OMAP3_PLATFORM_DRIVER platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); #endif +#ifdef OMAP1_PLATFORM_DRIVER + platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); +#endif +#ifdef PLATFORM_DRIVER + platform_driver_unregister(&PLATFORM_DRIVER); +#endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); #endif diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index db09dae7b557..60ff4220e8b4 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -580,14 +580,8 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) /* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling, * not necessarily continuous ... to guard against resume signaling. - * The short timeout is safe for non-root hubs, and is backward-compatible - * with earlier Linux hosts. */ -#ifdef CONFIG_USB_SUSPEND #define PORT_RESET_MSEC 50 -#else -#define PORT_RESET_MSEC 10 -#endif /* this timer value might be vendor-specific ... */ #define PORT_RESET_HW_MSEC 10 diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index eb35d9630237..ddfc31427bc0 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -31,6 +31,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> /*-------------------------------------------------------------------------*/ @@ -112,6 +114,8 @@ static const struct hc_driver ohci_omap3_hc_driver = { /*-------------------------------------------------------------------------*/ +static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32); + /* * configure so an HC device and id are always provided * always called with process context; sleeping is OK @@ -141,14 +145,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_irq_byname(pdev, "ohci-irq"); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "OHCI irq failed\n"); return -ENODEV; } - res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "ohci"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "UHH OHCI get resource failed\n"); return -ENOMEM; @@ -160,6 +163,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev) return -ENOMEM; } + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &omap_ohci_dma_mask; hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, dev_name(dev)); @@ -229,12 +239,20 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev) hcd->driver->shutdown(hcd); } +static const struct of_device_id omap_ohci_dt_ids[] = { + { .compatible = "ti,ohci-omap3" }, + { } +}; + +MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids); + static struct platform_driver ohci_hcd_omap3_driver = { .probe = ohci_hcd_omap3_probe, .remove = ohci_hcd_omap3_remove, .shutdown = ohci_hcd_omap3_shutdown, .driver = { .name = "ohci-omap3", + .of_match_table = of_match_ptr(omap_ohci_dt_ids), }, }; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d62f0404baaa..15ed7e8d887f 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1755,7 +1755,7 @@ sl811h_probe(struct platform_device *dev) /* for this device there's no useful distinction between the controller * and its root hub, except that the root hub only gets direct PM calls - * when CONFIG_USB_SUSPEND is enabled. + * when CONFIG_PM_RUNTIME is enabled. */ static int diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5efdffe32365..5c124bf5d018 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3141,10 +3141,11 @@ static int u132_probe(struct platform_device *pdev) #ifdef CONFIG_PM -/* for this device there's no useful distinction between the controller -* and its root hub, except that the root hub only gets direct PM calls -* when CONFIG_USB_SUSPEND is enabled. -*/ +/* + * for this device there's no useful distinction between the controller + * and its root hub, except that the root hub only gets direct PM calls + * when CONFIG_PM_RUNTIME is enabled. + */ static int u132_suspend(struct platform_device *pdev, pm_message_t state) { struct usb_hcd *hcd = platform_get_drvdata(pdev); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 68914429482f..187a3ec1069a 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1075,7 +1075,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) set_bit(port_index, &bus_state->bus_suspended); } /* USB core sets remote wake mask for USB 3.0 hubs, - * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND + * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME * is enabled, so also enable remote wake here. */ if (hcd->self.root_hub->do_remote_wakeup) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 6dc238c592bc..965b539bc474 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -51,7 +51,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, return NULL; } - memset(seg->trbs, 0, SEGMENT_SIZE); + memset(seg->trbs, 0, TRB_SEGMENT_SIZE); /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ if (cycle_state == 0) { for (i = 0; i < TRBS_PER_SEGMENT; i++) @@ -467,7 +467,7 @@ struct xhci_ring *xhci_dma_to_transfer_ring( { if (ep->ep_state & EP_HAS_STREAMS) return radix_tree_lookup(&ep->stream_info->trb_address_map, - address >> SEGMENT_SHIFT); + address >> TRB_SEGMENT_SHIFT); return ep->ring; } @@ -478,7 +478,7 @@ static struct xhci_ring *dma_to_stream_ring( u64 address) { return radix_tree_lookup(&stream_info->trb_address_map, - address >> SEGMENT_SHIFT); + address >> TRB_SEGMENT_SHIFT); } #endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ @@ -514,7 +514,7 @@ static int xhci_test_radix_tree(struct xhci_hcd *xhci, cur_ring = stream_info->stream_rings[cur_stream]; for (addr = cur_ring->first_seg->dma; - addr < cur_ring->first_seg->dma + SEGMENT_SIZE; + addr < cur_ring->first_seg->dma + TRB_SEGMENT_SIZE; addr += trb_size) { mapped_ring = dma_to_stream_ring(stream_info, addr); if (cur_ring != mapped_ring) { @@ -662,7 +662,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_stream, (unsigned long long) addr); key = (unsigned long) - (cur_ring->first_seg->dma >> SEGMENT_SHIFT); + (cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT); ret = radix_tree_insert(&stream_info->trb_address_map, key, cur_ring); if (ret) { @@ -693,7 +693,7 @@ cleanup_rings: if (cur_ring) { addr = cur_ring->first_seg->dma; radix_tree_delete(&stream_info->trb_address_map, - addr >> SEGMENT_SHIFT); + addr >> TRB_SEGMENT_SHIFT); xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; } @@ -764,7 +764,7 @@ void xhci_free_stream_info(struct xhci_hcd *xhci, if (cur_ring) { addr = cur_ring->first_seg->dma; radix_tree_delete(&stream_info->trb_address_map, - addr >> SEGMENT_SHIFT); + addr >> TRB_SEGMENT_SHIFT); xhci_ring_free(xhci, cur_ring); stream_info->stream_rings[cur_stream] = NULL; } @@ -2305,7 +2305,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * so we pick the greater alignment need. */ xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, - SEGMENT_SIZE, 64, xhci->page_size); + TRB_SEGMENT_SIZE, 64, xhci->page_size); /* See Table 46 and Note on Figure 55 */ xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 53b8f89a0b1c..b4aa79d154b2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -417,9 +417,9 @@ static void compliance_mode_recovery(unsigned long arg) * Compliance Mode Detected. Letting USB Core * handle the Warm Reset */ - xhci_dbg(xhci, "Compliance Mode Detected->Port %d!\n", + xhci_dbg(xhci, "Compliance mode detected->port %d\n", i + 1); - xhci_dbg(xhci, "Attempting Recovery routine!\n"); + xhci_dbg(xhci, "Attempting compliance mode recovery\n"); hcd = xhci->shared_hcd; if (hcd->state == HC_STATE_SUSPENDED) @@ -457,7 +457,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci) set_timer_slack(&xhci->comp_mode_recovery_timer, msecs_to_jiffies(COMP_MODE_RCVRY_MSECS)); add_timer(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "Compliance Mode Recovery Timer Initialized.\n"); + xhci_dbg(xhci, "Compliance mode recovery timer initialized\n"); } /* @@ -733,8 +733,11 @@ void xhci_stop(struct usb_hcd *hcd) /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && - (!(xhci_all_ports_seen_u0(xhci)))) + (!(xhci_all_ports_seen_u0(xhci)))) { del_timer_sync(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n", + __func__); + } if (xhci->quirks & XHCI_AMD_PLL_FIX) usb_amd_dev_put(); @@ -930,7 +933,8 @@ int xhci_suspend(struct xhci_hcd *xhci) if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { del_timer_sync(&xhci->comp_mode_recovery_timer); - xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n"); + xhci_dbg(xhci, "%s: compliance mode recovery timer deleted\n", + __func__); } /* step 5: remove core well power */ @@ -3801,7 +3805,7 @@ int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) return raw_port; } -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME /* BESL to HIRD Encoding array for USB2 LPM */ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, @@ -4051,7 +4055,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) return 0; } -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */ /*---------------------- USB 3.0 Link PM functions ------------------------*/ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 63582719e0fb..29c978e37135 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1238,8 +1238,8 @@ union xhci_trb { #define TRBS_PER_SEGMENT 64 /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) -#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) -#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE)) +#define TRB_SEGMENT_SIZE (TRBS_PER_SEGMENT*16) +#define TRB_SEGMENT_SHIFT (ilog2(TRB_SEGMENT_SIZE)) /* TRB buffer pointers can't cross 64KB boundaries */ #define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig index 33350f9dd34f..320d368c8dac 100644 --- a/drivers/usb/image/Kconfig +++ b/drivers/usb/image/Kconfig @@ -2,11 +2,9 @@ # USB Imaging devices configuration # comment "USB Imaging devices" - depends on USB config USB_MDC800 tristate "USB Mustek MDC800 Digital Camera support" - depends on USB ---help--- Say Y here if you want to connect this type of still camera to your computer's USB port. This driver can be used with gphoto 0.4.3 @@ -19,7 +17,7 @@ config USB_MDC800 config USB_MICROTEK tristate "Microtek X6USB scanner support" - depends on USB && SCSI + depends on SCSI help Say Y here if you want support for the Microtek X6USB and possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L. diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 3b1a3f4ec5e9..a51e7d6afda9 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -2,11 +2,9 @@ # USB Miscellaneous driver configuration # comment "USB Miscellaneous drivers" - depends on USB config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" - depends on USB ---help--- This driver loads firmware to Emagic EMI 6|2m low latency USB Audio and Midi interface. @@ -21,7 +19,6 @@ config USB_EMI62 config USB_EMI26 tristate "EMI 2|6 USB Audio interface support" - depends on USB ---help--- This driver loads firmware to Emagic EMI 2|6 low latency USB Audio interface. @@ -34,7 +31,6 @@ config USB_EMI26 config USB_ADUTUX tristate "ADU devices from Ontrak Control Systems" - depends on USB help Say Y if you want to use an ADU device from Ontrak Control Systems. @@ -44,7 +40,6 @@ config USB_ADUTUX config USB_SEVSEG tristate "USB 7-Segment LED Display" - depends on USB help Say Y here if you have a USB 7-Segment Display by Delcom @@ -53,7 +48,6 @@ config USB_SEVSEG config USB_RIO500 tristate "USB Diamond Rio500 support" - depends on USB help Say Y here if you want to connect a USB Rio500 mp3 player to your computer's USB port. Please read <file:Documentation/usb/rio.txt> @@ -64,7 +58,6 @@ config USB_RIO500 config USB_LEGOTOWER tristate "USB Lego Infrared Tower support" - depends on USB help Say Y here if you want to connect a USB Lego Infrared Tower to your computer's USB port. @@ -77,7 +70,6 @@ config USB_LEGOTOWER config USB_LCD tristate "USB LCD driver support" - depends on USB help Say Y here if you want to connect an USBLCD to your computer's USB port. The USBLCD is a small USB interface board for @@ -89,7 +81,6 @@ config USB_LCD config USB_LED tristate "USB LED driver support" - depends on USB help Say Y here if you want to connect an USBLED device to your computer's USB port. @@ -99,7 +90,6 @@ config USB_LED config USB_CYPRESS_CY7C63 tristate "Cypress CY7C63xxx USB driver support" - depends on USB help Say Y here if you want to connect a Cypress CY7C63xxx micro controller to your computer's USB port. Currently this @@ -113,7 +103,6 @@ config USB_CYPRESS_CY7C63 config USB_CYTHERM tristate "Cypress USB thermometer driver support" - depends on USB help Say Y here if you want to connect a Cypress USB thermometer device to your computer's USB port. This device is also known @@ -126,7 +115,6 @@ config USB_CYTHERM config USB_IDMOUSE tristate "Siemens ID USB Mouse Fingerprint sensor support" - depends on USB help Say Y here if you want to use the fingerprint sensor on the Siemens ID Mouse. There is also a Siemens ID Mouse @@ -140,7 +128,6 @@ config USB_IDMOUSE config USB_FTDI_ELAN tristate "Elan PCMCIA CardBus Adapter USB Client" - depends on USB default M help ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. @@ -164,7 +151,6 @@ config USB_FTDI_ELAN config USB_APPLEDISPLAY tristate "Apple Cinema Display support" - depends on USB select BACKLIGHT_LCD_SUPPORT select BACKLIGHT_CLASS_DEVICE help @@ -175,7 +161,6 @@ source "drivers/usb/misc/sisusbvga/Kconfig" config USB_LD tristate "USB LD driver" - depends on USB help This driver is for generic USB devices that use interrupt transfers, like LD Didactic's USB devices. @@ -185,7 +170,6 @@ config USB_LD config USB_TRANCEVIBRATOR tristate "PlayStation 2 Trance Vibrator driver support" - depends on USB help Say Y here if you want to connect a PlayStation 2 Trance Vibrator device to your computer's USB port. @@ -195,7 +179,6 @@ config USB_TRANCEVIBRATOR config USB_IOWARRIOR tristate "IO Warrior driver support" - depends on USB help Say Y here if you want to support the IO Warrior devices from Code Mercenaries. This includes support for the following devices: @@ -209,7 +192,6 @@ config USB_IOWARRIOR config USB_TEST tristate "USB testing driver" - depends on USB help This driver is for testing host controller software. It is used with specialized device firmware for regression and stress testing, @@ -220,7 +202,6 @@ config USB_TEST config USB_ISIGHTFW tristate "iSight firmware loading support" - depends on USB select FW_LOADER help This driver loads firmware for USB Apple iSight cameras, allowing @@ -233,7 +214,6 @@ config USB_ISIGHTFW config USB_YUREX tristate "USB YUREX driver support" - depends on USB help Say Y here if you want to connect a YUREX to your computer's USB port. The YUREX is a leg-shakes sensor. See @@ -246,7 +226,6 @@ config USB_YUREX config USB_EZUSB_FX2 tristate "Functions for loading firmware on EZUSB chips" - depends on USB help Say Y here if you need EZUSB device support. (Cypress FX/FX2/FX2LP microcontrollers) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 0fc6e5fc745f..ba6a5d6e618e 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -63,6 +63,7 @@ static const struct usb_device_id appledisplay_table[] = { { APPLEDISPLAY_DEVICE(0x9219) }, { APPLEDISPLAY_DEVICE(0x921c) }, { APPLEDISPLAY_DEVICE(0x921d) }, + { APPLEDISPLAY_DEVICE(0x9236) }, /* Terminating entry */ { } diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 30ea7ca6846e..0d03a5200482 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -1,7 +1,7 @@ config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" - depends on USB && (USB_MUSB_HDRC || USB_EHCI_HCD) + depends on (USB_MUSB_HDRC || USB_EHCI_HCD) ---help--- Say Y here if you intend to attach a USB2VGA dongle based on a Net2280 and a SiS315 chip. diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index dd573abd2d1e..c21386ec5d35 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3084,7 +3084,7 @@ static int sisusb_probe(struct usb_interface *intf, /* Allocate memory for our private */ if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); + dev_err(&dev->dev, "Failed to allocate memory for private data\n"); return -ENOMEM; } kref_init(&sisusb->kref); diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f713f6aeb6e5..d3a1cce1bf9c 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -307,18 +307,7 @@ static struct i2c_driver usb3503_driver = { .id_table = usb3503_id, }; -static int __init usb3503_init(void) -{ - return i2c_add_driver(&usb3503_driver); -} - -static void __exit usb3503_exit(void) -{ - i2c_del_driver(&usb3503_driver); -} - -module_init(usb3503_init); -module_exit(usb3503_exit); +module_i2c_driver(usb3503_driver); MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>"); MODULE_DESCRIPTION("USB3503 USB HUB driver"); diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig index 635745f57fbd..5c6ffa2a612e 100644 --- a/drivers/usb/mon/Kconfig +++ b/drivers/usb/mon/Kconfig @@ -4,7 +4,6 @@ config USB_MON tristate "USB Monitor" - depends on USB help If you select this option, a component which captures the USB traffic between peripheral-specific drivers and HC drivers will be built. diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 05e51432dd2f..06f8d29af1ef 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -6,8 +6,7 @@ # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller config USB_MUSB_HDRC tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' - depends on USB && USB_GADGET - select USB_OTG_UTILS + depends on USB_GADGET help Say Y here if your system has a dual role high speed USB controller based on the Mentor Graphics silicon IP. Then @@ -34,10 +33,12 @@ choice config USB_MUSB_DAVINCI tristate "DaVinci" depends on ARCH_DAVINCI_DMx + depends on BROKEN config USB_MUSB_DA8XX tristate "DA8xx/OMAP-L1x" depends on ARCH_DAVINCI_DA8XX + depends on BROKEN config USB_MUSB_TUSB6010 tristate "TUSB6010" @@ -53,7 +54,6 @@ config USB_MUSB_AM35X config USB_MUSB_DSPS tristate "TI DSPS platforms" - depends on SOC_TI81XX || SOC_AM33XX config USB_MUSB_BLACKFIN tristate "Blackfin" @@ -61,12 +61,12 @@ config USB_MUSB_BLACKFIN config USB_MUSB_UX500 tristate "U8500 and U5500" - depends on (ARCH_U8500 && AB8500_USB) endchoice choice prompt 'MUSB DMA mode' + default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM default USB_UX500_DMA if USB_MUSB_UX500 default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 59eea219034a..2231850c0625 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -149,7 +149,7 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { @@ -195,7 +195,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->is_active || (musb->a_wait_bcon == 0 && musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); del_timer(&otg_workaround); last_timer = jiffies; return; @@ -208,7 +208,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&otg_workaround, timeout); } @@ -298,7 +298,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci) /* NOTE: this must complete power-on within 100 ms. */ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index dbb31b30c7fa..5e63b160db0c 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -280,13 +280,13 @@ static void musb_conn_timer_handler(unsigned long _musb) break; default: dev_dbg(musb->controller, "%s state not handled\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); break; } spin_unlock_irqrestore(&musb->lock, flags); dev_dbg(musb->controller, "state is %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } static void bfin_musb_enable(struct musb *musb) @@ -307,7 +307,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on) dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index f522000e8f06..9db211ee15b5 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -435,7 +435,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx, } } -#ifdef CONFIG_USB_MUSB_DEBUG static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) { pr_debug("RXBD/%s %08x: " @@ -444,21 +443,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_options); } -#endif static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx) { -#ifdef CONFIG_USB_MUSB_DEBUG struct cppi_descriptor *bd; - if (!_dbg_level(level)) - return; cppi_dump_rx(level, rx, tag); if (rx->last_processed) cppi_dump_rxbd("last", rx->last_processed); for (bd = rx->head; bd; bd = bd->next) cppi_dump_rxbd("active", bd); -#endif } @@ -784,6 +778,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) void __iomem *tibase = musb->ctrl_base; int is_rndis = 0; struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram; + struct cppi_descriptor *d; if (onepacket) { /* almost every USB driver, host or peripheral side */ @@ -897,14 +892,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) bd->hw_options |= CPPI_SOP_SET; tail->hw_options |= CPPI_EOP_SET; -#ifdef CONFIG_USB_MUSB_DEBUG - if (_dbg_level(5)) { - struct cppi_descriptor *d; - - for (d = rx->head; d; d = d->next) - cppi_dump_rxbd("S", d); - } -#endif + for (d = rx->head; d; d = d->next) + cppi_dump_rxbd("S", d); /* in case the preceding transfer left some state... */ tail = rx->last_processed; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 41613a2b35e8..b903b744a224 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -198,7 +198,7 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { @@ -267,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->is_active || (musb->a_wait_bcon == 0 && musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); del_timer(&otg_workaround); last_timer = jiffies; return; @@ -280,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&otg_workaround, timeout); } @@ -360,7 +360,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index e040d9103735..bea6cc35471c 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb) */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { @@ -349,7 +349,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) davinci_musb_source_power(musb, drvvbus, 0); dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), err ? " ERROR" : "", devctl); retval = IRQ_HANDLED; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index daec6e0f7e38..37a261a6bb6a 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -372,13 +372,13 @@ static void musb_otg_timer_func(unsigned long data) case OTG_STATE_A_SUSPEND: case OTG_STATE_A_WAIT_BCON: dev_dbg(musb->controller, "HNP: %s timeout\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); musb_platform_set_vbus(musb, 0); musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; break; default: dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } musb->ignore_disconnect = 0; spin_unlock_irqrestore(&musb->lock, flags); @@ -393,13 +393,14 @@ void musb_hnp_stop(struct musb *musb) void __iomem *mbase = musb->mregs; u8 reg; - dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state)); + dev_dbg(musb->controller, "HNP: stop from %s\n", + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { case OTG_STATE_A_PERIPHERAL: musb_g_disconnect(musb); dev_dbg(musb->controller, "HNP: back to %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); break; case OTG_STATE_B_HOST: dev_dbg(musb->controller, "HNP: Disabling HR\n"); @@ -413,7 +414,7 @@ void musb_hnp_stop(struct musb *musb) break; default: dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } /* @@ -451,7 +452,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, */ if (int_usb & MUSB_INTR_RESUME) { handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state)); + dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state)); if (devctl & MUSB_DEVCTL_HM) { void __iomem *mbase = musb->mregs; @@ -493,7 +494,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "host", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } else { switch (musb->xceiv->state) { @@ -522,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, default: WARNING("bogus %s RESUME (%s)\n", "peripheral", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } } @@ -538,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, } dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); /* IRQ arrives from ID pin sense or (later, if VBUS power * is removed) SRP. responses are time critical: @@ -602,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; } - dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - otg_state_string(musb->xceiv->state), + dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, + "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", + usb_otg_state_string(musb->xceiv->state), devctl, ({ char *s; switch (devctl & MUSB_DEVCTL_VBUS) { @@ -628,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (int_usb & MUSB_INTR_SUSPEND) { dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n", - otg_state_string(musb->xceiv->state), devctl); + usb_otg_state_string(musb->xceiv->state), devctl); handled = IRQ_HANDLED; switch (musb->xceiv->state) { @@ -745,12 +747,12 @@ b_host: usb_hcd_resume_root_hub(hcd); dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", - otg_state_string(musb->xceiv->state), devctl); + usb_otg_state_string(musb->xceiv->state), devctl); } if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), MUSB_MODE(musb), devctl); handled = IRQ_HANDLED; @@ -787,7 +789,7 @@ b_host: break; default: WARNING("unhandled DISCONNECT transition (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); break; } } @@ -813,7 +815,7 @@ b_host: } } else { dev_dbg(musb->controller, "BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); switch (musb->xceiv->state) { case OTG_STATE_A_SUSPEND: /* We need to ignore disconnect on suspend @@ -826,7 +828,7 @@ b_host: case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ /* never use invalid T(a_wait_bcon) */ dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), TA_WAIT_BCON(musb)); mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(TA_WAIT_BCON(musb))); @@ -838,7 +840,7 @@ b_host: break; case OTG_STATE_B_WAIT_ACON: dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb_g_reset(musb); break; @@ -850,7 +852,7 @@ b_host: break; default: dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } } @@ -1632,7 +1634,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) int ret = -EINVAL; spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state)); + ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state)); spin_unlock_irqrestore(&musb->lock, flags); return ret; @@ -1951,9 +1953,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_write_ulpi_buscontrol(musb->mregs, busctl); } - MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + if (musb->xceiv->otg->default_a) { + MUSB_HST_MODE(musb); + musb->xceiv->state = OTG_STATE_A_IDLE; + } else { + MUSB_DEV_MODE(musb); + musb->xceiv->state = OTG_STATE_B_IDLE; + } status = musb_gadget_setup(musb); @@ -2008,7 +2014,6 @@ static int musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq = platform_get_irq_byname(pdev, "mc"); - int status; struct resource *iomem; void __iomem *base; @@ -2016,24 +2021,17 @@ static int musb_probe(struct platform_device *pdev) if (!iomem || irq <= 0) return -ENODEV; - base = ioremap(iomem->start, resource_size(iomem)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } + base = devm_ioremap_resource(dev, iomem); + if (IS_ERR(base)) + return PTR_ERR(base); - status = musb_init_controller(dev, irq, base); - if (status < 0) - iounmap(base); - - return status; + return musb_init_controller(dev, irq, base); } static int musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); - void __iomem *ctrl_base = musb->ctrl_base; /* this gets called on rmmod. * - Host mode: host may still be active @@ -2044,7 +2042,6 @@ static int musb_remove(struct platform_device *pdev) musb_shutdown(pdev); musb_free(musb); - iounmap(ctrl_base); device_init_wakeup(dev, 0); #ifndef CONFIG_MUSB_PIO_ONLY dma_set_mask(dev, *dev->parent->dma_mask); @@ -2293,8 +2290,6 @@ static int __init musb_init(void) if (usb_disabled()) return 0; - pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", - musb_driver_name); return platform_driver_register(&musb_driver); } module_init(musb_init); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 6bb89715b637..3a18e44e9391 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -38,6 +38,7 @@ #include <linux/module.h> #include <linux/usb/nop-usb-xceiv.h> #include <linux/platform_data/usb-omap.h> +#include <linux/sizes.h> #include <linux/of.h> #include <linux/of_device.h> @@ -224,7 +225,7 @@ static void otg_timer(unsigned long _musb) */ devctl = dsps_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { @@ -273,7 +274,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->is_active || (musb->a_wait_bcon == 0 && musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); del_timer(&glue->timer[pdev->id]); glue->last_timer[pdev->id] = jiffies; return; @@ -288,7 +289,7 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) glue->last_timer[pdev->id] = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), jiffies_to_msecs(timeout - jiffies)); mod_timer(&glue->timer[pdev->id], timeout); } @@ -334,7 +335,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ - if (usbintr & MUSB_INTR_BABBLE) + if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { @@ -377,7 +378,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* NOTE: this must complete power-on within 100 ms. */ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; @@ -596,14 +597,13 @@ err0: static int dsps_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; const struct of_device_id *match; const struct dsps_musb_wrapper *wrp; struct dsps_glue *glue; struct resource *iomem; int ret, i; - match = of_match_node(musb_dsps_of_match, np); + match = of_match_node(musb_dsps_of_match, pdev->dev.of_node); if (!match) { dev_err(&pdev->dev, "fail to get matching of_match struct\n"); ret = -EINVAL; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 83eddedcd9be..ba7092349fa9 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -46,48 +46,6 @@ #include "musb_core.h" -/* MUSB PERIPHERAL status 3-mar-2006: - * - * - EP0 seems solid. It passes both USBCV and usbtest control cases. - * Minor glitches: - * - * + remote wakeup to Linux hosts work, but saw USBCV failures; - * in one test run (operator error?) - * + endpoint halt tests -- in both usbtest and usbcv -- seem - * to break when dma is enabled ... is something wrongly - * clearing SENDSTALL? - * - * - Mass storage behaved ok when last tested. Network traffic patterns - * (with lots of short transfers etc) need retesting; they turn up the - * worst cases of the DMA, since short packets are typical but are not - * required. - * - * - TX/IN - * + both pio and dma behave in with network and g_zero tests - * + no cppi throughput issues other than no-hw-queueing - * + failed with FLAT_REG (DaVinci) - * + seems to behave with double buffering, PIO -and- CPPI - * + with gadgetfs + AIO, requests got lost? - * - * - RX/OUT - * + both pio and dma behave in with network and g_zero tests - * + dma is slow in typical case (short_not_ok is clear) - * + double buffering ok with PIO - * + double buffering *FAILS* with CPPI, wrong data bytes sometimes - * + request lossage observed with gadgetfs - * - * - ISO not tested ... might work, but only weakly isochronous - * - * - Gadget driver disabling of softconnect during bind() is ignored; so - * drivers can't hold off host requests until userspace is ready. - * (Workaround: they can turn it off later.) - * - * - PORTABILITY (assumes PIO works): - * + DaVinci, basically works with cppi dma - * + OMAP 2430, ditto with mentor dma - * + TUSB 6010, platform-specific dma in the works - */ - /* ----------------------------------------------------------------------- */ #define is_buffer_mapped(req) (is_dma_capable() && \ @@ -280,41 +238,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep) return ep->packet_sz; } - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral tx (IN) using Mentor DMA works as follows: - Only mode 0 is used for transfers <= wPktSize, - mode 1 is used for larger transfers, - - One of the following happens: - - Host sends IN token which causes an endpoint interrupt - -> TxAvail - -> if DMA is currently busy, exit. - -> if queue is non-empty, txstate(). - - - Request is queued by the gadget driver. - -> if queue was previously empty, txstate() - - txstate() - -> start - /\ -> setup DMA - | (data is transferred to the FIFO, then sent out when - | IN token(s) are recd from Host. - | -> DMA interrupt on completion - | calls TxAvail. - | -> stop DMA, ~DMAENAB, - | -> set TxPktRdy for last short pkt or zlp - | -> Complete Request - | -> Continue next request (call txstate) - |___________________________________| - - * Non-Mentor DMA engines can of course work differently, such as by - * upleveling from irq-per-packet to irq-per-buffer. - */ - -#endif - /* * An endpoint is transmitting data. This can be called either from * the IRQ routine or from ep.queue() to kickstart a request on an @@ -621,37 +544,6 @@ void musb_g_tx(struct musb *musb, u8 epnum) /* ------------------------------------------------------------ */ -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral rx (OUT) using Mentor DMA works as follows: - - Only mode 0 is used. - - - Request is queued by the gadget class driver. - -> if queue was previously empty, rxstate() - - - Host sends OUT token which causes an endpoint interrupt - /\ -> RxReady - | -> if request queued, call rxstate - | /\ -> setup DMA - | | -> DMA interrupt on completion - | | -> RxReady - | | -> stop DMA - | | -> ack the read - | | -> if data recd = max expected - | | by the request, or host - | | sent a short packet, - | | complete the request, - | | and start the next one. - | |_____________________________________| - | else just wait for the host - | to send the next OUT token. - |__________________________________________________| - - * Non-Mentor DMA engines can of course work differently. - */ - -#endif - /* * Context: controller locked, IRQs blocked, endpoint selected */ @@ -740,7 +632,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; - int transfer_size; + unsigned int transfer_size; c = musb->dma_controller; channel = musb_ep->dma; @@ -782,10 +674,11 @@ static void rxstate(struct musb *musb, struct musb_request *req) csr | MUSB_RXCSR_DMAMODE); musb_writew(epio, MUSB_RXCSR, csr); - transfer_size = min(request->length - request->actual, + transfer_size = min_t(unsigned int, + request->length - + request->actual, channel->max_len); musb_ep->dma->desired_mode = 1; - } else { if (!musb_ep->hb_mult && musb_ep->hw_ep->rx_double_buffered) @@ -815,7 +708,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) struct dma_controller *c; struct dma_channel *channel; - int transfer_size = 0; + unsigned int transfer_size = 0; c = musb->dma_controller; channel = musb_ep->dma; @@ -824,11 +717,13 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (fifo_count < musb_ep->packet_sz) transfer_size = fifo_count; else if (request->short_not_ok) - transfer_size = min(request->length - + transfer_size = min_t(unsigned int, + request->length - request->actual, channel->max_len); else - transfer_size = min(request->length - + transfer_size = min_t(unsigned int, + request->length - request->actual, (unsigned)fifo_count); @@ -1681,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) goto done; default: dev_dbg(musb->controller, "Unhandled wake: %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); goto done; } @@ -1801,13 +1696,6 @@ static const struct usb_gadget_ops musb_gadget_operations = { * all peripheral ports are external... */ -static void musb_gadget_release(struct device *dev) -{ - /* kref_put(WHAT) */ - dev_dbg(dev, "%s\n", __func__); -} - - static void init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) { @@ -1892,12 +1780,7 @@ int musb_gadget_setup(struct musb *musb) musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ - dev_set_name(&musb->g.dev, "gadget"); - musb->g.dev.parent = musb->controller; - musb->g.dev.dma_mask = musb->controller->dma_mask; - musb->g.dev.release = musb_gadget_release; musb->g.name = musb_driver_name; - musb->g.is_otg = 1; musb_g_init_endpoints(musb); @@ -1905,11 +1788,6 @@ int musb_gadget_setup(struct musb *musb) musb->is_active = 0; musb_platform_try_idle(musb, 0); - status = device_register(&musb->g.dev); - if (status != 0) { - put_device(&musb->g.dev); - return status; - } status = usb_add_gadget_udc(musb->controller, &musb->g); if (status) goto err; @@ -1924,8 +1802,6 @@ err: void musb_gadget_cleanup(struct musb *musb) { usb_del_gadget_udc(&musb->g); - if (musb->g.dev.parent) - device_unregister(&musb->g.dev); } /* @@ -1977,9 +1853,8 @@ static int musb_gadget_start(struct usb_gadget *g, goto err; } - if ((musb->xceiv->last_event == USB_EVENT_ID) - && otg->set_vbus) - otg_set_vbus(otg, 1); + if (musb->xceiv->last_event == USB_EVENT_ID) + musb_platform_set_vbus(musb, 1); hcd->self.uses_pio_for_control = 1; @@ -2063,6 +1938,7 @@ static int musb_gadget_stop(struct usb_gadget *g, dev_dbg(musb->controller, "unregistering driver %s\n", driver->function); musb->is_active = 0; + musb->gadget_driver = NULL; musb_platform_try_idle(musb, 0); spin_unlock_irqrestore(&musb->lock, flags); @@ -2099,7 +1975,7 @@ void musb_g_resume(struct musb *musb) break; default: WARNING("unhandled RESUME transition (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } @@ -2129,7 +2005,7 @@ void musb_g_suspend(struct musb *musb) * A_PERIPHERAL may need care too */ WARNING("unhandled SUSPEND transition (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } @@ -2163,7 +2039,7 @@ void musb_g_disconnect(struct musb *musb) switch (musb->xceiv->state) { default: dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); break; diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index c9c1ac4e075f..2af45a0c8930 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -505,8 +505,10 @@ static void ep0_rxstate(struct musb *musb) req->status = -EOVERFLOW; count = len; } - musb_read_fifo(&musb->endpoints[0], count, buf); - req->actual += count; + if (count > 0) { + musb_read_fifo(&musb->endpoints[0], count, buf); + req->actual += count; + } csr = MUSB_CSR0_P_SVDRXPKTRDY; if (count < 64 || req->actual == req->length) { musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 1ce1fcf3f3e7..8914dec49f01 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2453,7 +2453,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd) if (musb->is_active) { WARNING("trying to suspend as %s while active\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); return -EBUSY; } else return 0; @@ -2465,6 +2465,118 @@ static int musb_bus_resume(struct usb_hcd *hcd) return 0; } + +#ifndef CONFIG_MUSB_PIO_ONLY + +#define MUSB_USB_DMA_ALIGN 4 + +struct musb_temp_buffer { + void *kmalloc_ptr; + void *old_xfer_buffer; + u8 data[0]; +}; + +static void musb_free_temp_buffer(struct urb *urb) +{ + enum dma_data_direction dir; + struct musb_temp_buffer *temp; + + if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) + return; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + temp = container_of(urb->transfer_buffer, struct musb_temp_buffer, + data); + + if (dir == DMA_FROM_DEVICE) { + memcpy(temp->old_xfer_buffer, temp->data, + urb->transfer_buffer_length); + } + urb->transfer_buffer = temp->old_xfer_buffer; + kfree(temp->kmalloc_ptr); + + urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; +} + +static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +{ + enum dma_data_direction dir; + struct musb_temp_buffer *temp; + void *kmalloc_ptr; + size_t kmalloc_size; + + if (urb->num_sgs || urb->sg || + urb->transfer_buffer_length == 0 || + !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1))) + return 0; + + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + /* Allocate a buffer with enough padding for alignment */ + kmalloc_size = urb->transfer_buffer_length + + sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1; + + kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); + if (!kmalloc_ptr) + return -ENOMEM; + + /* Position our struct temp_buffer such that data is aligned */ + temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN); + + + temp->kmalloc_ptr = kmalloc_ptr; + temp->old_xfer_buffer = urb->transfer_buffer; + if (dir == DMA_TO_DEVICE) + memcpy(temp->data, urb->transfer_buffer, + urb->transfer_buffer_length); + urb->transfer_buffer = temp->data; + + urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; + + return 0; +} + +static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + struct musb *musb = hcd_to_musb(hcd); + int ret; + + /* + * The DMA engine in RTL1.8 and above cannot handle + * DMA addresses that are not aligned to a 4 byte boundary. + * For such engine implemented (un)map_urb_for_dma hooks. + * Do not use these hooks for RTL<1.8 + */ + if (musb->hwvers < MUSB_HWVERS_1800) + return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + + ret = musb_alloc_temp_buffer(urb, mem_flags); + if (ret) + return ret; + + ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); + if (ret) + musb_free_temp_buffer(urb); + + return ret; +} + +static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ + struct musb *musb = hcd_to_musb(hcd); + + usb_hcd_unmap_urb_for_dma(hcd, urb); + + /* Do not use this hook for RTL<1.8 (see description above) */ + if (musb->hwvers < MUSB_HWVERS_1800) + return; + + musb_free_temp_buffer(urb); +} +#endif /* !CONFIG_MUSB_PIO_ONLY */ + const struct hc_driver musb_hc_driver = { .description = "musb-hcd", .product_desc = "MUSB HDRC host driver", @@ -2484,6 +2596,11 @@ const struct hc_driver musb_hc_driver = { .urb_dequeue = musb_urb_dequeue, .endpoint_disable = musb_h_disable, +#ifndef CONFIG_MUSB_PIO_ONLY + .map_urb_for_dma = musb_map_urb_for_dma, + .unmap_urb_for_dma = musb_unmap_urb_for_dma, +#endif + .hub_status_data = musb_hub_status_data, .hub_control = musb_hub_control, .bus_suspend = musb_bus_suspend, diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index f70579154ded..ef7d11045f56 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -95,7 +95,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend) break; default: dev_dbg(musb->controller, "bogus rh suspend? %s\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } else if (power & MUSB_POWER_SUSPENDM) { power &= ~MUSB_POWER_SUSPENDM; @@ -203,7 +203,7 @@ void musb_root_disconnect(struct musb *musb) break; default: dev_dbg(musb->controller, "host disconnect (%s)\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 1a42a458f2c4..3551f1a30c65 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -117,7 +117,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->is_active || ((musb->a_wait_bcon == 0) && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); del_timer(&musb_idle_timer); last_timer = jiffies; return; @@ -134,7 +134,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(&musb_idle_timer, timeout); } @@ -174,8 +174,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) } } - if (otg->set_vbus) - otg_set_vbus(otg, 1); + otg_set_vbus(otg, 1); } else { musb->is_active = 1; otg->default_a = 1; @@ -200,7 +199,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on) dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), musb_readb(musb->mregs, MUSB_DEVCTL)); } @@ -292,14 +291,14 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) musb->xceiv->last_event = USB_EVENT_NONE; if (musb->gadget_driver) { + omap2430_musb_set_vbus(musb, 0); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } - if (data->interface_type == MUSB_INTERFACE_UTMI) { - if (musb->xceiv->otg->set_vbus) - otg_set_vbus(musb->xceiv->otg, 0); - } + if (data->interface_type == MUSB_INTERFACE_UTMI) + otg_set_vbus(musb->xceiv->otg, 0); + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DISCONNECT); break; @@ -355,7 +354,12 @@ static int omap2430_musb_init(struct musb *musb) else musb->xceiv = devm_usb_get_phy_dev(dev, 0); - if (IS_ERR_OR_NULL(musb->xceiv)) { + if (IS_ERR(musb->xceiv)) { + status = PTR_ERR(musb->xceiv); + + if (status == -ENXIO) + return status; + pr_err("HS USB OTG: no transceiver configured\n"); return -EPROBE_DEFER; } @@ -393,6 +397,8 @@ static int omap2430_musb_init(struct musb *musb) if (glue->status != OMAP_MUSB_UNKNOWN) omap_musb_set_mailbox(glue); + usb_phy_init(musb->xceiv); + pm_runtime_put_noidle(musb->controller); return 0; @@ -526,10 +532,10 @@ static int omap2430_probe(struct platform_device *pdev) } of_property_read_u32(np, "mode", (u32 *)&pdata->mode); - of_property_read_u32(np, "interface_type", + of_property_read_u32(np, "interface-type", (u32 *)&data->interface_type); - of_property_read_u32(np, "num_eps", (u32 *)&config->num_eps); - of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); + of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps); + of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits); of_property_read_u32(np, "power", (u32 *)&pdata->power); config->multipoint = of_property_read_bool(np, "multipoint"); pdata->has_mailbox = of_property_read_bool(np, diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 464bd23cccda..7369ba33c94f 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -423,7 +423,7 @@ static void musb_do_idle(unsigned long _musb) && (musb->idle_timeout == 0 || time_after(jiffies, musb->idle_timeout))) { dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); } /* FALLTHROUGH */ case OTG_STATE_A_IDLE: @@ -478,7 +478,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout) if (musb->is_active || ((musb->a_wait_bcon == 0) && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) { dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); + usb_otg_state_string(musb->xceiv->state)); del_timer(&musb_idle_timer); last_timer = jiffies; return; @@ -495,7 +495,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout) last_timer = timeout; dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), (unsigned long)jiffies_to_msecs(timeout - jiffies)); mod_timer(&musb_idle_timer, timeout); } @@ -571,7 +571,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on) musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n", - otg_state_string(musb->xceiv->state), + usb_otg_state_string(musb->xceiv->state), musb_readb(musb->mregs, MUSB_DEVCTL), musb_readl(tbase, TUSB_DEV_OTG_STAT), conf, prcm); @@ -678,13 +678,13 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) musb->is_active = 0; } dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->state), otg_stat); idle_timeout = jiffies + (1 * HZ); schedule_work(&musb->irq_work); } else /* A-dev state machine */ { dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->state), otg_stat); switch (musb->xceiv->state) { case OTG_STATE_A_IDLE: @@ -733,7 +733,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) u8 devctl; dev_dbg(musb->controller, "%s timer, %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); + usb_otg_state_string(musb->xceiv->state), otg_stat); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VRISE: diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 13a392913769..2c80004e0a83 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/usb/musb-ux500.h> #include "musb_core.h" @@ -36,6 +37,98 @@ struct ux500_glue { }; #define glue_to_musb(g) platform_get_drvdata(g->musb) +static void ux500_musb_set_vbus(struct musb *musb, int is_on) +{ + u8 devctl; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + /* HDRC controls CPEN, but beware current surges during device + * connect. They can trigger transient overcurrent conditions + * that must be ignored. + */ + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + if (is_on) { + if (musb->xceiv->state == OTG_STATE_A_IDLE) { + /* start the session */ + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + /* + * Wait for the musb to set as A device to enable the + * VBUS + */ + while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + + if (time_after(jiffies, timeout)) { + dev_err(musb->controller, + "configured as A device timeout"); + break; + } + } + + } else { + musb->is_active = 1; + musb->xceiv->otg->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + MUSB_HST_MODE(musb); + } + } else { + musb->is_active = 0; + + /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping + * right to B_IDLE... + */ + musb->xceiv->otg->default_a = 0; + devctl &= ~MUSB_DEVCTL_SESSION; + MUSB_DEV_MODE(musb); + } + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + /* + * Devctl values will be updated after vbus goes below + * session_valid. The time taken depends on the capacitance + * on VBUS line. The max discharge time can be upto 1 sec + * as per the spec. Typically on our platform, it is 200ms + */ + if (!is_on) + mdelay(200); + + dev_dbg(musb->controller, "VBUS %s, devctl %02x\n", + usb_otg_state_string(musb->xceiv->state), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} + +static int musb_otg_notifications(struct notifier_block *nb, + unsigned long event, void *unused) +{ + struct musb *musb = container_of(nb, struct musb, nb); + + dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n", + event, usb_otg_state_string(musb->xceiv->state)); + + switch (event) { + case UX500_MUSB_ID: + dev_dbg(musb->controller, "ID GND\n"); + ux500_musb_set_vbus(musb, 1); + break; + case UX500_MUSB_VBUS: + dev_dbg(musb->controller, "VBUS Connect\n"); + break; + case UX500_MUSB_NONE: + dev_dbg(musb->controller, "VBUS Disconnect\n"); + if (is_host_active(musb)) + ux500_musb_set_vbus(musb, 0); + else + musb->xceiv->state = OTG_STATE_B_IDLE; + break; + default: + dev_dbg(musb->controller, "ID float\n"); + return NOTIFY_DONE; + } + return NOTIFY_OK; +} + static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) { unsigned long flags; @@ -58,12 +151,21 @@ static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) static int ux500_musb_init(struct musb *musb) { + int status; + musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { pr_err("HS USB OTG: no transceiver configured\n"); return -EPROBE_DEFER; } + musb->nb.notifier_call = musb_otg_notifications; + status = usb_register_notifier(musb->xceiv, &musb->nb); + if (status < 0) { + dev_dbg(musb->controller, "notification register failed\n"); + return status; + } + musb->isr = ux500_musb_interrupt; return 0; @@ -71,6 +173,8 @@ static int ux500_musb_init(struct musb *musb) static int ux500_musb_exit(struct musb *musb) { + usb_unregister_notifier(musb->xceiv, &musb->nb); + usb_put_phy(musb->xceiv); return 0; @@ -79,6 +183,8 @@ static int ux500_musb_exit(struct musb *musb) static const struct musb_platform_ops ux500_ops = { .init = ux500_musb_init, .exit = ux500_musb_exit, + + .set_vbus = ux500_musb_set_vbus, }; static int ux500_probe(struct platform_device *pdev) diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 039e567dd3b6..338120641145 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -1,7 +1,7 @@ /* * drivers/usb/musb/ux500_dma.c * - * U8500 and U5500 DMA support code + * U8500 DMA support code * * Copyright (C) 2009 STMicroelectronics * Copyright (C) 2011 ST-Ericsson SA @@ -30,6 +30,7 @@ #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/pfn.h> +#include <linux/sizes.h> #include <linux/platform_data/usb-musb-ux500.h> #include "musb_core.h" @@ -56,7 +57,7 @@ struct ux500_dma_controller { }; /* Work function invoked from DMA callback to handle rx transfers. */ -void ux500_dma_callback(void *private_data) +static void ux500_dma_callback(void *private_data) { struct dma_channel *channel = private_data; struct ux500_dma_channel *ux500_channel = channel->private_data; @@ -93,8 +94,9 @@ static bool ux500_configure_channel(struct dma_channel *channel, struct musb *musb = ux500_channel->controller->private_data; dev_dbg(musb->controller, - "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n", - packet_sz, mode, dma_addr, len, ux500_channel->is_tx); + "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n", + packet_sz, mode, (unsigned long long) dma_addr, + len, ux500_channel->is_tx); ux500_channel->cur_len = len; @@ -191,7 +193,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length) { if ((maxpacket & 0x3) || - ((int)buf & 0x3) || + ((unsigned long int) buf & 0x3) || (length < 512) || (length & 0x3)) return false; @@ -372,12 +374,17 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba controller = kzalloc(sizeof(*controller), GFP_KERNEL); if (!controller) - return NULL; + goto kzalloc_fail; controller->private_data = musb; /* Save physical address for DMA controller. */ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) { + dev_err(musb->controller, "no memory resource defined\n"); + goto plat_get_fail; + } + controller->phy_base = (dma_addr_t) iomem->start; controller->controller.start = ux500_dma_controller_start; @@ -389,4 +396,9 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba controller->controller.is_compatible = ux500_dma_is_compatible; return &controller->controller; + +plat_get_fail: + kfree(controller); +kzalloc_fail: + return NULL; } diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig deleted file mode 100644 index 37962c99ff1e..000000000000 --- a/drivers/usb/otg/Kconfig +++ /dev/null @@ -1,141 +0,0 @@ -# -# USB OTG infrastructure may be needed for peripheral-only, host-only, -# or OTG-capable configurations when OTG transceivers or controllers -# are used. -# - -comment "OTG and related infrastructure" - -config USB_OTG_UTILS - bool - help - Select this to make sure the build includes objects from - the OTG infrastructure directory. - -if USB || USB_GADGET - -# -# USB Transceiver Drivers -# -config USB_GPIO_VBUS - tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" - depends on GENERIC_GPIO - select USB_OTG_UTILS - help - Provides simple GPIO VBUS sensing for controllers with an - internal transceiver via the usb_phy interface, and - optionally control of a D+ pullup GPIO as well as a VBUS - current limit regulator. - -config ISP1301_OMAP - tristate "Philips ISP1301 with OMAP OTG" - depends on I2C && ARCH_OMAP_OTG - select USB_OTG_UTILS - help - If you say yes here you get support for the Philips ISP1301 - USB-On-The-Go transceiver working with the OMAP OTG controller. - The ISP1301 is a full speed USB transceiver which is used in - products including H2, H3, and H4 development boards for Texas - Instruments OMAP processors. - - This driver can also be built as a module. If so, the module - will be called isp1301_omap. - -config USB_ULPI - bool "Generic ULPI Transceiver Driver" - depends on ARM - select USB_OTG_UTILS - 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). - -config TWL4030_USB - tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on TWL4030 - family chips (including the TWL5030 and TPS659x0 devices). - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config TWL6030_USB - tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on TWL6030 - family chips. This TWL6030 transceiver has the VBUS and ID GND - and OTG SRP events capabilities. For all other transceiver functionality - UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs - are hooked to this driver through platform_data structure. - The definition of internal PHY APIs are in the mach-omap2 layer. - -config NOP_USB_XCEIV - tristate "NOP USB Transceiver Driver" - select USB_OTG_UTILS - help - This driver is to be used by all the usb transceiver which are either - built-in with usb ip or which are autonomous and doesn't require any - phy programming such as ISP1x04 etc. - -config USB_MSM_OTG - tristate "OTG support for Qualcomm on-chip USB controller" - depends on (USB || USB_GADGET) && ARCH_MSM - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on MSM chips. It - handles PHY initialization, clock management, and workarounds - required after resetting the hardware and power management. - This driver is required even for peripheral only or host only - mode configurations. - This driver is not supported on boards like trout which - has an external PHY. - -config AB8500_USB - tristate "AB8500 USB Transceiver Driver" - depends on AB8500_CORE - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver in AB8500 chip. - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config FSL_USB2_OTG - bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND - select USB_OTG - select USB_OTG_UTILS - help - Enable this to support Freescale USB OTG transceiver. - -config USB_MXS_PHY - tristate "Freescale MXS USB PHY support" - depends on ARCH_MXC || ARCH_MXS - select STMP_DEVICE - select USB_OTG_UTILS - help - Enable this to support the Freescale MXS USB PHY. - - MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. - -config USB_MV_OTG - tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND - select USB_OTG - select USB_OTG_UTILS - help - Say Y here if you want to build Marvell USB OTG transciever - driver in kernel (including PXA and MMP series). This driver - implements role switch between EHCI host driver and gadget driver. - - To compile this driver as a module, choose M here. - -endif # USB || OTG diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile deleted file mode 100644 index a844b8d35d14..000000000000 --- a/drivers/usb/otg/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# OTG infrastructure and transceiver drivers -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG - -# infrastructure -obj-$(CONFIG_USB_OTG_UTILS) += otg.o - -# transceiver drivers -obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o -obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o -obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o -obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o -obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o -obj-$(CONFIG_USB_ULPI) += ulpi.o -obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o -obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o -obj-$(CONFIG_AB8500_USB) += ab8500-usb.o -fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o -obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o -obj-$(CONFIG_USB_MXS_PHY) += mxs-phy.o -obj-$(CONFIG_USB_MV_OTG) += mv_otg.o diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c deleted file mode 100644 index 2d86f26a0183..000000000000 --- a/drivers/usb/otg/ab8500-usb.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * drivers/usb/otg/ab8500_usb.c - * - * USB transceiver driver for AB8500 chip - * - * Copyright (C) 2010 ST-Ericsson AB - * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/usb/otg.h> -#include <linux/slab.h> -#include <linux/notifier.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/mfd/abx500.h> -#include <linux/mfd/abx500/ab8500.h> - -#define AB8500_MAIN_WD_CTRL_REG 0x01 -#define AB8500_USB_LINE_STAT_REG 0x80 -#define AB8500_USB_PHY_CTRL_REG 0x8A - -#define AB8500_BIT_OTG_STAT_ID (1 << 0) -#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0) -#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1) -#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0) -#define AB8500_BIT_WD_CTRL_KICK (1 << 1) - -#define AB8500_V1x_LINK_STAT_WAIT (HZ/10) -#define AB8500_WD_KICK_DELAY_US 100 /* usec */ -#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ -#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */ - -/* Usb line status register */ -enum ab8500_usb_link_status { - USB_LINK_NOT_CONFIGURED = 0, - USB_LINK_STD_HOST_NC, - USB_LINK_STD_HOST_C_NS, - USB_LINK_STD_HOST_C_S, - USB_LINK_HOST_CHG_NM, - USB_LINK_HOST_CHG_HS, - USB_LINK_HOST_CHG_HS_CHIRP, - USB_LINK_DEDICATED_CHG, - USB_LINK_ACA_RID_A, - USB_LINK_ACA_RID_B, - USB_LINK_ACA_RID_C_NM, - USB_LINK_ACA_RID_C_HS, - USB_LINK_ACA_RID_C_HS_CHIRP, - USB_LINK_HM_IDGND, - USB_LINK_RESERVED, - USB_LINK_NOT_VALID_LINK -}; - -struct ab8500_usb { - struct usb_phy phy; - struct device *dev; - int irq_num_id_rise; - int irq_num_id_fall; - int irq_num_vbus_rise; - int irq_num_vbus_fall; - int irq_num_link_status; - unsigned vbus_draw; - struct delayed_work dwork; - struct work_struct phy_dis_work; - unsigned long link_status_wait; - int rev; -}; - -static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) -{ - return container_of(x, struct ab8500_usb, phy); -} - -static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) -{ - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - AB8500_BIT_WD_CTRL_ENABLE); - - udelay(AB8500_WD_KICK_DELAY_US); - - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - (AB8500_BIT_WD_CTRL_ENABLE - | AB8500_BIT_WD_CTRL_KICK)); - - if (ab->rev > 0x10) /* v1.1 v2.0 */ - udelay(AB8500_WD_V11_DISABLE_DELAY_US); - else /* v1.0 */ - msleep(AB8500_WD_V10_DISABLE_DELAY_MS); - - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - 0); -} - -static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, - bool enable) -{ - u8 ctrl_reg; - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_PHY_CTRL_REG, - &ctrl_reg); - if (sel_host) { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN; - } else { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN; - } - - abx500_set_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_PHY_CTRL_REG, - ctrl_reg); - - /* Needed to enable the phy.*/ - if (enable) - ab8500_usb_wd_workaround(ab); -} - -#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true) -#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false) -#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true) -#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false) - -static int ab8500_usb_link_status_update(struct ab8500_usb *ab) -{ - u8 reg; - enum ab8500_usb_link_status lsts; - void *v = NULL; - enum usb_phy_events event; - - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_LINE_STAT_REG, - ®); - - lsts = (reg >> 3) & 0x0F; - - switch (lsts) { - case USB_LINK_NOT_CONFIGURED: - case USB_LINK_RESERVED: - case USB_LINK_NOT_VALID_LINK: - /* TODO: Disable regulators. */ - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); - ab->phy.state = OTG_STATE_B_IDLE; - ab->phy.otg->default_a = false; - ab->vbus_draw = 0; - event = USB_EVENT_NONE; - break; - - case USB_LINK_STD_HOST_NC: - case USB_LINK_STD_HOST_C_NS: - case USB_LINK_STD_HOST_C_S: - case USB_LINK_HOST_CHG_NM: - case USB_LINK_HOST_CHG_HS: - case USB_LINK_HOST_CHG_HS_CHIRP: - if (ab->phy.otg->gadget) { - /* TODO: Enable regulators. */ - ab8500_usb_peri_phy_en(ab); - v = ab->phy.otg->gadget; - } - event = USB_EVENT_VBUS; - break; - - case USB_LINK_HM_IDGND: - if (ab->phy.otg->host) { - /* TODO: Enable regulators. */ - ab8500_usb_host_phy_en(ab); - v = ab->phy.otg->host; - } - ab->phy.state = OTG_STATE_A_IDLE; - ab->phy.otg->default_a = true; - event = USB_EVENT_ID; - break; - - case USB_LINK_ACA_RID_A: - case USB_LINK_ACA_RID_B: - /* TODO */ - case USB_LINK_ACA_RID_C_NM: - case USB_LINK_ACA_RID_C_HS: - case USB_LINK_ACA_RID_C_HS_CHIRP: - case USB_LINK_DEDICATED_CHG: - /* TODO: vbus_draw */ - event = USB_EVENT_CHARGER; - break; - } - - atomic_notifier_call_chain(&ab->phy.notifier, event, v); - - return 0; -} - -static void ab8500_usb_delayed_work(struct work_struct *work) -{ - struct ab8500_usb *ab = container_of(work, struct ab8500_usb, - dwork.work); - - ab8500_usb_link_status_update(ab); -} - -static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - - return IRQ_HANDLED; -} - -static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - /* Link status will not be updated till phy is disabled. */ - ab8500_usb_peri_phy_dis(ab); - - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - - return IRQ_HANDLED; -} - -static irqreturn_t ab8500_usb_v20_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - ab8500_usb_link_status_update(ab); - - return IRQ_HANDLED; -} - -static void ab8500_usb_phy_disable_work(struct work_struct *work) -{ - struct ab8500_usb *ab = container_of(work, struct ab8500_usb, - phy_dis_work); - - if (!ab->phy.otg->host) - ab8500_usb_host_phy_dis(ab); - - if (!ab->phy.otg->gadget) - ab8500_usb_peri_phy_dis(ab); -} - -static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) -{ - struct ab8500_usb *ab; - - if (!phy) - return -ENODEV; - - ab = phy_to_ab(phy); - - ab->vbus_draw = mA; - - if (mA) - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_ENUMERATED, ab->phy.otg->gadget); - return 0; -} - -/* TODO: Implement some way for charging or other drivers to read - * ab->vbus_draw. - */ - -static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) -{ - /* TODO */ - return 0; -} - -static int ab8500_usb_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct ab8500_usb *ab; - - if (!otg) - return -ENODEV; - - ab = phy_to_ab(otg->phy); - - /* Some drivers call this function in atomic context. - * Do not update ab8500 registers directly till this - * is fixed. - */ - - if (!gadget) { - /* TODO: Disable regulators. */ - otg->gadget = NULL; - schedule_work(&ab->phy_dis_work); - } else { - otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; - - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - } - - return 0; -} - -static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct ab8500_usb *ab; - - if (!otg) - return -ENODEV; - - ab = phy_to_ab(otg->phy); - - /* Some drivers call this function in atomic context. - * Do not update ab8500 registers directly till this - * is fixed. - */ - - if (!host) { - /* TODO: Disable regulators. */ - otg->host = NULL; - schedule_work(&ab->phy_dis_work); - } else { - otg->host = host; - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - } - - return 0; -} - -static void ab8500_usb_irq_free(struct ab8500_usb *ab) -{ - if (ab->rev < 0x20) { - free_irq(ab->irq_num_id_rise, ab); - free_irq(ab->irq_num_id_fall, ab); - free_irq(ab->irq_num_vbus_rise, ab); - free_irq(ab->irq_num_vbus_fall, ab); - } else { - free_irq(ab->irq_num_link_status, ab); - } -} - -static int ab8500_usb_v1x_res_setup(struct platform_device *pdev, - struct ab8500_usb *ab) -{ - int err; - - ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R"); - if (ab->irq_num_id_rise < 0) { - dev_err(&pdev->dev, "ID rise irq not found\n"); - return ab->irq_num_id_rise; - } - err = request_threaded_irq(ab->irq_num_id_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for ID rise irq\n"); - goto fail0; - } - - ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); - if (ab->irq_num_id_fall < 0) { - dev_err(&pdev->dev, "ID fall irq not found\n"); - return ab->irq_num_id_fall; - } - err = request_threaded_irq(ab->irq_num_id_fall, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-fall", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for ID fall irq\n"); - goto fail1; - } - - ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R"); - if (ab->irq_num_vbus_rise < 0) { - dev_err(&pdev->dev, "VBUS rise irq not found\n"); - return ab->irq_num_vbus_rise; - } - err = request_threaded_irq(ab->irq_num_vbus_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for Vbus rise irq\n"); - goto fail2; - } - - ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F"); - if (ab->irq_num_vbus_fall < 0) { - dev_err(&pdev->dev, "VBUS fall irq not found\n"); - return ab->irq_num_vbus_fall; - } - err = request_threaded_irq(ab->irq_num_vbus_fall, NULL, - ab8500_usb_v1x_vbus_fall_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-fall", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for Vbus fall irq\n"); - goto fail3; - } - - return 0; -fail3: - free_irq(ab->irq_num_vbus_rise, ab); -fail2: - free_irq(ab->irq_num_id_fall, ab); -fail1: - free_irq(ab->irq_num_id_rise, ab); -fail0: - return err; -} - -static int ab8500_usb_v2_res_setup(struct platform_device *pdev, - struct ab8500_usb *ab) -{ - int err; - - ab->irq_num_link_status = platform_get_irq_byname(pdev, - "USB_LINK_STATUS"); - if (ab->irq_num_link_status < 0) { - dev_err(&pdev->dev, "Link status irq not found\n"); - return ab->irq_num_link_status; - } - - err = request_threaded_irq(ab->irq_num_link_status, NULL, - ab8500_usb_v20_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-link-status", ab); - if (err < 0) { - dev_err(ab->dev, - "request_irq failed for link status irq\n"); - return err; - } - - return 0; -} - -static int ab8500_usb_probe(struct platform_device *pdev) -{ - struct ab8500_usb *ab; - struct usb_otg *otg; - int err; - int rev; - - rev = abx500_get_chip_id(&pdev->dev); - if (rev < 0) { - dev_err(&pdev->dev, "Chip id read failed\n"); - return rev; - } else if (rev < 0x10) { - dev_err(&pdev->dev, "Unsupported AB8500 chip\n"); - return -ENODEV; - } - - ab = kzalloc(sizeof *ab, GFP_KERNEL); - if (!ab) - return -ENOMEM; - - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(ab); - return -ENOMEM; - } - - ab->dev = &pdev->dev; - ab->rev = rev; - ab->phy.dev = ab->dev; - ab->phy.otg = otg; - ab->phy.label = "ab8500"; - ab->phy.set_suspend = ab8500_usb_set_suspend; - ab->phy.set_power = ab8500_usb_set_power; - ab->phy.state = OTG_STATE_UNDEFINED; - - otg->phy = &ab->phy; - otg->set_host = ab8500_usb_set_host; - otg->set_peripheral = ab8500_usb_set_peripheral; - - platform_set_drvdata(pdev, ab); - - ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); - - /* v1: Wait for link status to become stable. - * all: Updates form set_host and set_peripheral as they are atomic. - */ - INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work); - - /* all: Disable phy when called from set_host and set_peripheral */ - INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); - - if (ab->rev < 0x20) { - err = ab8500_usb_v1x_res_setup(pdev, ab); - ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT; - } else { - err = ab8500_usb_v2_res_setup(pdev, ab); - } - - if (err < 0) - goto fail0; - - err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2); - if (err) { - dev_err(&pdev->dev, "Can't register transceiver\n"); - goto fail1; - } - - dev_info(&pdev->dev, "AB8500 usb driver initialized\n"); - - return 0; -fail1: - ab8500_usb_irq_free(ab); -fail0: - kfree(otg); - kfree(ab); - return err; -} - -static int ab8500_usb_remove(struct platform_device *pdev) -{ - struct ab8500_usb *ab = platform_get_drvdata(pdev); - - ab8500_usb_irq_free(ab); - - cancel_delayed_work_sync(&ab->dwork); - - cancel_work_sync(&ab->phy_dis_work); - - usb_remove_phy(&ab->phy); - - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); - - platform_set_drvdata(pdev, NULL); - - kfree(ab->phy.otg); - kfree(ab); - - return 0; -} - -static struct platform_driver ab8500_usb_driver = { - .probe = ab8500_usb_probe, - .remove = ab8500_usb_remove, - .driver = { - .name = "ab8500-usb", - .owner = THIS_MODULE, - }, -}; - -static int __init ab8500_usb_init(void) -{ - return platform_driver_register(&ab8500_usb_driver); -} -subsys_initcall(ab8500_usb_init); - -static void __exit ab8500_usb_exit(void) -{ - platform_driver_unregister(&ab8500_usb_driver); -} -module_exit(ab8500_usb_exit); - -MODULE_ALIAS("platform:ab8500_usb"); -MODULE_AUTHOR("ST-Ericsson AB"); -MODULE_DESCRIPTION("AB8500 usb transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 90549382eba5..aab2ab2fbc90 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -1,13 +1,74 @@ # # Physical Layer USB driver configuration # -comment "USB Physical Layer drivers" - depends on USB || USB_GADGET +menuconfig USB_PHY + bool "USB Physical Layer drivers" + help + USB controllers (those which are host, device or DRD) need a + device to handle the physical layer signalling, commonly called + a PHY. + + The following drivers add support for such PHY devices. + +if USB_PHY + +# +# USB Transceiver Drivers +# +config AB8500_USB + tristate "AB8500 USB Transceiver Driver" + depends on AB8500_CORE + help + Enable this to support the USB OTG transceiver in AB8500 chip. + This transceiver supports high and full speed devices plus, + in host mode, low speed. + +config FSL_USB2_OTG + bool "Freescale USB OTG Transceiver Driver" + depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND + select USB_OTG + help + Enable this to support Freescale USB OTG transceiver. + +config ISP1301_OMAP + tristate "Philips ISP1301 with OMAP OTG" + depends on I2C && ARCH_OMAP_OTG + help + If you say yes here you get support for the Philips ISP1301 + USB-On-The-Go transceiver working with the OMAP OTG controller. + The ISP1301 is a full speed USB transceiver which is used in + products including H2, H3, and H4 development boards for Texas + Instruments OMAP processors. + + This driver can also be built as a module. If so, the module + will be called isp1301_omap. + +config MV_U3D_PHY + bool "Marvell USB 3.0 PHY controller Driver" + depends on CPU_MMP3 + help + Enable this to support Marvell USB 3.0 phy controller for Marvell + SoC. + +config NOP_USB_XCEIV + tristate "NOP USB Transceiver Driver" + help + This driver is to be used by all the usb transceiver which are either + built-in with usb ip or which are autonomous and doesn't require any + phy programming such as ISP1x04 etc. + +config OMAP_CONTROL_USB + tristate "OMAP CONTROL USB Driver" + help + Enable this to add support for the USB part present in the control + module. This driver has API to power on the USB2 PHY and to write to + the mailbox. The mailbox is present only in omap4 and the register to + power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an + additional register to power on USB3 PHY. config OMAP_USB2 tristate "OMAP USB2 PHY Driver" depends on ARCH_OMAP2PLUS - select USB_OTG_UTILS select OMAP_CONTROL_USB help Enable this to support the transceiver that is part of SOC. This @@ -17,7 +78,6 @@ config OMAP_USB2 config OMAP_USB3 tristate "OMAP USB3 PHY Driver" - select USB_OTG_UTILS select OMAP_CONTROL_USB help Enable this to support the USB3 PHY that is part of SOC. This @@ -25,14 +85,55 @@ config OMAP_USB3 This driver interacts with the "OMAP Control USB Driver" to power on/off the PHY. -config OMAP_CONTROL_USB - tristate "OMAP CONTROL USB Driver" +config SAMSUNG_USBPHY + tristate "Samsung USB PHY Driver" help - Enable this to add support for the USB part present in the control - module. This driver has API to power on the USB2 PHY and to write to - the mailbox. The mailbox is present only in omap4 and the register to - power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an - additional register to power on USB3 PHY. + Enable this to support Samsung USB phy helper driver for Samsung SoCs. + This driver provides common interface to interact, for Samsung USB 2.0 PHY + driver and later for Samsung USB 3.0 PHY driver. + +config SAMSUNG_USB2PHY + tristate "Samsung USB 2.0 PHY controller Driver" + select SAMSUNG_USBPHY + help + Enable this to support Samsung USB 2.0 (High Speed) PHY controller + driver for Samsung SoCs. + +config SAMSUNG_USB3PHY + tristate "Samsung USB 3.0 PHY controller Driver" + select SAMSUNG_USBPHY + help + Enable this to support Samsung USB 3.0 (Super Speed) phy controller + for samsung SoCs. + +config TWL4030_USB + tristate "TWL4030 USB Transceiver Driver" + depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS + help + Enable this to support the USB OTG transceiver on TWL4030 + family chips (including the TWL5030 and TPS659x0 devices). + This transceiver supports high and full speed devices plus, + in host mode, low speed. + +config TWL6030_USB + tristate "TWL6030 USB Transceiver Driver" + depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS + help + Enable this to support the USB OTG transceiver on TWL6030 + family chips. This TWL6030 transceiver has the VBUS and ID GND + and OTG SRP events capabilities. For all other transceiver functionality + UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs + are hooked to this driver through platform_data structure. + The definition of internal PHY APIs are in the mach-omap2 layer. + +config USB_GPIO_VBUS + tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" + depends on GENERIC_GPIO + help + Provides simple GPIO VBUS sensing for controllers with an + internal transceiver via the usb_phy interface, and + optionally control of a D+ pullup GPIO as well as a VBUS + current limit regulator. config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" @@ -47,18 +148,41 @@ config USB_ISP1301 To compile this driver as a module, choose M here: the module will be called isp1301. -config MV_U3D_PHY - bool "Marvell USB 3.0 PHY controller Driver" - depends on USB_MV_U3D - select USB_OTG_UTILS +config USB_MSM_OTG + tristate "OTG support for Qualcomm on-chip USB controller" + depends on (USB || USB_GADGET) && ARCH_MSM help - Enable this to support Marvell USB 3.0 phy controller for Marvell - SoC. + Enable this to support the USB OTG transceiver on MSM chips. It + handles PHY initialization, clock management, and workarounds + required after resetting the hardware and power management. + This driver is required even for peripheral only or host only + mode configurations. + This driver is not supported on boards like trout which + has an external PHY. + +config USB_MV_OTG + tristate "Marvell USB OTG support" + depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND + select USB_OTG + help + Say Y here if you want to build Marvell USB OTG transciever + driver in kernel (including PXA and MMP series). This driver + implements role switch between EHCI host driver and gadget driver. + + To compile this driver as a module, choose M here. + +config USB_MXS_PHY + tristate "Freescale MXS USB PHY support" + depends on ARCH_MXC || ARCH_MXS + select STMP_DEVICE + help + Enable this to support the Freescale MXS USB PHY. + + MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. config USB_RCAR_PHY tristate "Renesas R-Car USB phy support" depends on USB || USB_GADGET - select USB_OTG_UTILS help Say Y here to add support for the Renesas R-Car USB phy driver. This chip is typically used as USB phy for USB host, gadget. @@ -67,10 +191,18 @@ config USB_RCAR_PHY To compile this driver as a module, choose M here: the module will be called rcar-phy. -config SAMSUNG_USBPHY - bool "Samsung USB PHY controller Driver" - depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS - select USB_OTG_UTILS +config USB_ULPI + bool "Generic ULPI Transceiver Driver" + depends on ARM + 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 - Enable this to support Samsung USB phy controller for samsung - SoCs. + Provides read/write operations to the ULPI phy register set for + controllers with a viewport register (e.g. Chipidea/ARC controllers). + +endif # USB_PHY diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index b13faa193e0c..a9169cb1e6fc 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -4,11 +4,30 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -obj-$(CONFIG_OMAP_USB2) += omap-usb2.o -obj-$(CONFIG_OMAP_USB3) += omap-usb3.o -obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o -obj-$(CONFIG_USB_ISP1301) += isp1301.o -obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o -obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o -obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o -obj-$(CONFIG_SAMSUNG_USBPHY) += samsung-usbphy.o +obj-$(CONFIG_USB_PHY) += phy.o + +# transceiver drivers, keep the list sorted + +obj-$(CONFIG_AB8500_USB) += phy-ab8500-usb.o +phy-fsl-usb2-objs := phy-fsl-usb.o phy-fsm-usb.o +obj-$(CONFIG_FSL_USB2_OTG) += phy-fsl-usb2.o +obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o +obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o +obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o +obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o +obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o +obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o +obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o +obj-$(CONFIG_SAMSUNG_USB2PHY) += phy-samsung-usb2.o +obj-$(CONFIG_SAMSUNG_USB3PHY) += phy-samsung-usb3.o +obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o +obj-$(CONFIG_TWL6030_USB) += phy-twl6030-usb.o +obj-$(CONFIG_USB_EHCI_TEGRA) += phy-tegra-usb.o +obj-$(CONFIG_USB_GPIO_VBUS) += phy-gpio-vbus-usb.o +obj-$(CONFIG_USB_ISP1301) += phy-isp1301.o +obj-$(CONFIG_USB_MSM_OTG) += phy-msm-usb.o +obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o +obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o +obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o +obj-$(CONFIG_USB_ULPI) += phy-ulpi.o +obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c deleted file mode 100644 index 18dbf7e37607..000000000000 --- a/drivers/usb/phy/isp1301.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * NXP ISP1301 USB transceiver driver - * - * Copyright (C) 2012 Roland Stigge - * - * Author: Roland Stigge <stigge@antcom.de> - * - * 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. - */ - -#include <linux/module.h> -#include <linux/i2c.h> - -#define DRV_NAME "isp1301" - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301", 0 }, - { } -}; - -static struct i2c_client *isp1301_i2c_client; - -static int isp1301_probe(struct i2c_client *client, - const struct i2c_device_id *i2c_id) -{ - isp1301_i2c_client = client; - return 0; -} - -static int isp1301_remove(struct i2c_client *client) -{ - return 0; -} - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = DRV_NAME, - }, - .probe = isp1301_probe, - .remove = isp1301_remove, - .id_table = isp1301_id, -}; - -module_i2c_driver(isp1301_driver); - -static int match(struct device *dev, void *data) -{ - struct device_node *node = (struct device_node *)data; - return (dev->of_node == node) && - (dev->driver == &isp1301_driver.driver); -} - -struct i2c_client *isp1301_get_client(struct device_node *node) -{ - if (node) { /* reference of ISP1301 I2C node via DT */ - struct device *dev = bus_find_device(&i2c_bus_type, NULL, - node, match); - if (!dev) - return NULL; - return to_i2c_client(dev); - } else { /* non-DT: only one ISP1301 chip supported */ - return isp1301_i2c_client; - } -} -EXPORT_SYMBOL_GPL(isp1301_get_client); - -MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); -MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c new file mode 100644 index 000000000000..4acef26a2ef5 --- /dev/null +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -0,0 +1,924 @@ +/* + * drivers/usb/otg/ab8500_usb.c + * + * USB transceiver driver for AB8500 chip + * + * Copyright (C) 2010 ST-Ericsson AB + * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/usb/otg.h> +#include <linux/slab.h> +#include <linux/notifier.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> +#include <linux/usb/musb-ux500.h> +#include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h> + +/* Bank AB8500_SYS_CTRL2_BLOCK */ +#define AB8500_MAIN_WD_CTRL_REG 0x01 + +/* Bank AB8500_USB */ +#define AB8500_USB_LINE_STAT_REG 0x80 +#define AB8505_USB_LINE_STAT_REG 0x94 +#define AB8500_USB_PHY_CTRL_REG 0x8A + +/* Bank AB8500_DEVELOPMENT */ +#define AB8500_BANK12_ACCESS 0x00 + +/* Bank AB8500_DEBUG */ +#define AB8500_USB_PHY_TUNE1 0x05 +#define AB8500_USB_PHY_TUNE2 0x06 +#define AB8500_USB_PHY_TUNE3 0x07 + +#define AB8500_BIT_OTG_STAT_ID (1 << 0) +#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0) +#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1) +#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0) +#define AB8500_BIT_WD_CTRL_KICK (1 << 1) + +#define AB8500_WD_KICK_DELAY_US 100 /* usec */ +#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ +#define AB8500_V20_31952_DISABLE_DELAY_US 100 /* usec */ + +/* Usb line status register */ +enum ab8500_usb_link_status { + USB_LINK_NOT_CONFIGURED_8500 = 0, + USB_LINK_STD_HOST_NC_8500, + USB_LINK_STD_HOST_C_NS_8500, + USB_LINK_STD_HOST_C_S_8500, + USB_LINK_HOST_CHG_NM_8500, + USB_LINK_HOST_CHG_HS_8500, + USB_LINK_HOST_CHG_HS_CHIRP_8500, + USB_LINK_DEDICATED_CHG_8500, + USB_LINK_ACA_RID_A_8500, + USB_LINK_ACA_RID_B_8500, + USB_LINK_ACA_RID_C_NM_8500, + USB_LINK_ACA_RID_C_HS_8500, + USB_LINK_ACA_RID_C_HS_CHIRP_8500, + USB_LINK_HM_IDGND_8500, + USB_LINK_RESERVED_8500, + USB_LINK_NOT_VALID_LINK_8500, +}; + +enum ab8505_usb_link_status { + USB_LINK_NOT_CONFIGURED_8505 = 0, + USB_LINK_STD_HOST_NC_8505, + USB_LINK_STD_HOST_C_NS_8505, + USB_LINK_STD_HOST_C_S_8505, + USB_LINK_CDP_8505, + USB_LINK_RESERVED0_8505, + USB_LINK_RESERVED1_8505, + USB_LINK_DEDICATED_CHG_8505, + USB_LINK_ACA_RID_A_8505, + USB_LINK_ACA_RID_B_8505, + USB_LINK_ACA_RID_C_NM_8505, + USB_LINK_RESERVED2_8505, + USB_LINK_RESERVED3_8505, + USB_LINK_HM_IDGND_8505, + USB_LINK_CHARGERPORT_NOT_OK_8505, + USB_LINK_CHARGER_DM_HIGH_8505, + USB_LINK_PHYEN_NO_VBUS_NO_IDGND_8505, + USB_LINK_STD_UPSTREAM_NO_IDGNG_NO_VBUS_8505, + USB_LINK_STD_UPSTREAM_8505, + USB_LINK_CHARGER_SE1_8505, + USB_LINK_CARKIT_CHGR_1_8505, + USB_LINK_CARKIT_CHGR_2_8505, + USB_LINK_ACA_DOCK_CHGR_8505, + USB_LINK_SAMSUNG_BOOT_CBL_PHY_EN_8505, + USB_LINK_SAMSUNG_BOOT_CBL_PHY_DISB_8505, + USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505, + USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505, + USB_LINK_MOTOROLA_FACTORY_CBL_PHY_EN_8505, +}; + +enum ab8500_usb_mode { + USB_IDLE = 0, + USB_PERIPHERAL, + USB_HOST, + USB_DEDICATED_CHG +}; + +struct ab8500_usb { + struct usb_phy phy; + struct device *dev; + struct ab8500 *ab8500; + unsigned vbus_draw; + struct work_struct phy_dis_work; + enum ab8500_usb_mode mode; + struct regulator *v_ape; + struct regulator *v_musb; + struct regulator *v_ulpi; + int saved_v_ulpi; + int previous_link_status_state; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_sleep; +}; + +static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) +{ + return container_of(x, struct ab8500_usb, phy); +} + +static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) +{ + abx500_set_register_interruptible(ab->dev, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WD_CTRL_REG, + AB8500_BIT_WD_CTRL_ENABLE); + + udelay(AB8500_WD_KICK_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WD_CTRL_REG, + (AB8500_BIT_WD_CTRL_ENABLE + | AB8500_BIT_WD_CTRL_KICK)); + + udelay(AB8500_WD_V11_DISABLE_DELAY_US); + + abx500_set_register_interruptible(ab->dev, + AB8500_SYS_CTRL2_BLOCK, + AB8500_MAIN_WD_CTRL_REG, + 0); +} + +static void ab8500_usb_regulator_enable(struct ab8500_usb *ab) +{ + int ret, volt; + + ret = regulator_enable(ab->v_ape); + if (ret) + dev_err(ab->dev, "Failed to enable v-ape\n"); + + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { + ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi); + if (ab->saved_v_ulpi < 0) + dev_err(ab->dev, "Failed to get v_ulpi voltage\n"); + + ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000); + if (ret < 0) + dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n", + ret); + + ret = regulator_set_optimum_mode(ab->v_ulpi, 28000); + if (ret < 0) + dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", + ret); + } + + ret = regulator_enable(ab->v_ulpi); + if (ret) + dev_err(ab->dev, "Failed to enable vddulpivio18\n"); + + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { + volt = regulator_get_voltage(ab->v_ulpi); + if ((volt != 1300000) && (volt != 1350000)) + dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n", + volt); + } + + ret = regulator_enable(ab->v_musb); + if (ret) + dev_err(ab->dev, "Failed to enable musb_1v8\n"); +} + +static void ab8500_usb_regulator_disable(struct ab8500_usb *ab) +{ + int ret; + + regulator_disable(ab->v_musb); + + regulator_disable(ab->v_ulpi); + + /* USB is not the only consumer of Vintcore, restore old settings */ + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { + if (ab->saved_v_ulpi > 0) { + ret = regulator_set_voltage(ab->v_ulpi, + ab->saved_v_ulpi, ab->saved_v_ulpi); + if (ret < 0) + dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n", + ab->saved_v_ulpi, ret); + } + + ret = regulator_set_optimum_mode(ab->v_ulpi, 0); + if (ret < 0) + dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", + ret); + } + + regulator_disable(ab->v_ape); +} + +static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit) +{ + /* Workaround for v2.0 bug # 31952 */ + if (is_ab8500_2p0(ab->ab8500)) { + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, AB8500_USB_PHY_CTRL_REG, + bit, bit); + udelay(AB8500_V20_31952_DISABLE_DELAY_US); + } +} + +static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : + AB8500_BIT_PHY_CTRL_DEVICE_EN; + + /* mux and configure USB pins to DEFAULT state */ + ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT); + if (IS_ERR(ab->pinctrl)) + dev_err(ab->dev, "could not get/set default pinstate\n"); + + ab8500_usb_regulator_enable(ab); + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, AB8500_USB_PHY_CTRL_REG, + bit, bit); +} + +static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) +{ + u8 bit; + bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : + AB8500_BIT_PHY_CTRL_DEVICE_EN; + + ab8500_usb_wd_linkstatus(ab, bit); + + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, AB8500_USB_PHY_CTRL_REG, + bit, 0); + + /* Needed to disable the phy.*/ + ab8500_usb_wd_workaround(ab); + + ab8500_usb_regulator_disable(ab); + + if (!IS_ERR(ab->pinctrl)) { + /* configure USB pins to SLEEP state */ + ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl, + PINCTRL_STATE_SLEEP); + + if (IS_ERR(ab->pins_sleep)) + dev_dbg(ab->dev, "could not get sleep pinstate\n"); + else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep)) + dev_err(ab->dev, "could not set pins to sleep state\n"); + + /* as USB pins are shared with idddet, release them to allow + * iddet to request them + */ + pinctrl_put(ab->pinctrl); + } +} + +#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true) +#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_disable(ab, true) +#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_enable(ab, false) +#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_disable(ab, false) + +static int ab8505_usb_link_status_update(struct ab8500_usb *ab, + enum ab8505_usb_link_status lsts) +{ + enum ux500_musb_vbus_id_status event = 0; + + dev_dbg(ab->dev, "ab8505_usb_link_status_update %d\n", lsts); + + /* + * Spurious link_status interrupts are seen at the time of + * disconnection of a device in RIDA state + */ + if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 && + (lsts == USB_LINK_STD_HOST_NC_8505)) + return 0; + + ab->previous_link_status_state = lsts; + + switch (lsts) { + case USB_LINK_ACA_RID_B_8505: + event = UX500_MUSB_RIDB; + case USB_LINK_NOT_CONFIGURED_8505: + case USB_LINK_RESERVED0_8505: + case USB_LINK_RESERVED1_8505: + case USB_LINK_RESERVED2_8505: + case USB_LINK_RESERVED3_8505: + ab->mode = USB_IDLE; + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + if (event != UX500_MUSB_RIDB) + event = UX500_MUSB_NONE; + /* + * Fallback to default B_IDLE as nothing + * is connected + */ + ab->phy.state = OTG_STATE_B_IDLE; + break; + + case USB_LINK_ACA_RID_C_NM_8505: + event = UX500_MUSB_RIDC; + case USB_LINK_STD_HOST_NC_8505: + case USB_LINK_STD_HOST_C_NS_8505: + case USB_LINK_STD_HOST_C_S_8505: + case USB_LINK_CDP_8505: + if (ab->mode == USB_IDLE) { + ab->mode = USB_PERIPHERAL; + ab8500_usb_peri_phy_en(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_PREPARE, &ab->vbus_draw); + } + if (event != UX500_MUSB_RIDC) + event = UX500_MUSB_VBUS; + break; + + case USB_LINK_ACA_RID_A_8505: + case USB_LINK_ACA_DOCK_CHGR_8505: + event = UX500_MUSB_RIDA; + case USB_LINK_HM_IDGND_8505: + if (ab->mode == USB_IDLE) { + ab->mode = USB_HOST; + ab8500_usb_host_phy_en(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_PREPARE, &ab->vbus_draw); + } + ab->phy.otg->default_a = true; + if (event != UX500_MUSB_RIDA) + event = UX500_MUSB_ID; + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + break; + + case USB_LINK_DEDICATED_CHG_8505: + ab->mode = USB_DEDICATED_CHG; + event = UX500_MUSB_CHARGER; + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + break; + + default: + break; + } + + return 0; +} + +static int ab8500_usb_link_status_update(struct ab8500_usb *ab, + enum ab8500_usb_link_status lsts) +{ + enum ux500_musb_vbus_id_status event = 0; + + dev_dbg(ab->dev, "ab8500_usb_link_status_update %d\n", lsts); + + /* + * Spurious link_status interrupts are seen in case of a + * disconnection of a device in IDGND and RIDA stage + */ + if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 && + (lsts == USB_LINK_STD_HOST_C_NS_8500 || + lsts == USB_LINK_STD_HOST_NC_8500)) + return 0; + + if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 && + lsts == USB_LINK_STD_HOST_NC_8500) + return 0; + + ab->previous_link_status_state = lsts; + + switch (lsts) { + case USB_LINK_ACA_RID_B_8500: + event = UX500_MUSB_RIDB; + case USB_LINK_NOT_CONFIGURED_8500: + case USB_LINK_NOT_VALID_LINK_8500: + ab->mode = USB_IDLE; + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + if (event != UX500_MUSB_RIDB) + event = UX500_MUSB_NONE; + /* Fallback to default B_IDLE as nothing is connected */ + ab->phy.state = OTG_STATE_B_IDLE; + break; + + case USB_LINK_ACA_RID_C_NM_8500: + case USB_LINK_ACA_RID_C_HS_8500: + case USB_LINK_ACA_RID_C_HS_CHIRP_8500: + event = UX500_MUSB_RIDC; + case USB_LINK_STD_HOST_NC_8500: + case USB_LINK_STD_HOST_C_NS_8500: + case USB_LINK_STD_HOST_C_S_8500: + case USB_LINK_HOST_CHG_NM_8500: + case USB_LINK_HOST_CHG_HS_8500: + case USB_LINK_HOST_CHG_HS_CHIRP_8500: + if (ab->mode == USB_IDLE) { + ab->mode = USB_PERIPHERAL; + ab8500_usb_peri_phy_en(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_PREPARE, &ab->vbus_draw); + } + if (event != UX500_MUSB_RIDC) + event = UX500_MUSB_VBUS; + break; + + case USB_LINK_ACA_RID_A_8500: + event = UX500_MUSB_RIDA; + case USB_LINK_HM_IDGND_8500: + if (ab->mode == USB_IDLE) { + ab->mode = USB_HOST; + ab8500_usb_host_phy_en(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_PREPARE, &ab->vbus_draw); + } + ab->phy.otg->default_a = true; + if (event != UX500_MUSB_RIDA) + event = UX500_MUSB_ID; + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + break; + + case USB_LINK_DEDICATED_CHG_8500: + ab->mode = USB_DEDICATED_CHG; + event = UX500_MUSB_CHARGER; + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + break; + + case USB_LINK_RESERVED_8500: + break; + } + + return 0; +} + +/* + * Connection Sequence: + * 1. Link Status Interrupt + * 2. Enable AB clock + * 3. Enable AB regulators + * 4. Enable USB phy + * 5. Reset the musb controller + * 6. Switch the ULPI GPIO pins to fucntion mode + * 7. Enable the musb Peripheral5 clock + * 8. Restore MUSB context + */ +static int abx500_usb_link_status_update(struct ab8500_usb *ab) +{ + u8 reg; + int ret = 0; + + if (is_ab8500(ab->ab8500)) { + enum ab8500_usb_link_status lsts; + + abx500_get_register_interruptible(ab->dev, + AB8500_USB, AB8500_USB_LINE_STAT_REG, ®); + lsts = (reg >> 3) & 0x0F; + ret = ab8500_usb_link_status_update(ab, lsts); + } else if (is_ab8505(ab->ab8500)) { + enum ab8505_usb_link_status lsts; + + abx500_get_register_interruptible(ab->dev, + AB8500_USB, AB8505_USB_LINE_STAT_REG, ®); + lsts = (reg >> 3) & 0x1F; + ret = ab8505_usb_link_status_update(ab, lsts); + } + + return ret; +} + +/* + * Disconnection Sequence: + * 1. Disconect Interrupt + * 2. Disable regulators + * 3. Disable AB clock + * 4. Disable the Phy + * 5. Link Status Interrupt + * 6. Disable Musb Clock + */ +static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data) +{ + struct ab8500_usb *ab = (struct ab8500_usb *) data; + enum usb_phy_events event = UX500_MUSB_NONE; + + /* Link status will not be updated till phy is disabled. */ + if (ab->mode == USB_HOST) { + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + ab8500_usb_host_phy_dis(ab); + ab->mode = USB_IDLE; + } + + if (ab->mode == USB_PERIPHERAL) { + atomic_notifier_call_chain(&ab->phy.notifier, + event, &ab->vbus_draw); + ab8500_usb_peri_phy_dis(ab); + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_CLEAN, &ab->vbus_draw); + ab->mode = USB_IDLE; + ab->phy.otg->default_a = false; + ab->vbus_draw = 0; + } + + if (is_ab8500_2p0(ab->ab8500)) { + if (ab->mode == USB_DEDICATED_CHG) { + ab8500_usb_wd_linkstatus(ab, + AB8500_BIT_PHY_CTRL_DEVICE_EN); + abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_USB, AB8500_USB_PHY_CTRL_REG, + AB8500_BIT_PHY_CTRL_DEVICE_EN, 0); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data) +{ + struct ab8500_usb *ab = (struct ab8500_usb *) data; + + abx500_usb_link_status_update(ab); + + return IRQ_HANDLED; +} + +static void ab8500_usb_phy_disable_work(struct work_struct *work) +{ + struct ab8500_usb *ab = container_of(work, struct ab8500_usb, + phy_dis_work); + + if (!ab->phy.otg->host) + ab8500_usb_host_phy_dis(ab); + + if (!ab->phy.otg->gadget) + ab8500_usb_peri_phy_dis(ab); +} + +static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) +{ + /* + * AB8500 V2 has eye diagram issues when drawing more than 100mA from + * VBUS. Set charging current to 100mA in case of standard host + */ + if (is_ab8500_2p0_or_earlier(ab->ab8500)) + if (mA > 100) + mA = 100; + + return mA; +} + +static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) +{ + struct ab8500_usb *ab; + + if (!phy) + return -ENODEV; + + ab = phy_to_ab(phy); + + mA = ab8500_eyediagram_workaroud(ab, mA); + + ab->vbus_draw = mA; + + atomic_notifier_call_chain(&ab->phy.notifier, + UX500_MUSB_VBUS, &ab->vbus_draw); + + return 0; +} + +static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) +{ + /* TODO */ + return 0; +} + +static int ab8500_usb_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + struct ab8500_usb *ab; + + if (!otg) + return -ENODEV; + + ab = phy_to_ab(otg->phy); + + ab->phy.otg->gadget = gadget; + + /* Some drivers call this function in atomic context. + * Do not update ab8500 registers directly till this + * is fixed. + */ + + if ((ab->mode != USB_IDLE) && (!gadget)) { + ab->mode = USB_IDLE; + schedule_work(&ab->phy_dis_work); + } + + return 0; +} + +static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + struct ab8500_usb *ab; + + if (!otg) + return -ENODEV; + + ab = phy_to_ab(otg->phy); + + ab->phy.otg->host = host; + + /* Some drivers call this function in atomic context. + * Do not update ab8500 registers directly till this + * is fixed. + */ + + if ((ab->mode != USB_IDLE) && (!host)) { + ab->mode = USB_IDLE; + schedule_work(&ab->phy_dis_work); + } + + return 0; +} + +static int ab8500_usb_regulator_get(struct ab8500_usb *ab) +{ + int err; + + ab->v_ape = devm_regulator_get(ab->dev, "v-ape"); + if (IS_ERR(ab->v_ape)) { + dev_err(ab->dev, "Could not get v-ape supply\n"); + err = PTR_ERR(ab->v_ape); + return err; + } + + ab->v_ulpi = devm_regulator_get(ab->dev, "vddulpivio18"); + if (IS_ERR(ab->v_ulpi)) { + dev_err(ab->dev, "Could not get vddulpivio18 supply\n"); + err = PTR_ERR(ab->v_ulpi); + return err; + } + + ab->v_musb = devm_regulator_get(ab->dev, "musb_1v8"); + if (IS_ERR(ab->v_musb)) { + dev_err(ab->dev, "Could not get musb_1v8 supply\n"); + err = PTR_ERR(ab->v_musb); + return err; + } + + return 0; +} + +static int ab8500_usb_irq_setup(struct platform_device *pdev, + struct ab8500_usb *ab) +{ + int err; + int irq; + + irq = platform_get_irq_byname(pdev, "USB_LINK_STATUS"); + if (irq < 0) { + dev_err(&pdev->dev, "Link status irq not found\n"); + return irq; + } + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ab8500_usb_link_status_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, "usb-link-status", ab); + if (err < 0) { + dev_err(ab->dev, "request_irq failed for link status irq\n"); + return err; + } + + irq = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); + if (irq < 0) { + dev_err(&pdev->dev, "ID fall irq not found\n"); + return irq; + } + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ab8500_usb_disconnect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, "usb-id-fall", ab); + if (err < 0) { + dev_err(ab->dev, "request_irq failed for ID fall irq\n"); + return err; + } + + irq = platform_get_irq_byname(pdev, "VBUS_DET_F"); + if (irq < 0) { + dev_err(&pdev->dev, "VBUS fall irq not found\n"); + return irq; + } + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ab8500_usb_disconnect_irq, + IRQF_NO_SUSPEND | IRQF_SHARED, "usb-vbus-fall", ab); + if (err < 0) { + dev_err(ab->dev, "request_irq failed for Vbus fall irq\n"); + return err; + } + + return 0; +} + +static int ab8500_usb_probe(struct platform_device *pdev) +{ + struct ab8500_usb *ab; + struct ab8500 *ab8500; + struct usb_otg *otg; + int err; + int rev; + + ab8500 = dev_get_drvdata(pdev->dev.parent); + rev = abx500_get_chip_id(&pdev->dev); + + if (is_ab8500_1p1_or_earlier(ab8500)) { + dev_err(&pdev->dev, "Unsupported AB8500 chip rev=%d\n", rev); + return -ENODEV; + } + + ab = devm_kzalloc(&pdev->dev, sizeof(*ab), GFP_KERNEL); + if (!ab) + return -ENOMEM; + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + ab->dev = &pdev->dev; + ab->ab8500 = ab8500; + ab->phy.dev = ab->dev; + ab->phy.otg = otg; + ab->phy.label = "ab8500"; + ab->phy.set_suspend = ab8500_usb_set_suspend; + ab->phy.set_power = ab8500_usb_set_power; + ab->phy.state = OTG_STATE_UNDEFINED; + + otg->phy = &ab->phy; + otg->set_host = ab8500_usb_set_host; + otg->set_peripheral = ab8500_usb_set_peripheral; + + platform_set_drvdata(pdev, ab); + + ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); + + /* all: Disable phy when called from set_host and set_peripheral */ + INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); + + err = ab8500_usb_regulator_get(ab); + if (err) + return err; + + err = ab8500_usb_irq_setup(pdev, ab); + if (err < 0) + return err; + + err = usb_add_phy(&ab->phy, USB_PHY_TYPE_USB2); + if (err) { + dev_err(&pdev->dev, "Can't register transceiver\n"); + return err; + } + + /* Phy tuning values for AB8500 */ + if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { + /* Enable the PBT/Bank 0x12 access */ + err = abx500_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01); + if (err < 0) + dev_err(ab->dev, "Failed to enable bank12 access err=%d\n", + err); + + err = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE1, 0xC8); + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n", + err); + + err = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE2, 0x00); + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n", + err); + + err = abx500_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE3, 0x78); + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", + err); + + /* Switch to normal mode/disable Bank 0x12 access */ + err = abx500_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x00); + if (err < 0) + dev_err(ab->dev, "Failed to switch bank12 access err=%d\n", + err); + } + + /* Phy tuning values for AB8505 */ + if (is_ab8505(ab->ab8500)) { + /* Enable the PBT/Bank 0x12 access */ + err = abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, + 0x01, 0x01); + if (err < 0) + dev_err(ab->dev, "Failed to enable bank12 access err=%d\n", + err); + + err = abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE1, + 0xC8, 0xC8); + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE1 register err=%d\n", + err); + + err = abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE2, + 0x60, 0x60); + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE2 register err=%d\n", + err); + + err = abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_DEBUG, AB8500_USB_PHY_TUNE3, + 0xFC, 0x80); + + if (err < 0) + dev_err(ab->dev, "Failed to set PHY_TUNE3 regester err=%d\n", + err); + + /* Switch to normal mode/disable Bank 0x12 access */ + err = abx500_mask_and_set_register_interruptible(ab->dev, + AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, + 0x00, 0x00); + if (err < 0) + dev_err(ab->dev, "Failed to switch bank12 access err=%d\n", + err); + } + + /* Needed to enable ID detection. */ + ab8500_usb_wd_workaround(ab); + + abx500_usb_link_status_update(ab); + + dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev); + + return 0; +} + +static int ab8500_usb_remove(struct platform_device *pdev) +{ + struct ab8500_usb *ab = platform_get_drvdata(pdev); + + cancel_work_sync(&ab->phy_dis_work); + + usb_remove_phy(&ab->phy); + + if (ab->mode == USB_HOST) + ab8500_usb_host_phy_dis(ab); + else if (ab->mode == USB_PERIPHERAL) + ab8500_usb_peri_phy_dis(ab); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver ab8500_usb_driver = { + .probe = ab8500_usb_probe, + .remove = ab8500_usb_remove, + .driver = { + .name = "ab8500-usb", + .owner = THIS_MODULE, + }, +}; + +static int __init ab8500_usb_init(void) +{ + return platform_driver_register(&ab8500_usb_driver); +} +subsys_initcall(ab8500_usb_init); + +static void __exit ab8500_usb_exit(void) +{ + platform_driver_unregister(&ab8500_usb_driver); +} +module_exit(ab8500_usb_exit); + +MODULE_ALIAS("platform:ab8500_usb"); +MODULE_AUTHOR("ST-Ericsson AB"); +MODULE_DESCRIPTION("AB8500 usb transceiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/phy/phy-fsl-usb.c index d16adb41eb21..97b9308507c3 100644 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -43,7 +43,7 @@ #include <asm/unaligned.h> -#include "fsl_otg.h" +#include "phy-fsl-usb.h" #define DRIVER_VERSION "Rev. 1.55" #define DRIVER_AUTHOR "Jerry Huang/Li Yang" @@ -361,28 +361,18 @@ int fsl_otg_init_timers(struct otg_fsm *fsm) void fsl_otg_uninit_timers(void) { /* FSM used timers */ - if (a_wait_vrise_tmr != NULL) - kfree(a_wait_vrise_tmr); - if (a_wait_bcon_tmr != NULL) - kfree(a_wait_bcon_tmr); - if (a_aidl_bdis_tmr != NULL) - kfree(a_aidl_bdis_tmr); - if (b_ase0_brst_tmr != NULL) - kfree(b_ase0_brst_tmr); - if (b_se0_srp_tmr != NULL) - kfree(b_se0_srp_tmr); - if (b_srp_fail_tmr != NULL) - kfree(b_srp_fail_tmr); - if (a_wait_enum_tmr != NULL) - kfree(a_wait_enum_tmr); + kfree(a_wait_vrise_tmr); + kfree(a_wait_bcon_tmr); + kfree(a_aidl_bdis_tmr); + kfree(b_ase0_brst_tmr); + kfree(b_se0_srp_tmr); + kfree(b_srp_fail_tmr); + kfree(a_wait_enum_tmr); /* device driver used timers */ - if (b_srp_wait_tmr != NULL) - kfree(b_srp_wait_tmr); - if (b_data_pulse_tmr != NULL) - kfree(b_data_pulse_tmr); - if (b_vbus_pulse_tmr != NULL) - kfree(b_vbus_pulse_tmr); + kfree(b_srp_wait_tmr); + kfree(b_data_pulse_tmr); + kfree(b_vbus_pulse_tmr); } /* Add timer to timer list */ @@ -1002,7 +992,7 @@ static int show_fsl_usb2_otg_state(struct device *dev, /* State */ t = scnprintf(next, size, "OTG state: %s\n\n", - otg_state_string(fsl_otg_dev->phy.state)); + usb_otg_state_string(fsl_otg_dev->phy.state)); size -= t; next += t; diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/phy/phy-fsl-usb.h index ca266280895d..ca266280895d 100644 --- a/drivers/usb/otg/fsl_otg.h +++ b/drivers/usb/phy/phy-fsl-usb.h diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/phy/phy-fsm-usb.c index ade131a8ae5e..c520b3548e7c 100644 --- a/drivers/usb/otg/otg_fsm.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -29,7 +29,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/otg.h> -#include "otg_fsm.h" +#include "phy-otg-fsm.h" /* Change USB protocol when there is a protocol change */ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) @@ -119,7 +119,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) state_changed = 1; if (fsm->otg->phy->state == new_state) return 0; - VDBG("Set state: %s\n", otg_state_string(new_state)); + VDBG("Set state: %s\n", usb_otg_state_string(new_state)); otg_leave_state(fsm, fsm->otg->phy->state); switch (new_state) { case OTG_STATE_B_IDLE: diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/phy/phy-fsm-usb.h index c30a2e1d9e46..c30a2e1d9e46 100644 --- a/drivers/usb/otg/otg_fsm.h +++ b/drivers/usb/phy/phy-fsm-usb.h diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index a7d4ac591982..4c76074e518d 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -61,6 +61,7 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) { struct regulator *vbus_draw = gpio_vbus->vbus_draw; int enabled; + int ret; if (!vbus_draw) return; @@ -69,12 +70,16 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) if (mA) { regulator_set_current_limit(vbus_draw, 0, 1000 * mA); if (!enabled) { - regulator_enable(vbus_draw); + ret = regulator_enable(vbus_draw); + if (ret < 0) + return; gpio_vbus->vbus_draw_enabled = 1; } } else { if (enabled) { - regulator_disable(vbus_draw); + ret = regulator_disable(vbus_draw); + if (ret < 0) + return; gpio_vbus->vbus_draw_enabled = 0; } } diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/phy/phy-isp1301-omap.c index af9cb11626b2..ae481afcb3ec 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -236,7 +236,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) static inline const char *state_name(struct isp1301 *isp) { - return otg_state_string(isp->phy.state); + return usb_otg_state_string(isp->phy.state); } /*-------------------------------------------------------------------------*/ @@ -481,7 +481,7 @@ static void check_state(struct isp1301 *isp, const char *tag) if (isp->phy.state == state && !extra) return; pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, - otg_state_string(state), fsm, state_name(isp), + usb_otg_state_string(state), fsm, state_name(isp), omap_readl(OTG_CTRL)); } @@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat) if (state != isp->phy.state) pr_debug(" isp, %s -> %s\n", - otg_state_string(state), state_name(isp)); + usb_otg_state_string(state), state_name(isp)); #ifdef CONFIG_USB_OTG /* update the OTG controller state to match the isp1301; may @@ -1212,7 +1212,7 @@ static void isp1301_release(struct device *dev) static struct isp1301 *the_transceiver; -static int __exit isp1301_remove(struct i2c_client *i2c) +static int isp1301_remove(struct i2c_client *i2c) { struct isp1301 *isp; @@ -1634,7 +1634,7 @@ static struct i2c_driver isp1301_driver = { .name = "isp1301_omap", }, .probe = isp1301_probe, - .remove = __exit_p(isp1301_remove), + .remove = isp1301_remove, .id_table = isp1301_id, }; diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c new file mode 100644 index 000000000000..225ae6c97eeb --- /dev/null +++ b/drivers/usb/phy/phy-isp1301.c @@ -0,0 +1,162 @@ +/* + * NXP ISP1301 USB transceiver driver + * + * Copyright (C) 2012 Roland Stigge + * + * Author: Roland Stigge <stigge@antcom.de> + * + * 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. + */ + +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/i2c.h> +#include <linux/usb/phy.h> +#include <linux/usb/isp1301.h> + +#define DRV_NAME "isp1301" + +struct isp1301 { + struct usb_phy phy; + struct mutex mutex; + + struct i2c_client *client; +}; + +#define phy_to_isp(p) (container_of((p), struct isp1301, phy)) + +static const struct i2c_device_id isp1301_id[] = { + { "isp1301", 0 }, + { } +}; + +static struct i2c_client *isp1301_i2c_client; + +static int __isp1301_write(struct isp1301 *isp, u8 reg, u8 value, u8 clear) +{ + return i2c_smbus_write_byte_data(isp->client, reg | clear, value); +} + +static int isp1301_write(struct isp1301 *isp, u8 reg, u8 value) +{ + return __isp1301_write(isp, reg, value, 0); +} + +static int isp1301_clear(struct isp1301 *isp, u8 reg, u8 value) +{ + return __isp1301_write(isp, reg, value, ISP1301_I2C_REG_CLEAR_ADDR); +} + +static int isp1301_phy_init(struct usb_phy *phy) +{ + struct isp1301 *isp = phy_to_isp(phy); + + /* Disable transparent UART mode first */ + isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_UART_EN); + isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_1, ~MC1_SPEED_REG); + isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG); + isp1301_clear(isp, ISP1301_I2C_MODE_CONTROL_2, ~0); + isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_PSW_EN + | MC2_SPD_SUSP_CTRL)); + + isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, ~0); + isp1301_write(isp, ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0); + isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLDOWN + | OTG1_DP_PULLDOWN)); + isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, (OTG1_DM_PULLUP + | OTG1_DP_PULLUP)); + + /* mask all interrupts */ + isp1301_clear(isp, ISP1301_I2C_INTERRUPT_LATCH, ~0); + isp1301_clear(isp, ISP1301_I2C_INTERRUPT_FALLING, ~0); + isp1301_clear(isp, ISP1301_I2C_INTERRUPT_RISING, ~0); + + return 0; +} + +static int isp1301_phy_set_vbus(struct usb_phy *phy, int on) +{ + struct isp1301 *isp = phy_to_isp(phy); + + if (on) + isp1301_write(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); + else + isp1301_clear(isp, ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); + + return 0; +} + +static int isp1301_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct isp1301 *isp; + struct usb_phy *phy; + + isp = devm_kzalloc(&client->dev, sizeof(*isp), GFP_KERNEL); + if (!isp) + return -ENOMEM; + + isp->client = client; + mutex_init(&isp->mutex); + + phy = &isp->phy; + phy->label = DRV_NAME; + phy->init = isp1301_phy_init; + phy->set_vbus = isp1301_phy_set_vbus; + phy->type = USB_PHY_TYPE_USB2; + + i2c_set_clientdata(client, isp); + usb_add_phy_dev(phy); + + isp1301_i2c_client = client; + + return 0; +} + +static int isp1301_remove(struct i2c_client *client) +{ + struct isp1301 *isp = i2c_get_clientdata(client); + + usb_remove_phy(&isp->phy); + isp1301_i2c_client = NULL; + + return 0; +} + +static struct i2c_driver isp1301_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = isp1301_probe, + .remove = isp1301_remove, + .id_table = isp1301_id, +}; + +module_i2c_driver(isp1301_driver); + +static int match(struct device *dev, void *data) +{ + struct device_node *node = (struct device_node *)data; + return (dev->of_node == node) && + (dev->driver == &isp1301_driver.driver); +} + +struct i2c_client *isp1301_get_client(struct device_node *node) +{ + if (node) { /* reference of ISP1301 I2C node via DT */ + struct device *dev = bus_find_device(&i2c_bus_type, NULL, + node, match); + if (!dev) + return NULL; + return to_i2c_client(dev); + } else { /* non-DT: only one ISP1301 chip supported */ + return isp1301_i2c_client; + } +} +EXPORT_SYMBOL_GPL(isp1301_get_client); + +MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); +MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/phy/phy-msm-usb.c index 749fbf41fb6f..749fbf41fb6f 100644 --- a/drivers/usb/otg/msm_otg.c +++ b/drivers/usb/phy/phy-msm-usb.c diff --git a/drivers/usb/phy/mv_u3d_phy.c b/drivers/usb/phy/phy-mv-u3d-usb.c index 9d8599122aa9..f7838a43347c 100644 --- a/drivers/usb/phy/mv_u3d_phy.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -15,7 +15,7 @@ #include <linux/usb/otg.h> #include <linux/platform_data/mv_usb.h> -#include "mv_u3d_phy.h" +#include "phy-mv-u3d-usb.h" /* * struct mv_u3d_phy - transceiver driver state @@ -313,7 +313,7 @@ err: return ret; } -static int __exit mv_u3d_phy_remove(struct platform_device *pdev) +static int mv_u3d_phy_remove(struct platform_device *pdev) { struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev); diff --git a/drivers/usb/phy/mv_u3d_phy.h b/drivers/usb/phy/phy-mv-u3d-usb.h index 2a658cb9a527..2a658cb9a527 100644 --- a/drivers/usb/phy/mv_u3d_phy.h +++ b/drivers/usb/phy/phy-mv-u3d-usb.h diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/phy/phy-mv-usb.c index b6a9be31133b..c987bbe27851 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -27,7 +27,7 @@ #include <linux/usb/hcd.h> #include <linux/platform_data/mv_usb.h> -#include "mv_otg.h" +#include "phy-mv-usb.h" #define DRIVER_DESC "Marvell USB OTG transceiver driver" #define DRIVER_VERSION "Jan 20, 2010" @@ -237,18 +237,12 @@ static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) static void otg_clock_enable(struct mv_otg *mvotg) { - unsigned int i; - - for (i = 0; i < mvotg->clknum; i++) - clk_prepare_enable(mvotg->clk[i]); + clk_prepare_enable(mvotg->clk); } static void otg_clock_disable(struct mv_otg *mvotg) { - unsigned int i; - - for (i = 0; i < mvotg->clknum; i++) - clk_disable_unprepare(mvotg->clk[i]); + clk_disable_unprepare(mvotg->clk); } static int mv_otg_enable_internal(struct mv_otg *mvotg) @@ -684,16 +678,14 @@ static int mv_otg_probe(struct platform_device *pdev) struct mv_otg *mvotg; struct usb_otg *otg; struct resource *r; - int retval = 0, clk_i, i; - size_t size; + int retval = 0, i; if (pdata == NULL) { dev_err(&pdev->dev, "failed to get platform data\n"); return -ENODEV; } - size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum; - mvotg = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + mvotg = devm_kzalloc(&pdev->dev, sizeof(*mvotg), GFP_KERNEL); if (!mvotg) { dev_err(&pdev->dev, "failed to allocate memory!\n"); return -ENOMEM; @@ -708,15 +700,9 @@ static int mv_otg_probe(struct platform_device *pdev) mvotg->pdev = pdev; mvotg->pdata = pdata; - mvotg->clknum = pdata->clknum; - for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) { - mvotg->clk[clk_i] = devm_clk_get(&pdev->dev, - pdata->clkname[clk_i]); - if (IS_ERR(mvotg->clk[clk_i])) { - retval = PTR_ERR(mvotg->clk[clk_i]); - return retval; - } - } + mvotg->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mvotg->clk)) + return PTR_ERR(mvotg->clk); mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); if (!mvotg->qwork) { diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/phy/phy-mv-usb.h index 8a9e351b36ba..551da6eb0ba8 100644 --- a/drivers/usb/otg/mv_otg.h +++ b/drivers/usb/phy/phy-mv-usb.h @@ -158,8 +158,7 @@ struct mv_otg { unsigned int active; unsigned int clock_gating; - unsigned int clknum; - struct clk *clk[0]; + struct clk *clk; }; #endif diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/phy/phy-mxs-usb.c index b0d9f119c749..9d4381e64d51 100644 --- a/drivers/usb/otg/mxs-phy.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -48,12 +48,12 @@ static void mxs_phy_hw_init(struct mxs_phy *mxs_phy) stmp_reset_block(base + HW_USBPHY_CTRL); /* Power up the PHY */ - writel_relaxed(0, base + HW_USBPHY_PWD); + writel(0, base + HW_USBPHY_PWD); /* enable FS/LS device */ - writel_relaxed(BM_USBPHY_CTRL_ENUTMILEVEL2 | - BM_USBPHY_CTRL_ENUTMILEVEL3, - base + HW_USBPHY_CTRL_SET); + writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | + BM_USBPHY_CTRL_ENUTMILEVEL3, + base + HW_USBPHY_CTRL_SET); } static int mxs_phy_init(struct usb_phy *phy) @@ -70,8 +70,8 @@ static void mxs_phy_shutdown(struct usb_phy *phy) { struct mxs_phy *mxs_phy = to_mxs_phy(phy); - writel_relaxed(BM_USBPHY_CTRL_CLKGATE, - phy->io_priv + HW_USBPHY_CTRL_SET); + writel(BM_USBPHY_CTRL_CLKGATE, + phy->io_priv + HW_USBPHY_CTRL_SET); clk_disable_unprepare(mxs_phy->clk); } @@ -81,15 +81,15 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend) struct mxs_phy *mxs_phy = to_mxs_phy(x); if (suspend) { - writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD); - writel_relaxed(BM_USBPHY_CTRL_CLKGATE, - x->io_priv + HW_USBPHY_CTRL_SET); + writel(0xffffffff, x->io_priv + HW_USBPHY_PWD); + writel(BM_USBPHY_CTRL_CLKGATE, + x->io_priv + HW_USBPHY_CTRL_SET); clk_disable_unprepare(mxs_phy->clk); } else { clk_prepare_enable(mxs_phy->clk); - writel_relaxed(BM_USBPHY_CTRL_CLKGATE, - x->io_priv + HW_USBPHY_CTRL_CLR); - writel_relaxed(0, x->io_priv + HW_USBPHY_PWD); + writel(BM_USBPHY_CTRL_CLKGATE, + x->io_priv + HW_USBPHY_CTRL_CLR); + writel(0, x->io_priv + HW_USBPHY_PWD); } return 0; @@ -102,8 +102,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy, (speed == USB_SPEED_HIGH) ? "high" : "non-high"); if (speed == USB_SPEED_HIGH) - writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, - phy->io_priv + HW_USBPHY_CTRL_SET); + writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_SET); return 0; } @@ -115,8 +115,8 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy, (speed == USB_SPEED_HIGH) ? "high" : "non-high"); if (speed == USB_SPEED_HIGH) - writel_relaxed(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, - phy->io_priv + HW_USBPHY_CTRL_CLR); + writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + phy->io_priv + HW_USBPHY_CTRL_CLR); return 0; } @@ -127,6 +127,7 @@ static int mxs_phy_probe(struct platform_device *pdev) void __iomem *base; struct clk *clk; struct mxs_phy *mxs_phy; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -166,11 +167,19 @@ static int mxs_phy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &mxs_phy->phy); + ret = usb_add_phy_dev(&mxs_phy->phy); + if (ret) + return ret; + return 0; } static int mxs_phy_remove(struct platform_device *pdev) { + struct mxs_phy *mxs_phy = platform_get_drvdata(pdev); + + usb_remove_phy(&mxs_phy->phy); + platform_set_drvdata(pdev, NULL); return 0; diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/phy/phy-nop.c index a3ce24b94a73..2b10cc969bbb 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/phy/phy-nop.c @@ -32,10 +32,16 @@ #include <linux/usb/otg.h> #include <linux/usb/nop-usb-xceiv.h> #include <linux/slab.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> struct nop_usb_xceiv { - struct usb_phy phy; - struct device *dev; + struct usb_phy phy; + struct device *dev; + struct clk *clk; + struct regulator *vcc; + struct regulator *reset; }; static struct platform_device *pd; @@ -64,6 +70,46 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) return 0; } +static int nop_init(struct usb_phy *phy) +{ + struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + + if (!IS_ERR(nop->vcc)) { + if (regulator_enable(nop->vcc)) + dev_err(phy->dev, "Failed to enable power\n"); + } + + if (!IS_ERR(nop->clk)) + clk_enable(nop->clk); + + if (!IS_ERR(nop->reset)) { + /* De-assert RESET */ + if (regulator_enable(nop->reset)) + dev_err(phy->dev, "Failed to de-assert reset\n"); + } + + return 0; +} + +static void nop_shutdown(struct usb_phy *phy) +{ + struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); + + if (!IS_ERR(nop->reset)) { + /* Assert RESET */ + if (regulator_disable(nop->reset)) + dev_err(phy->dev, "Failed to assert reset\n"); + } + + if (!IS_ERR(nop->clk)) + clk_disable(nop->clk); + + if (!IS_ERR(nop->vcc)) { + if (regulator_disable(nop->vcc)) + dev_err(phy->dev, "Failed to disable power\n"); + } +} + static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) { if (!otg) @@ -95,39 +141,96 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) static int nop_usb_xceiv_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct nop_usb_xceiv_platform_data *pdata = pdev->dev.platform_data; struct nop_usb_xceiv *nop; enum usb_phy_type type = USB_PHY_TYPE_USB2; int err; + u32 clk_rate = 0; + bool needs_vcc = false; + bool needs_reset = false; - nop = kzalloc(sizeof *nop, GFP_KERNEL); + nop = devm_kzalloc(&pdev->dev, sizeof(*nop), GFP_KERNEL); if (!nop) return -ENOMEM; - nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL); - if (!nop->phy.otg) { - kfree(nop); + nop->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*nop->phy.otg), + GFP_KERNEL); + if (!nop->phy.otg) return -ENOMEM; - } - if (pdata) + if (dev->of_node) { + struct device_node *node = dev->of_node; + + if (of_property_read_u32(node, "clock-frequency", &clk_rate)) + clk_rate = 0; + + needs_vcc = of_property_read_bool(node, "vcc-supply"); + needs_reset = of_property_read_bool(node, "reset-supply"); + + } else if (pdata) { type = pdata->type; + clk_rate = pdata->clk_rate; + needs_vcc = pdata->needs_vcc; + needs_reset = pdata->needs_reset; + } + + nop->clk = devm_clk_get(&pdev->dev, "main_clk"); + if (IS_ERR(nop->clk)) { + dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", + PTR_ERR(nop->clk)); + } + + if (!IS_ERR(nop->clk) && clk_rate) { + err = clk_set_rate(nop->clk, clk_rate); + if (err) { + dev_err(&pdev->dev, "Error setting clock rate\n"); + return err; + } + } + + if (!IS_ERR(nop->clk)) { + err = clk_prepare(nop->clk); + if (err) { + dev_err(&pdev->dev, "Error preparing clock\n"); + return err; + } + } + + nop->vcc = devm_regulator_get(&pdev->dev, "vcc"); + if (IS_ERR(nop->vcc)) { + dev_dbg(&pdev->dev, "Error getting vcc regulator: %ld\n", + PTR_ERR(nop->vcc)); + if (needs_vcc) + return -EPROBE_DEFER; + } + + nop->reset = devm_regulator_get(&pdev->dev, "reset"); + if (IS_ERR(nop->reset)) { + dev_dbg(&pdev->dev, "Error getting reset regulator: %ld\n", + PTR_ERR(nop->reset)); + if (needs_reset) + return -EPROBE_DEFER; + } nop->dev = &pdev->dev; nop->phy.dev = nop->dev; nop->phy.label = "nop-xceiv"; nop->phy.set_suspend = nop_set_suspend; + nop->phy.init = nop_init; + nop->phy.shutdown = nop_shutdown; nop->phy.state = OTG_STATE_UNDEFINED; + nop->phy.type = type; nop->phy.otg->phy = &nop->phy; nop->phy.otg->set_host = nop_set_host; nop->phy.otg->set_peripheral = nop_set_peripheral; - err = usb_add_phy(&nop->phy, type); + err = usb_add_phy_dev(&nop->phy); if (err) { dev_err(&pdev->dev, "can't register transceiver, err: %d\n", err); - goto exit; + goto err_add; } platform_set_drvdata(pdev, nop); @@ -135,9 +238,10 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); return 0; -exit: - kfree(nop->phy.otg); - kfree(nop); + +err_add: + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); return err; } @@ -145,21 +249,30 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev) { struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); + if (!IS_ERR(nop->clk)) + clk_unprepare(nop->clk); + usb_remove_phy(&nop->phy); platform_set_drvdata(pdev, NULL); - kfree(nop->phy.otg); - kfree(nop); return 0; } +static const struct of_device_id nop_xceiv_dt_ids[] = { + { .compatible = "usb-nop-xceiv" }, + { } +}; + +MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); + static struct platform_driver nop_usb_xceiv_driver = { .probe = nop_usb_xceiv_probe, .remove = nop_usb_xceiv_remove, .driver = { .name = "nop_usb_xceiv", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(nop_xceiv_dt_ids), }, }; diff --git a/drivers/usb/phy/omap-control-usb.c b/drivers/usb/phy/phy-omap-control.c index 1419ceda9759..1419ceda9759 100644 --- a/drivers/usb/phy/omap-control-usb.c +++ b/drivers/usb/phy/phy-omap-control.c diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c index 844ab68f08d0..844ab68f08d0 100644 --- a/drivers/usb/phy/omap-usb2.c +++ b/drivers/usb/phy/phy-omap-usb2.c diff --git a/drivers/usb/phy/omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c index a6e60b1e102e..a6e60b1e102e 100644 --- a/drivers/usb/phy/omap-usb3.c +++ b/drivers/usb/phy/phy-omap-usb3.c diff --git a/drivers/usb/phy/rcar-phy.c b/drivers/usb/phy/phy-rcar-usb.c index a35681b0c501..a35681b0c501 100644 --- a/drivers/usb/phy/rcar-phy.c +++ b/drivers/usb/phy/phy-rcar-usb.c diff --git a/drivers/usb/phy/phy-samsung-usb.c b/drivers/usb/phy/phy-samsung-usb.c new file mode 100644 index 000000000000..7b118ee5f5e4 --- /dev/null +++ b/drivers/usb/phy/phy-samsung-usb.c @@ -0,0 +1,236 @@ +/* linux/drivers/usb/phy/phy-samsung-usb.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Praveen Paneri <p.paneri@samsung.com> + * + * Samsung USB-PHY helper driver with common function calls; + * interacts with Samsung USB 2.0 PHY controller driver and later + * with Samsung USB 3.0 PHY driver. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/usb/samsung_usb_phy.h> + +#include "phy-samsung-usb.h" + +int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) +{ + struct device_node *usbphy_sys; + + /* Getting node for system controller interface for usb-phy */ + usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys"); + if (!usbphy_sys) { + dev_err(sphy->dev, "No sys-controller interface for usb-phy\n"); + return -ENODEV; + } + + sphy->pmuregs = of_iomap(usbphy_sys, 0); + + if (sphy->pmuregs == NULL) { + dev_err(sphy->dev, "Can't get usb-phy pmu control register\n"); + goto err0; + } + + sphy->sysreg = of_iomap(usbphy_sys, 1); + + /* + * Not returning error code here, since this situation is not fatal. + * Few SoCs may not have this switch available + */ + if (sphy->sysreg == NULL) + dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n"); + + of_node_put(usbphy_sys); + + return 0; + +err0: + of_node_put(usbphy_sys); + return -ENXIO; +} +EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt); + +/* + * Set isolation here for phy. + * Here 'on = true' would mean USB PHY block is isolated, hence + * de-activated and vice-versa. + */ +void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on) +{ + void __iomem *reg = NULL; + u32 reg_val; + u32 en_mask = 0; + + if (!sphy->pmuregs) { + dev_warn(sphy->dev, "Can't set pmu isolation\n"); + return; + } + + switch (sphy->drv_data->cpu_type) { + case TYPE_S3C64XX: + /* + * Do nothing: We will add here once S3C64xx goes for DT support + */ + break; + case TYPE_EXYNOS4210: + /* + * Fall through since exynos4210 and exynos5250 have similar + * register architecture: two separate registers for host and + * device phy control with enable bit at position 0. + */ + case TYPE_EXYNOS5250: + if (sphy->phy_type == USB_PHY_TYPE_DEVICE) { + reg = sphy->pmuregs + + sphy->drv_data->devphy_reg_offset; + en_mask = sphy->drv_data->devphy_en_mask; + } else if (sphy->phy_type == USB_PHY_TYPE_HOST) { + reg = sphy->pmuregs + + sphy->drv_data->hostphy_reg_offset; + en_mask = sphy->drv_data->hostphy_en_mask; + } + break; + default: + dev_err(sphy->dev, "Invalid SoC type\n"); + return; + } + + reg_val = readl(reg); + + if (on) + reg_val &= ~en_mask; + else + reg_val |= en_mask; + + writel(reg_val, reg); +} +EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation); + +/* + * Configure the mode of working of usb-phy here: HOST/DEVICE. + */ +void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy) +{ + u32 reg; + + if (!sphy->sysreg) { + dev_warn(sphy->dev, "Can't configure specified phy mode\n"); + return; + } + + reg = readl(sphy->sysreg); + + if (sphy->phy_type == USB_PHY_TYPE_DEVICE) + reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK; + else if (sphy->phy_type == USB_PHY_TYPE_HOST) + reg |= EXYNOS_USB20PHY_CFG_HOST_LINK; + + writel(reg, sphy->sysreg); +} +EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel); + +/* + * PHYs are different for USB Device and USB Host. + * This make sure that correct PHY type is selected before + * any operation on PHY. + */ +int samsung_usbphy_set_type(struct usb_phy *phy, + enum samsung_usb_phy_type phy_type) +{ + struct samsung_usbphy *sphy = phy_to_sphy(phy); + + sphy->phy_type = phy_type; + + return 0; +} +EXPORT_SYMBOL_GPL(samsung_usbphy_set_type); + +/* + * Returns reference clock frequency selection value + */ +int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy) +{ + struct clk *ref_clk; + int refclk_freq = 0; + + /* + * In exynos5250 USB host and device PHY use + * external crystal clock XXTI + */ + if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) + ref_clk = devm_clk_get(sphy->dev, "ext_xtal"); + else + ref_clk = devm_clk_get(sphy->dev, "xusbxti"); + if (IS_ERR(ref_clk)) { + dev_err(sphy->dev, "Failed to get reference clock\n"); + return PTR_ERR(ref_clk); + } + + if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) { + /* set clock frequency for PLL */ + switch (clk_get_rate(ref_clk)) { + case 9600 * KHZ: + refclk_freq = FSEL_CLKSEL_9600K; + break; + case 10 * MHZ: + refclk_freq = FSEL_CLKSEL_10M; + break; + case 12 * MHZ: + refclk_freq = FSEL_CLKSEL_12M; + break; + case 19200 * KHZ: + refclk_freq = FSEL_CLKSEL_19200K; + break; + case 20 * MHZ: + refclk_freq = FSEL_CLKSEL_20M; + break; + case 50 * MHZ: + refclk_freq = FSEL_CLKSEL_50M; + break; + case 24 * MHZ: + default: + /* default reference clock */ + refclk_freq = FSEL_CLKSEL_24M; + break; + } + } else { + switch (clk_get_rate(ref_clk)) { + case 12 * MHZ: + refclk_freq = PHYCLK_CLKSEL_12M; + break; + case 24 * MHZ: + refclk_freq = PHYCLK_CLKSEL_24M; + break; + case 48 * MHZ: + refclk_freq = PHYCLK_CLKSEL_48M; + break; + default: + if (sphy->drv_data->cpu_type == TYPE_S3C64XX) + refclk_freq = PHYCLK_CLKSEL_48M; + else + refclk_freq = PHYCLK_CLKSEL_24M; + break; + } + } + clk_put(ref_clk); + + return refclk_freq; +} +EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq); diff --git a/drivers/usb/phy/phy-samsung-usb.h b/drivers/usb/phy/phy-samsung-usb.h new file mode 100644 index 000000000000..70a9cae5e37f --- /dev/null +++ b/drivers/usb/phy/phy-samsung-usb.h @@ -0,0 +1,327 @@ +/* linux/drivers/usb/phy/phy-samsung-usb.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung USB-PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and + * OHCI-EXYNOS controllers. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/usb/phy.h> + +/* Register definitions */ + +#define SAMSUNG_PHYPWR (0x00) + +#define PHYPWR_NORMAL_MASK (0x19 << 0) +#define PHYPWR_OTG_DISABLE (0x1 << 4) +#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3) +#define PHYPWR_FORCE_SUSPEND (0x1 << 1) +/* For Exynos4 */ +#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0) +#define PHYPWR_SLEEP_PHY0 (0x1 << 5) + +#define SAMSUNG_PHYCLK (0x04) + +#define PHYCLK_MODE_USB11 (0x1 << 6) +#define PHYCLK_EXT_OSC (0x1 << 5) +#define PHYCLK_COMMON_ON_N (0x1 << 4) +#define PHYCLK_ID_PULL (0x1 << 2) +#define PHYCLK_CLKSEL_MASK (0x3 << 0) +#define PHYCLK_CLKSEL_48M (0x0 << 0) +#define PHYCLK_CLKSEL_12M (0x2 << 0) +#define PHYCLK_CLKSEL_24M (0x3 << 0) + +#define SAMSUNG_RSTCON (0x08) + +#define RSTCON_PHYLINK_SWRST (0x1 << 2) +#define RSTCON_HLINK_SWRST (0x1 << 1) +#define RSTCON_SWRST (0x1 << 0) + +/* EXYNOS5 */ +#define EXYNOS5_PHY_HOST_CTRL0 (0x00) + +#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) + +#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19) +#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19) +#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19) +#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19) + +#define HOST_CTRL0_FSEL_MASK (0x7 << 16) +#define HOST_CTRL0_FSEL(_x) ((_x) << 16) + +#define FSEL_CLKSEL_50M (0x7) +#define FSEL_CLKSEL_24M (0x5) +#define FSEL_CLKSEL_20M (0x4) +#define FSEL_CLKSEL_19200K (0x3) +#define FSEL_CLKSEL_12M (0x2) +#define FSEL_CLKSEL_10M (0x1) +#define FSEL_CLKSEL_9600K (0x0) + +#define HOST_CTRL0_TESTBURNIN (0x1 << 11) +#define HOST_CTRL0_RETENABLE (0x1 << 10) +#define HOST_CTRL0_COMMONON_N (0x1 << 9) +#define HOST_CTRL0_SIDDQ (0x1 << 6) +#define HOST_CTRL0_FORCESLEEP (0x1 << 5) +#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) +#define HOST_CTRL0_WORDINTERFACE (0x1 << 3) +#define HOST_CTRL0_UTMISWRST (0x1 << 2) +#define HOST_CTRL0_LINKSWRST (0x1 << 1) +#define HOST_CTRL0_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_TUNE0 (0x04) + +#define EXYNOS5_PHY_HSIC_CTRL1 (0x10) + +#define EXYNOS5_PHY_HSIC_TUNE1 (0x14) + +#define EXYNOS5_PHY_HSIC_CTRL2 (0x20) + +#define EXYNOS5_PHY_HSIC_TUNE2 (0x24) + +#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23) +#define HSIC_CTRL_REFCLKSEL (0x2 << 23) + +#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16) +#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16) +#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16) +#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16) +#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16) +#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16) +#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16) + +#define HSIC_CTRL_SIDDQ (0x1 << 6) +#define HSIC_CTRL_FORCESLEEP (0x1 << 5) +#define HSIC_CTRL_FORCESUSPEND (0x1 << 4) +#define HSIC_CTRL_WORDINTERFACE (0x1 << 3) +#define HSIC_CTRL_UTMISWRST (0x1 << 2) +#define HSIC_CTRL_PHYSWRST (0x1 << 0) + +#define EXYNOS5_PHY_HOST_EHCICTRL (0x30) + +#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29) +#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28) +#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27) +#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26) + +#define EXYNOS5_PHY_HOST_OHCICTRL (0x34) + +#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3) +#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2) +#define HOST_OHCICTRL_CNTSEL (0x1 << 1) +#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0) + +#define EXYNOS5_PHY_OTG_SYS (0x38) + +#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14) +#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13) +#define OTG_SYS_PHY0_SWRST (0x1 << 12) + +#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9) +#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9) +#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9) +#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9) + +#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8) +#define OTG_SYS_COMMON_ON (0x1 << 7) + +#define OTG_SYS_FSEL_MASK (0x7 << 4) +#define OTG_SYS_FSEL(_x) ((_x) << 4) + +#define OTG_SYS_FORCESLEEP (0x1 << 3) +#define OTG_SYS_OTGDISABLE (0x1 << 2) +#define OTG_SYS_SIDDQ_UOTG (0x1 << 1) +#define OTG_SYS_FORCESUSPEND (0x1 << 0) + +#define EXYNOS5_PHY_OTG_TUNE (0x40) + +/* EXYNOS5: USB 3.0 DRD */ +#define EXYNOS5_DRD_LINKSYSTEM (0x04) + +#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) +#define LINKSYSTEM_FLADJ(_x) ((_x) << 1) +#define LINKSYSTEM_XHCI_VERSION_CONTROL (0x1 << 27) + +#define EXYNOS5_DRD_PHYUTMI (0x08) + +#define PHYUTMI_OTGDISABLE (0x1 << 6) +#define PHYUTMI_FORCESUSPEND (0x1 << 1) +#define PHYUTMI_FORCESLEEP (0x1 << 0) + +#define EXYNOS5_DRD_PHYPIPE (0x0c) + +#define EXYNOS5_DRD_PHYCLKRST (0x10) + +#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23) +#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23) + +#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21) +#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21) + +#define PHYCLKRST_SSC_EN (0x1 << 20) +#define PHYCLKRST_REF_SSP_EN (0x1 << 19) +#define PHYCLKRST_REF_CLKDIV2 (0x1 << 18) + +#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x02 << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11) +#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11) + +#define PHYCLKRST_FSEL_MASK (0x3f << 5) +#define PHYCLKRST_FSEL(_x) ((_x) << 5) +#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5) +#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5) +#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5) +#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5) + +#define PHYCLKRST_RETENABLEN (0x1 << 4) + +#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) +#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2) +#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2) + +#define PHYCLKRST_PORTRESET (0x1 << 1) +#define PHYCLKRST_COMMONONN (0x1 << 0) + +#define EXYNOS5_DRD_PHYREG0 (0x14) +#define EXYNOS5_DRD_PHYREG1 (0x18) + +#define EXYNOS5_DRD_PHYPARAM0 (0x1c) + +#define PHYPARAM0_REF_USE_PAD (0x1 << 31) +#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26) +#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26) + +#define EXYNOS5_DRD_PHYPARAM1 (0x20) + +#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0) +#define PHYPARAM1_PCS_TXDEEMPH (0x1c) + +#define EXYNOS5_DRD_PHYTERM (0x24) + +#define EXYNOS5_DRD_PHYTEST (0x28) + +#define PHYTEST_POWERDOWN_SSP (0x1 << 3) +#define PHYTEST_POWERDOWN_HSP (0x1 << 2) + +#define EXYNOS5_DRD_PHYADP (0x2c) + +#define EXYNOS5_DRD_PHYBATCHG (0x30) + +#define PHYBATCHG_UTMI_CLKSEL (0x1 << 2) + +#define EXYNOS5_DRD_PHYRESUME (0x34) +#define EXYNOS5_DRD_LINKPORT (0x44) + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#ifndef KHZ +#define KHZ (1000) +#endif + +#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4) +#define S3C64XX_USBPHY_ENABLE (0x1 << 16) +#define EXYNOS_USBPHY_ENABLE (0x1 << 0) +#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0) + +enum samsung_cpu_type { + TYPE_S3C64XX, + TYPE_EXYNOS4210, + TYPE_EXYNOS5250, +}; + +/* + * struct samsung_usbphy_drvdata - driver data for various SoC variants + * @cpu_type: machine identifier + * @devphy_en_mask: device phy enable mask for PHY CONTROL register + * @hostphy_en_mask: host phy enable mask for PHY CONTROL register + * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from + * mapped address of system controller. + * @hostphy_reg_offset: offset to HOST PHY CONTROL register from + * mapped address of system controller. + * + * Here we have a separate mask for device type phy. + * Having different masks for host and device type phy helps + * in setting independent masks in case of SoCs like S5PV210, + * in which PHY0 and PHY1 enable bits belong to same register + * placed at position 0 and 1 respectively. + * Although for newer SoCs like exynos these bits belong to + * different registers altogether placed at position 0. + */ +struct samsung_usbphy_drvdata { + int cpu_type; + int devphy_en_mask; + int hostphy_en_mask; + u32 devphy_reg_offset; + u32 hostphy_reg_offset; +}; + +/* + * struct samsung_usbphy - transceiver driver state + * @phy: transceiver structure + * @plat: platform data + * @dev: The parent device supplied to the probe function + * @clk: usb phy clock + * @regs: usb phy controller registers memory base + * @pmuregs: USB device PHY_CONTROL register memory base + * @sysreg: USB2.0 PHY_CFG register memory base + * @ref_clk_freq: reference clock frequency selection + * @drv_data: driver data available for different SoCs + * @phy_type: Samsung SoCs specific phy types: #HOST + * #DEVICE + * @phy_usage: usage count for phy + * @lock: lock for phy operations + */ +struct samsung_usbphy { + struct usb_phy phy; + struct samsung_usbphy_data *plat; + struct device *dev; + struct clk *clk; + void __iomem *regs; + void __iomem *pmuregs; + void __iomem *sysreg; + int ref_clk_freq; + const struct samsung_usbphy_drvdata *drv_data; + enum samsung_usb_phy_type phy_type; + atomic_t phy_usage; + spinlock_t lock; +}; + +#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) + +static const struct of_device_id samsung_usbphy_dt_match[]; + +static inline const struct samsung_usbphy_drvdata +*samsung_usbphy_get_driver_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(samsung_usbphy_dt_match, + pdev->dev.of_node); + return match->data; + } + + return (struct samsung_usbphy_drvdata *) + platform_get_device_id(pdev)->driver_data; +} + +extern int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy); +extern void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on); +extern void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy); +extern int samsung_usbphy_set_type(struct usb_phy *phy, + enum samsung_usb_phy_type phy_type); +extern int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy); diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c new file mode 100644 index 000000000000..45ffe036dacc --- /dev/null +++ b/drivers/usb/phy/phy-samsung-usb2.c @@ -0,0 +1,509 @@ +/* linux/drivers/usb/phy/phy-samsung-usb2.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Praveen Paneri <p.paneri@samsung.com> + * + * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and + * OHCI-EXYNOS controllers. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/usb/otg.h> +#include <linux/usb/samsung_usb_phy.h> +#include <linux/platform_data/samsung-usbphy.h> + +#include "phy-samsung-usb.h" + +static int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + if (!otg) + return -ENODEV; + + if (!otg->host) + otg->host = host; + + return 0; +} + +static bool exynos5_phyhost_is_on(void __iomem *regs) +{ + u32 reg; + + reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0); + + return !(reg & HOST_CTRL0_SIDDQ); +} + +static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phyclk = sphy->ref_clk_freq; + u32 phyhost; + u32 phyotg; + u32 phyhsic; + u32 ehcictrl; + u32 ohcictrl; + + /* + * phy_usage helps in keeping usage count for phy + * so that the first consumer enabling the phy is also + * the last consumer to disable it. + */ + + atomic_inc(&sphy->phy_usage); + + if (exynos5_phyhost_is_on(regs)) { + dev_info(sphy->dev, "Already power on PHY\n"); + return; + } + + /* Host configuration */ + phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); + + /* phy reference clock configuration */ + phyhost &= ~HOST_CTRL0_FSEL_MASK; + phyhost |= HOST_CTRL0_FSEL(phyclk); + + /* host phy reset */ + phyhost &= ~(HOST_CTRL0_PHYSWRST | + HOST_CTRL0_PHYSWRSTALL | + HOST_CTRL0_SIDDQ | + /* Enable normal mode of operation */ + HOST_CTRL0_FORCESUSPEND | + HOST_CTRL0_FORCESLEEP); + + /* Link reset */ + phyhost |= (HOST_CTRL0_LINKSWRST | + HOST_CTRL0_UTMISWRST | + /* COMMON Block configuration during suspend */ + HOST_CTRL0_COMMONON_N); + writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); + udelay(10); + phyhost &= ~(HOST_CTRL0_LINKSWRST | + HOST_CTRL0_UTMISWRST); + writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); + + /* OTG configuration */ + phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); + + /* phy reference clock configuration */ + phyotg &= ~OTG_SYS_FSEL_MASK; + phyotg |= OTG_SYS_FSEL(phyclk); + + /* Enable normal mode of operation */ + phyotg &= ~(OTG_SYS_FORCESUSPEND | + OTG_SYS_SIDDQ_UOTG | + OTG_SYS_FORCESLEEP | + OTG_SYS_REFCLKSEL_MASK | + /* COMMON Block configuration during suspend */ + OTG_SYS_COMMON_ON); + + /* OTG phy & link reset */ + phyotg |= (OTG_SYS_PHY0_SWRST | + OTG_SYS_LINKSWRST_UOTG | + OTG_SYS_PHYLINK_SWRESET | + OTG_SYS_OTGDISABLE | + /* Set phy refclk */ + OTG_SYS_REFCLKSEL_CLKCORE); + + writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); + udelay(10); + phyotg &= ~(OTG_SYS_PHY0_SWRST | + OTG_SYS_LINKSWRST_UOTG | + OTG_SYS_PHYLINK_SWRESET); + writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); + + /* HSIC phy configuration */ + phyhsic = (HSIC_CTRL_REFCLKDIV_12 | + HSIC_CTRL_REFCLKSEL | + HSIC_CTRL_PHYSWRST); + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); + udelay(10); + phyhsic &= ~HSIC_CTRL_PHYSWRST; + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); + + udelay(80); + + /* enable EHCI DMA burst */ + ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL); + ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN | + HOST_EHCICTRL_ENAINCR4 | + HOST_EHCICTRL_ENAINCR8 | + HOST_EHCICTRL_ENAINCR16); + writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL); + + /* set ohci_suspend_on_n */ + ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL); + ohcictrl |= HOST_OHCICTRL_SUSPLGCY; + writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL); +} + +static void samsung_usb2phy_enable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phypwr; + u32 phyclk; + u32 rstcon; + + /* set clock frequency for PLL */ + phyclk = sphy->ref_clk_freq; + phypwr = readl(regs + SAMSUNG_PHYPWR); + rstcon = readl(regs + SAMSUNG_RSTCON); + + switch (sphy->drv_data->cpu_type) { + case TYPE_S3C64XX: + phyclk &= ~PHYCLK_COMMON_ON_N; + phypwr &= ~PHYPWR_NORMAL_MASK; + rstcon |= RSTCON_SWRST; + break; + case TYPE_EXYNOS4210: + phypwr &= ~PHYPWR_NORMAL_MASK_PHY0; + rstcon |= RSTCON_SWRST; + default: + break; + } + + writel(phyclk, regs + SAMSUNG_PHYCLK); + /* Configure PHY0 for normal operation*/ + writel(phypwr, regs + SAMSUNG_PHYPWR); + /* reset all ports of PHY and Link */ + writel(rstcon, regs + SAMSUNG_RSTCON); + udelay(10); + rstcon &= ~RSTCON_SWRST; + writel(rstcon, regs + SAMSUNG_RSTCON); +} + +static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phyhost; + u32 phyotg; + u32 phyhsic; + + if (atomic_dec_return(&sphy->phy_usage) > 0) { + dev_info(sphy->dev, "still being used\n"); + return; + } + + phyhsic = (HSIC_CTRL_REFCLKDIV_12 | + HSIC_CTRL_REFCLKSEL | + HSIC_CTRL_SIDDQ | + HSIC_CTRL_FORCESLEEP | + HSIC_CTRL_FORCESUSPEND); + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); + writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); + + phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); + phyhost |= (HOST_CTRL0_SIDDQ | + HOST_CTRL0_FORCESUSPEND | + HOST_CTRL0_FORCESLEEP | + HOST_CTRL0_PHYSWRST | + HOST_CTRL0_PHYSWRSTALL); + writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); + + phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); + phyotg |= (OTG_SYS_FORCESUSPEND | + OTG_SYS_SIDDQ_UOTG | + OTG_SYS_FORCESLEEP); + writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); +} + +static void samsung_usb2phy_disable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phypwr; + + phypwr = readl(regs + SAMSUNG_PHYPWR); + + switch (sphy->drv_data->cpu_type) { + case TYPE_S3C64XX: + phypwr |= PHYPWR_NORMAL_MASK; + break; + case TYPE_EXYNOS4210: + phypwr |= PHYPWR_NORMAL_MASK_PHY0; + default: + break; + } + + /* Disable analog and otg block power */ + writel(phypwr, regs + SAMSUNG_PHYPWR); +} + +/* + * The function passed to the usb driver for phy initialization + */ +static int samsung_usb2phy_init(struct usb_phy *phy) +{ + struct samsung_usbphy *sphy; + struct usb_bus *host = NULL; + unsigned long flags; + int ret = 0; + + sphy = phy_to_sphy(phy); + + host = phy->otg->host; + + /* Enable the phy clock */ + ret = clk_prepare_enable(sphy->clk); + if (ret) { + dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); + return ret; + } + + spin_lock_irqsave(&sphy->lock, flags); + + if (host) { + /* setting default phy-type for USB 2.0 */ + if (!strstr(dev_name(host->controller), "ehci") || + !strstr(dev_name(host->controller), "ohci")) + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); + } else { + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); + } + + /* Disable phy isolation */ + if (sphy->plat && sphy->plat->pmu_isolation) + sphy->plat->pmu_isolation(false); + else + samsung_usbphy_set_isolation(sphy, false); + + /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */ + samsung_usbphy_cfg_sel(sphy); + + /* Initialize usb phy registers */ + if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) + samsung_exynos5_usb2phy_enable(sphy); + else + samsung_usb2phy_enable(sphy); + + spin_unlock_irqrestore(&sphy->lock, flags); + + /* Disable the phy clock */ + clk_disable_unprepare(sphy->clk); + + return ret; +} + +/* + * The function passed to the usb driver for phy shutdown + */ +static void samsung_usb2phy_shutdown(struct usb_phy *phy) +{ + struct samsung_usbphy *sphy; + struct usb_bus *host = NULL; + unsigned long flags; + + sphy = phy_to_sphy(phy); + + host = phy->otg->host; + + if (clk_prepare_enable(sphy->clk)) { + dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); + return; + } + + spin_lock_irqsave(&sphy->lock, flags); + + if (host) { + /* setting default phy-type for USB 2.0 */ + if (!strstr(dev_name(host->controller), "ehci") || + !strstr(dev_name(host->controller), "ohci")) + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); + } else { + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); + } + + /* De-initialize usb phy registers */ + if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) + samsung_exynos5_usb2phy_disable(sphy); + else + samsung_usb2phy_disable(sphy); + + /* Enable phy isolation */ + if (sphy->plat && sphy->plat->pmu_isolation) + sphy->plat->pmu_isolation(true); + else + samsung_usbphy_set_isolation(sphy, true); + + spin_unlock_irqrestore(&sphy->lock, flags); + + clk_disable_unprepare(sphy->clk); +} + +static int samsung_usb2phy_probe(struct platform_device *pdev) +{ + struct samsung_usbphy *sphy; + struct usb_otg *otg; + struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + const struct samsung_usbphy_drvdata *drv_data; + struct device *dev = &pdev->dev; + struct resource *phy_mem; + void __iomem *phy_base; + struct clk *clk; + int ret; + + phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!phy_mem) { + dev_err(dev, "%s: missing mem resource\n", __func__); + return -ENODEV; + } + + phy_base = devm_ioremap_resource(dev, phy_mem); + if (IS_ERR(phy_base)) + return PTR_ERR(phy_base); + + sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); + if (!sphy) + return -ENOMEM; + + otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + drv_data = samsung_usbphy_get_driver_data(pdev); + + if (drv_data->cpu_type == TYPE_EXYNOS5250) + clk = devm_clk_get(dev, "usbhost"); + else + clk = devm_clk_get(dev, "otg"); + + if (IS_ERR(clk)) { + dev_err(dev, "Failed to get otg clock\n"); + return PTR_ERR(clk); + } + + sphy->dev = dev; + + if (dev->of_node) { + ret = samsung_usbphy_parse_dt(sphy); + if (ret < 0) + return ret; + } else { + if (!pdata) { + dev_err(dev, "no platform data specified\n"); + return -EINVAL; + } + } + + sphy->plat = pdata; + sphy->regs = phy_base; + sphy->clk = clk; + sphy->drv_data = drv_data; + sphy->phy.dev = sphy->dev; + sphy->phy.label = "samsung-usb2phy"; + sphy->phy.init = samsung_usb2phy_init; + sphy->phy.shutdown = samsung_usb2phy_shutdown; + sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy); + + sphy->phy.otg = otg; + sphy->phy.otg->phy = &sphy->phy; + sphy->phy.otg->set_host = samsung_usbphy_set_host; + + spin_lock_init(&sphy->lock); + + platform_set_drvdata(pdev, sphy); + + return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2); +} + +static int samsung_usb2phy_remove(struct platform_device *pdev) +{ + struct samsung_usbphy *sphy = platform_get_drvdata(pdev); + + usb_remove_phy(&sphy->phy); + + if (sphy->pmuregs) + iounmap(sphy->pmuregs); + if (sphy->sysreg) + iounmap(sphy->sysreg); + + return 0; +} + +static const struct samsung_usbphy_drvdata usb2phy_s3c64xx = { + .cpu_type = TYPE_S3C64XX, + .devphy_en_mask = S3C64XX_USBPHY_ENABLE, +}; + +static const struct samsung_usbphy_drvdata usb2phy_exynos4 = { + .cpu_type = TYPE_EXYNOS4210, + .devphy_en_mask = EXYNOS_USBPHY_ENABLE, + .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, +}; + +static struct samsung_usbphy_drvdata usb2phy_exynos5 = { + .cpu_type = TYPE_EXYNOS5250, + .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, + .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET, +}; + +#ifdef CONFIG_OF +static const struct of_device_id samsung_usbphy_dt_match[] = { + { + .compatible = "samsung,s3c64xx-usb2phy", + .data = &usb2phy_s3c64xx, + }, { + .compatible = "samsung,exynos4210-usb2phy", + .data = &usb2phy_exynos4, + }, { + .compatible = "samsung,exynos5250-usb2phy", + .data = &usb2phy_exynos5 + }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match); +#endif + +static struct platform_device_id samsung_usbphy_driver_ids[] = { + { + .name = "s3c64xx-usb2phy", + .driver_data = (unsigned long)&usb2phy_s3c64xx, + }, { + .name = "exynos4210-usb2phy", + .driver_data = (unsigned long)&usb2phy_exynos4, + }, { + .name = "exynos5250-usb2phy", + .driver_data = (unsigned long)&usb2phy_exynos5, + }, + {}, +}; + +MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids); + +static struct platform_driver samsung_usb2phy_driver = { + .probe = samsung_usb2phy_probe, + .remove = samsung_usb2phy_remove, + .id_table = samsung_usbphy_driver_ids, + .driver = { + .name = "samsung-usb2phy", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(samsung_usbphy_dt_match), + }, +}; + +module_platform_driver(samsung_usb2phy_driver); + +MODULE_DESCRIPTION("Samsung USB 2.0 phy controller"); +MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:samsung-usb2phy"); diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c new file mode 100644 index 000000000000..133f3d0c554f --- /dev/null +++ b/drivers/usb/phy/phy-samsung-usb3.c @@ -0,0 +1,347 @@ +/* linux/drivers/usb/phy/phy-samsung-usb3.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Vivek Gautam <gautam.vivek@samsung.com> + * + * Samsung USB 3.0 PHY transceiver; talks to DWC3 controller. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/usb/samsung_usb_phy.h> +#include <linux/platform_data/samsung-usbphy.h> + +#include "phy-samsung-usb.h" + +/* + * Sets the phy clk as EXTREFCLK (XXTI) which is internal clock from clock core. + */ +static u32 samsung_usb3phy_set_refclk(struct samsung_usbphy *sphy) +{ + u32 reg; + u32 refclk; + + refclk = sphy->ref_clk_freq; + + reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK | + PHYCLKRST_FSEL(refclk); + + switch (refclk) { + case FSEL_CLKSEL_50M: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF | + PHYCLKRST_SSC_REFCLKSEL(0x00)); + break; + case FSEL_CLKSEL_20M: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x00)); + break; + case FSEL_CLKSEL_19200K: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x88)); + break; + case FSEL_CLKSEL_24M: + default: + reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | + PHYCLKRST_SSC_REFCLKSEL(0x88)); + break; + } + + return reg; +} + +static int samsung_exynos5_usb3phy_enable(struct samsung_usbphy *sphy) +{ + void __iomem *regs = sphy->regs; + u32 phyparam0; + u32 phyparam1; + u32 linksystem; + u32 phybatchg; + u32 phytest; + u32 phyclkrst; + + /* Reset USB 3.0 PHY */ + writel(0x0, regs + EXYNOS5_DRD_PHYREG0); + + phyparam0 = readl(regs + EXYNOS5_DRD_PHYPARAM0); + /* Select PHY CLK source */ + phyparam0 &= ~PHYPARAM0_REF_USE_PAD; + /* Set Loss-of-Signal Detector sensitivity */ + phyparam0 &= ~PHYPARAM0_REF_LOSLEVEL_MASK; + phyparam0 |= PHYPARAM0_REF_LOSLEVEL; + writel(phyparam0, regs + EXYNOS5_DRD_PHYPARAM0); + + writel(0x0, regs + EXYNOS5_DRD_PHYRESUME); + + /* + * Setting the Frame length Adj value[6:1] to default 0x20 + * See xHCI 1.0 spec, 5.2.4 + */ + linksystem = LINKSYSTEM_XHCI_VERSION_CONTROL | + LINKSYSTEM_FLADJ(0x20); + writel(linksystem, regs + EXYNOS5_DRD_LINKSYSTEM); + + phyparam1 = readl(regs + EXYNOS5_DRD_PHYPARAM1); + /* Set Tx De-Emphasis level */ + phyparam1 &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; + phyparam1 |= PHYPARAM1_PCS_TXDEEMPH; + writel(phyparam1, regs + EXYNOS5_DRD_PHYPARAM1); + + phybatchg = readl(regs + EXYNOS5_DRD_PHYBATCHG); + phybatchg |= PHYBATCHG_UTMI_CLKSEL; + writel(phybatchg, regs + EXYNOS5_DRD_PHYBATCHG); + + /* PHYTEST POWERDOWN Control */ + phytest = readl(regs + EXYNOS5_DRD_PHYTEST); + phytest &= ~(PHYTEST_POWERDOWN_SSP | + PHYTEST_POWERDOWN_HSP); + writel(phytest, regs + EXYNOS5_DRD_PHYTEST); + + /* UTMI Power Control */ + writel(PHYUTMI_OTGDISABLE, regs + EXYNOS5_DRD_PHYUTMI); + + phyclkrst = samsung_usb3phy_set_refclk(sphy); + + phyclkrst |= PHYCLKRST_PORTRESET | + /* Digital power supply in normal operating mode */ + PHYCLKRST_RETENABLEN | + /* Enable ref clock for SS function */ + PHYCLKRST_REF_SSP_EN | + /* Enable spread spectrum */ + PHYCLKRST_SSC_EN | + /* Power down HS Bias and PLL blocks in suspend mode */ + PHYCLKRST_COMMONONN; + + writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST); + + udelay(10); + + phyclkrst &= ~(PHYCLKRST_PORTRESET); + writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST); + + return 0; +} + +static void samsung_exynos5_usb3phy_disable(struct samsung_usbphy *sphy) +{ + u32 phyutmi; + u32 phyclkrst; + u32 phytest; + void __iomem *regs = sphy->regs; + + phyutmi = PHYUTMI_OTGDISABLE | + PHYUTMI_FORCESUSPEND | + PHYUTMI_FORCESLEEP; + writel(phyutmi, regs + EXYNOS5_DRD_PHYUTMI); + + /* Resetting the PHYCLKRST enable bits to reduce leakage current */ + phyclkrst = readl(regs + EXYNOS5_DRD_PHYCLKRST); + phyclkrst &= ~(PHYCLKRST_REF_SSP_EN | + PHYCLKRST_SSC_EN | + PHYCLKRST_COMMONONN); + writel(phyclkrst, regs + EXYNOS5_DRD_PHYCLKRST); + + /* Control PHYTEST to remove leakage current */ + phytest = readl(regs + EXYNOS5_DRD_PHYTEST); + phytest |= (PHYTEST_POWERDOWN_SSP | + PHYTEST_POWERDOWN_HSP); + writel(phytest, regs + EXYNOS5_DRD_PHYTEST); +} + +static int samsung_usb3phy_init(struct usb_phy *phy) +{ + struct samsung_usbphy *sphy; + unsigned long flags; + int ret = 0; + + sphy = phy_to_sphy(phy); + + /* Enable the phy clock */ + ret = clk_prepare_enable(sphy->clk); + if (ret) { + dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); + return ret; + } + + spin_lock_irqsave(&sphy->lock, flags); + + /* setting default phy-type for USB 3.0 */ + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); + + /* Disable phy isolation */ + samsung_usbphy_set_isolation(sphy, false); + + /* Initialize usb phy registers */ + samsung_exynos5_usb3phy_enable(sphy); + + spin_unlock_irqrestore(&sphy->lock, flags); + + /* Disable the phy clock */ + clk_disable_unprepare(sphy->clk); + + return ret; +} + +/* + * The function passed to the usb driver for phy shutdown + */ +static void samsung_usb3phy_shutdown(struct usb_phy *phy) +{ + struct samsung_usbphy *sphy; + unsigned long flags; + + sphy = phy_to_sphy(phy); + + if (clk_prepare_enable(sphy->clk)) { + dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); + return; + } + + spin_lock_irqsave(&sphy->lock, flags); + + /* setting default phy-type for USB 3.0 */ + samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); + + /* De-initialize usb phy registers */ + samsung_exynos5_usb3phy_disable(sphy); + + /* Enable phy isolation */ + samsung_usbphy_set_isolation(sphy, true); + + spin_unlock_irqrestore(&sphy->lock, flags); + + clk_disable_unprepare(sphy->clk); +} + +static int samsung_usb3phy_probe(struct platform_device *pdev) +{ + struct samsung_usbphy *sphy; + struct samsung_usbphy_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct resource *phy_mem; + void __iomem *phy_base; + struct clk *clk; + int ret; + + phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!phy_mem) { + dev_err(dev, "%s: missing mem resource\n", __func__); + return -ENODEV; + } + + phy_base = devm_ioremap_resource(dev, phy_mem); + if (IS_ERR(phy_base)) + return PTR_ERR(phy_base); + + sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); + if (!sphy) + return -ENOMEM; + + clk = devm_clk_get(dev, "usbdrd30"); + if (IS_ERR(clk)) { + dev_err(dev, "Failed to get device clock\n"); + return PTR_ERR(clk); + } + + sphy->dev = dev; + + if (dev->of_node) { + ret = samsung_usbphy_parse_dt(sphy); + if (ret < 0) + return ret; + } else { + if (!pdata) { + dev_err(dev, "no platform data specified\n"); + return -EINVAL; + } + } + + sphy->plat = pdata; + sphy->regs = phy_base; + sphy->clk = clk; + sphy->phy.dev = sphy->dev; + sphy->phy.label = "samsung-usb3phy"; + sphy->phy.init = samsung_usb3phy_init; + sphy->phy.shutdown = samsung_usb3phy_shutdown; + sphy->drv_data = samsung_usbphy_get_driver_data(pdev); + sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy); + + spin_lock_init(&sphy->lock); + + platform_set_drvdata(pdev, sphy); + + return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3); +} + +static int samsung_usb3phy_remove(struct platform_device *pdev) +{ + struct samsung_usbphy *sphy = platform_get_drvdata(pdev); + + usb_remove_phy(&sphy->phy); + + if (sphy->pmuregs) + iounmap(sphy->pmuregs); + if (sphy->sysreg) + iounmap(sphy->sysreg); + + return 0; +} + +static struct samsung_usbphy_drvdata usb3phy_exynos5 = { + .cpu_type = TYPE_EXYNOS5250, + .devphy_en_mask = EXYNOS_USBPHY_ENABLE, +}; + +#ifdef CONFIG_OF +static const struct of_device_id samsung_usbphy_dt_match[] = { + { + .compatible = "samsung,exynos5250-usb3phy", + .data = &usb3phy_exynos5 + }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match); +#endif + +static struct platform_device_id samsung_usbphy_driver_ids[] = { + { + .name = "exynos5250-usb3phy", + .driver_data = (unsigned long)&usb3phy_exynos5, + }, + {}, +}; + +MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids); + +static struct platform_driver samsung_usb3phy_driver = { + .probe = samsung_usb3phy_probe, + .remove = samsung_usb3phy_remove, + .id_table = samsung_usbphy_driver_ids, + .driver = { + .name = "samsung-usb3phy", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(samsung_usbphy_dt_match), + }, +}; + +module_platform_driver(samsung_usb3phy_driver); + +MODULE_DESCRIPTION("Samsung USB 3.0 phy controller"); +MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:samsung-usb3phy"); diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/phy-tegra-usb.c index 5487d38481af..17d811292f3a 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -299,7 +299,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) val &= ~USB_SUSP_SET; writel(val, base + USB_SUSP_CTRL); } else - tegra_ehci_set_phcd(&phy->u_phy, true); + phy->set_phcd(&phy->u_phy, true); if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) pr_err("%s: timeout waiting for phy to stabilize\n", __func__); @@ -321,7 +321,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) val &= ~USB_SUSP_CLR; writel(val, base + USB_SUSP_CTRL); } else - tegra_ehci_set_phcd(&phy->u_phy, false); + phy->set_phcd(&phy->u_phy, false); if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, USB_PHY_CLK_VALID)) @@ -444,7 +444,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) utmi_phy_clk_enable(phy); if (!phy->is_legacy_phy) - tegra_ehci_set_pts(&phy->u_phy, 0); + phy->set_pts(&phy->u_phy, 0); return 0; } @@ -688,7 +688,10 @@ static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend) } struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, - void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode) + void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode, + void (*set_pts)(struct usb_phy *x, u8 pts_val), + void (*set_phcd)(struct usb_phy *x, bool enable)) + { struct tegra_usb_phy *phy; unsigned long parent_rate; @@ -707,6 +710,8 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, phy->dev = dev; phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); + phy->set_pts = set_pts; + phy->set_phcd = set_phcd; err = of_property_match_string(np, "phy_type", "ulpi"); if (err < 0) phy->is_ulpi_phy = false; diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c index a994715a3101..8f78d2d40722 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/phy/phy-twl4030-usb.c @@ -163,6 +163,8 @@ struct twl4030_usb { bool vbus_supplied; u8 asleep; bool irq_enabled; + + struct delayed_work id_workaround_work; }; /* internal define on top of container_of */ @@ -246,6 +248,25 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) /*-------------------------------------------------------------------------*/ +static bool twl4030_is_driving_vbus(struct twl4030_usb *twl) +{ + int ret; + + ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS); + if (ret < 0 || !(ret & PHY_DPLL_CLK)) + /* + * if clocks are off, registers are not updated, + * but we can assume we don't drive VBUS in this case + */ + return false; + + ret = twl4030_usb_read(twl, ULPI_OTG_CTRL); + if (ret < 0) + return false; + + return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false; +} + static enum omap_musb_vbus_id_status twl4030_usb_linkstat(struct twl4030_usb *twl) { @@ -268,13 +289,19 @@ static enum omap_musb_vbus_id_status if (status < 0) dev_err(twl->dev, "USB link status err %d\n", status); else if (status & (BIT(7) | BIT(2))) { - if (status & (BIT(7))) - twl->vbus_supplied = true; + if (status & BIT(7)) { + if (twl4030_is_driving_vbus(twl)) + status &= ~BIT(7); + else + twl->vbus_supplied = true; + } if (status & BIT(2)) linkstat = OMAP_MUSB_ID_GROUND; - else + else if (status & BIT(7)) linkstat = OMAP_MUSB_VBUS_VALID; + else + linkstat = OMAP_MUSB_VBUS_OFF; } else { if (twl->linkstat != OMAP_MUSB_UNKNOWN) linkstat = OMAP_MUSB_VBUS_OFF; @@ -287,10 +314,6 @@ static enum omap_musb_vbus_id_status * are registered, and that both are active... */ - spin_lock_irq(&twl->lock); - twl->linkstat = linkstat; - spin_unlock_irq(&twl->lock); - return linkstat; } @@ -361,9 +384,17 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on) static void twl4030_phy_power(struct twl4030_usb *twl, int on) { + int ret; + if (on) { - regulator_enable(twl->usb3v1); - regulator_enable(twl->usb1v8); + ret = regulator_enable(twl->usb3v1); + if (ret) + dev_err(twl->dev, "Failed to enable usb3v1\n"); + + ret = regulator_enable(twl->usb1v8); + if (ret) + dev_err(twl->dev, "Failed to enable usb1v8\n"); + /* * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP * in twl4030) resets the VUSB_DEDICATED2 register. This reset @@ -372,7 +403,11 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) * is re-activated. This ensures that VUSB3V1 is really active. */ twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); - regulator_enable(twl->usb1v5); + + ret = regulator_enable(twl->usb1v5); + if (ret) + dev_err(twl->dev, "Failed to enable usb1v5\n"); + __twl4030_phy_power(twl, 1); twl4030_usb_write(twl, PHY_CLK_CTRL, twl4030_usb_read(twl, PHY_CLK_CTRL) | @@ -412,6 +447,16 @@ static void twl4030_phy_resume(struct twl4030_usb *twl) __twl4030_phy_resume(twl); twl->asleep = 0; dev_dbg(twl->dev, "%s\n", __func__); + + /* + * XXX When VBUS gets driven after musb goes to A mode, + * ID_PRES related interrupts no longer arrive, why? + * Register itself is updated fine though, so we must poll. + */ + if (twl->linkstat == OMAP_MUSB_ID_GROUND) { + cancel_delayed_work(&twl->id_workaround_work); + schedule_delayed_work(&twl->id_workaround_work, HZ); + } } static int twl4030_usb_ldo_init(struct twl4030_usb *twl) @@ -432,7 +477,7 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl) /* Initialize 3.1V regulator */ twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); - twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); + twl->usb3v1 = devm_regulator_get(twl->dev, "usb3v1"); if (IS_ERR(twl->usb3v1)) return -ENODEV; @@ -441,18 +486,18 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl) /* Initialize 1.5V regulator */ twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); - twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); + twl->usb1v5 = devm_regulator_get(twl->dev, "usb1v5"); if (IS_ERR(twl->usb1v5)) - goto fail1; + return -ENODEV; twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); /* Initialize 1.8V regulator */ twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); - twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); + twl->usb1v8 = devm_regulator_get(twl->dev, "usb1v8"); if (IS_ERR(twl->usb1v8)) - goto fail2; + return -ENODEV; twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); @@ -461,14 +506,6 @@ static int twl4030_usb_ldo_init(struct twl4030_usb *twl) TWL4030_PM_MASTER_PROTECT_KEY); return 0; - -fail2: - regulator_put(twl->usb1v5); - twl->usb1v5 = NULL; -fail1: - regulator_put(twl->usb3v1); - twl->usb3v1 = NULL; - return -ENODEV; } static ssize_t twl4030_usb_vbus_show(struct device *dev, @@ -491,9 +528,18 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) { struct twl4030_usb *twl = _twl; enum omap_musb_vbus_id_status status; + bool status_changed = false; status = twl4030_usb_linkstat(twl); - if (status > 0) { + + spin_lock_irq(&twl->lock); + if (status >= 0 && status != twl->linkstat) { + twl->linkstat = status; + status_changed = true; + } + spin_unlock_irq(&twl->lock); + + if (status_changed) { /* FIXME add a set_power() method so that B-devices can * configure the charger appropriately. It's not always * correct to consume VBUS power, and how much current to @@ -505,37 +551,62 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) * USB_LINK_VBUS state. musb_hdrc won't care until it * starts to handle softconnect right. */ - if (status == OMAP_MUSB_VBUS_OFF || - status == OMAP_MUSB_ID_FLOAT) - twl4030_phy_suspend(twl, 0); - else - twl4030_phy_resume(twl); - - omap_musb_mailbox(twl->linkstat); + omap_musb_mailbox(status); } sysfs_notify(&twl->dev->kobj, NULL, "vbus"); return IRQ_HANDLED; } -static void twl4030_usb_phy_init(struct twl4030_usb *twl) +static void twl4030_id_workaround_work(struct work_struct *work) { + struct twl4030_usb *twl = container_of(work, struct twl4030_usb, + id_workaround_work.work); enum omap_musb_vbus_id_status status; + bool status_changed = false; status = twl4030_usb_linkstat(twl); - if (status > 0) { - if (status == OMAP_MUSB_VBUS_OFF || - status == OMAP_MUSB_ID_FLOAT) { - __twl4030_phy_power(twl, 0); - twl->asleep = 1; - } else { - __twl4030_phy_resume(twl); - twl->asleep = 0; - } - omap_musb_mailbox(twl->linkstat); + spin_lock_irq(&twl->lock); + if (status >= 0 && status != twl->linkstat) { + twl->linkstat = status; + status_changed = true; + } + spin_unlock_irq(&twl->lock); + + if (status_changed) { + dev_dbg(twl->dev, "handle missing status change to %d\n", + status); + omap_musb_mailbox(status); } + + /* don't schedule during sleep - irq works right then */ + if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) { + cancel_delayed_work(&twl->id_workaround_work); + schedule_delayed_work(&twl->id_workaround_work, HZ); + } +} + +static int twl4030_usb_phy_init(struct usb_phy *phy) +{ + struct twl4030_usb *twl = phy_to_twl(phy); + enum omap_musb_vbus_id_status status; + + /* + * Start in sleep state, we'll get called through set_suspend() + * callback when musb is runtime resumed and it's time to start. + */ + __twl4030_phy_power(twl, 0); + twl->asleep = 1; + + status = twl4030_usb_linkstat(twl); + twl->linkstat = status; + + if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID) + omap_musb_mailbox(twl->linkstat); + sysfs_notify(&twl->dev->kobj, NULL, "vbus"); + return 0; } static int twl4030_set_suspend(struct usb_phy *x, int suspend) @@ -612,6 +683,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) twl->phy.otg = otg; twl->phy.type = USB_PHY_TYPE_USB2; twl->phy.set_suspend = twl4030_set_suspend; + twl->phy.init = twl4030_usb_phy_init; otg->phy = &twl->phy; otg->set_host = twl4030_set_host; @@ -620,6 +692,8 @@ static int twl4030_usb_probe(struct platform_device *pdev) /* init spinlock for workqueue */ spin_lock_init(&twl->lock); + INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work); + err = twl4030_usb_ldo_init(twl); if (err) { dev_err(&pdev->dev, "ldo init failed\n"); @@ -640,30 +714,25 @@ static int twl4030_usb_probe(struct platform_device *pdev) * need both handles, otherwise just one suffices. */ twl->irq_enabled = true; - status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | - IRQF_ONESHOT, "twl4030_usb", twl); + status = devm_request_threaded_irq(twl->dev, twl->irq, NULL, + twl4030_usb_irq, IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl); if (status < 0) { dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", twl->irq, status); return status; } - /* Power down phy or make it work according to - * current link state. - */ - twl4030_usb_phy_init(twl); - dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); return 0; } -static int __exit twl4030_usb_remove(struct platform_device *pdev) +static int twl4030_usb_remove(struct platform_device *pdev) { struct twl4030_usb *twl = platform_get_drvdata(pdev); int val; - free_irq(twl->irq, twl); + cancel_delayed_work(&twl->id_workaround_work); device_remove_file(twl->dev, &dev_attr_vbus); /* set transceiver mode to power on defaults */ @@ -685,9 +754,6 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev) if (!twl->asleep) twl4030_phy_power(twl, 0); - regulator_put(twl->usb1v5); - regulator_put(twl->usb1v8); - regulator_put(twl->usb3v1); return 0; } @@ -702,7 +768,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, - .remove = __exit_p(twl4030_usb_remove), + .remove = twl4030_usb_remove, .driver = { .name = "twl4030_usb", .owner = THIS_MODULE, diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 8cd6cf49bdbd..9de7ada90a8b 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -211,6 +211,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) struct twl6030_usb *twl = _twl; enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; u8 vbus_state, hw_state; + int ret; hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); @@ -218,7 +219,10 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl) CONTROLLER_STAT1); if (!(hw_state & STS_USB_ID)) { if (vbus_state & VBUS_DET) { - regulator_enable(twl->usb3v3); + ret = regulator_enable(twl->usb3v3); + if (ret) + dev_err(twl->dev, "Failed to enable usb3v3\n"); + twl->asleep = 1; status = OMAP_MUSB_VBUS_VALID; twl->linkstat = status; @@ -245,12 +249,15 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) struct twl6030_usb *twl = _twl; enum omap_musb_vbus_id_status status = OMAP_MUSB_UNKNOWN; u8 hw_state; + int ret; hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); if (hw_state & STS_USB_ID) { + ret = regulator_enable(twl->usb3v3); + if (ret) + dev_err(twl->dev, "Failed to enable usb3v3\n"); - regulator_enable(twl->usb3v3); twl->asleep = 1; twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR); twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET); @@ -393,7 +400,7 @@ static int twl6030_usb_probe(struct platform_device *pdev) return 0; } -static int __exit twl6030_usb_remove(struct platform_device *pdev) +static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); @@ -420,7 +427,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, - .remove = __exit_p(twl6030_usb_remove), + .remove = twl6030_usb_remove, .driver = { .name = "twl6030_usb", .owner = THIS_MODULE, diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/phy/phy-ulpi-viewport.c index c5ba7e5423fc..c5ba7e5423fc 100644 --- a/drivers/usb/otg/ulpi_viewport.c +++ b/drivers/usb/phy/phy-ulpi-viewport.c diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/phy/phy-ulpi.c index 217339dd7a90..217339dd7a90 100644 --- a/drivers/usb/otg/ulpi.c +++ b/drivers/usb/phy/phy-ulpi.c diff --git a/drivers/usb/otg/otg.c b/drivers/usb/phy/phy.c index 2bd03d261a50..a9984c700d2c 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/phy/phy.c @@ -1,14 +1,13 @@ /* - * otg.c -- USB OTG utility code + * phy.c -- USB phy handling * - * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004-2013 Texas Instruments * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ - #include <linux/kernel.h> #include <linux/export.h> #include <linux/err.h> @@ -17,7 +16,7 @@ #include <linux/slab.h> #include <linux/of.h> -#include <linux/usb/otg.h> +#include <linux/usb/phy.h> static LIST_HEAD(phy_list); static LIST_HEAD(phy_bind_list); @@ -110,7 +109,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type) return phy; } -EXPORT_SYMBOL(devm_usb_get_phy); +EXPORT_SYMBOL_GPL(devm_usb_get_phy); /** * usb_get_phy - find the USB PHY @@ -143,7 +142,7 @@ err0: return phy; } -EXPORT_SYMBOL(usb_get_phy); +EXPORT_SYMBOL_GPL(usb_get_phy); /** * devm_usb_get_phy_by_phandle - find the USB PHY by phandle @@ -207,7 +206,7 @@ err0: return phy; } -EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); +EXPORT_SYMBOL_GPL(devm_usb_get_phy_by_phandle); /** * usb_get_phy_dev - find the USB PHY @@ -240,7 +239,7 @@ err0: return phy; } -EXPORT_SYMBOL(usb_get_phy_dev); +EXPORT_SYMBOL_GPL(usb_get_phy_dev); /** * devm_usb_get_phy_dev - find the USB PHY using device ptr and index @@ -270,7 +269,7 @@ struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) return phy; } -EXPORT_SYMBOL(devm_usb_get_phy_dev); +EXPORT_SYMBOL_GPL(devm_usb_get_phy_dev); /** * devm_usb_put_phy - release the USB PHY @@ -289,7 +288,7 @@ void devm_usb_put_phy(struct device *dev, struct usb_phy *phy) r = devres_destroy(dev, devm_usb_phy_release, devm_usb_phy_match, phy); dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); } -EXPORT_SYMBOL(devm_usb_put_phy); +EXPORT_SYMBOL_GPL(devm_usb_put_phy); /** * usb_put_phy - release the USB PHY @@ -308,7 +307,7 @@ void usb_put_phy(struct usb_phy *x) module_put(owner); } } -EXPORT_SYMBOL(usb_put_phy); +EXPORT_SYMBOL_GPL(usb_put_phy); /** * usb_add_phy - declare the USB PHY @@ -348,7 +347,7 @@ out: spin_unlock_irqrestore(&phy_lock, flags); return ret; } -EXPORT_SYMBOL(usb_add_phy); +EXPORT_SYMBOL_GPL(usb_add_phy); /** * usb_add_phy_dev - declare the USB PHY @@ -378,7 +377,7 @@ int usb_add_phy_dev(struct usb_phy *x) spin_unlock_irqrestore(&phy_lock, flags); return 0; } -EXPORT_SYMBOL(usb_add_phy_dev); +EXPORT_SYMBOL_GPL(usb_add_phy_dev); /** * usb_remove_phy - remove the OTG PHY @@ -400,7 +399,7 @@ void usb_remove_phy(struct usb_phy *x) } spin_unlock_irqrestore(&phy_lock, flags); } -EXPORT_SYMBOL(usb_remove_phy); +EXPORT_SYMBOL_GPL(usb_remove_phy); /** * usb_bind_phy - bind the phy and the controller that uses the phy @@ -414,7 +413,7 @@ EXPORT_SYMBOL(usb_remove_phy); * * To be used by platform specific initialization code. */ -int __init usb_bind_phy(const char *dev_name, u8 index, +int usb_bind_phy(const char *dev_name, u8 index, const char *phy_dev_name) { struct usb_phy_bind *phy_bind; @@ -437,38 +436,3 @@ int __init usb_bind_phy(const char *dev_name, u8 index, return 0; } EXPORT_SYMBOL_GPL(usb_bind_phy); - -const char *otg_state_string(enum usb_otg_state state) -{ - switch (state) { - case OTG_STATE_A_IDLE: - return "a_idle"; - case OTG_STATE_A_WAIT_VRISE: - return "a_wait_vrise"; - case OTG_STATE_A_WAIT_BCON: - return "a_wait_bcon"; - case OTG_STATE_A_HOST: - return "a_host"; - case OTG_STATE_A_SUSPEND: - return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: - return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: - return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: - return "a_vbus_err"; - case OTG_STATE_B_IDLE: - return "b_idle"; - case OTG_STATE_B_SRP_INIT: - return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: - return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: - return "b_wait_acon"; - case OTG_STATE_B_HOST: - return "b_host"; - default: - return "UNDEFINED"; - } -} -EXPORT_SYMBOL(otg_state_string); diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c deleted file mode 100644 index 967101ec15fd..000000000000 --- a/drivers/usb/phy/samsung-usbphy.c +++ /dev/null @@ -1,928 +0,0 @@ -/* linux/drivers/usb/phy/samsung-usbphy.c - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Author: Praveen Paneri <p.paneri@samsung.com> - * - * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and - * OHCI-EXYNOS controllers. - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/usb/otg.h> -#include <linux/usb/samsung_usb_phy.h> -#include <linux/platform_data/samsung-usbphy.h> - -/* Register definitions */ - -#define SAMSUNG_PHYPWR (0x00) - -#define PHYPWR_NORMAL_MASK (0x19 << 0) -#define PHYPWR_OTG_DISABLE (0x1 << 4) -#define PHYPWR_ANALOG_POWERDOWN (0x1 << 3) -#define PHYPWR_FORCE_SUSPEND (0x1 << 1) -/* For Exynos4 */ -#define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0) -#define PHYPWR_SLEEP_PHY0 (0x1 << 5) - -#define SAMSUNG_PHYCLK (0x04) - -#define PHYCLK_MODE_USB11 (0x1 << 6) -#define PHYCLK_EXT_OSC (0x1 << 5) -#define PHYCLK_COMMON_ON_N (0x1 << 4) -#define PHYCLK_ID_PULL (0x1 << 2) -#define PHYCLK_CLKSEL_MASK (0x3 << 0) -#define PHYCLK_CLKSEL_48M (0x0 << 0) -#define PHYCLK_CLKSEL_12M (0x2 << 0) -#define PHYCLK_CLKSEL_24M (0x3 << 0) - -#define SAMSUNG_RSTCON (0x08) - -#define RSTCON_PHYLINK_SWRST (0x1 << 2) -#define RSTCON_HLINK_SWRST (0x1 << 1) -#define RSTCON_SWRST (0x1 << 0) - -/* EXYNOS5 */ -#define EXYNOS5_PHY_HOST_CTRL0 (0x00) - -#define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) - -#define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19) -#define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19) -#define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19) -#define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19) - -#define HOST_CTRL0_FSEL_MASK (0x7 << 16) -#define HOST_CTRL0_FSEL(_x) ((_x) << 16) - -#define FSEL_CLKSEL_50M (0x7) -#define FSEL_CLKSEL_24M (0x5) -#define FSEL_CLKSEL_20M (0x4) -#define FSEL_CLKSEL_19200K (0x3) -#define FSEL_CLKSEL_12M (0x2) -#define FSEL_CLKSEL_10M (0x1) -#define FSEL_CLKSEL_9600K (0x0) - -#define HOST_CTRL0_TESTBURNIN (0x1 << 11) -#define HOST_CTRL0_RETENABLE (0x1 << 10) -#define HOST_CTRL0_COMMONON_N (0x1 << 9) -#define HOST_CTRL0_SIDDQ (0x1 << 6) -#define HOST_CTRL0_FORCESLEEP (0x1 << 5) -#define HOST_CTRL0_FORCESUSPEND (0x1 << 4) -#define HOST_CTRL0_WORDINTERFACE (0x1 << 3) -#define HOST_CTRL0_UTMISWRST (0x1 << 2) -#define HOST_CTRL0_LINKSWRST (0x1 << 1) -#define HOST_CTRL0_PHYSWRST (0x1 << 0) - -#define EXYNOS5_PHY_HOST_TUNE0 (0x04) - -#define EXYNOS5_PHY_HSIC_CTRL1 (0x10) - -#define EXYNOS5_PHY_HSIC_TUNE1 (0x14) - -#define EXYNOS5_PHY_HSIC_CTRL2 (0x20) - -#define EXYNOS5_PHY_HSIC_TUNE2 (0x24) - -#define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23) -#define HSIC_CTRL_REFCLKSEL (0x2 << 23) - -#define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16) -#define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16) -#define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16) -#define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16) -#define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16) -#define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16) -#define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16) - -#define HSIC_CTRL_SIDDQ (0x1 << 6) -#define HSIC_CTRL_FORCESLEEP (0x1 << 5) -#define HSIC_CTRL_FORCESUSPEND (0x1 << 4) -#define HSIC_CTRL_WORDINTERFACE (0x1 << 3) -#define HSIC_CTRL_UTMISWRST (0x1 << 2) -#define HSIC_CTRL_PHYSWRST (0x1 << 0) - -#define EXYNOS5_PHY_HOST_EHCICTRL (0x30) - -#define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29) -#define HOST_EHCICTRL_ENAINCR4 (0x1 << 28) -#define HOST_EHCICTRL_ENAINCR8 (0x1 << 27) -#define HOST_EHCICTRL_ENAINCR16 (0x1 << 26) - -#define EXYNOS5_PHY_HOST_OHCICTRL (0x34) - -#define HOST_OHCICTRL_SUSPLGCY (0x1 << 3) -#define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2) -#define HOST_OHCICTRL_CNTSEL (0x1 << 1) -#define HOST_OHCICTRL_CLKCKTRST (0x1 << 0) - -#define EXYNOS5_PHY_OTG_SYS (0x38) - -#define OTG_SYS_PHYLINK_SWRESET (0x1 << 14) -#define OTG_SYS_LINKSWRST_UOTG (0x1 << 13) -#define OTG_SYS_PHY0_SWRST (0x1 << 12) - -#define OTG_SYS_REFCLKSEL_MASK (0x3 << 9) -#define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9) -#define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9) -#define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9) - -#define OTG_SYS_IDPULLUP_UOTG (0x1 << 8) -#define OTG_SYS_COMMON_ON (0x1 << 7) - -#define OTG_SYS_FSEL_MASK (0x7 << 4) -#define OTG_SYS_FSEL(_x) ((_x) << 4) - -#define OTG_SYS_FORCESLEEP (0x1 << 3) -#define OTG_SYS_OTGDISABLE (0x1 << 2) -#define OTG_SYS_SIDDQ_UOTG (0x1 << 1) -#define OTG_SYS_FORCESUSPEND (0x1 << 0) - -#define EXYNOS5_PHY_OTG_TUNE (0x40) - -#ifndef MHZ -#define MHZ (1000*1000) -#endif - -#ifndef KHZ -#define KHZ (1000) -#endif - -#define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4) -#define S3C64XX_USBPHY_ENABLE (0x1 << 16) -#define EXYNOS_USBPHY_ENABLE (0x1 << 0) -#define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0) - -enum samsung_cpu_type { - TYPE_S3C64XX, - TYPE_EXYNOS4210, - TYPE_EXYNOS5250, -}; - -/* - * struct samsung_usbphy_drvdata - driver data for various SoC variants - * @cpu_type: machine identifier - * @devphy_en_mask: device phy enable mask for PHY CONTROL register - * @hostphy_en_mask: host phy enable mask for PHY CONTROL register - * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from - * mapped address of system controller. - * @hostphy_reg_offset: offset to HOST PHY CONTROL register from - * mapped address of system controller. - * - * Here we have a separate mask for device type phy. - * Having different masks for host and device type phy helps - * in setting independent masks in case of SoCs like S5PV210, - * in which PHY0 and PHY1 enable bits belong to same register - * placed at position 0 and 1 respectively. - * Although for newer SoCs like exynos these bits belong to - * different registers altogether placed at position 0. - */ -struct samsung_usbphy_drvdata { - int cpu_type; - int devphy_en_mask; - int hostphy_en_mask; - u32 devphy_reg_offset; - u32 hostphy_reg_offset; -}; - -/* - * struct samsung_usbphy - transceiver driver state - * @phy: transceiver structure - * @plat: platform data - * @dev: The parent device supplied to the probe function - * @clk: usb phy clock - * @regs: usb phy controller registers memory base - * @pmuregs: USB device PHY_CONTROL register memory base - * @sysreg: USB2.0 PHY_CFG register memory base - * @ref_clk_freq: reference clock frequency selection - * @drv_data: driver data available for different SoCs - * @phy_type: Samsung SoCs specific phy types: #HOST - * #DEVICE - * @phy_usage: usage count for phy - * @lock: lock for phy operations - */ -struct samsung_usbphy { - struct usb_phy phy; - struct samsung_usbphy_data *plat; - struct device *dev; - struct clk *clk; - void __iomem *regs; - void __iomem *pmuregs; - void __iomem *sysreg; - int ref_clk_freq; - const struct samsung_usbphy_drvdata *drv_data; - enum samsung_usb_phy_type phy_type; - atomic_t phy_usage; - spinlock_t lock; -}; - -#define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) - -int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - if (!otg->host) - otg->host = host; - - return 0; -} - -static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) -{ - struct device_node *usbphy_sys; - - /* Getting node for system controller interface for usb-phy */ - usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys"); - if (!usbphy_sys) { - dev_err(sphy->dev, "No sys-controller interface for usb-phy\n"); - return -ENODEV; - } - - sphy->pmuregs = of_iomap(usbphy_sys, 0); - - if (sphy->pmuregs == NULL) { - dev_err(sphy->dev, "Can't get usb-phy pmu control register\n"); - goto err0; - } - - sphy->sysreg = of_iomap(usbphy_sys, 1); - - /* - * Not returning error code here, since this situation is not fatal. - * Few SoCs may not have this switch available - */ - if (sphy->sysreg == NULL) - dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n"); - - of_node_put(usbphy_sys); - - return 0; - -err0: - of_node_put(usbphy_sys); - return -ENXIO; -} - -/* - * Set isolation here for phy. - * Here 'on = true' would mean USB PHY block is isolated, hence - * de-activated and vice-versa. - */ -static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on) -{ - void __iomem *reg = NULL; - u32 reg_val; - u32 en_mask = 0; - - if (!sphy->pmuregs) { - dev_warn(sphy->dev, "Can't set pmu isolation\n"); - return; - } - - switch (sphy->drv_data->cpu_type) { - case TYPE_S3C64XX: - /* - * Do nothing: We will add here once S3C64xx goes for DT support - */ - break; - case TYPE_EXYNOS4210: - /* - * Fall through since exynos4210 and exynos5250 have similar - * register architecture: two separate registers for host and - * device phy control with enable bit at position 0. - */ - case TYPE_EXYNOS5250: - if (sphy->phy_type == USB_PHY_TYPE_DEVICE) { - reg = sphy->pmuregs + - sphy->drv_data->devphy_reg_offset; - en_mask = sphy->drv_data->devphy_en_mask; - } else if (sphy->phy_type == USB_PHY_TYPE_HOST) { - reg = sphy->pmuregs + - sphy->drv_data->hostphy_reg_offset; - en_mask = sphy->drv_data->hostphy_en_mask; - } - break; - default: - dev_err(sphy->dev, "Invalid SoC type\n"); - return; - } - - reg_val = readl(reg); - - if (on) - reg_val &= ~en_mask; - else - reg_val |= en_mask; - - writel(reg_val, reg); -} - -/* - * Configure the mode of working of usb-phy here: HOST/DEVICE. - */ -static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy) -{ - u32 reg; - - if (!sphy->sysreg) { - dev_warn(sphy->dev, "Can't configure specified phy mode\n"); - return; - } - - reg = readl(sphy->sysreg); - - if (sphy->phy_type == USB_PHY_TYPE_DEVICE) - reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK; - else if (sphy->phy_type == USB_PHY_TYPE_HOST) - reg |= EXYNOS_USB20PHY_CFG_HOST_LINK; - - writel(reg, sphy->sysreg); -} - -/* - * PHYs are different for USB Device and USB Host. - * This make sure that correct PHY type is selected before - * any operation on PHY. - */ -static int samsung_usbphy_set_type(struct usb_phy *phy, - enum samsung_usb_phy_type phy_type) -{ - struct samsung_usbphy *sphy = phy_to_sphy(phy); - - sphy->phy_type = phy_type; - - return 0; -} - -/* - * Returns reference clock frequency selection value - */ -static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy) -{ - struct clk *ref_clk; - int refclk_freq = 0; - - /* - * In exynos5250 USB host and device PHY use - * external crystal clock XXTI - */ - if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) - ref_clk = clk_get(sphy->dev, "ext_xtal"); - else - ref_clk = clk_get(sphy->dev, "xusbxti"); - if (IS_ERR(ref_clk)) { - dev_err(sphy->dev, "Failed to get reference clock\n"); - return PTR_ERR(ref_clk); - } - - if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) { - /* set clock frequency for PLL */ - switch (clk_get_rate(ref_clk)) { - case 9600 * KHZ: - refclk_freq = FSEL_CLKSEL_9600K; - break; - case 10 * MHZ: - refclk_freq = FSEL_CLKSEL_10M; - break; - case 12 * MHZ: - refclk_freq = FSEL_CLKSEL_12M; - break; - case 19200 * KHZ: - refclk_freq = FSEL_CLKSEL_19200K; - break; - case 20 * MHZ: - refclk_freq = FSEL_CLKSEL_20M; - break; - case 50 * MHZ: - refclk_freq = FSEL_CLKSEL_50M; - break; - case 24 * MHZ: - default: - /* default reference clock */ - refclk_freq = FSEL_CLKSEL_24M; - break; - } - } else { - switch (clk_get_rate(ref_clk)) { - case 12 * MHZ: - refclk_freq = PHYCLK_CLKSEL_12M; - break; - case 24 * MHZ: - refclk_freq = PHYCLK_CLKSEL_24M; - break; - case 48 * MHZ: - refclk_freq = PHYCLK_CLKSEL_48M; - break; - default: - if (sphy->drv_data->cpu_type == TYPE_S3C64XX) - refclk_freq = PHYCLK_CLKSEL_48M; - else - refclk_freq = PHYCLK_CLKSEL_24M; - break; - } - } - clk_put(ref_clk); - - return refclk_freq; -} - -static bool exynos5_phyhost_is_on(void *regs) -{ - u32 reg; - - reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0); - - return !(reg & HOST_CTRL0_SIDDQ); -} - -static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy) -{ - void __iomem *regs = sphy->regs; - u32 phyclk = sphy->ref_clk_freq; - u32 phyhost; - u32 phyotg; - u32 phyhsic; - u32 ehcictrl; - u32 ohcictrl; - - /* - * phy_usage helps in keeping usage count for phy - * so that the first consumer enabling the phy is also - * the last consumer to disable it. - */ - - atomic_inc(&sphy->phy_usage); - - if (exynos5_phyhost_is_on(regs)) { - dev_info(sphy->dev, "Already power on PHY\n"); - return; - } - - /* Host configuration */ - phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); - - /* phy reference clock configuration */ - phyhost &= ~HOST_CTRL0_FSEL_MASK; - phyhost |= HOST_CTRL0_FSEL(phyclk); - - /* host phy reset */ - phyhost &= ~(HOST_CTRL0_PHYSWRST | - HOST_CTRL0_PHYSWRSTALL | - HOST_CTRL0_SIDDQ | - /* Enable normal mode of operation */ - HOST_CTRL0_FORCESUSPEND | - HOST_CTRL0_FORCESLEEP); - - /* Link reset */ - phyhost |= (HOST_CTRL0_LINKSWRST | - HOST_CTRL0_UTMISWRST | - /* COMMON Block configuration during suspend */ - HOST_CTRL0_COMMONON_N); - writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); - udelay(10); - phyhost &= ~(HOST_CTRL0_LINKSWRST | - HOST_CTRL0_UTMISWRST); - writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); - - /* OTG configuration */ - phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); - - /* phy reference clock configuration */ - phyotg &= ~OTG_SYS_FSEL_MASK; - phyotg |= OTG_SYS_FSEL(phyclk); - - /* Enable normal mode of operation */ - phyotg &= ~(OTG_SYS_FORCESUSPEND | - OTG_SYS_SIDDQ_UOTG | - OTG_SYS_FORCESLEEP | - OTG_SYS_REFCLKSEL_MASK | - /* COMMON Block configuration during suspend */ - OTG_SYS_COMMON_ON); - - /* OTG phy & link reset */ - phyotg |= (OTG_SYS_PHY0_SWRST | - OTG_SYS_LINKSWRST_UOTG | - OTG_SYS_PHYLINK_SWRESET | - OTG_SYS_OTGDISABLE | - /* Set phy refclk */ - OTG_SYS_REFCLKSEL_CLKCORE); - - writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); - udelay(10); - phyotg &= ~(OTG_SYS_PHY0_SWRST | - OTG_SYS_LINKSWRST_UOTG | - OTG_SYS_PHYLINK_SWRESET); - writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); - - /* HSIC phy configuration */ - phyhsic = (HSIC_CTRL_REFCLKDIV_12 | - HSIC_CTRL_REFCLKSEL | - HSIC_CTRL_PHYSWRST); - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); - udelay(10); - phyhsic &= ~HSIC_CTRL_PHYSWRST; - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); - - udelay(80); - - /* enable EHCI DMA burst */ - ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL); - ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN | - HOST_EHCICTRL_ENAINCR4 | - HOST_EHCICTRL_ENAINCR8 | - HOST_EHCICTRL_ENAINCR16); - writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL); - - /* set ohci_suspend_on_n */ - ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL); - ohcictrl |= HOST_OHCICTRL_SUSPLGCY; - writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL); -} - -static void samsung_usbphy_enable(struct samsung_usbphy *sphy) -{ - void __iomem *regs = sphy->regs; - u32 phypwr; - u32 phyclk; - u32 rstcon; - - /* set clock frequency for PLL */ - phyclk = sphy->ref_clk_freq; - phypwr = readl(regs + SAMSUNG_PHYPWR); - rstcon = readl(regs + SAMSUNG_RSTCON); - - switch (sphy->drv_data->cpu_type) { - case TYPE_S3C64XX: - phyclk &= ~PHYCLK_COMMON_ON_N; - phypwr &= ~PHYPWR_NORMAL_MASK; - rstcon |= RSTCON_SWRST; - break; - case TYPE_EXYNOS4210: - phypwr &= ~PHYPWR_NORMAL_MASK_PHY0; - rstcon |= RSTCON_SWRST; - default: - break; - } - - writel(phyclk, regs + SAMSUNG_PHYCLK); - /* Configure PHY0 for normal operation*/ - writel(phypwr, regs + SAMSUNG_PHYPWR); - /* reset all ports of PHY and Link */ - writel(rstcon, regs + SAMSUNG_RSTCON); - udelay(10); - rstcon &= ~RSTCON_SWRST; - writel(rstcon, regs + SAMSUNG_RSTCON); -} - -static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy) -{ - void __iomem *regs = sphy->regs; - u32 phyhost; - u32 phyotg; - u32 phyhsic; - - if (atomic_dec_return(&sphy->phy_usage) > 0) { - dev_info(sphy->dev, "still being used\n"); - return; - } - - phyhsic = (HSIC_CTRL_REFCLKDIV_12 | - HSIC_CTRL_REFCLKSEL | - HSIC_CTRL_SIDDQ | - HSIC_CTRL_FORCESLEEP | - HSIC_CTRL_FORCESUSPEND); - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); - writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); - - phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); - phyhost |= (HOST_CTRL0_SIDDQ | - HOST_CTRL0_FORCESUSPEND | - HOST_CTRL0_FORCESLEEP | - HOST_CTRL0_PHYSWRST | - HOST_CTRL0_PHYSWRSTALL); - writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); - - phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); - phyotg |= (OTG_SYS_FORCESUSPEND | - OTG_SYS_SIDDQ_UOTG | - OTG_SYS_FORCESLEEP); - writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); -} - -static void samsung_usbphy_disable(struct samsung_usbphy *sphy) -{ - void __iomem *regs = sphy->regs; - u32 phypwr; - - phypwr = readl(regs + SAMSUNG_PHYPWR); - - switch (sphy->drv_data->cpu_type) { - case TYPE_S3C64XX: - phypwr |= PHYPWR_NORMAL_MASK; - break; - case TYPE_EXYNOS4210: - phypwr |= PHYPWR_NORMAL_MASK_PHY0; - default: - break; - } - - /* Disable analog and otg block power */ - writel(phypwr, regs + SAMSUNG_PHYPWR); -} - -/* - * The function passed to the usb driver for phy initialization - */ -static int samsung_usbphy_init(struct usb_phy *phy) -{ - struct samsung_usbphy *sphy; - struct usb_bus *host = NULL; - unsigned long flags; - int ret = 0; - - sphy = phy_to_sphy(phy); - - host = phy->otg->host; - - /* Enable the phy clock */ - ret = clk_prepare_enable(sphy->clk); - if (ret) { - dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); - return ret; - } - - spin_lock_irqsave(&sphy->lock, flags); - - if (host) { - /* setting default phy-type for USB 2.0 */ - if (!strstr(dev_name(host->controller), "ehci") || - !strstr(dev_name(host->controller), "ohci")) - samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); - } else { - samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); - } - - /* Disable phy isolation */ - if (sphy->plat && sphy->plat->pmu_isolation) - sphy->plat->pmu_isolation(false); - else - samsung_usbphy_set_isolation(sphy, false); - - /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */ - samsung_usbphy_cfg_sel(sphy); - - /* Initialize usb phy registers */ - if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) - samsung_exynos5_usbphy_enable(sphy); - else - samsung_usbphy_enable(sphy); - - spin_unlock_irqrestore(&sphy->lock, flags); - - /* Disable the phy clock */ - clk_disable_unprepare(sphy->clk); - - return ret; -} - -/* - * The function passed to the usb driver for phy shutdown - */ -static void samsung_usbphy_shutdown(struct usb_phy *phy) -{ - struct samsung_usbphy *sphy; - struct usb_bus *host = NULL; - unsigned long flags; - - sphy = phy_to_sphy(phy); - - host = phy->otg->host; - - if (clk_prepare_enable(sphy->clk)) { - dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); - return; - } - - spin_lock_irqsave(&sphy->lock, flags); - - if (host) { - /* setting default phy-type for USB 2.0 */ - if (!strstr(dev_name(host->controller), "ehci") || - !strstr(dev_name(host->controller), "ohci")) - samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); - } else { - samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); - } - - /* De-initialize usb phy registers */ - if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) - samsung_exynos5_usbphy_disable(sphy); - else - samsung_usbphy_disable(sphy); - - /* Enable phy isolation */ - if (sphy->plat && sphy->plat->pmu_isolation) - sphy->plat->pmu_isolation(true); - else - samsung_usbphy_set_isolation(sphy, true); - - spin_unlock_irqrestore(&sphy->lock, flags); - - clk_disable_unprepare(sphy->clk); -} - -static const struct of_device_id samsung_usbphy_dt_match[]; - -static inline const struct samsung_usbphy_drvdata -*samsung_usbphy_get_driver_data(struct platform_device *pdev) -{ - if (pdev->dev.of_node) { - const struct of_device_id *match; - match = of_match_node(samsung_usbphy_dt_match, - pdev->dev.of_node); - return match->data; - } - - return (struct samsung_usbphy_drvdata *) - platform_get_device_id(pdev)->driver_data; -} - -static int samsung_usbphy_probe(struct platform_device *pdev) -{ - struct samsung_usbphy *sphy; - struct usb_otg *otg; - struct samsung_usbphy_data *pdata = pdev->dev.platform_data; - const struct samsung_usbphy_drvdata *drv_data; - struct device *dev = &pdev->dev; - struct resource *phy_mem; - void __iomem *phy_base; - struct clk *clk; - int ret; - - phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!phy_mem) { - dev_err(dev, "%s: missing mem resource\n", __func__); - return -ENODEV; - } - - phy_base = devm_ioremap_resource(dev, phy_mem); - if (IS_ERR(phy_base)) - return PTR_ERR(phy_base); - - sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); - if (!sphy) - return -ENOMEM; - - otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL); - if (!otg) - return -ENOMEM; - - drv_data = samsung_usbphy_get_driver_data(pdev); - - if (drv_data->cpu_type == TYPE_EXYNOS5250) - clk = devm_clk_get(dev, "usbhost"); - else - clk = devm_clk_get(dev, "otg"); - - if (IS_ERR(clk)) { - dev_err(dev, "Failed to get otg clock\n"); - return PTR_ERR(clk); - } - - sphy->dev = dev; - - if (dev->of_node) { - ret = samsung_usbphy_parse_dt(sphy); - if (ret < 0) - return ret; - } else { - if (!pdata) { - dev_err(dev, "no platform data specified\n"); - return -EINVAL; - } - } - - sphy->plat = pdata; - sphy->regs = phy_base; - sphy->clk = clk; - sphy->drv_data = drv_data; - sphy->phy.dev = sphy->dev; - sphy->phy.label = "samsung-usbphy"; - sphy->phy.init = samsung_usbphy_init; - sphy->phy.shutdown = samsung_usbphy_shutdown; - sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy); - - sphy->phy.otg = otg; - sphy->phy.otg->phy = &sphy->phy; - sphy->phy.otg->set_host = samsung_usbphy_set_host; - - spin_lock_init(&sphy->lock); - - platform_set_drvdata(pdev, sphy); - - return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2); -} - -static int samsung_usbphy_remove(struct platform_device *pdev) -{ - struct samsung_usbphy *sphy = platform_get_drvdata(pdev); - - usb_remove_phy(&sphy->phy); - - if (sphy->pmuregs) - iounmap(sphy->pmuregs); - if (sphy->sysreg) - iounmap(sphy->sysreg); - - return 0; -} - -static const struct samsung_usbphy_drvdata usbphy_s3c64xx = { - .cpu_type = TYPE_S3C64XX, - .devphy_en_mask = S3C64XX_USBPHY_ENABLE, -}; - -static const struct samsung_usbphy_drvdata usbphy_exynos4 = { - .cpu_type = TYPE_EXYNOS4210, - .devphy_en_mask = EXYNOS_USBPHY_ENABLE, - .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, -}; - -static struct samsung_usbphy_drvdata usbphy_exynos5 = { - .cpu_type = TYPE_EXYNOS5250, - .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, - .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET, -}; - -#ifdef CONFIG_OF -static const struct of_device_id samsung_usbphy_dt_match[] = { - { - .compatible = "samsung,s3c64xx-usbphy", - .data = &usbphy_s3c64xx, - }, { - .compatible = "samsung,exynos4210-usbphy", - .data = &usbphy_exynos4, - }, { - .compatible = "samsung,exynos5250-usbphy", - .data = &usbphy_exynos5 - }, - {}, -}; -MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match); -#endif - -static struct platform_device_id samsung_usbphy_driver_ids[] = { - { - .name = "s3c64xx-usbphy", - .driver_data = (unsigned long)&usbphy_s3c64xx, - }, { - .name = "exynos4210-usbphy", - .driver_data = (unsigned long)&usbphy_exynos4, - }, { - .name = "exynos5250-usbphy", - .driver_data = (unsigned long)&usbphy_exynos5, - }, - {}, -}; - -MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids); - -static struct platform_driver samsung_usbphy_driver = { - .probe = samsung_usbphy_probe, - .remove = samsung_usbphy_remove, - .id_table = samsung_usbphy_driver_ids, - .driver = { - .name = "samsung-usbphy", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(samsung_usbphy_dt_match), - }, -}; - -module_platform_driver(samsung_usbphy_driver); - -MODULE_DESCRIPTION("Samsung USB phy controller"); -MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-usbphy"); diff --git a/drivers/usb/renesas_usbhs/Kconfig b/drivers/usb/renesas_usbhs/Kconfig index 29feb00d7f39..019bf7e49ee6 100644 --- a/drivers/usb/renesas_usbhs/Kconfig +++ b/drivers/usb/renesas_usbhs/Kconfig @@ -4,7 +4,7 @@ config USB_RENESAS_USBHS tristate 'Renesas USBHS controller' - depends on USB && USB_GADGET && GENERIC_HARDIRQS + depends on USB_GADGET && GENERIC_HARDIRQS default n help Renesas USBHS is a discrete USB host and peripheral controller chip diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 9538f0feafe2..45b94019aec8 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -32,7 +32,6 @@ */ void usbhs_pkt_init(struct usbhs_pkt *pkt) { - pkt->dma = DMA_ADDR_INVALID; INIT_LIST_HEAD(&pkt->node); } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index c31731a843d1..a168a1760fce 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -23,8 +23,6 @@ #include <asm/dma.h> #include "pipe.h" -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - struct usbhs_fifo { char *name; u32 port; /* xFIFO */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 78fca978b2d0..ed4949faa70d 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -230,7 +230,7 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, return 0; } -struct usbhsg_recip_handle req_clear_feature = { +static struct usbhsg_recip_handle req_clear_feature = { .name = "clear feature", .device = usbhsg_recip_handler_std_control_done, .interface = usbhsg_recip_handler_std_control_done, @@ -271,7 +271,7 @@ static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, return 0; } -struct usbhsg_recip_handle req_set_feature = { +static struct usbhsg_recip_handle req_set_feature = { .name = "set feature", .device = usbhsg_recip_handler_std_set_device, .interface = usbhsg_recip_handler_std_control_done, @@ -372,7 +372,7 @@ static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, return 0; } -struct usbhsg_recip_handle req_get_status = { +static struct usbhsg_recip_handle req_get_status = { .name = "get status", .device = usbhsg_recip_handler_std_get_device, .interface = usbhsg_recip_handler_std_get_interface, @@ -845,7 +845,6 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, /* first hook up the driver ... */ gpriv->driver = driver; - gpriv->gadget.dev.driver = &driver->driver; return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); } @@ -861,7 +860,6 @@ static int usbhsg_gadget_stop(struct usb_gadget *gadget, return -EINVAL; usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); - gpriv->gadget.dev.driver = NULL; gpriv->driver = NULL; return 0; @@ -925,11 +923,6 @@ static int usbhsg_stop(struct usbhs_priv *priv) return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); } -static void usbhs_mod_gadget_release(struct device *pdev) -{ - /* do nothing */ -} - int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv; @@ -976,15 +969,10 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) /* * init gadget */ - dev_set_name(&gpriv->gadget.dev, "gadget"); gpriv->gadget.dev.parent = dev; - gpriv->gadget.dev.release = usbhs_mod_gadget_release; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.max_speed = USB_SPEED_HIGH; - ret = device_register(&gpriv->gadget.dev); - if (ret < 0) - goto err_add_udc; INIT_LIST_HEAD(&gpriv->gadget.ep_list); @@ -1014,15 +1002,13 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) ret = usb_add_gadget_udc(dev, &gpriv->gadget); if (ret) - goto err_register; + goto err_add_udc; dev_info(dev, "gadget probed\n"); return 0; -err_register: - device_unregister(&gpriv->gadget.dev); err_add_udc: kfree(gpriv->uep); @@ -1038,8 +1024,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv) usb_del_gadget_udc(&gpriv->gadget); - device_unregister(&gpriv->gadget.dev); - kfree(gpriv->uep); kfree(gpriv); } diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 17b7f9ae36ad..1d55762afbb1 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -4,7 +4,7 @@ menuconfig USB_SERIAL tristate "USB Serial Converter support" - depends on USB && TTY + depends on TTY ---help--- Say Y here if you have a USB device that provides normal serial ports, or acts like a serial device, and you want to connect it to @@ -667,6 +667,23 @@ config USB_SERIAL_ZIO To compile this driver as a module, choose M here: the module will be called zio. +config USB_SERIAL_WISHBONE + tristate "USB-Wishbone adapter interface driver" + help + Say Y here if you want to use a USB attached Wishbone bus. + + Wishbone is an open hardware SoC bus commonly used in FPGA + designs. Bus access can be serialized using the Etherbone + protocol <http://www.ohwr.org/projects/etherbone-core>. + + This driver is intended to be used with devices which attach + their internal Wishbone bus to a USB serial interface using + the Etherbone protocol. A userspace library is required to + speak the protocol made available by this driver as ttyUSBx. + + To compile this driver as a module, choose M here: the + module will be called wishbone-serial. + config USB_SERIAL_ZTE tristate "ZTE USB serial driver" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index eaf5ca14dfeb..cec63fa19104 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o +obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 4775f8209e55..3b16118cbf62 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -62,7 +62,6 @@ static int is_irda(struct usb_serial *serial) } struct ark3116_private { - struct async_icount icount; int irda; /* 1 for irda device */ /* protects hw register updates */ @@ -341,18 +340,15 @@ static void ark3116_close(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - if (serial->dev) { - /* disable DMA */ - ark3116_write_reg(serial, UART_FCR, 0); - - /* deactivate interrupts */ - ark3116_write_reg(serial, UART_IER, 0); + /* disable DMA */ + ark3116_write_reg(serial, UART_FCR, 0); - usb_serial_generic_close(port); - if (serial->num_interrupt_in) - usb_kill_urb(port->interrupt_in_urb); - } + /* deactivate interrupts */ + ark3116_write_reg(serial, UART_IER, 0); + usb_serial_generic_close(port); + if (serial->num_interrupt_in) + usb_kill_urb(port->interrupt_in_urb); } static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -405,31 +401,10 @@ err_out: return result; } -static int ark3116_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - return 0; -} - static int ark3116_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); struct serial_struct serstruct; void __user *user_arg = (void __user *)arg; @@ -451,33 +426,6 @@ static int ark3116_ioctl(struct tty_struct *tty, if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) return -EFAULT; return 0; - case TIOCMIWAIT: - for (;;) { - struct async_icount prev = priv->icount; - interruptible_sleep_on(&port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - if ((prev.rng == priv->icount.rng) && - (prev.dsr == priv->icount.dsr) && - (prev.dcd == priv->icount.dcd) && - (prev.cts == priv->icount.cts)) - return -EIO; - if ((arg & TIOCM_RNG && - (prev.rng != priv->icount.rng)) || - (arg & TIOCM_DSR && - (prev.dsr != priv->icount.dsr)) || - (arg & TIOCM_CD && - (prev.dcd != priv->icount.dcd)) || - (arg & TIOCM_CTS && - (prev.cts != priv->icount.cts))) - return 0; - } - break; } return -ENOIOCTLCMD; @@ -575,14 +523,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr) if (msr & UART_MSR_ANY_DELTA) { /* update input line counters */ if (msr & UART_MSR_DCTS) - priv->icount.cts++; + port->icount.cts++; if (msr & UART_MSR_DDSR) - priv->icount.dsr++; + port->icount.dsr++; if (msr & UART_MSR_DDCD) - priv->icount.dcd++; + port->icount.dcd++; if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&port->delta_msr_wait); + port->icount.rng++; + wake_up_interruptible(&port->port.delta_msr_wait); } } @@ -598,13 +546,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr) if (lsr&UART_LSR_BRK_ERROR_BITS) { if (lsr & UART_LSR_BI) - priv->icount.brk++; + port->icount.brk++; if (lsr & UART_LSR_FE) - priv->icount.frame++; + port->icount.frame++; if (lsr & UART_LSR_PE) - priv->icount.parity++; + port->icount.parity++; if (lsr & UART_LSR_OE) - priv->icount.overrun++; + port->icount.overrun++; } } @@ -722,7 +670,8 @@ static struct usb_serial_driver ark3116_device = { .ioctl = ark3116_ioctl, .tiocmget = ark3116_tiocmget, .tiocmset = ark3116_tiocmset, - .get_icount = ark3116_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .open = ark3116_open, .close = ark3116_close, .break_ctl = ark3116_break_ctl, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 37decb13d7eb..3c4db6d196c6 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -106,14 +106,15 @@ static int usb_serial_device_remove(struct device *dev) /* make sure suspend/resume doesn't race against port_remove */ usb_autopm_get_interface(port->serial->interface); + minor = port->number; + tty_unregister_device(usb_serial_tty_driver, minor); + device_remove_file(&port->dev, &dev_attr_port_number); driver = port->serial->type; if (driver->port_remove) retval = driver->port_remove(port); - minor = port->number; - tty_unregister_device(usb_serial_tty_driver, minor); dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", driver->description, minor); diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 07d4650a32ab..c2a4171ab9cb 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -296,7 +296,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); spin_unlock_irqrestore(&priv->lock, flags); ch341_set_handshake(port->serial->dev, priv->line_control); - wake_up_interruptible(&port->delta_msr_wait); } static void ch341_close(struct usb_serial_port *port) @@ -489,7 +488,7 @@ static void ch341_read_int_callback(struct urb *urb) tty_kref_put(tty); } - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); } exit: @@ -500,8 +499,9 @@ exit: __func__, status); } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg) { + struct usb_serial_port *port = tty->driver_data; struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 prevstatus; @@ -515,7 +515,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) spin_unlock_irqrestore(&priv->lock, flags); while (!multi_change) { - interruptible_sleep_on(&port->delta_msr_wait); + interruptible_sleep_on(&port->port.delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -542,26 +542,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) return 0; } -static int ch341_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number); - return wait_modem_info(port, arg); - - default: - dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); - break; - } - - return -ENOIOCTLCMD; -} - static int ch341_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; @@ -611,11 +591,11 @@ static struct usb_serial_driver ch341_device = { .dtr_rts = ch341_dtr_rts, .carrier_raised = ch341_carrier_raised, .close = ch341_close, - .ioctl = ch341_ioctl, .set_termios = ch341_set_termios, .break_ctl = ch341_break_ctl, .tiocmget = ch341_tiocmget, .tiocmset = ch341_tiocmset, + .tiocmiwait = ch341_tiocmiwait, .read_int_callback = ch341_read_int_callback, .port_probe = ch341_port_probe, .port_remove = ch341_port_remove, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4747d1c328ff..2c659553c07c 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -462,11 +462,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) static void cp210x_close(struct usb_serial_port *port) { usb_serial_generic_close(port); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) - cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); - mutex_unlock(&port->serial->disc_mutex); + cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); } /* diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 629bd2894506..781426230d69 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -51,7 +51,6 @@ #define CYBERJACK_PRODUCT_ID 0x0100 /* Function prototypes */ -static void cyberjack_disconnect(struct usb_serial *serial); static int cyberjack_port_probe(struct usb_serial_port *port); static int cyberjack_port_remove(struct usb_serial_port *port); static int cyberjack_open(struct tty_struct *tty, @@ -79,7 +78,6 @@ static struct usb_serial_driver cyberjack_device = { .description = "Reiner SCT Cyberjack USB card reader", .id_table = id_table, .num_ports = 1, - .disconnect = cyberjack_disconnect, .port_probe = cyberjack_port_probe, .port_remove = cyberjack_port_remove, .open = cyberjack_open, @@ -130,20 +128,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port) { struct cyberjack_private *priv; + usb_kill_urb(port->interrupt_in_urb); + priv = usb_get_serial_port_data(port); kfree(priv); return 0; } -static void cyberjack_disconnect(struct usb_serial *serial) -{ - int i; - - for (i = 0; i < serial->num_ports; ++i) - usb_kill_urb(serial->port[i]->interrupt_in_urb); -} - static int cyberjack_open(struct tty_struct *tty, struct usb_serial_port *port) { @@ -166,11 +158,8 @@ static int cyberjack_open(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port) { - if (port->serial->dev) { - /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - } + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); } static int cyberjack_write(struct tty_struct *tty, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index ba7352e4187e..d341555d37d8 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -129,13 +129,12 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static void cypress_send(struct usb_serial_port *port); static int cypress_write_room(struct tty_struct *tty); -static int cypress_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); static void cypress_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static int cypress_tiocmget(struct tty_struct *tty); static int cypress_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); +static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg); static int cypress_chars_in_buffer(struct tty_struct *tty); static void cypress_throttle(struct tty_struct *tty); static void cypress_unthrottle(struct tty_struct *tty); @@ -158,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = { .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = cypress_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -184,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = { .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = cypress_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -210,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = { .dtr_rts = cypress_dtr_rts, .write = cypress_write, .write_room = cypress_write_room, - .ioctl = cypress_ioctl, .set_termios = cypress_set_termios, .tiocmget = cypress_tiocmget, .tiocmset = cypress_tiocmset, + .tiocmiwait = cypress_tiocmiwait, .chars_in_buffer = cypress_chars_in_buffer, .throttle = cypress_throttle, .unthrottle = cypress_unthrottle, @@ -633,12 +632,6 @@ static void cypress_close(struct usb_serial_port *port) struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - /* writing is potentially harmful, lock must be taken */ - mutex_lock(&port->serial->disc_mutex); - if (port->serial->disconnected) { - mutex_unlock(&port->serial->disc_mutex); - return; - } spin_lock_irqsave(&priv->lock, flags); kfifo_reset_out(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); @@ -650,7 +643,6 @@ static void cypress_close(struct usb_serial_port *port) if (stats) dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count); - mutex_unlock(&port->serial->disc_mutex); } /* cypress_close */ @@ -855,55 +847,43 @@ static int cypress_tiocmset(struct tty_struct *tty, } -static int cypress_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) +static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - - dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd); - - switch (cmd) { - /* This code comes from drivers/char/serial.c and ftdi_sio.c */ - case TIOCMIWAIT: - for (;;) { - interruptible_sleep_on(&port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - { - char diff = priv->diff_status; - if (diff == 0) - return -EIO; /* no change => error */ - - /* consume all events */ - priv->diff_status = 0; - - /* return 0 if caller wanted to know about - these bits */ - if (((arg & TIOCM_RNG) && (diff & UART_RI)) || - ((arg & TIOCM_DSR) && (diff & UART_DSR)) || - ((arg & TIOCM_CD) && (diff & UART_CD)) || - ((arg & TIOCM_CTS) && (diff & UART_CTS))) - return 0; - /* otherwise caller can't care less about what - * happened, and so we continue to wait for - * more events. - */ - } - } - return 0; - default: - break; + char diff; + + for (;;) { + interruptible_sleep_on(&port->port.delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + + if (port->serial->disconnected) + return -EIO; + + diff = priv->diff_status; + if (diff == 0) + return -EIO; /* no change => error */ + + /* consume all events */ + priv->diff_status = 0; + + /* return 0 if caller wanted to know about + these bits */ + if (((arg & TIOCM_RNG) && (diff & UART_RI)) || + ((arg & TIOCM_DSR) && (diff & UART_DSR)) || + ((arg & TIOCM_CD) && (diff & UART_CD)) || + ((arg & TIOCM_CTS) && (diff & UART_CTS))) + return 0; + /* otherwise caller can't care less about what + * happened, and so we continue to wait for + * more events. + */ } - dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd); - return -ENOIOCTLCMD; -} /* cypress_ioctl */ + return 0; +} static void cypress_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) @@ -1189,7 +1169,7 @@ static void cypress_read_int_callback(struct urb *urb) if (priv->current_status != priv->prev_status) { priv->diff_status |= priv->current_status ^ priv->prev_status; - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); priv->prev_status = priv->current_status; } spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 31191581060c..7b807d389527 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -196,7 +196,6 @@ struct digi_port { unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; int dp_write_urb_in_use; unsigned int dp_modem_signals; - wait_queue_head_t dp_modem_change_wait; int dp_transmit_idle; wait_queue_head_t dp_transmit_idle_wait; int dp_throttled; @@ -1138,53 +1137,51 @@ static void digi_close(struct usb_serial_port *port) if (port->serial->disconnected) goto exit; - if (port->serial->dev) { - /* FIXME: Transmit idle belongs in the wait_unti_sent path */ - digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); - - /* disable input flow control */ - buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[1] = priv->dp_port_num; - buf[2] = DIGI_DISABLE; - buf[3] = 0; - - /* disable output flow control */ - buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[5] = priv->dp_port_num; - buf[6] = DIGI_DISABLE; - buf[7] = 0; - - /* disable reading modem signals automatically */ - buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[9] = priv->dp_port_num; - buf[10] = DIGI_DISABLE; - buf[11] = 0; - - /* disable receive */ - buf[12] = DIGI_CMD_RECEIVE_ENABLE; - buf[13] = priv->dp_port_num; - buf[14] = DIGI_DISABLE; - buf[15] = 0; - - /* flush fifos */ - buf[16] = DIGI_CMD_IFLUSH_FIFO; - buf[17] = priv->dp_port_num; - buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[19] = 0; - - ret = digi_write_oob_command(port, buf, 20, 0); - if (ret != 0) - dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret); - - /* wait for final commands on oob port to complete */ - prepare_to_wait(&priv->dp_flush_wait, &wait, - TASK_INTERRUPTIBLE); - schedule_timeout(DIGI_CLOSE_TIMEOUT); - finish_wait(&priv->dp_flush_wait, &wait); - - /* shutdown any outstanding bulk writes */ - usb_kill_urb(port->write_urb); - } + /* FIXME: Transmit idle belongs in the wait_unti_sent path */ + digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); + + /* disable input flow control */ + buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; + buf[1] = priv->dp_port_num; + buf[2] = DIGI_DISABLE; + buf[3] = 0; + + /* disable output flow control */ + buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; + buf[5] = priv->dp_port_num; + buf[6] = DIGI_DISABLE; + buf[7] = 0; + + /* disable reading modem signals automatically */ + buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; + buf[9] = priv->dp_port_num; + buf[10] = DIGI_DISABLE; + buf[11] = 0; + + /* disable receive */ + buf[12] = DIGI_CMD_RECEIVE_ENABLE; + buf[13] = priv->dp_port_num; + buf[14] = DIGI_DISABLE; + buf[15] = 0; + + /* flush fifos */ + buf[16] = DIGI_CMD_IFLUSH_FIFO; + buf[17] = priv->dp_port_num; + buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; + buf[19] = 0; + + ret = digi_write_oob_command(port, buf, 20, 0); + if (ret != 0) + dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", + ret); + /* wait for final commands on oob port to complete */ + prepare_to_wait(&priv->dp_flush_wait, &wait, + TASK_INTERRUPTIBLE); + schedule_timeout(DIGI_CLOSE_TIMEOUT); + finish_wait(&priv->dp_flush_wait, &wait); + + /* shutdown any outstanding bulk writes */ + usb_kill_urb(port->write_urb); exit: spin_lock_irq(&priv->dp_port_lock); priv->dp_write_urb_in_use = 0; @@ -1241,7 +1238,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num) spin_lock_init(&priv->dp_port_lock); priv->dp_port_num = port_num; - init_waitqueue_head(&priv->dp_modem_change_wait); init_waitqueue_head(&priv->dp_transmit_idle_wait); init_waitqueue_head(&priv->dp_flush_wait); init_waitqueue_head(&priv->dp_close_wait); @@ -1532,7 +1528,6 @@ static int digi_read_oob_callback(struct urb *urb) else priv->dp_modem_signals &= ~TIOCM_CD; - wake_up_interruptible(&priv->dp_modem_change_wait); spin_unlock(&priv->dp_port_lock); } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { spin_lock(&priv->dp_port_lock); diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index a172ad5c5ce8..090b411d893f 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -110,7 +110,7 @@ static void f81232_process_read_urb(struct urb *urb) line_status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); if (!urb->actual_length) return; @@ -242,8 +242,9 @@ static int f81232_carrier_raised(struct usb_serial_port *port) return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int f81232_tiocmiwait(struct tty_struct *tty, unsigned long arg) { + struct usb_serial_port *port = tty->driver_data; struct f81232_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prevstatus; @@ -255,7 +256,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) spin_unlock_irqrestore(&priv->lock, flags); while (1) { - interruptible_sleep_on(&port->delta_msr_wait); + interruptible_sleep_on(&port->port.delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -302,11 +303,6 @@ static int f81232_ioctl(struct tty_struct *tty, return -EFAULT; return 0; - - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, - port->number); - return wait_modem_info(port, arg); default: dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); @@ -358,6 +354,7 @@ static struct usb_serial_driver f81232_device = { .set_termios = f81232_set_termios, .tiocmget = f81232_tiocmget, .tiocmset = f81232_tiocmset, + .tiocmiwait = f81232_tiocmiwait, .process_read_urb = f81232_process_read_urb, .read_int_callback = f81232_read_int_callback, .port_probe = f81232_port_probe, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 9886180e45f1..242b5776648a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,7 +1,7 @@ /* * USB FTDI SIO driver * - * Copyright (C) 2009 - 2010 + * Copyright (C) 2009 - 2013 * Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2001 * Greg Kroah-Hartman (greg@kroah.com) @@ -55,7 +55,6 @@ static __u16 vendor = FTDI_VID; static __u16 product; struct ftdi_private { - struct kref kref; enum ftdi_chip_type chip_type; /* type of device, either SIO or FT8U232AM */ int baud_base; /* baud base clock for divisor setting */ @@ -68,7 +67,6 @@ struct ftdi_private { */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ - struct async_icount icount; char prev_status; /* Used for TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ __u16 interface; /* FT2232C, FT2232H or FT4232H port interface @@ -189,6 +187,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) }, { USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, @@ -870,7 +869,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), + { USB_DEVICE(ST_VID, ST_STMCLT_2232_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(ST_VID, ST_STMCLT_4232_PID), .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), @@ -911,7 +912,6 @@ static int ftdi_sio_probe(struct usb_serial *serial, static int ftdi_sio_port_probe(struct usb_serial_port *port); static int ftdi_sio_port_remove(struct usb_serial_port *port); static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_close(struct usb_serial_port *port); static void ftdi_dtr_rts(struct usb_serial_port *port, int on); static void ftdi_process_read_urb(struct urb *urb); static int ftdi_prepare_write_buffer(struct usb_serial_port *port, @@ -921,8 +921,6 @@ static void ftdi_set_termios(struct tty_struct *tty, static int ftdi_tiocmget(struct tty_struct *tty); static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int ftdi_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void ftdi_break_ctl(struct tty_struct *tty, int break_state); @@ -951,7 +949,6 @@ static struct usb_serial_driver ftdi_sio_device = { .port_probe = ftdi_sio_port_probe, .port_remove = ftdi_sio_port_remove, .open = ftdi_open, - .close = ftdi_close, .dtr_rts = ftdi_dtr_rts, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, @@ -959,7 +956,8 @@ static struct usb_serial_driver ftdi_sio_device = { .prepare_write_buffer = ftdi_prepare_write_buffer, .tiocmget = ftdi_tiocmget, .tiocmset = ftdi_tiocmset, - .get_icount = ftdi_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .ioctl = ftdi_ioctl, .set_termios = ftdi_set_termios, .break_ctl = ftdi_break_ctl, @@ -1688,7 +1686,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) return -ENOMEM; } - kref_init(&priv->kref); mutex_init(&priv->cfg_lock); priv->flags = ASYNC_LOW_LATENCY; @@ -1792,20 +1789,24 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) } /* - * First and second port on STMCLiteadaptors is reserved for JTAG interface - * and the forth port for pio + * First two ports on JTAG adaptors using an FT4232 such as STMicroelectronics's + * ST Micro Connect Lite are reserved for JTAG or other non-UART interfaces and + * can be accessed from userspace. + * The next two ports are enabled as UARTs by default, where port 2 is + * a conventional RS-232 UART. */ static int ftdi_stmclite_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - if (interface == udev->actconfig->interface[2]) - return 0; - - dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); + if (interface == udev->actconfig->interface[0] || + interface == udev->actconfig->interface[1]) { + dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); + return -ENODEV; + } - return -ENODEV; + return 0; } /* @@ -1826,22 +1827,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) return 0; } -static void ftdi_sio_priv_release(struct kref *k) -{ - struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); - - kfree(priv); -} - static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - wake_up_interruptible(&port->delta_msr_wait); - remove_sysfs_attrs(port); - kref_put(&priv->kref, ftdi_sio_priv_release); + kfree(priv); return 0; } @@ -1851,7 +1843,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) struct ktermios dummy; struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); - int result; /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ @@ -1870,12 +1861,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) ftdi_set_termios(tty, port, &dummy); } - /* Start reading from the device */ - result = usb_serial_generic_open(tty, port); - if (!result) - kref_get(&priv->kref); - - return result; + return usb_serial_generic_open(tty, port); } static void ftdi_dtr_rts(struct usb_serial_port *port, int on) @@ -1900,19 +1886,6 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on) clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } -/* - * usbserial:__serial_close only calls ftdi_close if the point is open - * - * This only gets called when it is the last close - */ -static void ftdi_close(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - usb_serial_generic_close(port); - kref_put(&priv->kref, ftdi_sio_priv_release); -} - /* The SIO requires the first byte to have: * B0 1 * B1 0 @@ -1940,7 +1913,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); if (!c) break; - priv->icount.tx += c; + port->icount.tx += c; buffer[i] = (c << 2) + 1; count += c + 1; } @@ -1948,7 +1921,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port, } else { count = kfifo_out_locked(&port->write_fifo, dest, size, &port->lock); - priv->icount.tx += count; + port->icount.tx += count; } return count; @@ -1977,15 +1950,15 @@ static int ftdi_process_packet(struct usb_serial_port *port, char diff_status = status ^ priv->prev_status; if (diff_status & FTDI_RS0_CTS) - priv->icount.cts++; + port->icount.cts++; if (diff_status & FTDI_RS0_DSR) - priv->icount.dsr++; + port->icount.dsr++; if (diff_status & FTDI_RS0_RI) - priv->icount.rng++; + port->icount.rng++; if (diff_status & FTDI_RS0_RLSD) - priv->icount.dcd++; + port->icount.dcd++; - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); priv->prev_status = status; } @@ -1995,18 +1968,18 @@ static int ftdi_process_packet(struct usb_serial_port *port, * over framing errors */ if (packet[1] & FTDI_RS_BI) { flag = TTY_BREAK; - priv->icount.brk++; + port->icount.brk++; usb_serial_handle_break(port); } else if (packet[1] & FTDI_RS_PE) { flag = TTY_PARITY; - priv->icount.parity++; + port->icount.parity++; } else if (packet[1] & FTDI_RS_FE) { flag = TTY_FRAME; - priv->icount.frame++; + port->icount.frame++; } /* Overrun is special, not associated with a char */ if (packet[1] & FTDI_RS_OE) { - priv->icount.overrun++; + port->icount.overrun++; tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); } } @@ -2020,7 +1993,7 @@ static int ftdi_process_packet(struct usb_serial_port *port, len -= 2; if (!len) return 0; /* status only */ - priv->icount.rx += len; + port->icount.rx += len; ch = packet + 2; if (port->port.console && port->sysrq) { @@ -2384,34 +2357,10 @@ static int ftdi_tiocmset(struct tty_struct *tty, return update_mctrl(port, set, clear); } -static int ftdi_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct async_icount *ic = &priv->icount; - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->tx = ic->tx; - icount->rx = ic->rx; - icount->frame = ic->frame; - icount->parity = ic->parity; - icount->overrun = ic->overrun; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - return 0; -} - static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); @@ -2425,35 +2374,6 @@ static int ftdi_ioctl(struct tty_struct *tty, case TIOCSSERIAL: /* sets serial port data */ return set_serial_info(tty, port, (struct serial_struct __user *) arg); - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was. - * - * This code is borrowed from linux/drivers/char/serial.c - */ - case TIOCMIWAIT: - cprev = priv->icount; - for (;;) { - interruptible_sleep_on(&port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - cnow = priv->icount; - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } case TIOCSERGETLSR: return get_lsr_info(port, (struct serial_struct __user *)arg); break; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index e79861eeed4c..98528270c43c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -74,6 +74,7 @@ #define FTDI_OPENDCC_THROTTLE_PID 0xBFDA #define FTDI_OPENDCC_GATEWAY_PID 0xBFDB #define FTDI_OPENDCC_GBM_PID 0xBFDC +#define FTDI_OPENDCC_GBM_BOOST_PID 0xBFDD /* NZR SEM 16+ USB (http://www.nzr.de) */ #define FTDI_NZR_SEM_USB_PID 0xC1E0 /* NZR SEM-LOG16+ */ @@ -1150,7 +1151,8 @@ * STMicroelectonics */ #define ST_VID 0x0483 -#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ +#define ST_STMCLT_2232_PID 0x3746 +#define ST_STMCLT_4232_PID 0x3747 /* * Papouch products (http://www.papouch.com/) diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 81caf5623ee2..b110c573ea85 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -946,16 +946,12 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) static void garmin_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n", __func__, port->number, garmin_data_p->mode, garmin_data_p->state, garmin_data_p->flags); - if (!serial) - return; - garmin_clear(garmin_data_p); /* shutdown our urbs */ @@ -1185,17 +1181,11 @@ static void garmin_read_bulk_callback(struct urb *urb) { unsigned long flags; struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; int status = urb->status; int retval; - if (!serial) { - dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__); - return; - } - if (status) { dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", __func__, status); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 4c5c23f1cae5..297665fdd16d 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,7 +1,7 @@ /* * USB Serial Converter Generic functions * - * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or @@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = { }, .id_table = generic_device_ids, .num_ports = 1, - .disconnect = usb_serial_generic_disconnect, - .release = usb_serial_generic_release, .throttle = usb_serial_generic_throttle, .unthrottle = usb_serial_generic_unthrottle, .resume = usb_serial_generic_resume, @@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port } EXPORT_SYMBOL_GPL(usb_serial_generic_open); -static void generic_cleanup(struct usb_serial_port *port) +void usb_serial_generic_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; unsigned long flags; int i; - if (serial->dev) { - /* shutdown any bulk transfers that might be going on */ - if (port->bulk_out_size) { - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); + if (port->bulk_out_size) { + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_kill_urb(port->write_urbs[i]); - spin_lock_irqsave(&port->lock, flags); - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - } - if (port->bulk_in_size) { - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); - } + spin_lock_irqsave(&port->lock, flags); + kfifo_reset_out(&port->write_fifo); + spin_unlock_irqrestore(&port->lock, flags); + } + if (port->bulk_in_size) { + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_kill_urb(port->read_urbs[i]); } -} - -void usb_serial_generic_close(struct usb_serial_port *port) -{ - generic_cleanup(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_close); @@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, if (!test_and_clear_bit(index, &port->read_urbs_free)) return 0; - dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__, - port->number, index); + dev_dbg(&port->dev, "%s - urb %d\n", __func__, index); res = usb_submit_urb(port->read_urbs[index], mem_flags); if (res) { @@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) } set_bit(i, &port->read_urbs_free); - dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n", - __func__, port->number, i, urb->actual_length); + dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, + urb->actual_length); if (urb->status) { dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", @@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); +static bool usb_serial_generic_msr_changed(struct tty_struct *tty, + unsigned long arg, struct async_icount *cprev) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + bool ret; + + /* + * Use tty-port initialised flag to detect all hangups including the + * one generated at USB-device disconnect. + * + * FIXME: Remove hupping check once tty_port_hangup calls shutdown + * (which clears the initialised flag) before wake up. + */ + if (test_bit(TTY_HUPPING, &tty->flags)) + return true; + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + return true; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy*/ + spin_unlock_irqrestore(&port->lock, flags); + + ret = ((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); + + *cprev = cnow; + + return ret; +} + +int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + int ret; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy */ + spin_unlock_irqrestore(&port->lock, flags); + + ret = wait_event_interruptible(port->port.delta_msr_wait, + usb_serial_generic_msr_changed(tty, arg, &cnow)); + if (!ret) { + if (test_bit(TTY_HUPPING, &tty->flags)) + ret = -EIO; + if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) + ret = -EIO; + } + + return ret; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait); + +int usb_serial_generic_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + struct async_icount cnow; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + cnow = port->icount; /* atomic copy */ + spin_unlock_irqrestore(&port->lock, flags); + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->tx = cnow.tx; + icount->rx = cnow.rx; + icount->frame = cnow.frame; + icount->parity = cnow.parity; + icount->overrun = cnow.overrun; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; + + return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount); + #ifdef CONFIG_MAGIC_SYSRQ int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) { @@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, { struct tty_port *port = &usb_port->port; - dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__, - usb_port->number, status); + dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status); if (status) wake_up_interruptible(&port->open_wait); @@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial) return c ? -EIO : 0; } EXPORT_SYMBOL_GPL(usb_serial_generic_resume); - -void usb_serial_generic_disconnect(struct usb_serial *serial) -{ - int i; - - /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) - generic_cleanup(serial->port[i]); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); - -void usb_serial_generic_release(struct usb_serial *serial) -{ -} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index cf0b0a2f7b56..1477e8593476 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -111,7 +111,6 @@ struct edgeport_port { wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner of this object */ }; @@ -215,8 +214,6 @@ static void edge_break(struct tty_struct *tty, int break_state); static int edge_tiocmget(struct tty_struct *tty); static int edge_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static int edge_startup(struct usb_serial *serial); static void edge_disconnect(struct usb_serial *serial); static void edge_release(struct usb_serial *serial); @@ -867,9 +864,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) init_waitqueue_head(&edge_port->wait_chase); init_waitqueue_head(&edge_port->wait_command); - /* initialize our icount structure */ - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - /* initialize our port settings */ edge_port->txCredits = 0; /* Can't send any data yet */ /* Must always set this bit to enable ints! */ @@ -1296,7 +1290,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, /* decrement the number of credits we have by the number we just sent */ edge_port->txCredits -= count; - edge_port->icount.tx += count; + edge_port->port->icount.tx += count; status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { @@ -1308,7 +1302,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, /* revert the credits as something bad happened. */ edge_port->txCredits += count; - edge_port->icount.tx -= count; + edge_port->port->icount.tx -= count; } dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n", __func__, count, edge_port->txCredits, fifo->count); @@ -1570,31 +1564,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - cnow = edge_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__, - port->number, icount->rx, icount->tx); - return 0; -} - static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct __user *retinfo) { @@ -1631,8 +1600,6 @@ static int edge_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; DEFINE_WAIT(wait); struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); @@ -1644,37 +1611,6 @@ static int edge_ioctl(struct tty_struct *tty, case TIOCGSERIAL: dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__, port->number); return get_serial_info(edge_port, (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, port->number); - cprev = edge_port->icount; - while (1) { - prepare_to_wait(&port->delta_msr_wait, - &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(&port->delta_msr_wait, &wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - } return -ENOIOCTLCMD; } @@ -1848,7 +1784,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, edge_serial->rxPort); edge_tty_recv(edge_port->port, buffer, rxLen); - edge_port->icount.rx += rxLen; + edge_port->port->icount.rx += rxLen; } buffer += rxLen; } @@ -2024,7 +1960,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; + icount = &edge_port->port->icount; /* update input line counters */ if (newMsr & EDGEPORT_MSR_DELTA_CTS) @@ -2035,7 +1971,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) icount->dcd++; if (newMsr & EDGEPORT_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&edge_port->port->delta_msr_wait); + wake_up_interruptible(&edge_port->port->port.delta_msr_wait); } /* Save the new modem status */ @@ -2070,7 +2006,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, edge_tty_recv(edge_port->port, &data, 1); /* update input line counters */ - icount = &edge_port->icount; + icount = &edge_port->port->icount; if (newLsr & LSR_BREAK) icount->brk++; if (newLsr & LSR_OVER_ERR) diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 1511dd0ad324..ae5fac5656c9 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -116,7 +116,8 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -147,7 +148,8 @@ static struct usb_serial_driver edgeport_4port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -178,7 +180,8 @@ static struct usb_serial_driver edgeport_8port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -209,7 +212,8 @@ static struct usb_serial_driver epic_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 7777172206de..158bf4bc29cc 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -86,7 +86,7 @@ struct edgeport_port { int baud_rate; int close_pending; int lsr_event; - struct async_icount icount; + struct edgeport_serial *edge_serial; struct usb_serial_port *port; __u8 bUartMode; /* Port type, 0: RS232, etc. */ @@ -206,7 +206,7 @@ static int restart_read(struct edgeport_port *edge_port); static void edge_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); -static void edge_send(struct tty_struct *tty); +static void edge_send(struct usb_serial_port *port, struct tty_struct *tty); /* sysfs attributes */ static int edge_create_sysfs_attrs(struct usb_serial_port *port); @@ -1445,7 +1445,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; + icount = &edge_port->port->icount; /* update input line counters */ if (msr & EDGEPORT_MSR_DELTA_CTS) @@ -1456,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) icount->dcd++; if (msr & EDGEPORT_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&edge_port->port->delta_msr_wait); + wake_up_interruptible(&edge_port->port->port.delta_msr_wait); } /* Save the new modem status */ @@ -1498,7 +1498,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, edge_tty_recv(edge_port->port, &data, 1); /* update input line counters */ - icount = &edge_port->icount; + icount = &edge_port->port->icount; if (new_lsr & LSR_BREAK) icount->brk++; if (new_lsr & LSR_OVER_ERR) @@ -1657,7 +1657,7 @@ static void edge_bulk_in_callback(struct urb *urb) else edge_tty_recv(edge_port->port, data, urb->actual_length); - edge_port->icount.rx += urb->actual_length; + edge_port->port->icount.rx += urb->actual_length; } exit: @@ -1712,7 +1712,7 @@ static void edge_bulk_out_callback(struct urb *urb) /* send any buffered data */ tty = tty_port_tty_get(&port->port); - edge_send(tty); + edge_send(port, tty); tty_kref_put(tty); } @@ -1750,8 +1750,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) dev = port->serial->dev; - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - /* turn off loopback */ status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0); if (status) { @@ -1909,21 +1907,10 @@ static void edge_close(struct usb_serial_port *port) kfifo_reset_out(&edge_port->write_fifo); spin_unlock_irqrestore(&edge_port->ep_lock, flags); - /* assuming we can still talk to the device, - * send a close port command to it */ dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__); port_number = port->number - port->serial->minor; - - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) { - send_cmd(serial->dev, - UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - 0, - NULL, - 0); - } - mutex_unlock(&serial->disc_mutex); + send_cmd(serial->dev, UMPC_CLOSE_PORT, + (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; @@ -1953,14 +1940,13 @@ static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, count = kfifo_in_locked(&edge_port->write_fifo, data, count, &edge_port->ep_lock); - edge_send(tty); + edge_send(port, tty); return count; } -static void edge_send(struct tty_struct *tty) +static void edge_send(struct usb_serial_port *port, struct tty_struct *tty) { - struct usb_serial_port *port = tty->driver_data; int count, result; struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned long flags; @@ -1999,7 +1985,7 @@ static void edge_send(struct tty_struct *tty) edge_port->ep_write_urb_in_use = 0; /* TODO: reschedule edge_send */ } else - edge_port->icount.tx += count; + edge_port->port->icount.tx += count; /* wakeup any process waiting for writes to complete */ /* there is now more room in the buffer for new writes */ @@ -2360,27 +2346,6 @@ static int edge_tiocmget(struct tty_struct *tty) return result; } -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount *ic = &edge_port->icount; - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->tx = ic->tx; - icount->rx = ic->rx; - icount->frame = ic->frame; - icount->parity = ic->parity; - icount->overrun = ic->overrun; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - return 0; -} - static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct __user *retinfo) { @@ -2392,7 +2357,7 @@ static int get_serial_info(struct edgeport_port *edge_port, cwait = edge_port->port->port.closing_wait; if (cwait != ASYNC_CLOSING_WAIT_NONE) - cwait = jiffies_to_msecs(closing_wait) / 10; + cwait = jiffies_to_msecs(cwait) / 10; memset(&tmp, 0, sizeof(tmp)); @@ -2416,8 +2381,6 @@ static int edge_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); @@ -2426,32 +2389,6 @@ static int edge_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); return get_serial_info(edge_port, (struct serial_struct __user *) arg); - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); - cprev = edge_port->icount; - while (1) { - interruptible_sleep_on(&port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* not reached */ - break; } return -ENOIOCTLCMD; } @@ -2463,8 +2400,6 @@ static void edge_break(struct tty_struct *tty, int break_state) int status; int bv = 0; /* Off */ - tty_wait_until_sent(tty, 0); - if (break_state == -1) bv = 1; /* On */ status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); @@ -2546,7 +2481,6 @@ static int edge_port_remove(struct usb_serial_port *port) struct edgeport_port *edge_port; edge_port = usb_get_serial_port_data(port); - edge_remove_sysfs_attrs(port); kfifo_free(&edge_port->write_fifo); kfree(edge_port); @@ -2618,7 +2552,8 @@ static struct usb_serial_driver edgeport_1port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, @@ -2649,7 +2584,8 @@ static struct usb_serial_driver edgeport_2port_device = { .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .write = edge_write, .write_room = edge_write_room, .chars_in_buffer = edge_chars_in_buffer, diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index ff77027160aa..9d74c278b7b5 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -55,7 +55,6 @@ static void read_rxcmd_callback(struct urb *urb); struct iuu_private { spinlock_t lock; /* store irq state */ - wait_queue_head_t delta_msr_wait; u8 line_status; int tiostatus; /* store IUART SIGNAL for tiocmget call */ u8 reset; /* if 1 reset is needed */ @@ -94,7 +93,6 @@ static int iuu_port_probe(struct usb_serial_port *port) priv->vcc = vcc_default; spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); usb_set_serial_port_data(port, priv); @@ -944,22 +942,13 @@ static void iuu_set_termios(struct tty_struct *tty, static void iuu_close(struct usb_serial_port *port) { /* iuu_led (port,255,0,0,0); */ - struct usb_serial *serial; - - serial = port->serial; - if (!serial) - return; iuu_uart_off(port); - if (serial->dev) { - /* free writebuf */ - /* shutdown our urbs */ - dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - iuu_led(port, 0, 0, 0xF000, 0xFF); - } + + usb_kill_urb(port->write_urb); + usb_kill_urb(port->read_urb); + + iuu_led(port, 0, 0, 0xF000, 0xFF); } static void iuu_init_termios(struct tty_struct *tty) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index b011478d2e5f..eb30d7b01f36 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -712,45 +712,45 @@ static void usa49wg_indat_callback(struct urb *urb) i = 0; len = 0; - if (urb->actual_length) { - while (i < urb->actual_length) { + while (i < urb->actual_length) { - /* Check port number from message*/ - if (data[i] >= serial->num_ports) { - dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", - __func__, data[i]); - return; - } - port = serial->port[data[i++]]; - len = data[i++]; + /* Check port number from message */ + if (data[i] >= serial->num_ports) { + dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", + __func__, data[i]); + return; + } + port = serial->port[data[i++]]; + len = data[i++]; - /* 0x80 bit is error flag */ - if ((data[i] & 0x80) == 0) { - /* no error on any byte */ - i++; - for (x = 1; x < len ; ++x) - tty_insert_flip_char(&port->port, - data[i++], 0); - } else { - /* - * some bytes had errors, every byte has status - */ - for (x = 0; x + 1 < len; x += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(&port->port, - data[i+1], flag); - i += 2; - } + /* 0x80 bit is error flag */ + if ((data[i] & 0x80) == 0) { + /* no error on any byte */ + i++; + for (x = 1; x < len && i < urb->actual_length; ++x) + tty_insert_flip_char(&port->port, + data[i++], 0); + } else { + /* + * some bytes had errors, every byte has status + */ + for (x = 0; x + 1 < len && + i + 1 < urb->actual_length; x += 2) { + int stat = data[i], flag = 0; + + if (stat & RXERROR_OVERRUN) + flag |= TTY_OVERRUN; + if (stat & RXERROR_FRAMING) + flag |= TTY_FRAME; + if (stat & RXERROR_PARITY) + flag |= TTY_PARITY; + /* XXX should handle break (0x10) */ + tty_insert_flip_char(&port->port, data[i+1], + flag); + i += 2; } - tty_flip_buffer_push(&port->port); } + tty_flip_buffer_push(&port->port); } /* Resubmit urb so we continue receiving */ @@ -1092,7 +1092,6 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on) static void keyspan_close(struct usb_serial_port *port) { int i; - struct usb_serial *serial = port->serial; struct keyspan_port_private *p_priv; p_priv = usb_get_serial_port_data(port); @@ -1100,28 +1099,17 @@ static void keyspan_close(struct usb_serial_port *port) p_priv->rts_state = 0; p_priv->dtr_state = 0; - if (serial->dev) { - keyspan_send_setup(port, 2); - /* pilot-xfer seems to work best with this delay */ - mdelay(100); - /* keyspan_set_termios(port, NULL); */ - } - - /*while (p_priv->outcont_urb->status == -EINPROGRESS) { - dev_dbg(&port->dev, "%s - urb in progress\n", __func__); - }*/ + keyspan_send_setup(port, 2); + /* pilot-xfer seems to work best with this delay */ + mdelay(100); p_priv->out_flip = 0; p_priv->in_flip = 0; - if (serial->dev) { - /* Stop reading/writing urbs */ - stop_urb(p_priv->inack_urb); - /* stop_urb(p_priv->outcont_urb); */ - for (i = 0; i < 2; i++) { - stop_urb(p_priv->in_urbs[i]); - stop_urb(p_priv->out_urbs[i]); - } + stop_urb(p_priv->inack_urb); + for (i = 0; i < 2; i++) { + stop_urb(p_priv->in_urbs[i]); + stop_urb(p_priv->out_urbs[i]); } } diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 2230223978ca..5f1d382e55cf 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -593,12 +593,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; - if (serial->dev) { - if (on) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2)); - else - keyspan_pda_set_modem_info(serial, 0); - } + if (on) + keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2)); + else + keyspan_pda_set_modem_info(serial, 0); } @@ -649,13 +647,8 @@ error: } static void keyspan_pda_close(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; - - if (serial->dev) { - /* shutdown our bulk reads and writes */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->interrupt_in_urb); - } + usb_kill_urb(port->write_urb); + usb_kill_urb(port->interrupt_in_urb); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 769d910ae0a5..1b4054fe52a5 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -341,28 +341,20 @@ static void klsi_105_close(struct usb_serial_port *port) { int rc; - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* send READ_OFF */ - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR | USB_DIR_OUT, - KL5KUSB105A_SIO_CONFIGURE_READ_OFF, - 0, /* index */ - NULL, 0, - KLSI_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, - "Disabling read failed (error = %d)\n", rc); - } - mutex_unlock(&port->serial->disc_mutex); + /* send READ_OFF */ + rc = usb_control_msg(port->serial->dev, + usb_sndctrlpipe(port->serial->dev, 0), + KL5KUSB105A_SIO_CONFIGURE, + USB_TYPE_VENDOR | USB_DIR_OUT, + KL5KUSB105A_SIO_CONFIGURE_READ_OFF, + 0, /* index */ + NULL, 0, + KLSI_TIMEOUT); + if (rc < 0) + dev_err(&port->dev, "failed to disable read: %d\n", rc); /* shutdown our bulk reads and writes */ usb_serial_generic_close(port); - - /* wgg - do I need this? I think so. */ - usb_kill_urb(port->interrupt_in_urb); } /* We need to write a complete 64-byte data block and encode the diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 903d938e174b..78b48c31abf5 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -65,7 +65,7 @@ static int kobil_tiocmget(struct tty_struct *tty); static int kobil_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void kobil_read_int_callback(struct urb *urb); -static void kobil_write_callback(struct urb *purb); +static void kobil_write_int_callback(struct urb *urb); static void kobil_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void kobil_init_termios(struct tty_struct *tty); @@ -99,6 +99,7 @@ static struct usb_serial_driver kobil_device = { .write = kobil_write, .write_room = kobil_write_room, .read_int_callback = kobil_read_int_callback, + .write_int_callback = kobil_write_int_callback, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -106,8 +107,6 @@ static struct usb_serial_driver * const serial_drivers[] = { }; struct kobil_private { - int write_int_endpoint_address; - int read_int_endpoint_address; unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */ int filled; /* index of the last char in buf */ int cur_pos; /* index of the next char to send in buf */ @@ -117,14 +116,8 @@ struct kobil_private { static int kobil_port_probe(struct usb_serial_port *port) { - int i; struct usb_serial *serial = port->serial; struct kobil_private *priv; - struct usb_device *pdev; - struct usb_host_config *actconfig; - struct usb_interface *interface; - struct usb_host_interface *altsetting; - struct usb_host_endpoint *endpoint; priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL); if (!priv) @@ -150,30 +143,6 @@ static int kobil_port_probe(struct usb_serial_port *port) } usb_set_serial_port_data(port, priv); - /* search for the necessary endpoints */ - pdev = serial->dev; - actconfig = pdev->actconfig; - interface = actconfig->interface[0]; - altsetting = interface->cur_altsetting; - endpoint = altsetting->endpoint; - - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - endpoint = &altsetting->endpoint[i]; - if (usb_endpoint_is_int_out(&endpoint->desc)) { - dev_dbg(&serial->dev->dev, - "%s Found interrupt out endpoint. Address: %d\n", - __func__, endpoint->desc.bEndpointAddress); - priv->write_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - if (usb_endpoint_is_int_in(&endpoint->desc)) { - dev_dbg(&serial->dev->dev, - "%s Found interrupt in endpoint. Address: %d\n", - __func__, endpoint->desc.bEndpointAddress); - priv->read_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - } return 0; } @@ -205,7 +174,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) struct kobil_private *priv; unsigned char *transfer_buffer; int transfer_buffer_length = 8; - int write_urb_transfer_buffer_length = 8; priv = usb_get_serial_port_data(port); @@ -214,27 +182,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) if (!transfer_buffer) return -ENOMEM; - /* allocate write_urb */ - if (!port->write_urb) { - dev_dbg(dev, "%s - Allocating port->write_urb\n", __func__); - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - dev_dbg(dev, "%s - usb_alloc_urb failed\n", __func__); - kfree(transfer_buffer); - return -ENOMEM; - } - } - - /* allocate memory for write_urb transfer buffer */ - port->write_urb->transfer_buffer = - kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); - if (!port->write_urb->transfer_buffer) { - kfree(transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - return -ENOMEM; - } - /* get hardware version */ result = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), @@ -310,12 +257,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) static void kobil_close(struct usb_serial_port *port) { /* FIXME: Add rts/dtr methods */ - if (port->write_urb) { - usb_poison_urb(port->write_urb); - kfree(port->write_urb->transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - } + usb_kill_urb(port->interrupt_out_urb); usb_kill_urb(port->interrupt_in_urb); } @@ -333,24 +275,8 @@ static void kobil_read_int_callback(struct urb *urb) } if (urb->actual_length) { - - /* BEGIN DEBUG */ - /* - char *dbg_data; - - dbg_data = kzalloc((3 * purb->actual_length + 10) - * sizeof(char), GFP_KERNEL); - if (! dbg_data) { - return; - } - for (i = 0; i < purb->actual_length; i++) { - sprintf(dbg_data +3*i, "%02X ", data[i]); - } - dev_dbg(&port->dev, " <-- %s\n", dbg_data); - kfree(dbg_data); - */ - /* END DEBUG */ - + usb_serial_debug_data(&port->dev, __func__, urb->actual_length, + data); tty_insert_flip_string(&port->port, data, urb->actual_length); tty_flip_buffer_push(&port->port); } @@ -360,7 +286,7 @@ static void kobil_read_int_callback(struct urb *urb) } -static void kobil_write_callback(struct urb *purb) +static void kobil_write_int_callback(struct urb *urb) { } @@ -403,23 +329,14 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, while (todo > 0) { /* max 8 byte in one urb (endpoint size) */ - length = (todo < 8) ? todo : 8; + length = min(todo, port->interrupt_out_size); /* copy data to transfer buffer */ - memcpy(port->write_urb->transfer_buffer, + memcpy(port->interrupt_out_buffer, priv->buf + priv->cur_pos, length); - usb_fill_int_urb(port->write_urb, - port->serial->dev, - usb_sndintpipe(port->serial->dev, - priv->write_int_endpoint_address), - port->write_urb->transfer_buffer, - length, - kobil_write_callback, - port, - 8 - ); + port->interrupt_out_urb->transfer_buffer_length = length; priv->cur_pos = priv->cur_pos + length; - result = usb_submit_urb(port->write_urb, GFP_NOIO); + result = usb_submit_urb(port->interrupt_out_urb, GFP_NOIO); dev_dbg(&port->dev, "%s - Send write URB returns: %i\n", __func__, result); todo = priv->filled - priv->cur_pos; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 06d5a60be2c4..6a15adf53360 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -35,7 +35,6 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/serial.h> -#include <linux/ioctl.h> #include "mct_u232.h" #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" @@ -44,7 +43,6 @@ /* * Function prototypes */ -static int mct_u232_startup(struct usb_serial *serial); static int mct_u232_port_probe(struct usb_serial_port *port); static int mct_u232_port_remove(struct usb_serial_port *remove); static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port); @@ -57,10 +55,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); static int mct_u232_tiocmget(struct tty_struct *tty); static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int mct_u232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static int mct_u232_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static void mct_u232_throttle(struct tty_struct *tty); static void mct_u232_unthrottle(struct tty_struct *tty); @@ -95,11 +89,10 @@ static struct usb_serial_driver mct_u232_device = { .break_ctl = mct_u232_break_ctl, .tiocmget = mct_u232_tiocmget, .tiocmset = mct_u232_tiocmset, - .attach = mct_u232_startup, + .tiocmiwait = usb_serial_generic_tiocmiwait, .port_probe = mct_u232_port_probe, .port_remove = mct_u232_port_remove, - .ioctl = mct_u232_ioctl, - .get_icount = mct_u232_get_icount, + .get_icount = usb_serial_generic_get_icount, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -107,13 +100,13 @@ static struct usb_serial_driver * const serial_drivers[] = { }; struct mct_u232_private { + struct urb *read_urb; spinlock_t lock; unsigned int control_state; /* Modem Line Setting (TIOCM) */ unsigned char last_lcr; /* Line Control Register */ unsigned char last_lsr; /* Line Status Register */ unsigned char last_msr; /* Modem Status Register */ unsigned int rx_flags; /* Throttling flags */ - struct async_icount icount; }; #define THROTTLED 0x01 @@ -382,22 +375,6 @@ static void mct_u232_msr_to_state(struct usb_serial_port *port, * Driver's tty interface functions */ -static int mct_u232_startup(struct usb_serial *serial) -{ - struct usb_serial_port *port, *rport; - - /* Puh, that's dirty */ - port = serial->port[0]; - rport = serial->port[1]; - /* No unlinking, it wasn't submitted yet. */ - usb_free_urb(port->read_urb); - port->read_urb = rport->interrupt_in_urb; - rport->interrupt_in_urb = NULL; - port->read_urb->context = port; - - return 0; -} /* mct_u232_startup */ - static int mct_u232_port_probe(struct usb_serial_port *port) { struct mct_u232_private *priv; @@ -406,6 +383,10 @@ static int mct_u232_port_probe(struct usb_serial_port *port) if (!priv) return -ENOMEM; + /* Use second interrupt-in endpoint for reading. */ + priv->read_urb = port->serial->port[1]->interrupt_in_urb; + priv->read_urb->context = port; + spin_lock_init(&priv->lock); usb_set_serial_port_data(port, priv); @@ -469,17 +450,17 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); spin_unlock_irqrestore(&priv->lock, flags); - retval = usb_submit_urb(port->read_urb, GFP_KERNEL); + retval = usb_submit_urb(priv->read_urb, GFP_KERNEL); if (retval) { dev_err(&port->dev, - "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n", + "usb_submit_urb(read) failed pipe 0x%x err %d\n", port->read_urb->pipe, retval); goto error; } retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { - usb_kill_urb(port->read_urb); + usb_kill_urb(priv->read_urb); dev_err(&port->dev, "usb_submit_urb(read int) failed pipe 0x%x err %d", port->interrupt_in_urb->pipe, retval); @@ -509,11 +490,9 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) static void mct_u232_close(struct usb_serial_port *port) { - /* - * Must kill the read urb as it is actually an interrupt urb, which - * generic close thus fails to kill. - */ - usb_kill_urb(port->read_urb); + struct mct_u232_private *priv = usb_get_serial_port_data(port); + + usb_kill_urb(priv->read_urb); usb_kill_urb(port->interrupt_in_urb); usb_serial_generic_close(port); @@ -570,7 +549,7 @@ static void mct_u232_read_int_callback(struct urb *urb) /* Record Control Line states */ mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); - mct_u232_msr_to_icount(&priv->icount, priv->last_msr); + mct_u232_msr_to_icount(&port->icount, priv->last_msr); #if 0 /* Not yet handled. See belkin_sa.c for further information */ @@ -598,7 +577,7 @@ static void mct_u232_read_int_callback(struct urb *urb) tty_kref_put(tty); } #endif - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); spin_unlock_irqrestore(&priv->lock, flags); exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -786,86 +765,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty) } } -static int mct_u232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - DEFINE_WAIT(wait); - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); - struct async_icount cnow, cprev; - unsigned long flags; - - dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); - - switch (cmd) { - - case TIOCMIWAIT: - - dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__); - - spin_lock_irqsave(&mct_u232_port->lock, flags); - cprev = mct_u232_port->icount; - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - for ( ; ; ) { - prepare_to_wait(&port->delta_msr_wait, - &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(&port->delta_msr_wait, &wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - spin_lock_irqsave(&mct_u232_port->lock, flags); - cnow = mct_u232_port->icount; - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - - } - return -ENOIOCTLCMD; -} - -static int mct_u232_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); - struct async_icount *ic = &mct_u232_port->icount; - unsigned long flags; - - spin_lock_irqsave(&mct_u232_port->lock, flags); - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->rx = ic->rx; - icount->tx = ic->tx; - icount->frame = ic->frame; - icount->overrun = ic->overrun; - icount->parity = ic->parity; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - - dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", - __func__, icount->rx, icount->tx); - return 0; -} - module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index bf3c7a23553e..47e247759eb0 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -177,10 +177,7 @@ static void metrousb_cleanup(struct usb_serial_port *port) usb_unlink_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) - metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); - mutex_unlock(&port->serial->disc_mutex); + metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); } static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e956eae198fd..cc0e54345df9 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -62,7 +62,6 @@ struct moschip_port { __u8 shadowMCR; /* last MCR value received */ __u8 shadowMSR; /* last MSR value received */ char open; - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner */ struct urb *write_urb_pool[NUM_URBS]; }; @@ -1071,9 +1070,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) dev_err(&port->dev, "%s - Error %d submitting read urb\n", __func__, response); - /* initialize our icount structure */ - memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); - /* initialize our port settings */ mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ @@ -1140,16 +1136,9 @@ static void mos7720_close(struct usb_serial_port *port) usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); - mutex_lock(&serial->disc_mutex); - /* these commands must not be issued if the device has - * been disconnected */ - if (!serial->disconnected) { - write_mos_reg(serial, port->number - port->serial->minor, - MCR, 0x00); - write_mos_reg(serial, port->number - port->serial->minor, - IER, 0x00); - } - mutex_unlock(&serial->disc_mutex); + write_mos_reg(serial, port->number - port->serial->minor, MCR, 0x00); + write_mos_reg(serial, port->number - port->serial->minor, IER, 0x00); + mos7720_port->open = 0; } @@ -1799,33 +1788,6 @@ static int mos7720_tiocmset(struct tty_struct *tty, return 0; } -static int mos7720_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - struct async_icount cnow; - - mos7720_port = usb_get_serial_port_data(port); - cnow = mos7720_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, - icount->rx, icount->tx); - return 0; -} - static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, unsigned int __user *value) { @@ -1901,8 +1863,6 @@ static int mos7720_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; struct moschip_port *mos7720_port; - struct async_icount cnow; - struct async_icount cprev; mos7720_port = usb_get_serial_port_data(port); if (mos7720_port == NULL) @@ -1927,27 +1887,6 @@ static int mos7720_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__); return get_serial_info(mos7720_port, (struct serial_struct __user *)arg); - - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); - cprev = mos7720_port->icount; - while (1) { - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = mos7720_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; } return -ENOIOCTLCMD; @@ -2103,7 +2042,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .ioctl = mos7720_ioctl, .tiocmget = mos7720_tiocmget, .tiocmset = mos7720_tiocmset, - .get_icount = mos7720_get_icount, .set_termios = mos7720_set_termios, .write = mos7720_write, .write_room = mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 2be376a2e0e3..a0d5ea545982 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -219,8 +219,6 @@ struct moschip_port { char open; char open_ports; wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ - int delta_msr_cond; - struct async_icount icount; struct usb_serial_port *port; /* loop back to the owner of this object */ /* Offsets */ @@ -399,32 +397,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) struct moschip_port *mos7840_port; struct async_icount *icount; mos7840_port = port; - icount = &mos7840_port->icount; if (new_msr & (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI | MOS_MSR_DELTA_CD)) { - icount = &mos7840_port->icount; + icount = &mos7840_port->port->icount; /* update input line counters */ - if (new_msr & MOS_MSR_DELTA_CTS) { + if (new_msr & MOS_MSR_DELTA_CTS) icount->cts++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_DSR) { + if (new_msr & MOS_MSR_DELTA_DSR) icount->dsr++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_CD) { + if (new_msr & MOS_MSR_DELTA_CD) icount->dcd++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_RI) { + if (new_msr & MOS_MSR_DELTA_RI) icount->rng++; - smp_wmb(); - } - mos7840_port->delta_msr_cond = 1; - wake_up_interruptible(&port->port->delta_msr_wait); + wake_up_interruptible(&port->port->port.delta_msr_wait); } } @@ -442,23 +430,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) } /* update input line counters */ - icount = &port->icount; - if (new_lsr & SERIAL_LSR_BI) { + icount = &port->port->icount; + if (new_lsr & SERIAL_LSR_BI) icount->brk++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_OE) { + if (new_lsr & SERIAL_LSR_OE) icount->overrun++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_PE) { + if (new_lsr & SERIAL_LSR_PE) icount->parity++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_FE) { + if (new_lsr & SERIAL_LSR_FE) icount->frame++; - smp_wmb(); - } } /************************************************************************/ @@ -777,9 +757,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) struct tty_port *tport = &mos7840_port->port->port; tty_insert_flip_string(tport, data, urb->actual_length); tty_flip_buffer_push(tport); - mos7840_port->icount.rx += urb->actual_length; - smp_wmb(); - dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx); + port->icount.rx += urb->actual_length; + dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx); } if (!mos7840_port->read_urb) { @@ -1127,17 +1106,12 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) /* initialize our wait queues */ init_waitqueue_head(&mos7840_port->wait_chase); - /* initialize our icount structure */ - memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount)); - /* initialize our port settings */ /* Must set to enable ints! */ mos7840_port->shadowMCR = MCR_MASTER_IE; /* send a open port command */ mos7840_port->open = 1; /* mos7840_change_port_settings(mos7840_port,old_termios); */ - mos7840_port->icount.tx = 0; - mos7840_port->icount.rx = 0; return 0; } @@ -1220,25 +1194,10 @@ static void mos7840_close(struct usb_serial_port *port) } } - /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists */ - if (serial->dev) { - if (mos7840_port->write_urb) { - dev_dbg(&port->dev, "%s", "Shutdown bulk write\n"); - usb_kill_urb(mos7840_port->write_urb); - } - if (mos7840_port->read_urb) { - dev_dbg(&port->dev, "%s", "Shutdown bulk read\n"); - usb_kill_urb(mos7840_port->read_urb); - mos7840_port->read_urb_busy = false; - } - if ((&mos7840_port->control_urb)) { - dev_dbg(&port->dev, "%s", "Shutdown control read\n"); - /*/ usb_kill_urb (mos7840_port->control_urb); */ - } - } -/* if(mos7840_port->ctrl_buf != NULL) */ -/* kfree(mos7840_port->ctrl_buf); */ + usb_kill_urb(mos7840_port->write_urb); + usb_kill_urb(mos7840_port->read_urb); + mos7840_port->read_urb_busy = false; + port0->open_ports--; dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number); if (port0->open_ports == 0) { @@ -1250,8 +1209,7 @@ static void mos7840_close(struct usb_serial_port *port) if (mos7840_port->write_urb) { /* if this urb had a transfer buffer already (old tx) free it */ - if (mos7840_port->write_urb->transfer_buffer != NULL) - kfree(mos7840_port->write_urb->transfer_buffer); + kfree(mos7840_port->write_urb->transfer_buffer); usb_free_urb(mos7840_port->write_urb); } @@ -1328,9 +1286,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state) if (mos7840_port == NULL) return; - if (serial->dev) - /* flush and block until tx is empty */ - mos7840_block_until_chase_response(tty, mos7840_port); + /* flush and block until tx is empty */ + mos7840_block_until_chase_response(tty, mos7840_port); if (break_state == -1) data = mos7840_port->shadowLCR | LCR_SET_BREAK; @@ -1520,9 +1477,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, goto exit; } bytes_sent = transfer_size; - mos7840_port->icount.tx += transfer_size; - smp_wmb(); - dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); + port->icount.tx += transfer_size; + dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx); exit: return bytes_sent; @@ -2141,34 +2097,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, return 0; } -static int mos7840_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - struct async_icount cnow; - - mos7840_port = mos7840_get_port_private(port); - cnow = mos7840_port->icount; - - smp_rmb(); - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, - icount->rx, icount->tx); - return 0; -} - /***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver @@ -2181,9 +2109,6 @@ static int mos7840_ioctl(struct tty_struct *tty, void __user *argp = (void __user *)arg; struct moschip_port *mos7840_port; - struct async_icount cnow; - struct async_icount cprev; - if (mos7840_port_paranoia_check(port, __func__)) return -1; @@ -2208,41 +2133,6 @@ static int mos7840_ioctl(struct tty_struct *tty, case TIOCSSERIAL: dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__); break; - - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); - cprev = mos7840_port->icount; - while (1) { - /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ - mos7840_port->delta_msr_cond = 0; - wait_event_interruptible(port->delta_msr_wait, - (port->serial->disconnected || - mos7840_port-> - delta_msr_cond == 1)); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - cnow = mos7840_port->icount; - smp_rmb(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - default: break; } @@ -2589,7 +2479,8 @@ static struct usb_serial_driver moschip7840_4port_device = { .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, .tiocmset = mos7840_tiocmset, - .get_icount = mos7840_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .port_probe = mos7840_port_probe, .port_remove = mos7840_port_remove, .read_bulk_callback = mos7840_bulk_in_callback, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 1e1cafe287e4..5739bf6f7200 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -33,8 +33,7 @@ /* function prototypes */ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); -static void omninet_close(struct usb_serial_port *port); -static void omninet_read_bulk_callback(struct urb *urb); +static void omninet_process_read_urb(struct urb *urb); static void omninet_write_bulk_callback(struct urb *urb); static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); @@ -61,11 +60,10 @@ static struct usb_serial_driver zyxel_omninet_device = { .port_probe = omninet_port_probe, .port_remove = omninet_port_remove, .open = omninet_open, - .close = omninet_close, .write = omninet_write, .write_room = omninet_write_room, - .read_bulk_callback = omninet_read_bulk_callback, .write_bulk_callback = omninet_write_bulk_callback, + .process_read_urb = omninet_process_read_urb, .disconnect = omninet_disconnect, }; @@ -74,29 +72,28 @@ static struct usb_serial_driver * const serial_drivers[] = { }; -/* The protocol. +/* + * The protocol. * * The omni.net always exchange 64 bytes of data with the host. The first - * four bytes are the control header, you can see it in the above structure. + * four bytes are the control header. * * oh_seq is a sequence number. Don't know if/how it's used. * oh_len is the length of the data bytes in the packet. * oh_xxx Bit-mapped, related to handshaking and status info. - * I normally set it to 0x03 in trasmitted frames. + * I normally set it to 0x03 in transmitted frames. * 7: Active when the TA is in a CONNECTed state. * 6: unknown * 5: handshaking, unknown * 4: handshaking, unknown * 3: unknown, usually 0 * 2: unknown, usually 0 - * 1: handshaking, unknown, usually set to 1 in trasmitted frames - * 0: handshaking, unknown, usually set to 1 in trasmitted frames + * 1: handshaking, unknown, usually set to 1 in transmitted frames + * 0: handshaking, unknown, usually set to 1 in transmitted frames * oh_pad Probably a pad byte. * * After the header you will find data bytes if oh_len was greater than zero. - * */ - struct omninet_header { __u8 oh_seq; __u8 oh_len; @@ -112,7 +109,7 @@ static int omninet_port_probe(struct usb_serial_port *port) { struct omninet_data *od; - od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL); + od = kzalloc(sizeof(*od), GFP_KERNEL); if (!od) return -ENOMEM; @@ -135,56 +132,32 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct usb_serial_port *wport; - int result = 0; wport = serial->port[1]; tty_port_tty_set(&wport->port, tty); - /* Start reading from the device */ - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - return result; -} - -static void omninet_close(struct usb_serial_port *port) -{ - usb_kill_urb(port->read_urb); + return usb_serial_generic_open(tty, port); } +#define OMNINET_HEADERLEN 4 +#define OMNINET_BULKOUTSIZE 64 +#define OMNINET_PAYLOADSIZE (OMNINET_BULKOUTSIZE - OMNINET_HEADERLEN) -#define OMNINET_DATAOFFSET 0x04 -#define OMNINET_HEADERLEN sizeof(struct omninet_header) -#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) - -static void omninet_read_bulk_callback(struct urb *urb) +static void omninet_process_read_urb(struct urb *urb) { - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct omninet_header *header = (struct omninet_header *) &data[0]; - int status = urb->status; - int result; + struct usb_serial_port *port = urb->context; + const struct omninet_header *hdr = urb->transfer_buffer; + const unsigned char *data; + size_t data_len; - if (status) { - dev_dbg(&port->dev, "%s - nonzero read bulk status received: %d\n", - __func__, status); + if (urb->actual_length <= OMNINET_HEADERLEN || !hdr->oh_len) return; - } - - if (urb->actual_length && header->oh_len) { - tty_insert_flip_string(&port->port, data + OMNINET_DATAOFFSET, - header->oh_len); - tty_flip_buffer_push(&port->port); - } - /* Continue trying to always read */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); + data = (char *)urb->transfer_buffer + OMNINET_HEADERLEN; + data_len = min_t(size_t, urb->actual_length - OMNINET_HEADERLEN, + hdr->oh_len); + tty_insert_flip_string(&port->port, data, data_len); + tty_flip_buffer_push(&port->port); } static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, @@ -209,9 +182,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; } - count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; + count = (count > OMNINET_PAYLOADSIZE) ? OMNINET_PAYLOADSIZE : count; - memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, + memcpy(wport->write_urb->transfer_buffer + OMNINET_HEADERLEN, buf, count); usb_serial_debug_data(&port->dev, __func__, count, @@ -223,7 +196,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, header->oh_pad = 0x00; /* send the data out the bulk port, always 64 bytes */ - wport->write_urb->transfer_buffer_length = 64; + wport->write_urb->transfer_buffer_length = OMNINET_BULKOUTSIZE; result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); if (result) { diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index e13e1a4d3e1e..5f4b0cd0f6e9 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -120,7 +120,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype, 0, 0, buffer, 1, 0); kfree(buffer); - return retval; + if (retval < 0) + return retval; + + return 0; } static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -306,7 +309,6 @@ static int opticon_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct opticon_private *priv = usb_get_serial_port_data(port); unsigned long flags; bool rts; @@ -327,15 +329,11 @@ static int opticon_tiocmset(struct tty_struct *tty, if (!changed) return 0; - /* Send the new RTS state to the connected device */ - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - ret = send_control_msg(port, CONTROL_RTS, !rts); - else - ret = -ENODEV; - mutex_unlock(&serial->disc_mutex); + ret = send_control_msg(port, CONTROL_RTS, !rts); + if (ret) + return usb_translate_errors(ret); - return ret; + return 0; } static int get_serial_info(struct usb_serial_port *port, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 09cd3967b8df..734372846abb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -347,6 +347,7 @@ static void option_instat_callback(struct urb *urb); /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_PRODUCT_OLICARD100 0xc000 +#define OLIVETTI_PRODUCT_OLICARD145 0xc003 /* Celot products */ #define CELOT_VENDOR_ID 0x211f @@ -1273,6 +1274,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, + { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ @@ -1350,6 +1352,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TPLINK_VENDOR_ID, TPLINK_PRODUCT_MA180), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) }, /* D-Link DWM-156 (variant) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) }, /* D-Link DWM-156 (variant) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 87c71ccfee87..7e3e0782e51f 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port); static void oti6858_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old); static void oti6858_init_termios(struct tty_struct *tty); -static int oti6858_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); static void oti6858_read_int_callback(struct urb *urb); static void oti6858_read_bulk_callback(struct urb *urb); static void oti6858_write_bulk_callback(struct urb *urb); @@ -136,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty); static int oti6858_tiocmget(struct tty_struct *tty); static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); +static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg); static int oti6858_port_probe(struct usb_serial_port *port); static int oti6858_port_remove(struct usb_serial_port *port); @@ -150,11 +149,11 @@ static struct usb_serial_driver oti6858_device = { .open = oti6858_open, .close = oti6858_close, .write = oti6858_write, - .ioctl = oti6858_ioctl, .set_termios = oti6858_set_termios, .init_termios = oti6858_init_termios, .tiocmget = oti6858_tiocmget, .tiocmset = oti6858_tiocmset, + .tiocmiwait = oti6858_tiocmiwait, .read_bulk_callback = oti6858_read_bulk_callback, .read_int_callback = oti6858_read_int_callback, .write_bulk_callback = oti6858_write_bulk_callback, @@ -650,8 +649,9 @@ static int oti6858_tiocmget(struct tty_struct *tty) return result; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg) { + struct usb_serial_port *port = tty->driver_data; struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prev, status; @@ -662,7 +662,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) spin_unlock_irqrestore(&priv->lock, flags); while (1) { - wait_event_interruptible(port->delta_msr_wait, + wait_event_interruptible(port->port.delta_msr_wait, port->serial->disconnected || priv->status.pin_state != prev); if (signal_pending(current)) @@ -689,24 +689,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) return 0; } -static int oti6858_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg); - - switch (cmd) { - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__); - return wait_modem_info(port, arg); - default: - dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - static void oti6858_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -765,7 +747,7 @@ static void oti6858_read_int_callback(struct urb *urb) if (!priv->transient) { if (xs->pin_state != priv->status.pin_state) - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE); } diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 3b10018d89a3..7151659367a0 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -149,7 +149,7 @@ static int pl2303_vendor_read(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, value, index, buf, 1, 100); - dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", + dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index, res, buf[0]); return res; @@ -161,7 +161,7 @@ static int pl2303_vendor_write(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, 100); - dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n", + dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x %d\n", VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index, res); return res; @@ -248,14 +248,15 @@ static int pl2303_port_remove(struct usb_serial_port *port) return 0; } -static int set_control_lines(struct usb_device *dev, u8 value) +static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value) { + struct usb_device *dev = port->serial->dev; int retval; retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); - dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__, + dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__, value, retval); return retval; } @@ -437,7 +438,7 @@ static void pl2303_set_termios(struct tty_struct *tty, if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(serial->dev, control); + pl2303_set_control_lines(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } @@ -480,7 +481,7 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, control); + pl2303_set_control_lines(port, control); } static void pl2303_close(struct usb_serial_port *port) @@ -530,7 +531,6 @@ static int pl2303_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; @@ -548,14 +548,11 @@ static int pl2303_tiocmset(struct tty_struct *tty, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - ret = set_control_lines(serial->dev, control); - else - ret = -ENODEV; - mutex_unlock(&serial->disc_mutex); + ret = pl2303_set_control_lines(port, control); + if (ret) + return usb_translate_errors(ret); - return ret; + return 0; } static int pl2303_tiocmget(struct tty_struct *tty) @@ -592,8 +589,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port) return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg) { + struct usb_serial_port *port = tty->driver_data; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prevstatus; @@ -605,7 +603,7 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) spin_unlock_irqrestore(&priv->lock, flags); while (1) { - interruptible_sleep_on(&port->delta_msr_wait); + interruptible_sleep_on(&port->port.delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; @@ -651,10 +649,6 @@ static int pl2303_ioctl(struct tty_struct *tty, return -EFAULT; return 0; - - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); - return wait_modem_info(port, arg); default: dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); break; @@ -720,7 +714,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port, spin_unlock_irqrestore(&priv->lock, flags); if (priv->line_status & UART_BREAK_ERROR) usb_serial_handle_break(port); - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); tty = tty_port_tty_get(&port->port); if (!tty) @@ -784,7 +778,7 @@ static void pl2303_process_read_urb(struct urb *urb) line_status = priv->line_status; priv->line_status &= ~UART_STATE_TRANSIENT_MASK; spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); if (!urb->actual_length) return; @@ -835,6 +829,7 @@ static struct usb_serial_driver pl2303_device = { .set_termios = pl2303_set_termios, .tiocmget = pl2303_tiocmget, .tiocmset = pl2303_tiocmset, + .tiocmiwait = pl2303_tiocmiwait, .process_read_urb = pl2303_process_read_urb, .read_int_callback = pl2303_read_int_callback, .attach = pl2303_startup, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index ef3a7d5eaab4..02b0803425c5 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -127,8 +127,6 @@ struct qt2_port_private { u8 shadowLSR; u8 shadowMSR; - struct async_icount icount; - struct usb_serial_port *port; }; @@ -420,12 +418,6 @@ static void qt2_close(struct usb_serial_port *port) port_priv->urb_in_use = false; spin_unlock_irqrestore(&port_priv->urb_lock, flags); - mutex_lock(&port->serial->disc_mutex); - if (port->serial->disconnected) { - mutex_unlock(&port->serial->disc_mutex); - return; - } - /* flush the port transmit buffer */ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -456,8 +448,6 @@ static void qt2_close(struct usb_serial_port *port) if (i < 0) dev_err(&port->dev, "%s - close port failed %i\n", __func__, i); - - mutex_unlock(&port->serial->disc_mutex); } static void qt2_disconnect(struct usb_serial *serial) @@ -490,71 +480,6 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct qt2_port_private *priv = usb_get_serial_port_data(port); - struct async_icount prev, cur; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - prev = priv->icount; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - wait_event_interruptible(port->delta_msr_wait, - (port->serial->disconnected || - (priv->icount.rng != prev.rng) || - (priv->icount.dsr != prev.dsr) || - (priv->icount.dcd != prev.dcd) || - (priv->icount.cts != prev.cts))); - - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - spin_lock_irqsave(&priv->lock, flags); - cur = priv->icount; - spin_unlock_irqrestore(&priv->lock, flags); - - if ((prev.rng == cur.rng) && - (prev.dsr == cur.dsr) && - (prev.dcd == cur.dcd) && - (prev.cts == cur.cts)) - return -EIO; - - if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || - (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || - (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || - (arg & TIOCM_CTS && (prev.cts != cur.cts))) - return 0; - } - return 0; -} - -static int qt2_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct qt2_port_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - static int qt2_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -564,10 +489,6 @@ static int qt2_ioctl(struct tty_struct *tty, case TIOCGSERIAL: return get_serial_info(port, (struct serial_struct __user *)arg); - - case TIOCMIWAIT: - return wait_modem_info(port, arg); - default: break; } @@ -948,18 +869,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) if (newMSR & UART_MSR_ANY_DELTA) { /* update input line counters */ if (newMSR & UART_MSR_DCTS) - port_priv->icount.cts++; - + port->icount.cts++; if (newMSR & UART_MSR_DDSR) - port_priv->icount.dsr++; - + port->icount.dsr++; if (newMSR & UART_MSR_DDCD) - port_priv->icount.dcd++; - + port->icount.dcd++; if (newMSR & UART_MSR_TERI) - port_priv->icount.rng++; + port->icount.rng++; - wake_up_interruptible(&port->delta_msr_wait); + wake_up_interruptible(&port->port.delta_msr_wait); } } @@ -979,7 +897,7 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) port_priv->shadowLSR = newLSR; spin_unlock_irqrestore(&port_priv->lock, flags); - icount = &port_priv->icount; + icount = &port->icount; if (newLSR & UART_LSR_BRK_ERROR_BITS) { @@ -1089,7 +1007,8 @@ static struct usb_serial_driver qt2_device = { .break_ctl = qt2_break_ctl, .tiocmget = qt2_tiocmget, .tiocmset = qt2_tiocmset, - .get_icount = qt2_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .ioctl = qt2_ioctl, .set_termios = qt2_set_termios, }; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d66148a17fe3..8894665cd610 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -774,30 +774,25 @@ static void sierra_close(struct usb_serial_port *port) portdata->rts_state = 0; portdata->dtr_state = 0; - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) { - serial->interface->needs_remote_wakeup = 0; - /* odd error handling due to pm counters */ - if (!usb_autopm_get_interface(serial->interface)) - sierra_send_setup(port); - else - usb_autopm_get_interface_no_resume(serial->interface); - - } - mutex_unlock(&serial->disc_mutex); - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) { + serial->interface->needs_remote_wakeup = 0; + /* odd error handling due to pm counters */ + if (!usb_autopm_get_interface(serial->interface)) + sierra_send_setup(port); + else + usb_autopm_get_interface_no_resume(serial->interface); + } + mutex_unlock(&serial->disc_mutex); + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); - /* Stop reading urbs */ - sierra_stop_rx_urbs(port); - /* .. and release them */ - for (i = 0; i < portdata->num_in_urbs; i++) { - sierra_release_urb(portdata->in_urbs[i]); - portdata->in_urbs[i] = NULL; - } + sierra_stop_rx_urbs(port); + for (i = 0; i < portdata->num_in_urbs; i++) { + sierra_release_urb(portdata->in_urbs[i]); + portdata->in_urbs[i] = NULL; } } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 549ef68ff5fa..cf3df793c2b7 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -1,7 +1,7 @@ /* * spcp8x5 USB to serial adaptor driver * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com) * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) * Copyright (C) 2006 S1 Corp. * @@ -13,8 +13,6 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * */ #include <linux/kernel.h> #include <linux/errno.h> @@ -28,7 +26,10 @@ #include <linux/usb.h> #include <linux/usb/serial.h> -#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" +#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" + +#define SPCP825_QUIRK_NO_UART_STATUS 0x01 +#define SPCP825_QUIRK_NO_WORK_MODE 0x02 #define SPCP8x5_007_VID 0x04FC #define SPCP8x5_007_PID 0x0201 @@ -46,13 +47,15 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)}, { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)}, { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, - { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)}, + { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID), + .driver_info = SPCP825_QUIRK_NO_UART_STATUS | + SPCP825_QUIRK_NO_WORK_MODE }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); struct spcp8x5_usb_ctrl_arg { - u8 type; + u8 type; u8 cmd; u8 cmd_type; u16 value; @@ -138,49 +141,33 @@ struct spcp8x5_usb_ctrl_arg { #define UART_OVERRUN_ERROR 0x40 #define UART_CTS 0x80 -enum spcp8x5_type { - SPCP825_007_TYPE, - SPCP825_008_TYPE, - SPCP825_PHILIP_TYPE, - SPCP825_INTERMATIC_TYPE, - SPCP835_TYPE, -}; - struct spcp8x5_private { - spinlock_t lock; - enum spcp8x5_type type; - u8 line_control; - u8 line_status; + unsigned quirks; + spinlock_t lock; + u8 line_control; }; +static int spcp8x5_probe(struct usb_serial *serial, + const struct usb_device_id *id) +{ + usb_set_serial_data(serial, (void *)id); + + return 0; +} + static int spcp8x5_port_probe(struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; + const struct usb_device_id *id = usb_get_serial_data(port->serial); struct spcp8x5_private *priv; - enum spcp8x5_type type = SPCP825_007_TYPE; - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - - if (product == 0x0201) - type = SPCP825_007_TYPE; - else if (product == 0x0231) - type = SPCP835_TYPE; - else if (product == 0x0235) - type = SPCP825_008_TYPE; - else if (product == 0x0204) - type = SPCP825_INTERMATIC_TYPE; - else if (product == 0x0471 && - serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) - type = SPCP825_PHILIP_TYPE; - dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; spin_lock_init(&priv->lock); - priv->type = type; + priv->quirks = id->driver_info; - usb_set_serial_port_data(port , priv); + usb_set_serial_port_data(port, priv); return 0; } @@ -195,86 +182,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port) return 0; } -/* set the modem control line of the device. - * NOTE spcp825-007 not supported this */ -static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value, - enum spcp8x5_type type) +static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr) { + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; int retval; - u8 mcr = 0 ; - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) return -EPERM; - mcr = (unsigned short)value; retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_UART_STATUS_TYPE, SET_UART_STATUS, mcr, 0x04, NULL, 0, 100); - if (retval != 0) - dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval); + if (retval != 0) { + dev_err(&port->dev, "failed to set control lines: %d\n", + retval); + } return retval; } -/* get the modem status register of the device - * NOTE spcp825-007 not supported this */ -static int spcp8x5_get_msr(struct usb_device *dev, u8 *status, - enum spcp8x5_type type) +static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) { - u8 *status_buffer; + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; + u8 *buf; int ret; - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS) return -EPERM; - if (status == NULL) - return -EINVAL; - status_buffer = kmalloc(1, GFP_KERNEL); - if (!status_buffer) + buf = kzalloc(1, GFP_KERNEL); + if (!buf) return -ENOMEM; - status_buffer[0] = status[0]; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_UART_STATUS, GET_UART_STATUS_TYPE, - 0, GET_UART_STATUS_MSR, status_buffer, 1, 100); + 0, GET_UART_STATUS_MSR, buf, 1, 100); if (ret < 0) - dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", - status_buffer, ret); + dev_err(&port->dev, "failed to get modem status: %d", ret); - dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer); - status[0] = status_buffer[0]; - kfree(status_buffer); + dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x", ret, *buf); + *status = *buf; + kfree(buf); return ret; } -/* select the work mode. - * NOTE this function not supported by spcp825-007 */ -static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, - u16 index, enum spcp8x5_type type) +static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value, + u16 index) { + struct spcp8x5_private *priv = usb_get_serial_port_data(port); + struct usb_device *dev = port->serial->dev; int ret; - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) + if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE) return; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_WORKING_MODE_TYPE, SET_WORKING_MODE, value, index, NULL, 0, 100); - dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index); + dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index); if (ret < 0) - dev_dbg(&dev->dev, - "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); + dev_err(&port->dev, "failed to set work mode: %d\n", ret); } static int spcp8x5_carrier_raised(struct usb_serial_port *port) { - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & MSR_STATUS_LINE_DCD) + u8 msr; + int ret; + + ret = spcp8x5_get_msr(port, &msr); + if (ret || msr & MSR_STATUS_LINE_DCD) return 1; + return 0; } @@ -293,20 +273,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) | MCR_CONTROL_LINE_RTS); control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); + spcp8x5_set_ctrl_line(port, control); } static void spcp8x5_init_termios(struct tty_struct *tty) { - /* for the 1st time call this function */ tty->termios = tty_std_termios; tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; tty->termios.c_ispeed = 115200; tty->termios.c_ospeed = 115200; } -/* set the serial param for transfer. we should check if we really need to - * transfer. if we set flow control we should do this too. */ static void spcp8x5_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { @@ -321,7 +298,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty, int i; u8 control; - /* check that they really want us to change something */ if (!tty_termios_hw_change(&tty->termios, old_termios)) return; @@ -337,7 +313,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(serial->dev, control , priv->type); + spcp8x5_set_ctrl_line(port, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } @@ -397,9 +373,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (cflag & PARENB) { buf[1] |= (cflag & PARODD) ? SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; - } else + } else { buf[1] |= SET_UART_FORMAT_PAR_NONE; - + } uartdata = buf[0] | buf[1]<<8; i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -412,22 +388,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (cflag & CRTSCTS) { /* enable hardware flow control */ - spcp8x5_set_workMode(serial->dev, 0x000a, - SET_WORKING_MODE_U2C, priv->type); + spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C); } } -/* open the serial port. do some usb system call. set termios and get the line - * status of the device. */ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) { struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct spcp8x5_private *priv = usb_get_serial_port_data(port); int ret; - unsigned long flags; - u8 status = 0x30; - /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -438,142 +408,16 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) if (ret) return ret; - spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); + spcp8x5_set_ctrl_line(port, priv->line_control); - /* Setup termios */ if (tty) spcp8x5_set_termios(tty, port, &tmp_termios); - spcp8x5_get_msr(serial->dev, &status, priv->type); - - /* may be we should update uart status here but now we did not do */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = status & 0xf0 ; - spin_unlock_irqrestore(&priv->lock, flags); - port->port.drain_delay = 256; return usb_serial_generic_open(tty, port); } -static void spcp8x5_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - u8 status; - char tty_flag; - - /* get tty_flag from status */ - tty_flag = TTY_NORMAL; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - /* wake up the wait for termios */ - wake_up_interruptible(&port->delta_msr_wait); - - if (!urb->actual_length) - return; - - - if (status & UART_STATE_TRANSIENT_MASK) { - /* break takes precedence over parity, which takes precedence - * over framing errors */ - if (status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - - /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) - tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); - - if (status & UART_DCD) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - usb_serial_handle_dcd_change(port, tty, - priv->line_status & MSR_STATUS_LINE_DCD); - tty_kref_put(tty); - } - } - } - - tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, - urb->actual_length); - tty_flip_buffer_push(&port->port); -} - -static int spcp8x5_wait_modem_info(struct usb_serial_port *port, - unsigned int arg) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - /* wake up in bulk read */ - interruptible_sleep_on(&port->delta_msr_wait); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus^status; - - if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) || - ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) || - ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) || - ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS))) - return 0; - - prevstatus = status; - } - /* NOTREACHED */ - return 0; -} - -static int spcp8x5_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, - port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, - port->number); - return spcp8x5_wait_modem_info(port, arg); - - default: - dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__, - cmd); - break; - } - - return -ENOIOCTLCMD; -} - static int spcp8x5_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { @@ -594,7 +438,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); + return spcp8x5_set_ctrl_line(port, control); } static int spcp8x5_tiocmget(struct tty_struct *tty) @@ -603,12 +447,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty) struct spcp8x5_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int mcr; - unsigned int status; + u8 status; unsigned int result; + result = spcp8x5_get_msr(port, &status); + if (result) + return result; + spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; - status = priv->line_status; spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) @@ -621,7 +468,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty) return result; } -/* All of the device info needed for the spcp8x5 SIO serial converter */ static struct usb_serial_driver spcp8x5_device = { .driver = { .owner = THIS_MODULE, @@ -629,17 +475,16 @@ static struct usb_serial_driver spcp8x5_device = { }, .id_table = id_table, .num_ports = 1, - .open = spcp8x5_open, + .open = spcp8x5_open, .dtr_rts = spcp8x5_dtr_rts, .carrier_raised = spcp8x5_carrier_raised, - .set_termios = spcp8x5_set_termios, + .set_termios = spcp8x5_set_termios, .init_termios = spcp8x5_init_termios, - .ioctl = spcp8x5_ioctl, - .tiocmget = spcp8x5_tiocmget, - .tiocmset = spcp8x5_tiocmset, + .tiocmget = spcp8x5_tiocmget, + .tiocmset = spcp8x5_tiocmset, + .probe = spcp8x5_probe, .port_probe = spcp8x5_port_probe, .port_remove = spcp8x5_port_remove, - .process_read_urb = spcp8x5_process_read_urb, }; static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 4b2a19757b4d..5b62dbbdf996 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -61,7 +61,6 @@ struct ssu100_port_private { spinlock_t status_lock; u8 shadowLSR; u8 shadowMSR; - struct async_icount icount; }; static inline int ssu100_control_msg(struct usb_device *dev, @@ -315,11 +314,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) return usb_serial_generic_open(tty, port); } -static void ssu100_close(struct usb_serial_port *port) -{ - usb_serial_generic_close(port); -} - static int get_serial_info(struct usb_serial_port *port, struct serial_struct __user *retinfo) { @@ -343,73 +337,6 @@ static int get_serial_info(struct usb_serial_port *port, return 0; } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount prev, cur; - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - prev = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - while (1) { - wait_event_interruptible(port->delta_msr_wait, - (port->serial->disconnected || - (priv->icount.rng != prev.rng) || - (priv->icount.dsr != prev.dsr) || - (priv->icount.dcd != prev.dcd) || - (priv->icount.cts != prev.cts))); - - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - spin_lock_irqsave(&priv->status_lock, flags); - cur = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if ((prev.rng == cur.rng) && - (prev.dsr == cur.dsr) && - (prev.dcd == cur.dcd) && - (prev.cts == cur.cts)) - return -EIO; - - if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || - (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || - (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || - (arg & TIOCM_CTS && (prev.cts != cur.cts))) - return 0; - } - return 0; -} - -static int ssu100_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - - - static int ssu100_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { @@ -421,10 +348,6 @@ static int ssu100_ioctl(struct tty_struct *tty, case TIOCGSERIAL: return get_serial_info(port, (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - return wait_modem_info(port, arg); - default: break; } @@ -532,14 +455,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) if (msr & UART_MSR_ANY_DELTA) { /* update input line counters */ if (msr & UART_MSR_DCTS) - priv->icount.cts++; + port->icount.cts++; if (msr & UART_MSR_DDSR) - priv->icount.dsr++; + port->icount.dsr++; if (msr & UART_MSR_DDCD) - priv->icount.dcd++; + port->icount.dcd++; if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&port->delta_msr_wait); + port->icount.rng++; + wake_up_interruptible(&port->port.delta_msr_wait); } } @@ -558,22 +481,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, /* we always want to update icount, but we only want to * update tty_flag for one case */ if (lsr & UART_LSR_BI) { - priv->icount.brk++; + port->icount.brk++; *tty_flag = TTY_BREAK; usb_serial_handle_break(port); } if (lsr & UART_LSR_PE) { - priv->icount.parity++; + port->icount.parity++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_PARITY; } if (lsr & UART_LSR_FE) { - priv->icount.frame++; + port->icount.frame++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_FRAME; } if (lsr & UART_LSR_OE){ - priv->icount.overrun++; + port->icount.overrun++; if (*tty_flag == TTY_NORMAL) *tty_flag = TTY_OVERRUN; } @@ -630,7 +553,6 @@ static struct usb_serial_driver ssu100_device = { .id_table = id_table, .num_ports = 1, .open = ssu100_open, - .close = ssu100_close, .attach = ssu100_attach, .port_probe = ssu100_port_probe, .port_remove = ssu100_port_remove, @@ -638,10 +560,10 @@ static struct usb_serial_driver ssu100_device = { .process_read_urb = ssu100_process_read_urb, .tiocmget = ssu100_tiocmget, .tiocmset = ssu100_tiocmset, - .get_icount = ssu100_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .ioctl = ssu100_ioctl, .set_termios = ssu100_set_termios, - .disconnect = usb_serial_generic_disconnect, }; static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index be05e6caf9a3..9b1648945e7a 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -1,6 +1,7 @@ /* * Symbol USB barcode to serial driver * + * Copyright (C) 2013 Johan Hovold <jhovold@gmail.com> * Copyright (C) 2009 Greg Kroah-Hartman <gregkh@suse.de> * Copyright (C) 2009 Novell Inc. * @@ -26,27 +27,17 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -/* This structure holds all of the individual device information */ struct symbol_private { - struct usb_device *udev; - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned char *int_buffer; - struct urb *int_urb; - int buffer_size; - u8 bInterval; - u8 int_address; spinlock_t lock; /* protects the following flags */ bool throttled; bool actually_throttled; - bool rts; }; static void symbol_int_callback(struct urb *urb) { - struct symbol_private *priv = urb->context; + struct usb_serial_port *port = urb->context; + struct symbol_private *priv = usb_get_serial_port_data(port); unsigned char *data = urb->transfer_buffer; - struct usb_serial_port *port = priv->port; int status = urb->status; int result; int data_length; @@ -84,7 +75,7 @@ static void symbol_int_callback(struct urb *urb) tty_insert_flip_string(&port->port, &data[1], data_length); tty_flip_buffer_push(&port->port); } else { - dev_dbg(&priv->udev->dev, + dev_dbg(&port->dev, "Improper amount of data received from the device, " "%d bytes", urb->actual_length); } @@ -94,12 +85,7 @@ exit: /* Continue trying to always read if we should */ if (!priv->throttled) { - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); + result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", @@ -118,15 +104,10 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; - priv->port = port; spin_unlock_irqrestore(&priv->lock, flags); /* Start reading from the device */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", @@ -136,10 +117,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) static void symbol_close(struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(port->serial); - - /* shutdown our urbs */ - usb_kill_urb(priv->int_urb); + usb_kill_urb(port->interrupt_in_urb); } static void symbol_throttle(struct tty_struct *tty) @@ -166,7 +144,7 @@ static void symbol_unthrottle(struct tty_struct *tty) spin_unlock_irq(&priv->lock); if (was_throttled) { - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); + result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", @@ -176,89 +154,36 @@ static void symbol_unthrottle(struct tty_struct *tty) static int symbol_startup(struct usb_serial *serial) { + if (!serial->num_interrupt_in) { + dev_err(&serial->dev->dev, "no interrupt-in endpoint\n"); + return -ENODEV; + } + + return 0; +} + +static int symbol_port_probe(struct usb_serial_port *port) +{ struct symbol_private *priv; - struct usb_host_interface *intf; - int i; - int retval = -ENOMEM; - bool int_in_found = false; - /* create our private serial structure */ priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + if (!priv) return -ENOMEM; - } + spin_lock_init(&priv->lock); - priv->serial = serial; - priv->port = serial->port[0]; - priv->udev = serial->dev; - - /* find our interrupt endpoint */ - intf = serial->interface->altsetting; - for (i = 0; i < intf->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - - endpoint = &intf->endpoint[i].desc; - if (!usb_endpoint_is_int_in(endpoint)) - continue; - - priv->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->int_urb) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->buffer_size = usb_endpoint_maxp(endpoint) * 2; - priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); - if (!priv->int_buffer) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->int_address = endpoint->bEndpointAddress; - priv->bInterval = endpoint->bInterval; - - /* set up our int urb */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - endpoint->bEndpointAddress), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - - int_in_found = true; - break; - } - if (!int_in_found) { - dev_err(&priv->udev->dev, - "Error - the proper endpoints were not found!\n"); - goto error; - } + usb_set_serial_port_data(port, priv); - usb_set_serial_data(serial, priv); return 0; - -error: - usb_free_urb(priv->int_urb); - kfree(priv->int_buffer); - kfree(priv); - return retval; -} - -static void symbol_disconnect(struct usb_serial *serial) -{ - struct symbol_private *priv = usb_get_serial_data(serial); - - usb_kill_urb(priv->int_urb); - usb_free_urb(priv->int_urb); } -static void symbol_release(struct usb_serial *serial) +static int symbol_port_remove(struct usb_serial_port *port) { - struct symbol_private *priv = usb_get_serial_data(serial); + struct symbol_private *priv = usb_get_serial_port_data(port); - kfree(priv->int_buffer); kfree(priv); + + return 0; } static struct usb_serial_driver symbol_device = { @@ -269,12 +194,13 @@ static struct usb_serial_driver symbol_device = { .id_table = id_table, .num_ports = 1, .attach = symbol_startup, + .port_probe = symbol_port_probe, + .port_remove = symbol_port_remove, .open = symbol_open, .close = symbol_close, - .disconnect = symbol_disconnect, - .release = symbol_release, .throttle = symbol_throttle, .unthrottle = symbol_unthrottle, + .read_int_callback = symbol_int_callback, }; static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 19a71a9eecf0..cac47aef2918 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -67,13 +67,10 @@ struct ti_port { int tp_is_open; __u8 tp_msr; - __u8 tp_lsr; __u8 tp_shadow_mcr; __u8 tp_uart_mode; /* 232 or 485 modes */ unsigned int tp_uart_base_addr; int tp_flags; - int tp_closing_wait;/* in .01 secs */ - struct async_icount tp_icount; wait_queue_head_t tp_write_wait; struct ti_device *tp_tdev; struct usb_serial_port *tp_port; @@ -108,8 +105,6 @@ static void ti_throttle(struct tty_struct *tty); static void ti_unthrottle(struct tty_struct *tty); static int ti_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); static void ti_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); static int ti_tiocmget(struct tty_struct *tty); @@ -124,15 +119,13 @@ static void ti_recv(struct usb_serial_port *port, unsigned char *data, int length); static void ti_send(struct ti_port *tport); static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); -static int ti_get_lsr(struct ti_port *tport); +static int ti_get_lsr(struct ti_port *tport, u8 *lsr); static int ti_get_serial_info(struct ti_port *tport, struct serial_struct __user *ret_arg); static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, struct serial_struct __user *new_arg); static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush); - static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); @@ -235,7 +228,8 @@ static struct usb_serial_driver ti_1port_device = { .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, @@ -265,7 +259,8 @@ static struct usb_serial_driver ti_2port_device = { .set_termios = ti_set_termios, .tiocmget = ti_tiocmget, .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, .break_ctl = ti_break, .read_int_callback = ti_interrupt_callback, .read_bulk_callback = ti_bulk_in_callback, @@ -430,7 +425,7 @@ static int ti_port_probe(struct usb_serial_port *port) tport->tp_uart_base_addr = TI_UART1_BASE_ADDR; else tport->tp_uart_base_addr = TI_UART2_BASE_ADDR; - tport->tp_closing_wait = closing_wait; + port->port.closing_wait = msecs_to_jiffies(10 * closing_wait); init_waitqueue_head(&tport->tp_write_wait); if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) { kfree(tport); @@ -480,8 +475,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) port_number = port->number - port->serial->minor; - memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount)); - tport->tp_msr = 0; tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); @@ -585,6 +578,8 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) tport->tp_is_open = 1; ++tdev->td_open_port_count; + port->port.drain_delay = 3; + goto release_lock; unlink_int_urb: @@ -604,6 +599,7 @@ static void ti_close(struct usb_serial_port *port) int port_number; int status; int do_unlock; + unsigned long flags; tdev = usb_get_serial_data(port->serial); tport = usb_get_serial_port_data(port); @@ -612,11 +608,12 @@ static void ti_close(struct usb_serial_port *port) tport->tp_is_open = 0; - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 1); - usb_kill_urb(port->read_urb); usb_kill_urb(port->write_urb); tport->tp_write_urb_in_use = 0; + spin_lock_irqsave(&tport->tp_lock, flags); + kfifo_reset_out(&tport->write_fifo); + spin_unlock_irqrestore(&tport->tp_lock, flags); port_number = port->number - port->serial->minor; @@ -687,6 +684,8 @@ static int ti_chars_in_buffer(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; + int ret; + u8 lsr; if (tport == NULL) return 0; @@ -695,6 +694,12 @@ static int ti_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&tport->write_fifo); spin_unlock_irqrestore(&tport->tp_lock, flags); + if (!chars) { + ret = ti_get_lsr(tport, &lsr); + if (!ret && !(lsr & TI_LSR_TX_EMPTY)) + chars = 1; + } + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -731,38 +736,11 @@ static void ti_unthrottle(struct tty_struct *tty) } } -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow = tport->tp_icount; - - dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__, - cnow.rx, cnow.tx); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - static int ti_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd); @@ -778,29 +756,6 @@ static int ti_ioctl(struct tty_struct *tty, dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__); return ti_set_serial_info(tty, tport, (struct serial_struct __user *)arg); - case TIOCMIWAIT: - dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); - cprev = tport->tp_icount; - while (1) { - interruptible_sleep_on(&port->delta_msr_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - - if (port->serial->disconnected) - return -EIO; - - cnow = tport->tp_icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) - return 0; - cprev = cnow; - } - break; } return -ENOIOCTLCMD; } @@ -1018,8 +973,6 @@ static void ti_break(struct tty_struct *tty, int break_state) if (tport == NULL) return; - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0); - status = ti_write_byte(port, tport->tp_tdev, tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); @@ -1156,7 +1109,7 @@ static void ti_bulk_in_callback(struct urb *urb) else ti_recv(port, urb->transfer_buffer, urb->actual_length); spin_lock(&tport->tp_lock); - tport->tp_icount.rx += urb->actual_length; + port->icount.rx += urb->actual_length; spin_unlock(&tport->tp_lock); } @@ -1264,7 +1217,7 @@ static void ti_send(struct ti_port *tport) /* TODO: reschedule ti_send */ } else { spin_lock_irqsave(&tport->tp_lock, flags); - tport->tp_icount.tx += count; + port->icount.tx += count; spin_unlock_irqrestore(&tport->tp_lock, flags); } @@ -1297,7 +1250,7 @@ static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) } -static int ti_get_lsr(struct ti_port *tport) +static int ti_get_lsr(struct ti_port *tport, u8 *lsr) { int size, status; struct ti_device *tdev = tport->tp_tdev; @@ -1323,7 +1276,7 @@ static int ti_get_lsr(struct ti_port *tport) dev_dbg(&port->dev, "%s - lsr 0x%02X\n", __func__, data->bLSR); - tport->tp_lsr = data->bLSR; + *lsr = data->bLSR; free_data: kfree(data); @@ -1336,10 +1289,15 @@ static int ti_get_serial_info(struct ti_port *tport, { struct usb_serial_port *port = tport->tp_port; struct serial_struct ret_serial; + unsigned cwait; if (!ret_arg) return -EFAULT; + cwait = port->port.closing_wait; + if (cwait != ASYNC_CLOSING_WAIT_NONE) + cwait = jiffies_to_msecs(cwait) / 10; + memset(&ret_serial, 0, sizeof(ret_serial)); ret_serial.type = PORT_16550A; @@ -1348,7 +1306,7 @@ static int ti_get_serial_info(struct ti_port *tport, ret_serial.flags = tport->tp_flags; ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE; ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ret_serial.closing_wait = tport->tp_closing_wait; + ret_serial.closing_wait = cwait; if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg))) return -EFAULT; @@ -1361,12 +1319,17 @@ static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, struct serial_struct __user *new_arg) { struct serial_struct new_serial; + unsigned cwait; if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) return -EFAULT; + cwait = new_serial.closing_wait; + if (cwait != ASYNC_CLOSING_WAIT_NONE) + cwait = msecs_to_jiffies(10 * new_serial.closing_wait); + tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; - tport->tp_closing_wait = new_serial.closing_wait; + tport->tp_port->port.closing_wait = cwait; return 0; } @@ -1382,7 +1345,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) if (msr & TI_MSR_DELTA_MASK) { spin_lock_irqsave(&tport->tp_lock, flags); - icount = &tport->tp_icount; + icount = &tport->tp_port->icount; if (msr & TI_MSR_DELTA_CTS) icount->cts++; if (msr & TI_MSR_DELTA_DSR) @@ -1391,7 +1354,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) icount->dcd++; if (msr & TI_MSR_DELTA_RI) icount->rng++; - wake_up_interruptible(&tport->tp_port->delta_msr_wait); + wake_up_interruptible(&tport->tp_port->port.delta_msr_wait); spin_unlock_irqrestore(&tport->tp_lock, flags); } @@ -1411,56 +1374,6 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) } -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) -{ - struct ti_device *tdev = tport->tp_tdev; - struct usb_serial_port *port = tport->tp_port; - wait_queue_t wait; - - spin_lock_irq(&tport->tp_lock); - - /* wait for data to drain from the buffer */ - tdev->td_urb_error = 0; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tport->tp_write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_len(&tport->write_fifo) == 0 - || timeout == 0 || signal_pending(current) - || tdev->td_urb_error - || port->serial->disconnected) /* disconnect */ - break; - spin_unlock_irq(&tport->tp_lock); - timeout = schedule_timeout(timeout); - spin_lock_irq(&tport->tp_lock); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tport->tp_write_wait, &wait); - - /* flush any remaining data in the buffer */ - if (flush) - kfifo_reset_out(&tport->write_fifo); - - spin_unlock_irq(&tport->tp_lock); - - mutex_lock(&port->serial->disc_mutex); - /* wait for data to drain from the device */ - /* wait for empty tx register, plus 20 ms */ - timeout += jiffies; - tport->tp_lsr &= ~TI_LSR_TX_EMPTY; - while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error - && !port->serial->disconnected) { - if (ti_get_lsr(tport)) - break; - mutex_unlock(&port->serial->disc_mutex); - msleep_interruptible(20); - mutex_lock(&port->serial->disc_mutex); - } - mutex_unlock(&port->serial->disc_mutex); -} - - static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty) { unsigned long flags; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 650be17a68f2..cf75beb1251b 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,6 +1,7 @@ /* * USB Serial Converter driver * + * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com) * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) @@ -14,7 +15,6 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver - * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -49,7 +49,6 @@ drivers depend on it. */ -/* initially all NULL */ static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; static DEFINE_MUTEX(table_lock); static LIST_HEAD(usb_serial_driver_list); @@ -139,7 +138,7 @@ static void destroy_serial(struct kref *kref) if (serial->minor != SERIAL_TTY_NO_MINOR) return_serial(serial); - if (serial->attached) + if (serial->attached && serial->type->release) serial->type->release(serial); /* Now that nothing is using the ports, they can be freed */ @@ -225,7 +224,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) return retval; } -static int serial_activate(struct tty_port *tport, struct tty_struct *tty) +static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty) { struct usb_serial_port *port = container_of(tport, struct usb_serial_port, port); @@ -249,30 +248,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); + return tty_port_open(&port->port, tty, filp); } /** - * serial_down - shut down hardware + * serial_port_shutdown - shut down hardware * @tport: tty port to shut down * - * Shut down a USB serial port unless it is the console. We never - * shut down the console hardware as it will always be in use. Serialized - * against activate by the tport mutex and kept to matching open/close pairs + * Shut down a USB serial port. Serialized against activate by the + * tport mutex and kept to matching open/close pairs * of calls by the ASYNCB_INITIALIZED flag. + * + * Not called if tty is console. */ -static void serial_down(struct tty_port *tport) +static void serial_port_shutdown(struct tty_port *tport) { struct usb_serial_port *port = container_of(tport, struct usb_serial_port, port); struct usb_serial_driver *drv = port->serial->type; - /* - * The console is magical. Do not hang up the console hardware - * or there will be tears. - */ - if (port->port.console) - return; + if (drv->close) drv->close(port); } @@ -281,7 +277,8 @@ static void serial_hangup(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); + tty_port_hangup(&port->port); } @@ -289,7 +286,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); + tty_port_close(&port->port, tty, filp); } @@ -308,14 +306,14 @@ static void serial_cleanup(struct tty_struct *tty) struct usb_serial *serial; struct module *owner; + dev_dbg(tty->dev, "%s\n", __func__); + /* The console is magical. Do not hang up the console hardware * or there will be tears. */ if (port->port.console) return; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); - tty->driver_data = NULL; serial = port->serial; @@ -339,10 +337,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf, if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; - dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__, - port->number, count); + dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count); - /* pass on to the driver specific version of this function */ retval = port->serial->type->write(tty, port, buf, count); if (retval < 0) retval = usb_translate_errors(retval); @@ -354,8 +350,8 @@ static int serial_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); - /* pass on to the driver specific version of this function */ + dev_dbg(tty->dev, "%s\n", __func__); + return port->serial->type->write_room(tty); } @@ -365,7 +361,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty) struct usb_serial *serial = port->serial; int count = 0; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); mutex_lock(&serial->disc_mutex); /* if the device was unplugged then any remaining characters @@ -383,9 +379,8 @@ static void serial_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); - /* pass on to the driver specific version of this function */ if (port->serial->type->throttle) port->serial->type->throttle(tty); } @@ -394,9 +389,8 @@ static void serial_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); - /* pass on to the driver specific version of this function */ if (port->serial->type->unthrottle) port->serial->type->unthrottle(tty); } @@ -407,15 +401,20 @@ static int serial_ioctl(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; int retval = -ENODEV; - dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__, - port->number, cmd); + dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd); + + switch (cmd) { + case TIOCMIWAIT: + if (port->serial->type->tiocmiwait) + retval = port->serial->type->tiocmiwait(tty, arg); + break; + default: + if (port->serial->type->ioctl) + retval = port->serial->type->ioctl(tty, cmd, arg); + else + retval = -ENOIOCTLCMD; + } - /* pass on to the driver specific version of this function - if it is available */ - if (port->serial->type->ioctl) { - retval = port->serial->type->ioctl(tty, cmd, arg); - } else - retval = -ENOIOCTLCMD; return retval; } @@ -423,10 +422,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); - /* pass on to the driver specific version of this function - if it is available */ if (port->serial->type->set_termios) port->serial->type->set_termios(tty, port, old); else @@ -437,12 +434,11 @@ static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); - /* pass on to the driver specific version of this function - if it is available */ if (port->serial->type->break_ctl) port->serial->type->break_ctl(tty, break_state); + return 0; } @@ -496,7 +492,7 @@ static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->tiocmget) return port->serial->type->tiocmget(tty); @@ -508,7 +504,7 @@ static int serial_tiocmset(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->tiocmset) return port->serial->type->tiocmset(tty, set, clear); @@ -520,7 +516,7 @@ static int serial_get_icount(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; - dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); + dev_dbg(tty->dev, "%s\n", __func__); if (port->serial->type->get_icount) return port->serial->type->get_icount(tty, icount); @@ -546,43 +542,39 @@ static void usb_serial_port_work(struct work_struct *work) tty_port_tty_wakeup(&port->port); } -static void kill_traffic(struct usb_serial_port *port) +static void usb_serial_port_poison_urbs(struct usb_serial_port *port) { int i; for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); + usb_poison_urb(port->read_urbs[i]); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); - /* - * This is tricky. - * Some drivers submit the read_urb in the - * handler for the write_urb or vice versa - * this order determines the order in which - * usb_kill_urb() must be used to reliably - * kill the URBs. As it is unknown here, - * both orders must be used in turn. - * The call below is not redundant. - */ - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_out_urb); + usb_poison_urb(port->write_urbs[i]); + + usb_poison_urb(port->interrupt_in_urb); + usb_poison_urb(port->interrupt_out_urb); +} + +static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) + usb_unpoison_urb(port->read_urbs[i]); + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) + usb_unpoison_urb(port->write_urbs[i]); + + usb_unpoison_urb(port->interrupt_in_urb); + usb_unpoison_urb(port->interrupt_out_urb); } -static void port_release(struct device *dev) +static void usb_serial_port_release(struct device *dev) { struct usb_serial_port *port = to_usb_serial_port(dev); int i; dev_dbg(dev, "%s\n", __func__); - /* - * Stop all the traffic before cancelling the work, so that - * nobody will restart it by calling usb_serial_port_softint. - */ - kill_traffic(port); - cancel_work_sync(&port->work); - usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_out_urb); for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { @@ -607,10 +599,8 @@ static struct usb_serial *create_serial(struct usb_device *dev, struct usb_serial *serial; serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); + if (!serial) return NULL; - } serial->dev = usb_get_dev(dev); serial->type = driver; serial->interface = usb_get_intf(interface); @@ -673,7 +663,7 @@ static struct usb_serial_driver *search_serial_device( return NULL; } -static int serial_carrier_raised(struct tty_port *port) +static int serial_port_carrier_raised(struct tty_port *port) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); struct usb_serial_driver *drv = p->serial->type; @@ -684,7 +674,7 @@ static int serial_carrier_raised(struct tty_port *port) return 1; } -static void serial_dtr_rts(struct tty_port *port, int on) +static void serial_port_dtr_rts(struct tty_port *port, int on) { struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); struct usb_serial *serial = p->serial; @@ -704,10 +694,10 @@ static void serial_dtr_rts(struct tty_port *port, int on) } static const struct tty_port_operations serial_port_ops = { - .carrier_raised = serial_carrier_raised, - .dtr_rts = serial_dtr_rts, - .activate = serial_activate, - .shutdown = serial_down, + .carrier_raised = serial_port_carrier_raised, + .dtr_rts = serial_port_dtr_rts, + .activate = serial_port_activate, + .shutdown = serial_port_shutdown, }; static int usb_serial_probe(struct usb_interface *interface, @@ -754,7 +744,6 @@ static int usb_serial_probe(struct usb_interface *interface, serial = create_serial(dev, interface, type); if (!serial) { module_put(type->driver.owner); - dev_err(ddev, "%s - out of memory\n", __func__); return -ENOMEM; } @@ -895,7 +884,6 @@ static int usb_serial_probe(struct usb_interface *interface, port->port.ops = &serial_port_ops; port->serial = serial; spin_lock_init(&port->lock); - init_waitqueue_head(&port->delta_msr_wait); /* Keep this for private driver use for the moment but should probably go away */ INIT_WORK(&port->work, usb_serial_port_work); @@ -903,7 +891,7 @@ static int usb_serial_probe(struct usb_interface *interface, port->dev.parent = &interface->dev; port->dev.driver = NULL; port->dev.bus = &usb_serial_bus_type; - port->dev.release = &port_release; + port->dev.release = &usb_serial_port_release; device_initialize(&port->dev); } @@ -919,16 +907,12 @@ static int usb_serial_probe(struct usb_interface *interface, for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) { set_bit(j, &port->read_urbs_free); port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->read_urbs[j]) { - dev_err(ddev, "No free urbs available\n"); + if (!port->read_urbs[j]) goto probe_error; - } port->bulk_in_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_in_buffers[j]) { - dev_err(ddev, "Couldn't allocate bulk_in_buffer\n"); + if (!port->bulk_in_buffers[j]) goto probe_error; - } usb_fill_bulk_urb(port->read_urbs[j], dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), @@ -955,16 +939,12 @@ static int usb_serial_probe(struct usb_interface *interface, for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { set_bit(j, &port->write_urbs_free); port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urbs[j]) { - dev_err(ddev, "No free urbs available\n"); + if (!port->write_urbs[j]) goto probe_error; - } port->bulk_out_buffers[j] = kmalloc(buffer_size, GFP_KERNEL); - if (!port->bulk_out_buffers[j]) { - dev_err(ddev, "Couldn't allocate bulk_out_buffer\n"); + if (!port->bulk_out_buffers[j]) goto probe_error; - } usb_fill_bulk_urb(port->write_urbs[j], dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress), @@ -982,19 +962,15 @@ static int usb_serial_probe(struct usb_interface *interface, endpoint = interrupt_in_endpoint[i]; port = serial->port[i]; port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_in_urb) { - dev_err(ddev, "No free urbs available\n"); + if (!port->interrupt_in_urb) goto probe_error; - } buffer_size = usb_endpoint_maxp(endpoint); port->interrupt_in_endpointAddress = endpoint->bEndpointAddress; port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->interrupt_in_buffer) { - dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n"); + if (!port->interrupt_in_buffer) goto probe_error; - } usb_fill_int_urb(port->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), @@ -1011,20 +987,16 @@ static int usb_serial_probe(struct usb_interface *interface, endpoint = interrupt_out_endpoint[i]; port = serial->port[i]; port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_out_urb) { - dev_err(ddev, "No free urbs available\n"); + if (!port->interrupt_out_urb) goto probe_error; - } buffer_size = usb_endpoint_maxp(endpoint); port->interrupt_out_size = buffer_size; port->interrupt_out_endpointAddress = endpoint->bEndpointAddress; port->interrupt_out_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!port->interrupt_out_buffer) { - dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n"); + if (!port->interrupt_out_buffer) goto probe_error; - } usb_fill_int_urb(port->interrupt_out_urb, dev, usb_sndintpipe(dev, endpoint->bEndpointAddress), @@ -1113,13 +1085,15 @@ static void usb_serial_disconnect(struct usb_interface *interface) tty_vhangup(tty); tty_kref_put(tty); } - kill_traffic(port); + usb_serial_port_poison_urbs(port); + wake_up_interruptible(&port->port.delta_msr_wait); cancel_work_sync(&port->work); if (device_is_registered(&port->dev)) device_del(&port->dev); } } - serial->type->disconnect(serial); + if (serial->type->disconnect) + serial->type->disconnect(serial); /* let the last holder of this object cause it to be cleaned up */ usb_serial_put(serial); @@ -1134,6 +1108,11 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) serial->suspending = 1; + /* + * serial->type->suspend() MUST return 0 in system sleep context, + * otherwise, the resume callback has to recover device from + * previous suspend failure. + */ if (serial->type->suspend) { r = serial->type->suspend(serial, message); if (r < 0) { @@ -1145,7 +1124,7 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (port) - kill_traffic(port); + usb_serial_port_poison_urbs(port); } err_out: @@ -1153,11 +1132,25 @@ err_out: } EXPORT_SYMBOL(usb_serial_suspend); +static void usb_serial_unpoison_port_urbs(struct usb_serial *serial) +{ + struct usb_serial_port *port; + int i; + + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (port) + usb_serial_port_unpoison_urbs(port); + } +} + int usb_serial_resume(struct usb_interface *intf) { struct usb_serial *serial = usb_get_intfdata(intf); int rv; + usb_serial_unpoison_port_urbs(serial); + serial->suspending = 0; if (serial->type->resume) rv = serial->type->resume(serial); @@ -1173,6 +1166,8 @@ static int usb_serial_reset_resume(struct usb_interface *intf) struct usb_serial *serial = usb_get_intfdata(intf); int rv; + usb_serial_unpoison_port_urbs(serial); + serial->suspending = 0; if (serial->type->reset_resume) rv = serial->type->reset_resume(serial); @@ -1309,12 +1304,12 @@ module_exit(usb_serial_exit); do { \ if (!type->function) { \ type->function = usb_serial_generic_##function; \ - pr_debug("Had to override the " #function \ - " usb serial operation with the generic one.");\ - } \ + pr_debug("%s: using generic " #function "\n", \ + type->driver.name); \ + } \ } while (0) -static void fixup_generic(struct usb_serial_driver *device) +static void usb_serial_operations_init(struct usb_serial_driver *device) { set_to_generic_if_null(device, open); set_to_generic_if_null(device, write); @@ -1323,8 +1318,6 @@ static void fixup_generic(struct usb_serial_driver *device) set_to_generic_if_null(device, chars_in_buffer); set_to_generic_if_null(device, read_bulk_callback); set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, disconnect); - set_to_generic_if_null(device, release); set_to_generic_if_null(device, process_read_urb); set_to_generic_if_null(device, prepare_write_buffer); } @@ -1336,8 +1329,6 @@ static int usb_serial_register(struct usb_serial_driver *driver) if (usb_disabled()) return -ENODEV; - fixup_generic(driver); - if (!driver->description) driver->description = driver->driver.name; if (!driver->usb_driver) { @@ -1346,6 +1337,8 @@ static int usb_serial_register(struct usb_serial_driver *driver) return -EINVAL; } + usb_serial_operations_init(driver); + /* Add this device to our list of devices */ mutex_lock(&table_lock); list_add(&driver->driver_list, &usb_serial_driver_list); @@ -1463,7 +1456,6 @@ void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_driver } EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); -/* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 571965aa1cc0..ece326ef63a0 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -421,20 +421,19 @@ void usb_wwan_close(struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - if (serial->dev) { - /* Stop reading/writing urbs */ - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); + /* Stop reading/writing urbs */ + spin_lock_irq(&intfdata->susp_lock); + portdata->opened = 0; + spin_unlock_irq(&intfdata->susp_lock); - for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); - for (i = 0; i < N_OUT_URB; i++) - usb_kill_urb(portdata->out_urbs[i]); - /* balancing - important as an error cannot be handled*/ - usb_autopm_get_interface_no_resume(serial->interface); - serial->interface->needs_remote_wakeup = 0; - } + for (i = 0; i < N_IN_URB; i++) + usb_kill_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + usb_kill_urb(portdata->out_urbs[i]); + + /* balancing - important as an error cannot be handled*/ + usb_autopm_get_interface_no_resume(serial->interface); + serial->interface->needs_remote_wakeup = 0; } EXPORT_SYMBOL(usb_wwan_close); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 1129aa73c23e..7573ec8a084f 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -257,24 +257,18 @@ static void visor_close(struct usb_serial_port *port) { unsigned char *transfer_buffer; - /* shutdown our urbs */ usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Try to send shutdown message, unless the device is gone */ - transfer_buffer = kmalloc(0x12, GFP_KERNEL); - if (transfer_buffer) { - usb_control_msg(port->serial->dev, + transfer_buffer = kmalloc(0x12, GFP_KERNEL); + if (!transfer_buffer) + return; + usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), VISOR_CLOSE_NOTIFICATION, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); - kfree(transfer_buffer); - } - } - mutex_unlock(&port->serial->disc_mutex); + kfree(transfer_buffer); } static void visor_read_int_callback(struct urb *urb) diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c new file mode 100644 index 000000000000..100573c6f19e --- /dev/null +++ b/drivers/usb/serial/wishbone-serial.c @@ -0,0 +1,95 @@ +/* + * USB Wishbone-Serial adapter driver + * + * Copyright (C) 2013 Wesley W. Terpstra <w.terpstra@gsi.de> + * Copyright (C) 2013 GSI Helmholtz Centre for Heavy Ion Research GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/uaccess.h> + +#define GSI_VENDOR_OPENCLOSE 0xB0 + +static const struct usb_device_id id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x1D50, 0x6062, 0xFF, 0xFF, 0xFF) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* + * Etherbone must be told that a new stream has begun before data arrives. + * This is necessary to restart the negotiation of Wishbone bus parameters. + * Similarly, when the stream ends, Etherbone must be told so that the cycle + * line can be driven low in the case that userspace failed to do so. + */ +static int usb_gsi_openclose(struct usb_serial_port *port, int value) +{ + struct usb_device *dev = port->serial->dev; + + return usb_control_msg( + dev, + usb_sndctrlpipe(dev, 0), /* Send to EP0OUT */ + GSI_VENDOR_OPENCLOSE, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + value, /* wValue = device is open(1) or closed(0) */ + port->serial->interface->cur_altsetting->desc.bInterfaceNumber, + NULL, 0, /* There is no data stage */ + 5000); /* Timeout till operation fails */ +} + +static int wishbone_serial_open(struct tty_struct *tty, + struct usb_serial_port *port) +{ + int retval; + + retval = usb_gsi_openclose(port, 1); + if (retval) { + dev_err(&port->serial->dev->dev, + "Could not mark device as open (%d)\n", + retval); + return retval; + } + + retval = usb_serial_generic_open(tty, port); + if (retval) + usb_gsi_openclose(port, 0); + + return retval; +} + +static void wishbone_serial_close(struct usb_serial_port *port) +{ + usb_serial_generic_close(port); + usb_gsi_openclose(port, 0); +} + +static struct usb_serial_driver wishbone_serial_device = { + .driver = { + .owner = THIS_MODULE, + .name = "wishbone_serial", + }, + .id_table = id_table, + .num_ports = 1, + .open = &wishbone_serial_open, + .close = &wishbone_serial_close, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &wishbone_serial_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_AUTHOR("Wesley W. Terpstra <w.terpstra@gsi.de>"); +MODULE_DESCRIPTION("USB Wishbone-Serial adapter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index eab04a6b5fbc..8470e1b114f2 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -4,11 +4,10 @@ comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may" comment "also be needed; see USB_STORAGE Help for more info" - depends on USB config USB_STORAGE tristate "USB Mass Storage support" - depends on USB && SCSI + depends on SCSI ---help--- Say Y here if you want to connect USB mass storage devices to your computer's USB port. This is the driver you need for USB @@ -188,7 +187,7 @@ config USB_STORAGE_CYPRESS_ATACB config USB_STORAGE_ENE_UB6250 tristate "USB ENE card reader support" - depends on USB && SCSI + depends on SCSI depends on USB_STORAGE ---help--- Say Y here if you wish to control a ENE SD/MS Card reader. @@ -203,7 +202,7 @@ config USB_STORAGE_ENE_UB6250 config USB_UAS tristate "USB Attached SCSI" - depends on USB && SCSI && BROKEN + depends on SCSI && BROKEN help The USB Attached SCSI protocol is supported by some USB storage devices. It permits higher performance by supporting diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c index be5564cc8e01..77a2ddfe6487 100644 --- a/drivers/usb/storage/alauda.c +++ b/drivers/usb/storage/alauda.c @@ -326,8 +326,7 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data) rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, command, 0xc0, 0, 1, data, 2); - US_DEBUGP("alauda_get_media_status: Media status %02X %02X\n", - data[0], data[1]); + usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]); return rc; } @@ -402,7 +401,7 @@ static int alauda_init_media(struct us_data *us) ready = 1; } - US_DEBUGP("alauda_init_media: We are ready for action!\n"); + usb_stor_dbg(us, "We are ready for action!\n"); if (alauda_ack_media(us) != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -413,15 +412,15 @@ static int alauda_init_media(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; if (data[0] != 0x14) { - US_DEBUGP("alauda_init_media: Media not ready after ack\n"); + usb_stor_dbg(us, "Media not ready after ack\n"); return USB_STOR_TRANSPORT_ERROR; } if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("alauda_init_media: Media signature: %02X %02X %02X %02X\n", - data[0], data[1], data[2], data[3]); + usb_stor_dbg(us, "Media signature: %02X %02X %02X %02X\n", + data[0], data[1], data[2], data[3]); media_info = alauda_card_find_id(data[1]); if (media_info == NULL) { printk(KERN_WARNING @@ -432,8 +431,8 @@ static int alauda_init_media(struct us_data *us) } MEDIA_INFO(us).capacity = 1 << media_info->chipshift; - US_DEBUGP("Found media with capacity: %ldMB\n", - MEDIA_INFO(us).capacity >> 20); + usb_stor_dbg(us, "Found media with capacity: %ldMB\n", + MEDIA_INFO(us).capacity >> 20); MEDIA_INFO(us).pageshift = media_info->pageshift; MEDIA_INFO(us).blockshift = media_info->blockshift; @@ -472,7 +471,7 @@ static int alauda_check_media(struct us_data *us) /* Check for no media or door open */ if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10) || ((status[1] & 0x01) == 0)) { - US_DEBUGP("alauda_check_media: No media, or door open\n"); + usb_stor_dbg(us, "No media, or door open\n"); alauda_free_maps(&MEDIA_INFO(us)); info->sense_key = 0x02; info->sense_asc = 0x3A; @@ -482,7 +481,7 @@ static int alauda_check_media(struct us_data *us) /* Check for media change */ if (status[0] & 0x08) { - US_DEBUGP("alauda_check_media: Media change detected\n"); + usb_stor_dbg(us, "Media change detected\n"); alauda_free_maps(&MEDIA_INFO(us)); alauda_init_media(us); @@ -518,7 +517,7 @@ static int alauda_check_status2(struct us_data *us) if (rc != USB_STOR_XFER_GOOD) return rc; - US_DEBUGP("alauda_check_status2: %02X %02X %02X\n", data[0], data[1], data[2]); + usb_stor_dbg(us, "%02X %02X %02X\n", data[0], data[1], data[2]); if (data[0] & ALAUDA_STATUS_ERROR) return USB_STOR_XFER_ERROR; @@ -584,7 +583,7 @@ static int alauda_read_map(struct us_data *us, unsigned int zone) goto error; } - US_DEBUGP("alauda_read_map: Mapping blocks for zone %d\n", zone); + usb_stor_dbg(us, "Mapping blocks for zone %d\n", zone); /* 1024 PBA's per zone */ for (i = 0; i < zonesize; i++) @@ -604,7 +603,7 @@ static int alauda_read_map(struct us_data *us, unsigned int zone) if (data[j] != 0) goto nonz; pba_to_lba[i] = UNUSABLE; - US_DEBUGP("alauda_read_map: PBA %d has no logical mapping\n", blocknum); + usb_stor_dbg(us, "PBA %d has no logical mapping\n", blocknum); continue; nonz: @@ -617,19 +616,18 @@ static int alauda_read_map(struct us_data *us, unsigned int zone) nonff: /* normal PBAs start with six FFs */ if (j < 6) { - US_DEBUGP("alauda_read_map: PBA %d has no logical mapping: " - "reserved area = %02X%02X%02X%02X " - "data status %02X block status %02X\n", - blocknum, data[0], data[1], data[2], data[3], - data[4], data[5]); + usb_stor_dbg(us, "PBA %d has no logical mapping: reserved area = %02X%02X%02X%02X data status %02X block status %02X\n", + blocknum, + data[0], data[1], data[2], data[3], + data[4], data[5]); pba_to_lba[i] = UNUSABLE; continue; } if ((data[6] >> 4) != 0x01) { - US_DEBUGP("alauda_read_map: PBA %d has invalid address " - "field %02X%02X/%02X%02X\n", - blocknum, data[6], data[7], data[11], data[12]); + usb_stor_dbg(us, "PBA %d has invalid address field %02X%02X/%02X%02X\n", + blocknum, data[6], data[7], + data[11], data[12]); pba_to_lba[i] = UNUSABLE; continue; } @@ -711,7 +709,7 @@ static int alauda_erase_block(struct us_data *us, u16 pba) }; unsigned char buf[2]; - US_DEBUGP("alauda_erase_block: Erasing PBA %d\n", pba); + usb_stor_dbg(us, "Erasing PBA %d\n", pba); rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, command, 9, NULL); @@ -723,8 +721,7 @@ static int alauda_erase_block(struct us_data *us, u16 pba) if (rc != USB_STOR_XFER_GOOD) return rc; - US_DEBUGP("alauda_erase_block: Erase result: %02X %02X\n", - buf[0], buf[1]); + usb_stor_dbg(us, "Erase result: %02X %02X\n", buf[0], buf[1]); return rc; } @@ -741,8 +738,7 @@ static int alauda_read_block_raw(struct us_data *us, u16 pba, PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us) }; - US_DEBUGP("alauda_read_block: pba %d page %d count %d\n", - pba, page, pages); + usb_stor_dbg(us, "pba %d page %d count %d\n", pba, page, pages); rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, command, 9, NULL); @@ -793,7 +789,7 @@ static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data) PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us) }; - US_DEBUGP("alauda_write_block: pba %d\n", pba); + usb_stor_dbg(us, "pba %d\n", pba); rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, command, 9, NULL); @@ -866,14 +862,14 @@ static int alauda_write_lba(struct us_data *us, u16 lba, cptr = bptr + pagesize; nand_compute_ecc(bptr, ecc); if (!nand_compare_ecc(cptr+13, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n", + i, pba); nand_store_ecc(cptr+13, ecc); } nand_compute_ecc(bptr + (pagesize / 2), ecc); if (!nand_compare_ecc(cptr+8, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n", + i, pba); nand_store_ecc(cptr+8, ecc); } cptr[6] = cptr[11] = MSB_of(lbap); @@ -900,8 +896,7 @@ static int alauda_write_lba(struct us_data *us, u16 lba, new_pba_offset = new_pba - (zone * zonesize); MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba; MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba; - US_DEBUGP("alauda_write_lba: Remapped LBA %d to PBA %d\n", - lba, new_pba); + usb_stor_dbg(us, "Remapped LBA %d to PBA %d\n", lba, new_pba); if (pba != UNDEF) { unsigned int pba_offset = pba - (zone * zonesize); @@ -964,8 +959,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address, /* Not overflowing capacity? */ if (lba >= max_lba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, max_lba); + usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", + lba, max_lba); result = USB_STOR_TRANSPORT_ERROR; break; } @@ -978,8 +973,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address, pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset]; if (pba == UNDEF) { /* this lba was never written */ - US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", - pages, lba, page); + usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", + pages, lba, page); /* This is not really an error. It just means that the block has never been written. @@ -988,9 +983,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address, memset(buffer, 0, len); } else { - US_DEBUGP("Read %d pages, from PBA %d" - " (LBA %d) page %d\n", - pages, pba, lba, page); + usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n", + pages, pba, lba, page); result = alauda_read_block(us, pba, page, pages, buffer); if (result != USB_STOR_TRANSPORT_GOOD) @@ -1066,8 +1060,8 @@ static int alauda_write_data(struct us_data *us, unsigned long address, /* Not overflowing capacity? */ if (lba >= max_lba) { - US_DEBUGP("alauda_write_data: Requested lba %u exceeds " - "maximum %u\n", lba, max_lba); + usb_stor_dbg(us, "Requested lba %u exceeds maximum %u\n", + lba, max_lba); result = USB_STOR_TRANSPORT_ERROR; break; } @@ -1122,11 +1116,9 @@ static int init_alauda(struct us_data *us) nand_init_ecc(); us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("init_alauda: Gah! Can't allocate storage for" - "alauda info struct!\n"); + if (!us->extra) return USB_STOR_TRANSPORT_ERROR; - } + info = (struct alauda_info *) us->extra; us->extra_destructor = alauda_info_destructor; @@ -1147,15 +1139,14 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) }; if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("alauda_transport: INQUIRY. " - "Returning bogus response.\n"); + usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); memcpy(ptr, inquiry_response, sizeof(inquiry_response)); fill_inquiry_response(us, ptr, 36); return USB_STOR_TRANSPORT_GOOD; } if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("alauda_transport: TEST_UNIT_READY.\n"); + usb_stor_dbg(us, "TEST_UNIT_READY\n"); return alauda_check_media(us); } @@ -1193,8 +1184,7 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("alauda_transport: READ_10: page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "READ_10: page %d pagect %d\n", page, pages); return alauda_read_data(us, page, pages); } @@ -1211,14 +1201,13 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("alauda_transport: WRITE_10: page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "WRITE_10: page %d pagect %d\n", page, pages); return alauda_write_data(us, page, pages); } if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("alauda_transport: REQUEST_SENSE.\n"); + usb_stor_dbg(us, "REQUEST_SENSE\n"); memset(ptr, 0, 18); ptr[0] = 0xF0; @@ -1237,8 +1226,8 @@ static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; } - US_DEBUGP("alauda_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); + usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", + srb->cmnd[0], srb->cmnd[0]); info->sense_key = 0x05; info->sense_asc = 0x20; info->sense_ascq = 0x00; diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c index 070b5c0ebbf9..8514a2d82b72 100644 --- a/drivers/usb/storage/cypress_atacb.c +++ b/drivers/usb/storage/cypress_atacb.c @@ -159,7 +159,7 @@ static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) if (srb->result == SAM_STAT_CHECK_CONDITION && memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB, sizeof(usb_stor_sense_invalidCDB)) == 0) { - US_DEBUGP("cypress atacb not supported ???\n"); + usb_stor_dbg(us, "cypress atacb not supported ???\n"); goto end; } @@ -248,14 +248,26 @@ static int cypress_probe(struct usb_interface *intf, { struct us_data *us; int result; + struct usb_device *device; result = usb_stor_probe1(&us, intf, id, (id - cypress_usb_ids) + cypress_unusual_dev_list); if (result) return result; - us->protocol_name = "Transparent SCSI with Cypress ATACB"; - us->proto_handler = cypress_atacb_passthrough; + /* Among CY7C68300 chips, the A revision does not support Cypress ATACB + * Filter out this revision from EEPROM default descriptor values + */ + device = interface_to_usbdev(intf); + if (device->descriptor.iManufacturer != 0x38 || + device->descriptor.iProduct != 0x4e || + device->descriptor.iSerialNumber != 0x64) { + us->protocol_name = "Transparent SCSI with Cypress ATACB"; + us->proto_handler = cypress_atacb_passthrough; + } else { + us->protocol_name = "Transparent SCSI"; + us->proto_handler = usb_stor_transparent_scsi_command; + } result = usb_stor_probe2(us); return result; diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c index 494fee5af41d..7b17c2169812 100644 --- a/drivers/usb/storage/datafab.c +++ b/drivers/usb/storage/datafab.c @@ -123,7 +123,7 @@ datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("datafab_bulk_read: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL); } @@ -134,7 +134,7 @@ datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("datafab_bulk_write: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL); } @@ -300,9 +300,8 @@ static int datafab_write_data(struct us_data *us, goto leave; if (reply[0] != 0x50 && reply[1] != 0) { - US_DEBUGP("datafab_write_data: Gah! " - "write return code: %02x %02x\n", - reply[0], reply[1]); + usb_stor_dbg(us, "Gah! write return code: %02x %02x\n", + reply[0], reply[1]); result = USB_STOR_TRANSPORT_ERROR; goto leave; } @@ -342,7 +341,7 @@ static int datafab_determine_lun(struct us_data *us, if (!buf) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("datafab_determine_lun: locating...\n"); + usb_stor_dbg(us, "locating...\n"); // we'll try 3 times before giving up... // @@ -474,16 +473,16 @@ static int datafab_handle_mode_sense(struct us_data *us, switch (pc) { case 0x0: - US_DEBUGP("datafab_handle_mode_sense: Current values\n"); + usb_stor_dbg(us, "Current values\n"); break; case 0x1: - US_DEBUGP("datafab_handle_mode_sense: Changeable values\n"); + usb_stor_dbg(us, "Changeable values\n"); break; case 0x2: - US_DEBUGP("datafab_handle_mode_sense: Default values\n"); + usb_stor_dbg(us, "Default values\n"); break; case 0x3: - US_DEBUGP("datafab_handle_mode_sense: Saves values\n"); + usb_stor_dbg(us, "Saves values\n"); break; } @@ -566,11 +565,9 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) if (!us->extra) { us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("datafab_transport: Gah! " - "Can't allocate storage for Datafab info struct!\n"); + if (!us->extra) return USB_STOR_TRANSPORT_ERROR; - } + us->extra_destructor = datafab_info_destructor; ((struct datafab_info *)us->extra)->lun = -1; } @@ -578,7 +575,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) info = (struct datafab_info *) (us->extra); if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response"); + usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); memcpy(ptr, inquiry_reply, sizeof(inquiry_reply)); fill_inquiry_response(us, ptr, 36); return USB_STOR_TRANSPORT_GOOD; @@ -590,8 +587,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); + usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", + info->sectors, info->ssize); // build the reply // we need the last sector, not the number of sectors @@ -603,7 +600,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("datafab_transport: Gah! MODE_SELECT_10.\n"); + usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -615,7 +612,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("datafab_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", + block, blocks); return datafab_read_data(us, info, block, blocks); } @@ -628,7 +626,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("datafab_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", + block, blocks); return datafab_read_data(us, info, block, blocks); } @@ -638,7 +637,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("datafab_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", + block, blocks); return datafab_write_data(us, info, block, blocks); } @@ -651,17 +651,18 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", + block, blocks); return datafab_write_data(us, info, block, blocks); } if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n"); + usb_stor_dbg(us, "TEST_UNIT_READY\n"); return datafab_id_device(us, info); } if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("datafab_transport: REQUEST_SENSE. Returning faked response\n"); + usb_stor_dbg(us, "REQUEST_SENSE - Returning faked response\n"); // this response is pretty bogus right now. eventually if necessary // we can set the correct sense data. so far though it hasn't been @@ -679,12 +680,12 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); + usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); return datafab_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); + usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); return datafab_handle_mode_sense(us, srb, 0); } @@ -698,7 +699,7 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) if (srb->cmnd[0] == START_STOP) { /* this is used by sd.c'check_scsidisk_media_change to detect media change */ - US_DEBUGP("datafab_transport: START_STOP.\n"); + usb_stor_dbg(us, "START_STOP\n"); /* the first datafab_id_device after a media change returns an error (determined experimentally) */ rc = datafab_id_device(us, info); @@ -712,8 +713,8 @@ static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) return rc; } - US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); + usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", + srb->cmnd[0], srb->cmnd[0]); info->sense_key = 0x05; info->sense_asc = 0x20; info->sense_ascq = 0x00; diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c index a2b5526c9fa0..e08f64780e30 100644 --- a/drivers/usb/storage/debug.c +++ b/drivers/usb/storage/debug.c @@ -42,16 +42,19 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/device.h> #include <linux/cdrom.h> +#include <linux/export.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_dbg.h> +#include "usb.h" #include "debug.h" #include "scsi.h" -void usb_stor_show_command(struct scsi_cmnd *srb) +void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb) { char *what = NULL; int i; @@ -149,18 +152,18 @@ void usb_stor_show_command(struct scsi_cmnd *srb) case WRITE_LONG_2: what = "WRITE_LONG_2"; break; default: what = "(unknown command)"; break; } - US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len); - US_DEBUGP(""); + usb_stor_dbg(us, "Command %s (%d bytes)\n", what, srb->cmd_len); + usb_stor_dbg(us, "bytes: "); for (i = 0; i < srb->cmd_len && i < 16; i++) US_DEBUGPX(" %02x", srb->cmnd[i]); US_DEBUGPX("\n"); } -void usb_stor_show_sense( - unsigned char key, - unsigned char asc, - unsigned char ascq) { - +void usb_stor_show_sense(const struct us_data *us, + unsigned char key, + unsigned char asc, + unsigned char ascq) +{ const char *what, *keystr; keystr = scsi_sense_key_string(key); @@ -171,7 +174,22 @@ void usb_stor_show_sense( if (what == NULL) what = "(unknown ASC/ASCQ)"; - US_DEBUGP("%s: ", keystr); + usb_stor_dbg(us, "%s: ", keystr); US_DEBUGPX(what, ascq); US_DEBUGPX("\n"); } + +int usb_stor_dbg(const struct us_data *us, const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + + r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args); + + va_end(args); + + return r; +} +EXPORT_SYMBOL_GPL(usb_stor_dbg); diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h index dbb985d52423..b1273f03e223 100644 --- a/drivers/usb/storage/debug.h +++ b/drivers/usb/storage/debug.h @@ -47,15 +47,22 @@ #define USB_STORAGE "usb-storage: " #ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(struct scsi_cmnd *srb); -void usb_stor_show_sense( unsigned char key, - unsigned char asc, unsigned char ascq ); -#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) -#define US_DEBUGPX(x...) printk( x ) -#define US_DEBUG(x) x +void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb); +void usb_stor_show_sense(const struct us_data *us, unsigned char key, + unsigned char asc, unsigned char ascq); +__printf(2, 3) int usb_stor_dbg(const struct us_data *us, + const char *fmt, ...); + +#define US_DEBUGPX(fmt, ...) printk(fmt, ##__VA_ARGS__) +#define US_DEBUG(x) x #else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) +__printf(2, 3) +static inline int _usb_stor_dbg(const struct us_data *us, + const char *fmt, ...) {return 1;} +#define usb_stor_dbg(us, fmt, ...) \ + do { if (0) _usb_stor_dbg(us, fmt, ##__VA_ARGS__); } while (0) +#define US_DEBUGPX(fmt, ...) \ + do { if (0) printk(fmt, ##__VA_ARGS__); } while (0) #define US_DEBUG(x) #endif diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 118b134a1dad..1bfc9a6cab5f 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -504,12 +504,12 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) unsigned int cswlen = 0, partial = 0; unsigned int transfer_length = bcb->DataTransferLength; - /* US_DEBUGP("transport --- ene_send_scsi_cmd\n"); */ + /* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */ /* send cmd to out endpoint */ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("send cmd to out endpoint fail ---\n"); + usb_stor_dbg(us, "send cmd to out endpoint fail ---\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -529,7 +529,7 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) transfer_length, 0, &partial); } if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("data transfer fail ---\n"); + usb_stor_dbg(us, "data transfer fail ---\n"); return USB_STOR_TRANSPORT_ERROR; } } @@ -539,14 +539,14 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) US_BULK_CS_WRAP_LEN, &cswlen); if (result == USB_STOR_XFER_SHORT && cswlen == 0) { - US_DEBUGP("Received 0-length CSW; retrying...\n"); + usb_stor_dbg(us, "Received 0-length CSW; retrying...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); } if (result == USB_STOR_XFER_STALLED) { /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); + usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); } @@ -626,7 +626,7 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) struct scatterlist *sg = NULL; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - US_DEBUGP("sd_scsi_read_capacity\n"); + usb_stor_dbg(us, "sd_scsi_read_capacity\n"); if (info->SD_Status.HiCapacity) { bl_len = 0x200; if (info->SD_Status.IsMMC) @@ -639,8 +639,8 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) * (1 << (info->SD_C_SIZE_MULT + 2)) - 1; } info->bl_num = bl_num; - US_DEBUGP("bl_len = %x\n", bl_len); - US_DEBUGP("bl_num = %x\n", bl_num); + usb_stor_dbg(us, "bl_len = %x\n", bl_len); + usb_stor_dbg(us, "bl_num = %x\n", bl_num); /*srb->request_bufflen = 8; */ buf[0] = (bl_num >> 24) & 0xff; @@ -675,7 +675,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) result = ene_load_bincode(us, SD_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD RW pattern Fail !!\n"); + usb_stor_dbg(us, "Load SD RW pattern Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -715,7 +715,7 @@ static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) result = ene_load_bincode(us, SD_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD RW pattern Fail !!\n"); + usb_stor_dbg(us, "Load SD RW pattern Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -1493,7 +1493,7 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) struct scatterlist *sg = NULL; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - US_DEBUGP("ms_scsi_read_capacity\n"); + usb_stor_dbg(us, "ms_scsi_read_capacity\n"); bl_len = 0x200; if (info->MS_Status.IsMSPro) bl_num = info->MSP_TotalBlock - 1; @@ -1501,8 +1501,8 @@ static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1; info->bl_num = bl_num; - US_DEBUGP("bl_len = %x\n", bl_len); - US_DEBUGP("bl_num = %x\n", bl_num); + usb_stor_dbg(us, "bl_len = %x\n", bl_len); + usb_stor_dbg(us, "bl_num = %x\n", bl_num); /*srb->request_bufflen = 8; */ buf[0] = (bl_num >> 24) & 0xff; @@ -1654,7 +1654,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb) if (info->MS_Status.IsMSPro) { result = ene_load_bincode(us, MSP_RW_PATTERN); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load MPS RW pattern Fail !!\n"); + usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -1854,7 +1854,7 @@ static int ene_get_card_status(struct us_data *us, u8 *buf) u32 reg4b; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - /*US_DEBUGP("transport --- ENE_ReadSDReg\n");*/ + /*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/ reg4b = *(u32 *)&buf[0x18]; info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f); @@ -1894,45 +1894,44 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) switch (flag) { /* For SD */ case SD_INIT1_PATTERN: - US_DEBUGP("SD_INIT1_PATTERN\n"); + usb_stor_dbg(us, "SD_INIT1_PATTERN\n"); fw_name = SD_INIT1_FIRMWARE; break; case SD_INIT2_PATTERN: - US_DEBUGP("SD_INIT2_PATTERN\n"); + usb_stor_dbg(us, "SD_INIT2_PATTERN\n"); fw_name = SD_INIT2_FIRMWARE; break; case SD_RW_PATTERN: - US_DEBUGP("SD_RW_PATTERN\n"); + usb_stor_dbg(us, "SD_RW_PATTERN\n"); fw_name = SD_RW_FIRMWARE; break; /* For MS */ case MS_INIT_PATTERN: - US_DEBUGP("MS_INIT_PATTERN\n"); + usb_stor_dbg(us, "MS_INIT_PATTERN\n"); fw_name = MS_INIT_FIRMWARE; break; case MSP_RW_PATTERN: - US_DEBUGP("MSP_RW_PATTERN\n"); + usb_stor_dbg(us, "MSP_RW_PATTERN\n"); fw_name = MSP_RW_FIRMWARE; break; case MS_RW_PATTERN: - US_DEBUGP("MS_RW_PATTERN\n"); + usb_stor_dbg(us, "MS_RW_PATTERN\n"); fw_name = MS_RW_FIRMWARE; break; default: - US_DEBUGP("----------- Unknown PATTERN ----------\n"); + usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n"); goto nofw; } err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev); if (err) { - US_DEBUGP("load firmware %s failed\n", fw_name); + usb_stor_dbg(us, "load firmware %s failed\n", fw_name); goto nofw; } buf = kmalloc(sd_fw->size, GFP_KERNEL); - if (buf == NULL) { - US_DEBUGP("Malloc memory for fireware failed!\n"); + if (buf == NULL) goto nofw; - } + memcpy(buf, sd_fw->data, sd_fw->size); memset(bcb, 0, sizeof(struct bulk_cb_wrap)); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); @@ -2116,9 +2115,9 @@ static int ene_ms_init(struct us_data *us) } else { ms_card_init(us); /* Card is MS (to ms.c)*/ } - US_DEBUGP("MS Init Code OK !!\n"); + usb_stor_dbg(us, "MS Init Code OK !!\n"); } else { - US_DEBUGP("MS Card Not Ready --- %x\n", buf[0]); + usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]); return USB_STOR_TRANSPORT_ERROR; } @@ -2132,11 +2131,11 @@ static int ene_sd_init(struct us_data *us) struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - US_DEBUGP("transport --- ENE_SDInit\n"); + usb_stor_dbg(us, "transport --- ENE_SDInit\n"); /* SD Init Part-1 */ result = ene_load_bincode(us, SD_INIT1_PATTERN); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD Init Code Part-1 Fail !!\n"); + usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -2147,14 +2146,14 @@ static int ene_sd_init(struct us_data *us) result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Execution SD Init Code Fail !!\n"); + usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } /* SD Init Part-2 */ result = ene_load_bincode(us, SD_INIT2_PATTERN); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD Init Code Part-2 Fail !!\n"); + usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -2166,21 +2165,23 @@ static int ene_sd_init(struct us_data *us) result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Execution SD Init Code Fail !!\n"); + usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } info->SD_Status = *(struct SD_STATUS *)&buf[0]; if (info->SD_Status.Insert && info->SD_Status.Ready) { + struct SD_STATUS *s = &info->SD_Status; + ene_get_card_status(us, (unsigned char *)&buf); - US_DEBUGP("Insert = %x\n", info->SD_Status.Insert); - US_DEBUGP("Ready = %x\n", info->SD_Status.Ready); - US_DEBUGP("IsMMC = %x\n", info->SD_Status.IsMMC); - US_DEBUGP("HiCapacity = %x\n", info->SD_Status.HiCapacity); - US_DEBUGP("HiSpeed = %x\n", info->SD_Status.HiSpeed); - US_DEBUGP("WtP = %x\n", info->SD_Status.WtP); + usb_stor_dbg(us, "Insert = %x\n", s->Insert); + usb_stor_dbg(us, "Ready = %x\n", s->Ready); + usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); + usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity); + usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); + usb_stor_dbg(us, "WtP = %x\n", s->WtP); } else { - US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]); + usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]); return USB_STOR_TRANSPORT_ERROR; } return USB_STOR_TRANSPORT_GOOD; @@ -2293,7 +2294,7 @@ static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) int result = 0; struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - /*US_DEBUG(usb_stor_show_command(srb)); */ + /*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid(srb, 0); if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) { result = ene_init(us); @@ -2362,7 +2363,6 @@ static int ene_ub6250_resume(struct usb_interface *iface) mutex_lock(&us->dev_mutex); - US_DEBUGP("%s\n", __func__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_RESUME); @@ -2382,7 +2382,7 @@ static int ene_ub6250_reset_resume(struct usb_interface *iface) u8 tmp = 0; struct us_data *us = usb_get_intfdata(iface); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - US_DEBUGP("%s\n", __func__); + /* Report the reset to the SCSI core */ usb_stor_reset_resume(iface); diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index e6df087dca9d..ef16068b7087 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -40,7 +40,7 @@ MODULE_AUTHOR("David Brown <usb-storage@davidb.org>"); MODULE_LICENSE("GPL"); #ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *, int); +static void pdump(struct us_data *us, void *ibuffer, int length); #endif /* Bits of HD_STATUS */ @@ -161,20 +161,20 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, fxfr->Count = cpu_to_le32 (count); memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - US_DEBUGP("Read data Freecom! (c=%d)\n", count); + usb_stor_dbg(us, "Read data Freecom! (c=%d)\n", count); /* Issue the transfer command. */ result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, FCM_PACKET_LENGTH, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("Freecom readdata transport error\n"); + usb_stor_dbg(us, "Freecom readdata transport error\n"); return USB_STOR_TRANSPORT_ERROR; } /* Now transfer all of our blocks. */ - US_DEBUGP("Start of read\n"); + usb_stor_dbg(us, "Start of read\n"); result = usb_stor_bulk_srb(us, ipipe, srb); - US_DEBUGP("freecom_readdata done!\n"); + usb_stor_dbg(us, "freecom_readdata done!\n"); if (result > USB_STOR_XFER_SHORT) return USB_STOR_TRANSPORT_ERROR; @@ -194,21 +194,21 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, fxfr->Count = cpu_to_le32 (count); memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - US_DEBUGP("Write data Freecom! (c=%d)\n", count); + usb_stor_dbg(us, "Write data Freecom! (c=%d)\n", count); /* Issue the transfer command. */ result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, FCM_PACKET_LENGTH, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("Freecom writedata transport error\n"); + usb_stor_dbg(us, "Freecom writedata transport error\n"); return USB_STOR_TRANSPORT_ERROR; } /* Now transfer all of our blocks. */ - US_DEBUGP("Start of write\n"); + usb_stor_dbg(us, "Start of write\n"); result = usb_stor_bulk_srb(us, opipe, srb); - US_DEBUGP("freecom_writedata done!\n"); + usb_stor_dbg(us, "freecom_writedata done!\n"); if (result > USB_STOR_XFER_SHORT) return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_GOOD; @@ -230,7 +230,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) fcb = (struct freecom_cb_wrap *) us->iobuf; fst = (struct freecom_status *) us->iobuf; - US_DEBUGP("Freecom TRANSPORT STARTED\n"); + usb_stor_dbg(us, "Freecom TRANSPORT STARTED\n"); /* Get handles for both transports. */ opipe = us->send_bulk_pipe; @@ -242,7 +242,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) memcpy (fcb->Atapi, srb->cmnd, 12); memset (fcb->Filler, 0, sizeof (fcb->Filler)); - US_DEBUG(pdump (srb->cmnd, 12)); + US_DEBUG(pdump(us, srb->cmnd, 12)); /* Send it out. */ result = usb_stor_bulk_transfer_buf (us, opipe, fcb, @@ -252,7 +252,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) * USB land. It returns the status in its own registers, which * come back in the bulk pipe. */ if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("freecom transport error\n"); + usb_stor_dbg(us, "freecom transport error\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -260,11 +260,11 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) * doesn't hurt us to always do it now. */ result = usb_stor_bulk_transfer_buf (us, ipipe, fst, FCM_STATUS_PACKET_LENGTH, &partial); - US_DEBUGP("foo Status result %d %u\n", result, partial); + usb_stor_dbg(us, "foo Status result %d %u\n", result, partial); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUG(pdump ((void *) fst, partial)); + US_DEBUG(pdump(us, (void *)fst, partial)); /* The firmware will time-out commands after 20 seconds. Some commands * can legitimately take longer than this, so we use a different @@ -275,8 +275,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) * may not work, but that is a condition that should never happen. */ while (fst->Status & FCM_STATUS_BUSY) { - US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n"); - US_DEBUGP("fst->Status is %x\n", fst->Status); + usb_stor_dbg(us, "20 second USB/ATAPI bridge TIMEOUT occurred!\n"); + usb_stor_dbg(us, "fst->Status is %x\n", fst->Status); /* Get the status again */ fcb->Type = FCM_PACKET_STATUS; @@ -293,7 +293,7 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) * registers, which come back in the bulk pipe. */ if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("freecom transport error\n"); + usb_stor_dbg(us, "freecom transport error\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -301,26 +301,26 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) result = usb_stor_bulk_transfer_buf (us, ipipe, fst, FCM_STATUS_PACKET_LENGTH, &partial); - US_DEBUGP("bar Status result %d %u\n", result, partial); + usb_stor_dbg(us, "bar Status result %d %u\n", result, partial); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUG(pdump ((void *) fst, partial)); + US_DEBUG(pdump(us, (void *)fst, partial)); } if (partial != 4) return USB_STOR_TRANSPORT_ERROR; if ((fst->Status & 1) != 0) { - US_DEBUGP("operation failed\n"); + usb_stor_dbg(us, "operation failed\n"); return USB_STOR_TRANSPORT_FAILED; } /* The device might not have as much data available as we * requested. If you ask for more than the device has, this reads * and such will hang. */ - US_DEBUGP("Device indicates that it has %d bytes available\n", - le16_to_cpu (fst->Count)); - US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb)); + usb_stor_dbg(us, "Device indicates that it has %d bytes available\n", + le16_to_cpu(fst->Count)); + usb_stor_dbg(us, "SCSI requested %d\n", scsi_bufflen(srb)); /* Find the length we desire to read. */ switch (srb->cmnd[0]) { @@ -337,7 +337,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) /* verify that this amount is legal */ if (length > scsi_bufflen(srb)) { length = scsi_bufflen(srb); - US_DEBUGP("Truncating request to match buffer length: %d\n", length); + usb_stor_dbg(us, "Truncating request to match buffer length: %d\n", + length); } /* What we do now depends on what direction the data is supposed to @@ -351,29 +352,29 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) /* Make sure that the status indicates that the device * wants data as well. */ if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { - US_DEBUGP("SCSI wants data, drive doesn't have any\n"); + usb_stor_dbg(us, "SCSI wants data, drive doesn't have any\n"); return USB_STOR_TRANSPORT_FAILED; } result = freecom_readdata (srb, us, ipipe, opipe, length); if (result != USB_STOR_TRANSPORT_GOOD) return result; - US_DEBUGP("FCM: Waiting for status\n"); + usb_stor_dbg(us, "Waiting for status\n"); result = usb_stor_bulk_transfer_buf (us, ipipe, fst, FCM_PACKET_LENGTH, &partial); - US_DEBUG(pdump ((void *) fst, partial)); + US_DEBUG(pdump(us, (void *)fst, partial)); if (partial != 4 || result > USB_STOR_XFER_SHORT) return USB_STOR_TRANSPORT_ERROR; if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); + usb_stor_dbg(us, "operation failed\n"); return USB_STOR_TRANSPORT_FAILED; } if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); + usb_stor_dbg(us, "Drive seems still hungry\n"); return USB_STOR_TRANSPORT_FAILED; } - US_DEBUGP("Transfer happy\n"); + usb_stor_dbg(us, "Transfer happy\n"); break; case DMA_TO_DEVICE: @@ -387,22 +388,22 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) if (result != USB_STOR_TRANSPORT_GOOD) return result; - US_DEBUGP("FCM: Waiting for status\n"); + usb_stor_dbg(us, "Waiting for status\n"); result = usb_stor_bulk_transfer_buf (us, ipipe, fst, FCM_PACKET_LENGTH, &partial); if (partial != 4 || result > USB_STOR_XFER_SHORT) return USB_STOR_TRANSPORT_ERROR; if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); + usb_stor_dbg(us, "operation failed\n"); return USB_STOR_TRANSPORT_FAILED; } if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); + usb_stor_dbg(us, "Drive seems still hungry\n"); return USB_STOR_TRANSPORT_FAILED; } - US_DEBUGP("Transfer happy\n"); + usb_stor_dbg(us, "Transfer happy\n"); break; @@ -412,8 +413,8 @@ static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) default: /* should never hit here -- filtered in usb.c */ - US_DEBUGP ("freecom unimplemented direction: %d\n", - us->srb->sc_data_direction); + usb_stor_dbg(us, "freecom unimplemented direction: %d\n", + us->srb->sc_data_direction); /* Return fail, SCSI seems to handle this better. */ return USB_STOR_TRANSPORT_FAILED; break; @@ -434,7 +435,7 @@ static int init_freecom(struct us_data *us) result = usb_stor_control_msg(us, us->recv_ctrl_pipe, 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); buffer[32] = '\0'; - US_DEBUGP("String returned from FC init is: %s\n", buffer); + usb_stor_dbg(us, "String returned from FC init is: %s\n", buffer); /* Special thanks to the people at Freecom for providing me with * this "magic sequence", which they use in their Windows and MacOS @@ -445,7 +446,7 @@ static int init_freecom(struct us_data *us) /* send reset */ result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from activate reset is %d\n", result); + usb_stor_dbg(us, "result from activate reset is %d\n", result); /* wait 250ms */ mdelay(250); @@ -453,7 +454,7 @@ static int init_freecom(struct us_data *us) /* clear reset */ result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from clear reset is %d\n", result); + usb_stor_dbg(us, "result from clear reset is %d\n", result); /* wait 3 seconds */ mdelay(3 * 1000); @@ -470,7 +471,7 @@ static int usb_stor_freecom_reset(struct us_data *us) } #ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *ibuffer, int length) +static void pdump(struct us_data *us, void *ibuffer, int length) { static char line[80]; int offset = 0; @@ -490,7 +491,7 @@ static void pdump (void *ibuffer, int length) line[offset++] = '.'; } line[offset] = 0; - US_DEBUGP("%s\n", line); + usb_stor_dbg(us, "%s\n", line); offset = 0; } offset += sprintf (line+offset, "%08x:", i); @@ -517,7 +518,7 @@ static void pdump (void *ibuffer, int length) line[offset++] = '.'; } line[offset] = 0; - US_DEBUGP("%s\n", line); + usb_stor_dbg(us, "%s\n", line); offset = 0; } #endif diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c index 105d900150c1..5a8b5ff1e45b 100644 --- a/drivers/usb/storage/initializers.c +++ b/drivers/usb/storage/initializers.c @@ -48,12 +48,12 @@ int usb_stor_euscsi_init(struct us_data *us) { int result; - US_DEBUGP("Attempting to init eUSCSI bridge...\n"); + usb_stor_dbg(us, "Attempting to init eUSCSI bridge...\n"); us->iobuf[0] = 0x1; result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x01, 0x0, us->iobuf, 0x1, 5000); - US_DEBUGP("-- result is %d\n", result); + usb_stor_dbg(us, "-- result is %d\n", result); return 0; } @@ -68,7 +68,7 @@ int usb_stor_ucr61s2b_init(struct us_data *us) unsigned int partial; static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS"; - US_DEBUGP("Sending UCR-61S2B initialization packet...\n"); + usb_stor_dbg(us, "Sending UCR-61S2B initialization packet...\n"); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->Tag = 0; @@ -83,7 +83,7 @@ int usb_stor_ucr61s2b_init(struct us_data *us) if (res) return -EIO; - US_DEBUGP("Getting status packet...\n"); + usb_stor_dbg(us, "Getting status packet...\n"); res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &partial); if (res) @@ -101,6 +101,6 @@ int usb_stor_huawei_e220_init(struct us_data *us) USB_REQ_SET_FEATURE, USB_TYPE_STANDARD | USB_RECIP_DEVICE, 0x01, 0x0, NULL, 0x0, 1000); - US_DEBUGP("Huawei mode set result is %d\n", result); + usb_stor_dbg(us, "Huawei mode set result is %d\n", result); return 0; } diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index ecea47877364..599d8bff26c3 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -503,7 +503,7 @@ static int isd200_action( struct us_data *us, int action, switch ( action ) { case ACTION_READ_STATUS: - US_DEBUGP(" isd200_action(READ_STATUS)\n"); + usb_stor_dbg(us, " isd200_action(READ_STATUS)\n"); ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | @@ -512,7 +512,7 @@ static int isd200_action( struct us_data *us, int action, break; case ACTION_ENUM: - US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value); + usb_stor_dbg(us, " isd200_action(ENUM,0x%02x)\n", value); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4| ACTION_SELECT_5; @@ -522,7 +522,7 @@ static int isd200_action( struct us_data *us, int action, break; case ACTION_RESET: - US_DEBUGP(" isd200_action(RESET)\n"); + usb_stor_dbg(us, " isd200_action(RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; @@ -531,7 +531,7 @@ static int isd200_action( struct us_data *us, int action, break; case ACTION_REENABLE: - US_DEBUGP(" isd200_action(REENABLE)\n"); + usb_stor_dbg(us, " isd200_action(REENABLE)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; @@ -540,7 +540,7 @@ static int isd200_action( struct us_data *us, int action, break; case ACTION_SOFT_RESET: - US_DEBUGP(" isd200_action(SOFT_RESET)\n"); + usb_stor_dbg(us, " isd200_action(SOFT_RESET)\n"); ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; @@ -549,7 +549,7 @@ static int isd200_action( struct us_data *us, int action, break; case ACTION_IDENTIFY: - US_DEBUGP(" isd200_action(IDENTIFY)\n"); + usb_stor_dbg(us, " isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = ATA_CMD_ID_ATA; isd200_set_srb(info, DMA_FROM_DEVICE, info->id, @@ -557,7 +557,7 @@ static int isd200_action( struct us_data *us, int action, break; default: - US_DEBUGP("Error: Undefined action %d\n",action); + usb_stor_dbg(us, "Error: Undefined action %d\n", action); return ISD200_ERROR; } @@ -567,7 +567,8 @@ static int isd200_action( struct us_data *us, int action, if (status == USB_STOR_TRANSPORT_GOOD) status = ISD200_GOOD; else { - US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status); + usb_stor_dbg(us, " isd200_action(0x%02x) error: %d\n", + action, status); status = ISD200_ERROR; /* need to reset device here */ } @@ -589,17 +590,17 @@ static int isd200_read_regs( struct us_data *us ) int retStatus = ISD200_GOOD; int transferStatus; - US_DEBUGP("Entering isd200_IssueATAReadRegs\n"); + usb_stor_dbg(us, "Entering isd200_IssueATAReadRegs\n"); transferStatus = isd200_action( us, ACTION_READ_STATUS, info->RegsBuf, sizeof(info->ATARegs) ); if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error reading ATA registers\n"); + usb_stor_dbg(us, " Error reading ATA registers\n"); retStatus = ISD200_ERROR; } else { memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); - US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", - info->ATARegs[ATA_REG_ERROR_OFFSET]); + usb_stor_dbg(us, " Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", + info->ATARegs[ATA_REG_ERROR_OFFSET]); } return retStatus; @@ -629,7 +630,7 @@ static void isd200_invoke_transport( struct us_data *us, * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- command was aborted\n"); + usb_stor_dbg(us, "-- command was aborted\n"); goto Handle_Abort; } @@ -641,23 +642,23 @@ static void isd200_invoke_transport( struct us_data *us, break; case USB_STOR_TRANSPORT_NO_SENSE: - US_DEBUGP("-- transport indicates protocol failure\n"); + usb_stor_dbg(us, "-- transport indicates protocol failure\n"); srb->result = SAM_STAT_CHECK_CONDITION; return; case USB_STOR_TRANSPORT_FAILED: - US_DEBUGP("-- transport indicates command failure\n"); + usb_stor_dbg(us, "-- transport indicates command failure\n"); need_auto_sense = 1; break; case USB_STOR_TRANSPORT_ERROR: - US_DEBUGP("-- transport indicates transport error\n"); + usb_stor_dbg(us, "-- transport indicates transport error\n"); srb->result = DID_ERROR << 16; /* Need reset here */ return; default: - US_DEBUGP("-- transport indicates unknown error\n"); + usb_stor_dbg(us, "-- transport indicates unknown error\n"); srb->result = DID_ERROR << 16; /* Need reset here */ return; @@ -669,14 +670,14 @@ static void isd200_invoke_transport( struct us_data *us, (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); + usb_stor_dbg(us, "-- unexpectedly short transfer\n"); need_auto_sense = 1; } if (need_auto_sense) { result = isd200_read_regs(us); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- auto-sense aborted\n"); + usb_stor_dbg(us, "-- auto-sense aborted\n"); goto Handle_Abort; } if (result == ISD200_GOOD) { @@ -710,40 +711,40 @@ static void isd200_invoke_transport( struct us_data *us, } #ifdef CONFIG_USB_STORAGE_DEBUG -static void isd200_log_config( struct isd200_info* info ) +static void isd200_log_config(struct us_data *us, struct isd200_info *info) { - US_DEBUGP(" Event Notification: 0x%x\n", - info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", - info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", - info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", - (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_MASTER); - US_DEBUGP(" ATAPI Reset: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); - US_DEBUGP(" ATA Timing: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_TIMING); - US_DEBUGP(" ATA Major Command: 0x%x\n", - info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", - info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); - US_DEBUGP(" Descriptor Override: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); - US_DEBUGP(" SRST Enable: 0x%x\n", - info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); + usb_stor_dbg(us, " Event Notification: 0x%x\n", + info->ConfigData.EventNotification); + usb_stor_dbg(us, " External Clock: 0x%x\n", + info->ConfigData.ExternalClock); + usb_stor_dbg(us, " ATA Init Timeout: 0x%x\n", + info->ConfigData.ATAInitTimeout); + usb_stor_dbg(us, " ATAPI Command Block Size: 0x%x\n", + (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); + usb_stor_dbg(us, " Master/Slave Selection: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_MASTER); + usb_stor_dbg(us, " ATAPI Reset: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); + usb_stor_dbg(us, " ATA Timing: 0x%x\n", + info->ConfigData.ATAConfig & ATACFG_TIMING); + usb_stor_dbg(us, " ATA Major Command: 0x%x\n", + info->ConfigData.ATAMajorCommand); + usb_stor_dbg(us, " ATA Minor Command: 0x%x\n", + info->ConfigData.ATAMinorCommand); + usb_stor_dbg(us, " Init Status: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); + usb_stor_dbg(us, " Config Descriptor 2: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); + usb_stor_dbg(us, " Skip Device Boot: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); + usb_stor_dbg(us, " ATA 3 State Supsend: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); + usb_stor_dbg(us, " Descriptor Override: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); + usb_stor_dbg(us, " Last LUN Identifier: 0x%x\n", + info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); + usb_stor_dbg(us, " SRST Enable: 0x%x\n", + info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); } #endif @@ -762,9 +763,9 @@ static int isd200_write_config( struct us_data *us ) int result; #ifdef CONFIG_USB_STORAGE_DEBUG - US_DEBUGP("Entering isd200_write_config\n"); - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - isd200_log_config(info); + usb_stor_dbg(us, "Entering isd200_write_config\n"); + usb_stor_dbg(us, " Writing the following ISD200 Config Data:\n"); + isd200_log_config(us, info); #endif /* let's send the command via the control pipe */ @@ -779,13 +780,13 @@ static int isd200_write_config( struct us_data *us ) sizeof(info->ConfigData)); if (result >= 0) { - US_DEBUGP(" ISD200 Config Data was written successfully\n"); + usb_stor_dbg(us, " ISD200 Config Data was written successfully\n"); } else { - US_DEBUGP(" Request to write ISD200 Config Data failed!\n"); + usb_stor_dbg(us, " Request to write ISD200 Config Data failed!\n"); retStatus = ISD200_ERROR; } - US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_write_config %08X\n", retStatus); return retStatus; } @@ -804,7 +805,7 @@ static int isd200_read_config( struct us_data *us ) int retStatus = ISD200_GOOD; int result; - US_DEBUGP("Entering isd200_read_config\n"); + usb_stor_dbg(us, "Entering isd200_read_config\n"); /* read the configuration information from ISD200. Use this to */ /* determine what the special ATA CDB bytes are. */ @@ -821,16 +822,16 @@ static int isd200_read_config( struct us_data *us ) if (result >= 0) { - US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); + usb_stor_dbg(us, " Retrieved the following ISD200 Config Data:\n"); #ifdef CONFIG_USB_STORAGE_DEBUG - isd200_log_config(info); + isd200_log_config(us, info); #endif } else { - US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); + usb_stor_dbg(us, " Request to get ISD200 Config Data failed!\n"); retStatus = ISD200_ERROR; } - US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_read_config %08X\n", retStatus); return retStatus; } @@ -848,15 +849,15 @@ static int isd200_atapi_soft_reset( struct us_data *us ) int retStatus = ISD200_GOOD; int transferStatus; - US_DEBUGP("Entering isd200_atapi_soft_reset\n"); + usb_stor_dbg(us, "Entering isd200_atapi_soft_reset\n"); transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 ); if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing Atapi Soft Reset\n"); + usb_stor_dbg(us, " Error issuing Atapi Soft Reset\n"); retStatus = ISD200_ERROR; } - US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_atapi_soft_reset %08X\n", retStatus); return retStatus; } @@ -874,13 +875,13 @@ static int isd200_srst( struct us_data *us ) int retStatus = ISD200_GOOD; int transferStatus; - US_DEBUGP("Entering isd200_SRST\n"); + usb_stor_dbg(us, "Entering isd200_SRST\n"); transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 ); /* check to see if this request failed */ if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing SRST\n"); + usb_stor_dbg(us, " Error issuing SRST\n"); retStatus = ISD200_ERROR; } else { /* delay 10ms to give the drive a chance to see it */ @@ -888,7 +889,7 @@ static int isd200_srst( struct us_data *us ) transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 ); if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error taking drive out of reset\n"); + usb_stor_dbg(us, " Error taking drive out of reset\n"); retStatus = ISD200_ERROR; } else { /* delay 50ms to give the drive a chance to recover after SRST */ @@ -896,7 +897,7 @@ static int isd200_srst( struct us_data *us ) } } - US_DEBUGP("Leaving isd200_srst %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_srst %08X\n", retStatus); return retStatus; } @@ -926,10 +927,6 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* loop until we detect !BSY or timeout */ while(1) { -#ifdef CONFIG_USB_STORAGE_DEBUG - char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? - "Master" : "Slave"; -#endif status = isd200_action( us, ACTION_ENUM, NULL, master_slave ); if ( status != ISD200_GOOD ) @@ -942,9 +939,13 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, if (!detect) { if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) { - US_DEBUGP(" %s status is still BSY, try again...\n",mstr); + usb_stor_dbg(us, " %s status is still BSY, try again...\n", + master_slave == ATA_ADDRESS_DEVHEAD_STD ? + "Master" : "Slave"); } else { - US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); + usb_stor_dbg(us, " %s status !BSY, continue with next operation\n", + master_slave == ATA_ADDRESS_DEVHEAD_STD ? + "Master" : "Slave"); break; } } @@ -953,11 +954,11 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, /* ATA_ERR (workaround for Archos CD-ROM) */ else if (regs[ATA_REG_STATUS_OFFSET] & (ATA_BUSY | ATA_DF | ATA_ERR)) { - US_DEBUGP(" Status indicates it is not ready, try again...\n"); + usb_stor_dbg(us, " Status indicates it is not ready, try again...\n"); } /* check for DRDY, ATA devices set DRDY after SRST */ else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) { - US_DEBUGP(" Identified ATA device\n"); + usb_stor_dbg(us, " Identified ATA device\n"); info->DeviceFlags |= DF_ATA_DEVICE; info->DeviceHead = master_slave; break; @@ -978,27 +979,27 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, */ if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && !recheckAsMaster) { - US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); + usb_stor_dbg(us, " Identified ATAPI device as slave. Rechecking again as master\n"); recheckAsMaster = 1; master_slave = ATA_ADDRESS_DEVHEAD_STD; } else { - US_DEBUGP(" Identified ATAPI device\n"); + usb_stor_dbg(us, " Identified ATAPI device\n"); info->DeviceHead = master_slave; status = isd200_atapi_soft_reset(us); break; } } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); + usb_stor_dbg(us, " Not ATA, not ATAPI - Weird\n"); break; } /* check for timeout on this request */ if (time_after_eq(jiffies, endTime)) { if (!detect) - US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); + usb_stor_dbg(us, " BSY check timeout, just continue with next operation...\n"); else - US_DEBUGP(" Device detect timeout!\n"); + usb_stor_dbg(us, " Device detect timeout!\n"); break; } } @@ -1020,7 +1021,7 @@ static int isd200_manual_enum(struct us_data *us) struct isd200_info *info = (struct isd200_info *)us->extra; int retStatus = ISD200_GOOD; - US_DEBUGP("Entering isd200_manual_enum\n"); + usb_stor_dbg(us, "Entering isd200_manual_enum\n"); retStatus = isd200_read_config(us); if (retStatus == ISD200_GOOD) { @@ -1039,14 +1040,15 @@ static int isd200_manual_enum(struct us_data *us) isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { - US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); + usb_stor_dbg(us, " Setting Master/Slave selection to %d\n", + isslave); info->ConfigData.ATAConfig &= 0x3f; info->ConfigData.ATAConfig |= (isslave<<6); retStatus = isd200_write_config(us); } } - US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_manual_enum %08X\n", retStatus); return(retStatus); } @@ -1064,35 +1066,35 @@ static void isd200_fix_driveid(u16 *id) #endif } -static void isd200_dump_driveid(u16 *id) +static void isd200_dump_driveid(struct us_data *us, u16 *id) { - US_DEBUGP(" Identify Data Structure:\n"); - US_DEBUGP(" config = 0x%x\n", id[ATA_ID_CONFIG]); - US_DEBUGP(" cyls = 0x%x\n", id[ATA_ID_CYLS]); - US_DEBUGP(" heads = 0x%x\n", id[ATA_ID_HEADS]); - US_DEBUGP(" track_bytes = 0x%x\n", id[4]); - US_DEBUGP(" sector_bytes = 0x%x\n", id[5]); - US_DEBUGP(" sectors = 0x%x\n", id[ATA_ID_SECTORS]); - US_DEBUGP(" serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); - US_DEBUGP(" buf_type = 0x%x\n", id[20]); - US_DEBUGP(" buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); - US_DEBUGP(" ecc_bytes = 0x%x\n", id[22]); - US_DEBUGP(" fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); - US_DEBUGP(" model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); - US_DEBUGP(" max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); - US_DEBUGP(" dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); - US_DEBUGP(" capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); - US_DEBUGP(" tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); - US_DEBUGP(" tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); - US_DEBUGP(" field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); - US_DEBUGP(" cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); - US_DEBUGP(" cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); - US_DEBUGP(" cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); - US_DEBUGP(" cur_capacity = 0x%x\n", ata_id_u32(id, 57)); - US_DEBUGP(" multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); - US_DEBUGP(" lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); - US_DEBUGP(" command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); - US_DEBUGP(" command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); + usb_stor_dbg(us, " Identify Data Structure:\n"); + usb_stor_dbg(us, " config = 0x%x\n", id[ATA_ID_CONFIG]); + usb_stor_dbg(us, " cyls = 0x%x\n", id[ATA_ID_CYLS]); + usb_stor_dbg(us, " heads = 0x%x\n", id[ATA_ID_HEADS]); + usb_stor_dbg(us, " track_bytes = 0x%x\n", id[4]); + usb_stor_dbg(us, " sector_bytes = 0x%x\n", id[5]); + usb_stor_dbg(us, " sectors = 0x%x\n", id[ATA_ID_SECTORS]); + usb_stor_dbg(us, " serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); + usb_stor_dbg(us, " buf_type = 0x%x\n", id[20]); + usb_stor_dbg(us, " buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); + usb_stor_dbg(us, " ecc_bytes = 0x%x\n", id[22]); + usb_stor_dbg(us, " fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); + usb_stor_dbg(us, " model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); + usb_stor_dbg(us, " max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); + usb_stor_dbg(us, " dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); + usb_stor_dbg(us, " capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); + usb_stor_dbg(us, " tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); + usb_stor_dbg(us, " tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); + usb_stor_dbg(us, " field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); + usb_stor_dbg(us, " cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); + usb_stor_dbg(us, " cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); + usb_stor_dbg(us, " cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); + usb_stor_dbg(us, " cur_capacity = 0x%x\n", ata_id_u32(id, 57)); + usb_stor_dbg(us, " multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); + usb_stor_dbg(us, " lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); + usb_stor_dbg(us, " command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); + usb_stor_dbg(us, " command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); } /************************************************************************** @@ -1109,7 +1111,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) int retStatus = ISD200_GOOD; u16 *id = info->id; - US_DEBUGP("Entering isd200_get_inquiry_data\n"); + usb_stor_dbg(us, "Entering isd200_get_inquiry_data\n"); /* set default to Master */ info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; @@ -1127,7 +1129,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) id, ATA_ID_WORDS * 2); if (transferStatus != ISD200_TRANSPORT_GOOD) { /* Error issuing ATA Command Identify */ - US_DEBUGP(" Error issuing ATA Command Identify\n"); + usb_stor_dbg(us, " Error issuing ATA Command Identify\n"); retStatus = ISD200_ERROR; } else { /* ATA Command Identify successful */ @@ -1136,7 +1138,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) __u16 *dest; isd200_fix_driveid(id); - isd200_dump_driveid(id); + isd200_dump_driveid(us, id); memset(&info->InquiryData, 0, sizeof(info->InquiryData)); @@ -1170,7 +1172,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) /* determine if it supports Media Status Notification */ if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { - US_DEBUGP(" Device supports Media Status Notification\n"); + usb_stor_dbg(us, " Device supports Media Status Notification\n"); /* Indicate that it is enabled, even though it is not * This allows the lock/unlock of the media to work @@ -1190,7 +1192,8 @@ static int isd200_get_inquiry_data( struct us_data *us ) us->protocol_name = "Transparent SCSI"; us->proto_handler = usb_stor_transparent_scsi_command; - US_DEBUGP("Protocol changed to: %s\n", us->protocol_name); + usb_stor_dbg(us, "Protocol changed to: %s\n", + us->protocol_name); /* Free driver structure */ us->extra_destructor(info); @@ -1200,7 +1203,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) } } - US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus); + usb_stor_dbg(us, "Leaving isd200_get_inquiry_data %08X\n", retStatus); return(retStatus); } @@ -1231,7 +1234,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, /* SCSI Command */ switch (srb->cmnd[0]) { case INQUIRY: - US_DEBUGP(" ATA OUT - INQUIRY\n"); + usb_stor_dbg(us, " ATA OUT - INQUIRY\n"); /* copy InquiryData */ usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, @@ -1241,7 +1244,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, break; case MODE_SENSE: - US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_MODE_SENSE\n"); /* Initialize the return buffer */ usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb); @@ -1255,14 +1258,14 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; isd200_srb_set_bufflen(srb, 0); } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); + usb_stor_dbg(us, " Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } break; case TEST_UNIT_READY: - US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_TEST_UNIT_READY\n"); if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) { @@ -1273,7 +1276,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; isd200_srb_set_bufflen(srb, 0); } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); + usb_stor_dbg(us, " Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } @@ -1284,7 +1287,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, unsigned long capacity; struct read_capacity_data readCapacityData; - US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_READ_CAPACITY\n"); if (ata_id_has_lba(id)) capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1; @@ -1303,7 +1306,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, break; case READ_10: - US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_READ\n"); lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; @@ -1335,7 +1338,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, break; case WRITE_10: - US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_WRITE\n"); lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; @@ -1367,10 +1370,11 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, break; case ALLOW_MEDIUM_REMOVAL: - US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); + usb_stor_dbg(us, " ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); + usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", + srb->cmnd[4]); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -1380,25 +1384,25 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; isd200_srb_set_bufflen(srb, 0); } else { - US_DEBUGP(" Not removeable media, just report okay\n"); + usb_stor_dbg(us, " Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } break; case START_STOP: - US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n"); - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); + usb_stor_dbg(us, " ATA OUT - SCSIOP_START_STOP_UNIT\n"); + usb_stor_dbg(us, " srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); if ((srb->cmnd[4] & 0x3) == 0x2) { - US_DEBUGP(" Media Eject\n"); + usb_stor_dbg(us, " Media Eject\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 0; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; } else if ((srb->cmnd[4] & 0x3) == 0x1) { - US_DEBUGP(" Get Media Status\n"); + usb_stor_dbg(us, " Get Media Status\n"); ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; ataCdb->generic.TransferBlockSize = 1; @@ -1406,14 +1410,15 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; isd200_srb_set_bufflen(srb, 0); } else { - US_DEBUGP(" Nothing to do, just report okay\n"); + usb_stor_dbg(us, " Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; sendToTransport = 0; } break; default: - US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); + usb_stor_dbg(us, "Unsupported SCSI command - 0x%X\n", + srb->cmnd[0]); srb->result = DID_ERROR << 16; sendToTransport = 0; break; @@ -1457,8 +1462,7 @@ static int isd200_init_info(struct us_data *us) retStatus = ISD200_ERROR; else { info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); - info->RegsBuf = (unsigned char *) - kmalloc(sizeof(info->ATARegs), GFP_KERNEL); + info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL); info->srb.sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { @@ -1471,8 +1475,7 @@ static int isd200_init_info(struct us_data *us) if (retStatus == ISD200_GOOD) { us->extra = info; us->extra_destructor = isd200_free_info_ptrs; - } else - US_DEBUGP("ERROR - kmalloc failure\n"); + } return retStatus; } @@ -1483,19 +1486,19 @@ static int isd200_init_info(struct us_data *us) static int isd200_Initialization(struct us_data *us) { - US_DEBUGP("ISD200 Initialization...\n"); + usb_stor_dbg(us, "ISD200 Initialization...\n"); /* Initialize ISD200 info struct */ if (isd200_init_info(us) == ISD200_ERROR) { - US_DEBUGP("ERROR Initializing ISD200 Info struct\n"); + usb_stor_dbg(us, "ERROR Initializing ISD200 Info struct\n"); } else { /* Get device specific data */ if (isd200_get_inquiry_data(us) != ISD200_GOOD) - US_DEBUGP("ISD200 Initialization Failure\n"); + usb_stor_dbg(us, "ISD200 Initialization Failure\n"); else - US_DEBUGP("ISD200 Initialization complete\n"); + usb_stor_dbg(us, "ISD200 Initialization complete\n"); } return 0; @@ -1520,7 +1523,7 @@ static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) /* Make sure driver was initialized */ if (us->extra == NULL) - US_DEBUGP("ERROR Driver not initialized\n"); + usb_stor_dbg(us, "ERROR Driver not initialized\n"); scsi_set_resid(srb, 0); /* scsi_bufflen might change in protocol translation to ata */ diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c index ddc78780b1ad..563078be6547 100644 --- a/drivers/usb/storage/jumpshot.c +++ b/drivers/usb/storage/jumpshot.c @@ -118,7 +118,7 @@ static inline int jumpshot_bulk_read(struct us_data *us, if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL); } @@ -131,7 +131,7 @@ static inline int jumpshot_bulk_write(struct us_data *us, if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL); } @@ -152,8 +152,7 @@ static int jumpshot_get_status(struct us_data *us) return USB_STOR_TRANSPORT_ERROR; if (us->iobuf[0] != 0x50) { - US_DEBUGP("jumpshot_get_status: 0x%2x\n", - us->iobuf[0]); + usb_stor_dbg(us, "0x%2x\n", us->iobuf[0]); return USB_STOR_TRANSPORT_ERROR; } @@ -218,7 +217,7 @@ static int jumpshot_read_data(struct us_data *us, if (result != USB_STOR_XFER_GOOD) goto leave; - US_DEBUGP("jumpshot_read_data: %d bytes\n", len); + usb_stor_dbg(us, "%d bytes\n", len); // Store the data in the transfer buffer usb_stor_access_xfer_buf(buffer, len, us->srb, @@ -314,7 +313,7 @@ static int jumpshot_write_data(struct us_data *us, } while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10)); if (result != USB_STOR_TRANSPORT_GOOD) - US_DEBUGP("jumpshot_write_data: Gah! Waitcount = 10. Bad write!?\n"); + usb_stor_dbg(us, "Gah! Waitcount = 10. Bad write!?\n"); sector += thistime; totallen -= len; @@ -349,8 +348,7 @@ static int jumpshot_id_device(struct us_data *us, 0, 0x20, 0, 6, command, 2); if (rc != USB_STOR_XFER_GOOD) { - US_DEBUGP("jumpshot_id_device: Gah! " - "send_control for read_capacity failed\n"); + usb_stor_dbg(us, "Gah! send_control for read_capacity failed\n"); rc = USB_STOR_TRANSPORT_ERROR; goto leave; } @@ -400,17 +398,17 @@ static int jumpshot_handle_mode_sense(struct us_data *us, switch (pc) { case 0x0: - US_DEBUGP("jumpshot_handle_mode_sense: Current values\n"); - break; + usb_stor_dbg(us, "Current values\n"); + break; case 0x1: - US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n"); - break; + usb_stor_dbg(us, "Changeable values\n"); + break; case 0x2: - US_DEBUGP("jumpshot_handle_mode_sense: Default values\n"); - break; + usb_stor_dbg(us, "Default values\n"); + break; case 0x3: - US_DEBUGP("jumpshot_handle_mode_sense: Saves values\n"); - break; + usb_stor_dbg(us, "Saves values\n"); + break; } memset(ptr, 0, 8); @@ -494,17 +492,16 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) if (!us->extra) { us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n"); + if (!us->extra) return USB_STOR_TRANSPORT_ERROR; - } + us->extra_destructor = jumpshot_info_destructor; } info = (struct jumpshot_info *) (us->extra); if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n"); + usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); memcpy(ptr, inquiry_response, sizeof(inquiry_response)); fill_inquiry_response(us, ptr, 36); return USB_STOR_TRANSPORT_GOOD; @@ -521,8 +518,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("jumpshot_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); + usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", + info->sectors, info->ssize); // build the reply // @@ -534,7 +531,7 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("jumpshot_transport: Gah! MODE_SELECT_10.\n"); + usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -544,7 +541,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("jumpshot_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", + block, blocks); return jumpshot_read_data(us, info, block, blocks); } @@ -557,7 +555,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("jumpshot_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", + block, blocks); return jumpshot_read_data(us, info, block, blocks); } @@ -567,7 +566,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("jumpshot_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", + block, blocks); return jumpshot_write_data(us, info, block, blocks); } @@ -580,18 +580,19 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", + block, blocks); return jumpshot_write_data(us, info, block, blocks); } if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n"); + usb_stor_dbg(us, "TEST_UNIT_READY\n"); return jumpshot_get_status(us); } if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("jumpshot_transport: REQUEST_SENSE.\n"); + usb_stor_dbg(us, "REQUEST_SENSE\n"); memset(ptr, 0, 18); ptr[0] = 0xF0; @@ -605,12 +606,12 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) } if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); + usb_stor_dbg(us, "MODE_SENSE_6 detected\n"); return jumpshot_handle_mode_sense(us, srb, 1); } if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); + usb_stor_dbg(us, "MODE_SENSE_10 detected\n"); return jumpshot_handle_mode_sense(us, srb, 0); } @@ -624,7 +625,7 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) if (srb->cmnd[0] == START_STOP) { /* this is used by sd.c'check_scsidisk_media_change to detect media change */ - US_DEBUGP("jumpshot_transport: START_STOP.\n"); + usb_stor_dbg(us, "START_STOP\n"); /* the first jumpshot_id_device after a media change returns an error (determined experimentally) */ rc = jumpshot_id_device(us, info); @@ -638,8 +639,8 @@ static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) return rc; } - US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); + usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", + srb->cmnd[0], srb->cmnd[0]); info->sense_key = 0x05; info->sense_asc = 0x20; info->sense_ascq = 0x00; diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c index f085ffb606c8..94d16ee5e84b 100644 --- a/drivers/usb/storage/karma.c +++ b/drivers/usb/storage/karma.c @@ -106,7 +106,7 @@ static int rio_karma_send_command(char cmd, struct us_data *us) static unsigned char seq = 1; struct karma_data *data = (struct karma_data *) us->extra; - US_DEBUGP("karma: sending command %04x\n", cmd); + usb_stor_dbg(us, "sending command %04x\n", cmd); memset(us->iobuf, 0, RIO_SEND_LEN); memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN); us->iobuf[5] = cmd; @@ -139,10 +139,10 @@ static int rio_karma_send_command(char cmd, struct us_data *us) if (seq == 0) seq = 1; - US_DEBUGP("karma: sent command %04x\n", cmd); + usb_stor_dbg(us, "sent command %04x\n", cmd); return 0; err: - US_DEBUGP("karma: command %04x failed\n", cmd); + usb_stor_dbg(us, "command %04x failed\n", cmd); return USB_STOR_TRANSPORT_FAILED; } diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index cb79de61f4c8..26964895c88b 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -195,6 +195,7 @@ static int onetouch_connect_input(struct us_data *ss) pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); + maxp = min(maxp, ONETOUCH_PKT_LEN); onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); input_dev = input_allocate_device(); @@ -245,8 +246,7 @@ static int onetouch_connect_input(struct us_data *ss) input_dev->open = usb_onetouch_open; input_dev->close = usb_onetouch_close; - usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, - (maxp > 8 ? 8 : maxp), + usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp, usb_onetouch_irq, onetouch, endpoint->bInterval); onetouch->irq->transfer_dma = onetouch->data_dma; onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c index e0f76bb05915..b2b35b1d7de8 100644 --- a/drivers/usb/storage/option_ms.c +++ b/drivers/usb/storage/option_ms.c @@ -50,7 +50,7 @@ static int option_rezero(struct us_data *us) char *buffer; int result; - US_DEBUGP("Option MS: %s", "DEVICE MODE SWITCH\n"); + usb_stor_dbg(us, "Option MS: %s\n", "DEVICE MODE SWITCH"); buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL); if (buffer == NULL) @@ -95,7 +95,7 @@ static int option_inquiry(struct us_data *us) char *buffer; int result; - US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n"); + usb_stor_dbg(us, "Option MS: %s\n", "device inquiry for vendor name"); buffer = kzalloc(0x24, GFP_KERNEL); if (buffer == NULL) @@ -138,31 +138,32 @@ int option_ms_init(struct us_data *us) { int result; - US_DEBUGP("Option MS: option_ms_init called\n"); + usb_stor_dbg(us, "Option MS: %s\n", "option_ms_init called"); /* Additional test for vendor information via INQUIRY, * because some vendor/product IDs are ambiguous */ result = option_inquiry(us); if (result != 0) { - US_DEBUGP("Option MS: vendor is not Option or not determinable," - " no action taken\n"); + usb_stor_dbg(us, "Option MS: %s\n", + "vendor is not Option or not determinable, no action taken"); return 0; } else - US_DEBUGP("Option MS: this is a genuine Option device," - " proceeding\n"); + usb_stor_dbg(us, "Option MS: %s\n", + "this is a genuine Option device, proceeding"); /* Force Modem mode */ if (option_zero_cd == ZCD_FORCE_MODEM) { - US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); + usb_stor_dbg(us, "Option MS: %s\n", "Forcing Modem Mode"); result = option_rezero(us); if (result != USB_STOR_XFER_GOOD) - US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); + usb_stor_dbg(us, "Option MS: %s\n", + "Failed to switch to modem mode"); return -EIO; } else if (option_zero_cd == ZCD_ALLOW_MS) { /* Allow Mass Storage mode (keep CD-Rom) */ - US_DEBUGP("Option MS: %s", "Allowing Mass Storage Mode if device" - " requests it\n"); + usb_stor_dbg(us, "Option MS: %s\n", + "Allowing Mass Storage Mode if device requests it"); } return 0; diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 6c3586a4c956..4797228747fb 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -254,8 +254,8 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, /* check bulk status */ if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN)) { - US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n", - le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN); + usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n", + le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN); return USB_STOR_TRANSPORT_ERROR; } @@ -351,8 +351,8 @@ static int rts51x_get_max_lun(struct us_data *us) USB_RECIP_INTERFACE, 0, us->ifnum, us->iobuf, 1, 10 * HZ); - US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, us->iobuf[0]); + usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n", + result, us->iobuf[0]); /* if we have a successful request, return the result */ if (result > 0) @@ -371,7 +371,7 @@ static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len) if (buf == NULL) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len); + usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len); cmnd[0] = 0xF0; cmnd[1] = 0x0D; @@ -402,7 +402,7 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len) if (buf == NULL) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len); + usb_stor_dbg(us, "addr = 0x%x, len = %d\n", addr, len); cmnd[0] = 0xF0; cmnd[1] = 0x0E; @@ -431,7 +431,7 @@ static int rts51x_read_status(struct us_data *us, if (buf == NULL) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("%s, lun = %d\n", __func__, lun); + usb_stor_dbg(us, "lun = %d\n", lun); cmnd[0] = 0xF0; cmnd[1] = 0x09; @@ -458,7 +458,7 @@ static int rts51x_check_status(struct us_data *us, u8 lun) if (retval != STATUS_SUCCESS) return -EIO; - US_DEBUGP("chip->status_len = %d\n", chip->status_len); + usb_stor_dbg(us, "chip->status_len = %d\n", chip->status_len); chip->status[lun].vid = ((u16) buf[0] << 8) | buf[1]; chip->status[lun].pid = ((u16) buf[2] << 8) | buf[3]; @@ -509,7 +509,7 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len) u8 cmnd[12] = {0}; u8 *buf; - US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len); + usb_stor_dbg(us, "addr = 0xfe47, len = %d\n", len); buf = kmemdup(data, len, GFP_NOIO); if (!buf) @@ -549,7 +549,7 @@ static int do_config_autodelink(struct us_data *us, int enable, int force) value &= ~0x03; } - US_DEBUGP("In %s,set 0xfe47 to 0x%x\n", __func__, value); + usb_stor_dbg(us, "set 0xfe47 to 0x%x\n", value); /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */ retval = __do_config_autodelink(us, &value, 1); @@ -565,8 +565,6 @@ static int config_autodelink_after_power_on(struct us_data *us) int retval; u8 value; - US_DEBUGP("%s: <---\n", __func__); - if (!CHK_AUTO_DELINK(chip)) return 0; @@ -624,8 +622,6 @@ static int config_autodelink_after_power_on(struct us_data *us) } } - US_DEBUGP("%s: --->\n", __func__); - return 0; } @@ -635,8 +631,6 @@ static int config_autodelink_before_power_down(struct us_data *us) int retval; u8 value; - US_DEBUGP("%s: <---\n", __func__); - if (!CHK_AUTO_DELINK(chip)) return 0; @@ -698,8 +692,6 @@ static int config_autodelink_before_power_down(struct us_data *us) } } - US_DEBUGP("%s: --->\n", __func__); - return 0; } @@ -709,23 +701,19 @@ static void fw5895_init(struct us_data *us) int retval; u8 val; - US_DEBUGP("%s: <---\n", __func__); - if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) { - US_DEBUGP("Not the specified device, return immediately!\n"); + usb_stor_dbg(us, "Not the specified device, return immediately!\n"); } else { retval = rts51x_read_mem(us, 0xFD6F, &val, 1); if (retval == STATUS_SUCCESS && (val & 0x1F) == 0) { val = 0x1F; retval = rts51x_write_mem(us, 0xFD70, &val, 1); if (retval != STATUS_SUCCESS) - US_DEBUGP("Write memory fail\n"); + usb_stor_dbg(us, "Write memory fail\n"); } else { - US_DEBUGP("Read memory fail, OR (val & 0x1F) != 0\n"); + usb_stor_dbg(us, "Read memory fail, OR (val & 0x1F) != 0\n"); } } - - US_DEBUGP("%s: --->\n", __func__); } #ifdef CONFIG_REALTEK_AUTOPM @@ -735,10 +723,8 @@ static void fw5895_set_mmc_wp(struct us_data *us) int retval; u8 buf[13]; - US_DEBUGP("%s: <---\n", __func__); - if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) { - US_DEBUGP("Not the specified device, return immediately!\n"); + usb_stor_dbg(us, "Not the specified device, return immediately!\n"); } else { retval = rts51x_read_mem(us, 0xFD6F, buf, 1); if (retval == STATUS_SUCCESS && (buf[0] & 0x24) == 0x24) { @@ -748,26 +734,24 @@ static void fw5895_set_mmc_wp(struct us_data *us) buf[0] |= 0x04; retval = rts51x_write_mem(us, 0xFD70, buf, 1); if (retval != STATUS_SUCCESS) - US_DEBUGP("Write memory fail\n"); + usb_stor_dbg(us, "Write memory fail\n"); } else { - US_DEBUGP("Read memory fail\n"); + usb_stor_dbg(us, "Read memory fail\n"); } } else { - US_DEBUGP("Read memory fail, OR (buf[0]&0x24)!=0x24\n"); + usb_stor_dbg(us, "Read memory fail, OR (buf[0]&0x24)!=0x24\n"); } } - - US_DEBUGP("%s: --->\n", __func__); } static void rts51x_modi_suspend_timer(struct rts51x_chip *chip) { - US_DEBUGP("%s: <---, state:%d\n", __func__, rts51x_get_stat(chip)); + struct us_data *us = chip->us; + + usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip)); chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay); mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires); - - US_DEBUGP("%s: --->\n", __func__); } static void rts51x_suspend_timer_fn(unsigned long data) @@ -775,8 +759,6 @@ static void rts51x_suspend_timer_fn(unsigned long data) struct rts51x_chip *chip = (struct rts51x_chip *)data; struct us_data *us = chip->us; - US_DEBUGP("%s: <---\n", __func__); - switch (rts51x_get_stat(chip)) { case RTS51X_STAT_INIT: case RTS51X_STAT_RUN: @@ -784,32 +766,25 @@ static void rts51x_suspend_timer_fn(unsigned long data) break; case RTS51X_STAT_IDLE: case RTS51X_STAT_SS: - US_DEBUGP("%s: RTS51X_STAT_SS, intf->pm_usage_cnt:%d," - "power.usage:%d\n", __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read(&us->pusb_intf->dev.power.usage_count)); + usb_stor_dbg(us, "RTS51X_STAT_SS, intf->pm_usage_cnt:%d, power.usage:%d\n", + atomic_read(&us->pusb_intf->pm_usage_cnt), + atomic_read(&us->pusb_intf->dev.power.usage_count)); if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) { - US_DEBUGP("%s: Ready to enter SS state.\n", - __func__); + usb_stor_dbg(us, "Ready to enter SS state\n"); rts51x_set_stat(chip, RTS51X_STAT_SS); /* ignore mass storage interface's children */ pm_suspend_ignore_children(&us->pusb_intf->dev, true); usb_autopm_put_interface_async(us->pusb_intf); - US_DEBUGP("%s: RTS51X_STAT_SS 01," - "intf->pm_usage_cnt:%d, power.usage:%d\n", - __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read( - &us->pusb_intf->dev.power.usage_count)); + usb_stor_dbg(us, "RTS51X_STAT_SS 01, intf->pm_usage_cnt:%d, power.usage:%d\n", + atomic_read(&us->pusb_intf->pm_usage_cnt), + atomic_read(&us->pusb_intf->dev.power.usage_count)); } break; default: - US_DEBUGP("%s: Unknonwn state !!!\n", __func__); + usb_stor_dbg(us, "Unknown state !!!\n"); break; } - - US_DEBUGP("%s: --->\n", __func__); } static inline int working_scsi(struct scsi_cmnd *srb) @@ -834,24 +809,21 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) }; int ret; - US_DEBUGP("%s: <---\n", __func__); - if (working_scsi(srb)) { - US_DEBUGP("%s: working scsi, intf->pm_usage_cnt:%d," - "power.usage:%d\n", __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read(&us->pusb_intf->dev.power.usage_count)); + usb_stor_dbg(us, "working scsi, intf->pm_usage_cnt:%d, power.usage:%d\n", + atomic_read(&us->pusb_intf->pm_usage_cnt), + atomic_read(&us->pusb_intf->dev.power.usage_count)); if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) { ret = usb_autopm_get_interface(us->pusb_intf); - US_DEBUGP("%s: working scsi, ret=%d\n", __func__, ret); + usb_stor_dbg(us, "working scsi, ret=%d\n", ret); } if (rts51x_get_stat(chip) != RTS51X_STAT_RUN) rts51x_set_stat(chip, RTS51X_STAT_RUN); chip->proto_handler_backup(srb, us); } else { if (rts51x_get_stat(chip) == RTS51X_STAT_SS) { - US_DEBUGP("%s: NOT working scsi\n", __func__); + usb_stor_dbg(us, "NOT working scsi\n"); if ((srb->cmnd[0] == TEST_UNIT_READY) && (chip->pwr_state == US_SUSPEND)) { if (TST_LUN_READY(chip, srb->device->lun)) { @@ -862,8 +834,7 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) media_not_present, US_SENSE_SIZE); } - US_DEBUGP("%s: TEST_UNIT_READY--->\n", - __func__); + usb_stor_dbg(us, "TEST_UNIT_READY\n"); goto out; } if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { @@ -876,12 +847,11 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) } else { srb->result = SAM_STAT_GOOD; } - US_DEBUGP("%s: ALLOW_MEDIUM_REMOVAL--->\n", - __func__); + usb_stor_dbg(us, "ALLOW_MEDIUM_REMOVAL\n"); goto out; } } else { - US_DEBUGP("%s: NOT working scsi, not SS\n", __func__); + usb_stor_dbg(us, "NOT working scsi, not SS\n"); chip->proto_handler_backup(srb, us); /* Check whether card is plugged in */ if (srb->cmnd[0] == TEST_UNIT_READY) { @@ -901,11 +871,9 @@ static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) } } out: - US_DEBUGP("%s: state:%d\n", __func__, rts51x_get_stat(chip)); + usb_stor_dbg(us, "state:%d\n", rts51x_get_stat(chip)); if (rts51x_get_stat(chip) == RTS51X_STAT_RUN) rts51x_modi_suspend_timer(chip); - - US_DEBUGP("%s: --->\n", __func__); } static int realtek_cr_autosuspend_setup(struct us_data *us) @@ -923,7 +891,7 @@ static int realtek_cr_autosuspend_setup(struct us_data *us) retval = rts51x_read_status(us, 0, buf, 16, &(chip->status_len)); if (retval != STATUS_SUCCESS) { - US_DEBUGP("Read status fail\n"); + usb_stor_dbg(us, "Read status fail\n"); return -EIO; } status = chip->status; @@ -966,11 +934,13 @@ static int realtek_cr_autosuspend_setup(struct us_data *us) static void realtek_cr_destructor(void *extra) { struct rts51x_chip *chip = (struct rts51x_chip *)extra; - - US_DEBUGP("%s: <---\n", __func__); + struct us_data *us; if (!chip) return; + + us = chip->us; + #ifdef CONFIG_REALTEK_AUTOPM if (ss_en) { del_timer(&chip->rts51x_suspend_timer); @@ -985,8 +955,6 @@ static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s: <---\n", __func__); - /* wait until no command is running */ mutex_lock(&us->dev_mutex); @@ -994,8 +962,6 @@ static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) mutex_unlock(&us->dev_mutex); - US_DEBUGP("%s: --->\n", __func__); - return 0; } @@ -1003,13 +969,9 @@ static int realtek_cr_resume(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s: <---\n", __func__); - fw5895_init(us); config_autodelink_after_power_on(us); - US_DEBUGP("%s: --->\n", __func__); - return 0; } #else @@ -1030,7 +992,7 @@ static int init_realtek_cr(struct us_data *us) us->extra_destructor = realtek_cr_destructor; us->max_lun = chip->max_lun = rts51x_get_max_lun(us); - US_DEBUGP("chip->max_lun = %d\n", chip->max_lun); + usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun); size = (chip->max_lun + 1) * sizeof(struct rts51x_status); chip->status = kzalloc(size, GFP_KERNEL); @@ -1057,7 +1019,7 @@ static int init_realtek_cr(struct us_data *us) } #endif - US_DEBUGP("chip->flag = 0x%x\n", chip->flag); + usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag); (void)config_autodelink_after_power_on(us); @@ -1079,7 +1041,7 @@ static int realtek_cr_probe(struct usb_interface *intf, struct us_data *us; int result; - US_DEBUGP("Probe Realtek Card Reader!\n"); + dev_dbg(&intf->dev, "Probe Realtek Card Reader!\n"); result = usb_stor_probe1(&us, intf, id, (id - realtek_cr_ids) + diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 92f35abee92d..4faa982807f2 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -313,8 +313,6 @@ static int queuecommand_lck(struct scsi_cmnd *srb, { struct us_data *us = host_to_us(srb->device->host); - US_DEBUGP("%s called\n", __func__); - /* check for state-transition errors */ if (us->srb != NULL) { printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n", @@ -324,7 +322,7 @@ static int queuecommand_lck(struct scsi_cmnd *srb, /* fail the command if we are disconnecting */ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("Fail command during disconnect\n"); + usb_stor_dbg(us, "Fail command during disconnect\n"); srb->result = DID_NO_CONNECT << 16; done(srb); return 0; @@ -349,7 +347,7 @@ static int command_abort(struct scsi_cmnd *srb) { struct us_data *us = host_to_us(srb->device->host); - US_DEBUGP("%s called\n", __func__); + usb_stor_dbg(us, "%s called\n", __func__); /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING * bits are protected by the host lock. */ @@ -358,7 +356,7 @@ static int command_abort(struct scsi_cmnd *srb) /* Is this command still active? */ if (us->srb != srb) { scsi_unlock(us_to_host(us)); - US_DEBUGP ("-- nothing to abort\n"); + usb_stor_dbg(us, "-- nothing to abort\n"); return FAILED; } @@ -386,7 +384,7 @@ static int device_reset(struct scsi_cmnd *srb) struct us_data *us = host_to_us(srb->device->host); int result; - US_DEBUGP("%s called\n", __func__); + usb_stor_dbg(us, "%s called\n", __func__); /* lock the device pointers and do the reset */ mutex_lock(&(us->dev_mutex)); @@ -402,7 +400,8 @@ static int bus_reset(struct scsi_cmnd *srb) struct us_data *us = host_to_us(srb->device->host); int result; - US_DEBUGP("%s called\n", __func__); + usb_stor_dbg(us, "%s called\n", __func__); + result = usb_stor_port_reset(us); return result < 0 ? FAILED : SUCCESS; } diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 7bd54e0d5120..732027f33200 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -105,8 +105,6 @@ static struct us_unusual_dev sddr09_unusual_dev_list[] = { #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) -/* #define US_DEBUGP printk */ - /* * First some stuff that does not belong here: * data on SmartMedia and other cards, completely @@ -347,7 +345,7 @@ sddr09_test_unit_ready(struct us_data *us) { result = sddr09_send_scsi_command(us, command, 6); - US_DEBUGP("sddr09_test_unit_ready returns %d\n", result); + usb_stor_dbg(us, "sddr09_test_unit_ready returns %d\n", result); return result; } @@ -423,8 +421,8 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, result = sddr09_send_scsi_command(us, command, 12); if (result) { - US_DEBUGP("Result for send_control in sddr09_read2%d %d\n", - x, result); + usb_stor_dbg(us, "Result for send_control in sddr09_read2%d %d\n", + x, result); return result; } @@ -432,8 +430,8 @@ sddr09_readX(struct us_data *us, int x, unsigned long fromaddress, buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", - x, result); + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read2%d %d\n", + x, result); return -EIO; } return 0; @@ -494,8 +492,7 @@ sddr09_read22(struct us_data *us, unsigned long fromaddress, int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); - US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n", - nr_of_pages, bulklen); + usb_stor_dbg(us, "reading %d pages, %d bytes\n", nr_of_pages, bulklen); return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen, buf, use_sg); } @@ -538,7 +535,7 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) { unsigned char *command = us->iobuf; int result; - US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress); + usb_stor_dbg(us, "erase address %lu\n", Eaddress); memset(command, 0, 12); command[0] = 0xEA; @@ -551,8 +548,8 @@ sddr09_erase(struct us_data *us, unsigned long Eaddress) { result = sddr09_send_scsi_command(us, command, 12); if (result) - US_DEBUGP("Result for send_control in sddr09_erase %d\n", - result); + usb_stor_dbg(us, "Result for send_control in sddr09_erase %d\n", + result); return result; } @@ -609,8 +606,8 @@ sddr09_writeX(struct us_data *us, result = sddr09_send_scsi_command(us, command, 12); if (result) { - US_DEBUGP("Result for send_control in sddr09_writeX %d\n", - result); + usb_stor_dbg(us, "Result for send_control in sddr09_writeX %d\n", + result); return result; } @@ -618,8 +615,8 @@ sddr09_writeX(struct us_data *us, buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", - result); + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_writeX %d\n", + result); return -EIO; } return 0; @@ -687,8 +684,8 @@ sddr09_read_sg_test_only(struct us_data *us) { result = sddr09_send_scsi_command(us, command, 4*nsg+3); if (result) { - US_DEBUGP("Result for send_control in sddr09_read_sg %d\n", - result); + usb_stor_dbg(us, "Result for send_control in sddr09_read_sg %d\n", + result); return result; } @@ -700,8 +697,8 @@ sddr09_read_sg_test_only(struct us_data *us) { buf, bulklen, NULL); kfree(buf); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", - result); + usb_stor_dbg(us, "Result for bulk_transfer in sddr09_read_sg %d\n", + result); return -EIO; } @@ -727,7 +724,7 @@ sddr09_read_status(struct us_data *us, unsigned char *status) { unsigned char *data = us->iobuf; int result; - US_DEBUGP("Reading status...\n"); + usb_stor_dbg(us, "Reading status...\n"); memset(command, 0, 12); command[0] = 0xEC; @@ -789,8 +786,8 @@ sddr09_read_data(struct us_data *us, /* Not overflowing capacity? */ if (lba >= maxlba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, maxlba); + usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", + lba, maxlba); result = -EIO; break; } @@ -800,8 +797,8 @@ sddr09_read_data(struct us_data *us, if (pba == UNDEF) { /* this lba was never written */ - US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", - pages, lba, page); + usb_stor_dbg(us, "Read %d zero pages (LBA %d) page %d\n", + pages, lba, page); /* This is not really an error. It just means that the block has never been written. @@ -811,9 +808,8 @@ sddr09_read_data(struct us_data *us, memset(buffer, 0, len); } else { - US_DEBUGP("Read %d pages, from PBA %d" - " (LBA %d) page %d\n", - pages, pba, lba, page); + usb_stor_dbg(us, "Read %d pages, from PBA %d (LBA %d) page %d\n", + pages, pba, lba, page); address = ((pba << info->blockshift) + page) << info->pageshift; @@ -916,14 +912,14 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, cptr = bptr + info->pagesize; nand_compute_ecc(bptr, ecc); if (!nand_compare_ecc(cptr+13, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d- of pba %d\n", + i, pba); nand_store_ecc(cptr+13, ecc); } nand_compute_ecc(bptr+(info->pagesize / 2), ecc); if (!nand_compare_ecc(cptr+8, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", - i, pba); + usb_stor_dbg(us, "Warning: bad ecc in page %d+ of pba %d\n", + i, pba); nand_store_ecc(cptr+8, ecc); } cptr[6] = cptr[11] = MSB_of(lbap); @@ -943,22 +939,21 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, nand_store_ecc(cptr+8, ecc); } - US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba); + usb_stor_dbg(us, "Rewrite PBA %d (LBA %d)\n", pba, lba); result = sddr09_write_inplace(us, address>>1, info->blocksize, info->pageshift, blockbuffer, 0); - US_DEBUGP("sddr09_write_inplace returns %d\n", result); + usb_stor_dbg(us, "sddr09_write_inplace returns %d\n", result); #if 0 { unsigned char status = 0; int result2 = sddr09_read_status(us, &status); if (result2) - US_DEBUGP("sddr09_write_inplace: cannot read status\n"); + usb_stor_dbg(us, "cannot read status\n"); else if (status != 0xc0) - US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n", - status); + usb_stor_dbg(us, "status after write: 0x%x\n", status); } #endif @@ -1031,8 +1026,8 @@ sddr09_write_data(struct us_data *us, /* Not overflowing capacity? */ if (lba >= maxlba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, maxlba); + usb_stor_dbg(us, "Error: Requested lba %u exceeds maximum %u\n", + lba, maxlba); result = -EIO; break; } @@ -1064,8 +1059,8 @@ sddr09_read_control(struct us_data *us, unsigned char *content, int use_sg) { - US_DEBUGP("Read control address %lu, blocks %d\n", - address, blocks); + usb_stor_dbg(us, "Read control address %lu, blocks %d\n", + address, blocks); return sddr09_read21(us, address, blocks, CONTROL_SHIFT, content, use_sg); @@ -1111,21 +1106,21 @@ sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { result = sddr09_read_status(us, &status); if (result) { - US_DEBUGP("sddr09_get_wp: read_status fails\n"); + usb_stor_dbg(us, "read_status fails\n"); return result; } - US_DEBUGP("sddr09_get_wp: status 0x%02X", status); + usb_stor_dbg(us, "status 0x%02X", status); if ((status & 0x80) == 0) { info->flags |= SDDR09_WP; /* write protected */ - US_DEBUGP(" WP"); + US_DEBUGPX(" WP"); } if (status & 0x40) - US_DEBUGP(" Ready"); + US_DEBUGPX(" Ready"); if (status & LUNBITS) - US_DEBUGP(" Suspended"); + US_DEBUGPX(" Suspended"); if (status & 0x1) - US_DEBUGP(" Error"); - US_DEBUGP("\n"); + US_DEBUGPX(" Error"); + US_DEBUGPX("\n"); return 0; } @@ -1154,12 +1149,12 @@ sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { char blurbtxt[256]; int result; - US_DEBUGP("Reading capacity...\n"); + usb_stor_dbg(us, "Reading capacity...\n"); result = sddr09_read_deviceID(us, deviceID); if (result) { - US_DEBUGP("Result of read_deviceID is %d\n", result); + usb_stor_dbg(us, "Result of read_deviceID is %d\n", result); printk(KERN_WARNING "sddr09: could not read card info\n"); return NULL; } @@ -1392,7 +1387,7 @@ sddr09_read_map(struct us_data *us) { lbact += ct; } info->lbact = lbact; - US_DEBUGP("Found %d LBA's\n", lbact); + usb_stor_dbg(us, "Found %d LBA's\n", lbact); result = 0; done: @@ -1423,18 +1418,18 @@ sddr09_common_init(struct us_data *us) { /* set the configuration -- STALL is an acceptable response here */ if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { - US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev - ->actconfig->desc.bConfigurationValue); + usb_stor_dbg(us, "active config #%d != 1 ??\n", + us->pusb_dev->actconfig->desc.bConfigurationValue); return -EINVAL; } result = usb_reset_configuration(us->pusb_dev); - US_DEBUGP("Result of usb_reset_configuration is %d\n", result); + usb_stor_dbg(us, "Result of usb_reset_configuration is %d\n", result); if (result == -EPIPE) { - US_DEBUGP("-- stall on control interface\n"); + usb_stor_dbg(us, "-- stall on control interface\n"); } else if (result != 0) { /* it's not a stall, but another error -- time to bail */ - US_DEBUGP("-- Unknown error. Rejecting device\n"); + usb_stor_dbg(us, "-- Unknown error. Rejecting device\n"); return -EINVAL; } @@ -1464,20 +1459,20 @@ usb_stor_sddr09_dpcm_init(struct us_data *us) { result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); if (result) { - US_DEBUGP("sddr09_init: send_command fails\n"); + usb_stor_dbg(us, "send_command fails\n"); return result; } - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); // get 07 02 result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); if (result) { - US_DEBUGP("sddr09_init: 2nd send_command fails\n"); + usb_stor_dbg(us, "2nd send_command fails\n"); return result; } - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); + usb_stor_dbg(us, "%02X %02X\n", data[0], data[1]); // get 07 00 result = sddr09_request_sense(us, data, 18); @@ -1507,7 +1502,7 @@ static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) { int ret; - US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun); + usb_stor_dbg(us, "LUN=%d\n", srb->device->lun); switch (srb->device->lun) { case 0: @@ -1533,8 +1528,7 @@ static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) break; default: - US_DEBUGP("dpcm_transport: Invalid LUN %d\n", - srb->device->lun); + usb_stor_dbg(us, "Invalid LUN %d\n", srb->device->lun); ret = USB_STOR_TRANSPORT_ERROR; break; } @@ -1640,8 +1634,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) or for all pages. */ /* %% We should check DBD %% */ if (modepage == 0x01 || modepage == 0x3F) { - US_DEBUGP("SDDR09: Dummy up request for " - "mode page 0x%x\n", modepage); + usb_stor_dbg(us, "Dummy up request for mode page 0x%x\n", + modepage); memcpy(ptr, mode_page_01, sizeof(mode_page_01)); ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); @@ -1667,8 +1661,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("READ_10: read page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "READ_10: read page %d pagect %d\n", + page, pages); result = sddr09_read_data(us, page, pages); return (result == 0 ? USB_STOR_TRANSPORT_GOOD : @@ -1682,8 +1676,8 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) page |= short_pack(srb->cmnd[5], srb->cmnd[4]); pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - US_DEBUGP("WRITE_10: write page %d pagect %d\n", - page, pages); + usb_stor_dbg(us, "WRITE_10: write page %d pagect %d\n", + page, pages); result = sddr09_write_data(us, page, pages); return (result == 0 ? USB_STOR_TRANSPORT_GOOD : @@ -1710,12 +1704,12 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) for (i=0; i<12; i++) sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]); - US_DEBUGP("SDDR09: Send control for command %s\n", ptr); + usb_stor_dbg(us, "Send control for command %s\n", ptr); result = sddr09_send_scsi_command(us, srb->cmnd, 12); if (result) { - US_DEBUGP("sddr09_transport: sddr09_send_scsi_command " - "returns %d\n", result); + usb_stor_dbg(us, "sddr09_send_scsi_command returns %d\n", + result); return USB_STOR_TRANSPORT_ERROR; } @@ -1727,10 +1721,10 @@ static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) ? us->send_bulk_pipe : us->recv_bulk_pipe; - US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == DMA_TO_DEVICE) ? - "sending" : "receiving", - scsi_bufflen(srb)); + usb_stor_dbg(us, "%s %d bytes\n", + (srb->sc_data_direction == DMA_TO_DEVICE) ? + "sending" : "receiving", + scsi_bufflen(srb)); result = usb_stor_bulk_srb(us, pipe, srb); diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c index d278c5a99b7a..aacedef9667c 100644 --- a/drivers/usb/storage/sddr55.c +++ b/drivers/usb/storage/sddr55.c @@ -145,8 +145,7 @@ static int sddr55_status(struct us_data *us) result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); - US_DEBUGP("Result for send_command in status %d\n", - result); + usb_stor_dbg(us, "Result for send_command in status %d\n", result); if (result != USB_STOR_XFER_GOOD) { set_sense_info (4, 0, 0); /* hardware error */ @@ -236,9 +235,8 @@ static int sddr55_read_data(struct us_data *us, info->blocksize - page); len = pages << info->pageshift; - US_DEBUGP("Read %02X pages, from PBA %04X" - " (LBA %04X) page %02X\n", - pages, pba, lba, page); + usb_stor_dbg(us, "Read %02X pages, from PBA %04X (LBA %04X) page %02X\n", + pages, pba, lba, page); if (pba == NOT_ALLOCATED) { /* no pba for this lba, fill with zeroes */ @@ -261,8 +259,8 @@ static int sddr55_read_data(struct us_data *us, result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); - US_DEBUGP("Result for send_command in read_data %d\n", - result); + usb_stor_dbg(us, "Result for send_command in read_data %d\n", + result); if (result != USB_STOR_XFER_GOOD) { result = USB_STOR_TRANSPORT_ERROR; @@ -368,9 +366,8 @@ static int sddr55_write_data(struct us_data *us, usb_stor_access_xfer_buf(buffer, len, us->srb, &sg, &offset, FROM_XFER_BUF); - US_DEBUGP("Write %02X pages, to PBA %04X" - " (LBA %04X) page %02X\n", - pages, pba, lba, page); + usb_stor_dbg(us, "Write %02X pages, to PBA %04X (LBA %04X) page %02X\n", + pages, pba, lba, page); command[4] = 0; @@ -384,7 +381,7 @@ static int sddr55_write_data(struct us_data *us, /* set pba to first block in zone lba is in */ pba = (lba / 1000) * 1024; - US_DEBUGP("No PBA for LBA %04X\n",lba); + usb_stor_dbg(us, "No PBA for LBA %04X\n", lba); if (max_pba > 1024) max_pba = 1024; @@ -407,14 +404,15 @@ static int sddr55_write_data(struct us_data *us, if (pba == -1) { /* oh dear */ - US_DEBUGP("Couldn't find unallocated block\n"); + usb_stor_dbg(us, "Couldn't find unallocated block\n"); set_sense_info (3, 0x31, 0); /* medium error */ result = USB_STOR_TRANSPORT_FAILED; goto leave; } - US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba); + usb_stor_dbg(us, "Allocating PBA %04X for LBA %04X\n", + pba, lba); /* set writing to unallocated block flag */ command[4] = 0x40; @@ -439,8 +437,8 @@ static int sddr55_write_data(struct us_data *us, DMA_TO_DEVICE, command, 8); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for send_command in write_data %d\n", - result); + usb_stor_dbg(us, "Result for send_command in write_data %d\n", + result); /* set_sense_info is superfluous here? */ set_sense_info (3, 0x3, 0);/* peripheral write error */ @@ -453,8 +451,8 @@ static int sddr55_write_data(struct us_data *us, DMA_TO_DEVICE, buffer, len); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for send_data in write_data %d\n", - result); + usb_stor_dbg(us, "Result for send_data in write_data %d\n", + result); /* set_sense_info is superfluous here? */ set_sense_info (3, 0x3, 0);/* peripheral write error */ @@ -466,8 +464,8 @@ static int sddr55_write_data(struct us_data *us, result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for get_status in write_data %d\n", - result); + usb_stor_dbg(us, "Result for get_status in write_data %d\n", + result); /* set_sense_info is superfluous here? */ set_sense_info (3, 0x3, 0);/* peripheral write error */ @@ -487,8 +485,8 @@ static int sddr55_write_data(struct us_data *us, goto leave; } - US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n", - lba, pba, new_pba); + usb_stor_dbg(us, "Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n", + lba, pba, new_pba); /* update the lba<->pba maps, note new_pba might be the same as pba */ info->lba_to_pba[lba] = new_pba; @@ -531,8 +529,8 @@ static int sddr55_read_deviceID(struct us_data *us, command[7] = 0x84; result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); - US_DEBUGP("Result of send_control for device ID is %d\n", - result); + usb_stor_dbg(us, "Result of send_control for device ID is %d\n", + result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -568,20 +566,19 @@ static unsigned long sddr55_get_capacity(struct us_data *us) { int result; struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - US_DEBUGP("Reading capacity...\n"); + usb_stor_dbg(us, "Reading capacity...\n"); result = sddr55_read_deviceID(us, &manufacturerID, &deviceID); - US_DEBUGP("Result of read_deviceID is %d\n", - result); + usb_stor_dbg(us, "Result of read_deviceID is %d\n", result); if (result != USB_STOR_XFER_GOOD) return 0; - US_DEBUGP("Device ID = %02X\n", deviceID); - US_DEBUGP("Manuf ID = %02X\n", manufacturerID); + usb_stor_dbg(us, "Device ID = %02X\n", deviceID); + usb_stor_dbg(us, "Manuf ID = %02X\n", manufacturerID); info->pageshift = 9; info->smallpageshift = 0; @@ -753,7 +750,7 @@ static int sddr55_read_map(struct us_data *us) { } if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF)) - US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); + usb_stor_dbg(us, "LBA %04X <-> PBA %04X\n", lba, i); info->lba_to_pba[lba + zone * 1000] = i; } @@ -808,7 +805,10 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) info = (struct sddr55_card_info *)(us->extra); if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]); + usb_stor_dbg(us, "request sense %02x/%02x/%02x\n", + info->sense_data[2], + info->sense_data[12], + info->sense_data[13]); memcpy (ptr, info->sense_data, sizeof info->sense_data); ptr[0] = 0x70; @@ -892,13 +892,11 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); if ( (srb->cmnd[2] & 0x3F) == 0x01 ) { - US_DEBUGP( - "SDDR55: Dummy up request for mode page 1\n"); + usb_stor_dbg(us, "Dummy up request for mode page 1\n"); return USB_STOR_TRANSPORT_GOOD; } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) { - US_DEBUGP( - "SDDR55: Dummy up request for all mode pages\n"); + usb_stor_dbg(us, "Dummy up request for all mode pages\n"); return USB_STOR_TRANSPORT_GOOD; } @@ -908,10 +906,8 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - US_DEBUGP( - "SDDR55: %s medium removal. Not that I can do" - " anything about it...\n", - (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); + usb_stor_dbg(us, "%s medium removal. Not that I can do anything about it...\n", + (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); return USB_STOR_TRANSPORT_GOOD; @@ -935,8 +931,8 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) if (lba >= info->max_log_blks) { - US_DEBUGP("Error: Requested LBA %04X exceeds maximum " - "block %04X\n", lba, info->max_log_blks-1); + usb_stor_dbg(us, "Error: Requested LBA %04X exceeds maximum block %04X\n", + lba, info->max_log_blks - 1); set_sense_info (5, 0x24, 0); /* invalid field in command */ @@ -946,15 +942,13 @@ static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) pba = info->lba_to_pba[lba]; if (srb->cmnd[0] == WRITE_10) { - US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X" - " pages %d\n", - pba, lba, page, pages); + usb_stor_dbg(us, "WRITE_10: write block %04X (LBA %04X) page %01X pages %d\n", + pba, lba, page, pages); return sddr55_write_data(us, lba, page, pages); } else { - US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X" - " pages %d\n", - pba, lba, page, pages); + usb_stor_dbg(us, "READ_10: read block %04X (LBA %04X) page %01X pages %d\n", + pba, lba, page, pages); return sddr55_read_data(us, lba, page, pages); } diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index daf2fc58ae02..4ef2a80728f7 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -271,7 +271,7 @@ static int usbat_bulk_read(struct us_data *us, if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("usbat_bulk_read: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL); } @@ -286,7 +286,7 @@ static int usbat_bulk_write(struct us_data *us, if (len == 0) return USB_STOR_XFER_GOOD; - US_DEBUGP("usbat_bulk_write: len = %d\n", len); + usb_stor_dbg(us, "len = %d\n", len); return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL); } @@ -312,7 +312,7 @@ static int usbat_get_status(struct us_data *us, unsigned char *status) int rc; rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status); - US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status)); + usb_stor_dbg(us, "0x%02X\n", *status); return rc; } @@ -425,7 +425,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) return USB_STOR_TRANSPORT_FAILED; if ((*status & 0x80)==0x00) { /* not busy */ - US_DEBUGP("Waited not busy for %d steps\n", i); + usb_stor_dbg(us, "Waited not busy for %d steps\n", i); return USB_STOR_TRANSPORT_GOOD; } @@ -439,8 +439,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) msleep(1000); /* X minutes */ } - US_DEBUGP("Waited not busy for %d minutes, timing out.\n", - minutes); + usb_stor_dbg(us, "Waited not busy for %d minutes, timing out\n", + minutes); return USB_STOR_TRANSPORT_FAILED; } @@ -657,8 +657,9 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, if (*status & 0x20) /* device fault */ return USB_STOR_TRANSPORT_FAILED; - US_DEBUGP("Redoing %s\n", - direction==DMA_TO_DEVICE ? "write" : "read"); + usb_stor_dbg(us, "Redoing %s\n", + direction == DMA_TO_DEVICE + ? "write" : "read"); } else if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -667,8 +668,8 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } - US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==DMA_TO_DEVICE ? "Writing" : "Reading"); + usb_stor_dbg(us, "Bummer! %s bulk data 20 times failed\n", + direction == DMA_TO_DEVICE ? "Writing" : "Reading"); return USB_STOR_TRANSPORT_FAILED; } @@ -827,7 +828,7 @@ static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) data_flags, USBAT_UIO_READ); - US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags)); + usb_stor_dbg(us, "UIO register reads %02X\n", *data_flags); return result; } @@ -900,10 +901,11 @@ static int usbat_device_enable_cdt(struct us_data *us) /* * Determine if media is present. */ -static int usbat_flash_check_media_present(unsigned char *uio) +static int usbat_flash_check_media_present(struct us_data *us, + unsigned char *uio) { if (*uio & USBAT_UIO_UI0) { - US_DEBUGP("usbat_flash_check_media_present: no media detected\n"); + usb_stor_dbg(us, "no media detected\n"); return USBAT_FLASH_MEDIA_NONE; } @@ -913,10 +915,11 @@ static int usbat_flash_check_media_present(unsigned char *uio) /* * Determine if media has changed since last operation */ -static int usbat_flash_check_media_changed(unsigned char *uio) +static int usbat_flash_check_media_changed(struct us_data *us, + unsigned char *uio) { if (*uio & USBAT_UIO_0) { - US_DEBUGP("usbat_flash_check_media_changed: media change detected\n"); + usb_stor_dbg(us, "media change detected\n"); return USBAT_FLASH_MEDIA_CHANGED; } @@ -937,7 +940,7 @@ static int usbat_flash_check_media(struct us_data *us, return USB_STOR_TRANSPORT_ERROR; /* Check for media existence */ - rc = usbat_flash_check_media_present(uio); + rc = usbat_flash_check_media_present(us, uio); if (rc == USBAT_FLASH_MEDIA_NONE) { info->sense_key = 0x02; info->sense_asc = 0x3A; @@ -946,7 +949,7 @@ static int usbat_flash_check_media(struct us_data *us, } /* Check for media change */ - rc = usbat_flash_check_media_changed(uio); + rc = usbat_flash_check_media_changed(us, uio); if (rc == USBAT_FLASH_MEDIA_CHANGED) { /* Reset and re-enable card detect */ @@ -1008,11 +1011,11 @@ static int usbat_identify_device(struct us_data *us, /* Check for error bit, or if the command 'fell through' */ if (status == 0xA1 || !(status & 0x01)) { /* Device is HP 8200 */ - US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); + usb_stor_dbg(us, "Detected HP8200 CDRW\n"); info->devicetype = USBAT_DEV_HP8200; } else { /* Device is a CompactFlash reader/writer */ - US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); + usb_stor_dbg(us, "Detected Flash reader/writer\n"); info->devicetype = USBAT_DEV_FLASH; } @@ -1075,7 +1078,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, /* ATA command : IDENTIFY DEVICE */ rc = usbat_multiple_write(us, registers, command, 3); if (rc != USB_STOR_XFER_GOOD) { - US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); + usb_stor_dbg(us, "Gah! identify_device failed\n"); rc = USB_STOR_TRANSPORT_ERROR; goto leave; } @@ -1178,7 +1181,7 @@ static int usbat_flash_read_data(struct us_data *us, if (result != USB_STOR_TRANSPORT_GOOD) goto leave; - US_DEBUGP("usbat_flash_read_data: %d bytes\n", len); + usb_stor_dbg(us, "%d bytes\n", len); /* Store the data in the transfer buffer */ usb_stor_access_xfer_buf(buffer, len, us->srb, @@ -1301,8 +1304,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, unsigned int sg_offset = 0; struct scatterlist *sg = NULL; - US_DEBUGP("handle_read10: transfersize %d\n", - srb->transfersize); + usb_stor_dbg(us, "transfersize %d\n", srb->transfersize); if (scsi_bufflen(srb) < 0x10000) { @@ -1329,14 +1331,14 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, len = short_pack(data[7+9], data[7+8]); len <<= 16; len |= data[7+7]; - US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); + usb_stor_dbg(us, "GPCMD_READ_CD: len %d\n", len); srb->transfersize = scsi_bufflen(srb)/len; } if (!srb->transfersize) { srb->transfersize = 2048; /* A guess */ - US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", - srb->transfersize); + usb_stor_dbg(us, "transfersize 0, forcing %d\n", + srb->transfersize); } /* @@ -1346,7 +1348,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, */ len = (65535/srb->transfersize) * srb->transfersize; - US_DEBUGP("Max read is %d bytes\n", len); + usb_stor_dbg(us, "Max read is %d bytes\n", len); len = min(len, scsi_bufflen(srb)); buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) /* bloody hell! */ @@ -1460,10 +1462,9 @@ static int init_usbat(struct us_data *us, int devicetype) unsigned char *status = us->iobuf; us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n"); + if (!us->extra) return 1; - } + info = (struct usbat_info *) (us->extra); /* Enable peripheral control signals */ @@ -1473,7 +1474,7 @@ static int init_usbat(struct us_data *us, int devicetype) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 1\n"); + usb_stor_dbg(us, "INIT 1\n"); msleep(2000); @@ -1481,7 +1482,7 @@ static int init_usbat(struct us_data *us, int devicetype) if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("INIT 2\n"); + usb_stor_dbg(us, "INIT 2\n"); rc = usbat_read_user_io(us, status); if (rc != USB_STOR_XFER_GOOD) @@ -1491,32 +1492,32 @@ static int init_usbat(struct us_data *us, int devicetype) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 3\n"); + usb_stor_dbg(us, "INIT 3\n"); rc = usbat_select_and_test_registers(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("INIT 4\n"); + usb_stor_dbg(us, "INIT 4\n"); rc = usbat_read_user_io(us, status); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 5\n"); + usb_stor_dbg(us, "INIT 5\n"); /* Enable peripheral control signals and card detect */ rc = usbat_device_enable_cdt(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("INIT 6\n"); + usb_stor_dbg(us, "INIT 6\n"); rc = usbat_read_user_io(us, status); if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 7\n"); + usb_stor_dbg(us, "INIT 7\n"); msleep(1400); @@ -1524,19 +1525,19 @@ static int init_usbat(struct us_data *us, int devicetype) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 8\n"); + usb_stor_dbg(us, "INIT 8\n"); rc = usbat_select_and_test_registers(us); if (rc != USB_STOR_TRANSPORT_GOOD) return rc; - US_DEBUGP("INIT 9\n"); + usb_stor_dbg(us, "INIT 9\n"); /* At this point, we need to detect which device we are using */ if (usbat_set_transport(us, info, devicetype)) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 10\n"); + usb_stor_dbg(us, "INIT 10\n"); if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { subcountH = 0x02; @@ -1547,7 +1548,7 @@ static int init_usbat(struct us_data *us, int devicetype) if (rc != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - US_DEBUGP("INIT 11\n"); + usb_stor_dbg(us, "INIT 11\n"); return USB_STOR_TRANSPORT_GOOD; } @@ -1592,7 +1593,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) } result = usbat_get_status(us, status); - US_DEBUGP("Status = %02X\n", *status); + usb_stor_dbg(us, "Status = %02X\n", *status); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; if (srb->cmnd[0] == TEST_UNIT_READY) @@ -1610,7 +1611,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) if (result == USB_STOR_TRANSPORT_GOOD) { transferred += len; - US_DEBUGP("Wrote %08X bytes\n", transferred); + usb_stor_dbg(us, "Wrote %08X bytes\n", transferred); } return result; @@ -1623,8 +1624,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) } if (len > 0xFFFF) { - US_DEBUGP("Error: len = %08X... what do I do now?\n", - len); + usb_stor_dbg(us, "Error: len = %08X... what do I do now?\n", + len); return USB_STOR_TRANSPORT_ERROR; } @@ -1693,7 +1694,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) }; if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n"); + usb_stor_dbg(us, "INQUIRY - Returning bogus response\n"); memcpy(ptr, inquiry_response, sizeof(inquiry_response)); fill_inquiry_response(us, ptr, 36); return USB_STOR_TRANSPORT_GOOD; @@ -1710,8 +1711,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) /* hard coded 512 byte sectors as per ATA spec */ info->ssize = 0x200; - US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); + usb_stor_dbg(us, "READ_CAPACITY: %ld sectors, %ld bytes per sector\n", + info->sectors, info->ssize); /* * build the reply @@ -1726,7 +1727,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("usbat_flash_transport: Gah! MODE_SELECT_10.\n"); + usb_stor_dbg(us, "Gah! MODE_SELECT_10\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -1736,7 +1737,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("usbat_flash_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_10: read block 0x%04lx count %ld\n", + block, blocks); return usbat_flash_read_data(us, info, block, blocks); } @@ -1750,7 +1752,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "READ_12: read block 0x%04lx count %ld\n", + block, blocks); return usbat_flash_read_data(us, info, block, blocks); } @@ -1760,7 +1763,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_10: write block 0x%04lx count %ld\n", + block, blocks); return usbat_flash_write_data(us, info, block, blocks); } @@ -1774,13 +1778,14 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); + usb_stor_dbg(us, "WRITE_12: write block 0x%04lx count %ld\n", + block, blocks); return usbat_flash_write_data(us, info, block, blocks); } if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n"); + usb_stor_dbg(us, "TEST_UNIT_READY\n"); rc = usbat_flash_check_media(us, info); if (rc != USB_STOR_TRANSPORT_GOOD) @@ -1790,7 +1795,7 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) } if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n"); + usb_stor_dbg(us, "REQUEST_SENSE\n"); memset(ptr, 0, 18); ptr[0] = 0xF0; @@ -1811,8 +1816,8 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; } - US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); + usb_stor_dbg(us, "Gah! Unknown command: %d (0x%x)\n", + srb->cmnd[0], srb->cmnd[0]); info->sense_key = 0x05; info->sense_asc = 0x20; info->sense_ascq = 0x00; diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 17e36952bced..2ea657be14c8 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -47,7 +47,7 @@ static bool containsFullLinuxPackage(struct swoc_info *swocInfo) static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode) { int result; - US_DEBUGP("SWIMS: %s", "DEVICE MODE SWITCH\n"); + dev_dbg(&udev->dev, "SWIMS: %s", "DEVICE MODE SWITCH\n"); result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */ USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */ @@ -65,7 +65,7 @@ static int sierra_get_swoc_info(struct usb_device *udev, { int result; - US_DEBUGP("SWIMS: Attempting to get TRU-Install info.\n"); + dev_dbg(&udev->dev, "SWIMS: Attempting to get TRU-Install info\n"); result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */ @@ -81,11 +81,11 @@ static int sierra_get_swoc_info(struct usb_device *udev, return result; } -static void debug_swoc(struct swoc_info *swocInfo) +static void debug_swoc(const struct device *dev, struct swoc_info *swocInfo) { - US_DEBUGP("SWIMS: SWoC Rev: %02d \n", swocInfo->rev); - US_DEBUGP("SWIMS: Linux SKU: %04X \n", swocInfo->LinuxSKU); - US_DEBUGP("SWIMS: Linux Version: %04X \n", swocInfo->LinuxVer); + dev_dbg(dev, "SWIMS: SWoC Rev: %02d\n", swocInfo->rev); + dev_dbg(dev, "SWIMS: Linux SKU: %04X\n", swocInfo->LinuxSKU); + dev_dbg(dev, "SWIMS: Linux Version: %04X\n", swocInfo->LinuxVer); } @@ -101,18 +101,17 @@ static ssize_t show_truinst(struct device *dev, struct device_attribute *attr, } else { swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL); if (!swocInfo) { - US_DEBUGP("SWIMS: Allocation failure\n"); snprintf(buf, PAGE_SIZE, "Error\n"); return -ENOMEM; } result = sierra_get_swoc_info(udev, swocInfo); if (result < 0) { - US_DEBUGP("SWIMS: failed SWoC query\n"); + dev_dbg(dev, "SWIMS: failed SWoC query\n"); kfree(swocInfo); snprintf(buf, PAGE_SIZE, "Error\n"); return -EIO; } - debug_swoc(swocInfo); + debug_swoc(dev, swocInfo); result = snprintf(buf, PAGE_SIZE, "REV=%02d SKU=%04X VER=%04X\n", swocInfo->rev, @@ -138,61 +137,55 @@ int sierra_ms_init(struct us_data *us) sh = us_to_host(us); scsi_get_host_dev(sh); - US_DEBUGP("SWIMS: sierra_ms_init called\n"); - /* Force Modem mode */ if (swi_tru_install == TRU_FORCE_MODEM) { - US_DEBUGP("SWIMS: %s", "Forcing Modem Mode\n"); + usb_stor_dbg(us, "SWIMS: Forcing Modem Mode\n"); result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); if (result < 0) - US_DEBUGP("SWIMS: Failed to switch to modem mode.\n"); + usb_stor_dbg(us, "SWIMS: Failed to switch to modem mode\n"); return -EIO; } /* Force Mass Storage mode (keep CD-Rom) */ else if (swi_tru_install == TRU_FORCE_MS) { - US_DEBUGP("SWIMS: %s", "Forcing Mass Storage Mode\n"); + usb_stor_dbg(us, "SWIMS: Forcing Mass Storage Mode\n"); goto complete; } /* Normal TRU-Install Logic */ else { - US_DEBUGP("SWIMS: %s", "Normal SWoC Logic\n"); + usb_stor_dbg(us, "SWIMS: Normal SWoC Logic\n"); swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL); - if (!swocInfo) { - US_DEBUGP("SWIMS: %s", "Allocation failure\n"); + if (!swocInfo) return -ENOMEM; - } retries = 3; do { retries--; result = sierra_get_swoc_info(udev, swocInfo); if (result < 0) { - US_DEBUGP("SWIMS: %s", "Failed SWoC query\n"); + usb_stor_dbg(us, "SWIMS: Failed SWoC query\n"); schedule_timeout_uninterruptible(2*HZ); } } while (retries && result < 0); if (result < 0) { - US_DEBUGP("SWIMS: %s", - "Completely failed SWoC query\n"); + usb_stor_dbg(us, "SWIMS: Completely failed SWoC query\n"); kfree(swocInfo); return -EIO; } - debug_swoc(swocInfo); + debug_swoc(&us->pusb_dev->dev, swocInfo); /* If there is not Linux software on the TRU-Install device * then switch to modem mode */ if (!containsFullLinuxPackage(swocInfo)) { - US_DEBUGP("SWIMS: %s", - "Switching to Modem Mode\n"); + usb_stor_dbg(us, "SWIMS: Switching to Modem Mode\n"); result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); if (result < 0) - US_DEBUGP("SWIMS: Failed to switch modem\n"); + usb_stor_dbg(us, "SWIMS: Failed to switch modem\n"); kfree(swocInfo); return -EIO; } diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c0543c83923e..22c7d4360fa2 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -166,7 +166,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) /* cancel the URB, if it hasn't been cancelled already */ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling URB\n"); + usb_stor_dbg(us, "-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } } @@ -178,8 +178,8 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags); if (timeleft <= 0) { - US_DEBUGP("%s -- cancelling URB\n", - timeleft == 0 ? "Timeout" : "Signal"); + usb_stor_dbg(us, "%s -- cancelling URB\n", + timeleft == 0 ? "Timeout" : "Signal"); usb_kill_urb(us->current_urb); } @@ -197,9 +197,8 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, { int status; - US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", - __func__, request, requesttype, - value, index, size); + usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", + request, requesttype, value, index, size); /* fill in the devrequest structure */ us->cr->bRequestType = requesttype; @@ -249,7 +248,7 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) if (result >= 0) usb_reset_endpoint(us->pusb_dev, endp); - US_DEBUGP("%s: result = %d\n", __func__, result); + usb_stor_dbg(us, "result = %d\n", result); return result; } EXPORT_SYMBOL_GPL(usb_stor_clear_halt); @@ -265,18 +264,18 @@ EXPORT_SYMBOL_GPL(usb_stor_clear_halt); static int interpret_urb_result(struct us_data *us, unsigned int pipe, unsigned int length, int result, unsigned int partial) { - US_DEBUGP("Status code %d; transferred %u/%u\n", - result, partial, length); + usb_stor_dbg(us, "Status code %d; transferred %u/%u\n", + result, partial, length); switch (result) { /* no error code; did we send all the data? */ case 0: if (partial != length) { - US_DEBUGP("-- short transfer\n"); + usb_stor_dbg(us, "-- short transfer\n"); return USB_STOR_XFER_SHORT; } - US_DEBUGP("-- transfer complete\n"); + usb_stor_dbg(us, "-- transfer complete\n"); return USB_STOR_XFER_GOOD; /* stalled */ @@ -284,39 +283,40 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, /* for control endpoints, (used by CB[I]) a stall indicates * a failed command */ if (usb_pipecontrol(pipe)) { - US_DEBUGP("-- stall on control pipe\n"); + usb_stor_dbg(us, "-- stall on control pipe\n"); return USB_STOR_XFER_STALLED; } /* for other sorts of endpoint, clear the stall */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + usb_stor_dbg(us, "clearing endpoint halt for pipe 0x%x\n", + pipe); if (usb_stor_clear_halt(us, pipe) < 0) return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; /* babble - the device tried to send more than we wanted to read */ case -EOVERFLOW: - US_DEBUGP("-- babble\n"); + usb_stor_dbg(us, "-- babble\n"); return USB_STOR_XFER_LONG; /* the transfer was cancelled by abort, disconnect, or timeout */ case -ECONNRESET: - US_DEBUGP("-- transfer cancelled\n"); + usb_stor_dbg(us, "-- transfer cancelled\n"); return USB_STOR_XFER_ERROR; /* short scatter-gather read transfer */ case -EREMOTEIO: - US_DEBUGP("-- short read transfer\n"); + usb_stor_dbg(us, "-- short read transfer\n"); return USB_STOR_XFER_SHORT; /* abort or disconnect in progress */ case -EIO: - US_DEBUGP("-- abort or disconnect in progress\n"); + usb_stor_dbg(us, "-- abort or disconnect in progress\n"); return USB_STOR_XFER_ERROR; /* the catch-all error case */ default: - US_DEBUGP("-- unknown error\n"); + usb_stor_dbg(us, "-- unknown error\n"); return USB_STOR_XFER_ERROR; } } @@ -331,9 +331,8 @@ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, { int result; - US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", - __func__, request, requesttype, - value, index, size); + usb_stor_dbg(us, "rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", + request, requesttype, value, index, size); /* fill in the devrequest structure */ us->cr->bRequestType = requesttype; @@ -367,7 +366,7 @@ static int usb_stor_intr_transfer(struct us_data *us, void *buf, unsigned int pipe = us->recv_intr_pipe; unsigned int maxp; - US_DEBUGP("%s: xfer %u bytes\n", __func__, length); + usb_stor_dbg(us, "xfer %u bytes\n", length); /* calculate the max packet size */ maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)); @@ -394,7 +393,7 @@ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, { int result; - US_DEBUGP("%s: xfer %u bytes\n", __func__, length); + usb_stor_dbg(us, "xfer %u bytes\n", length); /* fill and submit the URB */ usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, @@ -426,12 +425,11 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, return USB_STOR_XFER_ERROR; /* initialize the scatter-gather request block */ - US_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__, - length, num_sg); + usb_stor_dbg(us, "xfer %u bytes, %d entries\n", length, num_sg); result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, sg, num_sg, length, GFP_NOIO); if (result) { - US_DEBUGP("usb_sg_init returned %d\n", result); + usb_stor_dbg(us, "usb_sg_init returned %d\n", result); return USB_STOR_XFER_ERROR; } @@ -444,7 +442,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, /* cancel the request, if it hasn't been cancelled already */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling sg request\n"); + usb_stor_dbg(us, "-- cancelling sg request\n"); usb_sg_cancel(&us->current_sg); } } @@ -609,14 +607,14 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) * short-circuit all other processing */ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- command was aborted\n"); + usb_stor_dbg(us, "-- command was aborted\n"); srb->result = DID_ABORT << 16; goto Handle_Errors; } /* if there is a transport error, reset and don't auto-sense */ if (result == USB_STOR_TRANSPORT_ERROR) { - US_DEBUGP("-- transport indicates error, resetting\n"); + usb_stor_dbg(us, "-- transport indicates error, resetting\n"); srb->result = DID_ERROR << 16; goto Handle_Errors; } @@ -645,7 +643,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) */ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && srb->sc_data_direction != DMA_FROM_DEVICE) { - US_DEBUGP("-- CB transport device requiring auto-sense\n"); + usb_stor_dbg(us, "-- CB transport device requiring auto-sense\n"); need_auto_sense = 1; } @@ -655,7 +653,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) * "failure" and an "error" in the transport mechanism. */ if (result == USB_STOR_TRANSPORT_FAILED) { - US_DEBUGP("-- transport indicates command failure\n"); + usb_stor_dbg(us, "-- transport indicates command failure\n"); need_auto_sense = 1; } @@ -670,7 +668,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && !(srb->cmnd[2] & 0x20))) { - US_DEBUGP("-- SAT supported, increasing auto-sense\n"); + usb_stor_dbg(us, "-- SAT supported, increasing auto-sense\n"); us->fflags |= US_FL_SANE_SENSE; } @@ -684,7 +682,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) (srb->cmnd[0] == MODE_SENSE) || (srb->cmnd[0] == LOG_SENSE) || (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); + usb_stor_dbg(us, "-- unexpectedly short transfer\n"); } /* Now, if we need to do the auto-sense, let's do it */ @@ -700,7 +698,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) if (us->fflags & US_FL_SANE_SENSE) sense_size = ~0; Retry_Sense: - US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); + usb_stor_dbg(us, "Issuing auto-REQUEST_SENSE\n"); scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); @@ -719,7 +717,7 @@ Retry_Sense: scsi_eh_restore_cmnd(srb, &ses); if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- auto-sense aborted\n"); + usb_stor_dbg(us, "-- auto-sense aborted\n"); srb->result = DID_ABORT << 16; /* If SANE_SENSE caused this problem, disable it */ @@ -737,7 +735,7 @@ Retry_Sense: */ if (temp_result == USB_STOR_TRANSPORT_FAILED && sense_size != US_SENSE_SIZE) { - US_DEBUGP("-- auto-sense failure, retry small sense\n"); + usb_stor_dbg(us, "-- auto-sense failure, retry small sense\n"); sense_size = US_SENSE_SIZE; us->fflags &= ~US_FL_SANE_SENSE; us->fflags |= US_FL_BAD_SENSE; @@ -746,7 +744,7 @@ Retry_Sense: /* Other failures */ if (temp_result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("-- auto-sense failure\n"); + usb_stor_dbg(us, "-- auto-sense failure\n"); /* we skip the reset if this happens to be a * multi-target device, since failure of an @@ -766,27 +764,28 @@ Retry_Sense: !(us->fflags & US_FL_SANE_SENSE) && !(us->fflags & US_FL_BAD_SENSE) && (srb->sense_buffer[0] & 0x7C) == 0x70) { - US_DEBUGP("-- SANE_SENSE support enabled\n"); + usb_stor_dbg(us, "-- SANE_SENSE support enabled\n"); us->fflags |= US_FL_SANE_SENSE; /* Indicate to the user that we truncated their sense * because we didn't know it supported larger sense. */ - US_DEBUGP("-- Sense data truncated to %i from %i\n", - US_SENSE_SIZE, - srb->sense_buffer[7] + 8); + usb_stor_dbg(us, "-- Sense data truncated to %i from %i\n", + US_SENSE_SIZE, + srb->sense_buffer[7] + 8); srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, &sshdr); - US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - sshdr.response_code, sshdr.sense_key, - sshdr.asc, sshdr.ascq); + usb_stor_dbg(us, "-- Result from auto-sense is %d\n", + temp_result); + usb_stor_dbg(us, "-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", + sshdr.response_code, sshdr.sense_key, + sshdr.asc, sshdr.ascq); #ifdef CONFIG_USB_STORAGE_DEBUG - usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); + usb_stor_show_sense(us, sshdr.sense_key, sshdr.asc, sshdr.ascq); #endif /* set the result so the higher layers expect this data */ @@ -892,20 +891,18 @@ Retry_Sense: /* Stop the current URB transfer */ void usb_stor_stop_transport(struct us_data *us) { - US_DEBUGP("%s called\n", __func__); - /* If the state machine is blocked waiting for an URB, * let's wake it up. The test_and_clear_bit() call * guarantees that if a URB has just been submitted, * it won't be cancelled more than once. */ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling URB\n"); + usb_stor_dbg(us, "-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } /* If we are waiting for a scatter-gather operation, cancel it. */ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling sg request\n"); + usb_stor_dbg(us, "-- cancelling sg request\n"); usb_sg_cancel(&us->current_sg); } } @@ -928,7 +925,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); + usb_stor_dbg(us, "Call to usb_stor_ctrl_transfer() returned %d\n", + result); /* if we stalled the command, it means command failed */ if (result == USB_STOR_XFER_STALLED) { @@ -946,7 +944,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_srb(us, pipe, srb); - US_DEBUGP("CBI data stage result is 0x%x\n", result); + usb_stor_dbg(us, "CBI data stage result is 0x%x\n", result); /* if we stalled the data transfer it means command failed */ if (result == USB_STOR_XFER_STALLED) @@ -964,8 +962,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_GOOD; result = usb_stor_intr_transfer(us, us->iobuf, 2); - US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", - us->iobuf[0], us->iobuf[1]); + usb_stor_dbg(us, "Got interrupt data (0x%x, 0x%x)\n", + us->iobuf[0], us->iobuf[1]); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -992,8 +990,8 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) * into the first byte -- so if it's non-zero, call it a failure. */ if (us->iobuf[0]) { - US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n", - us->iobuf[0]); + usb_stor_dbg(us, "CBI IRQ data showed reserved bType 0x%x\n", + us->iobuf[0]); goto Failed; } @@ -1034,8 +1032,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us) USB_RECIP_INTERFACE, 0, us->ifnum, us->iobuf, 1, 10*HZ); - US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, us->iobuf[0]); + usb_stor_dbg(us, "GetMaxLUN command result is %d, data is %d\n", + result, us->iobuf[0]); /* if we have a successful request, return the result */ if (result > 0) @@ -1084,14 +1082,14 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) memcpy(bcb->CDB, srb->cmnd, bcb->Length); /* send it to out endpoint */ - US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", - le32_to_cpu(bcb->Signature), bcb->Tag, - le32_to_cpu(bcb->DataTransferLength), bcb->Flags, - (bcb->Lun >> 4), (bcb->Lun & 0x0F), - bcb->Length); + usb_stor_dbg(us, "Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", + le32_to_cpu(bcb->Signature), bcb->Tag, + le32_to_cpu(bcb->DataTransferLength), bcb->Flags, + (bcb->Lun >> 4), (bcb->Lun & 0x0F), + bcb->Length); result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL); - US_DEBUGP("Bulk command transfer result=%d\n", result); + usb_stor_dbg(us, "Bulk command transfer result=%d\n", result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -1108,7 +1106,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; result = usb_stor_bulk_srb(us, pipe, srb); - US_DEBUGP("Bulk data transfer result 0x%x\n", result); + usb_stor_dbg(us, "Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; @@ -1127,7 +1125,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) */ /* get CSW for device status */ - US_DEBUGP("Attempting to get CSW...\n"); + usb_stor_dbg(us, "Attempting to get CSW...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); @@ -1136,7 +1134,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) * CSWs. If we encounter such a thing, try to read the CSW again. */ if (result == USB_STOR_XFER_SHORT && cswlen == 0) { - US_DEBUGP("Received 0-length CSW; retrying...\n"); + usb_stor_dbg(us, "Received 0-length CSW; retrying...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, &cswlen); } @@ -1145,24 +1143,24 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (result == USB_STOR_XFER_STALLED) { /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); + usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n"); result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, US_BULK_CS_WRAP_LEN, NULL); } /* if we still have a failure at this point, we're in trouble */ - US_DEBUGP("Bulk status result = %d\n", result); + usb_stor_dbg(us, "Bulk status result = %d\n", result); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; /* check bulk status */ residue = le32_to_cpu(bcs->Residue); - US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", - le32_to_cpu(bcs->Signature), bcs->Tag, - residue, bcs->Status); + usb_stor_dbg(us, "Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", + le32_to_cpu(bcs->Signature), bcs->Tag, + residue, bcs->Status); if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) || bcs->Status > US_BULK_STAT_PHASE) { - US_DEBUGP("Bulk logical error\n"); + usb_stor_dbg(us, "Bulk logical error\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -1173,12 +1171,12 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (!us->bcs_signature) { us->bcs_signature = bcs->Signature; if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN)) - US_DEBUGP("Learnt BCS signature 0x%08X\n", - le32_to_cpu(us->bcs_signature)); + usb_stor_dbg(us, "Learnt BCS signature 0x%08X\n", + le32_to_cpu(us->bcs_signature)); } else if (bcs->Signature != us->bcs_signature) { - US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n", - le32_to_cpu(bcs->Signature), - le32_to_cpu(us->bcs_signature)); + usb_stor_dbg(us, "Signature mismatch: got %08X, expecting %08X\n", + le32_to_cpu(bcs->Signature), + le32_to_cpu(us->bcs_signature)); return USB_STOR_TRANSPORT_ERROR; } @@ -1255,7 +1253,7 @@ static int usb_stor_reset_common(struct us_data *us, int result2; if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("No reset during disconnect\n"); + usb_stor_dbg(us, "No reset during disconnect\n"); return -EIO; } @@ -1263,7 +1261,7 @@ static int usb_stor_reset_common(struct us_data *us, request, requesttype, value, index, data, size, 5*HZ); if (result < 0) { - US_DEBUGP("Soft reset failed: %d\n", result); + usb_stor_dbg(us, "Soft reset failed: %d\n", result); return result; } @@ -1273,23 +1271,23 @@ static int usb_stor_reset_common(struct us_data *us, test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6); if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("Reset interrupted by disconnect\n"); + usb_stor_dbg(us, "Reset interrupted by disconnect\n"); return -EIO; } - US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); + usb_stor_dbg(us, "Soft reset: clearing bulk-in endpoint halt\n"); result = usb_stor_clear_halt(us, us->recv_bulk_pipe); - US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); + usb_stor_dbg(us, "Soft reset: clearing bulk-out endpoint halt\n"); result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); /* return a result code based on the result of the clear-halts */ if (result >= 0) result = result2; if (result < 0) - US_DEBUGP("Soft reset failed\n"); + usb_stor_dbg(us, "Soft reset failed\n"); else - US_DEBUGP("Soft reset done\n"); + usb_stor_dbg(us, "Soft reset done\n"); return result; } @@ -1299,8 +1297,6 @@ static int usb_stor_reset_common(struct us_data *us, int usb_stor_CB_reset(struct us_data *us) { - US_DEBUGP("%s called\n", __func__); - memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE); us->iobuf[0] = SEND_DIAGNOSTIC; us->iobuf[1] = 4; @@ -1315,8 +1311,6 @@ EXPORT_SYMBOL_GPL(usb_stor_CB_reset); */ int usb_stor_Bulk_reset(struct us_data *us) { - US_DEBUGP("%s called\n", __func__); - return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0); @@ -1336,16 +1330,17 @@ int usb_stor_port_reset(struct us_data *us) result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); if (result < 0) - US_DEBUGP("unable to lock device for reset: %d\n", result); + usb_stor_dbg(us, "unable to lock device for reset: %d\n", + result); else { /* Were we disconnected while waiting for the lock? */ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { result = -EIO; - US_DEBUGP("No reset during disconnect\n"); + usb_stor_dbg(us, "No reset during disconnect\n"); } else { result = usb_reset_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", - result); + usb_stor_dbg(us, "usb_reset_device returns %d\n", + result); } usb_unlock_device(us->pusb_dev); } diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index d6bee407af02..5c4fe0749af1 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -183,7 +183,6 @@ int usb_stor_suspend(struct usb_interface *iface, pm_message_t message) /* Wait until no command is running */ mutex_lock(&us->dev_mutex); - US_DEBUGP("%s\n", __func__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_SUSPEND); @@ -201,7 +200,6 @@ int usb_stor_resume(struct usb_interface *iface) mutex_lock(&us->dev_mutex); - US_DEBUGP("%s\n", __func__); if (us->suspend_resume_hook) (us->suspend_resume_hook)(us, US_RESUME); @@ -214,8 +212,6 @@ int usb_stor_reset_resume(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s\n", __func__); - /* Report the reset to the SCSI core */ usb_stor_report_bus_reset(us); @@ -236,8 +232,6 @@ int usb_stor_pre_reset(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s\n", __func__); - /* Make sure no command runs during the reset */ mutex_lock(&us->dev_mutex); return 0; @@ -248,8 +242,6 @@ int usb_stor_post_reset(struct usb_interface *iface) { struct us_data *us = usb_get_intfdata(iface); - US_DEBUGP("%s\n", __func__); - /* Report the reset to the SCSI core */ usb_stor_report_bus_reset(us); @@ -311,11 +303,11 @@ static int usb_stor_control_thread(void * __us) struct Scsi_Host *host = us_to_host(us); for (;;) { - US_DEBUGP("*** thread sleeping.\n"); + usb_stor_dbg(us, "*** thread sleeping\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) break; - US_DEBUGP("*** thread awakened.\n"); + usb_stor_dbg(us, "*** thread awakened\n"); /* lock the device pointers */ mutex_lock(&(us->dev_mutex)); @@ -327,7 +319,7 @@ static int usb_stor_control_thread(void * __us) if (us->srb == NULL) { scsi_unlock(host); mutex_unlock(&us->dev_mutex); - US_DEBUGP("-- exiting\n"); + usb_stor_dbg(us, "-- exiting\n"); break; } @@ -343,7 +335,7 @@ static int usb_stor_control_thread(void * __us) * is UNKNOWN */ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { - US_DEBUGP("UNKNOWN data direction\n"); + usb_stor_dbg(us, "UNKNOWN data direction\n"); us->srb->result = DID_ERROR << 16; } @@ -352,14 +344,14 @@ static int usb_stor_control_thread(void * __us) */ else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { - US_DEBUGP("Bad target number (%d:%d)\n", - us->srb->device->id, us->srb->device->lun); + usb_stor_dbg(us, "Bad target number (%d:%d)\n", + us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } else if (us->srb->device->lun > us->max_lun) { - US_DEBUGP("Bad LUN (%d:%d)\n", - us->srb->device->id, us->srb->device->lun); + usb_stor_dbg(us, "Bad LUN (%d:%d)\n", + us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } @@ -371,14 +363,14 @@ static int usb_stor_control_thread(void * __us) 0x00, 0x80, 0x02, 0x02, 0x1F, 0x00, 0x00, 0x00}; - US_DEBUGP("Faking INQUIRY command\n"); + usb_stor_dbg(us, "Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); us->srb->result = SAM_STAT_GOOD; } /* we've got a command, let's do it! */ else { - US_DEBUG(usb_stor_show_command(us->srb)); + US_DEBUG(usb_stor_show_command(us, us->srb)); us->proto_handler(us->srb, us); usb_mark_last_busy(us->pusb_dev); } @@ -388,12 +380,12 @@ static int usb_stor_control_thread(void * __us) /* indicate that the command is done */ if (us->srb->result != DID_ABORT << 16) { - US_DEBUGP("scsi cmd done, result=0x%x\n", - us->srb->result); + usb_stor_dbg(us, "scsi cmd done, result=0x%x\n", + us->srb->result); us->srb->scsi_done(us->srb); } else { SkipForAbort: - US_DEBUGP("scsi command aborted\n"); + usb_stor_dbg(us, "scsi command aborted\n"); } /* If an abort request was received we need to signal that @@ -435,34 +427,30 @@ SkipForAbort: /* Associate our private data with the USB device */ static int associate_dev(struct us_data *us, struct usb_interface *intf) { - US_DEBUGP("-- %s\n", __func__); - /* Fill in the device-related fields */ us->pusb_dev = interface_to_usbdev(intf); us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", - le16_to_cpu(us->pusb_dev->descriptor.idVendor), - le16_to_cpu(us->pusb_dev->descriptor.idProduct), - le16_to_cpu(us->pusb_dev->descriptor.bcdDevice)); - US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", - intf->cur_altsetting->desc.bInterfaceSubClass, - intf->cur_altsetting->desc.bInterfaceProtocol); + usb_stor_dbg(us, "Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", + le16_to_cpu(us->pusb_dev->descriptor.idVendor), + le16_to_cpu(us->pusb_dev->descriptor.idProduct), + le16_to_cpu(us->pusb_dev->descriptor.bcdDevice)); + usb_stor_dbg(us, "Interface Subclass: 0x%02x, Protocol: 0x%02x\n", + intf->cur_altsetting->desc.bInterfaceSubClass, + intf->cur_altsetting->desc.bInterfaceProtocol); /* Store our private data in the interface */ usb_set_intfdata(intf, us); /* Allocate the control/setup and DMA-mapped buffers */ us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL); - if (!us->cr) { - US_DEBUGP("usb_ctrlrequest allocation failed\n"); + if (!us->cr) return -ENOMEM; - } us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE, GFP_KERNEL, &us->iobuf_dma); if (!us->iobuf) { - US_DEBUGP("I/O buffer allocation failed\n"); + usb_stor_dbg(us, "I/O buffer allocation failed\n"); return -ENOMEM; } return 0; @@ -738,7 +726,7 @@ static int get_pipes(struct us_data *us) } if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) { - US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); + usb_stor_dbg(us, "Endpoint sanity check failed! Rejecting dev.\n"); return -EIO; } @@ -765,7 +753,7 @@ static int usb_stor_acquire_resources(struct us_data *us) us->current_urb = usb_alloc_urb(0, GFP_KERNEL); if (!us->current_urb) { - US_DEBUGP("URB allocation failed\n"); + usb_stor_dbg(us, "URB allocation failed\n"); return -ENOMEM; } @@ -792,20 +780,18 @@ static int usb_stor_acquire_resources(struct us_data *us) /* Release all our dynamic resources */ static void usb_stor_release_resources(struct us_data *us) { - US_DEBUGP("-- %s\n", __func__); - /* Tell the control thread to exit. The SCSI host must * already have been removed and the DISCONNECTING flag set * so that we won't accept any more commands. */ - US_DEBUGP("-- sending exit command to thread\n"); + usb_stor_dbg(us, "-- sending exit command to thread\n"); complete(&us->cmnd_ready); if (us->ctl_thread) kthread_stop(us->ctl_thread); /* Call the destructor routine, if it exists */ if (us->extra_destructor) { - US_DEBUGP("-- calling extra_destructor()\n"); + usb_stor_dbg(us, "-- calling extra_destructor()\n"); us->extra_destructor(us->extra); } @@ -817,8 +803,6 @@ static void usb_stor_release_resources(struct us_data *us) /* Dissociate from the USB device */ static void dissociate_dev(struct us_data *us) { - US_DEBUGP("-- %s\n", __func__); - /* Free the buffers */ kfree(us->cr); usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma); @@ -918,7 +902,7 @@ int usb_stor_probe1(struct us_data **pus, struct us_data *us; int result; - US_DEBUGP("USB Mass Storage device detected\n"); + dev_info(&intf->dev, "USB Mass Storage device detected\n"); /* * Ask the SCSI layer to allocate a host structure, with extra @@ -926,8 +910,7 @@ int usb_stor_probe1(struct us_data **pus, */ host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us)); if (!host) { - dev_warn(&intf->dev, - "Unable to allocate the scsi host\n"); + dev_warn(&intf->dev, "Unable to allocate the scsi host\n"); return -ENOMEM; } @@ -964,7 +947,7 @@ int usb_stor_probe1(struct us_data **pus, return 0; BadDevice: - US_DEBUGP("storage_probe() failed\n"); + usb_stor_dbg(us, "storage_probe() failed\n"); release_everything(us); return result; } @@ -981,8 +964,8 @@ int usb_stor_probe2(struct us_data *us) result = -ENXIO; goto BadDevice; } - US_DEBUGP("Transport: %s\n", us->transport_name); - US_DEBUGP("Protocol: %s\n", us->protocol_name); + usb_stor_dbg(us, "Transport: %s\n", us->transport_name); + usb_stor_dbg(us, "Protocol: %s\n", us->protocol_name); /* fix for single-lun devices */ if (us->fflags & US_FL_SINGLE_LUN) @@ -1028,7 +1011,7 @@ int usb_stor_probe2(struct us_data *us) /* We come here if there are any problems */ BadDevice: - US_DEBUGP("storage_probe() failed\n"); + usb_stor_dbg(us, "storage_probe() failed\n"); release_everything(us); return result; } @@ -1039,7 +1022,6 @@ void usb_stor_disconnect(struct usb_interface *intf) { struct us_data *us = usb_get_intfdata(intf); - US_DEBUGP("storage_disconnect() called\n"); quiesce_and_remove_host(us); release_everything(us); } @@ -1075,8 +1057,7 @@ static int storage_probe(struct usb_interface *intf, } else { unusual_dev = &for_dynamic_ids; - US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport", - "with the Transparent SCSI protocol for dynamic id:", + dev_dbg(&intf->dev, "Use Bulk-Only transport with the Transparent SCSI protocol for dynamic id: 0x%04x 0x%04x\n", id->idVendor, id->idProduct); } @@ -1090,10 +1071,6 @@ static int storage_probe(struct usb_interface *intf, return result; } -/*********************************************************************** - * Initialization and registration - ***********************************************************************/ - static struct usb_driver usb_storage_driver = { .name = "usb-storage", .probe = storage_probe, @@ -1108,30 +1085,4 @@ static struct usb_driver usb_storage_driver = { .soft_unbind = 1, }; -static int __init usb_stor_init(void) -{ - int retval; - - pr_info("Initializing USB Mass Storage driver...\n"); - - /* register the driver, return usb_register return code if error */ - retval = usb_register(&usb_storage_driver); - if (retval == 0) - pr_info("USB Mass Storage support registered.\n"); - return retval; -} - -static void __exit usb_stor_exit(void) -{ - US_DEBUGP("usb_stor_exit() called\n"); - - /* Deregister the driver - * This will cause disconnect() to be called for each - * attached unit - */ - US_DEBUGP("-- calling usb_deregister()\n"); - usb_deregister(&usb_storage_driver) ; -} - -module_init(usb_stor_init); -module_exit(usb_stor_exit); +module_usb_driver(usb_storage_driver); diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c index d29503e954ab..0db0a919d72b 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/usb-common.c @@ -14,6 +14,32 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/usb/ch9.h> +#include <linux/usb/otg.h> + +const char *usb_otg_state_string(enum usb_otg_state state) +{ + static const char *const names[] = { + [OTG_STATE_A_IDLE] = "a_idle", + [OTG_STATE_A_WAIT_VRISE] = "a_wait_vrise", + [OTG_STATE_A_WAIT_BCON] = "a_wait_bcon", + [OTG_STATE_A_HOST] = "a_host", + [OTG_STATE_A_SUSPEND] = "a_suspend", + [OTG_STATE_A_PERIPHERAL] = "a_peripheral", + [OTG_STATE_A_WAIT_VFALL] = "a_wait_vfall", + [OTG_STATE_A_VBUS_ERR] = "a_vbus_err", + [OTG_STATE_B_IDLE] = "b_idle", + [OTG_STATE_B_SRP_INIT] = "b_srp_init", + [OTG_STATE_B_PERIPHERAL] = "b_peripheral", + [OTG_STATE_B_WAIT_ACON] = "b_wait_acon", + [OTG_STATE_B_HOST] = "b_host", + }; + + if (state < 0 || state >= ARRAY_SIZE(names)) + return "UNDEFINED"; + + return names[state]; +} +EXPORT_SYMBOL_GPL(usb_otg_state_string); const char *usb_speed_string(enum usb_device_speed speed) { @@ -32,4 +58,25 @@ const char *usb_speed_string(enum usb_device_speed speed) } EXPORT_SYMBOL_GPL(usb_speed_string); +const char *usb_state_string(enum usb_device_state state) +{ + static const char *const names[] = { + [USB_STATE_NOTATTACHED] = "not attached", + [USB_STATE_ATTACHED] = "attached", + [USB_STATE_POWERED] = "powered", + [USB_STATE_RECONNECTING] = "reconnecting", + [USB_STATE_UNAUTHENTICATED] = "unauthenticated", + [USB_STATE_DEFAULT] = "default", + [USB_STATE_ADDRESS] = "addresssed", + [USB_STATE_CONFIGURED] = "configured", + [USB_STATE_SUSPENDED] = "suspended", + }; + + if (state < 0 || state >= ARRAY_SIZE(names)) + return "UNKNOWN"; + + return names[state]; +} +EXPORT_SYMBOL_GPL(usb_state_string); + MODULE_LICENSE("GPL"); diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index ce310170829f..7ed3b039dbe8 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -61,11 +61,10 @@ struct usb_skel { __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ int errors; /* the last request tanked */ bool ongoing_read; /* a read is going on */ - bool processed_urb; /* indicates we haven't processed the urb */ spinlock_t err_lock; /* lock for errors */ struct kref kref; struct mutex io_mutex; /* synchronize I/O with disconnect */ - struct completion bulk_in_completion; /* to wait for an ongoing read */ + wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ }; #define to_skel_dev(d) container_of(d, struct usb_skel, kref) @@ -185,7 +184,7 @@ static void skel_read_bulk_callback(struct urb *urb) dev->ongoing_read = 0; spin_unlock(&dev->err_lock); - complete(&dev->bulk_in_completion); + wake_up_interruptible(&dev->bulk_in_wait); } static int skel_do_read_io(struct usb_skel *dev, size_t count) @@ -206,13 +205,16 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count) dev->ongoing_read = 1; spin_unlock_irq(&dev->err_lock); + /* submit bulk in urb, which means no data to deliver */ + dev->bulk_in_filled = 0; + dev->bulk_in_copied = 0; + /* do it */ rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); if (rv < 0) { dev_err(&dev->interface->dev, "%s - failed submitting read urb, error %d\n", __func__, rv); - dev->bulk_in_filled = 0; rv = (rv == -ENOMEM) ? rv : -EIO; spin_lock_irq(&dev->err_lock); dev->ongoing_read = 0; @@ -261,25 +263,9 @@ retry: * IO may take forever * hence wait in an interruptible state */ - rv = wait_for_completion_interruptible(&dev->bulk_in_completion); + rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read)); if (rv < 0) goto exit; - /* - * by waiting we also semiprocessed the urb - * we must finish now - */ - dev->bulk_in_copied = 0; - dev->processed_urb = 1; - } - - if (!dev->processed_urb) { - /* - * the URB hasn't been processed - * do it now - */ - wait_for_completion(&dev->bulk_in_completion); - dev->bulk_in_copied = 0; - dev->processed_urb = 1; } /* errors must be reported */ @@ -289,8 +275,6 @@ retry: dev->errors = 0; /* to preserve notifications about reset */ rv = (rv == -EPIPE) ? rv : -EIO; - /* no data to deliver */ - dev->bulk_in_filled = 0; /* report it */ goto exit; } @@ -526,7 +510,7 @@ static int skel_probe(struct usb_interface *interface, mutex_init(&dev->io_mutex); spin_lock_init(&dev->err_lock); init_usb_anchor(&dev->submitted); - init_completion(&dev->bulk_in_completion); + init_waitqueue_head(&dev->bulk_in_wait); dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig index 8bf19760d447..0e17b966e1b4 100644 --- a/drivers/usb/wusbcore/Kconfig +++ b/drivers/usb/wusbcore/Kconfig @@ -3,7 +3,6 @@ # config USB_WUSB tristate "Enable Wireless USB extensions" - depends on USB depends on PCI depends on UWB select CRYPTO @@ -19,7 +18,6 @@ config USB_WUSB config USB_WUSB_CBAF tristate "Support WUSB Cable Based Association (CBA)" - depends on USB help Some WUSB devices support Cable Based Association. It's used to enable the secure communication between the host and the |