diff options
Diffstat (limited to 'drivers/usb/host')
44 files changed, 5933 insertions, 3055 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index bf8be2a41a4a..33b467a8352d 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -4,6 +4,19 @@ comment "USB Host Controller Drivers" depends on USB +config USB_C67X00_HCD + tristate "Cypress C67x00 HCD support" + depends on USB + help + The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role + host/peripheral/OTG USB controllers. + + Enable this option to support this chip in host controller mode. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called c67x00. + config USB_EHCI_HCD tristate "EHCI HCD (USB 2.0) support" depends on USB && USB_ARCH_HAS_EHCI @@ -30,8 +43,8 @@ config USB_EHCI_HCD module will be called ehci-hcd. config USB_EHCI_ROOT_HUB_TT - bool "Root Hub Transaction Translators (EXPERIMENTAL)" - depends on USB_EHCI_HCD && EXPERIMENTAL + bool "Root Hub Transaction Translators" + depends on USB_EHCI_HCD ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -95,6 +108,32 @@ config USB_ISP116X_HCD To compile this driver as a module, choose M here: the module will be called isp116x-hcd. +config USB_ISP1760_HCD + tristate "ISP 1760 HCD support" + depends on USB && EXPERIMENTAL + ---help--- + The ISP1760 chip is a USB 2.0 host controller. + + This driver does not support isochronous transfers or OTG. + + To compile this driver as a module, choose M here: the + module will be called isp1760-hcd. + +config USB_ISP1760_PCI + bool "Support for the PCI bus" + depends on USB_ISP1760_HCD && PCI + ---help--- + Enables support for the device present on the PCI bus. + This should only be required if you happen to have the eval kit from + NXP and you are going to test it. + +config USB_ISP1760_OF + bool "Support for the OF platform bus" + depends on USB_ISP1760_HCD && OF + ---help--- + Enables support for the device present on the PowerPC + OpenFirmware platform bus. + config USB_OHCI_HCD tristate "OHCI HCD support" depends on USB && USB_ARCH_HAS_OHCI @@ -260,3 +299,9 @@ config USB_R8A66597_HCD To compile this driver as a module, choose M here: the module will be called r8a66597-hcd. +config SUPERH_ON_CHIP_R8A66597 + boolean "Enable SuperH on-chip USB like the R8A66597" + depends on USB_R8A66597_HCD && CPU_SUBTYPE_SH7366 + help + Renesas SuperH processor has USB like the R8A66597. + This driver supported processor is SH7366. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index bb8e9d44f371..f1edda2dcfde 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -6,6 +6,8 @@ ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG endif +isp1760-objs := isp1760-hcd.o isp1760-if.o + obj-$(CONFIG_PCI) += pci-quirks.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o @@ -16,4 +18,4 @@ 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_ISP1760_HCD) += isp1760.o diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index da7532d38bf1..8b5f991e949c 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c @@ -237,6 +237,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; + /* FIXME we only want one one probe() not two */ ret = usb_ehci_au1xxx_probe(&ehci_au1xxx_hc_driver, &hcd, pdev); return ret; } @@ -245,6 +246,7 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + /* FIXME we only want one one remove() not two */ usb_ehci_au1xxx_remove(hcd, pdev); return 0; } @@ -265,7 +267,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev) return 0; } */ -MODULE_ALIAS("au1xxx-ehci"); +MODULE_ALIAS("platform:au1xxx-ehci"); static struct platform_driver ehci_hcd_au1xxx_driver = { .probe = ehci_hcd_au1xxx_drv_probe, .remove = ehci_hcd_au1xxx_drv_remove, @@ -274,6 +276,5 @@ static struct platform_driver ehci_hcd_au1xxx_driver = { /*.resume = ehci_hcd_au1xxx_drv_resume, */ .driver = { .name = "au1xxx-ehci", - .bus = &platform_bus_type } }; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 64ebfc5548a3..0f82fdcaef09 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -27,7 +27,7 @@ #define ehci_warn(ehci, fmt, args...) \ dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#ifdef EHCI_VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG # define vdbg dbg # define ehci_vdbg ehci_dbg #else @@ -398,7 +398,7 @@ static void qh_lines ( unsigned size = *sizep; char *next = *nextp; char mark; - u32 list_end = EHCI_LIST_END(ehci); + __le32 list_end = EHCI_LIST_END(ehci); if (qh->hw_qtd_next == list_end) /* NEC does this */ mark = '@'; @@ -670,7 +670,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) spin_lock_irqsave (&ehci->lock, flags); - if (buf->bus->controller->power.power_state.event) { + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { size = scnprintf (next, size, "bus %s, device %s (driver " DRIVER_VERSION ")\n" "%s\n" diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index adb0defa1631..6d9bed6c1f48 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -1,5 +1,4 @@ /* - * (C) Copyright David Brownell 2000-2002 * Copyright (c) 2005 MontaVista Software * * This program is free software; you can redistribute it and/or modify it @@ -28,7 +27,6 @@ /* FIXME: Power Management is un-ported so temporarily disable it */ #undef CONFIG_PM -/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ /* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ @@ -331,6 +329,7 @@ static int ehci_fsl_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; + /* FIXME we only want one one probe() not two */ return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); } @@ -338,12 +337,12 @@ static int ehci_fsl_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + /* FIXME we only want one one remove() not two */ usb_hcd_fsl_remove(hcd, pdev); - return 0; } -MODULE_ALIAS("fsl-ehci"); +MODULE_ALIAS("platform:fsl-ehci"); static struct platform_driver ehci_fsl_driver = { .probe = ehci_fsl_drv_probe, @@ -351,5 +350,5 @@ static struct platform_driver ehci_fsl_driver = { .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "fsl-ehci", - }, + }, }; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 85074cb36f38..369a8a5ea7bb 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -57,35 +57,6 @@ * Special thanks to Intel and VIA for providing host controllers to * test this driver on, and Cypress (including In-System Design) for * providing early devices for those host controllers to talk to! - * - * HISTORY: - * - * 2004-05-10 Root hub and PCI suspend/resume support; remote wakeup. (db) - * 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net) - * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka, - * <sojkam@centrum.cz>, updates by DB). - * - * 2002-11-29 Correct handling for hw async_next register. - * 2002-08-06 Handling for bulk and interrupt transfers is mostly shared; - * only scheduling is different, no arbitrary limitations. - * 2002-07-25 Sanity check PCI reads, mostly for better cardbus support, - * clean up HC run state handshaking. - * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts - * 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other - * missing pieces: enabling 64bit dma, handoff from BIOS/SMM. - * 2002-05-07 Some error path cleanups to report better errors; wmb(); - * use non-CVS version id; better iso bandwidth claim. - * 2002-04-19 Control/bulk/interrupt submit no longer uses giveback() on - * errors in submit path. Bugfixes to interrupt scheduling/processing. - * 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift - * more checking to generic hcd framework (db). Make it work with - * Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt). - * 2002-01-14 Minor cleanup; version synch. - * 2002-01-08 Fix roothub handoff of FS/LS to companion controllers. - * 2002-01-04 Control/Bulk queuing behaves. - * - * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. - * 2001-June Works with usb-storage and NEC EHCI on 2.4 */ #define DRIVER_VERSION "10 Dec 2004" @@ -95,7 +66,7 @@ static const char hcd_name [] = "ehci_hcd"; -#undef EHCI_VERBOSE_DEBUG +#undef VERBOSE_DEBUG #undef EHCI_URB_TRACE #ifdef DEBUG @@ -174,6 +145,16 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, return -ETIMEDOUT; } +static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + int error = handshake(ehci, ptr, mask, done, usec); + if (error) + ehci_to_hcd(ehci)->state = HC_STATE_HALT; + + return error; +} + /* force HC to halt state from unknown (EHCI spec section 2.3) */ static int ehci_halt (struct ehci_hcd *ehci) { @@ -246,11 +227,9 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /* wait for any schedule enables/disables to take effect */ temp = ehci_readl(ehci, &ehci->regs->command) << 10; temp &= STS_ASS | STS_PSS; - if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, - temp, 16 * 125) != 0) { - ehci_to_hcd(ehci)->state = HC_STATE_HALT; + if (handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_ASS | STS_PSS, temp, 16 * 125)) return; - } /* then disable anything that's still active */ temp = ehci_readl(ehci, &ehci->regs->command); @@ -258,11 +237,8 @@ static void ehci_quiesce (struct ehci_hcd *ehci) ehci_writel(ehci, temp, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ - if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS, - 0, 16 * 125) != 0) { - ehci_to_hcd(ehci)->state = HC_STATE_HALT; - return; - } + handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_ASS | STS_PSS, 0, 16 * 125); } /*-------------------------------------------------------------------------*/ @@ -355,17 +331,13 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) &ehci->regs->port_status[port]); } -/* ehci_shutdown kick in for silicon on any bus (not just pci, etc). - * This forcibly disables dma and IRQs, helping kexec and other cases - * where the next system software may expect clean state. +/* + * Halt HC, turn off all ports, and let the BIOS use the companion controllers. + * Should be called with ehci->lock held. */ -static void -ehci_shutdown (struct usb_hcd *hcd) +static void ehci_silence_controller(struct ehci_hcd *ehci) { - struct ehci_hcd *ehci; - - ehci = hcd_to_ehci (hcd); - (void) ehci_halt (ehci); + ehci_halt(ehci); ehci_turn_off_all_ports(ehci); /* make BIOS/etc use companion controller during reboot */ @@ -375,6 +347,22 @@ ehci_shutdown (struct usb_hcd *hcd) ehci_readl(ehci, &ehci->regs->configured_flag); } +/* ehci_shutdown kick in for silicon on any bus (not just pci, etc). + * This forcibly disables dma and IRQs, helping kexec and other cases + * where the next system software may expect clean state. + */ +static void ehci_shutdown(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + del_timer_sync(&ehci->watchdog); + del_timer_sync(&ehci->iaa_watchdog); + + spin_lock_irq(&ehci->lock); + ehci_silence_controller(ehci); + spin_unlock_irq(&ehci->lock); +} + static void ehci_port_power (struct ehci_hcd *ehci, int is_on) { unsigned port; @@ -425,15 +413,15 @@ static void ehci_work (struct ehci_hcd *ehci) timer_action (ehci, TIMER_IO_WATCHDOG); } +/* + * Called when the ehci_hcd module is removed. + */ static void ehci_stop (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); ehci_dbg (ehci, "stop\n"); - /* Turn off port power on all root hub ports. */ - ehci_port_power (ehci, 0); - /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); del_timer_sync(&ehci->iaa_watchdog); @@ -442,13 +430,10 @@ static void ehci_stop (struct usb_hcd *hcd) if (HC_IS_RUNNING (hcd->state)) ehci_quiesce (ehci); + ehci_silence_controller(ehci); ehci_reset (ehci); - ehci_writel(ehci, 0, &ehci->regs->intr_enable); spin_unlock_irq(&ehci->lock); - /* let companion controllers work when we aren't */ - ehci_writel(ehci, 0, &ehci->regs->configured_flag); - remove_companion_file(ehci); remove_debug_files (ehci); @@ -676,7 +661,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; -#ifdef EHCI_VERBOSE_DEBUG +#ifdef VERBOSE_DEBUG /* unrequested/ignored: Frame List Rollover */ dbg_status (ehci, "irq", status); #endif @@ -710,6 +695,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* remote wakeup [4.3.1] */ if (status & STS_PCD) { unsigned i = HCS_N_PORTS (ehci->hcs_params); + + /* kick root hub later */ pcd_status = status; /* resume root hub? */ @@ -738,8 +725,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { - /* bogus "fatal" IRQs appear on some chips... why? */ - status = ehci_readl(ehci, &ehci->regs->status); dbg_cmd (ehci, "fatal", ehci_readl(ehci, &ehci->regs->command)); dbg_status (ehci, "fatal", status); @@ -758,7 +743,7 @@ dead: if (bh) ehci_work (ehci); spin_unlock (&ehci->lock); - if (pcd_status & STS_PCD) + if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; } @@ -788,8 +773,14 @@ static int ehci_urb_enqueue ( INIT_LIST_HEAD (&qtd_list); switch (usb_pipetype (urb->pipe)) { - // case PIPE_CONTROL: - // case PIPE_BULK: + case PIPE_CONTROL: + /* qh_completions() code doesn't handle all the fault cases + * in multi-TD control transfers. Even 1KB is rare anyway. + */ + if (urb->transfer_buffer_length > (16 * 1024)) + return -EMSGSIZE; + /* FALLTHROUGH */ + /* case PIPE_BULK: */ default: if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) return -ENOMEM; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4e065e556e4b..382587c4457c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -28,7 +28,9 @@ /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_PERSIST +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) + +#ifdef CONFIG_PM static int ehci_hub_control( struct usb_hcd *hcd, @@ -104,15 +106,6 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) ehci->owned_ports = 0; } -#else /* CONFIG_USB_PERSIST */ - -static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci) -{ } - -#endif - -#ifdef CONFIG_PM - static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); @@ -158,10 +151,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } /* enable remote wakeup on all ports */ - if (device_may_wakeup(&hcd->self.root_hub->dev)) - t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; + if (hcd->self.root_hub->do_remote_wakeup) + t2 |= PORT_WAKE_BITS; else - t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); + t2 &= ~PORT_WAKE_BITS; if (t1 != t2) { ehci_vdbg (ehci, "port %d, %08x -> %08x\n", @@ -183,7 +176,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) /* allow remote wakeup */ mask = INTR_MASK; - if (!device_may_wakeup(&hcd->self.root_hub->dev)) + if (!hcd->self.root_hub->do_remote_wakeup) mask &= ~STS_PCD; ehci_writel(ehci, mask, &ehci->regs->intr_enable); ehci_readl(ehci, &ehci->regs->intr_enable); @@ -241,8 +234,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) i = HCS_N_PORTS (ehci->hcs_params); while (i--) { temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - temp &= ~(PORT_RWC_BITS - | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); + temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); if (test_bit(i, &ehci->bus_suspended) && (temp & PORT_SUSPEND)) { ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); @@ -281,9 +273,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq (&ehci->lock); - - if (!power_okay) - ehci_handover_companion_ports(ehci); + ehci_handover_companion_ports(ehci); return 0; } @@ -540,13 +530,11 @@ ehci_hub_descriptor ( if (HCS_INDICATOR (ehci->hcs_params)) temp |= 0x0080; /* per-port indicators (LEDs) */ #endif - desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp); + desc->wHubCharacteristics = cpu_to_le16(temp); } /*-------------------------------------------------------------------------*/ -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) - static int ehci_hub_control ( struct usb_hcd *hcd, u16 typeReq, @@ -778,11 +766,11 @@ static int ehci_hub_control ( if (temp & PORT_POWER) status |= 1 << USB_PORT_FEAT_POWER; -#ifndef EHCI_VERBOSE_DEBUG +#ifndef VERBOSE_DEBUG if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); - put_unaligned(cpu_to_le32 (status), (__le32 *) buf); + put_unaligned_le32(status, buf); break; case SetHubFeature: switch (wValue) { @@ -812,8 +800,6 @@ static int ehci_hub_control ( if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) goto error; - if (device_may_wakeup(&hcd->self.root_hub->dev)) - temp |= PORT_WAKE_BITS; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); break; case USB_PORT_FEAT_POWER: diff --git a/drivers/usb/host/ehci-ixp4xx.c b/drivers/usb/host/ehci-ixp4xx.c index 3041d8f055f4..601c8795a854 100644 --- a/drivers/usb/host/ehci-ixp4xx.c +++ b/drivers/usb/host/ehci-ixp4xx.c @@ -140,13 +140,12 @@ static int ixp4xx_ehci_remove(struct platform_device *pdev) return 0; } -MODULE_ALIAS("ixp4xx-ehci"); +MODULE_ALIAS("platform:ixp4xx-ehci"); static struct platform_driver ixp4xx_ehci_driver = { .probe = ixp4xx_ehci_probe, .remove = ixp4xx_ehci_remove, .driver = { .name = "ixp4xx-ehci", - .bus = &platform_bus_type }, }; diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 72ccd56e36dd..5bb7f6bb13f3 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -130,6 +130,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) case PCI_VENDOR_ID_TDI: if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { ehci->is_tdi_rh_tt = 1; + hcd->has_tt = 1; tdi_reset(ehci); } break; @@ -221,6 +222,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); #endif + ehci_port_power(ehci, 1); retval = ehci_pci_reinit(ehci, pdev); done: return retval; @@ -299,7 +301,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd) if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { int mask = INTR_MASK; - if (!device_may_wakeup(&hcd->self.root_hub->dev)) + if (!hcd->self.root_hub->do_remote_wakeup) mask &= ~STS_PCD; ehci_writel(ehci, mask, &ehci->regs->intr_enable); ehci_readl(ehci, &ehci->regs->intr_enable); @@ -329,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); - ehci_handover_companion_ports(ehci); hcd->state = HC_STATE_SUSPENDED; return 0; @@ -353,8 +354,8 @@ static const struct hc_driver ehci_pci_hc_driver = { .reset = ehci_pci_setup, .start = ehci_run, #ifdef CONFIG_PM - .suspend = ehci_pci_suspend, - .resume = ehci_pci_resume, + .pci_suspend = ehci_pci_suspend, + .pci_resume = ehci_pci_resume, #endif .stop = ehci_stop, .shutdown = ehci_shutdown, diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c index a3249078c808..6c76036783a1 100644 --- a/drivers/usb/host/ehci-ppc-soc.c +++ b/drivers/usb/host/ehci-ppc-soc.c @@ -175,6 +175,7 @@ static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) if (usb_disabled()) return -ENODEV; + /* FIXME we only want one one probe() not two */ ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev); return ret; } @@ -183,17 +184,17 @@ static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); + /* FIXME we only want one one remove() not two */ usb_ehci_ppc_soc_remove(hcd, pdev); return 0; } -MODULE_ALIAS("ppc-soc-ehci"); +MODULE_ALIAS("platform:ppc-soc-ehci"); static struct platform_driver ehci_ppc_soc_driver = { .probe = ehci_hcd_ppc_soc_drv_probe, .remove = ehci_hcd_ppc_soc_drv_remove, .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "ppc-soc-ehci", - .bus = &platform_bus_type } }; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index bbda58eb8813..69782221bcf3 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -125,7 +125,6 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) goto fail_irq; } - dev->core.power.power_state = PMSG_ON; dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 2e49de820b14..b85b54160cda 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -242,7 +242,8 @@ __acquires(ehci->lock) if (unlikely(urb->unlinked)) { COUNT(ehci->stats.unlink); } else { - if (likely(status == -EINPROGRESS)) + /* report non-error and short read status as zero */ + if (status == -EINPROGRESS || status == -EREMOTEIO) status = 0; COUNT(ehci->stats.complete); } @@ -250,7 +251,7 @@ __acquires(ehci->lock) #ifdef EHCI_URB_TRACE ehci_dbg (ehci, "%s %s urb %p ep%d%s status %d len %d/%d\n", - __FUNCTION__, urb->dev->devpath, urb, + __func__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", status, @@ -283,9 +284,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) int last_status = -EINPROGRESS; int stopped; unsigned count = 0; - int do_status = 0; u8 state; - u32 halt = HALT_BIT(ehci); + __le32 halt = HALT_BIT(ehci); if (unlikely (list_empty (&qh->qtd_list))) return count; @@ -309,7 +309,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) struct ehci_qtd *qtd; struct urb *urb; u32 token = 0; - int qtd_status; qtd = list_entry (entry, struct ehci_qtd, qtd_list); urb = qtd->urb; @@ -336,11 +335,20 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* always clean up qtds the hc de-activated */ if ((token & QTD_STS_ACTIVE) == 0) { + /* on STALL, error, and short reads this urb must + * complete and all its qtds must be recycled. + */ if ((token & QTD_STS_HALT) != 0) { stopped = 1; /* magic dummy for some short reads; qh won't advance. * that silicon quirk can kick in with this dummy too. + * + * other short reads won't stop the queue, including + * control transfers (status stage handles that) or + * most other single-qtd reads ... the queue stops if + * URB_SHORT_NOT_OK was set so the driver submitting + * the urbs could clean it up. */ } else if (IS_SHORT_READ (token) && !(qtd->hw_alt_next @@ -354,28 +362,21 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) { break; + /* scan the whole queue for unlinks whenever it stops */ } else { stopped = 1; - if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) + /* cancel everything if we halt, suspend, etc */ + if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) last_status = -ESHUTDOWN; - /* ignore active urbs unless some previous qtd - * for the urb faulted (including short read) or - * its urb was canceled. we may patch qh or qtds. + /* this qtd is active; skip it unless a previous qtd + * for its urb faulted, or its urb was canceled. */ - if (likely(last_status == -EINPROGRESS && - !urb->unlinked)) - continue; - - /* issue status after short control reads */ - if (unlikely (do_status != 0) - && QTD_PID (token) == 0 /* OUT */) { - do_status = 0; + else if (last_status == -EINPROGRESS && !urb->unlinked) continue; - } - /* token in overlay may be most current */ + /* qh unlinked; token in overlay may be most current */ if (state == QH_STATE_IDLE && cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current) @@ -392,21 +393,32 @@ halt: } } - /* remove it from the queue */ - qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); - if (unlikely(qtd_status == -EREMOTEIO)) { - do_status = (!urb->unlinked && - usb_pipecontrol(urb->pipe)); - qtd_status = 0; + /* unless we already know the urb's status, collect qtd status + * and update count of bytes transferred. in common short read + * cases with only one data qtd (including control transfers), + * queue processing won't halt. but with two or more qtds (for + * example, with a 32 KB transfer), when the first qtd gets a + * short read the second must be removed by hand. + */ + if (last_status == -EINPROGRESS) { + last_status = qtd_copy_status(ehci, urb, + qtd->length, token); + if (last_status == -EREMOTEIO + && (qtd->hw_alt_next + & EHCI_LIST_END(ehci))) + last_status = -EINPROGRESS; } - if (likely(last_status == -EINPROGRESS)) - last_status = qtd_status; + /* if we're removing something not at the queue head, + * patch the hardware queue pointer. + */ if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { last = list_entry (qtd->qtd_list.prev, struct ehci_qtd, qtd_list); last->hw_next = qtd->hw_next; } + + /* remove qtd; it's recycled after possible urb completion */ list_del (&qtd->qtd_list); last = qtd; } @@ -431,7 +443,15 @@ halt: qh_refresh(ehci, qh); break; case QH_STATE_LINKED: - /* should be rare for periodic transfers, + /* We won't refresh a QH that's linked (after the HC + * stopped the queue). That avoids a race: + * - HC reads first part of QH; + * - CPU updates that first part and the token; + * - HC reads rest of that QH, including token + * Result: HC gets an inconsistent image, and then + * DMAs to/from the wrong memory (corrupting it). + * + * That should be rare for interrupt transfers, * except maybe high bandwidth ... */ if ((cpu_to_hc32(ehci, QH_SMASK) @@ -549,6 +569,12 @@ qh_urb_transaction ( this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket); len -= this_qtd_len; buf += this_qtd_len; + + /* + * short reads advance to a "magic" dummy instead of the next + * qtd ... that forces the queue to stop, for manual cleanup. + * (this will usually be overridden later.) + */ if (is_input) qtd->hw_alt_next = ehci->async->hw_alt_next; @@ -568,8 +594,10 @@ qh_urb_transaction ( list_add_tail (&qtd->qtd_list, head); } - /* unless the bulk/interrupt caller wants a chance to clean - * up after short reads, hc should advance qh past this urb + /* + * unless the caller requires manual cleanup after short reads, + * have the alt_next mechanism keep the queue running after the + * last data qtd (the only one, for control and most other cases). */ if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 || usb_pipecontrol (urb->pipe))) @@ -657,6 +685,14 @@ qh_make ( type = usb_pipetype (urb->pipe); maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input); + /* 1024 byte maxpacket is a hardware ceiling. High bandwidth + * acts like up to 3KB, but is built from smaller packets. + */ + if (max_packet(maxp) > 1024) { + ehci_dbg(ehci, "bogus qh maxpacket %d\n", max_packet(maxp)); + goto done; + } + /* Compute interrupt scheduling parameters just once, and save. * - allowing for high bandwidth, how many nsec/uframe are used? * - split transactions need a second CSPLIT uframe; same question @@ -757,7 +793,13 @@ qh_make ( info2 |= (EHCI_TUNE_MULT_HS << 30); } else if (type == PIPE_BULK) { info1 |= (EHCI_TUNE_RL_HS << 28); - info1 |= 512 << 16; /* usb2 fixed maxpacket */ + /* The USB spec says that high speed bulk endpoints + * always use 512 byte maxpacket. But some device + * vendors decided to ignore that, and MSFT is happy + * to help them do so. So now people expect to use + * such nonconformant devices with Linux too; sigh. + */ + info1 |= max_packet(maxp) << 16; info2 |= (EHCI_TUNE_MULT_HS << 30); } else { /* PIPE_INTERRUPT */ info1 |= max_packet (maxp) << 16; @@ -841,7 +883,7 @@ static struct ehci_qh *qh_append_tds ( ) { struct ehci_qh *qh = NULL; - u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); + __hc32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); qh = (struct ehci_qh *) *ptr; if (unlikely (qh == NULL)) { @@ -932,7 +974,7 @@ submit_async ( #ifdef EHCI_URB_TRACE ehci_dbg (ehci, "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", - __FUNCTION__, urb->dev->devpath, urb, + __func__, urb->dev->devpath, urb, epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", urb->transfer_buffer_length, qtd, urb->ep->hcpriv); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 8a8e08a51ba3..be575e46eac3 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -440,11 +440,10 @@ static int enable_periodic (struct ehci_hcd *ehci) /* did clearing PSE did take effect yet? * takes effect only at frame boundaries... */ - status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125); - if (status != 0) { - ehci_to_hcd(ehci)->state = HC_STATE_HALT; + status = handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_PSS, 0, 9 * 125); + if (status) return status; - } cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; ehci_writel(ehci, cmd, &ehci->regs->command); @@ -465,11 +464,10 @@ static int disable_periodic (struct ehci_hcd *ehci) /* did setting PSE not take effect yet? * takes effect only at frame boundaries... */ - status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); - if (status != 0) { - ehci_to_hcd(ehci)->state = HC_STATE_HALT; + status = handshake_on_error_set_halt(ehci, &ehci->regs->status, + STS_PSS, STS_PSS, 9 * 125); + if (status) return status; - } cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; ehci_writel(ehci, cmd, &ehci->regs->command); @@ -1183,21 +1181,18 @@ itd_urb_transaction ( struct ehci_itd, itd_list); list_del (&itd->itd_list); itd_dma = itd->itd_dma; - } else - itd = NULL; - - if (!itd) { + } else { spin_unlock_irqrestore (&ehci->lock, flags); itd = dma_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma); spin_lock_irqsave (&ehci->lock, flags); + if (!itd) { + iso_sched_free(stream, sched); + spin_unlock_irqrestore(&ehci->lock, flags); + return -ENOMEM; + } } - if (unlikely (NULL == itd)) { - iso_sched_free (stream, sched); - spin_unlock_irqrestore (&ehci->lock, flags); - return -ENOMEM; - } memset (itd, 0, sizeof *itd); itd->itd_dma = itd_dma; list_add (&itd->itd_list, &sched->td_list); @@ -1682,7 +1677,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, #ifdef EHCI_URB_TRACE ehci_dbg (ehci, "%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n", - __FUNCTION__, urb->dev->devpath, urb, + __func__, urb->dev->devpath, urb, usb_pipeendpoint (urb->pipe), usb_pipein (urb->pipe) ? "in" : "out", urb->transfer_buffer_length, @@ -1816,21 +1811,18 @@ sitd_urb_transaction ( struct ehci_sitd, sitd_list); list_del (&sitd->sitd_list); sitd_dma = sitd->sitd_dma; - } else - sitd = NULL; - - if (!sitd) { + } else { spin_unlock_irqrestore (&ehci->lock, flags); sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags, &sitd_dma); spin_lock_irqsave (&ehci->lock, flags); + if (!sitd) { + iso_sched_free(stream, iso_sched); + spin_unlock_irqrestore(&ehci->lock, flags); + return -ENOMEM; + } } - if (!sitd) { - iso_sched_free (stream, iso_sched); - spin_unlock_irqrestore (&ehci->lock, flags); - return -ENOMEM; - } memset (sitd, 0, sizeof *sitd); sitd->sitd_dma = sitd_dma; list_add (&sitd->sitd_list, &iso_sched->td_list); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 203a3359a648..20b9a0d07420 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1400,7 +1400,7 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd) spin_unlock_irqrestore(&isp116x->lock, flags); val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); val |= HCCONTROL_USB_SUSPEND; - if (device_may_wakeup(&hcd->self.root_hub->dev)) + if (hcd->self.root_hub->do_remote_wakeup) val |= HCCONTROL_RWE; /* Wait for usb transfers to finish */ msleep(2); @@ -1442,11 +1442,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) break; case HCCONTROL_USB_OPER: spin_unlock_irq(&isp116x->lock); - /* Without setting power_state here the - SUSPENDED state won't be removed from - sysfs/usbN/power.state as a response to remote - wakeup. Maybe in the future. */ - hcd->self.root_hub->dev.power.power_state = PMSG_ON; return 0; default: /* HCCONTROL_USB_RESET: this may happen, when during @@ -1460,7 +1455,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) if ((isp116x->rhdesca & RH_A_NDP) == 2) isp116x_hub_control(hcd, SetPortFeature, USB_PORT_FEAT_POWER, 2, NULL, 0); - hcd->self.root_hub->dev.power.power_state = PMSG_ON; return 0; } @@ -1486,8 +1480,6 @@ static int isp116x_bus_resume(struct usb_hcd *hcd) isp116x_write_reg32(isp116x, HCCONTROL, (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); spin_unlock_irq(&isp116x->lock); - /* see analogous comment above */ - hcd->self.root_hub->dev.power.power_state = PMSG_ON; hcd->state = HC_STATE_RUNNING; return 0; @@ -1663,7 +1655,6 @@ static int __devinit isp116x_probe(struct platform_device *pdev) static int isp116x_suspend(struct platform_device *dev, pm_message_t state) { VDBG("%s: state %x\n", __func__, state.event); - dev->dev.power.power_state = state; return 0; } @@ -1672,8 +1663,7 @@ static int isp116x_suspend(struct platform_device *dev, pm_message_t state) */ static int isp116x_resume(struct platform_device *dev) { - VDBG("%s: state %x\n", __func__, dev->power.power_state.event); - dev->dev.power.power_state = PMSG_ON; + VDBG("%s\n", __func__); return 0; } diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c new file mode 100644 index 000000000000..4ba96c1e060c --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.c @@ -0,0 +1,2231 @@ +/* + * Driver for the NXP ISP1760 chip + * + * However, the code might contain some bugs. What doesn't work for sure is: + * - ISO + * - OTG + e The interrupt line is configured as active low, level. + * + * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> + * + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/usb.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <asm/unaligned.h> + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +static struct kmem_cache *qtd_cachep; +static struct kmem_cache *qh_cachep; + +struct isp1760_hcd { + u32 hcs_params; + spinlock_t lock; + struct inter_packet_info atl_ints[32]; + struct inter_packet_info int_ints[32]; + struct memory_chunk memory_pool[BLOCKS]; + + /* periodic schedule support */ +#define DEFAULT_I_TDPS 1024 + unsigned periodic_size; + unsigned i_thresh; + unsigned long reset_done; + unsigned long next_statechange; +}; + +static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) +{ + return (struct isp1760_hcd *) (hcd->hcd_priv); +} +static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv) +{ + return container_of((void *) priv, struct usb_hcd, hcd_priv); +} + +/* Section 2.2 Host Controller Capability Registers */ +#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ +#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ +#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ +#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ +#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ +#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ +#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ + +/* Section 2.3 Host Controller Operational Registers */ +#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ +#define CMD_RESET (1<<1) /* reset HC not bus */ +#define CMD_RUN (1<<0) /* start/stop HC */ +#define STS_PCD (1<<2) /* port change detect */ +#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ + +#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ +#define PORT_POWER (1<<12) /* true: has power (see PPC) */ +#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ +#define PORT_RESET (1<<8) /* reset port */ +#define PORT_SUSPEND (1<<7) /* suspend port */ +#define PORT_RESUME (1<<6) /* resume it */ +#define PORT_PE (1<<2) /* port enable */ +#define PORT_CSC (1<<1) /* connect status change */ +#define PORT_CONNECT (1<<0) /* device connected */ +#define PORT_RWC_BITS (PORT_CSC) + +struct isp1760_qtd { + struct isp1760_qtd *hw_next; + u8 packet_type; + u8 toggle; + + void *data_buffer; + /* the rest is HCD-private */ + struct list_head qtd_list; + struct urb *urb; + size_t length; + + /* isp special*/ + u32 status; +#define URB_COMPLETE_NOTIFY (1 << 0) +#define URB_ENQUEUED (1 << 1) +#define URB_TYPE_ATL (1 << 2) +#define URB_TYPE_INT (1 << 3) +}; + +struct isp1760_qh { + /* first part defined by EHCI spec */ + struct list_head qtd_list; + struct isp1760_hcd *priv; + + /* periodic schedule info */ + unsigned short period; /* polling interval */ + struct usb_device *dev; + + u32 toggle; + u32 ping; +}; + +#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED) + +static unsigned int isp1760_readl(__u32 __iomem *regs) +{ + return readl(regs); +} + +static void isp1760_writel(const unsigned int val, __u32 __iomem *regs) +{ + writel(val, regs); +} + +/* + * The next two copy via MMIO data to/from the device. memcpy_{to|from}io() + * doesn't quite work because some people have to enforce 32-bit access + */ +static void priv_read_copy(struct isp1760_hcd *priv, u32 *src, + __u32 __iomem *dst, u32 offset, u32 len) +{ + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 val; + u8 *buff8; + + if (!src) { + printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len); + return; + } + isp1760_writel(offset, hcd->regs + HC_MEMORY_REG); + /* XXX + * 90nsec delay, the spec says something how this could be avoided. + */ + mdelay(1); + + while (len >= 4) { + *src = __raw_readl(dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + + /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully + * allocated. + */ + val = isp1760_readl(dst); + + buff8 = (u8 *)src; + while (len) { + + *buff8 = val; + val >>= 8; + len--; + buff8++; + } +} + +static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src, + __u32 __iomem *dst, u32 len) +{ + while (len >= 4) { + __raw_writel(*src, dst); + len -= 4; + src++; + dst++; + } + + if (!len) + return; + /* in case we have 3, 2 or 1 by left. The buffer is allocated and the + * extra bytes should not be read by the HW + */ + + __raw_writel(*src, dst); +} + +/* memory management of the 60kb on the chip from 0x1000 to 0xffff */ +static void init_memory(struct isp1760_hcd *priv) +{ + int i; + u32 payload; + + payload = 0x1000; + for (i = 0; i < BLOCK_1_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_1_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_2_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + + for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) { + priv->memory_pool[i].start = payload; + priv->memory_pool[i].size = BLOCK_3_SIZE; + priv->memory_pool[i].free = 1; + payload += priv->memory_pool[i].size; + } + + BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE); +} + +static u32 alloc_mem(struct isp1760_hcd *priv, u32 size) +{ + int i; + + if (!size) + return ISP1760_NULL_POINTER; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].size >= size && + priv->memory_pool[i].free) { + + priv->memory_pool[i].free = 0; + return priv->memory_pool[i].start; + } + } + + printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n", + size); + printk(KERN_ERR "Current memory map:\n"); + for (i = 0; i < BLOCKS; i++) { + printk(KERN_ERR "Pool %2d size %4d status: %d\n", + i, priv->memory_pool[i].size, + priv->memory_pool[i].free); + } + /* XXX maybe -ENOMEM could be possible */ + BUG(); + return 0; +} + +static void free_mem(struct isp1760_hcd *priv, u32 mem) +{ + int i; + + if (mem == ISP1760_NULL_POINTER) + return; + + for (i = 0; i < BLOCKS; i++) { + if (priv->memory_pool[i].start == mem) { + + BUG_ON(priv->memory_pool[i].free); + + priv->memory_pool[i].free = 1; + return ; + } + } + + printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n", + mem); + BUG(); +} + +static void isp1760_init_regs(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_SKIPMAP_REG); + + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_INT_PTD_DONEMAP_REG); + isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs + + HC_ISO_PTD_DONEMAP_REG); +} + +static int handshake(struct isp1760_hcd *priv, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + u32 result; + + do { + result = isp1760_readl(ptr); + if (result == ~0) + return -ENODEV; + result &= mask; + if (result == done) + return 0; + udelay(1); + usec--; + } while (usec > 0); + return -ETIMEDOUT; +} + +/* reset a non-running (STS_HALT == 1) controller */ +static int ehci_reset(struct isp1760_hcd *priv) +{ + int retval; + struct usb_hcd *hcd = priv_to_hcd(priv); + u32 command = isp1760_readl(hcd->regs + HC_USBCMD); + + command |= CMD_RESET; + isp1760_writel(command, hcd->regs + HC_USBCMD); + hcd->state = HC_STATE_HALT; + priv->next_statechange = jiffies; + retval = handshake(priv, hcd->regs + HC_USBCMD, + CMD_RESET, 0, 250 * 1000); + return retval; +} + +static void qh_destroy(struct isp1760_qh *qh) +{ + BUG_ON(!list_empty(&qh->qtd_list)); + kmem_cache_free(qh_cachep, qh); +} + +static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qh *qh; + + qh = kmem_cache_zalloc(qh_cachep, flags); + if (!qh) + return qh; + + INIT_LIST_HEAD(&qh->qtd_list); + qh->priv = priv; + return qh; +} + +/* magic numbers that can affect system performance */ +#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ +#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ +#define EHCI_TUNE_RL_TT 0 +#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ +#define EHCI_TUNE_MULT_TT 1 +#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ + +/* one-time init, only for memory state */ +static int priv_init(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 hcc_params; + + spin_lock_init(&priv->lock); + + /* + * hw default: 1K periodic list heads, one per frame. + * periodic_size can shrink by USBCMD update if hcc_params allows. + */ + priv->periodic_size = DEFAULT_I_TDPS; + + /* controllers may cache some of the periodic schedule ... */ + hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS); + /* full frame cache */ + if (HCC_ISOC_CACHE(hcc_params)) + priv->i_thresh = 8; + else /* N microframes cached */ + priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); + + return 0; +} + +static int isp1760_hc_setup(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int result; + u32 scratch; + + isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG); + scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG); + if (scratch != 0xdeadbabe) { + printk(KERN_ERR "ISP1760: Scratch test failed.\n"); + return -ENODEV; + } + + /* pre reset */ + isp1760_init_regs(hcd); + + /* reset */ + isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG); + mdelay(100); + + isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG); + mdelay(100); + + result = ehci_reset(priv); + if (result) + return result; + + /* Step 11 passed */ + + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG); + isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE); + + /* ATL reset */ + scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL); + mdelay(10); + isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL); + + isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL); + mdelay(10); + + priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS); + + return priv_init(hcd); +} + +static void isp1760_init_maps(struct usb_hcd *hcd) +{ + /*set last maps, for iso its only 1, else 32 tds bitmap*/ + isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG); + isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG); + isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG); +} + +static void isp1760_enable_interrupts(struct usb_hcd *hcd) +{ + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG); + isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG); + isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG); + /* step 23 passed */ +} + +static int isp1760_run(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int retval; + u32 temp; + u32 command; + u32 chipid; + + hcd->uses_new_polling = 1; + hcd->poll_rh = 0; + + hcd->state = HC_STATE_RUNNING; + isp1760_enable_interrupts(hcd); + temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL); + temp |= FINAL_HW_CONFIG; + isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~(CMD_LRESET|CMD_RESET); + command |= CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); + + retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN, + 250 * 1000); + if (retval) + return retval; + + /* + * XXX + * Spec says to write FLAG_CF as last config action, priv code grabs + * the semaphore while doing so. + */ + down_write(&ehci_cf_port_reset_rwsem); + isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG); + + retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF, + 250 * 1000); + up_write(&ehci_cf_port_reset_rwsem); + if (retval) + return retval; + + chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG); + isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff, + chipid >> 16); + + /* PTD Register Init Part 2, Step 28 */ + /* enable INTs */ + isp1760_init_maps(hcd); + + /* GRR this is run-once init(), being done every time the HC starts. + * So long as they're part of class devices, we can't do it init() + * since the class device isn't created that early. + */ + return 0; +} + +static u32 base_to_chip(u32 base) +{ + return ((base - 0x400) >> 3); +} + +static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 dw0; + u32 dw1; + u32 dw2; + u32 dw3; + u32 maxpacket; + u32 multi; + u32 pid_code; + u32 rl = RL_COUNTER; + u32 nak = NAK_COUNTER; + + /* according to 3.6.2, max packet len can not be > 0x400 */ + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + + /* DW0 */ + dw0 = PTD_VALID; + dw0 |= PTD_LENGTH(qtd->length); + dw0 |= PTD_MAXPACKET(maxpacket); + dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe)); + dw1 = usb_pipeendpoint(urb->pipe) >> 1; + + /* DW1 */ + dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe)); + + pid_code = qtd->packet_type; + dw1 |= PTD_PID_TOKEN(pid_code); + + if (usb_pipebulk(urb->pipe)) + dw1 |= PTD_TRANS_BULK; + else if (usb_pipeint(urb->pipe)) + dw1 |= PTD_TRANS_INT; + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split transaction */ + + dw1 |= PTD_TRANS_SPLIT; + if (urb->dev->speed == USB_SPEED_LOW) + dw1 |= PTD_SE_USB_LOSPEED; + + dw1 |= PTD_PORT_NUM(urb->dev->ttport); + dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum); + + /* SE bit for Split INT transfers */ + if (usb_pipeint(urb->pipe) && + (urb->dev->speed == USB_SPEED_LOW)) + dw1 |= 2 << 16; + + dw3 = 0; + rl = 0; + nak = 0; + } else { + dw0 |= PTD_MULTI(multi); + if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) + dw3 = qh->ping; + else + dw3 = 0; + } + /* DW2 */ + dw2 = 0; + dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload)); + dw2 |= PTD_RL_CNT(rl); + dw3 |= PTD_NAC_CNT(nak); + + /* DW3 */ + if (usb_pipecontrol(urb->pipe)) + dw3 |= PTD_DATA_TOGGLE(qtd->toggle); + else + dw3 |= qh->toggle; + + + dw3 |= PTD_ACTIVE; + /* Cerr */ + dw3 |= PTD_CERR(ERR_COUNTER); + + memset(ptd, 0, sizeof(*ptd)); + + ptd->dw0 = cpu_to_le32(dw0); + ptd->dw1 = cpu_to_le32(dw1); + ptd->dw2 = cpu_to_le32(dw2); + ptd->dw3 = cpu_to_le32(dw3); +} + +static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + u32 maxpacket; + u32 multi; + u32 numberofusofs; + u32 i; + u32 usofmask, usof; + u32 period; + + maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + multi = 1 + ((maxpacket >> 11) & 0x3); + maxpacket &= 0x7ff; + /* length of the data per uframe */ + maxpacket = multi * maxpacket; + + numberofusofs = urb->transfer_buffer_length / maxpacket; + if (urb->transfer_buffer_length % maxpacket) + numberofusofs += 1; + + usofmask = 1; + usof = 0; + for (i = 0; i < numberofusofs; i++) { + usof |= usofmask; + usofmask <<= 1; + } + + if (urb->dev->speed != USB_SPEED_HIGH) { + /* split */ + ptd->dw5 = __constant_cpu_to_le32(0x1c); + + if (qh->period >= 32) + period = qh->period / 2; + else + period = qh->period; + + } else { + + if (qh->period >= 8) + period = qh->period/8; + else + period = qh->period; + + if (period >= 32) + period = 16; + + if (qh->period >= 8) { + /* millisecond period */ + period = (period << 3); + } else { + /* usof based tranmsfers */ + /* minimum 4 usofs */ + usof = 0x11; + } + } + + ptd->dw2 |= cpu_to_le32(period); + ptd->dw4 = cpu_to_le32(usof); +} + +static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct isp1760_qtd *qtd, struct urb *urb, + u32 payload, struct ptd *ptd) +{ + transform_into_atl(priv, qh, qtd, urb, payload, ptd); + transform_add_int(priv, qh, qtd, urb, payload, ptd); +} + +static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len, + u32 token) +{ + int count; + + qtd->data_buffer = databuffer; + qtd->packet_type = GET_QTD_TOKEN_TYPE(token); + qtd->toggle = GET_DATA_TOGGLE(token); + + if (len > HC_ATL_PL_SIZE) + count = HC_ATL_PL_SIZE; + else + count = len; + + qtd->length = count; + return count; +} + +static int check_error(struct ptd *ptd) +{ + int error = 0; + u32 dw3; + + dw3 = le32_to_cpu(ptd->dw3); + if (dw3 & DW3_HALT_BIT) + error = -EPIPE; + + if (dw3 & DW3_ERROR_BIT) { + printk(KERN_ERR "error bit is set in DW3\n"); + error = -EPIPE; + } + + if (dw3 & DW3_QTD_ACTIVE) { + printk(KERN_ERR "transfer active bit is set DW3\n"); + printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf, + (le32_to_cpu(ptd->dw2) >> 25) & 0xf); + } + + return error; +} + +static void check_int_err_status(u32 dw4) +{ + u32 i; + + dw4 >>= 8; + + for (i = 0; i < 8; i++) { + switch (dw4 & 0x7) { + case INT_UNDERRUN: + printk(KERN_ERR "ERROR: under run , %d\n", i); + break; + + case INT_EXACT: + printk(KERN_ERR "ERROR: transaction error, %d\n", i); + break; + + case INT_BABBLE: + printk(KERN_ERR "ERROR: babble error, %d\n", i); + break; + } + dw4 >>= 3; + } +} + +static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv, + u32 payload) +{ + u32 token; + struct usb_hcd *hcd = priv_to_hcd(priv); + + token = qtd->packet_type; + + if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) { + switch (token) { + case IN_PID: + break; + case OUT_PID: + case SETUP_PID: + priv_write_copy(priv, qtd->data_buffer, + hcd->regs + payload, + qtd->length); + } + } +} + +static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_atl(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->atl_ints[slot].urb = urb; + priv->atl_ints[slot].qh = qh; + priv->atl_ints[slot].qtd = qtd; + priv->atl_ints[slot].data_buffer = qtd->data_buffer; + priv->atl_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_ATL; + qtd->status |= slot << 16; +} + +static void enqueue_one_int_qtd(u32 int_regs, u32 payload, + struct isp1760_hcd *priv, struct isp1760_qh *qh, + struct urb *urb, u32 slot, struct isp1760_qtd *qtd) +{ + struct ptd ptd; + struct usb_hcd *hcd = priv_to_hcd(priv); + + transform_into_int(priv, qh, qtd, urb, payload, &ptd); + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd)); + enqueue_one_qtd(qtd, priv, payload); + + priv->int_ints[slot].urb = urb; + priv->int_ints[slot].qh = qh; + priv->int_ints[slot].qtd = qtd; + priv->int_ints[slot].data_buffer = qtd->data_buffer; + priv->int_ints[slot].payload = payload; + qtd->status |= URB_ENQUEUED | URB_TYPE_INT; + qtd->status |= slot << 16; +} + +void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 atl_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 skip_map, or_map; + u32 queue_entry; + u32 slot; + u32 int_regs, payload; + u32 buffstatus; + + skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + BUG_ON(!skip_map); + slot = __ffs(skip_map); + queue_entry = 1 << slot; + + int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd); + + payload = alloc_mem(priv, qtd->length); + + enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd); + + or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map |= queue_entry; + isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + skip_map &= ~queue_entry; + isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG); + + buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG); + buffstatus |= INT_BUFFER; + isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG); +} + +static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status) +__releases(priv->lock) +__acquires(priv->lock) +{ + if (!urb->unlinked) { + if (status == -EINPROGRESS) + status = 0; + } + + /* complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + spin_unlock(&priv->lock); + usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status); + spin_lock(&priv->lock); +} + +static void isp1760_qtd_free(struct isp1760_qtd *qtd) +{ + kmem_cache_free(qtd_cachep, qtd); +} + +static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + + tmp_qtd = qtd->hw_next; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + return tmp_qtd; +} + +/* + * Remove this QTD from the QH list and free its memory. If this QTD + * isn't the last one than remove also his successor(s). + * Returns the QTD which is part of an new URB and should be enqueued. + */ +static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd) +{ + struct isp1760_qtd *tmp_qtd; + int last_one; + + do { + tmp_qtd = qtd->hw_next; + last_one = qtd->status & URB_COMPLETE_NOTIFY; + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + qtd = tmp_qtd; + } while (!last_one && qtd); + + return qtd; +} + +static void do_atl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 atl_regs_base; + u32 atl_regs; + u32 queue_entry; + u32 payload; + u32 length; + u32 or_map; + u32 status = -EINVAL; + int error; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + u32 rl; + u32 nakcount; + + done_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG); + + atl_regs_base = ATL_REGS_OFFSET; + while (done_map) { + u32 dw1; + u32 dw2; + u32 dw3; + + status = 0; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd); + + urb = priv->atl_ints[queue_entry].urb; + qtd = priv->atl_ints[queue_entry].qtd; + qh = priv->atl_ints[queue_entry].qh; + payload = priv->atl_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "qh is 0\n"); + continue; + } + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs, + atl_regs, sizeof(ptd)); + + dw1 = le32_to_cpu(ptd.dw1); + dw2 = le32_to_cpu(ptd.dw2); + dw3 = le32_to_cpu(ptd.dw3); + rl = (dw2 >> 25) & 0x0f; + nakcount = (dw3 >> 19) & 0xf; + + /* Transfer Error, *but* active and no HALT -> reload */ + if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) && + !(dw3 & DW3_HALT_BIT)) { + + /* according to ppriv code, we have to + * reload this one if trasfered bytes != requested bytes + * else act like everything went smooth.. + * XXX This just doesn't feel right and hasn't + * triggered so far. + */ + + length = PTD_XFERRED_LENGTH(dw3); + printk(KERN_ERR "Should reload now.... transfered %d " + "of %zu\n", length, qtd->length); + BUG(); + } + + if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) { + u32 buffstatus; + + /* XXX + * NAKs are handled in HW by the chip. Usually if the + * device is not able to send data fast enough. + * This did not trigger for a long time now. + */ + printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: " + "%d of %d done: %08x cur: %08x\n", qtd, + urb, qh, PTD_XFERRED_LENGTH(dw3), + qtd->length, done_map, + (1 << queue_entry)); + + /* RL counter = ERR counter */ + dw3 &= ~(0xf << 19); + dw3 |= rl << 19; + dw3 &= ~(3 << (55 - 32)); + dw3 |= ERR_COUNTER << (55 - 32); + + /* + * It is not needed to write skip map back because it + * is unchanged. Just make sure that this entry is + * unskipped once it gets written to the HW. + */ + skip_map &= ~(1 << queue_entry); + or_map = isp1760_readl(usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + or_map |= 1 << queue_entry; + isp1760_writel(or_map, usb_hcd->regs + + HC_ATL_IRQ_MASK_OR_REG); + + ptd.dw3 = cpu_to_le32(dw3); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID); + priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs + + atl_regs, sizeof(ptd)); + + buffstatus = isp1760_readl(usb_hcd->regs + + HC_BUFFER_STATUS_REG); + buffstatus |= ATL_BUFFER; + isp1760_writel(buffstatus, usb_hcd->regs + + HC_BUFFER_STATUS_REG); + continue; + } + + error = check_error(&ptd); + if (error) { + status = error; + priv->atl_ints[queue_entry].qh->toggle = 0; + priv->atl_ints[queue_entry].qh->ping = 0; + urb->status = -EPIPE; + +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + } else { + if (usb_pipetype(urb->pipe) == PIPE_BULK) { + priv->atl_ints[queue_entry].qh->toggle = dw3 & + (1 << 25); + priv->atl_ints[queue_entry].qh->ping = dw3 & + (1 << 26); + } + } + + length = PTD_XFERRED_LENGTH(dw3); + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->atl_ints[queue_entry].data_buffer, + usb_hcd->regs + payload, payload, + length); + + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->atl_ints[queue_entry].data_buffer = NULL; + priv->atl_ints[queue_entry].urb = NULL; + priv->atl_ints[queue_entry].qtd = NULL; + priv->atl_ints[queue_entry].qh = NULL; + + free_mem(priv, payload); + + isp1760_writel(skip_map, usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + + if (urb->status == -EPIPE) { + /* HALT was received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) { + /* short BULK received */ + + printk(KERN_ERR "short bulk, %d instead %d\n", length, + qtd->length); + if (urb->transfer_flags & URB_SHORT_NOT_OK) { + urb->status = -EREMOTEIO; + printk(KERN_ERR "not okey\n"); + } + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_up_qtdlist(qtd); + + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + /* that was the last qtd of that URB */ + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_ATL_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_ATL_PTD_SKIPMAP_REG); + } +} + +static void do_intl_int(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 done_map, skip_map; + struct ptd ptd; + struct urb *urb = NULL; + u32 int_regs; + u32 int_regs_base; + u32 payload; + u32 length; + u32 or_map; + int error; + u32 queue_entry; + struct isp1760_qtd *qtd; + struct isp1760_qh *qh; + + done_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_DONEMAP_REG); + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + + or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + or_map &= ~done_map; + isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG); + + int_regs_base = INT_REGS_OFFSET; + + while (done_map) { + u32 dw1; + u32 dw3; + + queue_entry = __ffs(done_map); + done_map &= ~(1 << queue_entry); + skip_map |= 1 << queue_entry; + + int_regs = int_regs_base + queue_entry * sizeof(struct ptd); + urb = priv->int_ints[queue_entry].urb; + qtd = priv->int_ints[queue_entry].qtd; + qh = priv->int_ints[queue_entry].qh; + payload = priv->int_ints[queue_entry].payload; + + if (!qh) { + printk(KERN_ERR "(INT) qh is 0\n"); + continue; + } + + priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs, + int_regs, sizeof(ptd)); + dw1 = le32_to_cpu(ptd.dw1); + dw3 = le32_to_cpu(ptd.dw3); + check_int_err_status(le32_to_cpu(ptd.dw4)); + + error = check_error(&ptd); + if (error) { +#if 0 + printk(KERN_ERR "Error in %s().\n", __func__); + printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x " + "dw3: %08x dw4: %08x dw5: %08x dw6: " + "%08x dw7: %08x\n", + ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3, + ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7); +#endif + urb->status = -EPIPE; + priv->int_ints[queue_entry].qh->toggle = 0; + priv->int_ints[queue_entry].qh->ping = 0; + + } else { + priv->int_ints[queue_entry].qh->toggle = + dw3 & (1 << 25); + priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26); + } + + if (urb->dev->speed != USB_SPEED_HIGH) + length = PTD_XFERRED_LENGTH_LO(dw3); + else + length = PTD_XFERRED_LENGTH(dw3); + + if (length) { + switch (DW1_GET_PID(dw1)) { + case IN_PID: + priv_read_copy(priv, + priv->int_ints[queue_entry].data_buffer, + usb_hcd->regs + payload , payload, + length); + case OUT_PID: + + urb->actual_length += length; + + case SETUP_PID: + break; + } + } + + priv->int_ints[queue_entry].data_buffer = NULL; + priv->int_ints[queue_entry].urb = NULL; + priv->int_ints[queue_entry].qtd = NULL; + priv->int_ints[queue_entry].qh = NULL; + + isp1760_writel(skip_map, usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + free_mem(priv, payload); + + if (urb->status == -EPIPE) { + /* HALT received */ + + qtd = clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else if (qtd->status & URB_COMPLETE_NOTIFY) { + + if (urb->status == -EINPROGRESS) + urb->status = 0; + + qtd = clean_this_qtd(qtd); + isp1760_urb_done(priv, urb, urb->status); + + } else { + /* next QTD of this URB */ + + qtd = clean_this_qtd(qtd); + BUG_ON(!qtd); + } + + if (qtd) + enqueue_an_INT_packet(usb_hcd, qh, qtd); + + skip_map = isp1760_readl(usb_hcd->regs + + HC_INT_PTD_SKIPMAP_REG); + } +} + +#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) +static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb, + gfp_t flags) +{ + struct isp1760_qh *qh; + int is_input, type; + + qh = isp1760_qh_alloc(priv, flags); + if (!qh) + return qh; + + /* + * init endpoint/device data for this QH + */ + is_input = usb_pipein(urb->pipe); + type = usb_pipetype(urb->pipe); + + if (type == PIPE_INTERRUPT) { + + if (urb->dev->speed == USB_SPEED_HIGH) { + + qh->period = urb->interval >> 3; + if (qh->period == 0 && urb->interval != 1) { + /* NOTE interval 2 or 4 uframes could work. + * But interval 1 scheduling is simpler, and + * includes high bandwidth. + */ + printk(KERN_ERR "intr period %d uframes, NYET!", + urb->interval); + qh_destroy(qh); + return NULL; + } + } else { + qh->period = urb->interval; + } + } + + /* support for tt scheduling, and access to toggles */ + qh->dev = urb->dev; + + if (!usb_pipecontrol(urb->pipe)) + usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, + 1); + return qh; +} + +/* + * For control/bulk/interrupt, return QH with these TDs appended. + * Allocates and initializes the QH if necessary. + * Returns null if it can't allocate a QH it needs to. + * If the QH has TDs (urbs) already, that's great. + */ +static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *qtd_list, int epnum, + void **ptr) +{ + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + struct isp1760_qtd *prev_qtd; + + qh = (struct isp1760_qh *)*ptr; + if (!qh) { + /* can't sleep here, we have priv->lock... */ + qh = qh_make(priv, urb, GFP_ATOMIC); + if (!qh) + return qh; + *ptr = qh; + } + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, + qtd_list); + if (!list_empty(&qh->qtd_list)) + prev_qtd = list_entry(qh->qtd_list.prev, + struct isp1760_qtd, qtd_list); + else + prev_qtd = NULL; + + list_splice(qtd_list, qh->qtd_list.prev); + if (prev_qtd) { + BUG_ON(prev_qtd->hw_next); + prev_qtd->hw_next = qtd; + } + + urb->hcpriv = qh; + return qh; +} + +static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list) +{ + struct list_head *entry, *temp; + + list_for_each_safe(entry, temp, qtd_list) { + struct isp1760_qtd *qtd; + + qtd = list_entry(entry, struct isp1760_qtd, qtd_list); + list_del(&qtd->qtd_list); + isp1760_qtd_free(qtd); + } +} + +static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb, + struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p) +{ + struct isp1760_qtd *qtd; + int epnum; + unsigned long flags; + struct isp1760_qh *qh = NULL; + int rc; + int qh_busy; + + qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list); + epnum = urb->ep->desc.bEndpointAddress; + + spin_lock_irqsave(&priv->lock, flags); + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) { + rc = -ESHUTDOWN; + goto done; + } + rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb); + if (rc) + goto done; + + qh = urb->ep->hcpriv; + if (qh) + qh_busy = !list_empty(&qh->qtd_list); + else + qh_busy = 0; + + qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv); + if (!qh) { + usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb); + rc = -ENOMEM; + goto done; + } + + if (!qh_busy) + p(priv_to_hcd(priv), qh, qtd); + +done: + spin_unlock_irqrestore(&priv->lock, flags); + if (!qh) + qtd_list_free(priv, urb, qtd_list); + return rc; +} + +static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv, + gfp_t flags) +{ + struct isp1760_qtd *qtd; + + qtd = kmem_cache_zalloc(qtd_cachep, flags); + if (qtd) + INIT_LIST_HEAD(&qtd->qtd_list); + + return qtd; +} + +/* + * create a list of filled qtds for this URB; won't link into qh. + */ +static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv, + struct urb *urb, struct list_head *head, gfp_t flags) +{ + struct isp1760_qtd *qtd, *qtd_prev; + void *buf; + int len, maxpacket; + int is_input; + u32 token; + + /* + * URBs map to sequences of QTDs: one logical transaction + */ + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + return NULL; + + list_add_tail(&qtd->qtd_list, head); + qtd->urb = urb; + urb->status = -EINPROGRESS; + + token = 0; + /* for split transactions, SplitXState initialized to zero */ + + len = urb->transfer_buffer_length; + is_input = usb_pipein(urb->pipe); + if (usb_pipecontrol(urb->pipe)) { + /* SETUP pid */ + qtd_fill(qtd, urb->setup_packet, + sizeof(struct usb_ctrlrequest), + token | SETUP_PID); + + /* ... and always at least one more pid */ + token ^= DATA_TOGGLE; + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* for zero length DATA stages, STATUS is always IN */ + if (len == 0) + token |= IN_PID; + } + + /* + * data transfer stage: buffer setup + */ + buf = urb->transfer_buffer; + + if (is_input) + token |= IN_PID; + else + token |= OUT_PID; + + maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); + + /* + * buffer gets wrapped in one or more qtds; + * last one may be "short" (including zero len) + * and may serve as a control status ack + */ + for (;;) { + int this_qtd_len; + + if (!buf && len) { + /* XXX This looks like usb storage / SCSI bug */ + printk(KERN_ERR "buf is null, dma is %08lx len is %d\n", + (long unsigned)urb->transfer_dma, len); + WARN_ON(1); + } + + this_qtd_len = qtd_fill(qtd, buf, len, token); + len -= this_qtd_len; + buf += this_qtd_len; + + /* qh makes control packets use qtd toggle; maybe switch it */ + if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) + token ^= DATA_TOGGLE; + + if (len <= 0) + break; + + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + } + + /* + * control requests may need a terminating data "status" ack; + * bulk ones may need a terminating short packet (zero length). + */ + if (urb->transfer_buffer_length != 0) { + int one_more = 0; + + if (usb_pipecontrol(urb->pipe)) { + one_more = 1; + /* "in" <--> "out" */ + token ^= IN_PID; + /* force DATA1 */ + token |= DATA_TOGGLE; + } else if (usb_pipebulk(urb->pipe) + && (urb->transfer_flags & URB_ZERO_PACKET) + && !(urb->transfer_buffer_length % maxpacket)) { + one_more = 1; + } + if (one_more) { + qtd_prev = qtd; + qtd = isp1760_qtd_alloc(priv, flags); + if (!qtd) + goto cleanup; + qtd->urb = urb; + qtd_prev->hw_next = qtd; + list_add_tail(&qtd->qtd_list, head); + + /* never any data in such packets */ + qtd_fill(qtd, NULL, 0, token); + } + } + + qtd->status = URB_COMPLETE_NOTIFY; + return head; + +cleanup: + qtd_list_free(priv, urb, head); + return NULL; +} + +static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct list_head qtd_list; + packet_enqueue *pe; + + INIT_LIST_HEAD(&qtd_list); + + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: + case PIPE_BULK: + + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_ATL_packet; + break; + + case PIPE_INTERRUPT: + if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags)) + return -ENOMEM; + pe = enqueue_an_INT_packet; + break; + + case PIPE_ISOCHRONOUS: + printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n"); + default: + return -EPIPE; + } + + isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe); + return 0; +} + +static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, + int status) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + struct inter_packet_info *ints; + u32 i; + u32 reg_base, or_reg, skip_reg; + int flags; + struct ptd ptd; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: + return -EPIPE; + break; + + case PIPE_INTERRUPT: + ints = priv->int_ints; + reg_base = INT_REGS_OFFSET; + or_reg = HC_INT_IRQ_MASK_OR_REG; + skip_reg = HC_INT_PTD_SKIPMAP_REG; + break; + + default: + ints = priv->atl_ints; + reg_base = ATL_REGS_OFFSET; + or_reg = HC_ATL_IRQ_MASK_OR_REG; + skip_reg = HC_ATL_PTD_SKIPMAP_REG; + break; + } + + memset(&ptd, 0, sizeof(ptd)); + spin_lock_irqsave(&priv->lock, flags); + + for (i = 0; i < 32; i++) { + if (ints->urb == urb) { + u32 skip_map; + u32 or_map; + struct isp1760_qtd *qtd; + + skip_map = isp1760_readl(hcd->regs + skip_reg); + skip_map |= 1 << i; + isp1760_writel(skip_map, hcd->regs + skip_reg); + + or_map = isp1760_readl(hcd->regs + or_reg); + or_map &= ~(1 << i); + isp1760_writel(or_map, hcd->regs + or_reg); + + priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base + + i * sizeof(ptd), sizeof(ptd)); + qtd = ints->qtd; + + clean_up_qtdlist(qtd); + + free_mem(priv, ints->payload); + + ints->urb = NULL; + ints->qh = NULL; + ints->qtd = NULL; + ints->data_buffer = NULL; + ints->payload = 0; + + isp1760_urb_done(priv, urb, status); + break; + } + ints++; + } + + spin_unlock_irqrestore(&priv->lock, flags); + return 0; +} + +static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + u32 imask; + irqreturn_t irqret = IRQ_NONE; + + spin_lock(&priv->lock); + + if (!(usb_hcd->state & HC_STATE_RUNNING)) + goto leave; + + imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG); + if (unlikely(!imask)) + goto leave; + + isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG); + if (imask & HC_ATL_INT) + do_atl_int(usb_hcd); + + if (imask & HC_INTL_INT) + do_intl_int(usb_hcd); + + irqret = IRQ_HANDLED; +leave: + spin_unlock(&priv->lock); + return irqret; +} + +static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 temp, status = 0; + u32 mask; + int retval = 1; + unsigned long flags; + + /* if !USB_SUSPEND, root hub timers won't get shut down ... */ + if (!HC_IS_RUNNING(hcd->state)) + return 0; + + /* init status to no-changes */ + buf[0] = 0; + mask = PORT_CSC; + + spin_lock_irqsave(&priv->lock, flags); + temp = isp1760_readl(hcd->regs + HC_PORTSC1); + + if (temp & PORT_OWNER) { + if (temp & PORT_CSC) { + temp &= ~PORT_CSC; + isp1760_writel(temp, hcd->regs + HC_PORTSC1); + goto done; + } + } + + /* + * Return status information even for ports with OWNER set. + * Otherwise khubd wouldn't see the disconnect event when a + * high-speed device is switched over to the companion + * controller by the user. + */ + + if ((temp & mask) != 0 + || ((temp & PORT_RESUME) != 0 + && time_after_eq(jiffies, + priv->reset_done))) { + buf [0] |= 1 << (0 + 1); + status = STS_PCD; + } + /* FIXME autosuspend idle root hubs */ +done: + spin_unlock_irqrestore(&priv->lock, flags); + return status ? retval : 0; +} + +static void isp1760_hub_descriptor(struct isp1760_hcd *priv, + struct usb_hub_descriptor *desc) +{ + int ports = HCS_N_PORTS(priv->hcs_params); + u16 temp; + + desc->bDescriptorType = 0x29; + /* priv 1.0, 2.3.9 says 20ms max */ + desc->bPwrOn2PwrGood = 10; + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = ports; + temp = 1 + (ports / 8); + desc->bDescLength = 7 + 2 * temp; + + /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ + memset(&desc->bitmap[0], 0, temp); + memset(&desc->bitmap[temp], 0xff, temp); + + /* per-port overcurrent reporting */ + temp = 0x0008; + if (HCS_PPC(priv->hcs_params)) + /* per-port power control */ + temp |= 0x0001; + else + /* no power switching */ + temp |= 0x0002; + desc->wHubCharacteristics = cpu_to_le16(temp); +} + +#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) + +static int check_reset_complete(struct isp1760_hcd *priv, int index, + u32 __iomem *status_reg, int port_status) +{ + if (!(port_status & PORT_CONNECT)) + return port_status; + + /* if reset finished and it's still not enabled -- handoff */ + if (!(port_status & PORT_PE)) { + + printk(KERN_ERR "port %d full speed --> companion\n", + index + 1); + + port_status |= PORT_OWNER; + port_status &= ~PORT_RWC_BITS; + isp1760_writel(port_status, status_reg); + + } else + printk(KERN_ERR "port %d high speed\n", index + 1); + + return port_status; +} + +static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, + u16 wValue, u16 wIndex, char *buf, u16 wLength) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + int ports = HCS_N_PORTS(priv->hcs_params); + u32 __iomem *status_reg = hcd->regs + HC_PORTSC1; + u32 temp, status; + unsigned long flags; + int retval = 0; + unsigned selector; + + /* + * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. + * HCS_INDICATOR may say we can change LEDs to off/amber/green. + * (track current state ourselves) ... blink for diagnostics, + * power, "this is the one", etc. EHCI spec supports this. + */ + + spin_lock_irqsave(&priv->lock, flags); + switch (typeReq) { + case ClearHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + + /* + * Even if OWNER is set, so the port is owned by the + * companion controller, khubd needs to be able to clear + * the port-change status bits (especially + * USB_PORT_FEAT_C_CONNECTION). + */ + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp & ~PORT_PE, status_reg); + break; + case USB_PORT_FEAT_C_ENABLE: + /* XXX error? */ + break; + case USB_PORT_FEAT_SUSPEND: + if (temp & PORT_RESET) + goto error; + + if (temp & PORT_SUSPEND) { + if ((temp & PORT_PE) == 0) + goto error; + /* resume signaling for 20 msec */ + temp &= ~(PORT_RWC_BITS); + isp1760_writel(temp | PORT_RESUME, + status_reg); + priv->reset_done = jiffies + + msecs_to_jiffies(20); + } + break; + case USB_PORT_FEAT_C_SUSPEND: + /* we auto-clear this feature */ + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp & ~PORT_POWER, status_reg); + break; + case USB_PORT_FEAT_C_CONNECTION: + isp1760_writel(temp | PORT_CSC, + status_reg); + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + /* XXX error ?*/ + break; + case USB_PORT_FEAT_C_RESET: + /* GetPortStatus clears reset */ + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + case GetHubDescriptor: + isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) + buf); + break; + case GetHubStatus: + /* no hub-wide feature/status flags */ + memset(buf, 0, 4); + break; + case GetPortStatus: + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + status = 0; + temp = isp1760_readl(status_reg); + + /* wPortChange bits */ + if (temp & PORT_CSC) + status |= 1 << USB_PORT_FEAT_C_CONNECTION; + + + /* whoever resumes must GetPortStatus to complete it!! */ + if (temp & PORT_RESUME) { + printk(KERN_ERR "Port resume should be skipped.\n"); + + /* Remote Wakeup received? */ + if (!priv->reset_done) { + /* resume signaling for 20 msec */ + priv->reset_done = jiffies + + msecs_to_jiffies(20); + /* check the port again */ + mod_timer(&priv_to_hcd(priv)->rh_timer, + priv->reset_done); + } + + /* resume completed? */ + else if (time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_SUSPEND; + priv->reset_done = 0; + + /* stop resume signaling */ + temp = isp1760_readl(status_reg); + isp1760_writel( + temp & ~(PORT_RWC_BITS | PORT_RESUME), + status_reg); + retval = handshake(priv, status_reg, + PORT_RESUME, 0, 2000 /* 2msec */); + if (retval != 0) { + isp1760_err(priv, + "port %d resume error %d\n", + wIndex + 1, retval); + goto error; + } + temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); + } + } + + /* whoever resets must GetPortStatus to complete it!! */ + if ((temp & PORT_RESET) + && time_after_eq(jiffies, + priv->reset_done)) { + status |= 1 << USB_PORT_FEAT_C_RESET; + priv->reset_done = 0; + + /* force reset to complete */ + isp1760_writel(temp & ~PORT_RESET, + status_reg); + /* REVISIT: some hardware needs 550+ usec to clear + * this bit; seems too long to spin routinely... + */ + retval = handshake(priv, status_reg, + PORT_RESET, 0, 750); + if (retval != 0) { + isp1760_err(priv, "port %d reset error %d\n", + wIndex + 1, retval); + goto error; + } + + /* see what we found out */ + temp = check_reset_complete(priv, wIndex, status_reg, + isp1760_readl(status_reg)); + } + /* + * Even if OWNER is set, there's no harm letting khubd + * see the wPortStatus values (they should all be 0 except + * for PORT_POWER anyway). + */ + + if (temp & PORT_OWNER) + printk(KERN_ERR "Warning: PORT_OWNER is set\n"); + + if (temp & PORT_CONNECT) { + status |= 1 << USB_PORT_FEAT_CONNECTION; + /* status may be from integrated TT */ + status |= ehci_port_speed(priv, temp); + } + if (temp & PORT_PE) + status |= 1 << USB_PORT_FEAT_ENABLE; + if (temp & (PORT_SUSPEND|PORT_RESUME)) + status |= 1 << USB_PORT_FEAT_SUSPEND; + if (temp & PORT_RESET) + status |= 1 << USB_PORT_FEAT_RESET; + if (temp & PORT_POWER) + status |= 1 << USB_PORT_FEAT_POWER; + + put_unaligned(cpu_to_le32(status), (__le32 *) buf); + break; + case SetHubFeature: + switch (wValue) { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* no hub-wide feature/status flags */ + break; + default: + goto error; + } + break; + case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; + if (!wIndex || wIndex > ports) + goto error; + wIndex--; + temp = isp1760_readl(status_reg); + if (temp & PORT_OWNER) + break; + +/* temp &= ~PORT_RWC_BITS; */ + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + isp1760_writel(temp | PORT_PE, status_reg); + break; + + case USB_PORT_FEAT_SUSPEND: + if ((temp & PORT_PE) == 0 + || (temp & PORT_RESET) != 0) + goto error; + + isp1760_writel(temp | PORT_SUSPEND, status_reg); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(priv->hcs_params)) + isp1760_writel(temp | PORT_POWER, + status_reg); + break; + case USB_PORT_FEAT_RESET: + if (temp & PORT_RESUME) + goto error; + /* line status bits may report this as low speed, + * which can be fine if this root hub has a + * transaction translator built in. + */ + if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT + && PORT_USB11(temp)) { + temp |= PORT_OWNER; + } else { + temp |= PORT_RESET; + temp &= ~PORT_PE; + + /* + * caller must wait, then call GetPortStatus + * usb 2.0 spec says 50 ms resets on root + */ + priv->reset_done = jiffies + + msecs_to_jiffies(50); + } + isp1760_writel(temp, status_reg); + break; + default: + goto error; + } + isp1760_readl(hcd->regs + HC_USBCMD); + break; + + default: +error: + /* "stall" on error */ + retval = -EPIPE; + } + spin_unlock_irqrestore(&priv->lock, flags); + return retval; +} + +static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd, + struct usb_host_endpoint *ep) +{ + struct isp1760_hcd *priv = hcd_to_priv(usb_hcd); + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; + u32 flags; + + spin_lock_irqsave(&priv->lock, flags); + qh = ep->hcpriv; + if (!qh) + goto out; + + ep->hcpriv = NULL; + do { + /* more than entry might get removed */ + if (list_empty(&qh->qtd_list)) + break; + + qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd, + qtd_list); + + if (qtd->status & URB_ENQUEUED) { + + spin_unlock_irqrestore(&priv->lock, flags); + isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET); + spin_lock_irqsave(&priv->lock, flags); + } else { + struct urb *urb; + + urb = qtd->urb; + clean_up_qtdlist(qtd); + isp1760_urb_done(priv, urb, -ECONNRESET); + } + } while (1); + + qh_destroy(qh); + /* remove requests and leak them. + * ATL are pretty fast done, INT could take a while... + * The latter shoule be removed + */ +out: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int isp1760_get_frame(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + u32 fr; + + fr = isp1760_readl(hcd->regs + HC_FRINDEX); + return (fr >> 3) % priv->periodic_size; +} + +static void isp1760_stop(struct usb_hcd *hcd) +{ + struct isp1760_hcd *priv = hcd_to_priv(hcd); + + isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, + NULL, 0); + mdelay(20); + + spin_lock_irq(&priv->lock); + ehci_reset(priv); + /* Disable IRQ */ + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + spin_unlock_irq(&priv->lock); + + isp1760_writel(0, hcd->regs + HC_CONFIGFLAG); +} + +static void isp1760_shutdown(struct usb_hcd *hcd) +{ + u32 command; + + isp1760_stop(hcd); + isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL); + + command = isp1760_readl(hcd->regs + HC_USBCMD); + command &= ~CMD_RUN; + isp1760_writel(command, hcd->regs + HC_USBCMD); +} + +static const struct hc_driver isp1760_hc_driver = { + .description = "isp1760-hcd", + .product_desc = "NXP ISP1760 USB Host Controller", + .hcd_priv_size = sizeof(struct isp1760_hcd), + .irq = isp1760_irq, + .flags = HCD_MEMORY | HCD_USB2, + .reset = isp1760_hc_setup, + .start = isp1760_run, + .stop = isp1760_stop, + .shutdown = isp1760_shutdown, + .urb_enqueue = isp1760_urb_enqueue, + .urb_dequeue = isp1760_urb_dequeue, + .endpoint_disable = isp1760_endpoint_disable, + .get_frame_number = isp1760_get_frame, + .hub_status_data = isp1760_hub_status_data, + .hub_control = isp1760_hub_control, +}; + +int __init init_kmem_once(void) +{ + qtd_cachep = kmem_cache_create("isp1760_qtd", + sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | + SLAB_MEM_SPREAD, NULL); + + if (!qtd_cachep) + return -ENOMEM; + + qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), + 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); + + if (!qh_cachep) { + kmem_cache_destroy(qtd_cachep); + return -ENOMEM; + } + + return 0; +} + +void deinit_kmem_cache(void) +{ + kmem_cache_destroy(qtd_cachep); + kmem_cache_destroy(qh_cachep); +} + +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname) +{ + struct usb_hcd *hcd; + struct isp1760_hcd *priv; + int ret; + + if (usb_disabled()) + return ERR_PTR(-ENODEV); + + /* prevent usb-core allocating DMA pages */ + dev->dma_mask = NULL; + + hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id); + if (!hcd) + return ERR_PTR(-ENOMEM); + + priv = hcd_to_priv(hcd); + init_memory(priv); + hcd->regs = ioremap(res_start, res_len); + if (!hcd->regs) { + ret = -EIO; + goto err_put; + } + + ret = usb_add_hcd(hcd, irq, irqflags); + if (ret) + goto err_unmap; + + hcd->irq = irq; + hcd->rsrc_start = res_start; + hcd->rsrc_len = res_len; + + return hcd; + +err_unmap: + iounmap(hcd->regs); + +err_put: + usb_put_hcd(hcd); + + return ERR_PTR(ret); +} + +MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); +MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h new file mode 100644 index 000000000000..3d86d0f6b147 --- /dev/null +++ b/drivers/usb/host/isp1760-hcd.h @@ -0,0 +1,206 @@ +#ifndef _ISP1760_HCD_H_ +#define _ISP1760_HCD_H_ + +/* exports for if */ +struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, + u64 irqflags, struct device *dev, const char *busname); +int init_kmem_once(void); +void deinit_kmem_cache(void); + +/* EHCI capability registers */ +#define HC_CAPLENGTH 0x00 +#define HC_HCSPARAMS 0x04 +#define HC_HCCPARAMS 0x08 + +/* EHCI operational registers */ +#define HC_USBCMD 0x20 +#define HC_USBSTS 0x24 +#define HC_FRINDEX 0x2c +#define HC_CONFIGFLAG 0x60 +#define HC_PORTSC1 0x64 +#define HC_ISO_PTD_DONEMAP_REG 0x130 +#define HC_ISO_PTD_SKIPMAP_REG 0x134 +#define HC_ISO_PTD_LASTPTD_REG 0x138 +#define HC_INT_PTD_DONEMAP_REG 0x140 +#define HC_INT_PTD_SKIPMAP_REG 0x144 +#define HC_INT_PTD_LASTPTD_REG 0x148 +#define HC_ATL_PTD_DONEMAP_REG 0x150 +#define HC_ATL_PTD_SKIPMAP_REG 0x154 +#define HC_ATL_PTD_LASTPTD_REG 0x158 + +/* Configuration Register */ +#define HC_HW_MODE_CTRL 0x300 +#define ALL_ATX_RESET (1 << 31) +#define HW_DATA_BUS_32BIT (1 << 8) +#define HW_DACK_POL_HIGH (1 << 6) +#define HW_DREQ_POL_HIGH (1 << 5) +#define HW_INTR_HIGH_ACT (1 << 2) +#define HW_INTR_EDGE_TRIG (1 << 1) +#define HW_GLOBAL_INTR_EN (1 << 0) + +#define HC_CHIP_ID_REG 0x304 +#define HC_SCRATCH_REG 0x308 + +#define HC_RESET_REG 0x30c +#define SW_RESET_RESET_HC (1 << 1) +#define SW_RESET_RESET_ALL (1 << 0) + +#define HC_BUFFER_STATUS_REG 0x334 +#define ATL_BUFFER 0x1 +#define INT_BUFFER 0x2 +#define ISO_BUFFER 0x4 +#define BUFFER_MAP 0x7 + +#define HC_MEMORY_REG 0x33c +#define HC_PORT1_CTRL 0x374 +#define PORT1_POWER (3 << 3) +#define PORT1_INIT1 (1 << 7) +#define PORT1_INIT2 (1 << 23) + +/* Interrupt Register */ +#define HC_INTERRUPT_REG 0x310 + +#define HC_INTERRUPT_ENABLE 0x314 +#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT) +#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT) + +#define HC_ISO_INT (1 << 9) +#define HC_ATL_INT (1 << 8) +#define HC_INTL_INT (1 << 7) +#define HC_EOT_INT (1 << 3) +#define HC_SOT_INT (1 << 1) + +#define HC_ISO_IRQ_MASK_OR_REG 0x318 +#define HC_INT_IRQ_MASK_OR_REG 0x31C +#define HC_ATL_IRQ_MASK_OR_REG 0x320 +#define HC_ISO_IRQ_MASK_AND_REG 0x324 +#define HC_INT_IRQ_MASK_AND_REG 0x328 +#define HC_ATL_IRQ_MASK_AND_REG 0x32C + +/* Register sets */ +#define HC_BEGIN_OF_ATL 0x0c00 +#define HC_BEGIN_OF_INT 0x0800 +#define HC_BEGIN_OF_ISO 0x0400 +#define HC_BEGIN_OF_PAYLOAD 0x1000 + +/* urb state*/ +#define DELETE_URB (0x0008) +#define NO_TRANSFER_ACTIVE (0xffffffff) + +#define ATL_REGS_OFFSET (0xc00) +#define INT_REGS_OFFSET (0x800) + +/* Philips Transfer Descriptor (PTD) */ +struct ptd { + __le32 dw0; + __le32 dw1; + __le32 dw2; + __le32 dw3; + __le32 dw4; + __le32 dw5; + __le32 dw6; + __le32 dw7; +}; + +struct inter_packet_info { + void *data_buffer; + u32 payload; +#define PTD_FIRE_NEXT (1 << 0) +#define PTD_URB_FINISHED (1 << 1) + struct urb *urb; + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; +}; + + +typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, + struct isp1760_qtd *qtd); + +#define isp1760_info(priv, fmt, args...) \ + dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args) + +#define isp1760_err(priv, fmt, args...) \ + dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args) + +/* chip memory management */ +struct memory_chunk { + unsigned int start; + unsigned int size; + unsigned int free; +}; + +/* + * 60kb divided in: + * - 32 blocks @ 256 bytes + * - 20 blocks @ 1024 bytes + * - 4 blocks @ 8192 bytes + */ + +#define BLOCK_1_NUM 32 +#define BLOCK_2_NUM 20 +#define BLOCK_3_NUM 4 + +#define BLOCK_1_SIZE 256 +#define BLOCK_2_SIZE 1024 +#define BLOCK_3_SIZE 8192 +#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) +#define PAYLOAD_SIZE 0xf000 + +/* I saw if some reloads if the pointer was negative */ +#define ISP1760_NULL_POINTER (0x400) + +/* ATL */ +/* DW0 */ +#define PTD_VALID 1 +#define PTD_LENGTH(x) (((u32) x) << 3) +#define PTD_MAXPACKET(x) (((u32) x) << 18) +#define PTD_MULTI(x) (((u32) x) << 29) +#define PTD_ENDPOINT(x) (((u32) x) << 31) +/* DW1 */ +#define PTD_DEVICE_ADDR(x) (((u32) x) << 3) +#define PTD_PID_TOKEN(x) (((u32) x) << 10) +#define PTD_TRANS_BULK ((u32) 2 << 12) +#define PTD_TRANS_INT ((u32) 3 << 12) +#define PTD_TRANS_SPLIT ((u32) 1 << 14) +#define PTD_SE_USB_LOSPEED ((u32) 2 << 16) +#define PTD_PORT_NUM(x) (((u32) x) << 18) +#define PTD_HUB_NUM(x) (((u32) x) << 25) +#define PTD_PING(x) (((u32) x) << 26) +/* DW2 */ +#define PTD_RL_CNT(x) (((u32) x) << 25) +#define PTD_DATA_START_ADDR(x) (((u32) x) << 8) +#define BASE_ADDR 0x1000 +/* DW3 */ +#define PTD_CERR(x) (((u32) x) << 23) +#define PTD_NAC_CNT(x) (((u32) x) << 19) +#define PTD_ACTIVE ((u32) 1 << 31) +#define PTD_DATA_TOGGLE(x) (((u32) x) << 25) + +#define DW3_HALT_BIT (1 << 30) +#define DW3_ERROR_BIT (1 << 28) +#define DW3_QTD_ACTIVE (1 << 31) + +#define INT_UNDERRUN (1 << 2) +#define INT_BABBLE (1 << 1) +#define INT_EXACT (1 << 0) + +#define DW1_GET_PID(x) (((x) >> 10) & 0x3) +#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff) +#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff) + +#define SETUP_PID (2) +#define IN_PID (1) +#define OUT_PID (0) +#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3) + +#define DATA_TOGGLE (1 << 31) +#define GET_DATA_TOGGLE(x) ((x) >> 31) + +/* Errata 1 */ +#define RL_COUNTER (0) +#define NAK_COUNTER (0) +#define ERR_COUNTER (2) + +#define HC_ATL_PL_SIZE (8192) + +#endif diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c new file mode 100644 index 000000000000..73fb2a38f1e4 --- /dev/null +++ b/drivers/usb/host/isp1760-if.c @@ -0,0 +1,298 @@ +/* + * Glue code for the ISP1760 driver and bus + * Currently there is support for + * - OpenFirmware + * - PCI + * + * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> + * + */ + +#include <linux/usb.h> +#include <linux/io.h> + +#include "../core/hcd.h" +#include "isp1760-hcd.h" + +#ifdef CONFIG_USB_ISP1760_OF +#include <linux/of.h> +#include <linux/of_platform.h> +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +#include <linux/pci.h> +#endif + +#ifdef CONFIG_USB_ISP1760_OF +static int of_isp1760_probe(struct of_device *dev, + const struct of_device_id *match) +{ + struct usb_hcd *hcd; + struct device_node *dp = dev->node; + struct resource *res; + struct resource memory; + struct of_irq oirq; + int virq; + u64 res_len; + int ret; + + ret = of_address_to_resource(dp, 0, &memory); + if (ret) + return -ENXIO; + + res = request_mem_region(memory.start, memory.end - memory.start + 1, + dev->dev.bus_id); + if (!res) + return -EBUSY; + + res_len = memory.end - memory.start + 1; + + if (of_irq_map_one(dp, 0, &oirq)) { + ret = -ENODEV; + goto release_reg; + } + + virq = irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); + + hcd = isp1760_register(memory.start, res_len, virq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + if (IS_ERR(hcd)) { + ret = PTR_ERR(hcd); + goto release_reg; + } + + dev_set_drvdata(&dev->dev, hcd); + return ret; + +release_reg: + release_mem_region(memory.start, memory.end - memory.start + 1); + return ret; +} + +static int of_isp1760_remove(struct of_device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(&dev->dev); + + dev_set_drvdata(&dev->dev, NULL); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + return 0; +} + +static struct of_device_id of_isp1760_match[] = { + { + .compatible = "nxp,usb-isp1760", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_isp1760_match); + +static struct of_platform_driver isp1760_of_driver = { + .name = "nxp-isp1760", + .match_table = of_isp1760_match, + .probe = of_isp1760_probe, + .remove = of_isp1760_remove, +}; +#endif + +#ifdef CONFIG_USB_ISP1760_PCI +static u32 nxp_pci_io_base; +static u32 iolength; +static u32 pci_mem_phy0; +static u32 length; +static u8 *chip_addr; +static u8 *iobase; + +static int __devinit isp1761_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u8 latency, limit; + __u32 reg_data; + int retry_count; + int length; + int status = 1; + struct usb_hcd *hcd; + + if (usb_disabled()) + return -ENODEV; + + if (pci_enable_device(dev) < 0) + return -ENODEV; + + if (!dev->irq) + return -ENODEV; + + /* Grab the PLX PCI mem maped port start address we need */ + nxp_pci_io_base = pci_resource_start(dev, 0); + iolength = pci_resource_len(dev, 0); + + if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { + printk(KERN_ERR "request region #1\n"); + return -EBUSY; + } + + iobase = ioremap_nocache(nxp_pci_io_base, iolength); + if (!iobase) { + printk(KERN_ERR "ioremap #1\n"); + release_mem_region(nxp_pci_io_base, iolength); + return -ENOMEM; + } + /* Grab the PLX PCI shared memory of the ISP 1761 we need */ + pci_mem_phy0 = pci_resource_start(dev, 3); + length = pci_resource_len(dev, 3); + + if (length < 0xffff) { + printk(KERN_ERR "memory length for this resource is less than " + "required\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -ENOMEM; + } + + if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) { + printk(KERN_ERR "host controller already in use\n"); + release_mem_region(nxp_pci_io_base, iolength); + iounmap(iobase); + return -EBUSY; + } + + /* bad pci latencies can contribute to overruns */ + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); + if (latency) { + pci_read_config_byte(dev, PCI_MAX_LAT, &limit); + if (limit && limit < latency) + pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); + } + + /* Try to check whether we can access Scratch Register of + * Host Controller or not. The initial PCI access is retried until + * local init for the PCI bridge is completed + */ + retry_count = 20; + reg_data = 0; + while ((reg_data != 0xFACE) && retry_count) { + /*by default host is in 16bit mode, so + * io operations at this stage must be 16 bit + * */ + writel(0xface, chip_addr + HC_SCRATCH_REG); + udelay(100); + reg_data = readl(chip_addr + HC_SCRATCH_REG); + retry_count--; + } + + /* Host Controller presence is detected by writing to scratch register + * and reading back and checking the contents are same or not + */ + if (reg_data != 0xFACE) { + err("scratch register mismatch %x", reg_data); + goto clean; + } + + pci_set_master(dev); + + status = readl(iobase + 0x68); + status |= 0x900; + writel(status, iobase + 0x68); + + dev->dev.dma_mask = NULL; + hcd = isp1760_register(pci_mem_phy0, length, dev->irq, + IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id); + pci_set_drvdata(dev, hcd); + if (!hcd) + return 0; +clean: + status = -ENODEV; + iounmap(iobase); + release_mem_region(pci_mem_phy0, length); + release_mem_region(nxp_pci_io_base, iolength); + return status; +} +static void isp1761_pci_remove(struct pci_dev *dev) +{ + struct usb_hcd *hcd; + + hcd = pci_get_drvdata(dev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + + pci_disable_device(dev); + + iounmap(iobase); + iounmap(chip_addr); + + release_mem_region(nxp_pci_io_base, iolength); + release_mem_region(pci_mem_phy0, length); +} + +static void isp1761_pci_shutdown(struct pci_dev *dev) +{ + printk(KERN_ERR "ips1761_pci_shutdown\n"); +} + +static const struct pci_device_id isp1760_plx [] = { { + /* handle any USB 2.0 EHCI controller */ + PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0), + .driver_data = 0, +}, +{ /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, isp1760_plx); + +static struct pci_driver isp1761_pci_driver = { + .name = "isp1760", + .id_table = isp1760_plx, + .probe = isp1761_pci_probe, + .remove = isp1761_pci_remove, + .shutdown = isp1761_pci_shutdown, +}; +#endif + +static int __init isp1760_init(void) +{ + int ret; + + init_kmem_once(); + +#ifdef CONFIG_USB_ISP1760_OF + ret = of_register_platform_driver(&isp1760_of_driver); + if (ret) { + deinit_kmem_cache(); + return ret; + } +#endif +#ifdef CONFIG_USB_ISP1760_PCI + ret = pci_register_driver(&isp1761_pci_driver); + if (ret) + goto unreg_of; +#endif + return ret; + +#ifdef CONFIG_USB_ISP1760_PCI +unreg_of: +#endif +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif + deinit_kmem_cache(); + return ret; +} +module_init(isp1760_init); + +static void __exit isp1760_exit(void) +{ +#ifdef CONFIG_USB_ISP1760_OF + of_unregister_platform_driver(&isp1760_of_driver); +#endif +#ifdef CONFIG_USB_ISP1760_PCI + pci_unregister_driver(&isp1761_pci_driver); +#endif + deinit_kmem_cache(); +} +module_exit(isp1760_exit); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index d72dc07dda01..c96db1153dcf 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -261,7 +261,6 @@ static const struct hc_driver ohci_at91_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -348,6 +347,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) if (!clocked) at91_start_clock(); + ohci_finish_controller_resume(hcd); return 0; } #else diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index f90fe0c7373f..1b9abdba920b 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -288,7 +288,6 @@ static const struct hc_driver ohci_au1xxx_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index a22c30aa745d..e06bfaebec54 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -655,7 +655,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) hcd->product_desc, hcd_name); - if (bus->controller->power.power_state.event) { + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { size -= scnprintf (next, size, "SUSPENDED (no register access)\n"); goto done; diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 156e93a9d0df..06aadfb0ec29 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -135,7 +135,6 @@ static struct hc_driver ohci_ep93xx_hc_driver = { .get_frame_number = ohci_get_frame, .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -177,7 +176,6 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_ ep93xx_stop_hc(&pdev->dev); hcd->state = HC_STATE_SUSPENDED; - pdev->dev.power.power_state = PMSG_SUSPEND; return 0; } @@ -193,9 +191,8 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) ohci->next_statechange = jiffies; ep93xx_start_hc(&pdev->dev); - pdev->dev.power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(hcd); + ohci_finish_controller_resume(hcd); return 0; } #endif diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 48e4b11f4d3e..79a78029f896 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -36,18 +36,6 @@ /*-------------------------------------------------------------------------*/ -/* hcd->hub_irq_enable() */ -static void ohci_rhsc_enable (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - spin_lock_irq(&ohci->lock); - if (!ohci->autostop) - del_timer(&hcd->rh_timer); /* Prevent next poll */ - ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); - spin_unlock_irq(&ohci->lock); -} - #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) @@ -103,11 +91,11 @@ __acquires(ohci->lock) finish_unlinks (ohci, ohci_frame_no(ohci)); /* maybe resume can wake root hub */ - if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) || - autostop) + if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) { ohci->hc_control |= OHCI_CTRL_RWE; - else { - ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); + } else { + ohci_writel(ohci, OHCI_INTR_RHSC | OHCI_INTR_RD, + &ohci->regs->intrdisable); ohci->hc_control &= ~OHCI_CTRL_RWE; } @@ -326,23 +314,76 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return rc; } +/* Carry out the final steps of resuming the controller device */ +static void ohci_finish_controller_resume(struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + int port; + bool need_reinit = false; + + /* See if the controller is already running or has been reset */ + ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { + need_reinit = true; + } else { + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: + case OHCI_USB_RESET: + need_reinit = true; + } + } + + /* If needed, reinitialize and suspend the root hub */ + if (need_reinit) { + spin_lock_irq(&ohci->lock); + hcd->state = HC_STATE_RESUMING; + ohci_rh_resume(ohci); + hcd->state = HC_STATE_QUIESCING; + ohci_rh_suspend(ohci, 0); + hcd->state = HC_STATE_SUSPENDED; + spin_unlock_irq(&ohci->lock); + } + + /* Normally just turn on port power and enable interrupts */ + else { + ohci_dbg(ohci, "powerup ports\n"); + for (port = 0; port < ohci->num_ports; port++) + ohci_writel(ohci, RH_PS_PPS, + &ohci->regs->roothub.portstatus[port]); + + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); + ohci_readl(ohci, &ohci->regs->intrenable); + msleep(20); + } +} + /* Carry out polling-, autostop-, and autoresume-related state changes */ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, int any_connected) { int poll_rh = 1; + int rhsc; + rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC; switch (ohci->hc_control & OHCI_CTRL_HCFS) { case OHCI_USB_OPER: - /* keep on polling until we know a device is connected - * and RHSC is enabled */ + /* If no status changes are pending, enable status-change + * interrupts. + */ + if (!rhsc && !changed) { + rhsc = OHCI_INTR_RHSC; + ohci_writel(ohci, rhsc, &ohci->regs->intrenable); + } + + /* Keep on polling until we know a device is connected + * and RHSC is enabled, or until we autostop. + */ if (!ohci->autostop) { if (any_connected || !device_may_wakeup(&ohci_to_hcd(ohci) ->self.root_hub->dev)) { - if (ohci_readl(ohci, &ohci->regs->intrenable) & - OHCI_INTR_RHSC) + if (rhsc) poll_rh = 0; } else { ohci->autostop = 1; @@ -355,12 +396,13 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, ohci->autostop = 0; ohci->next_statechange = jiffies + STATECHANGE_DELAY; - } else if (time_after_eq(jiffies, + } else if (rhsc && time_after_eq(jiffies, ohci->next_statechange) && !ohci->ed_rm_list && !(ohci->hc_control & OHCI_SCHED_ENABLES)) { ohci_rh_suspend(ohci, 1); + poll_rh = 0; } } break; @@ -374,6 +416,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, else usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); } else { + if (!rhsc && (ohci->autostop || + ohci_to_hcd(ohci)->self.root_hub-> + do_remote_wakeup)) + ohci_writel(ohci, OHCI_INTR_RHSC, + &ohci->regs->intrenable); + /* everything is idle, no need for polling */ poll_rh = 0; } @@ -395,12 +443,16 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci) static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, int any_connected) { - int poll_rh = 1; - - /* keep on polling until RHSC is enabled */ + /* If RHSC is enabled, don't poll */ if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) - poll_rh = 0; - return poll_rh; + return 0; + + /* If no status changes are pending, enable status-change interrupts */ + if (!changed) { + ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); + return 0; + } + return 1; } #endif /* CONFIG_PM */ @@ -561,17 +613,21 @@ static void start_hnp(struct ohci_hcd *ohci); static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) { __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; - u32 temp; + u32 temp = 0; u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); u16 reset_done = now + PORT_RESET_MSEC; + int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC); /* build a "continuous enough" reset signal, with up to * 3msec gap between pulses. scheduler HZ==100 must work; * this might need to be deadline-scheduled. */ do { + int limit_2; + /* spin until any current reset finishes */ - for (;;) { + limit_2 = PORT_RESET_HW_MSEC * 2; + while (--limit_2 >= 0) { temp = ohci_readl (ohci, portstat); /* handle e.g. CardBus eject */ if (temp == ~(u32)0) @@ -581,6 +637,17 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) udelay (500); } + /* timeout (a hardware error) has been observed when + * EHCI sets CF while this driver is resetting a port; + * presumably other disconnect paths might do it too. + */ + if (limit_2 < 0) { + ohci_dbg(ohci, + "port[%d] reset timeout, stat %08x\n", + port, temp); + break; + } + if (!(temp & RH_PS_CCS)) break; if (temp & RH_PS_PRSC) @@ -590,8 +657,11 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) ohci_writel (ohci, RH_PS_PRS, portstat); msleep(PORT_RESET_HW_MSEC); now = ohci_readl(ohci, &ohci->regs->fmnumber); - } while (tick_before(now, reset_done)); - /* caller synchronizes using PRSC */ + } while (tick_before(now, reset_done) && --limit_1 >= 0); + + /* caller synchronizes using PRSC ... and handles PRS + * still being set when this returns. + */ return 0; } @@ -666,14 +736,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c index 13c12ed22252..96d14fa1d833 100644 --- a/drivers/usb/host/ohci-lh7a404.c +++ b/drivers/usb/host/ohci-lh7a404.c @@ -193,7 +193,6 @@ static const struct hc_driver ohci_lh7a404_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 7bfca1ed1b58..6859fb5f1d6f 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -466,7 +466,6 @@ static const struct hc_driver ohci_omap_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -505,21 +504,20 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) omap_ohci_clock_power(0); ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->dev.power.power_state = PMSG_SUSPEND; return 0; } static int ohci_omap_resume(struct platform_device *dev) { - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); + struct usb_hcd *hcd = platform_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; omap_ohci_clock_power(1); - dev->dev.power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(platform_get_drvdata(dev)); + ohci_finish_controller_resume(hcd); return 0; } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index d0360f65ebd9..3bf175d95a23 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -238,42 +238,6 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd) return ret; } -#if defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \ - defined(CONFIG_USB_EHCI_HCD_MODULE)) - -/* Following a power loss, we must prepare to regain control of the ports - * we used to own. This means turning on the port power before ehci-hcd - * tries to switch ownership. - * - * This isn't a 100% perfect solution. On most systems the OHCI controllers - * lie at lower PCI addresses than the EHCI controller, so they will be - * discovered (and hence resumed) first. But there is no guarantee things - * will always work this way. If the EHCI controller is resumed first and - * the OHCI ports are unpowered, then the handover will fail. - */ -static void prepare_for_handover(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int port; - - /* Here we "know" root ports should always stay powered */ - ohci_dbg(ohci, "powerup ports\n"); - for (port = 0; port < ohci->num_ports; port++) - ohci_writel(ohci, RH_PS_PPS, - &ohci->regs->roothub.portstatus[port]); - - /* Flush those writes */ - ohci_readl(ohci, &ohci->regs->control); - msleep(20); -} - -#else - -static inline void prepare_for_handover(struct usb_hcd *hcd) -{ } - -#endif /* CONFIG_USB_PERSIST etc. */ - #ifdef CONFIG_PM static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) @@ -313,10 +277,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) static int ohci_pci_resume (struct usb_hcd *hcd) { set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* FIXME: we should try to detect loss of VBUS power here */ - prepare_for_handover(hcd); - + ohci_finish_controller_resume(hcd); return 0; } @@ -345,9 +306,8 @@ static const struct hc_driver ohci_pci_hc_driver = { .shutdown = ohci_shutdown, #ifdef CONFIG_PM - /* these suspend/resume entries are for upstream PCI glue ONLY */ - .suspend = ohci_pci_suspend, - .resume = ohci_pci_resume, + .pci_suspend = ohci_pci_suspend, + .pci_resume = ohci_pci_resume, #endif /* @@ -367,7 +327,6 @@ static const struct hc_driver ohci_pci_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 28b458f20cc3..664f07ee8732 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -280,7 +280,6 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index 605d59cba28e..28467e288a93 100644 --- a/drivers/usb/host/ohci-pnx8550.c +++ b/drivers/usb/host/ohci-pnx8550.c @@ -201,7 +201,6 @@ static const struct hc_driver ohci_pnx8550_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index a67252791223..50e55db13636 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -72,7 +72,6 @@ static const struct hc_driver ohci_ppc_of_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 523c30125577..cd3398b675b2 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -172,7 +172,6 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 01a0caeaa6bc..bfdeb0d22d05 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -68,7 +68,6 @@ static const struct hc_driver ps3_ohci_hc_driver = { .get_frame_number = ohci_get_frame, .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, .start_port_reset = ohci_start_port_reset, #if defined(CONFIG_PM) .bus_suspend = ohci_bus_suspend, @@ -127,7 +126,6 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) goto fail_irq; } - dev->core.power.power_state = PMSG_ON; dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id); diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 8ad9b3b604b5..70b0d4b459e7 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -298,7 +298,6 @@ static const struct hc_driver ohci_pxa27x_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -339,7 +338,6 @@ static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_ pxa27x_stop_hc(&pdev->dev); hcd->state = HC_STATE_SUSPENDED; - pdev->dev.power.power_state = PMSG_SUSPEND; return 0; } @@ -357,9 +355,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) if ((status = pxa27x_start_hc(&pdev->dev)) < 0) return status; - pdev->dev.power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(hcd); - + ohci_finish_controller_resume(hcd); return 0; } #endif diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index ead4772f0f27..a73d2ff322e2 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -466,7 +466,6 @@ static const struct hc_driver ohci_s3c2410_hc_driver = { */ .hub_status_data = ohci_s3c2410_hub_status_data, .hub_control = ohci_s3c2410_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 0f48f2d99226..99438c65981b 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -231,7 +231,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c index e7ee607278fe..60f03cc7ec4f 100644 --- a/drivers/usb/host/ohci-sh.c +++ b/drivers/usb/host/ohci-sh.c @@ -68,7 +68,6 @@ static const struct hc_driver ohci_sh_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index 4ea92762fb28..77204f001b9a 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -75,7 +75,6 @@ static const struct hc_driver ohci_sm501_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -199,7 +198,8 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) usb_put_hcd(hcd); dma_release_declared_memory(&pdev->dev); mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - release_mem_region(mem->start, mem->end - mem->start + 1); + if (mem) + release_mem_region(mem->start, mem->end - mem->start + 1); /* mask interrupts and disable power */ @@ -224,24 +224,26 @@ static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED; - dev->power.power_state = PMSG_SUSPEND; return 0; } static int ohci_sm501_resume(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); if (time_before(jiffies, ohci->next_statechange)) msleep(5); ohci->next_statechange = jiffies; sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); - dev->power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(platform_get_drvdata(pdev)); + ohci_finish_controller_resume(hcd); return 0; } +#else +#define ohci_sm501_suspend NULL +#define ohci_sm501_resume NULL #endif /*-------------------------------------------------------------------------*/ @@ -253,10 +255,8 @@ static struct platform_driver ohci_hcd_sm501_driver = { .probe = ohci_hcd_sm501_drv_probe, .remove = ohci_hcd_sm501_drv_remove, .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM .suspend = ohci_sm501_suspend, .resume = ohci_sm501_resume, -#endif .driver = { .owner = THIS_MODULE, .name = "sm501-usb", diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c index 6e9c2d6db887..c4265caec780 100644 --- a/drivers/usb/host/ohci-ssb.c +++ b/drivers/usb/host/ohci-ssb.c @@ -60,36 +60,6 @@ static int ssb_ohci_start(struct usb_hcd *hcd) return err; } -#ifdef CONFIG_PM -static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - unsigned long flags; - - spin_lock_irqsave(&ohci->lock, flags); - - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */ - - /* make sure snapshot being resumed re-enumerates everything */ - if (message.event == PM_EVENT_PRETHAW) - ohci_usb_reset(ohci); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - spin_unlock_irqrestore(&ohci->lock, flags); - return 0; -} - -static int ssb_ohci_hcd_resume(struct usb_hcd *hcd) -{ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - usb_hcd_resume_root_hub(hcd); - return 0; -} -#endif /* CONFIG_PM */ - static const struct hc_driver ssb_ohci_hc_driver = { .description = "ssb-usb-ohci", .product_desc = "SSB OHCI Controller", @@ -103,11 +73,6 @@ static const struct hc_driver ssb_ohci_hc_driver = { .stop = ohci_stop, .shutdown = ohci_shutdown, -#ifdef CONFIG_PM - .suspend = ssb_ohci_hcd_suspend, - .resume = ssb_ohci_hcd_resume, -#endif - .urb_enqueue = ohci_urb_enqueue, .urb_dequeue = ohci_urb_dequeue, .endpoint_disable = ohci_endpoint_disable, @@ -116,7 +81,6 @@ static const struct hc_driver ssb_ohci_hc_driver = { .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - .hub_irq_enable = ohci_rhsc_enable, #ifdef CONFIG_PM .bus_suspend = ohci_bus_suspend, .bus_resume = ohci_bus_resume, @@ -224,6 +188,7 @@ static int ssb_ohci_resume(struct ssb_device *dev) ssb_device_enable(dev, ohcidev->enable_flags); + ohci_finish_controller_resume(hcd); return 0; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 0ee694f043cc..ae6e70edd745 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -106,7 +106,7 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", - __FUNCTION__, legsup); + __func__, legsup); goto reset_needed; } @@ -114,14 +114,14 @@ int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || !(cmd & UHCI_USBCMD_EGSM)) { dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", - __FUNCTION__, cmd); + __func__, cmd); goto reset_needed; } intr = inw(base + UHCI_USBINTR); if (intr & (~UHCI_USBINTR_RESUME)) { dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n", - __FUNCTION__, intr); + __func__, intr); goto reset_needed; } return 0; diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 9f80e5285575..16667342b3c3 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -46,15 +46,17 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); MODULE_ALIAS("platform:r8a66597_hcd"); -#define DRIVER_VERSION "29 May 2007" +#define DRIVER_VERSION "10 Apr 2008" static const char hcd_name[] = "r8a66597_hcd"; /* module parameters */ +#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) static unsigned short clock = XTAL12; module_param(clock, ushort, 0644); MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " "(default=0)"); +#endif static unsigned short vif = LDRV; module_param(vif, ushort, 0644); @@ -106,11 +108,22 @@ static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address, r8a66597_write(r8a66597, val, devadd_reg); } -static int enable_controller(struct r8a66597 *r8a66597) +static int r8a66597_clock_enable(struct r8a66597 *r8a66597) { u16 tmp; int i = 0; +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) + do { + r8a66597_write(r8a66597, SCKE, SYSCFG0); + tmp = r8a66597_read(r8a66597, SYSCFG0); + if (i++ > 1000) { + err("register access fail."); + return -ENXIO; + } + } while ((tmp & SCKE) != SCKE); + r8a66597_write(r8a66597, 0x04, 0x02); +#else do { r8a66597_write(r8a66597, USBE, SYSCFG0); tmp = r8a66597_read(r8a66597, SYSCFG0); @@ -132,13 +145,63 @@ static int enable_controller(struct r8a66597 *r8a66597) return -ENXIO; } } while ((tmp & SCKE) != SCKE); +#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */ + + return 0; +} + +static void r8a66597_clock_disable(struct r8a66597 *r8a66597) +{ + r8a66597_bclr(r8a66597, SCKE, SYSCFG0); + udelay(1); +#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) + r8a66597_bclr(r8a66597, PLLC, SYSCFG0); + r8a66597_bclr(r8a66597, XCKE, SYSCFG0); + r8a66597_bclr(r8a66597, USBE, SYSCFG0); +#endif +} + +static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port) +{ + u16 val; + + val = port ? DRPD : DCFM | DRPD; + r8a66597_bset(r8a66597, val, get_syscfg_reg(port)); + r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); + + r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port)); + r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port)); + r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); +} - r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0); - r8a66597_bset(r8a66597, DRPD, SYSCFG1); +static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port) +{ + u16 val, tmp; + + r8a66597_write(r8a66597, 0, get_intenb_reg(port)); + r8a66597_write(r8a66597, 0, get_intsts_reg(port)); + + r8a66597_port_power(r8a66597, port, 0); + + do { + tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS; + udelay(640); + } while (tmp == EDGESTS); + + val = port ? DRPD : DCFM | DRPD; + r8a66597_bclr(r8a66597, val, get_syscfg_reg(port)); + r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); +} + +static int enable_controller(struct r8a66597 *r8a66597) +{ + int ret, port; + + ret = r8a66597_clock_enable(r8a66597); + if (ret < 0) + return ret; r8a66597_bset(r8a66597, vif & LDRV, PINCFG); - r8a66597_bset(r8a66597, HSE, SYSCFG0); - r8a66597_bset(r8a66597, HSE, SYSCFG1); r8a66597_bset(r8a66597, USBE, SYSCFG0); r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0); @@ -146,53 +209,30 @@ static int enable_controller(struct r8a66597 *r8a66597) r8a66597_bset(r8a66597, BRDY0, BRDYENB); r8a66597_bset(r8a66597, BEMP0, BEMPENB); - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG); - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG); - r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL); r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL); r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL); - r8a66597_bset(r8a66597, TRNENSEL, SOFCFG); r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1); - r8a66597_bclr(r8a66597, DTCHE, INTENB1); - r8a66597_bset(r8a66597, ATTCHE, INTENB1); - r8a66597_bclr(r8a66597, DTCHE, INTENB2); - r8a66597_bset(r8a66597, ATTCHE, INTENB2); + + for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) + r8a66597_enable_port(r8a66597, port); return 0; } static void disable_controller(struct r8a66597 *r8a66597) { - u16 tmp; + int port; r8a66597_write(r8a66597, 0, INTENB0); - r8a66597_write(r8a66597, 0, INTENB1); - r8a66597_write(r8a66597, 0, INTENB2); r8a66597_write(r8a66597, 0, INTSTS0); - r8a66597_write(r8a66597, 0, INTSTS1); - r8a66597_write(r8a66597, 0, INTSTS2); - - r8a66597_port_power(r8a66597, 0, 0); - r8a66597_port_power(r8a66597, 1, 0); - - do { - tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS; - udelay(640); - } while (tmp == EDGESTS); - r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0); - r8a66597_bclr(r8a66597, DRPD, SYSCFG1); - r8a66597_bclr(r8a66597, HSE, SYSCFG0); - r8a66597_bclr(r8a66597, HSE, SYSCFG1); + for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) + r8a66597_disable_port(r8a66597, port); - r8a66597_bclr(r8a66597, SCKE, SYSCFG0); - udelay(1); - r8a66597_bclr(r8a66597, PLLC, SYSCFG0); - r8a66597_bclr(r8a66597, XCKE, SYSCFG0); - r8a66597_bclr(r8a66597, USBE, SYSCFG0); + r8a66597_clock_disable(r8a66597); } static int get_parent_r8a66597_address(struct r8a66597 *r8a66597, @@ -577,13 +617,9 @@ static void pipe_buffer_setting(struct r8a66597 *r8a66597, PIPEBUF); r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket, PIPEMAXP); - if (info->interval) - info->interval--; r8a66597_write(r8a66597, info->interval, PIPEPERI); } - - /* this function must be called with interrupt disabled */ static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td) { @@ -715,6 +751,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe, struct urb *urb) { +#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597) int i; struct r8a66597_pipe_info *info = &pipe->info; @@ -742,6 +779,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, break; } } +#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */ } /* this function must be called with interrupt disabled */ @@ -825,6 +863,25 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597, dev->dma_map = 0; } +static unsigned long get_timer_interval(struct urb *urb, __u8 interval) +{ + __u8 i; + unsigned long time = 1; + + if (usb_pipeisoc(urb->pipe)) + return 0; + + if (get_r8a66597_usb_speed(urb->dev->speed) == HSMODE) { + for (i = 0; i < (interval - 1); i++) + time *= 2; + time = time * 125 / 1000; /* uSOF -> msec */ + } else { + time = interval; + } + + return time; +} + /* this function must be called with interrupt disabled */ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, struct usb_host_endpoint *hep, @@ -840,7 +897,16 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, & USB_ENDPOINT_XFERTYPE_MASK); info.bufnum = get_bufnum(info.pipenum); info.buf_bsize = get_buf_bsize(info.pipenum); - info.interval = ep->bInterval; + if (info.type == R8A66597_BULK) { + info.interval = 0; + info.timer_interval = 0; + } else { + if (ep->bInterval > IITV) + info.interval = IITV; + else + info.interval = ep->bInterval ? ep->bInterval - 1 : 0; + info.timer_interval = get_timer_interval(urb, ep->bInterval); + } if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; else @@ -876,10 +942,19 @@ static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum) } /* this function must be called with interrupt disabled */ -static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port) +static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port, + u16 syssts) { - r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION) - | (1 << USB_PORT_FEAT_C_CONNECTION); + if (syssts == SE0) { + r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); + return; + } + + if (syssts == FS_JSTS) + r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); + else if (syssts == LS_JSTS) + r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); + r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); } @@ -918,7 +993,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, struct r8a66597_td *td) { int i; - u16 *p = (u16 *)td->urb->setup_packet; + __le16 *p = (__le16 *)td->urb->setup_packet; unsigned long setup_addr = USBREQ; r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, @@ -926,7 +1001,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr); + r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); setup_addr += 2; } r8a66597_write(r8a66597, SUREQ, DCPCTR); @@ -960,9 +1035,9 @@ static void prepare_packet_read(struct r8a66597 *r8a66597, r8a66597_write(r8a66597, TRCLR, td->pipe->pipetre); r8a66597_write(r8a66597, - (urb->transfer_buffer_length - + td->maxpacket - 1) - / td->maxpacket, + DIV_ROUND_UP + (urb->transfer_buffer_length, + td->maxpacket), td->pipe->pipetrn); r8a66597_bset(r8a66597, TRENB, td->pipe->pipetre); @@ -1021,8 +1096,7 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); - r8a66597_write(r8a66597, BCLR, CFIFOCTR); - r8a66597_write(r8a66597, BVAL, CFIFOCTR); + r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR); enable_irq_empty(r8a66597, 0); } else { r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); @@ -1454,13 +1528,21 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597) } } +static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597) +{ + mod_timer(&r8a66597->rh_timer, + jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME)); +} + static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port) { struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST; rh->scount = R8A66597_MAX_SAMPLING; - mod_timer(&r8a66597->rh_timer, jiffies + msecs_to_jiffies(50)); + r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION) + | (1 << USB_PORT_FEAT_C_CONNECTION); + r8a66597_root_hub_start_polling(r8a66597); } static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) @@ -1547,41 +1629,55 @@ static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port) if ((tmp & USBRST) == USBRST) { r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, dvstctr_reg); - mod_timer(&r8a66597->rh_timer, - jiffies + msecs_to_jiffies(50)); + r8a66597_root_hub_start_polling(r8a66597); } else r8a66597_usb_connect(r8a66597, port); } + if (!(rh->port & (1 << USB_PORT_FEAT_CONNECTION))) { + r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port)); + r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); + } + if (rh->scount > 0) { tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST; if (tmp == rh->old_syssts) { rh->scount--; - if (rh->scount == 0) { - if (tmp == FS_JSTS) { - r8a66597_bset(r8a66597, HSE, - get_syscfg_reg(port)); - r8a66597_usb_preconnect(r8a66597, port); - } else if (tmp == LS_JSTS) { - r8a66597_bclr(r8a66597, HSE, - get_syscfg_reg(port)); - r8a66597_usb_preconnect(r8a66597, port); - } else if (tmp == SE0) - r8a66597_bset(r8a66597, ATTCHE, - get_intenb_reg(port)); - } else { - mod_timer(&r8a66597->rh_timer, - jiffies + msecs_to_jiffies(50)); - } + if (rh->scount == 0) + r8a66597_check_syssts(r8a66597, port, tmp); + else + r8a66597_root_hub_start_polling(r8a66597); } else { rh->scount = R8A66597_MAX_SAMPLING; rh->old_syssts = tmp; - mod_timer(&r8a66597->rh_timer, - jiffies + msecs_to_jiffies(50)); + r8a66597_root_hub_start_polling(r8a66597); } } } +static void r8a66597_interval_timer(unsigned long _r8a66597) +{ + struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; + unsigned long flags; + u16 pipenum; + struct r8a66597_td *td; + + spin_lock_irqsave(&r8a66597->lock, flags); + + for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { + if (!(r8a66597->interval_map & (1 << pipenum))) + continue; + if (timer_pending(&r8a66597->interval_timer[pipenum])) + continue; + + td = r8a66597_get_td(r8a66597, pipenum); + if (td) + start_transfer(r8a66597, td); + } + + spin_unlock_irqrestore(&r8a66597->lock, flags); +} + static void r8a66597_td_timer(unsigned long _r8a66597) { struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; @@ -1763,10 +1859,17 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd, urb->hcpriv = td; if (request) { - ret = start_transfer(r8a66597, td); - if (ret < 0) { - list_del(&td->queue); - kfree(td); + if (td->pipe->info.timer_interval) { + r8a66597->interval_map |= 1 << td->pipenum; + mod_timer(&r8a66597->interval_timer[td->pipenum], + jiffies + msecs_to_jiffies( + td->pipe->info.timer_interval)); + } else { + ret = start_transfer(r8a66597, td); + if (ret < 0) { + list_del(&td->queue); + kfree(td); + } } } else set_td_timer(r8a66597, td); @@ -2028,7 +2131,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case GetPortStatus: if (wIndex > R8A66597_MAX_ROOT_HUB) goto error; - *(u32 *)buf = cpu_to_le32(rh->port); + *(__le32 *)buf = cpu_to_le32(rh->port); break; case SetPortFeature: if (wIndex > R8A66597_MAX_ROOT_HUB) @@ -2107,13 +2210,11 @@ static struct hc_driver r8a66597_hc_driver = { #if defined(CONFIG_PM) static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state) { - pdev->dev.power.power_state = state; return 0; } static int r8a66597_resume(struct platform_device *pdev) { - pdev->dev.power.power_state = PMSG_ON; return 0; } #else /* if defined(CONFIG_PM) */ @@ -2194,6 +2295,9 @@ static int __init r8a66597_probe(struct platform_device *pdev) init_timer(&r8a66597->td_timer[i]); r8a66597->td_timer[i].function = r8a66597_td_timer; r8a66597->td_timer[i].data = (unsigned long)r8a66597; + setup_timer(&r8a66597->interval_timer[i], + r8a66597_interval_timer, + (unsigned long)r8a66597); } INIT_LIST_HEAD(&r8a66597->child_device); diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h index 57388252b693..84ee01417315 100644 --- a/drivers/usb/host/r8a66597.h +++ b/drivers/usb/host/r8a66597.h @@ -187,7 +187,11 @@ #define REW 0x4000 /* b14: Buffer rewind */ #define DCLRM 0x2000 /* b13: DMA buffer clear mode */ #define DREQE 0x1000 /* b12: DREQ output enable */ +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) +#define MBW 0x0800 +#else #define MBW 0x0400 /* b10: Maximum bit width for FIFO access */ +#endif #define MBW_8 0x0000 /* 8bit */ #define MBW_16 0x0400 /* 16bit */ #define BIGEND 0x0100 /* b8: Big endian mode */ @@ -395,8 +399,13 @@ #define R8A66597_MAX_NUM_PIPE 10 #define R8A66597_BUF_BSIZE 8 #define R8A66597_MAX_DEVICE 10 +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) +#define R8A66597_MAX_ROOT_HUB 1 +#else #define R8A66597_MAX_ROOT_HUB 2 -#define R8A66597_MAX_SAMPLING 10 +#endif +#define R8A66597_MAX_SAMPLING 5 +#define R8A66597_RH_POLL_TIME 10 #define R8A66597_MAX_DMA_CHANNEL 2 #define R8A66597_PIPE_NO_DMA R8A66597_MAX_DMA_CHANNEL #define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5)) @@ -404,6 +413,7 @@ #define make_devsel(addr) (addr << 12) struct r8a66597_pipe_info { + unsigned long timer_interval; u16 pipenum; u16 address; /* R8A66597 HCD usb address */ u16 epnum; @@ -478,9 +488,11 @@ struct r8a66597 { struct timer_list rh_timer; struct timer_list td_timer[R8A66597_MAX_NUM_PIPE]; + struct timer_list interval_timer[R8A66597_MAX_NUM_PIPE]; unsigned short address_map; unsigned short timeout_map; + unsigned short interval_map; unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE]; unsigned char dma_map; @@ -526,8 +538,21 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, unsigned long offset, u16 *buf, int len) { +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) + unsigned long fifoaddr = r8a66597->reg + offset; + unsigned long count; + + count = len / 4; + insl(fifoaddr, buf, count); + + if (len & 0x00000003) { + unsigned long tmp = inl(fifoaddr); + memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03); + } +#else len = (len + 1) / 2; insw(r8a66597->reg + offset, buf, len); +#endif } static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, @@ -541,6 +566,24 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, int len) { unsigned long fifoaddr = r8a66597->reg + offset; +#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) + unsigned long count; + unsigned char *pb; + int i; + + count = len / 4; + outsl(fifoaddr, buf, count); + + if (len & 0x00000003) { + pb = (unsigned char *)buf + count * 4; + for (i = 0; i < (len & 0x00000003); i++) { + if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND) + outb(pb[i], fifoaddr + i); + else + outb(pb[i], fifoaddr + 3 - i); + } + } +#else int odd = len & 0x0001; len = len / 2; @@ -549,6 +592,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, buf = &buf[len]; outb((unsigned char)*buf, fifoaddr); } +#endif } static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, @@ -581,6 +625,11 @@ static inline unsigned long get_dvstctr_reg(int port) return port == 0 ? DVSTCTR0 : DVSTCTR1; } +static inline unsigned long get_dmacfg_reg(int port) +{ + return port == 0 ? DMA0CFG : DMA1CFG; +} + static inline unsigned long get_intenb_reg(int port) { return port == 0 ? INTENB1 : INTENB2; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 629bca0ebe8f..426575247b23 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -94,12 +94,10 @@ static void port_power(struct sl811 *sl811, int is_on) sl811->port1 = (1 << USB_PORT_FEAT_POWER); sl811->irq_enable = SL11H_INTMASK_INSRMV; - hcd->self.controller->power.power_state = PMSG_ON; } else { sl811->port1 = 0; sl811->irq_enable = 0; hcd->state = HC_STATE_HALT; - hcd->self.controller->power.power_state = PMSG_SUSPEND; } sl811->ctrl1 = 0; sl811_write(sl811, SL11H_IRQ_ENABLE, 0); @@ -1102,7 +1100,7 @@ sl811h_hub_descriptor ( /* no overcurrent errors detection/handling */ temp |= 0x0010; - desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); + desc->wHubCharacteristics = cpu_to_le16(temp); /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ desc->bitmap[0] = 0 << 1; @@ -1337,7 +1335,7 @@ static int sl811h_bus_suspend(struct usb_hcd *hcd) { // SOFs off - DBG("%s\n", __FUNCTION__); + DBG("%s\n", __func__); return 0; } @@ -1345,7 +1343,7 @@ static int sl811h_bus_resume(struct usb_hcd *hcd) { // SOFs on - DBG("%s\n", __FUNCTION__); + DBG("%s\n", __func__); return 0; } @@ -1508,15 +1506,7 @@ static const char proc_filename[] = "driver/sl811h"; static void create_debug_file(struct sl811 *sl811) { - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = sl811; - sl811->pde = pde; + sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); } static void remove_debug_file(struct sl811 *sl811) @@ -1772,8 +1762,6 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state) port_power(sl811, 0); break; } - if (retval == 0) - dev->dev.power.power_state = state; return retval; } @@ -1786,15 +1774,13 @@ sl811h_resume(struct platform_device *dev) /* with no "check to see if VBUS is still powered" board hook, * let's assume it'd only be powered to enable remote wakeup. */ - if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND - || !device_can_wakeup(&hcd->self.root_hub->dev)) { + if (!sl811->port1 || !device_can_wakeup(&hcd->self.root_hub->dev)) { sl811->port1 = 0; port_power(sl811, 1); usb_root_hub_lost_power(hcd->self.root_hub); return 0; } - dev->dev.power.power_state = PMSG_ON; return sl811h_bus_resume(hcd); } diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 8e117a795e93..f29307405bb3 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -67,7 +67,7 @@ #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) + OHCI_INTR_WDH) MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); MODULE_DESCRIPTION("U132 USB Host Controller Driver"); MODULE_LICENSE("GPL"); @@ -77,15 +77,15 @@ INT_MODULE_PARM(testing, 0); static int distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" - "t setup"); + "t setup"); static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); /* * u132_module_lock exists to protect access to global variables * */ static struct mutex u132_module_lock; -static int u132_exiting = 0; -static int u132_instances = 0; +static int u132_exiting; +static int u132_instances; static struct list_head u132_static_list; /* * end of the global variables protected by u132_module_lock @@ -97,115 +97,115 @@ static struct workqueue_struct *workqueue; #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) " + "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 *u132; + int reset; + int enable; + int power; + int Status; }; struct u132_addr { - u8 address; + 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]; + 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 list_head urb_more; + struct urb *urb; }; struct u132_spin { - spinlock_t slock; + 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 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; + 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 list_head u132_list; - struct mutex sw_lock; - struct semaphore 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]; + struct kref kref; + struct list_head u132_list; + 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]; }; /* @@ -213,34 +213,34 @@ struct u132 { * 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); + 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); + 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); + 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); + 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]); + 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); + 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); + 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; + u132_to_hcd(u132)->state = HC_STATE_HALT; } @@ -250,147 +250,147 @@ static inline void u132_disable(struct u132 *u132) #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) + 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); - list_del_init(&u132->u132_list); - 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); + 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); + list_del_init(&u132->u132_list); + 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); + kref_put(&u132->kref, u132_hcd_delete); } static inline void u132_u132_init_kref(struct u132 *u132) { - kref_init(&u132->kref); + 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; + 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); + 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); + kref_get(&udev->kref); } static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) + struct u132_udev *udev) { - kref_init(&udev->kref); + 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); + kref_put(&u132->kref, u132_hcd_delete); } static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) + 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); - return; + 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); + return; } static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) + unsigned int delta) { - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); - return; + kref_get(&u132->kref); + u132_ring_requeue_work(u132, ring, delta); + return; } 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); - } + 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); + 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); + 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); + kref_get(&endp->kref); } static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) + struct u132_endp *endp) { - kref_init(&endp->kref); - kref_get(&u132->kref); + kref_init(&endp->kref); + kref_get(&u132->kref); } static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) + unsigned int delta) { if (queue_delayed_work(workqueue, &endp->scheduler, delta)) kref_get(&endp->kref); @@ -398,13 +398,13 @@ static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, 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); + 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); + kref_put(&u132->kref, u132_hcd_delete); } static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) @@ -421,200 +421,201 @@ static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) static void u132_monitor_cancel_work(struct u132 *u132) { - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); + 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; + 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; - } - } + 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 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); + 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); - } down(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - up(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); + 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); - return; + return; } static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) + struct urb *urb, int status) { - u132_endp_put_kref(u132, endp); + u132_endp_put_kref(u132, endp); } static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) + 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); + 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); + 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); - return; + return; } 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)) + 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); + 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)) + 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); + 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)) + 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); + 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)) + 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); + return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, + endp, urb, address, endp->usb_endp, toggle_bits, callback); } @@ -623,683 +624,678 @@ static inline int edset_output(struct u132 *u132, struct u132_ring *ring, * */ 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]; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval == 0) { - } else - 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); - up(&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); - up(&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]); - } - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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; - } else { - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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]; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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); - up(&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) { - } else - 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); - up(&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); - up(&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]); - up(&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); - up(&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]); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + mutex_unlock(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; } else if (!urb->unlinked) { - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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) { - } else - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - up(&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 { - up(&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 { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + mutex_unlock(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; } else if (!urb->unlinked) { - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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) { - } else - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - up(&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) { - } else - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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]; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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) { - } else - 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, 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + mutex_unlock(&u132->scheduler_lock); + u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); + return; } else if (!urb->unlinked) { - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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) { - } else - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { + 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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + 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; - down(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - up(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { + 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); - up(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; + 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; - up(&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) { - } else - 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_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); - up(&u132->scheduler_lock); + mutex_unlock(&u132->scheduler_lock); u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } + return; + } } /* @@ -1308,302 +1304,296 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, */ static void u132_hcd_ring_work_scheduler(struct work_struct *work) { - struct u132_ring *ring = + struct u132_ring *ring = container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - down(&u132->scheduler_lock); - if (ring->in_use) { - up(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *last_endp = ring->curr_endp; - struct list_head *scan; - struct list_head *head = &last_endp->endp_ring; - unsigned long wakeup = 0; - list_for_each(scan, head) { - struct u132_endp *endp = list_entry(scan, - struct u132_endp, 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); - up(&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); - up(&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); - up(&u132->scheduler_lock); - return; - } else { - up(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - up(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } + 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 *last_endp = ring->curr_endp; + struct list_head *scan; + struct list_head *head = &last_endp->endp_ring; + unsigned long wakeup = 0; + list_for_each(scan, head) { + struct u132_endp *endp = list_entry(scan, + struct u132_endp, 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 = + struct u132_ring *ring; + struct u132_endp *endp = container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - down(&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); - up(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - up(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - up(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - up(&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) { - up(&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; - up(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval == 0) { - } else - 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) { - up(&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; - up(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval == 0) { - } else - 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; - up(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - u8 address = u132->addr[endp->usb_addr].address; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - up(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval == 0) { - } else - 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) { - up(&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; - up(&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) { - up(&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; - up(&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; - } - } - } + 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; + u8 address = u132->addr[endp->usb_addr].address; + 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_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; + 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; - hcd->self.controller->power.power_state = PMSG_ON; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - hcd->self.controller->power.power_state = PMSG_SUSPEND; - } + 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; - retval = u132_write_pcimem(u132, periodicstart, - ((9 *fi) / 10) & 0x3fff); - if (retval) - return retval; - return 0; + 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; + retval = u132_write_pcimem(u132, periodicstart, + ((9 * fi) / 10) & 0x3fff); + if (retval) + return retval; + return 0; } 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 "?"; + 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; + 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; } @@ -1613,280 +1603,278 @@ static int u132_init(struct u132 *u132) */ 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; - if (u132->hc_fminterval != FI) { - } - 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; + 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); - } + 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 *) - (pdev->dev.platform_data))->vendor; - u16 device = ((struct u132_platform_data *) - (pdev->dev.platform_data))->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; - } + 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 *) + (pdev->dev.platform_data))->vendor; + u16 device = ((struct u132_platform_data *) + (pdev->dev.platform_data))->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; - } + 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 usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, + gfp_t mem_flags) { - struct u132_ring *ring; - unsigned long irqs; + 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; - } + if (!endp) + return -ENOMEM; spin_lock_init(&endp->queue_lock.slock); spin_lock_irqsave(&endp->queue_lock.slock, irqs); @@ -1899,94 +1887,93 @@ static int create_endpoint_and_queue_int(struct u132 *u132, 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; + 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; + 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; + 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) + 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 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; - } + if (!endp) + return -ENOMEM; spin_lock_init(&endp->queue_lock.slock); spin_lock_irqsave(&endp->queue_lock.slock, irqs); @@ -1999,91 +1986,90 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, 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; + 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; + 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; + 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 usb_device *usb_dev, u8 usb_addr, u8 usb_endp, + gfp_t mem_flags) { - struct u132_ring *ring; + 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; - } + if (!endp) + return -ENOMEM; spin_lock_init(&endp->queue_lock.slock); spin_lock_irqsave(&endp->queue_lock.slock, irqs); @@ -2096,204 +2082,203 @@ static int create_endpoint_and_queue_control(struct u132 *u132, 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; + 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; - } + 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) { - } else - 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; - } + 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 (__GFP_WAIT & mem_flags) { - printk(KERN_ERR "invalid context for function that migh" - "t 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) { + struct u132 *u132 = hcd_to_u132(hcd); + if (irqs_disabled()) { + if (__GFP_WAIT & mem_flags) { + printk(KERN_ERR "invalid context for function that migh" + "t 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); + 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( @@ -2303,39 +2288,39 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, address); if (retval) usb_hcd_unlink_urb_from_ep( - hcd, urb); + 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, + 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); + } + } 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( @@ -2345,46 +2330,46 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, address); if (retval) usb_hcd_unlink_urb_from_ep( - hcd, urb); + hcd, urb); + } + spin_unlock_irqrestore(&endp->queue_lock.slock, + irqs); + if (retval) { + return retval; + } else { + u132_endp_queue_work(u132, endp, 0); + return 0; } - 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, + } 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); + 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( @@ -2395,267 +2380,267 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, 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, + 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); - } - } + mem_flags); + } + } } static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct list_head *scan; - struct list_head *head = &endp->urb_more; - list_for_each(scan, head) { - struct u132_urbq *urbq = list_entry(scan, struct u132_urbq, - urb_more); - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(scan); - endp->queue_size -= 1; - urb->error_count = 0; + struct u132_endp *endp, struct urb *urb) +{ + struct list_head *scan; + struct list_head *head = &endp->urb_more; + list_for_each(scan, head) { + struct u132_urbq *urbq = list_entry(scan, struct u132_urbq, + urb_more); + if (urbq->urb == urb) { + struct usb_hcd *hcd = u132_to_hcd(u132); + list_del(scan); + endp->queue_size -= 1; + urb->error_count = 0; usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } else - continue; - } - 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; + return 0; + } else + continue; + } + 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; + unsigned long irqs; int rc; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); + 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); + 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; - } else - continue; - } - 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); + 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; + } else + continue; + } + 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; + 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 { + 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; - } - } + 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); - } - } + 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); - } + 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 { - int frame = 0; - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - msleep(100); - return frame; - } + 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 frame = 0; + dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); + msleep(100); + return frame; + } } 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 = 0x29; - 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 = 0; - if (rh_a & RH_A_NPS) - temp |= 0x0002; - if (rh_a & RH_A_PSM) - temp |= 0x0001; - if (rh_a & RH_A_NOCP) { - temp |= 0x0010; - } else if (rh_a & RH_A_OCPM) - temp |= 0x0008; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); - desc->bitmap[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->bitmap[1] = (rh_b & RH_B_DR) >> 8; - desc->bitmap[2] = 0xff; - } else - desc->bitmap[1] = 0xff; - return 0; + 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 = 0x29; + 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 = 0; + if (rh_a & RH_A_NPS) + temp |= 0x0002; + if (rh_a & RH_A_PSM) + temp |= 0x0001; + if (rh_a & RH_A_NOCP) + temp |= 0x0010; + else if (rh_a & RH_A_OCPM) + temp |= 0x0008; + desc->wHubCharacteristics = cpu_to_le16(temp); + retval = u132_read_pcimem(u132, roothub.b, &rh_b); + if (retval) + return retval; + memset(desc->bitmap, 0xff, sizeof(desc->bitmap)); + desc->bitmap[0] = rh_b & RH_B_DR; + if (u132->num_ports > 7) { + desc->bitmap[1] = (rh_b & RH_B_DR) >> 8; + desc->bitmap[2] = 0xff; + } else + desc->bitmap[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; + 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; - } + 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; + } } @@ -2666,381 +2651,340 @@ static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) #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; + 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 retval; - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - if (retval) - return retval; - return 0; - case USB_PORT_FEAT_POWER: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - if (retval) - return retval; - return 0; - case USB_PORT_FEAT_RESET: - retval = u132_roothub_portreset(u132, port_index); - if (retval) - return retval; - return 0; - default: - return -EPIPE; - } - } + u16 wIndex) +{ + if (wIndex == 0 || wIndex > u132->num_ports) { + return -EINVAL; + } else { + int retval; + int port_index = wIndex - 1; + struct u132_port *port = &u132->port[port_index]; + port->Status &= ~(1 << wValue); + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + retval = u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PSS); + if (retval) + return retval; + return 0; + case USB_PORT_FEAT_POWER: + retval = u132_write_pcimem(u132, + roothub.portstatus[port_index], RH_PS_PPS); + if (retval) + return retval; + return 0; + case USB_PORT_FEAT_RESET: + retval = u132_roothub_portreset(u132, port_index); + if (retval) + return retval; + return 0; + 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; - int retval; - 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; - } - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - if (retval) - return retval; - return 0; - } + u16 wIndex) +{ + if (wIndex == 0 || wIndex > u132->num_ports) { + return -EINVAL; + } else { + int port_index = wIndex - 1; + u32 temp; + int retval; + 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; + } + retval = u132_write_pcimem(u132, roothub.portstatus[port_index], + temp); + if (retval) + return retval; + return 0; + } } /* 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; - } + 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; - } + 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; -} - -static void u132_hub_irq_enable(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); - } else if (u132->going > 0) - dev_err(&u132->platform_dev->dev, "device is being removed\n"); + 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_hcd_suspend(struct usb_hcd *hcd, pm_message_t message) -{ - 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_hcd_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; -} - 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; + 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; + 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_hcd_suspend NULL -#define u132_hcd_resume NULL #define u132_bus_suspend NULL #define u132_bus_resume NULL #endif static 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, - .suspend = u132_hcd_suspend, - .resume = u132_hcd_resume, - .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, - .hub_irq_enable = u132_hub_irq_enable, + .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, }; /* @@ -3051,148 +2995,152 @@ static struct hc_driver u132_hc_driver = { */ static int __devexit 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" + 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" + 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; + 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 = pdev->dev.platform_data; - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - init_MUTEX(&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, + 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 = pdev->dev.platform_data; + 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); - return; + } + 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); + return; } static int __devinit u132_probe(struct platform_device *pdev) { - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - u32 num_ports; - 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; - num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */ - if (pdev->dev.dma_mask) { - return -EINVAL; - } - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - int retval = 0; - struct u132 *u132 = hcd_to_u132(hcd); - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - list_add_tail(&u132->u132_list, &u132_static_list); - 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 { - u132_monitor_queue_work(u132, 100); - return 0; - } - } + struct usb_hcd *hcd; + int retval; + u32 control; + u32 rh_a = -1; + u32 num_ports; + + 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; + num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */ + if (pdev->dev.dma_mask) + return -EINVAL; + + hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id); + if (!hcd) { + printk(KERN_ERR "failed to create the usb hcd struct for U132\n" + ); + ftdi_elan_gone_away(pdev); + return -ENOMEM; + } else { + int retval = 0; + struct u132 *u132 = hcd_to_u132(hcd); + hcd->rsrc_start = 0; + mutex_lock(&u132_module_lock); + list_add_tail(&u132->u132_list, &u132_static_list); + 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 { + u132_monitor_queue_work(u132, 100); + return 0; + } + } } @@ -3203,61 +3151,58 @@ static int __devinit u132_probe(struct platform_device *pdev) */ 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 { + 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); + 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); - } + while (ports-- > 0) { + port_power(u132, ports, 0); + } break; } - if (retval == 0) - pdev->dev.power.power_state = state; - return retval; - } + 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 (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - pdev->dev.power.power_state = PMSG_ON; - retval = u132_bus_resume(hcd); - } - return retval; - } + 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 @@ -3270,47 +3215,48 @@ static int u132_resume(struct platform_device *pdev) * the platform_driver struct is static because it is per type of module */ static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = __devexit_p(u132_remove), - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = (char *)hcd_name, - .owner = THIS_MODULE, - }, + .probe = u132_probe, + .remove = __devexit_p(u132_remove), + .suspend = u132_suspend, + .resume = u132_resume, + .driver = { + .name = (char *)hcd_name, + .owner = THIS_MODULE, + }, }; static int __init u132_hcd_init(void) { - int retval; - INIT_LIST_HEAD(&u132_static_list); - u132_instances = 0; - u132_exiting = 0; - mutex_init(&u132_module_lock); - if (usb_disabled()) - return -ENODEV; - printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__, - __DATE__); - workqueue = create_singlethread_workqueue("u132"); - retval = platform_driver_register(&u132_platform_driver); - return retval; + int retval; + INIT_LIST_HEAD(&u132_static_list); + u132_instances = 0; + u132_exiting = 0; + mutex_init(&u132_module_lock); + if (usb_disabled()) + return -ENODEV; + printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__, + __DATE__); + workqueue = create_singlethread_workqueue("u132"); + retval = platform_driver_register(&u132_platform_driver); + return retval; } module_init(u132_hcd_init); static void __exit u132_hcd_exit(void) { - struct u132 *u132; - struct u132 *temp; - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { - platform_device_unregister(u132->platform_dev); - } platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - flush_workqueue(workqueue); - destroy_workqueue(workqueue); + struct u132 *u132; + struct u132 *temp; + mutex_lock(&u132_module_lock); + u132_exiting += 1; + mutex_unlock(&u132_module_lock); + list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { + platform_device_unregister(u132->platform_dev); + } + platform_driver_unregister(&u132_platform_driver); + printk(KERN_INFO "u132-hcd driver deregistered\n"); + wait_event(u132_hcd_wait, u132_instances == 0); + flush_workqueue(workqueue); + destroy_workqueue(workqueue); } diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index ec987897b8ed..3a7bfe7a8874 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } -static int remote_wakeup_is_broken(struct uhci_hcd *uhci) +static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) { int port; const char *sys_info; @@ -261,33 +261,60 @@ __releases(uhci->lock) __acquires(uhci->lock) { int auto_stop; - int int_enable, egsm_enable; + int int_enable, egsm_enable, wakeup_enable; + struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); - dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, - "%s%s\n", __FUNCTION__, + dev_dbg(&rhdev->dev, "%s%s\n", __func__, (auto_stop ? " (auto-stop)" : "")); - /* If we get a suspend request when we're already auto-stopped - * then there's nothing to do. + /* Start off by assuming Resume-Detect interrupts and EGSM work + * and that remote wakeups should be enabled. + */ + egsm_enable = USBCMD_EGSM; + uhci->RD_enable = 1; + int_enable = USBINTR_RESUME; + wakeup_enable = 1; + + /* In auto-stop mode wakeups must always be detected, but + * Resume-Detect interrupts may be prohibited. (In the absence + * of CONFIG_PM, they are always disallowed.) */ - if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) { - uhci->rh_state = new_state; - return; + if (auto_stop) { + if (!device_may_wakeup(&rhdev->dev)) + int_enable = 0; + + /* In bus-suspend mode wakeups may be disabled, but if they are + * allowed then so are Resume-Detect interrupts. + */ + } else { +#ifdef CONFIG_PM + if (!rhdev->do_remote_wakeup) + wakeup_enable = 0; +#endif } - /* Enable resume-detect interrupts if they work. - * Then enter Global Suspend mode if _it_ works, still configured. + /* EGSM causes the root hub to echo a 'K' signal (resume) out any + * port which requests a remote wakeup. According to the USB spec, + * every hub is supposed to do this. But if we are ignoring + * remote-wakeup requests anyway then there's no point to it. + * We also shouldn't enable EGSM if it's broken. */ - egsm_enable = USBCMD_EGSM; - uhci->working_RD = 1; - int_enable = USBINTR_RESUME; - if (remote_wakeup_is_broken(uhci)) + if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) egsm_enable = 0; - if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable || - !device_may_wakeup( - &uhci_to_hcd(uhci)->self.root_hub->dev)) - uhci->working_RD = int_enable = 0; + + /* If we're ignoring wakeup events then there's no reason to + * enable Resume-Detect interrupts. We also shouldn't enable + * them if they are broken or disallowed. + * + * This logic may lead us to enabling RD but not EGSM. The UHCI + * spec foolishly says that RD works only when EGSM is on, but + * there's no harm in enabling it anyway -- perhaps some chips + * will implement it! + */ + if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || + !int_enable) + uhci->RD_enable = int_enable = 0; outw(int_enable, uhci->io_addr + USBINTR); outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); @@ -308,14 +335,17 @@ __acquires(uhci->lock) return; } if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) - dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev, - "Controller not stopped yet!\n"); + dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); uhci_get_current_frame_number(uhci); uhci->rh_state = new_state; uhci->is_stopped = UHCI_IS_STOPPED; - uhci_to_hcd(uhci)->poll_rh = !int_enable; + + /* If interrupts don't work and remote wakeup is enabled then + * the suspended root hub needs to be polled. + */ + uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable); uhci_scan_schedule(uhci); uhci_fsbr_off(uhci); @@ -342,7 +372,7 @@ __releases(uhci->lock) __acquires(uhci->lock) { dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, - "%s%s\n", __FUNCTION__, + "%s%s\n", __func__, uhci->rh_state == UHCI_RH_AUTO_STOPPED ? " (auto-start)" : ""); @@ -351,9 +381,12 @@ __acquires(uhci->lock) * for 20 ms. */ if (uhci->rh_state == UHCI_RH_SUSPENDED) { + unsigned egsm; + + /* Keep EGSM on if it was set before */ + egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM; uhci->rh_state = UHCI_RH_RESUMING; - outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF, - uhci->io_addr + USBCMD); + outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD); spin_unlock_irq(&uhci->lock); msleep(20); spin_lock_irq(&uhci->lock); @@ -737,12 +770,12 @@ static int uhci_rh_resume(struct usb_hcd *hcd) return rc; } -static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) +static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int rc = 0; - dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + dev_dbg(uhci_dev(uhci), "%s\n", __func__); spin_lock_irq(&uhci->lock); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) @@ -774,11 +807,11 @@ done: return rc; } -static int uhci_resume(struct usb_hcd *hcd) +static int uhci_pci_resume(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); + dev_dbg(uhci_dev(uhci), "%s\n", __func__); /* Since we aren't in D3 any more, it's safe to set this flag * even if the controller was dead. @@ -808,8 +841,10 @@ static int uhci_resume(struct usb_hcd *hcd) spin_unlock_irq(&uhci->lock); - if (!uhci->working_RD) { - /* Suspended root hub needs to be polled */ + /* If interrupts don't work and remote wakeup is enabled then + * the suspended root hub needs to be polled. + */ + if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) { hcd->poll_rh = 1; usb_hcd_poll_rh_status(hcd); } @@ -872,8 +907,8 @@ static const struct hc_driver uhci_driver = { .reset = uhci_init, .start = uhci_start, #ifdef CONFIG_PM - .suspend = uhci_suspend, - .resume = uhci_resume, + .pci_suspend = uhci_pci_suspend, + .pci_resume = uhci_pci_resume, .bus_suspend = uhci_rh_suspend, .bus_resume = uhci_rh_resume, #endif diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 340d6ed3e6e9..7d01c5677f92 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -400,8 +400,9 @@ struct uhci_hcd { unsigned int scan_in_progress:1; /* Schedule scan is running */ unsigned int need_rescan:1; /* Redo the schedule scan */ unsigned int dead:1; /* Controller has died */ - unsigned int working_RD:1; /* Suspended root hub doesn't - need to be polled */ + unsigned int RD_enable:1; /* Suspended root hub with + Resume-Detect interrupts + enabled */ unsigned int is_initialized:1; /* Data structure is usable */ unsigned int fsbr_is_on:1; /* FSBR is turned on */ unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 60379b17bbc1..db645936eedd 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1171,7 +1171,7 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) /* Some debugging code */ dev_dbg(&urb->dev->dev, "%s: failed with status %x\n", - __FUNCTION__, status); + __func__, status); if (debug > 1 && errbuf) { /* Print the chain for debugging */ |