diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/Kconfig | 27 | ||||
-rw-r--r-- | drivers/usb/host/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-ppc-of.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/fsl-mph-dr-of.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/max3421-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/oxu210hp-hcd.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/pci-quirks.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/u132-hcd.c | 3219 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dbgcap.c | 191 | ||||
-rw-r--r-- | drivers/usb/host/xhci-dbgcap.h | 4 | ||||
-rw-r--r-- | drivers/usb/host/xhci-debugfs.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 83 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mtk.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-mtk.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 215 | ||||
-rw-r--r-- | drivers/usb/host/xhci-plat.c | 19 | ||||
-rw-r--r-- | drivers/usb/host/xhci-rcar.c | 36 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-tegra.c | 17 | ||||
-rw-r--r-- | drivers/usb/host/xhci-trace.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/xhci-trace.h | 20 | ||||
-rw-r--r-- | drivers/usb/host/xhci.c | 202 | ||||
-rw-r--r-- | drivers/usb/host/xhci.h | 1 |
23 files changed, 479 insertions, 3587 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index eacb603ad1b2..c170672f847e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -622,33 +622,6 @@ config FHCI_DEBUG Say "y" to see some FHCI debug information and statistics through debugfs. -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB_FTDI_ELAN - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php> - config USB_SL811_HCD tristate "SL811HS HCD support" depends on HAS_IOMEM diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5a13712f367d..be4e5245c52f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o -obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 62a0a193798c..b3aa464e9d2c 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -151,13 +151,13 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) of_node_put(np); } - if (of_get_property(dn, "big-endian", NULL)) { + if (of_property_read_bool(dn, "big-endian")) { ehci->big_endian_mmio = 1; ehci->big_endian_desc = 1; } - if (of_get_property(dn, "big-endian-regs", NULL)) + if (of_property_read_bool(dn, "big-endian-regs")) ehci->big_endian_mmio = 1; - if (of_get_property(dn, "big-endian-desc", NULL)) + if (of_property_read_bool(dn, "big-endian-desc")) ehci->big_endian_desc = 1; ehci->caps = hcd->regs; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 46c6a152b865..9db909d12354 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -200,19 +200,16 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) dev_data = get_dr_mode_data(np); if (of_device_is_compatible(np, "fsl-usb2-mph")) { - if (of_get_property(np, "port0", NULL)) + if (of_property_present(np, "port0")) pdata->port_enables |= FSL_USB2_PORT0_ENABLED; - if (of_get_property(np, "port1", NULL)) + if (of_property_present(np, "port1")) pdata->port_enables |= FSL_USB2_PORT1_ENABLED; pdata->operating_mode = FSL_USB2_MPH_HOST; } else { - if (of_get_property(np, "fsl,invert-drvvbus", NULL)) - pdata->invert_drvvbus = 1; - - if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) - pdata->invert_pwr_fault = 1; + pdata->invert_drvvbus = of_property_read_bool(np, "fsl,invert-drvvbus"); + pdata->invert_pwr_fault = of_property_read_bool(np, "fsl,invert-pwr-fault"); /* setup mode selected in the device tree */ pdata->operating_mode = dev_data->op_mode; diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 28d1524ee2fa..d152d72de126 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1951,7 +1951,7 @@ static struct spi_driver max3421_driver = { .remove = max3421_remove, .driver = { .name = "max3421-hcd", - .of_match_table = of_match_ptr(max3421_of_match_table), + .of_match_table = max3421_of_match_table, }, }; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 3a441310c713..f998d3f1a78a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -169,7 +169,7 @@ struct ehci_regs { #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ /* PORTSC: offset 0x44 */ - u32 port_status[0]; /* up to N_PORTS */ + u32 port_status[]; /* up to N_PORTS */ /* 31:23 reserved */ #define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index ef08d68b9714..2665832f9add 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -207,8 +207,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); static void usb_amd_find_chipset_info(void) { unsigned long flags; - struct amd_chipset_info info; - info.need_pll_quirk = false; + struct amd_chipset_info info = { }; spin_lock_irqsave(&amd_lock, flags); @@ -218,7 +217,6 @@ static void usb_amd_find_chipset_info(void) spin_unlock_irqrestore(&amd_lock, flags); return; } - memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); if (!amd_chipset_sb_type_init(&info)) { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c deleted file mode 100644 index 95240c9c45bd..000000000000 --- a/drivers/usb/host/u132-hcd.c +++ /dev/null @@ -1,3219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* -* Host Controller Driver for the Elan Digital Systems U132 adapter -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB host drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/pci_ids.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/byteorder.h> - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name <linux/usb/ohci.h> - */ - -#include "ohci.h" -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); -MODULE_DESCRIPTION("U132 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -INT_MODULE_PARM(testing, 0); -/* Some boards misreport power switching/overcurrent*/ -static bool distrust_firmware = true; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent" - "t setup"); -static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); -/* -* u132_module_lock exists to protect access to global variables -* -*/ -static DEFINE_MUTEX(u132_module_lock); -static int u132_exiting; -static int u132_instances; -/* -* end of the global variables protected by u132_module_lock -*/ -static struct workqueue_struct *workqueue; -#define MAX_U132_PORTS 7 -#define MAX_U132_ADDRS 128 -#define MAX_U132_UDEVS 4 -#define MAX_U132_ENDPS 100 -#define MAX_U132_RINGS 4 -static const char *cc_to_text[16] = { - "No Error ", - "CRC Error ", - "Bit Stuff ", - "Data Togg ", - "Stall ", - "DevNotResp ", - "PIDCheck ", - "UnExpPID ", - "DataOver ", - "DataUnder ", - "(for hw) ", - "(for hw) ", - "BufferOver ", - "BuffUnder ", - "(for HCD) ", - "(for HCD) " -}; -struct u132_port { - struct u132 *u132; - int reset; - int enable; - int power; - int Status; -}; -struct u132_addr { - u8 address; -}; -struct u132_udev { - struct kref kref; - struct usb_device *usb_device; - u8 enumeration; - u8 udev_number; - u8 usb_addr; - u8 portnumber; - u8 endp_number_in[16]; - u8 endp_number_out[16]; -}; -#define ENDP_QUEUE_SHIFT 3 -#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT) -#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1) -struct u132_urbq { - struct list_head urb_more; - struct urb *urb; -}; -struct u132_spin { - spinlock_t slock; -}; -struct u132_endp { - struct kref kref; - u8 udev_number; - u8 endp_number; - u8 usb_addr; - u8 usb_endp; - struct u132 *u132; - struct list_head endp_ring; - struct u132_ring *ring; - unsigned toggle_bits:2; - unsigned active:1; - unsigned delayed:1; - unsigned input:1; - unsigned output:1; - unsigned pipetype:2; - unsigned dequeueing:1; - unsigned edset_flush:1; - unsigned spare_bits:14; - unsigned long jiffies; - struct usb_host_endpoint *hep; - struct u132_spin queue_lock; - u16 queue_size; - u16 queue_last; - u16 queue_next; - struct urb *urb_list[ENDP_QUEUE_SIZE]; - struct list_head urb_more; - struct delayed_work scheduler; -}; -struct u132_ring { - unsigned in_use:1; - unsigned length:7; - u8 number; - struct u132 *u132; - struct u132_endp *curr_endp; - struct delayed_work scheduler; -}; -struct u132 { - struct kref kref; - struct mutex sw_lock; - struct mutex scheduler_lock; - struct u132_platform_data *board; - struct platform_device *platform_dev; - struct u132_ring ring[MAX_U132_RINGS]; - int sequence_num; - int going; - int power; - int reset; - int num_ports; - u32 hc_control; - u32 hc_fminterval; - u32 hc_roothub_status; - u32 hc_roothub_a; - u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; - int flags; - unsigned long next_statechange; - struct delayed_work monitor; - int num_endpoints; - struct u132_addr addr[MAX_U132_ADDRS]; - struct u132_udev udev[MAX_U132_UDEVS]; - struct u132_port port[MAX_U132_PORTS]; - struct u132_endp *endp[MAX_U132_ENDPS]; -}; - -/* -* these cannot be inlines because we need the structure offset!! -* Does anyone have a better way????? -*/ -#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \ - offsetof(struct ohci_regs, member), 0, data) -#define u132_read_pcimem(u132, member, data) \ - usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -#define u132_write_pcimem(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -static inline struct u132 *udev_to_u132(struct u132_udev *udev) -{ - u8 udev_number = udev->udev_number; - return container_of(udev, struct u132, udev[udev_number]); -} - -static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) -{ - return (struct u132 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) -{ - return container_of((void *)u132, struct usb_hcd, hcd_priv); -} - -static inline void u132_disable(struct u132 *u132) -{ - u132_to_hcd(u132)->state = HC_STATE_HALT; -} - - -#define kref_to_u132(d) container_of(d, struct u132, kref) -#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) -#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) -#include "../misc/usb_u132.h" -static const char hcd_name[] = "u132_hcd"; -#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ - USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ - USB_PORT_STAT_C_RESET) << 16) -static void u132_hcd_delete(struct kref *kref) -{ - struct u132 *u132 = kref_to_u132(kref); - struct platform_device *pdev = u132->platform_dev; - struct usb_hcd *hcd = u132_to_hcd(u132); - u132->going += 1; - mutex_lock(&u132_module_lock); - u132_instances -= 1; - mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" - "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); - usb_put_hcd(hcd); -} - -static inline void u132_u132_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static inline void u132_u132_init_kref(struct u132 *u132) -{ - kref_init(&u132->kref); -} - -static void u132_udev_delete(struct kref *kref) -{ - struct u132_udev *udev = kref_to_u132_udev(kref); - udev->udev_number = 0; - udev->usb_device = NULL; - udev->usb_addr = 0; - udev->enumeration = 0; -} - -static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_put(&udev->kref, u132_udev_delete); -} - -static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_get(&udev->kref); -} - -static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) -{ - kref_init(&udev->kref); -} - -static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - if (delta > 0) { - if (queue_delayed_work(workqueue, &ring->scheduler, delta)) - return; - } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) - return; - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); -} - -static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) -{ - if (cancel_delayed_work(&ring->scheduler)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_endp_delete(struct kref *kref) -{ - struct u132_endp *endp = kref_to_u132_endp(kref); - struct u132 *u132 = endp->u132; - u8 usb_addr = endp->usb_addr; - u8 usb_endp = endp->usb_endp; - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - u8 endp_number = endp->endp_number; - struct usb_host_endpoint *hep = endp->hep; - struct u132_ring *ring = endp->ring; - struct list_head *head = &endp->endp_ring; - ring->length -= 1; - if (endp == ring->curr_endp) { - if (list_empty(head)) { - ring->curr_endp = NULL; - list_del(head); - } else { - struct u132_endp *next_endp = list_entry(head->next, - struct u132_endp, endp_ring); - ring->curr_endp = next_endp; - list_del(head); - } - } else - list_del(head); - if (endp->input) { - udev->endp_number_in[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - if (endp->output) { - udev->endp_number_out[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - u132->endp[endp_number - 1] = NULL; - hep->hcpriv = NULL; - kfree(endp); - u132_u132_put_kref(u132); -} - -static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_get(&endp->kref); -} - -static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) -{ - kref_init(&endp->kref); - kref_get(&u132->kref); -} - -static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) -{ - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); -} - -static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) -{ - if (cancel_delayed_work(&endp->scheduler)) - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_monitor_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) -{ - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_get(&u132->kref); -} - -static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) -{ - if (!queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_cancel_work(struct u132 *u132) -{ - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static int read_roothub_info(struct u132 *u132) -{ - u32 revision; - int retval; - retval = u132_read_pcimem(u132, revision, &revision); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } else if ((revision & 0xFF) == 0x10) { - } else if ((revision & 0xFF) == 0x11) { - } else { - dev_err(&u132->platform_dev->dev, "device revision is not valid" - " %08X\n", revision); - return -ENODEV; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.status, - &u132->hc_roothub_status); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.status\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.a\n", retval); - return retval; - } - { - int I = u132->num_ports; - int i = 0; - while (I-- > 0) { - retval = u132_read_pcimem(u132, roothub.portstatus[i], - &u132->hc_roothub_portstatus[i]); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d acc" - "essing device roothub.portstatus[%d]\n" - , retval, i); - return retval; - } else - i += 1; - } - } - return 0; -} - -static void u132_hcd_monitor_work(struct work_struct *work) -{ - struct u132 *u132 = container_of(work, struct u132, monitor.work); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - u132_monitor_put_kref(u132); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - u132_monitor_put_kref(u132); - return; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = read_roothub_info(u132); - if (retval) { - struct usb_hcd *hcd = u132_to_hcd(u132); - u132_disable(u132); - u132->going = 1; - mutex_unlock(&u132->sw_lock); - usb_hc_died(hcd); - ftdi_elan_gone_away(u132->platform_dev); - u132_monitor_put_kref(u132); - return; - } else { - u132_monitor_requeue_work(u132, 500); - mutex_unlock(&u132->sw_lock); - return; - } - } -} - -static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - struct u132_ring *ring; - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - u132_endp_put_kref(u132, endp); -} - -static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); -} - -static inline int edset_input(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_single(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_output(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - - -/* -* must not LOCK sw_lock -* -*/ -static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - if (urb->actual_length > 0) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - } else { - ring->in_use = 0; - endp->active = 0; - endp->jiffies = jiffies + - msecs_to_jiffies(urb->interval); - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - } - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 1 & toggle_bits); - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p givin" - "g back INTERRUPT %s\n", urb, - cc_to_text[condition_code]); - } - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - urb->actual_length += len; - endp->toggle_bits = toggle_bits; - if (urb->transfer_buffer_length > urb->actual_length) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - int retval; - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_DATAUNDERRUN) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" - ") giving back BULK IN %s\n", urb, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back B" - "ULK IN code=%d %s\n", urb, condition_code, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - if ((condition_code == TD_CC_NOERROR) || ((condition_code == - TD_DATAUNDERRUN) && ((urb->transfer_flags & - URB_SHORT_NOT_OK) == 0))) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0x3, - u132_hcd_configure_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, "giving back SETUP I" - "NPUT STALL urb %p\n", urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, "giving back SETUP IN" - "PUT %s urb %p\n", cc_to_text[condition_code], - urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - if (usb_pipein(urb->pipe)) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - u132->addr[0].address = 0; - endp->usb_addr = udev->usb_addr; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, 0, endp->usb_endp, 0, - u132_hcd_enumeration_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0x3, - u132_hcd_initial_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0, - u132_hcd_initial_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -/* -* this work function is only executed from the work queue -* -*/ -static void u132_hcd_ring_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring = - container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - mutex_lock(&u132->scheduler_lock); - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *endp, *last_endp = ring->curr_endp; - unsigned long wakeup = 0; - list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) { - if (endp->queue_next == endp->queue_last) { - } else if ((endp->delayed == 0) - || time_after_eq(jiffies, endp->jiffies)) { - ring->curr_endp = endp; - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - } - if (last_endp->queue_next == last_endp->queue_last) { - } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, - last_endp->jiffies)) { - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = last_endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - if (wakeup > 0) { - u132_ring_requeue_work(u132, ring, wakeup); - mutex_unlock(&u132->scheduler_lock); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } -} - -static void u132_hcd_endp_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring; - struct u132_endp *endp = - container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - if (endp->edset_flush) { - endp->edset_flush = 0; - if (endp->dequeueing) - usb_ftdi_elan_edset_flush(u132->platform_dev, - ring->number, endp); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->pipetype == PIPE_INTERRUPT) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else if (endp->pipetype == PIPE_CONTROL) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (address == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (endp->usb_addr == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - address = u132->addr[endp->usb_addr].address; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - if (endp->input) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_input(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } else { /* output pipe */ - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_output_sent); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } - } -} -#ifdef CONFIG_PM - -static void port_power(struct u132 *u132, int pn, int is_on) -{ - u132->port[pn].power = is_on; -} - -#endif - -static void u132_power(struct u132 *u132, int is_on) -{ - struct usb_hcd *hcd = u132_to_hcd(u132) - ; /* hub is inactive unless the port is powered */ - if (is_on) { - if (u132->power) - return; - u132->power = 1; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - } -} - -static int u132_periodic_reinit(struct u132 *u132) -{ - int retval; - u32 fi = u132->hc_fminterval & 0x03fff; - u32 fit; - u32 fminterval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - fit = fminterval & FIT; - retval = u132_write_pcimem(u132, fminterval, - (fit ^ FIT) | u132->hc_fminterval); - if (retval) - return retval; - return u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); -} - -static char *hcfs2string(int state) -{ - switch (state) { - case OHCI_USB_RESET: - return "reset"; - case OHCI_USB_RESUME: - return "resume"; - case OHCI_USB_OPER: - return "operational"; - case OHCI_USB_SUSPEND: - return "suspend"; - } - return "?"; -} - -static int u132_init(struct u132 *u132) -{ - int retval; - u32 control; - u132_disable(u132); - u132->next_statechange = jiffies; - retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (u132->num_ports == 0) { - u32 rh_a = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - u132->num_ports = rh_a & RH_A_NDP; - retval = read_roothub_info(u132); - if (retval) - return retval; - } - if (u132->num_ports > MAX_U132_PORTS) - return -EINVAL; - - return 0; -} - - -/* Start an OHCI controller, set the BUS operational -* resets USB and controller -* enable interrupts -*/ -static int u132_run(struct u132 *u132) -{ - int retval; - u32 control; - u32 status; - u32 fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int first = u132->hc_fminterval == 0; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - u132_disable(u132); - if (first) { - u32 temp; - retval = u132_read_pcimem(u132, fminterval, &temp); - if (retval) - return retval; - u132->hc_fminterval = temp & 0x3fff; - u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " - "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), - u132->hc_control); - switch (u132->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { - int temp; /* power down each port */ - for (temp = 0; temp < u132->num_ports; temp++) { - retval = u132_write_pcimem(u132, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; -retry: - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra: { - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, "USB HC reset" - " timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (u132->flags & OHCI_QUIRK_INITRESET) { - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, hcca, 0x00000000); - if (retval) - return retval; - retval = u132_periodic_reinit(u132); - if (retval) - return retval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - retval = u132_read_pcimem(u132, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(u132->flags & OHCI_QUIRK_INITRESET)) { - u132->flags |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" - "\n", fminterval, periodicstart); - } /* start controller operations */ - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrstatus, mask); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (u132->flags & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = u132_write_pcimem(u132, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - return 0; -} - -static void u132_hcd_stop(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" - "een removed %d\n", u132, hcd, u132->going); - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - } else { - mutex_lock(&u132->sw_lock); - msleep(100); - u132_power(u132, 0); - mutex_unlock(&u132->sw_lock); - } -} - -static int u132_hcd_start(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else if (hcd->self.controller) { - int retval; - struct platform_device *pdev = - to_platform_device(hcd->self.controller); - u16 vendor = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->vendor; - u16 device = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->device; - mutex_lock(&u132->sw_lock); - msleep(10); - if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { - u132->flags = OHCI_QUIRK_AMD756; - } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" - "ounds unavailable\n"); - } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) - u132->flags |= OHCI_QUIRK_ZFMICRO; - retval = u132_run(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - msleep(100); - mutex_unlock(&u132->sw_lock); - return retval; - } else { - dev_err(&u132->platform_dev->dev, "platform_device missing\n"); - return -ENODEV; - } -} - -static int u132_hcd_reset(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = u132_init(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); - return 0; -} - -static int queue_int_on_old_endpoint(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - int ring_number; - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - ring_number = 3; - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - ring_number = 2; - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - ring = endp->ring = &u132->ring[ring_number - 1]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - urb->hcpriv = u132; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; -} - -static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_control(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - u132_endp_init_kref(u132, endp); - u132_endp_get_kref(u132, endp); - if (usb_addr == 0) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_init_kref(u132, udev); - u132_udev_get_kref(u132, udev); - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_get_kref(u132, udev); - udev->enumeration = 2; - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } -} - -static int queue_control_on_old_endpoint(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp) -{ - if (usb_addr == 0) { - if (usb_pipein(urb->pipe)) { - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } else { /* usb_pipeout(urb->pipe) */ - struct u132_addr *addr = &u132->addr[usb_dev->devnum]; - int I = MAX_U132_UDEVS; - int i = 0; - while (--I > 0) { - struct u132_udev *udev = &u132->udev[++i]; - if (udev->usb_device) { - continue; - } else { - udev->enumeration = 1; - u132->addr[0].address = i; - endp->udev_number = i; - udev->udev_number = i; - udev->usb_addr = usb_dev->devnum; - u132_udev_init_kref(u132, udev); - udev->endp_number_in[usb_endp] = - endp->endp_number; - u132_udev_get_kref(u132, udev); - udev->endp_number_out[usb_endp] = - endp->endp_number; - udev->usb_device = usb_dev; - ((u8 *) (urb->setup_packet))[2] = - addr->address = i; - u132_udev_get_kref(u132, udev); - break; - } - } - if (I == 0) { - dev_err(&u132->platform_dev->dev, "run out of d" - "evice space\n"); - return -EINVAL; - } - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - urb->hcpriv = u132; - if (udev->enumeration != 2) - udev->enumeration = 2; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } -} - -static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (irqs_disabled()) { - if (gfpflags_allow_blocking(mem_flags)) { - printk(KERN_ERR "invalid context for function that might sleep\n"); - return -EINVAL; - } - } - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - return -ESHUTDOWN; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - struct usb_device *usb_dev = urb->dev; - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_int_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, - msecs_to_jiffies(urb->interval)) - ; - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { /*(endp == NULL) */ - return create_endpoint_and_queue_int(u132, udev, - urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, "the hardware does no" - "t support PIPE_ISOCHRONOUS\n"); - return -EINVAL; - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_bulk_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_bulk(u132, - udev, urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } else { - struct u132_endp *endp = urb->ep->hcpriv; - u16 urb_size = 8; - u8 *b = urb->setup_packet; - int i = 0; - char data[30 * 3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_control_on_old_endpoint( - u132, urb, usb_dev, - endp, usb_addr, - usb_endp); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_control(u132, - urb, usb_dev, usb_addr, usb_endp, - mem_flags); - } - } -} - -static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct u132_urbq *urbq; - - list_for_each_entry(urbq, &endp->urb_more, urb_more) { - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(&urbq->urb_more); - endp->queue_size -= 1; - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } - } - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" - "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" - "\n", urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - return -EINVAL; -} - -static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - int rc; - - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return rc; - } - if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" - "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } - if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { - if (endp->active) { - endp->dequeueing = 1; - endp->edset_flush = 1; - u132_endp_queue_work(u132, endp, 0); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return 0; - } else { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, status); - return 0; - } - } else { - u16 queue_list = 0; - u16 queue_size = endp->queue_size; - u16 queue_scan = endp->queue_next; - struct urb **urb_slot = NULL; - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - if (urb == endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]) { - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - break; - } - } - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]; - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - } - if (urb_slot) { - struct usb_hcd *hcd = u132_to_hcd(u132); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_size -= 1; - if (list_empty(&endp->urb_more)) { - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, - struct u132_urbq, urb_more); - list_del(next); - *urb_slot = urbq->urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - kfree(urbq); - } - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, status); - return 0; - } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in " - "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" - "=%d size=%d next=%04X last=%04X\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', - endp->output ? 'O' : ' ', endp->usb_endp, - endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } else { - int retval; - - usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); - retval = dequeue_from_overflow_chain(u132, endp, - urb); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return retval; - } - } -} - -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - if (usb_pipein(urb->pipe)) { - u8 endp_number = udev->endp_number_in[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } else { - u8 endp_number = udev->endp_number_out[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } - } -} - -static void u132_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" - ") has been removed %d\n", u132, hcd, hep, - u132->going); - } else { - struct u132_endp *endp = hep->hcpriv; - if (endp) - u132_endp_put_kref(u132, endp); - } -} - -static int u132_get_frame(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - mdelay(100); - return 0; - } -} - -static int u132_roothub_descriptor(struct u132 *u132, - struct usb_hub_descriptor *desc) -{ - int retval; - u16 temp; - u32 rh_a = -1; - u32 rh_b = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - desc->bDescriptorType = USB_DT_HUB; - desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = u132->num_ports; - temp = 1 + (u132->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM; - if (rh_a & RH_A_NPS) - temp |= HUB_CHAR_NO_LPSM; - if (rh_a & RH_A_PSM) - temp |= HUB_CHAR_INDV_PORT_LPSM; - if (rh_a & RH_A_NOCP) - temp |= HUB_CHAR_NO_OCPM; - else if (rh_a & RH_A_OCPM) - temp |= HUB_CHAR_INDV_PORT_OCPM; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else - desc->u.hs.DeviceRemovable[1] = 0xff; - return 0; -} - -static int u132_roothub_status(struct u132 *u132, __le32 *desc) -{ - u32 rh_status = -1; - int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); - *desc = cpu_to_le32(rh_status); - return ret_status; -} - -static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port = wIndex - 1; - u32 rh_portstatus = -1; - int ret_portstatus = u132_read_pcimem(u132, - roothub.portstatus[port], &rh_portstatus); - *desc = cpu_to_le32(rh_portstatus); - if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, "Port %d Status Chan" - "ge = %08X\n", port, *desc); - } - return ret_portstatus; - } -} - - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 -#define PORT_RESET_MSEC 10 -/* wrap-aware logic morphed from <linux/jiffies.h> */ -#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -static int u132_roothub_portreset(struct u132 *u132, int port_index) -{ - int retval; - u32 fmnumber; - u16 now; - u16 reset_done; - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - reset_done = now + PORT_RESET_MSEC; - do { - u32 portstat; - do { - retval = u132_read_pcimem(u132, - roothub.portstatus[port_index], &portstat); - if (retval) - return retval; - if (RH_PS_PRS & portstat) - continue; - else - break; - } while (tick_before(now, reset_done)); - if (RH_PS_PRS & portstat) - return -ENODEV; - if (RH_PS_CCS & portstat) { - if (RH_PS_PRSC & portstat) { - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], - RH_PS_PRSC); - if (retval) - return retval; - } - } else - break; /* start the next reset, - sleep till it's probably done */ - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - RH_PS_PRS); - if (retval) - return retval; - msleep(PORT_RESET_HW_MSEC); - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - } while (tick_before(now, reset_done)); - return 0; -} - -static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - case USB_PORT_FEAT_POWER: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - case USB_PORT_FEAT_RESET: - return u132_roothub_portreset(u132, port_index); - default: - return -EPIPE; - } - } -} - -static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - u32 temp; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - if ((u132->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, "TODO resume_" - "root_hub\n"); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - return -EPIPE; - } - return u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - } -} - - -/* the virtual root hub timer IRQ checks for hub status*/ -static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" - "ed %d\n", hcd, u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - return -ESHUTDOWN; - } else { - int i, changed = 0, length = 1; - if (u132->flags & OHCI_QUIRK_AMD756) { - if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, "bogus NDP, r" - "ereads as NDP=%d\n", - u132->hc_roothub_a & RH_A_NDP); - goto done; - } - } - if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - if (u132->num_ports > 7) { - buf[1] = 0; - length++; - } - for (i = 0; i < u132->num_ports; i++) { - if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | - RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | - RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - continue; - } - if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) - continue; - - if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) - continue; - } -done: - return changed ? length : 0; - } -} - -static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - mutex_lock(&u132->sw_lock); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case ClearPortFeature:{ - retval = u132_roothub_clearportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - case GetHubDescriptor:{ - retval = u132_roothub_descriptor(u132, - (struct usb_hub_descriptor *)buf); - if (retval) - goto error; - break; - } - case GetHubStatus:{ - retval = u132_roothub_status(u132, - (__le32 *) buf); - if (retval) - goto error; - break; - } - case GetPortStatus:{ - retval = u132_roothub_portstatus(u132, - (__le32 *) buf, wIndex); - if (retval) - goto error; - break; - } - case SetPortFeature:{ - retval = u132_roothub_setportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - default: - goto stall; - error: - u132_disable(u132); - u132->going = 1; - break; - stall: - retval = -EPIPE; - break; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - - -#ifdef CONFIG_PM -static int u132_bus_suspend(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -static int u132_bus_resume(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -#else -#define u132_bus_suspend NULL -#define u132_bus_resume NULL -#endif -static const struct hc_driver u132_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct u132), - .irq = NULL, - .flags = HCD_USB11 | HCD_MEMORY, - .reset = u132_hcd_reset, - .start = u132_hcd_start, - .stop = u132_hcd_stop, - .urb_enqueue = u132_urb_enqueue, - .urb_dequeue = u132_urb_dequeue, - .endpoint_disable = u132_endpoint_disable, - .get_frame_number = u132_get_frame, - .hub_status_data = u132_hub_status_data, - .hub_control = u132_hub_control, - .bus_suspend = u132_bus_suspend, - .bus_resume = u132_bus_resume, - .start_port_reset = u132_start_port_reset, -}; - -/* -* This function may be called by the USB core whilst the "usb_all_devices_rwsem" -* is held for writing, thus this module must not call usb_remove_hcd() -* synchronously - but instead should immediately stop activity to the -* device and asynchronously call usb_remove_hcd() -*/ -static int u132_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - if (hcd) { - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, "already being remove" - "d\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, "removing device u132" - ".%d\n", u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } - while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } - } else - return 0; -} - -static void u132_initialise(struct u132 *u132, struct platform_device *pdev) -{ - int rings = MAX_U132_RINGS; - int ports = MAX_U132_PORTS; - int addrs = MAX_U132_ADDRS; - int udevs = MAX_U132_UDEVS; - int endps = MAX_U132_ENDPS; - u132->board = dev_get_platdata(&pdev->dev); - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - mutex_init(&u132->scheduler_lock); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - ring->u132 = u132; - ring->number = rings + 1; - ring->length = 0; - ring->curr_endp = NULL; - INIT_DELAYED_WORK(&ring->scheduler, - u132_hcd_ring_work_scheduler); - } - mutex_lock(&u132->sw_lock); - INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); - while (ports-- > 0) { - struct u132_port *port = &u132->port[ports]; - port->u132 = u132; - port->reset = 0; - port->enable = 0; - port->power = 0; - port->Status = 0; - } - while (addrs-- > 0) { - struct u132_addr *addr = &u132->addr[addrs]; - addr->address = 0; - } - while (udevs-- > 0) { - struct u132_udev *udev = &u132->udev[udevs]; - int i = ARRAY_SIZE(udev->endp_number_in); - int o = ARRAY_SIZE(udev->endp_number_out); - udev->usb_device = NULL; - udev->udev_number = 0; - udev->usb_addr = 0; - udev->portnumber = 0; - while (i-- > 0) - udev->endp_number_in[i] = 0; - - while (o-- > 0) - udev->endp_number_out[o] = 0; - - } - while (endps-- > 0) - u132->endp[endps] = NULL; - - mutex_unlock(&u132->sw_lock); -} - -static int u132_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - - msleep(100); - if (u132_exiting > 0) - return -ENODEV; - - retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); - if (retval) - return retval; - - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - struct u132 *u132 = hcd_to_u132(hcd); - retval = 0; - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - u132->sequence_num = ++u132_instances; - mutex_unlock(&u132_module_lock); - u132_u132_init_kref(u132); - u132_initialise(u132, pdev); - hcd->product_desc = "ELAN U132 Host Controller"; - retval = usb_add_hcd(hcd, 0, 0); - if (retval != 0) { - dev_err(&u132->platform_dev->dev, "init error %d\n", - retval); - u132_u132_put_kref(u132); - return retval; - } else { - device_wakeup_enable(hcd->self.controller); - u132_monitor_queue_work(u132, 100); - return 0; - } - } -} - - -#ifdef CONFIG_PM -/* - * for this device there's no useful distinction between the controller - * and its root hub. - */ -static int u132_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0, ports; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = u132_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 0); - } - break; - } - return retval; - } -} - -static int u132_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - if (!u132->port[0].power) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - retval = u132_bus_resume(hcd); - } - return retval; - } -} - -#else -#define u132_suspend NULL -#define u132_resume NULL -#endif -/* -* this driver is loaded explicitly by ftdi_u132 -* -* the platform_driver struct is static because it is per type of module -*/ -static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = u132_remove, - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = hcd_name, - }, -}; -static int __init u132_hcd_init(void) -{ - int retval; - u132_instances = 0; - u132_exiting = 0; - if (usb_disabled()) - return -ENODEV; - workqueue = create_singlethread_workqueue("u132"); - if (!workqueue) - return -ENOMEM; - retval = platform_driver_register(&u132_platform_driver); - if (retval) - destroy_workqueue(workqueue); - - return retval; -} - - -module_init(u132_hcd_init); -static void __exit u132_hcd_exit(void) -{ - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - destroy_workqueue(workqueue); -} - - -module_exit(u132_hcd_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:u132_hcd"); diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index f1367b53b260..b40d9238d447 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -124,10 +124,10 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) /* Set DbC context and info registers: */ lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); - dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); + dev_info = (dbc->idVendor << 16) | dbc->bInterfaceProtocol; writel(dev_info, &dbc->regs->devinfo1); - dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID); + dev_info = (dbc->bcdDevice << 16) | dbc->idProduct; writel(dev_info, &dbc->regs->devinfo2); } @@ -971,7 +971,186 @@ static ssize_t dbc_store(struct device *dev, return count; } +static ssize_t dbc_idVendor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idVendor); +} + +static ssize_t dbc_idVendor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u16 value; + u32 dev_info; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idVendor = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_idProduct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idProduct); +} + +static ssize_t dbc_idProduct_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idProduct = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu)) | value; + writel(dev_info, ptr); + return size; +} + +static ssize_t dbc_bcdDevice_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->bcdDevice); +} + +static ssize_t dbc_bcdDevice_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bcdDevice = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_bInterfaceProtocol_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol); +} + +static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u8 value; + int ret; + + /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */ + ret = kstrtou8(buf, 0, &value); + if (ret || value > 1) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bInterfaceProtocol = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffu)) | value; + writel(dev_info, ptr); + + return size; +} + static DEVICE_ATTR_RW(dbc); +static DEVICE_ATTR_RW(dbc_idVendor); +static DEVICE_ATTR_RW(dbc_idProduct); +static DEVICE_ATTR_RW(dbc_bcdDevice); +static DEVICE_ATTR_RW(dbc_bInterfaceProtocol); + +static struct attribute *dbc_dev_attributes[] = { + &dev_attr_dbc.attr, + &dev_attr_dbc_idVendor.attr, + &dev_attr_dbc_idProduct.attr, + &dev_attr_dbc_bcdDevice.attr, + &dev_attr_dbc_bInterfaceProtocol.attr, + NULL +}; + +static const struct attribute_group dbc_dev_attrib_grp = { + .attrs = dbc_dev_attributes, +}; struct xhci_dbc * xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver) @@ -986,6 +1165,10 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->regs = base; dbc->dev = dev; dbc->driver = driver; + dbc->idProduct = DBC_PRODUCT_ID; + dbc->idVendor = DBC_VENDOR_ID; + dbc->bcdDevice = DBC_DEVICE_REV; + dbc->bInterfaceProtocol = DBC_PROTOCOL; if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) goto err; @@ -993,7 +1176,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); - ret = device_create_file(dev, &dev_attr_dbc); + ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp); if (ret) goto err; @@ -1012,7 +1195,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc) xhci_dbc_stop(dbc); /* remove sysfs files */ - device_remove_file(dbc->dev, &dev_attr_dbc); + sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp); kfree(dbc); } diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index ca04192fdab1..51a7ab3ba0ca 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -132,6 +132,10 @@ struct xhci_dbc { struct dbc_str_descs *string; dma_addr_t string_dma; size_t string_size; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 bInterfaceProtocol; enum dbc_state state; struct delayed_work event_work; diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 0bc7fe11f749..99baa60ef50f 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -133,6 +133,7 @@ static void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base, regset->regs = regs; regset->nregs = nregs; regset->base = hcd->regs + base; + regset->dev = hcd->self.controller; debugfs_create_regset32((const char *)rgs->name, 0444, parent, regset); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d0a9467aa5fc..7e106bd804ca 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -9,6 +9,7 @@ */ #include <linux/usb.h> +#include <linux/overflow.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/dmapool.h> @@ -543,14 +544,11 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; if (size > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(dev, size, - stream_ctx, dma); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_free(xhci->small_streams_pool, - stream_ctx, dma); + dma_free_coherent(dev, size, stream_ctx, dma); + else if (size > SMALL_STREAM_ARRAY_SIZE) + dma_pool_free(xhci->medium_streams_pool, stream_ctx, dma); else - return dma_pool_free(xhci->medium_streams_pool, - stream_ctx, dma); + dma_pool_free(xhci->small_streams_pool, stream_ctx, dma); } /* @@ -568,17 +566,14 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, gfp_t mem_flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; + size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(dev, size, - dma, mem_flags); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_alloc(xhci->small_streams_pool, - mem_flags, dma); + return dma_alloc_coherent(dev, size, dma, mem_flags); + if (size > SMALL_STREAM_ARRAY_SIZE) + return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma); else - return dma_pool_alloc(xhci->medium_streams_pool, - mem_flags, dma); + return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma); } struct xhci_ring *xhci_dma_to_transfer_ring( @@ -612,8 +607,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, int ret; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - xhci_dbg(xhci, "Allocating %u streams and %u " - "stream context array entries.\n", + xhci_dbg(xhci, "Allocating %u streams and %u stream context array entries.\n", num_streams, num_stream_ctxs); if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); @@ -642,8 +636,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, mem_flags); if (!stream_info->stream_ctx_array) goto cleanup_ring_array; - memset(stream_info->stream_ctx_array, 0, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs); /* Allocate everything needed to free the stream rings later */ stream_info->free_streams_command = @@ -673,8 +665,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_ring->cycle_state; stream_info->stream_ctx_array[cur_stream].stream_ring = cpu_to_le64(addr); - xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", - cur_stream, (unsigned long long) addr); + xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr); ret = xhci_update_stream_mapping(cur_ring, mem_flags); if (ret) { @@ -984,16 +975,14 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, if (!dev->out_ctx) goto fail; - xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->out_ctx->dma); + xhci_dbg(xhci, "Slot %d output ctx = 0x%pad (dma)\n", slot_id, &dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; - xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->in_ctx->dma); + xhci_dbg(xhci, "Slot %d input ctx = 0x%pad (dma)\n", slot_id, &dev->in_ctx->dma); /* Initialize the cancellation and bandwidth list for each ep */ for (i = 0; i < 31; i++) { @@ -1400,8 +1389,9 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev, if ((udev->speed >= USB_SPEED_SUPER_PLUS) && USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ - else if (udev->speed >= USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER) return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); max_packet = usb_endpoint_maxp(&ep->desc); @@ -1660,7 +1650,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) goto fail_sp; xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - num_sp * sizeof(u64), + size_mul(sizeof(u64), num_sp), &xhci->scratchpad->sp_dma, flags); if (!xhci->scratchpad->sp_array) goto fail_sp2; @@ -1685,11 +1675,10 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) return 0; fail_sp4: - for (i = i - 1; i >= 0; i--) { + while (i--) dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_array[i]); - } kfree(xhci->scratchpad->sp_buffers); @@ -1799,7 +1788,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_segment *seg; struct xhci_erst_entry *entry; - size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; + size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs); erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, size, &erst->erst_dma_addr, flags); if (!erst->entries) @@ -1830,7 +1819,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) if (!ir) return; - erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries); + erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; if (ir->erst.entries) dma_free_coherent(dev, erst_size, ir->erst.entries, @@ -1960,8 +1949,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, ir->event_ring->dequeue); if (!deq) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; @@ -1970,8 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter */ temp &= ~ERST_EHB; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write event ring dequeue pointer, " - "preserving EHB bit"); + "// Write event ring dequeue pointer, preserving EHB bit"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &ir->ir_set->erst_dequeue); } @@ -2004,8 +1991,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { - xhci_warn(xhci, "Ignoring unknown port speed, " - "Ext Cap %p, revision = 0x%x\n", + xhci_warn(xhci, "Ignoring unknown port speed, Ext Cap %p, revision = 0x%x\n", addr, major_revision); /* Ignoring port protocol we can't understand. FIXME */ return; @@ -2020,9 +2006,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x", - addr, port_offset, port_count, major_revision); + "Ext Cap %p, port offset = %u, count = %u, revision = 0x%x", + addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ @@ -2079,10 +2064,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, struct xhci_port *hw_port = &xhci->hw_ports[i]; /* Duplicate entry. Ignore the port if the revisions differ. */ if (hw_port->rhub) { - xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," - " port %u\n", addr, i); - xhci_warn(xhci, "Port was marked as USB %u, " - "duplicated as USB %u\n", + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p, port %u\n", addr, i); + xhci_warn(xhci, "Port was marked as USB %u, duplicated as USB %u\n", hw_port->rhub->maj_rev, major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. @@ -2358,8 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci->dcbaa->dma = dma; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Device context base array address = 0x%llx (DMA), %p (virt)", - (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); + "// Device context base array address = 0x%pad (DMA), %p (virt)", + &xhci->dcbaa->dma, xhci->dcbaa); xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* @@ -2400,8 +2383,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx", - (unsigned long long)xhci->cmd_ring->first_seg->dma); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", + &xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); @@ -2421,8 +2404,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) val = readl(&xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Doorbell array is located at offset 0x%x" - " from cap regs base addr", val); + "// Doorbell array is located at offset 0x%x from cap regs base addr", + val); xhci->dba = (void __iomem *) xhci->cap_regs + val; /* Set ir_set to interrupt register set 0 */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index f7cbb08fc506..90cf40d6d0c3 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -398,6 +398,7 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) clks[2].id = "ref_ck"; clks[3].id = "mcu_ck"; clks[4].id = "dma_ck"; + clks[5].id = "frmcnt_ck"; return devm_clk_bulk_get_optional(mtk->dev, BULK_CLKS_NUM, clks); } diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 1174a510dd38..faaaf05e36ce 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -15,7 +15,7 @@ #include "xhci.h" -#define BULK_CLKS_NUM 5 +#define BULK_CLKS_NUM 6 #define BULK_VREGS_NUM 2 /* support at most 64 ep, use 32 size hash table */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 6db07ca419c3..ddb79f23fb3b 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,14 +78,207 @@ static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; static int xhci_pci_setup(struct usb_hcd *hcd); +static int xhci_pci_run(struct usb_hcd *hcd); static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .reset = xhci_pci_setup, + .start = xhci_pci_run, .update_hub_device = xhci_pci_update_hub_device, }; +static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + + if (hcd->msix_enabled) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int i; + + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(pci_irq_vector(pdev, i)); + } +} + +/* Free any IRQs and disable MSI-X */ +static void xhci_cleanup_msix(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (xhci->quirks & XHCI_PLAT) + return; + + /* return if using legacy interrupt */ + if (hcd->irq > 0) + return; + + if (hcd->msix_enabled) { + int i; + + for (i = 0; i < xhci->msix_count; i++) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + } else { + free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); + } + + pci_free_irq_vectors(pdev); + hcd->msix_enabled = 0; +} + +/* + * Set up MSI + */ +static int xhci_setup_msi(struct xhci_hcd *xhci) +{ + int ret; + /* + * TODO:Check with MSI Soc for sysdev + */ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate MSI entry"); + return ret; + } + + ret = request_irq(pdev->irq, xhci_msi_irq, + 0, "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "disable MSI interrupt"); + pci_free_irq_vectors(pdev); + } + + return ret; +} + +/* + * Set up MSI-X + */ +static int xhci_setup_msix(struct xhci_hcd *xhci) +{ + int i, ret; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * calculate number of msi-x vectors supported. + * - HCS_MAX_INTRS: the max number of interrupts the host can handle, + * with max number of interrupters based on the xhci HCSPARAMS1. + * - num_online_cpus: maximum msi-x vectors per CPUs core. + * Add additional 1 vector to ensure always available interrupt. + */ + xhci->msix_count = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); + + ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, + PCI_IRQ_MSIX); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Failed to enable MSI-X"); + return ret; + } + + for (i = 0; i < xhci->msix_count; i++) { + ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, + "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) + goto disable_msix; + } + + hcd->msix_enabled = 1; + return ret; + +disable_msix: + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); + while (--i >= 0) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + pci_free_irq_vectors(pdev); + return ret; +} + +static int xhci_try_enable_msi(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev; + int ret; + + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + /* + * Some Fresco Logic host controllers advertise MSI, but fail to + * generate interrupts. Don't even try to enable MSI. + */ + if (xhci->quirks & XHCI_BROKEN_MSI) + goto legacy_irq; + + /* unregister the legacy interrupt */ + if (hcd->irq) + free_irq(hcd->irq, hcd); + hcd->irq = 0; + + ret = xhci_setup_msix(xhci); + if (ret) + /* fall back to msi*/ + ret = xhci_setup_msi(xhci); + + if (!ret) { + hcd->msi_enabled = 1; + return 0; + } + + if (!pdev->irq) { + xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); + return -EINVAL; + } + + legacy_irq: + if (!strlen(hcd->irq_descr)) + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", + hcd->driver->description, hcd->self.busnum); + + /* fall back to legacy interrupt*/ + ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, + hcd->irq_descr, hcd); + if (ret) { + xhci_err(xhci, "request interrupt %d failed\n", + pdev->irq); + return ret; + } + hcd->irq = pdev->irq; + return 0; +} + +static int xhci_pci_run(struct usb_hcd *hcd) +{ + int ret; + + if (usb_hcd_is_primary_hcd(hcd)) { + ret = xhci_try_enable_msi(hcd); + if (ret) + return ret; + } + + return xhci_run(hcd); +} + +static void xhci_pci_stop(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + xhci_stop(hcd); + + if (usb_hcd_is_primary_hcd(hcd)) + xhci_cleanup_msix(xhci); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -535,7 +728,6 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_hcd_pci_remove(dev); } -#ifdef CONFIG_PM /* * In some Intel xHCI controllers, in order to get D3 working, * through a vendor specific SSIC CONFIG register at offset 0x883c, @@ -622,6 +814,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) xhci_sparse_control_quirk(hcd); ret = xhci_suspend(xhci, do_wakeup); + + /* synchronize irq when using MSI-X */ + xhci_msix_sync_irqs(xhci); + if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED)) xhci_ssic_port_unused_quirk(hcd, false); @@ -724,12 +920,12 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); xhci_shutdown(hcd); + xhci_cleanup_msix(xhci); /* Yet another workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) pci_set_power_state(pdev, PCI_D3hot); } -#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -771,22 +967,19 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM .driver = { - .pm = &usb_hcd_pci_pm_ops + .pm = pm_ptr(&usb_hcd_pci_pm_ops), }, -#endif }; static int __init xhci_pci_init(void) { xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides); -#ifdef CONFIG_PM - xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend; - xhci_pci_hc_driver.pci_resume = xhci_pci_resume; - xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late; - xhci_pci_hc_driver.shutdown = xhci_pci_shutdown; -#endif + xhci_pci_hc_driver.pci_suspend = pm_ptr(xhci_pci_suspend); + xhci_pci_hc_driver.pci_resume = pm_ptr(xhci_pci_resume); + xhci_pci_hc_driver.pci_poweroff_late = pm_ptr(xhci_pci_poweroff_late); + xhci_pci_hc_driver.shutdown = pm_ptr(xhci_pci_shutdown); + xhci_pci_hc_driver.stop = xhci_pci_stop; return pci_register_driver(&xhci_pci_driver); } module_init(xhci_pci_init); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index b9f9625467d6..b0c8e8efc43b 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -291,6 +291,21 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s goto dealloc_usb2_hcd; } + xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, + "usb-phy", 1); + if (IS_ERR(xhci->shared_hcd->usb_phy)) { + if (PTR_ERR(xhci->shared_hcd->usb_phy) != -ENODEV) + dev_err(sysdev, "%s get usb3phy fail (ret=%d)\n", + __func__, + (int)PTR_ERR(xhci->shared_hcd->usb_phy)); + xhci->shared_hcd->usb_phy = NULL; + } else { + ret = usb_phy_init(xhci->shared_hcd->usb_phy); + if (ret) + dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n", + __func__, ret); + } + xhci->shared_hcd->tpl_support = hcd->tpl_support; } @@ -362,10 +377,8 @@ static int xhci_generic_plat_probe(struct platform_device *pdev) if (is_of_node(sysdev->fwnode) || is_acpi_device_node(sysdev->fwnode)) break; -#ifdef CONFIG_PCI - else if (sysdev->bus == &pci_bus_type) + else if (dev_is_pci(sysdev)) break; -#endif } if (!sysdev) diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 7f18509a1d39..ad966b797b89 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -12,26 +12,22 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/usb/phy.h> -#include <linux/sys_soc.h> #include "xhci.h" #include "xhci-plat.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" -#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem" #define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem" /* -* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x) -* - The V2 firmware is for r8a7795 ES1.x. +* - The V3 firmware is for all R-Car Gen3 * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * performance degradation. So, this driver continues to use the V1 if R-Car * Gen2. * - The V1 firmware is impossible to use on R-Car Gen3. */ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1); -MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); /*** Register Offset ***/ @@ -78,18 +74,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); #define RCAR_USB3_RX_POL_VAL BIT(21) #define RCAR_USB3_TX_POL_VAL BIT(4) -/* For soc_device_attribute */ -#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ -#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */ - -static const struct soc_device_attribute rcar_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = (void *)RCAR_XHCI_FIRMWARE_V2, - }, - { /* sentinel */ } -}; - static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ @@ -135,9 +119,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) const struct firmware *fw; int retval, index, j; u32 data, val, temp; - u32 quirks = 0; - const struct soc_device_attribute *attr; - const char *firmware_name; /* * According to the datasheet, "Upon the completion of FW Download, @@ -146,19 +127,8 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) if (readl(regs + RCAR_USB3_DL_CTRL) & RCAR_USB3_DL_CTRL_FW_SUCCESS) return 0; - attr = soc_device_match(rcar_quirks_match); - if (attr) - quirks = (uintptr_t)attr->data; - - if (quirks & RCAR_XHCI_FIRMWARE_V2) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; - else if (quirks & RCAR_XHCI_FIRMWARE_V3) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; - else - firmware_name = priv->firmware_name; - /* request R-Car USB3.0 firmware */ - retval = request_firmware(&fw, firmware_name, dev); + retval = request_firmware(&fw, priv->firmware_name, dev); if (retval) return retval; @@ -312,7 +282,7 @@ static struct platform_driver usb_xhci_renesas_driver = { .driver = { .name = "xhci-renesas-hcd", .pm = &xhci_plat_pm_ops, - .of_match_table = of_match_ptr(usb_xhci_of_match), + .of_match_table = usb_xhci_of_match, }, }; module_platform_driver(usb_xhci_renesas_driver); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index eb788c60c1c0..1ad12d5a4857 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3106,6 +3106,7 @@ irqreturn_t xhci_msi_irq(int irq, void *hcd) { return xhci_irq(hcd); } +EXPORT_SYMBOL_GPL(xhci_msi_irq); /**** Endpoint Ring Operations ****/ diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index a88c39e525c2..c75d93244143 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1535,7 +1535,6 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) static int tegra_xusb_probe(struct platform_device *pdev) { - struct of_phandle_args args; struct tegra_xusb *tegra; struct device_node *np; struct resource *regs; @@ -1594,15 +1593,13 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_padctl; } - /* Older device-trees don't have padctrl interrupt */ - err = of_irq_parse_one(np, 0, &args); - if (!err) { - tegra->padctl_irq = of_irq_get(np, 0); - if (tegra->padctl_irq <= 0) { - err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq; - goto put_padctl; - } - } else { + tegra->padctl_irq = of_irq_get(np, 0); + if (tegra->padctl_irq == -EPROBE_DEFER) { + err = tegra->padctl_irq; + goto put_padctl; + } else if (tegra->padctl_irq <= 0) { + /* Older device-trees don't have padctrl interrupt */ + tegra->padctl_irq = 0; dev_dbg(&pdev->dev, "%pOF is missing an interrupt, disabling PM support\n", np); } diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c index d0070814d1ea..062662d23241 100644 --- a/drivers/usb/host/xhci-trace.c +++ b/drivers/usb/host/xhci-trace.c @@ -12,3 +12,4 @@ #include "xhci-trace.h" EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks); +EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_init); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 61e93a3540a7..4286dba5b157 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -120,7 +120,6 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __field(u32, field1) __field(u32, field2) __field(u32, field3) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -130,8 +129,8 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __entry->field3 = le32_to_cpu(trb->field[3]); ), TP_printk("%s: %s", xhci_ring_type_string(__entry->type), - xhci_decode_trb(__get_str(str), XHCI_MSG_MAX, __entry->field0, __entry->field1, - __entry->field2, __entry->field3) + xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0, + __entry->field1, __entry->field2, __entry->field3) ) ); @@ -322,7 +321,6 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -330,7 +328,7 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", xhci_decode_ep_context(__get_str(str), + TP_printk("%s", xhci_decode_ep_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) ); @@ -368,7 +366,6 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __field(u32, info2) __field(u32, tt_info) __field(u32, state) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->dev_info); @@ -376,7 +373,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __entry->tt_info = le64_to_cpu(ctx->tt_info); __entry->state = le32_to_cpu(ctx->dev_state); ), - TP_printk("%s", xhci_decode_slot_context(__get_str(str), + TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->tt_info, __entry->state) ) @@ -433,13 +430,12 @@ DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx, TP_STRUCT__entry( __field(u32, drop) __field(u32, add) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags); __entry->add = le32_to_cpu(ctrl_ctx->add_flags); ), - TP_printk("%s", xhci_decode_ctrl_ctx(__get_str(str), __entry->drop, __entry->add) + TP_printk("%s", xhci_decode_ctrl_ctx(__get_buf(XHCI_MSG_MAX), __entry->drop, __entry->add) ) ); @@ -525,7 +521,6 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -533,7 +528,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - xhci_decode_portsc(__get_str(str), __entry->portsc) + xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) ) ); @@ -558,14 +553,13 @@ DECLARE_EVENT_CLASS(xhci_log_doorbell, TP_STRUCT__entry( __field(u32, slot) __field(u32, doorbell) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->slot = slot; __entry->doorbell = doorbell; ), TP_printk("Ring doorbell for %s", - xhci_decode_doorbell(__get_str(str), __entry->slot, __entry->doorbell) + xhci_decode_doorbell(__get_buf(XHCI_MSG_MAX), __entry->slot, __entry->doorbell) ) ); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6307bae9cddf..78790dc13c5f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -322,192 +322,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) return 0; } -#ifdef CONFIG_USB_PCI -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - /* - * TODO:Check with MSI Soc for sysdev - */ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "failed to allocate MSI entry"); - return ret; - } - - ret = request_irq(pdev->irq, xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "disable MSI interrupt"); - pci_free_irq_vectors(pdev); - } - - return ret; -} - -/* - * Set up MSI-X - */ -static int xhci_setup_msix(struct xhci_hcd *xhci) -{ - int i, ret; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * calculate number of msi-x vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. - * - num_online_cpus: maximum msi-x vectors per CPUs core. - * Add additional 1 vector to ensure always available interrupt. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, - PCI_IRQ_MSIX); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Failed to enable MSI-X"); - return ret; - } - - for (i = 0; i < xhci->msix_count; i++) { - ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, - "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; - } - - hcd->msix_enabled = 1; - return ret; - -disable_msix: - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); - while (--i >= 0) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - pci_free_irq_vectors(pdev); - return ret; -} - -/* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - if (xhci->quirks & XHCI_PLAT) - return; - - /* return if using legacy interrupt */ - if (hcd->irq > 0) - return; - - if (hcd->msix_enabled) { - int i; - - for (i = 0; i < xhci->msix_count; i++) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - } else { - free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); - } - - pci_free_irq_vectors(pdev); - hcd->msix_enabled = 0; -} - -static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - - if (hcd->msix_enabled) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int i; - - for (i = 0; i < xhci->msix_count; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - } -} - -static int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev; - int ret; - - /* The xhci platform device has set up IRQs through usb_add_hcd. */ - if (xhci->quirks & XHCI_PLAT) - return 0; - - pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - /* - * Some Fresco Logic host controllers advertise MSI, but fail to - * generate interrupts. Don't even try to enable MSI. - */ - if (xhci->quirks & XHCI_BROKEN_MSI) - goto legacy_irq; - - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (!ret) { - hcd->msi_enabled = 1; - return 0; - } - - if (!pdev->irq) { - xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); - return -EINVAL; - } - - legacy_irq: - if (!strlen(hcd->irq_descr)) - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", - hcd->driver->description, hcd->self.busnum); - - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return ret; - } - hcd->irq = pdev->irq; - return 0; -} - -#else - -static inline int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - return 0; -} - -static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ -} - -static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ -} - -#endif - static void compliance_mode_recovery(struct timer_list *t) { struct xhci_hcd *xhci; @@ -705,10 +519,6 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); - ret = xhci_try_enable_msi(hcd); - if (ret) - return ret; - temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -758,7 +568,7 @@ EXPORT_SYMBOL_GPL(xhci_run); * Disable device contexts, disable IRQs, and quiesce the HC. * Reset the HC, finish any completed transactions, and cleanup memory. */ -static void xhci_stop(struct usb_hcd *hcd) +void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -781,8 +591,6 @@ static void xhci_stop(struct usb_hcd *hcd) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { @@ -809,6 +617,7 @@ static void xhci_stop(struct usb_hcd *hcd) readl(&xhci->op_regs->status)); mutex_unlock(&xhci->mutex); } +EXPORT_SYMBOL_GPL(xhci_stop); /* * Shutdown HC (not bus-specific) @@ -850,8 +659,6 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_shutdown completed - status = %x", readl(&xhci->op_regs->status)); @@ -1143,10 +950,6 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) __func__); } - /* step 5: remove core well power */ - /* synchronize irq when using MSI-X */ - xhci_msix_sync_irqs(xhci); - return rc; } EXPORT_SYMBOL_GPL(xhci_suspend); @@ -1250,7 +1053,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) spin_unlock_irq(&xhci->lock); if (retval) return retval; - xhci_cleanup_msix(xhci); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 786002bb35db..08d721921b7b 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2125,6 +2125,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); +void xhci_stop(struct usb_hcd *hcd); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, |