LIBS += drivers/rtc/librtc.a
LIBS += drivers/serial/libserial.a
LIBS += drivers/twserial/libtws.a
-LIBS += drivers/usb/libusb.a
+LIBS += drivers/usb/gadget/libusb_gadget.a
+LIBS += drivers/usb/host/libusb_host.a
+LIBS += drivers/usb/musb/libusb_musb.a
LIBS += drivers/video/libvideo.a
LIBS += drivers/watchdog/libwatchdog.a
LIBS += common/libcommon.a
* Descriptors, Strings, Local variables.
*/
-/* defined and used by usbdcore_ep0.c */
+/* defined and used by gadget/ep0.c */
extern struct usb_string_descriptor **usb_strings;
/* Indicies, References */
#ifndef __USB_TTY_H__
#define __USB_TTY_H__
-#include <usbdcore.h>
+#include <usbdevice.h>
#if defined(CONFIG_PPC)
-#include <usbdcore_mpc8xx.h>
+#include <usb/mpc8xx_udc.h>
#elif defined(CONFIG_ARM)
-#include <usbdcore_omap1510.h>
+#include <usb/omap1510_udc.h>
#endif
#include <version_autogenerated.h>
+++ /dev/null
-#
-# (C) Copyright 2000-2007
-# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-#
-# See file CREDITS for list of people who contributed to this
-# project.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-# MA 02111-1307 USA
-#
-
-include $(TOPDIR)/config.mk
-
-LIB := $(obj)libusb.a
-
-# core
-COBJS-y += usbdcore.o
-COBJS-$(CONFIG_USB_OHCI_NEW) += usb_ohci.o
-COBJS-$(CONFIG_USB_EHCI) += usb_ehci_core.o
-
-# host
-COBJS-$(CONFIG_USB_ATMEL) += atmel_usb.o
-COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
-COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-COBJS-$(CONFIG_USB_S3C64XX) += s3c64xx_usb.o
-COBJS-$(CONFIG_USB_SL811HS) += sl811_usb.o
-COBJS-$(CONFIG_USB_EHCI_FSL) += usb_ehci_fsl.o
-COBJS-$(CONFIG_USB_EHCI_PCI) += usb_ehci_pci.o
-COBJS-$(CONFIG_USB_EHCI_IXP4XX) += usb_ehci_ixp.o
-COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
-COBJS-$(CONFIG_USB_DAVINCI) += davinci_usb.o
-COBJS-$(CONFIG_USB_EHCI_VCT) += usb_ehci_vct.o
-
-# device
-ifdef CONFIG_USB_DEVICE
-COBJS-y += usbdcore_ep0.o
-COBJS-$(CONFIG_OMAP1510) += usbdcore_omap1510.o
-COBJS-$(CONFIG_OMAP1610) += usbdcore_omap1510.o
-COBJS-$(CONFIG_MPC885_FAMILY) += usbdcore_mpc8xx.o
-endif
-
-COBJS := $(COBJS-y)
-SRCS := $(COBJS:.o=.c)
-OBJS := $(addprefix $(obj),$(COBJS))
-
-all: $(LIB)
-
-$(LIB): $(obj).depend $(OBJS)
- $(AR) $(ARFLAGS) $@ $(OBJS)
-
-#########################################################################
-
-# defines $(obj).depend target
-include $(SRCTREE)/rules.mk
-
-sinclude $(obj).depend
-
-#########################################################################
+++ /dev/null
-/*
- * (C) Copyright 2006
- * DENX Software Engineering <mk@denx.de>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-
-#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
-
-#include <asm/arch/hardware.h>
-#include <asm/arch/io.h>
-#include <asm/arch/at91_pmc.h>
-
-int usb_cpu_init(void)
-{
-
-#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
- defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
- /* Enable PLLB */
- at91_sys_write(AT91_CKGR_PLLBR, CONFIG_SYS_AT91_PLLB);
- while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
- ;
-#endif
-
- /* Enable USB host clock. */
- at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_UHP);
-#ifdef CONFIG_AT91SAM9261
- at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP | AT91_PMC_HCK0);
-#else
- at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP);
-#endif
-
- return 0;
-}
-
-int usb_cpu_stop(void)
-{
- /* Disable USB host clock. */
- at91_sys_write(AT91_PMC_PCDR, 1 << AT91_ID_UHP);
-#ifdef CONFIG_AT91SAM9261
- at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_HCK0);
-#else
- at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP);
-#endif
-
-#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
- defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
- /* Disable PLLB */
- at91_sys_write(AT91_CKGR_PLLBR, 0);
- while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != 0)
- ;
-#endif
-
- return 0;
-}
-
-int usb_cpu_init_fail(void)
-{
- return usb_cpu_stop();
-}
-
-#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
+++ /dev/null
-/*
- * TI's Davinci platform specific USB wrapper functions.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include "davinci_usb.h"
-
-/* MUSB platform configuration */
-struct musb_config musb_cfg = {
- (struct musb_regs *)MENTOR_USB0_BASE,
- DAVINCI_USB_TIMEOUT,
- 0
-};
-
-/* MUSB module register overlay */
-struct davinci_usb_regs *dregs;
-
-/*
- * Enable the USB phy
- */
-static u8 phy_on(void)
-{
- u32 timeout;
-
- /* Wait until the USB phy is turned on */
- writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN, USBPHY_CTL_PADDR);
- timeout = musb_cfg.timeout;
- while (timeout--)
- if (readl(USBPHY_CTL_PADDR) & USBPHY_PHYCLKGD)
- return 1;
-
- /* USB phy was not turned on */
- return 0;
-}
-
-/*
- * Disable the USB phy
- */
-static void phy_off(void)
-{
- /* powerdown the on-chip PHY and its oscillator */
- writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, USBPHY_CTL_PADDR);
-}
-
-/*
- * This function performs Davinci platform specific initialization for usb0.
- */
-int musb_platform_init(void)
-{
- u32 revision;
-
- /* enable USB VBUS */
- enable_vbus();
-
- /* start the on-chip USB phy and its pll */
- if (!phy_on())
- return -1;
-
- /* reset the controller */
- dregs = (struct davinci_usb_regs *)DAVINCI_USB0_BASE;
- writel(1, &dregs->ctrlr);
- udelay(5000);
-
- /* Returns zero if e.g. not clocked */
- revision = readl(&dregs->version);
- if (!revision)
- return -1;
-
- /* Disable all interrupts */
- writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_RXINT_MASK |
- DAVINCI_USB_TXINT_MASK , &dregs->intmsksetr);
- return 0;
-}
-
-/*
- * This function performs Davinci platform specific deinitialization for usb0.
- */
-void musb_platform_deinit(void)
-{
- /* Turn of the phy */
- phy_off();
-
- /* flush any interrupts */
- writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK |
- DAVINCI_USB_RXINT_MASK , &dregs->intclrr);
-}
+++ /dev/null
-/*
- * TI's Davinci platform specific USB wrapper functions.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#ifndef __DAVINCI_USB_H__
-#define __DAVINCI_USB_H__
-
-#include <asm/arch/hardware.h>
-#include "musb_core.h"
-
-/* Base address of DAVINCI usb0 wrapper */
-#define DAVINCI_USB0_BASE 0x01C64000
-
-/* Base address of DAVINCI musb core */
-#define MENTOR_USB0_BASE (DAVINCI_USB0_BASE+0x400)
-
-/*
- * Davinci platform USB wrapper register overlay. Note: Only the required
- * registers are included in this structure. It can be expanded as required.
- */
-struct davinci_usb_regs {
- u32 version;
- u32 ctrlr;
- u32 reserved[0x20];
- u32 intclrr;
- u32 intmskr;
- u32 intmsksetr;
-};
-
-#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
-#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
-#define DAVINCI_USB_USBINT_SHIFT 16
-#define DAVINCI_USB_TXINT_SHIFT 0
-#define DAVINCI_USB_RXINT_SHIFT 8
-#define DAVINCI_INTR_DRVVBUS 0x0100
-
-#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
-#define DAVINCI_USB_TXINT_MASK \
- (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
-#define DAVINCI_USB_RXINT_MASK \
- (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
-#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
- (0x80 + (8*(_bEnd)) + (_bOffset))
-
-/* Integrated highspeed/otg PHY */
-#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
-#define USBPHY_PHYCLKGD (1 << 8)
-#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
-#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
-#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
-#define USBPHY_CLKO1SEL (1 << 3)
-#define USBPHY_OSCPDWN (1 << 2)
-#define USBPHY_PHYPDWN (1 << 0)
-
-/* Timeout for Davinci USB module */
-#define DAVINCI_USB_TIMEOUT 0x3FFFFFF
-
-/* IO Expander I2C address and VBUS enable mask */
-#define IOEXP_I2C_ADDR 0x3A
-#define IOEXP_VBUSEN_MASK 1
-
-/* extern functions */
-extern void lpsc_on(unsigned int id);
-extern int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
-extern int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
-extern void enable_vbus(void);
-#endif /* __DAVINCI_USB_H__ */
--- /dev/null
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_gadget.a
+
+ifdef CONFIG_USB_DEVICE
+COBJS-y += core.o
+COBJS-y += ep0.o
+COBJS-$(CONFIG_OMAP1510) += omap1510_udc.o
+COBJS-$(CONFIG_OMAP1610) += omap1510_udc.o
+COBJS-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o
+endif
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ * Stuart Lynne <sl@lineo.com>,
+ * Tom Rushworth <tbr@lineo.com>,
+ * Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <malloc.h>
+#include <usbdevice.h>
+
+#define MAX_INTERFACES 2
+
+
+int maxstrings = 20;
+
+/* Global variables ************************************************************************** */
+
+struct usb_string_descriptor **usb_strings;
+
+int usb_devices;
+
+extern struct usb_function_driver ep0_driver;
+
+int registered_functions;
+int registered_devices;
+
+char *usbd_device_events[] = {
+ "DEVICE_UNKNOWN",
+ "DEVICE_INIT",
+ "DEVICE_CREATE",
+ "DEVICE_HUB_CONFIGURED",
+ "DEVICE_RESET",
+ "DEVICE_ADDRESS_ASSIGNED",
+ "DEVICE_CONFIGURED",
+ "DEVICE_SET_INTERFACE",
+ "DEVICE_SET_FEATURE",
+ "DEVICE_CLEAR_FEATURE",
+ "DEVICE_DE_CONFIGURED",
+ "DEVICE_BUS_INACTIVE",
+ "DEVICE_BUS_ACTIVITY",
+ "DEVICE_POWER_INTERRUPTION",
+ "DEVICE_HUB_RESET",
+ "DEVICE_DESTROY",
+ "DEVICE_FUNCTION_PRIVATE",
+};
+
+char *usbd_device_states[] = {
+ "STATE_INIT",
+ "STATE_CREATED",
+ "STATE_ATTACHED",
+ "STATE_POWERED",
+ "STATE_DEFAULT",
+ "STATE_ADDRESSED",
+ "STATE_CONFIGURED",
+ "STATE_UNKNOWN",
+};
+
+char *usbd_device_requests[] = {
+ "GET STATUS", /* 0 */
+ "CLEAR FEATURE", /* 1 */
+ "RESERVED", /* 2 */
+ "SET FEATURE", /* 3 */
+ "RESERVED", /* 4 */
+ "SET ADDRESS", /* 5 */
+ "GET DESCRIPTOR", /* 6 */
+ "SET DESCRIPTOR", /* 7 */
+ "GET CONFIGURATION", /* 8 */
+ "SET CONFIGURATION", /* 9 */
+ "GET INTERFACE", /* 10 */
+ "SET INTERFACE", /* 11 */
+ "SYNC FRAME", /* 12 */
+};
+
+char *usbd_device_descriptors[] = {
+ "UNKNOWN", /* 0 */
+ "DEVICE", /* 1 */
+ "CONFIG", /* 2 */
+ "STRING", /* 3 */
+ "INTERFACE", /* 4 */
+ "ENDPOINT", /* 5 */
+ "DEVICE QUALIFIER", /* 6 */
+ "OTHER SPEED", /* 7 */
+ "INTERFACE POWER", /* 8 */
+};
+
+char *usbd_device_status[] = {
+ "USBD_OPENING",
+ "USBD_OK",
+ "USBD_SUSPENDED",
+ "USBD_CLOSING",
+};
+
+
+/* Descriptor support functions ************************************************************** */
+
+
+/**
+ * usbd_get_string - find and return a string descriptor
+ * @index: string index to return
+ *
+ * Find an indexed string and return a pointer to a it.
+ */
+struct usb_string_descriptor *usbd_get_string (__u8 index)
+{
+ if (index >= maxstrings) {
+ return NULL;
+ }
+ return usb_strings[index];
+}
+
+
+/* Access to device descriptor functions ***************************************************** */
+
+
+/* *
+ * usbd_device_configuration_instance - find a configuration instance for this device
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Get specifed device configuration. Index should be bConfigurationValue-1.
+ */
+static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
+ unsigned int port, unsigned int configuration)
+{
+ if (configuration >= device->configurations)
+ return NULL;
+
+ return device->configuration_instance_array + configuration;
+}
+
+
+/* *
+ * usbd_device_interface_instance
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
+{
+ struct usb_configuration_instance *configuration_instance;
+
+ if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
+ return NULL;
+ }
+ if (interface >= configuration_instance->interfaces) {
+ return NULL;
+ }
+ return configuration_instance->interface_instance_array + interface;
+}
+
+/* *
+ * usbd_device_alternate_descriptor_list
+ * @device:
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified alternate descriptor for the specified device.
+ */
+struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
+{
+ struct usb_interface_instance *interface_instance;
+
+ if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
+ return NULL;
+ }
+
+ if (alternate >= interface_instance->alternates) {
+ return NULL;
+ }
+
+ return interface_instance->alternates_instance_array + alternate;
+}
+
+
+/* *
+ * usbd_device_device_descriptor
+ * @device: which device
+ * @configuration: index to configuration, 0 - N-1
+ * @port: which port
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
+{
+ return (device->device_descriptor);
+}
+
+
+/**
+ * usbd_device_configuration_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ *
+ * Return the specified configuration descriptor for the specified device.
+ */
+struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
+ usb_device_instance
+ *device, int port, int configuration)
+{
+ struct usb_configuration_instance *configuration_instance;
+ if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
+ return NULL;
+ }
+ return (configuration_instance->configuration_descriptor);
+}
+
+
+/**
+ * usbd_device_interface_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ *
+ * Return the specified interface descriptor for the specified device.
+ */
+struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
+ *device, int port, int configuration, int interface, int alternate)
+{
+ struct usb_interface_instance *interface_instance;
+ if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
+ return NULL;
+ }
+ if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
+ return NULL;
+ }
+ return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
+}
+
+/**
+ * usbd_device_endpoint_descriptor_index
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: index setting
+ * @index: which index
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
+ *device, int port, int configuration, int interface, int alternate, int index)
+{
+ struct usb_alternate_instance *alternate_instance;
+
+ if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+ return NULL;
+ }
+ if (index >= alternate_instance->endpoints) {
+ return NULL;
+ }
+ return *(alternate_instance->endpoints_descriptor_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_transfersize
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @index: which index
+ *
+ * Return the specified endpoint transfer size;
+ */
+int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
+{
+ struct usb_alternate_instance *alternate_instance;
+
+ if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
+ return 0;
+ }
+ if (index >= alternate_instance->endpoints) {
+ return 0;
+ }
+ return *(alternate_instance->endpoint_transfersize_array + index);
+}
+
+
+/**
+ * usbd_device_endpoint_descriptor
+ * @device: which device
+ * @port: which port
+ * @configuration: index to configuration, 0 - N-1
+ * @interface: index to interface
+ * @alternate: alternate setting
+ * @endpoint: which endpoint
+ *
+ * Return the specified endpoint descriptor for the specified device.
+ */
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
+{
+ struct usb_endpoint_descriptor *endpoint_descriptor;
+ int i;
+
+ for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
+ if (endpoint_descriptor->bEndpointAddress == endpoint) {
+ return endpoint_descriptor;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * usbd_endpoint_halted
+ * @device: point to struct usb_device_instance
+ * @endpoint: endpoint to check
+ *
+ * Return non-zero if endpoint is halted.
+ */
+int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
+{
+ return (device->status == USB_STATUS_HALT);
+}
+
+
+/**
+ * usbd_rcv_complete - complete a receive
+ * @endpoint:
+ * @len:
+ * @urb_bad:
+ *
+ * Called from rcv interrupt to complete.
+ */
+void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
+{
+ if (endpoint) {
+ struct urb *rcv_urb;
+
+ /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
+
+ /* if we had an urb then update actual_length, dispatch if neccessary */
+ if ((rcv_urb = endpoint->rcv_urb)) {
+
+ /*usbdbg("actual: %d buffer: %d\n", */
+ /*rcv_urb->actual_length, rcv_urb->buffer_length); */
+
+ /* check the urb is ok, are we adding data less than the packetsize */
+ if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
+ /*usbdbg("updating actual_length by %d\n",len); */
+
+ /* increment the received data size */
+ rcv_urb->actual_length += len;
+
+ } else {
+ usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
+ rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
+
+ rcv_urb->actual_length = 0;
+ rcv_urb->status = RECV_ERROR;
+ }
+ } else {
+ usberr("no rcv_urb!");
+ }
+ } else {
+ usberr("no endpoint!");
+ }
+
+}
+
+/**
+ * usbd_tx_complete - complete a transmit
+ * @endpoint:
+ * @resetart:
+ *
+ * Called from tx interrupt to complete.
+ */
+void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
+{
+ if (endpoint) {
+ struct urb *tx_urb;
+
+ /* if we have a tx_urb advance or reset, finish if complete */
+ if ((tx_urb = endpoint->tx_urb)) {
+ int sent = endpoint->last;
+ endpoint->sent += sent;
+ endpoint->last -= sent;
+
+ if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
+ tx_urb->actual_length = 0;
+ endpoint->sent = 0;
+ endpoint->last = 0;
+
+ /* Remove from active, save for re-use */
+ urb_detach(tx_urb);
+ urb_append(&endpoint->done, tx_urb);
+ /*usbdbg("done->next %p, tx_urb %p, done %p", */
+ /* endpoint->done.next, tx_urb, &endpoint->done); */
+
+ endpoint->tx_urb = first_urb_detached(&endpoint->tx);
+ if( endpoint->tx_urb ) {
+ endpoint->tx_queue--;
+ usbdbg("got urb from tx list");
+ }
+ if( !endpoint->tx_urb ) {
+ /*usbdbg("taking urb from done list"); */
+ endpoint->tx_urb = first_urb_detached(&endpoint->done);
+ }
+ if( !endpoint->tx_urb ) {
+ usbdbg("allocating new urb for tx_urb");
+ endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
+ }
+ }
+ }
+ }
+}
+
+/* URB linked list functions ***************************************************** */
+
+/*
+ * Initialize an urb_link to be a single element list.
+ * If the urb_link is being used as a distinguished list head
+ * the list is empty when the head is the only link in the list.
+ */
+void urb_link_init (urb_link * ul)
+{
+ if (ul) {
+ ul->prev = ul->next = ul;
+ }
+}
+
+/*
+ * Detach an urb_link from a list, and set it
+ * up as a single element list, so no dangling
+ * pointers can be followed, and so it can be
+ * joined to another list if so desired.
+ */
+void urb_detach (struct urb *urb)
+{
+ if (urb) {
+ urb_link *ul = &urb->link;
+ ul->next->prev = ul->prev;
+ ul->prev->next = ul->next;
+ urb_link_init (ul);
+ }
+}
+
+/*
+ * Return the first urb_link in a list with a distinguished
+ * head "hd", or NULL if the list is empty. This will also
+ * work as a predicate, returning NULL if empty, and non-NULL
+ * otherwise.
+ */
+urb_link *first_urb_link (urb_link * hd)
+{
+ urb_link *nx;
+ if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
+ /* There is at least one element in the list */
+ /* (besides the distinguished head). */
+ return (nx);
+ }
+ /* The list is empty */
+ return (NULL);
+}
+
+/*
+ * Return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ */
+struct urb *first_urb (urb_link * hd)
+{
+ urb_link *nx;
+ if (NULL == (nx = first_urb_link (hd))) {
+ /* The list is empty */
+ return (NULL);
+ }
+ return (p2surround (struct urb, link, nx));
+}
+
+/*
+ * Detach and return the first urb in a list with a distinguished
+ * head "hd", or NULL if the list is empty.
+ *
+ */
+struct urb *first_urb_detached (urb_link * hd)
+{
+ struct urb *urb;
+ if ((urb = first_urb (hd))) {
+ urb_detach (urb);
+ }
+ return urb;
+}
+
+
+/*
+ * Append an urb_link (or a whole list of
+ * urb_links) to the tail of another list
+ * of urb_links.
+ */
+void urb_append (urb_link * hd, struct urb *urb)
+{
+ if (hd && urb) {
+ urb_link *new = &urb->link;
+
+ /* This allows the new urb to be a list of urbs, */
+ /* with new pointing at the first, but the link */
+ /* must be initialized. */
+ /* Order is important here... */
+ urb_link *pul = hd->prev;
+ new->prev->next = hd;
+ hd->prev = new->prev;
+ new->prev = pul;
+ pul->next = new;
+ }
+}
+
+/* URB create/destroy functions ***************************************************** */
+
+/**
+ * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
+ * @device: device instance
+ * @endpoint: endpoint
+ *
+ * Allocate an urb structure. The usb device urb structure is used to
+ * contain all data associated with a transfer, including a setup packet for
+ * control transfers.
+ *
+ * NOTE: endpoint_address MUST contain a direction flag.
+ */
+struct urb *usbd_alloc_urb (struct usb_device_instance *device,
+ struct usb_endpoint_instance *endpoint)
+{
+ struct urb *urb;
+
+ if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
+ usberr (" F A T A L: malloc(%zu) FAILED!!!!",
+ sizeof (struct urb));
+ return NULL;
+ }
+
+ /* Fill in known fields */
+ memset (urb, 0, sizeof (struct urb));
+ urb->endpoint = endpoint;
+ urb->device = device;
+ urb->buffer = (u8 *) urb->buffer_data;
+ urb->buffer_length = sizeof (urb->buffer_data);
+
+ urb_link_init (&urb->link);
+
+ return urb;
+}
+
+/**
+ * usbd_dealloc_urb - deallocate an URB and associated buffer
+ * @urb: pointer to an urb structure
+ *
+ * Deallocate an urb structure and associated data.
+ */
+void usbd_dealloc_urb (struct urb *urb)
+{
+ if (urb) {
+ free (urb);
+ }
+}
+
+/* Event signaling functions ***************************************************** */
+
+/**
+ * usbd_device_event - called to respond to various usb events
+ * @device: pointer to struct device
+ * @event: event to respond to
+ *
+ * Used by a Bus driver to indicate an event.
+ */
+void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
+{
+ usb_device_state_t state;
+
+ if (!device || !device->bus) {
+ usberr("(%p,%d) NULL device or device->bus", device, event);
+ return;
+ }
+
+ state = device->device_state;
+
+ usbinfo("%s", usbd_device_events[event]);
+
+ switch (event) {
+ case DEVICE_UNKNOWN:
+ break;
+ case DEVICE_INIT:
+ device->device_state = STATE_INIT;
+ break;
+
+ case DEVICE_CREATE:
+ device->device_state = STATE_ATTACHED;
+ break;
+
+ case DEVICE_HUB_CONFIGURED:
+ device->device_state = STATE_POWERED;
+ break;
+
+ case DEVICE_RESET:
+ device->device_state = STATE_DEFAULT;
+ device->address = 0;
+ break;
+
+ case DEVICE_ADDRESS_ASSIGNED:
+ device->device_state = STATE_ADDRESSED;
+ break;
+
+ case DEVICE_CONFIGURED:
+ device->device_state = STATE_CONFIGURED;
+ break;
+
+ case DEVICE_DE_CONFIGURED:
+ device->device_state = STATE_ADDRESSED;
+ break;
+
+ case DEVICE_BUS_INACTIVE:
+ if (device->status != USBD_CLOSING) {
+ device->status = USBD_SUSPENDED;
+ }
+ break;
+ case DEVICE_BUS_ACTIVITY:
+ if (device->status != USBD_CLOSING) {
+ device->status = USBD_OK;
+ }
+ break;
+
+ case DEVICE_SET_INTERFACE:
+ break;
+ case DEVICE_SET_FEATURE:
+ break;
+ case DEVICE_CLEAR_FEATURE:
+ break;
+
+ case DEVICE_POWER_INTERRUPTION:
+ device->device_state = STATE_POWERED;
+ break;
+ case DEVICE_HUB_RESET:
+ device->device_state = STATE_ATTACHED;
+ break;
+ case DEVICE_DESTROY:
+ device->device_state = STATE_UNKNOWN;
+ break;
+
+ case DEVICE_FUNCTION_PRIVATE:
+ break;
+
+ default:
+ usbdbg("event %d - not handled",event);
+ break;
+ }
+ /*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
+ device->name, event, state,
+ device->device_state, device->status, device->address); */
+
+ /* tell the bus interface driver */
+ if( device->event ) {
+ /* usbdbg("calling device->event"); */
+ device->event(device, event, data);
+ }
+}
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@CodeHermit.ie
+ *
+ * Based on
+ * linux/drivers/usbd/ep0.c
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ * Stuart Lynne <sl@lineo.com>,
+ * Tom Rushworth <tbr@lineo.com>,
+ * Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * This is the builtin ep0 control function. It implements all required functionality
+ * for responding to control requests (SETUP packets).
+ *
+ * XXX
+ *
+ * Currently we do not pass any SETUP packets (or other) to the configured
+ * function driver. This may need to change.
+ *
+ * XXX
+ *
+ * As alluded to above, a simple callback cdc_recv_setup has been implemented
+ * in the usb_device data structure to facilicate passing
+ * Common Device Class packets to a function driver.
+ *
+ * XXX
+ */
+
+#include <common.h>
+#include <usbdevice.h>
+
+#if 0
+#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
+#else
+#define dbg_ep0(lvl,fmt,args...)
+#endif
+
+/* EP0 Configuration Set ********************************************************************* */
+
+
+/**
+ * ep0_get_status - fill in URB data with appropriate status
+ * @device:
+ * @urb:
+ * @index:
+ * @requesttype:
+ *
+ */
+static int ep0_get_status (struct usb_device_instance *device,
+ struct urb *urb, int index, int requesttype)
+{
+ char *cp;
+
+ urb->actual_length = 2;
+ cp = (char*)urb->buffer;
+ cp[0] = cp[1] = 0;
+
+ switch (requesttype) {
+ case USB_REQ_RECIPIENT_DEVICE:
+ cp[0] = USB_STATUS_SELFPOWERED;
+ break;
+ case USB_REQ_RECIPIENT_INTERFACE:
+ break;
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ cp[0] = usbd_endpoint_halted (device, index);
+ break;
+ case USB_REQ_RECIPIENT_OTHER:
+ urb->actual_length = 0;
+ default:
+ break;
+ }
+ dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
+ return 0;
+}
+
+/**
+ * ep0_get_one
+ * @device:
+ * @urb:
+ * @result:
+ *
+ * Set a single byte value in the urb send buffer. Return non-zero to signal
+ * a request error.
+ */
+static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
+ __u8 result)
+{
+ urb->actual_length = 1; /* XXX 2? */
+ ((char *) urb->buffer)[0] = result;
+ return 0;
+}
+
+/**
+ * copy_config
+ * @urb: pointer to urb
+ * @data: pointer to configuration data
+ * @length: length of data
+ *
+ * Copy configuration data to urb transfer buffer if there is room for it.
+ */
+void copy_config (struct urb *urb, void *data, int max_length,
+ int max_buf)
+{
+ int available;
+ int length;
+
+ /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
+ /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
+
+ if (!data) {
+ dbg_ep0 (1, "data is NULL");
+ return;
+ }
+ length = max_length;
+
+ if (length > max_length) {
+ dbg_ep0 (1, "length: %d >= max_length: %d", length,
+ max_length);
+ return;
+ }
+ /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
+ /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
+
+ if ((available =
+ /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
+ return;
+ }
+ /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+ /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+ if (length > available) {
+ length = available;
+ }
+ /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
+ /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
+
+ memcpy (urb->buffer + urb->actual_length, data, length);
+ urb->actual_length += length;
+
+ dbg_ep0 (3,
+ "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
+ urb->actual_length, urb->buffer_length, max_buf, max_length,
+ available);
+}
+
+/**
+ * ep0_get_descriptor
+ * @device:
+ * @urb:
+ * @max:
+ * @descriptor_type:
+ * @index:
+ *
+ * Called by ep0_rx_process for a get descriptor device command. Determine what
+ * descriptor is being requested, copy to send buffer. Return zero if ok to send,
+ * return non-zero to signal a request error.
+ */
+static int ep0_get_descriptor (struct usb_device_instance *device,
+ struct urb *urb, int max, int descriptor_type,
+ int index)
+{
+ int port = 0; /* XXX compound device */
+ char *cp;
+
+ /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
+
+ if (!urb || !urb->buffer || !urb->buffer_length
+ || (urb->buffer_length < 255)) {
+ dbg_ep0 (2, "invalid urb %p", urb);
+ return -1L;
+ }
+
+ /* setup tx urb */
+ urb->actual_length = 0;
+ cp = (char*)urb->buffer;
+
+ dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
+
+ switch (descriptor_type) {
+ case USB_DESCRIPTOR_TYPE_DEVICE:
+ {
+ struct usb_device_descriptor *device_descriptor;
+ if (!
+ (device_descriptor =
+ usbd_device_device_descriptor (device, port))) {
+ return -1;
+ }
+ /* copy descriptor for this device */
+ copy_config (urb, device_descriptor,
+ sizeof (struct usb_device_descriptor),
+ max);
+
+ /* correct the correct control endpoint 0 max packet size into the descriptor */
+ device_descriptor =
+ (struct usb_device_descriptor *) urb->buffer;
+
+ }
+ dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
+ break;
+
+ case USB_DESCRIPTOR_TYPE_CONFIGURATION:
+ {
+ struct usb_configuration_descriptor
+ *configuration_descriptor;
+ struct usb_device_descriptor *device_descriptor;
+ if (!
+ (device_descriptor =
+ usbd_device_device_descriptor (device, port))) {
+ return -1;
+ }
+ /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
+ if (index >= device_descriptor->bNumConfigurations) {
+ dbg_ep0 (0, "index too large: %d >= %d", index,
+ device_descriptor->
+ bNumConfigurations);
+ return -1;
+ }
+
+ if (!
+ (configuration_descriptor =
+ usbd_device_configuration_descriptor (device,
+ port,
+ index))) {
+ dbg_ep0 (0,
+ "usbd_device_configuration_descriptor failed: %d",
+ index);
+ return -1;
+ }
+ dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
+ copy_config (urb, configuration_descriptor,
+
+ cpu_to_le16(configuration_descriptor->wTotalLength),
+ max);
+ }
+
+ break;
+
+ case USB_DESCRIPTOR_TYPE_STRING:
+ {
+ struct usb_string_descriptor *string_descriptor;
+ if (!(string_descriptor = usbd_get_string (index))) {
+ serial_printf("Invalid string index %d\n", index);
+ return -1;
+ }
+ dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
+ copy_config (urb, string_descriptor, string_descriptor->bLength, max);
+ }
+ break;
+ case USB_DESCRIPTOR_TYPE_INTERFACE:
+ serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
+ return -1;
+ case USB_DESCRIPTOR_TYPE_ENDPOINT:
+ serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
+ return -1;
+ case USB_DESCRIPTOR_TYPE_HID:
+ {
+ serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
+ return -1; /* unsupported at this time */
+#if 0
+ int bNumInterface =
+ le16_to_cpu (urb->device_request.wIndex);
+ int bAlternateSetting = 0;
+ int class = 0;
+ struct usb_class_descriptor *class_descriptor;
+
+ if (!(class_descriptor =
+ usbd_device_class_descriptor_index (device,
+ port, 0,
+ bNumInterface,
+ bAlternateSetting,
+ class))
+ || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
+ dbg_ep0 (3, "[%d] interface is not HID",
+ bNumInterface);
+ return -1;
+ }
+ /* copy descriptor for this class */
+ copy_config (urb, class_descriptor,
+ class_descriptor->descriptor.hid.bLength,
+ max);
+#endif
+ }
+ break;
+ case USB_DESCRIPTOR_TYPE_REPORT:
+ {
+ serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
+ return -1; /* unsupported at this time */
+#if 0
+ int bNumInterface =
+ le16_to_cpu (urb->device_request.wIndex);
+ int bAlternateSetting = 0;
+ int class = 0;
+ struct usb_class_report_descriptor *report_descriptor;
+
+ if (!(report_descriptor =
+ usbd_device_class_report_descriptor_index
+ (device, port, 0, bNumInterface,
+ bAlternateSetting, class))
+ || report_descriptor->bDescriptorType !=
+ USB_DT_REPORT) {
+ dbg_ep0 (3, "[%d] descriptor is not REPORT",
+ bNumInterface);
+ return -1;
+ }
+ /* copy report descriptor for this class */
+ /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
+ if (max - urb->actual_length > 0) {
+ int length =
+ MIN (report_descriptor->wLength,
+ max - urb->actual_length);
+ memcpy (urb->buffer + urb->actual_length,
+ &report_descriptor->bData[0], length);
+ urb->actual_length += length;
+ }
+#endif
+ }
+ break;
+ case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+ {
+ /* If a USB device supports both a full speed and low speed operation
+ * we must send a Device_Qualifier descriptor here
+ */
+ return -1;
+ }
+ default:
+ return -1;
+ }
+
+
+ dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
+ urb->buffer, urb->buffer_length, urb->actual_length,
+ device->bus->endpoint_array[0].tx_packetSize);
+/*
+ if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
+ dbg_ep0(0, "adding null byte");
+ urb->buffer[urb->actual_length++] = 0;
+ dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
+ urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
+ }
+*/
+ return 0;
+
+}
+
+/**
+ * ep0_recv_setup - called to indicate URB has been received
+ * @urb: pointer to struct urb
+ *
+ * Check if this is a setup packet, process the device request, put results
+ * back into the urb and return zero or non-zero to indicate success (DATA)
+ * or failure (STALL).
+ *
+ */
+int ep0_recv_setup (struct urb *urb)
+{
+ /*struct usb_device_request *request = urb->buffer; */
+ /*struct usb_device_instance *device = urb->device; */
+
+ struct usb_device_request *request;
+ struct usb_device_instance *device;
+ int address;
+
+ dbg_ep0 (0, "entering ep0_recv_setup()");
+ if (!urb || !urb->device) {
+ dbg_ep0 (3, "invalid URB %p", urb);
+ return -1;
+ }
+
+ request = &urb->device_request;
+ device = urb->device;
+
+ dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
+
+
+ /*dbg_ep0(2, "- - - - - - - - - -"); */
+
+ dbg_ep0 (2,
+ "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
+ request->bmRequestType, request->bRequest,
+ le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
+ le16_to_cpu (request->wLength),
+ USBD_DEVICE_REQUESTS (request->bRequest));
+
+ /* handle USB Standard Request (c.f. USB Spec table 9-2) */
+ if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+ if(device->device_state <= STATE_CONFIGURED){
+ /* Attempt to handle a CDC specific request if we are
+ * in the configured state.
+ */
+ return device->cdc_recv_setup(request,urb);
+ }
+ dbg_ep0 (1, "non standard request: %x",
+ request->bmRequestType & USB_REQ_TYPE_MASK);
+ return -1; /* Stall here */
+ }
+
+ switch (device->device_state) {
+ case STATE_CREATED:
+ case STATE_ATTACHED:
+ case STATE_POWERED:
+ /* It actually is important to allow requests in these states,
+ * Windows will request descriptors before assigning an
+ * address to the client.
+ */
+
+ /*dbg_ep0 (1, "request %s not allowed in this state: %s", */
+ /* USBD_DEVICE_REQUESTS(request->bRequest), */
+ /* usbd_device_states[device->device_state]); */
+ /*return -1; */
+ break;
+
+ case STATE_INIT:
+ case STATE_DEFAULT:
+ switch (request->bRequest) {
+ case USB_REQ_GET_STATUS:
+ case USB_REQ_GET_INTERFACE:
+ case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_SET_DESCRIPTOR:
+ /* case USB_REQ_SET_CONFIGURATION: */
+ case USB_REQ_SET_INTERFACE:
+ dbg_ep0 (1,
+ "request %s not allowed in DEFAULT state: %s",
+ USBD_DEVICE_REQUESTS (request->bRequest),
+ usbd_device_states[device->device_state]);
+ return -1;
+
+ case USB_REQ_SET_CONFIGURATION:
+ case USB_REQ_SET_ADDRESS:
+ case USB_REQ_GET_DESCRIPTOR:
+ case USB_REQ_GET_CONFIGURATION:
+ break;
+ }
+ case STATE_ADDRESSED:
+ case STATE_CONFIGURED:
+ break;
+ case STATE_UNKNOWN:
+ dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
+ USBD_DEVICE_REQUESTS (request->bRequest),
+ usbd_device_states[device->device_state]);
+ return -1;
+ }
+
+ /* handle all requests that return data (direction bit set on bm RequestType) */
+ if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
+
+ dbg_ep0 (3, "Device-to-Host");
+
+ switch (request->bRequest) {
+
+ case USB_REQ_GET_STATUS:
+ return ep0_get_status (device, urb, request->wIndex,
+ request->bmRequestType &
+ USB_REQ_RECIPIENT_MASK);
+
+ case USB_REQ_GET_DESCRIPTOR:
+ return ep0_get_descriptor (device, urb,
+ le16_to_cpu (request->wLength),
+ le16_to_cpu (request->wValue) >> 8,
+ le16_to_cpu (request->wValue) & 0xff);
+
+ case USB_REQ_GET_CONFIGURATION:
+ serial_printf("get config %d\n", device->configuration);
+ return ep0_get_one (device, urb,
+ device->configuration);
+
+ case USB_REQ_GET_INTERFACE:
+ return ep0_get_one (device, urb, device->alternate);
+
+ case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
+ return -1;
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_SET_ADDRESS:
+ case USB_REQ_SET_DESCRIPTOR:
+ case USB_REQ_SET_CONFIGURATION:
+ case USB_REQ_SET_INTERFACE:
+ return -1;
+ }
+ }
+ /* handle the requests that do not return data */
+ else {
+
+
+ /*dbg_ep0(3, "Host-to-Device"); */
+ switch (request->bRequest) {
+
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ dbg_ep0 (0, "Host-to-Device");
+ switch (request->
+ bmRequestType & USB_REQ_RECIPIENT_MASK) {
+ case USB_REQ_RECIPIENT_DEVICE:
+ /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
+ /* XXX fall through for now as we do not support either */
+ case USB_REQ_RECIPIENT_INTERFACE:
+ case USB_REQ_RECIPIENT_OTHER:
+ dbg_ep0 (0, "request %s not",
+ USBD_DEVICE_REQUESTS (request->bRequest));
+ default:
+ return -1;
+
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
+ if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
+ /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
+ /* request->bRequest == USB_REQ_SET_FEATURE); */
+ /* NEED TO IMPLEMENT THIS!!! */
+ return -1;
+ } else {
+ dbg_ep0 (1, "request %s bad wValue: %04x",
+ USBD_DEVICE_REQUESTS
+ (request->bRequest),
+ le16_to_cpu (request->wValue));
+ return -1;
+ }
+ }
+
+ case USB_REQ_SET_ADDRESS:
+ /* check if this is a re-address, reset first if it is (this shouldn't be possible) */
+ if (device->device_state != STATE_DEFAULT) {
+ dbg_ep0 (1, "set_address: %02x state: %s",
+ le16_to_cpu (request->wValue),
+ usbd_device_states[device->device_state]);
+ return -1;
+ }
+ address = le16_to_cpu (request->wValue);
+ if ((address & 0x7f) != address) {
+ dbg_ep0 (1, "invalid address %04x %04x",
+ address, address & 0x7f);
+ return -1;
+ }
+ device->address = address;
+
+ /*dbg_ep0(2, "address: %d %d %d", */
+ /* request->wValue, le16_to_cpu(request->wValue), device->address); */
+
+ return 0;
+
+ case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
+ dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
+ return -1;
+
+ case USB_REQ_SET_CONFIGURATION:
+ /* c.f. 9.4.7 - the top half of wValue is reserved */
+ device->configuration = le16_to_cpu(request->wValue) & 0xff;
+
+ /* reset interface and alternate settings */
+ device->interface = device->alternate = 0;
+
+ /*dbg_ep0(2, "set configuration: %d", device->configuration); */
+ /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */
+ return 0;
+
+ case USB_REQ_SET_INTERFACE:
+ device->interface = le16_to_cpu (request->wIndex);
+ device->alternate = le16_to_cpu (request->wValue);
+ /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
+ serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
+ return 0;
+
+ case USB_REQ_GET_STATUS:
+ case USB_REQ_GET_DESCRIPTOR:
+ case USB_REQ_GET_CONFIGURATION:
+ case USB_REQ_GET_INTERFACE:
+ case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
+ return -1;
+ }
+ }
+ return -1;
+}
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usbd/ep0.c
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ * Stuart Lynne <sl@lineo.com>,
+ * Tom Rushworth <tbr@lineo.com>,
+ * Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __USBDCORE_EP0_H__
+#define __USBDCORE_EP0_H__
+
+
+int ep0_recv_setup (struct urb *urb);
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit
+ * bodonoghue@CodeHermit.ie
+ *
+ * References
+ * DasUBoot/drivers/usb/gadget/omap1510_udc.c, for design and implementation
+ * ideas.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * Notes :
+ * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX
+ * packet to force the USB re-transmit protocol.
+ *
+ * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console
+ * be careful that tracing doesn't create Hiesen-bugs with respect to
+ * response timeouts to control requests.
+ *
+ * 3. This driver should be able to support any higher level driver that
+ * that wants to do either of the two standard UDC implementations
+ * Control-Bulk-Interrupt or Bulk-IN/Bulk-Out standards. Hence
+ * gserial and cdc_acm should work with this code.
+ *
+ * 4. NAK events never actually get raised at all, the documentation
+ * is just wrong !
+ *
+ * 5. For some reason, cbd_datlen is *always* +2 the value it should be.
+ * this means that having an RX cbd of 16 bytes is not possible, since
+ * the same size is reported for 14 bytes received as 16 bytes received
+ * until we can find out why this happens, RX cbds must be limited to 8
+ * bytes. TODO: check errata for this behaviour.
+ *
+ * 6. Right now this code doesn't support properly powering up with the USB
+ * cable attached to the USB host my development board the Adder87x doesn't
+ * have a pull-up fitted to allow this, so it is necessary to power the
+ * board and *then* attached the USB cable to the host. However somebody
+ * with a different design in their board may be able to keep the cable
+ * constantly connected and simply enable/disable a pull-up re
+ * figure 31.1 in MPC885RM.pdf instead of having to power up the board and
+ * then attach the cable !
+ *
+ */
+#include <common.h>
+#include <config.h>
+#include <commproc.h>
+#include <usbdevice.h>
+#include <usb/mpc8xx_udc.h>
+
+#include "ep0.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ERR(fmt, args...)\
+ serial_printf("ERROR : [%s] %s:%d: "fmt,\
+ __FILE__,__FUNCTION__,__LINE__, ##args)
+#ifdef __DEBUG_UDC__
+#define DBG(fmt,args...)\
+ serial_printf("[%s] %s:%d: "fmt,\
+ __FILE__,__FUNCTION__,__LINE__, ##args)
+#else
+#define DBG(fmt,args...)
+#endif
+
+/* Static Data */
+#ifdef __SIMULATE_ERROR__
+static char err_poison_test = 0;
+#endif
+static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];
+static u32 address_base = STATE_NOT_READY;
+static mpc8xx_udc_state_t udc_state = 0;
+static struct usb_device_instance *udc_device = 0;
+static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];
+static volatile cbd_t *tx_cbd[TX_RING_SIZE];
+static volatile cbd_t *rx_cbd[RX_RING_SIZE];
+static volatile immap_t *immr = 0;
+static volatile cpm8xx_t *cp = 0;
+static volatile usb_pram_t *usb_paramp = 0;
+static volatile usb_t *usbp = 0;
+static int rx_ct = 0;
+static int tx_ct = 0;
+
+/* Static Function Declarations */
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+ usb_device_state_t final);
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+ usb_device_state_t final);
+static void mpc8xx_udc_stall (unsigned int ep);
+static void mpc8xx_udc_flush_tx_fifo (int epid);
+static void mpc8xx_udc_flush_rx_fifo (void);
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
+ struct urb *tx_urb);
+static void mpc8xx_udc_dump_request (struct usb_device_request *request);
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+ volatile cpm8xx_t * cp);
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_cbd_init (void);
+static void mpc8xx_udc_endpoint_init (void);
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_set_nak (unsigned int ep);
+static short mpc8xx_udc_handle_txerr (void);
+static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid);
+
+/******************************************************************************
+ Global Linkage
+ *****************************************************************************/
+
+/* udc_init
+ *
+ * Do initial bus gluing
+ */
+int udc_init (void)
+{
+ /* Init various pointers */
+ immr = (immap_t *) CONFIG_SYS_IMMR;
+ cp = (cpm8xx_t *) & (immr->im_cpm);
+ usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]);
+ usbp = (usb_t *) & (cp->cp_scc[0]);
+
+ memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS));
+
+ udc_device = 0;
+ udc_state = STATE_NOT_READY;
+
+ usbp->usmod = 0x00;
+ usbp->uscom = 0;
+
+ /* Set USB Frame #0, Respond at Address & Get a clock source */
+ usbp->usaddr = 0x00;
+ mpc8xx_udc_clock_init (immr, cp);
+
+ /* PA15, PA14 as perhiperal USBRXD and USBOE */
+ immr->im_ioport.iop_padir &= ~0x0003;
+ immr->im_ioport.iop_papar |= 0x0003;
+
+ /* PC11/PC10 as peripheral USBRXP USBRXN */
+ immr->im_ioport.iop_pcso |= 0x0030;
+
+ /* PC7/PC6 as perhiperal USBTXP and USBTXN */
+ immr->im_ioport.iop_pcdir |= 0x0300;
+ immr->im_ioport.iop_pcpar |= 0x0300;
+
+ /* Set the base address */
+ address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE);
+
+ /* Initialise endpoints and circular buffers */
+ mpc8xx_udc_endpoint_init ();
+ mpc8xx_udc_cbd_init ();
+
+ /* Assign allocated Dual Port Endpoint descriptors */
+ usb_paramp->ep0ptr = (u32) endpoints[0];
+ usb_paramp->ep1ptr = (u32) endpoints[1];
+ usb_paramp->ep2ptr = (u32) endpoints[2];
+ usb_paramp->ep3ptr = (u32) endpoints[3];
+ usb_paramp->frame_n = 0;
+
+ DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",
+ usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,
+ usb_paramp->ep3ptr);
+
+ return 0;
+}
+
+/* udc_irq
+ *
+ * Poll for whatever events may have occured
+ */
+void udc_irq (void)
+{
+ int epid = 0;
+ volatile cbd_t *rx_cbdp = 0;
+ volatile cbd_t *rx_cbdp_base = 0;
+
+ if (udc_state != STATE_READY) {
+ return;
+ }
+
+ if (usbp->usber & USB_E_BSY) {
+ /* This shouldn't happen. If it does then it's a bug ! */
+ usbp->usber |= USB_E_BSY;
+ mpc8xx_udc_flush_rx_fifo ();
+ }
+
+ /* Scan all RX/Bidirectional Endpoints for RX data. */
+ for (epid = 0; epid < MAX_ENDPOINTS; epid++) {
+ if (!ep_ref[epid].prx) {
+ continue;
+ }
+ rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;
+
+ do {
+ if (!(rx_cbdp->cbd_sc & RX_BD_E)) {
+
+ if (rx_cbdp->cbd_sc & 0x1F) {
+ /* Corrupt data discard it.
+ * Controller has NAK'd this packet.
+ */
+ mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+ } else {
+ if (!epid) {
+ mpc8xx_udc_ep0_rx (rx_cbdp);
+
+ } else {
+ /* Process data */
+ mpc8xx_udc_set_nak (epid);
+ mpc8xx_udc_epn_rx (epid, rx_cbdp);
+ mpc8xx_udc_clear_rxbd (rx_cbdp);
+ }
+ }
+
+ /* Advance RX CBD pointer */
+ mpc8xx_udc_advance_rx (&rx_cbdp, epid);
+ ep_ref[epid].prx = rx_cbdp;
+ } else {
+ /* Advance RX CBD pointer */
+ mpc8xx_udc_advance_rx (&rx_cbdp, epid);
+ }
+
+ } while (rx_cbdp != rx_cbdp_base);
+ }
+
+ /* Handle TX events as appropiate, the correct place to do this is
+ * in a tx routine. Perhaps TX on epn was pre-empted by ep0
+ */
+
+ if (usbp->usber & USB_E_TXB) {
+ usbp->usber |= USB_E_TXB;
+ }
+
+ if (usbp->usber & (USB_TX_ERRMASK)) {
+ mpc8xx_udc_handle_txerr ();
+ }
+
+ /* Switch to the default state, respond at the default address */
+ if (usbp->usber & USB_E_RESET) {
+ usbp->usber |= USB_E_RESET;
+ usbp->usaddr = 0x00;
+ udc_device->device_state = STATE_DEFAULT;
+ }
+
+ /* if(usbp->usber&USB_E_IDLE){
+ We could suspend here !
+ usbp->usber|=USB_E_IDLE;
+ DBG("idle state change\n");
+ }
+ if(usbp->usbs){
+ We could resume here when IDLE is deasserted !
+ Not worth doing, so long as we are self powered though.
+ }
+ */
+
+ return;
+}
+
+/* udc_endpoint_write
+ *
+ * Write some data to an endpoint
+ */
+int udc_endpoint_write (struct usb_endpoint_instance *epi)
+{
+ int ep = 0;
+ short epid = 1, unnak = 0, ret = 0;
+
+ if (udc_state != STATE_READY) {
+ ERR ("invalid udc_state != STATE_READY!\n");
+ return -1;
+ }
+
+ if (!udc_device || !epi) {
+ return -1;
+ }
+
+ if (udc_device->device_state != STATE_CONFIGURED) {
+ return -1;
+ }
+
+ ep = epi->endpoint_address & 0x03;
+ if (ep >= MAX_ENDPOINTS) {
+ return -1;
+ }
+
+ /* Set NAK for all RX endpoints during TX */
+ for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
+
+ /* Don't set NAK on DATA IN/CONTROL endpoints */
+ if (ep_ref[epid].sc & USB_DIR_IN) {
+ continue;
+ }
+
+ if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) {
+ unnak |= 1 << epid;
+ }
+
+ mpc8xx_udc_set_nak (epid);
+ }
+
+ mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep],
+ epi->tx_urb);
+ ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]);
+
+ /* Remove temporary NAK */
+ for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
+ if (unnak & (1 << epid)) {
+ udc_unset_nak (epid);
+ }
+ }
+
+ return ret;
+}
+
+/* mpc8xx_udc_assign_urb
+ *
+ * Associate a given urb to an endpoint TX or RX transmit/receive buffers
+ */
+static int mpc8xx_udc_assign_urb (int ep, char direction)
+{
+ struct usb_endpoint_instance *epi = 0;
+
+ if (ep >= MAX_ENDPOINTS) {
+ goto err;
+ }
+ epi = &udc_device->bus->endpoint_array[ep];
+ if (!epi) {
+ goto err;
+ }
+
+ if (!ep_ref[ep].urb) {
+ ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array);
+ if (!ep_ref[ep].urb) {
+ goto err;
+ }
+ } else {
+ ep_ref[ep].urb->actual_length = 0;
+ }
+
+ switch (direction) {
+ case USB_DIR_IN:
+ epi->tx_urb = ep_ref[ep].urb;
+ break;
+ case USB_DIR_OUT:
+ epi->rcv_urb = ep_ref[ep].urb;
+ break;
+ default:
+ goto err;
+ }
+ return 0;
+
+ err:
+ udc_state = STATE_ERROR;
+ return -1;
+}
+
+/* udc_setup_ep
+ *
+ * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram
+ * Isochronous endpoints aren't yet supported!
+ */
+void udc_setup_ep (struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *epi)
+{
+ uchar direction = 0;
+ int ep_attrib = 0;
+
+ if (epi && (ep < MAX_ENDPOINTS)) {
+
+ if (ep == 0) {
+ if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL
+ || epi->tx_attributes !=
+ USB_ENDPOINT_XFER_CONTROL) {
+
+ /* ep0 must be a control endpoint */
+ udc_state = STATE_ERROR;
+ return;
+
+ }
+ if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+ mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize,
+ epi->rcv_packetSize);
+ }
+ usbp->usep[ep] = 0x0000;
+ return;
+ }
+
+ if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) {
+
+ direction = 1;
+ ep_attrib = epi->tx_attributes;
+ epi->rcv_packetSize = 0;
+ ep_ref[ep].sc |= USB_DIR_IN;
+ } else {
+
+ direction = 0;
+ ep_attrib = epi->rcv_attributes;
+ epi->tx_packetSize = 0;
+ ep_ref[ep].sc &= ~USB_DIR_IN;
+ }
+
+ if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address
+ & USB_ENDPOINT_DIR_MASK)) {
+ return;
+ }
+
+ switch (ep_attrib) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+ mpc8xx_udc_cbd_attach (ep,
+ epi->tx_packetSize,
+ epi->rcv_packetSize);
+ }
+ usbp->usep[ep] = ep << 12;
+ epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;
+
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+ if (direction) {
+ mpc8xx_udc_cbd_attach (ep,
+ epi->tx_packetSize,
+ 0);
+ } else {
+ mpc8xx_udc_cbd_attach (ep,
+ 0,
+ epi->rcv_packetSize);
+ }
+ }
+ usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8);
+
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ default:
+ serial_printf ("Error endpoint attrib %d>3\n", ep_attrib);
+ udc_state = STATE_ERROR;
+ break;
+ }
+ }
+
+}
+
+/* udc_connect
+ *
+ * Move state, switch on the USB
+ */
+void udc_connect (void)
+{
+ /* Enable pull-up resistor on D+
+ * TODO: fit a pull-up resistor to drive SE0 for > 2.5us
+ */
+
+ if (udc_state != STATE_ERROR) {
+ udc_state = STATE_READY;
+ usbp->usmod |= USMOD_EN;
+ }
+}
+
+/* udc_disconnect
+ *
+ * Disconnect is not used but, is included for completeness
+ */
+void udc_disconnect (void)
+{
+ /* Disable pull-up resistor on D-
+ * TODO: fix a pullup resistor to control this
+ */
+
+ if (udc_state != STATE_ERROR) {
+ udc_state = STATE_NOT_READY;
+ }
+ usbp->usmod &= ~USMOD_EN;
+}
+
+/* udc_enable
+ *
+ * Grab an EP0 URB, register interest in a subset of USB events
+ */
+void udc_enable (struct usb_device_instance *device)
+{
+ if (udc_state == STATE_ERROR) {
+ return;
+ }
+
+ udc_device = device;
+
+ if (!ep_ref[0].urb) {
+ ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array);
+ }
+
+ /* Register interest in all events except SOF, enable transceiver */
+ usbp->usber = 0x03FF;
+ usbp->usbmr = 0x02F7;
+
+ return;
+}
+
+/* udc_disable
+ *
+ * disable the currently hooked device
+ */
+void udc_disable (void)
+{
+ int i = 0;
+
+ if (udc_state == STATE_ERROR) {
+ DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n");
+ return;
+ }
+
+ udc_device = 0;
+
+ for (; i < MAX_ENDPOINTS; i++) {
+ if (ep_ref[i].urb) {
+ usbd_dealloc_urb (ep_ref[i].urb);
+ ep_ref[i].urb = 0;
+ }
+ }
+
+ usbp->usbmr = 0x00;
+ usbp->usmod = ~USMOD_EN;
+ udc_state = STATE_NOT_READY;
+}
+
+/* udc_startup_events
+ *
+ * Enable the specified device
+ */
+void udc_startup_events (struct usb_device_instance *device)
+{
+ udc_enable (device);
+ if (udc_state == STATE_READY) {
+ usbd_device_event_irq (device, DEVICE_CREATE, 0);
+ }
+}
+
+/* udc_set_nak
+ *
+ * Allow upper layers to signal lower layers should not accept more RX data
+ *
+ */
+void udc_set_nak (int epid)
+{
+ if (epid) {
+ mpc8xx_udc_set_nak (epid);
+ }
+}
+
+/* udc_unset_nak
+ *
+ * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
+ * Switch off NAKing on this endpoint to accept more data output from host.
+ *
+ */
+void udc_unset_nak (int epid)
+{
+ if (epid > MAX_ENDPOINTS) {
+ return;
+ }
+
+ if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) {
+ usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK);
+ __asm__ ("eieio");
+ }
+}
+
+/******************************************************************************
+ Static Linkage
+******************************************************************************/
+
+/* udc_state_transition_up
+ * udc_state_transition_down
+ *
+ * Helper functions to implement device state changes. The device states and
+ * the events that transition between them are:
+ *
+ * STATE_ATTACHED
+ * || /\
+ * \/ ||
+ * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET
+ * || /\
+ * \/ ||
+ * STATE_POWERED
+ * || /\
+ * \/ ||
+ * DEVICE_RESET DEVICE_POWER_INTERRUPTION
+ * || /\
+ * \/ ||
+ * STATE_DEFAULT
+ * || /\
+ * \/ ||
+ * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET
+ * || /\
+ * \/ ||
+ * STATE_ADDRESSED
+ * || /\
+ * \/ ||
+ * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED
+ * || /\
+ * \/ ||
+ * STATE_CONFIGURED
+ *
+ * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way. If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition_down transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ */
+
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+ usb_device_state_t final)
+{
+ if (initial < final) {
+ switch (initial) {
+ case STATE_ATTACHED:
+ usbd_device_event_irq (udc_device,
+ DEVICE_HUB_CONFIGURED, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq (udc_device,
+ DEVICE_ADDRESS_ASSIGNED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
+ 0);
+ case STATE_CONFIGURED:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+ usb_device_state_t final)
+{
+ if (initial > final) {
+ switch (initial) {
+ case STATE_CONFIGURED:
+ usbd_device_event_irq (udc_device,
+ DEVICE_DE_CONFIGURED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq (udc_device,
+ DEVICE_POWER_INTERRUPTION, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq (udc_device, DEVICE_HUB_RESET,
+ 0);
+ case STATE_ATTACHED:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* mpc8xx_udc_stall
+ *
+ * Force returning of STALL tokens on the given endpoint. Protocol or function
+ * STALL conditions are permissable here
+ */
+static void mpc8xx_udc_stall (unsigned int ep)
+{
+ usbp->usep[ep] |= STALL_BITMASK;
+}
+
+/* mpc8xx_udc_set_nak
+ *
+ * Force returning of NAK responses for the given endpoint as a kind of very
+ * simple flow control
+ */
+static void mpc8xx_udc_set_nak (unsigned int ep)
+{
+ usbp->usep[ep] |= NAK_BITMASK;
+ __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_handle_txerr
+ *
+ * Handle errors relevant to TX. Return a status code to allow calling
+ * indicative of what if anything happened
+ */
+static short mpc8xx_udc_handle_txerr ()
+{
+ short ep = 0, ret = 0;
+
+ for (; ep < TX_RING_SIZE; ep++) {
+ if (usbp->usber & (0x10 << ep)) {
+
+ /* Timeout or underrun */
+ if (tx_cbd[ep]->cbd_sc & 0x06) {
+ ret = 1;
+ mpc8xx_udc_flush_tx_fifo (ep);
+
+ } else {
+ if (usbp->usep[ep] & STALL_BITMASK) {
+ if (!ep) {
+ usbp->usep[ep] &= ~STALL_BITMASK;
+ }
+ } /* else NAK */
+ }
+ usbp->usber |= (0x10 << ep);
+ }
+ }
+ return ret;
+}
+
+/* mpc8xx_udc_advance_rx
+ *
+ * Advance cbd rx
+ */
+static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid)
+{
+ if ((*rx_cbdp)->cbd_sc & RX_BD_W) {
+ *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CONFIG_SYS_IMMR);
+
+ } else {
+ (*rx_cbdp)++;
+ }
+}
+
+
+/* mpc8xx_udc_flush_tx_fifo
+ *
+ * Flush a given TX fifo. Assumes one tx cbd per endpoint
+ */
+static void mpc8xx_udc_flush_tx_fifo (int epid)
+{
+ volatile cbd_t *tx_cbdp = 0;
+
+ if (epid > MAX_ENDPOINTS) {
+ return;
+ }
+
+ /* TX stop */
+ immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01);
+ __asm__ ("eieio");
+ while (immr->im_cpm.cp_cpcr & 0x01);
+
+ usbp->uscom = 0x40 | 0;
+
+ /* reset ring */
+ tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CONFIG_SYS_IMMR);
+ tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
+
+
+ endpoints[epid]->tptr = endpoints[epid]->tbase;
+ endpoints[epid]->tstate = 0x00;
+ endpoints[epid]->tbcnt = 0x00;
+
+ /* TX start */
+ immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01);
+ __asm__ ("eieio");
+ while (immr->im_cpm.cp_cpcr & 0x01);
+
+ return;
+}
+
+/* mpc8xx_udc_flush_rx_fifo
+ *
+ * For the sake of completeness of the namespace, it seems like
+ * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo();
+ * If RX_BD_E is true => a driver bug either here or in an upper layer
+ * not polling frequently enough. If RX_BD_E is true we have told the host
+ * we have accepted data but, the CPM found it had no-where to put that data
+ * which needless to say would be a bad thing.
+ */
+static void mpc8xx_udc_flush_rx_fifo ()
+{
+ int i = 0;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
+ ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n",
+ rx_cbd[i], rx_cbd[i]->cbd_datlen,
+ rx_cbd[i]->cbd_sc);
+
+ }
+ }
+ ERR ("BUG : Input over-run\n");
+}
+
+/* mpc8xx_udc_clear_rxbd
+ *
+ * Release control of RX CBD to CP.
+ */
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp)
+{
+ rx_cbdp->cbd_datlen = 0x0000;
+ rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I));
+ __asm__ ("eieio");
+}
+
+/* mpc8xx_udc_tx_irq
+ *
+ * Parse for tx timeout, control RX or USB reset/busy conditions
+ * Return -1 on timeout, -2 on fatal error, else return zero
+ */
+static int mpc8xx_udc_tx_irq (int ep)
+{
+ int i = 0;
+
+ if (usbp->usber & (USB_TX_ERRMASK)) {
+ if (mpc8xx_udc_handle_txerr ()) {
+ /* Timeout, controlling function must retry send */
+ return -1;
+ }
+ }
+
+ if (usbp->usber & (USB_E_RESET | USB_E_BSY)) {
+ /* Fatal, abandon TX transaction */
+ return -2;
+ }
+
+ if (usbp->usber & USB_E_RXB) {
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
+ if ((rx_cbd[i] == ep_ref[0].prx) || ep) {
+ return -2;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* mpc8xx_udc_ep_tx
+ *
+ * Transmit in a re-entrant fashion outbound USB packets.
+ * Implement retry/timeout mechanism described in USB specification
+ * Toggle DATA0/DATA1 pids as necessary
+ * Introduces non-standard tx_retry. The USB standard has no scope for slave
+ * devices to give up TX, however tx_retry stops us getting stuck in an endless
+ * TX loop.
+ */
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
+{
+ struct urb *urb = epi->tx_urb;
+ volatile cbd_t *tx_cbdp = 0;
+ unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0;
+ int ret = 0;
+
+ if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) {
+ return -1;
+ }
+
+ ep = epi->endpoint_address & 0x03;
+ tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
+
+ if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) {
+ mpc8xx_udc_flush_tx_fifo (ep);
+ usbp->usber |= USB_E_TXB;
+ };
+
+ while (tx_retry++ < 100) {
+ ret = mpc8xx_udc_tx_irq (ep);
+ if (ret == -1) {
+ /* ignore timeout here */
+ } else if (ret == -2) {
+ /* Abandon TX */
+ mpc8xx_udc_flush_tx_fifo (ep);
+ return -1;
+ }
+
+ tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
+ while (tx_cbdp->cbd_sc & TX_BD_R) {
+ };
+ tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W);
+
+ pkt_len = urb->actual_length - epi->sent;
+
+ if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) {
+ pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT);
+ }
+
+ for (x = 0; x < pkt_len; x++) {
+ *((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) =
+ urb->buffer[epi->sent + x];
+ }
+ tx_cbdp->cbd_datlen = pkt_len;
+ tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid);
+ __asm__ ("eieio");
+
+#ifdef __SIMULATE_ERROR__
+ if (++err_poison_test == 2) {
+ err_poison_test = 0;
+ tx_cbdp->cbd_sc &= ~TX_BD_TC;
+ }
+#endif
+
+ usbp->uscom = (USCOM_STR | ep);
+
+ while (!(usbp->usber & USB_E_TXB)) {
+ ret = mpc8xx_udc_tx_irq (ep);
+ if (ret == -1) {
+ /* TX timeout */
+ break;
+ } else if (ret == -2) {
+ if (usbp->usber & USB_E_TXB) {
+ usbp->usber |= USB_E_TXB;
+ }
+ mpc8xx_udc_flush_tx_fifo (ep);
+ return -1;
+ }
+ };
+
+ if (usbp->usber & USB_E_TXB) {
+ usbp->usber |= USB_E_TXB;
+ }
+
+ /* ACK must be present <= 18bit times from TX */
+ if (ret == -1) {
+ continue;
+ }
+
+ /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
+ epi->sent += pkt_len;
+ epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize);
+ TOGGLE_TX_PID (ep_ref[ep].pid);
+
+ if (epi->sent >= epi->tx_urb->actual_length) {
+
+ epi->tx_urb->actual_length = 0;
+ epi->sent = 0;
+
+ if (ep_ref[ep].sc & EP_SEND_ZLP) {
+ ep_ref[ep].sc &= ~EP_SEND_ZLP;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent,
+ epi->tx_urb->actual_length);
+
+ return -1;
+}
+
+/* mpc8xx_udc_dump_request
+ *
+ * Dump a control request to console
+ */
+static void mpc8xx_udc_dump_request (struct usb_device_request *request)
+{
+ DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x "
+ "wIndex:%04x wLength:%04x ?\n",
+ request->bmRequestType,
+ request->bRequest,
+ request->wValue, request->wIndex, request->wLength);
+
+ return;
+}
+
+/* mpc8xx_udc_ep0_rx_setup
+ *
+ * Decode received ep0 SETUP packet. return non-zero on error
+ */
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp)
+{
+ unsigned int x = 0;
+ struct urb *purb = ep_ref[0].urb;
+ struct usb_endpoint_instance *epi =
+ &udc_device->bus->endpoint_array[0];
+
+ for (; x < rx_cbdp->cbd_datlen; x++) {
+ *(((unsigned char *) &ep_ref[0].urb->device_request) + x) =
+ *((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
+ }
+
+ mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+ if (ep0_recv_setup (purb)) {
+ mpc8xx_udc_dump_request (&purb->device_request);
+ return -1;
+ }
+
+ if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+ == USB_REQ_HOST2DEVICE) {
+
+ switch (purb->device_request.bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ /* Send the Status OUT ZLP */
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ purb->actual_length = 0;
+ mpc8xx_udc_init_tx (epi, purb);
+ mpc8xx_udc_ep_tx (epi);
+
+ /* Move to the addressed state */
+ usbp->usaddr = udc_device->address;
+ mpc8xx_udc_state_transition_up (udc_device->device_state,
+ STATE_ADDRESSED);
+ return 0;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (!purb->device_request.wValue) {
+ /* Respond at default address */
+ usbp->usaddr = 0x00;
+ mpc8xx_udc_state_transition_down (udc_device->device_state,
+ STATE_ADDRESSED);
+ } else {
+ /* TODO: Support multiple configurations */
+ mpc8xx_udc_state_transition_up (udc_device->device_state,
+ STATE_CONFIGURED);
+ for (x = 1; x < MAX_ENDPOINTS; x++) {
+ if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) {
+ ep_ref[x].pid = TX_BD_PID_DATA0;
+ } else {
+ ep_ref[x].pid = RX_BD_PID_DATA0;
+ }
+ /* Set configuration must unstall endpoints */
+ usbp->usep[x] &= ~STALL_BITMASK;
+ }
+ }
+ break;
+ default:
+ /* CDC/Vendor specific */
+ break;
+ }
+
+ /* Send ZLP as ACK in Status OUT phase */
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ purb->actual_length = 0;
+ mpc8xx_udc_init_tx (epi, purb);
+ mpc8xx_udc_ep_tx (epi);
+
+ } else {
+
+ if (purb->actual_length) {
+ ep_ref[0].pid = TX_BD_PID_DATA1;
+ mpc8xx_udc_init_tx (epi, purb);
+
+ if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) {
+ ep_ref[0].sc |= EP_SEND_ZLP;
+ }
+
+ if (purb->device_request.wValue ==
+ USB_DESCRIPTOR_TYPE_DEVICE) {
+ if (le16_to_cpu (purb->device_request.wLength)
+ > purb->actual_length) {
+ /* Send EP0_MAX_PACKET_SIZE bytes
+ * unless correct size requested.
+ */
+ if (purb->actual_length > epi->tx_packetSize) {
+ purb->actual_length = epi->tx_packetSize;
+ }
+ }
+ }
+ mpc8xx_udc_ep_tx (epi);
+
+ } else {
+ /* Corrupt SETUP packet? */
+ ERR ("Zero length data or SETUP with DATA-IN phase ?\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* mpc8xx_udc_init_tx
+ *
+ * Setup some basic parameters for a TX transaction
+ */
+static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
+ struct urb *tx_urb)
+{
+ epi->sent = 0;
+ epi->last = 0;
+ epi->tx_urb = tx_urb;
+}
+
+/* mpc8xx_udc_ep0_rx
+ *
+ * Receive ep0/control USB data. Parse and possibly send a response.
+ */
+static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp)
+{
+ if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) {
+
+ /* Unconditionally accept SETUP packets */
+ if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) {
+ mpc8xx_udc_stall (0);
+ }
+
+ } else {
+
+ mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+ if ((rx_cbdp->cbd_datlen - 2)) {
+ /* SETUP with a DATA phase
+ * outside of SETUP packet.
+ * Reply with STALL.
+ */
+ mpc8xx_udc_stall (0);
+ }
+ }
+}
+
+/* mpc8xx_udc_epn_rx
+ *
+ * Receive some data from cbd into USB system urb data abstraction
+ * Upper layers should NAK if there is insufficient RX data space
+ */
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp)
+{
+ struct usb_endpoint_instance *epi = 0;
+ struct urb *urb = 0;
+ unsigned int x = 0;
+
+ if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) {
+ return 0;
+ }
+
+ /* USB 2.0 PDF section 8.6.4
+ * Discard data with invalid PID it is a resend.
+ */
+ if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) {
+ return 1;
+ }
+ TOGGLE_RX_PID (ep_ref[epid].pid);
+
+ epi = &udc_device->bus->endpoint_array[epid];
+ urb = epi->rcv_urb;
+
+ for (; x < (rx_cbdp->cbd_datlen - 2); x++) {
+ *((unsigned char *) (urb->buffer + urb->actual_length + x)) =
+ *((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
+ }
+
+ if (x) {
+ usbd_rcv_complete (epi, x, 0);
+ if (ep_ref[epid].urb->status == RECV_ERROR) {
+ DBG ("RX error unset NAK\n");
+ udc_unset_nak (epid);
+ }
+ }
+ return x;
+}
+
+/* mpc8xx_udc_clock_init
+ *
+ * Obtain a clock reference for Full Speed Signaling
+ */
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+ volatile cpm8xx_t * cp)
+{
+
+#if defined(CONFIG_SYS_USB_EXTC_CLK)
+
+ /* This has been tested with a 48MHz crystal on CLK6 */
+ switch (CONFIG_SYS_USB_EXTC_CLK) {
+ case 1:
+ immr->im_ioport.iop_papar |= 0x0100;
+ immr->im_ioport.iop_padir &= ~0x0100;
+ cp->cp_sicr |= 0x24;
+ break;
+ case 2:
+ immr->im_ioport.iop_papar |= 0x0200;
+ immr->im_ioport.iop_padir &= ~0x0200;
+ cp->cp_sicr |= 0x2D;
+ break;
+ case 3:
+ immr->im_ioport.iop_papar |= 0x0400;
+ immr->im_ioport.iop_padir &= ~0x0400;
+ cp->cp_sicr |= 0x36;
+ break;
+ case 4:
+ immr->im_ioport.iop_papar |= 0x0800;
+ immr->im_ioport.iop_padir &= ~0x0800;
+ cp->cp_sicr |= 0x3F;
+ break;
+ default:
+ udc_state = STATE_ERROR;
+ break;
+ }
+
+#elif defined(CONFIG_SYS_USB_BRGCLK)
+
+ /* This has been tested with brgclk == 50MHz */
+ int divisor = 0;
+
+ if (gd->cpu_clk < 48000000L) {
+ ERR ("brgclk is too slow for full-speed USB!\n");
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48MHz)
+ * but, can /probably/ live with close-ish alternative rates.
+ */
+ divisor = (gd->cpu_clk / 48000000L) - 1;
+ cp->cp_sicr &= ~0x0000003F;
+
+ switch (CONFIG_SYS_USB_BRGCLK) {
+ case 1:
+ cp->cp_brgc1 |= (divisor | CPM_BRG_EN);
+ cp->cp_sicr &= ~0x2F;
+ break;
+ case 2:
+ cp->cp_brgc2 |= (divisor | CPM_BRG_EN);
+ cp->cp_sicr |= 0x00000009;
+ break;
+ case 3:
+ cp->cp_brgc3 |= (divisor | CPM_BRG_EN);
+ cp->cp_sicr |= 0x00000012;
+ break;
+ case 4:
+ cp->cp_brgc4 = (divisor | CPM_BRG_EN);
+ cp->cp_sicr |= 0x0000001B;
+ break;
+ default:
+ udc_state = STATE_ERROR;
+ break;
+ }
+
+#else
+#error "CONFIG_SYS_USB_EXTC_CLK or CONFIG_SYS_USB_BRGCLK must be defined"
+#endif
+
+}
+
+/* mpc8xx_udc_cbd_attach
+ *
+ * attach a cbd to and endpoint
+ */
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size)
+{
+
+ if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) {
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT ||
+ (!tx_size && !rx_size)) {
+ udc_state = STATE_ERROR;
+ return;
+ }
+
+ /* Attach CBD to appropiate Parameter RAM Endpoint data structure */
+ if (rx_size) {
+ endpoints[ep]->rbase = (u32) rx_cbd[rx_ct];
+ endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+ rx_ct++;
+
+ if (!ep) {
+
+ endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+ rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+ rx_ct++;
+
+ } else {
+ rx_ct += 2;
+ endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+ rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+ rx_ct++;
+ }
+
+ /* Where we expect to RX data on this endpoint */
+ ep_ref[ep].prx = rx_cbd[rx_ct - 1];
+ } else {
+
+ ep_ref[ep].prx = 0;
+ endpoints[ep]->rbase = 0;
+ endpoints[ep]->rbptr = 0;
+ }
+
+ if (tx_size) {
+ endpoints[ep]->tbase = (u32) tx_cbd[tx_ct];
+ endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct];
+ tx_ct++;
+ } else {
+ endpoints[ep]->tbase = 0;
+ endpoints[ep]->tbptr = 0;
+ }
+
+ endpoints[ep]->tstate = 0;
+ endpoints[ep]->tbcnt = 0;
+ endpoints[ep]->mrblr = EP_MAX_PKT;
+ endpoints[ep]->rfcr = 0x18;
+ endpoints[ep]->tfcr = 0x18;
+ ep_ref[ep].sc |= EP_ATTACHED;
+
+ DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n",
+ ep, endpoints[ep]->rbase, endpoints[ep]->rbptr,
+ endpoints[ep]->tbase, endpoints[ep]->tbptr,
+ ep_ref[ep].prx);
+
+ return;
+}
+
+/* mpc8xx_udc_cbd_init
+ *
+ * Allocate space for a cbd and allocate TX/RX data space
+ */
+static void mpc8xx_udc_cbd_init (void)
+{
+ int i = 0;
+
+ for (; i < TX_RING_SIZE; i++) {
+ tx_cbd[i] = (cbd_t *)
+ mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
+ }
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ rx_cbd[i] = (cbd_t *)
+ mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
+ }
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ tx_cbd[i]->cbd_bufaddr =
+ mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
+
+ tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W);
+ tx_cbd[i]->cbd_datlen = 0x0000;
+ }
+
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ rx_cbd[i]->cbd_bufaddr =
+ mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
+ rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E);
+ rx_cbd[i]->cbd_datlen = 0x0000;
+
+ }
+
+ return;
+}
+
+/* mpc8xx_udc_endpoint_init
+ *
+ * Attach an endpoint to some dpram
+ */
+static void mpc8xx_udc_endpoint_init (void)
+{
+ int i = 0;
+
+ for (; i < MAX_ENDPOINTS; i++) {
+ endpoints[i] = (usb_epb_t *)
+ mpc8xx_udc_alloc (sizeof (usb_epb_t), 32);
+ }
+}
+
+/* mpc8xx_udc_alloc
+ *
+ * Grab the address of some dpram
+ */
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
+{
+ u32 retaddr = address_base;
+
+ while (retaddr % alignment) {
+ retaddr++;
+ }
+ address_base += data_size;
+
+ return retaddr;
+}
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usb/device/bi/omap.c
+ * TI OMAP1510 USB bus interface driver
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ * (C) Copyright 2002
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#ifdef CONFIG_OMAP_SX1
+#include <i2c.h>
+#endif
+#include <usbdevice.h>
+#include <usb/omap1510_udc.h>
+
+#include "ep0.h"
+
+
+#define UDC_INIT_MDELAY 80 /* Device settle delay */
+#define UDC_MAX_ENDPOINTS 31 /* Number of endpoints on this UDC */
+
+/* Some kind of debugging output... */
+#if 1
+#define UDCDBG(str)
+#define UDCDBGA(fmt,args...)
+#else /* The bugs still exists... */
+#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)
+#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)
+#endif
+
+#if 1
+#define UDCREG(name)
+#define UDCREGL(name)
+#else /* The bugs still exists... */
+#define UDCREG(name) serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name)) /* For 16-bit regs */
+#define UDCREGL(name) serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name)) /* For 32-bit regs */
+#endif
+
+
+static struct urb *ep0_urb = NULL;
+
+static struct usb_device_instance *udc_device; /* Used in interrupt handler */
+static u16 udc_devstat = 0; /* UDC status (DEVSTAT) */
+static u32 udc_interrupts = 0;
+
+static void udc_stall_ep (unsigned int ep_addr);
+
+
+static struct usb_endpoint_instance *omap1510_find_ep (int ep)
+{
+ int i;
+
+ for (i = 0; i < udc_device->bus->max_endpoints; i++) {
+ if (udc_device->bus->endpoint_array[i].endpoint_address == ep)
+ return &udc_device->bus->endpoint_array[i];
+ }
+ return NULL;
+}
+
+/* ************************************************************************** */
+/* IO
+ */
+
+/*
+ * omap1510_prepare_endpoint_for_rx
+ *
+ * This function implements TRM Figure 14-11.
+ *
+ * The endpoint to prepare for transfer is specified as a physical endpoint
+ * number. For OUT (rx) endpoints 1 through 15, the corresponding endpoint
+ * configuration register is checked to see if the endpoint is ISO or not.
+ * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.
+ * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
+ */
+static void omap1510_prepare_endpoint_for_rx (int ep_addr)
+{
+ int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+ UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr);
+ if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) {
+ if ((inw (UDC_EP_RX (ep_num)) &
+ (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) ==
+ UDC_EPn_RX_Valid) {
+ /* rx endpoint is valid, non-ISO, so enable its FIFO */
+ outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ outw (0, UDC_EP_NUM);
+ }
+ }
+}
+
+/* omap1510_configure_endpoints
+ *
+ * This function implements TRM Figure 14-10.
+ */
+static void omap1510_configure_endpoints (struct usb_device_instance *device)
+{
+ int ep;
+ struct usb_bus_instance *bus;
+ struct usb_endpoint_instance *endpoint;
+ unsigned short ep_ptr;
+ unsigned short ep_size;
+ unsigned short ep_isoc;
+ unsigned short ep_doublebuffer;
+ int ep_addr;
+ int packet_size;
+ int buffer_size;
+ int attributes;
+
+ bus = device->bus;
+
+ /* There is a dedicated 2048 byte buffer for USB packets that may be
+ * arbitrarily partitioned among the endpoints on 8-byte boundaries.
+ * The first 8 bytes are reserved for receiving setup packets on
+ * endpoint 0.
+ */
+ ep_ptr = 8; /* reserve the first 8 bytes for the setup fifo */
+
+ for (ep = 0; ep < bus->max_endpoints; ep++) {
+ endpoint = bus->endpoint_array + ep;
+ ep_addr = endpoint->endpoint_address;
+ if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ /* IN endpoint */
+ packet_size = endpoint->tx_packetSize;
+ attributes = endpoint->tx_attributes;
+ } else {
+ /* OUT endpoint */
+ packet_size = endpoint->rcv_packetSize;
+ attributes = endpoint->rcv_attributes;
+ }
+
+ switch (packet_size) {
+ case 0:
+ ep_size = 0;
+ break;
+ case 8:
+ ep_size = 0;
+ break;
+ case 16:
+ ep_size = 1;
+ break;
+ case 32:
+ ep_size = 2;
+ break;
+ case 64:
+ ep_size = 3;
+ break;
+ case 128:
+ ep_size = 4;
+ break;
+ case 256:
+ ep_size = 5;
+ break;
+ case 512:
+ ep_size = 6;
+ break;
+ default:
+ UDCDBGA ("ep 0x%02x has bad packet size %d",
+ ep_addr, packet_size);
+ packet_size = 0;
+ ep_size = 0;
+ break;
+ }
+
+ switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ default:
+ /* A non-isochronous endpoint may optionally be
+ * double-buffered. For now we disable
+ * double-buffering.
+ */
+ ep_doublebuffer = 0;
+ ep_isoc = 0;
+ if (packet_size > 64)
+ packet_size = 0;
+ if (!ep || !ep_doublebuffer)
+ buffer_size = packet_size;
+ else
+ buffer_size = packet_size * 2;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* Isochronous endpoints are always double-
+ * buffered, but the double-buffering bit
+ * in the endpoint configuration register
+ * becomes the msb of the endpoint size so we
+ * set the double-buffering flag to zero.
+ */
+ ep_doublebuffer = 0;
+ ep_isoc = 1;
+ buffer_size = packet_size * 2;
+ break;
+ }
+
+ /* check to see if our packet buffer RAM is exhausted */
+ if ((ep_ptr + buffer_size) > 2048) {
+ UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size);
+ buffer_size = packet_size = 0;
+ }
+
+ /* force a default configuration for endpoint 0 since it is
+ * always enabled
+ */
+ if (!ep && ((packet_size < 8) || (packet_size > 64))) {
+ buffer_size = packet_size = 64;
+ ep_size = 3;
+ }
+
+ if (!ep) {
+ /* configure endpoint 0 */
+ outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
+ /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */
+ /* ep_ptr, packet_size); */
+ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ /* IN endpoint */
+ if (packet_size) {
+ outw ((1 << 15) | (ep_doublebuffer << 14) |
+ (ep_size << 12) | (ep_isoc << 11) |
+ (ep_ptr >> 3),
+ UDC_EP_TX (ep_addr &
+ USB_ENDPOINT_NUMBER_MASK));
+ UDCDBGA ("IN ep %d buffer offset 0x%03x"
+ " packet size 0x%03x",
+ ep_addr & USB_ENDPOINT_NUMBER_MASK,
+ ep_ptr, packet_size);
+ } else {
+ outw (0,
+ UDC_EP_TX (ep_addr &
+ USB_ENDPOINT_NUMBER_MASK));
+ }
+ } else {
+ /* OUT endpoint */
+ if (packet_size) {
+ outw ((1 << 15) | (ep_doublebuffer << 14) |
+ (ep_size << 12) | (ep_isoc << 11) |
+ (ep_ptr >> 3),
+ UDC_EP_RX (ep_addr &
+ USB_ENDPOINT_NUMBER_MASK));
+ UDCDBGA ("OUT ep %d buffer offset 0x%03x"
+ " packet size 0x%03x",
+ ep_addr & USB_ENDPOINT_NUMBER_MASK,
+ ep_ptr, packet_size);
+ } else {
+ outw (0,
+ UDC_EP_RX (ep_addr &
+ USB_ENDPOINT_NUMBER_MASK));
+ }
+ }
+ ep_ptr += buffer_size;
+ }
+}
+
+/* omap1510_deconfigure_device
+ *
+ * This function balances omap1510_configure_device.
+ */
+static void omap1510_deconfigure_device (void)
+{
+ int epnum;
+
+ UDCDBG ("clear Cfg_Lock");
+ outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
+ UDCREG (UDC_SYSCON1);
+
+ /* deconfigure all endpoints */
+ for (epnum = 1; epnum <= 15; epnum++) {
+ outw (0, UDC_EP_RX (epnum));
+ outw (0, UDC_EP_TX (epnum));
+ }
+}
+
+/* omap1510_configure_device
+ *
+ * This function implements TRM Figure 14-9.
+ */
+static void omap1510_configure_device (struct usb_device_instance *device)
+{
+ omap1510_configure_endpoints (device);
+
+
+ /* Figure 14-9 indicates we should enable interrupts here, but we have
+ * other routines (udc_all_interrupts, udc_suspended_interrupts) to
+ * do that.
+ */
+
+ UDCDBG ("set Cfg_Lock");
+ outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
+ UDCREG (UDC_SYSCON1);
+}
+
+/* omap1510_write_noniso_tx_fifo
+ *
+ * This function implements TRM Figure 14-30.
+ *
+ * If the endpoint has an active tx_urb, then the next packet of data from the
+ * URB is written to the tx FIFO. The total amount of data in the urb is given
+ * by urb->actual_length. The maximum amount of data that can be sent in any
+ * one packet is given by endpoint->tx_packetSize. The number of data bytes
+ * from this URB that have already been transmitted is given by endpoint->sent.
+ * endpoint->last is updated by this routine with the number of data bytes
+ * transmitted in this packet.
+ *
+ * In accordance with Figure 14-30, the EP_NUM register must already have been
+ * written with the value to select the appropriate tx FIFO before this routine
+ * is called.
+ */
+static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance
+ *endpoint)
+{
+ struct urb *urb = endpoint->tx_urb;
+
+ if (urb) {
+ unsigned int last, i;
+
+ UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d",
+ urb->buffer, urb->buffer_length, urb->actual_length);
+ if ((last =
+ MIN (urb->actual_length - endpoint->sent,
+ endpoint->tx_packetSize))) {
+ u8 *cp = urb->buffer + endpoint->sent;
+
+ UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last);
+
+ if (((u32) cp & 1) == 0) { /* word aligned? */
+ outsw (UDC_DATA, cp, last >> 1);
+ } else { /* byte aligned. */
+ for (i = 0; i < (last >> 1); i++) {
+ u16 w = ((u16) cp[2 * i + 1] << 8) |
+ (u16) cp[2 * i];
+ outw (w, UDC_DATA);
+ }
+ }
+ if (last & 1) {
+ outb (*(cp + last - 1), UDC_DATA);
+ }
+ }
+ endpoint->last = last;
+ }
+}
+
+/* omap1510_read_noniso_rx_fifo
+ *
+ * This function implements TRM Figure 14-28.
+ *
+ * If the endpoint has an active rcv_urb, then the next packet of data is read
+ * from the rcv FIFO and written to rcv_urb->buffer at offset
+ * rcv_urb->actual_length to append the packet data to the data from any
+ * previous packets for this transfer. We assume that there is sufficient room
+ * left in the buffer to hold an entire packet of data.
+ *
+ * The return value is the number of bytes read from the FIFO for this packet.
+ *
+ * In accordance with Figure 14-28, the EP_NUM register must already have been
+ * written with the value to select the appropriate rcv FIFO before this routine
+ * is called.
+ */
+static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance
+ *endpoint)
+{
+ struct urb *urb = endpoint->rcv_urb;
+ int len = 0;
+
+ if (urb) {
+ len = inw (UDC_RXFSTAT);
+
+ if (len) {
+ unsigned char *cp = urb->buffer + urb->actual_length;
+
+ insw (UDC_DATA, cp, len >> 1);
+ if (len & 1)
+ *(cp + len - 1) = inb (UDC_DATA);
+ }
+ }
+ return len;
+}
+
+/* omap1510_prepare_for_control_write_status
+ *
+ * This function implements TRM Figure 14-17.
+ *
+ * We have to deal here with non-autodecoded control writes that haven't already
+ * been dealt with by ep0_recv_setup. The non-autodecoded standard control
+ * write requests are: set/clear endpoint feature, set configuration, set
+ * interface, and set descriptor. ep0_recv_setup handles set/clear requests for
+ * ENDPOINT_HALT by halting the endpoint for a set request and resetting the
+ * endpoint for a clear request. ep0_recv_setup returns an error for
+ * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
+ * the setup handler. A SET_INTERFACE request is handled by ep0_recv_setup by
+ * generating a DEVICE_SET_INTERFACE event. This leaves only the
+ * SET_CONFIGURATION event for us to deal with here.
+ *
+ */
+static void omap1510_prepare_for_control_write_status (struct urb *urb)
+{
+ struct usb_device_request *request = &urb->device_request;;
+
+ /* check for a SET_CONFIGURATION request */
+ if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
+ int configuration = le16_to_cpu (request->wValue) & 0xff;
+ unsigned short devstat = inw (UDC_DEVSTAT);
+
+ if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
+ /* device is currently in ADDRESSED state */
+ if (configuration) {
+ /* Assume the specified non-zero configuration
+ * value is valid and switch to the CONFIGURED
+ * state.
+ */
+ outw (UDC_Dev_Cfg, UDC_SYSCON2);
+ }
+ } else if ((devstat & UDC_CFG) == UDC_CFG) {
+ /* device is currently in CONFIGURED state */
+ if (!configuration) {
+ /* Switch to ADDRESSED state. */
+ outw (UDC_Clr_Cfg, UDC_SYSCON2);
+ }
+ }
+ }
+
+ /* select EP0 tx FIFO */
+ outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+ /* clear endpoint (no data bytes in status stage) */
+ outw (UDC_Clr_EP, UDC_CTRL);
+ /* enable the EP0 tx FIFO */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ /* deselect the endpoint */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+}
+
+/* udc_state_transition_up
+ * udc_state_transition_down
+ *
+ * Helper functions to implement device state changes. The device states and
+ * the events that transition between them are:
+ *
+ * STATE_ATTACHED
+ * || /\
+ * \/ ||
+ * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET
+ * || /\
+ * \/ ||
+ * STATE_POWERED
+ * || /\
+ * \/ ||
+ * DEVICE_RESET DEVICE_POWER_INTERRUPTION
+ * || /\
+ * \/ ||
+ * STATE_DEFAULT
+ * || /\
+ * \/ ||
+ * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET
+ * || /\
+ * \/ ||
+ * STATE_ADDRESSED
+ * || /\
+ * \/ ||
+ * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED
+ * || /\
+ * \/ ||
+ * STATE_CONFIGURED
+ *
+ * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way. If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition_down transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ * These functions must only be called with interrupts disabled.
+ */
+static void udc_state_transition_up (usb_device_state_t initial,
+ usb_device_state_t final)
+{
+ if (initial < final) {
+ switch (initial) {
+ case STATE_ATTACHED:
+ usbd_device_event_irq (udc_device,
+ DEVICE_HUB_CONFIGURED, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq (udc_device,
+ DEVICE_ADDRESS_ASSIGNED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
+ 0);
+ case STATE_CONFIGURED:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void udc_state_transition_down (usb_device_state_t initial,
+ usb_device_state_t final)
+{
+ if (initial > final) {
+ switch (initial) {
+ case STATE_CONFIGURED:
+ usbd_device_event_irq (udc_device, DEVICE_DE_CONFIGURED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq (udc_device, DEVICE_POWER_INTERRUPTION, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, 0);
+ case STATE_ATTACHED:
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Handle all device state changes.
+ * This function implements TRM Figure 14-21.
+ */
+static void omap1510_udc_state_changed (void)
+{
+ u16 bits;
+ u16 devstat = inw (UDC_DEVSTAT);
+
+ UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat);
+
+ bits = devstat ^ udc_devstat;
+ if (bits) {
+ if (bits & UDC_ATT) {
+ if (devstat & UDC_ATT) {
+ UDCDBG ("device attached and powered");
+ udc_state_transition_up (udc_device->device_state, STATE_POWERED);
+ } else {
+ UDCDBG ("device detached or unpowered");
+ udc_state_transition_down (udc_device->device_state, STATE_ATTACHED);
+ }
+ }
+ if (bits & UDC_USB_Reset) {
+ if (devstat & UDC_USB_Reset) {
+ UDCDBG ("device reset in progess");
+ udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+ } else {
+ UDCDBG ("device reset completed");
+ }
+ }
+ if (bits & UDC_DEF) {
+ if (devstat & UDC_DEF) {
+ UDCDBG ("device entering default state");
+ udc_state_transition_up (udc_device->device_state, STATE_DEFAULT);
+ } else {
+ UDCDBG ("device leaving default state");
+ udc_state_transition_down (udc_device->device_state, STATE_POWERED);
+ }
+ }
+ if (bits & UDC_SUS) {
+ if (devstat & UDC_SUS) {
+ UDCDBG ("entering suspended state");
+ usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0);
+ } else {
+ UDCDBG ("leaving suspended state");
+ usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0);
+ }
+ }
+ if (bits & UDC_R_WK_OK) {
+ UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK)
+ ? "enabled" : "disabled");
+ }
+ if (bits & UDC_ADD) {
+ if (devstat & UDC_ADD) {
+ UDCDBG ("default -> addressed");
+ udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED);
+ } else {
+ UDCDBG ("addressed -> default");
+ udc_state_transition_down (udc_device->device_state, STATE_DEFAULT);
+ }
+ }
+ if (bits & UDC_CFG) {
+ if (devstat & UDC_CFG) {
+ UDCDBG ("device configured");
+ /* The ep0_recv_setup function generates the
+ * DEVICE_CONFIGURED event when a
+ * USB_REQ_SET_CONFIGURATION setup packet is
+ * received, so we should already be in the
+ * state STATE_CONFIGURED.
+ */
+ udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED);
+ } else {
+ UDCDBG ("device deconfigured");
+ udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED);
+ }
+ }
+ }
+
+ /* Clear interrupt source */
+ outw (UDC_DS_Chg, UDC_IRQ_SRC);
+
+ /* Save current DEVSTAT */
+ udc_devstat = devstat;
+}
+
+/* Handle SETUP USB interrupt.
+ * This function implements TRM Figure 14-14.
+ */
+static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
+{
+ UDCDBG ("-> Entering device setup");
+
+ do {
+ const int setup_pktsize = 8;
+ unsigned char *datap =
+ (unsigned char *) &ep0_urb->device_request;
+
+ /* Gain access to EP 0 setup FIFO */
+ outw (UDC_Setup_Sel, UDC_EP_NUM);
+
+ /* Read control request data */
+ insb (UDC_DATA, datap, setup_pktsize);
+
+ UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]",
+ *(datap + 0), *(datap + 1), *(datap + 2),
+ *(datap + 3), *(datap + 4), *(datap + 5),
+ *(datap + 6), *(datap + 7));
+
+ /* Reset EP0 setup FIFO */
+ outw (0, UDC_EP_NUM);
+ } while (inw (UDC_IRQ_SRC) & UDC_Setup);
+
+ /* Try to process setup packet */
+ if (ep0_recv_setup (ep0_urb)) {
+ /* Not a setup packet, stall next EP0 transaction */
+ udc_stall_ep (0);
+ UDCDBG ("can't parse setup packet, still waiting for setup");
+ return;
+ }
+
+ /* Check direction */
+ if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+ == USB_REQ_HOST2DEVICE) {
+ UDCDBG ("control write on EP0");
+ if (le16_to_cpu (ep0_urb->device_request.wLength)) {
+ /* We don't support control write data stages.
+ * The only standard control write request with a data
+ * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
+ * support that so we just stall those requests. A
+ * function driver might support a non-standard
+ * write request with a data stage, but it isn't
+ * obvious what we would do with the data if we read it
+ * so we'll just stall it. It seems like the API isn't
+ * quite right here.
+ */
+#if 0
+ /* Here is what we would do if we did support control
+ * write data stages.
+ */
+ ep0_urb->actual_length = 0;
+ outw (0, UDC_EP_NUM);
+ /* enable the EP0 rx FIFO */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+#else
+ /* Stall this request */
+ UDCDBG ("Stalling unsupported EP0 control write data "
+ "stage.");
+ udc_stall_ep (0);
+#endif
+ } else {
+ omap1510_prepare_for_control_write_status (ep0_urb);
+ }
+ } else {
+ UDCDBG ("control read on EP0");
+ /* The ep0_recv_setup function has already placed our response
+ * packet data in ep0_urb->buffer and the packet length in
+ * ep0_urb->actual_length.
+ */
+ endpoint->tx_urb = ep0_urb;
+ endpoint->sent = 0;
+ /* select the EP0 tx FIFO */
+ outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+ /* Write packet data to the FIFO. omap1510_write_noniso_tx_fifo
+ * will update endpoint->last with the number of bytes written
+ * to the FIFO.
+ */
+ omap1510_write_noniso_tx_fifo (endpoint);
+ /* enable the FIFO to start the packet transmission */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ /* deselect the EP0 tx FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ }
+
+ UDCDBG ("<- Leaving device setup");
+}
+
+/* Handle endpoint 0 RX interrupt
+ * This routine implements TRM Figure 14-16.
+ */
+static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint)
+{
+ unsigned short status;
+
+ UDCDBG ("RX on EP0");
+ /* select EP0 rx FIFO */
+ outw (UDC_EP_Sel, UDC_EP_NUM);
+
+ status = inw (UDC_STAT_FLG);
+
+ if (status & UDC_ACK) {
+ /* Check direction */
+ if ((ep0_urb->device_request.bmRequestType
+ & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
+ /* This rx interrupt must be for a control write data
+ * stage packet.
+ *
+ * We don't support control write data stages.
+ * We should never end up here.
+ */
+
+ /* clear the EP0 rx FIFO */
+ outw (UDC_Clr_EP, UDC_CTRL);
+
+ /* deselect the EP0 rx FIFO */
+ outw (0, UDC_EP_NUM);
+
+ UDCDBG ("Stalling unexpected EP0 control write "
+ "data stage packet");
+ udc_stall_ep (0);
+ } else {
+ /* This rx interrupt must be for a control read status
+ * stage packet.
+ */
+ UDCDBG ("ACK on EP0 control read status stage packet");
+ /* deselect EP0 rx FIFO */
+ outw (0, UDC_EP_NUM);
+ }
+ } else if (status & UDC_STALL) {
+ UDCDBG ("EP0 stall during RX");
+ /* deselect EP0 rx FIFO */
+ outw (0, UDC_EP_NUM);
+ } else {
+ /* deselect EP0 rx FIFO */
+ outw (0, UDC_EP_NUM);
+ }
+}
+
+/* Handle endpoint 0 TX interrupt
+ * This routine implements TRM Figure 14-18.
+ */
+static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint)
+{
+ unsigned short status;
+ struct usb_device_request *request = &ep0_urb->device_request;
+
+ UDCDBG ("TX on EP0");
+ /* select EP0 TX FIFO */
+ outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+
+ status = inw (UDC_STAT_FLG);
+ if (status & UDC_ACK) {
+ /* Check direction */
+ if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
+ USB_REQ_HOST2DEVICE) {
+ /* This tx interrupt must be for a control write status
+ * stage packet.
+ */
+ UDCDBG ("ACK on EP0 control write status stage packet");
+ /* deselect EP0 TX FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ } else {
+ /* This tx interrupt must be for a control read data
+ * stage packet.
+ */
+ int wLength = le16_to_cpu (request->wLength);
+
+ /* Update our count of bytes sent so far in this
+ * transfer.
+ */
+ endpoint->sent += endpoint->last;
+
+ /* We are finished with this transfer if we have sent
+ * all of the bytes in our tx urb (urb->actual_length)
+ * unless we need a zero-length terminating packet. We
+ * need a zero-length terminating packet if we returned
+ * fewer bytes than were requested (wLength) by the host,
+ * and the number of bytes we returned is an exact
+ * multiple of the packet size endpoint->tx_packetSize.
+ */
+ if ((endpoint->sent == ep0_urb->actual_length)
+ && ((ep0_urb->actual_length == wLength)
+ || (endpoint->last !=
+ endpoint->tx_packetSize))) {
+ /* Done with control read data stage. */
+ UDCDBG ("control read data stage complete");
+ /* deselect EP0 TX FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ /* select EP0 RX FIFO to prepare for control
+ * read status stage.
+ */
+ outw (UDC_EP_Sel, UDC_EP_NUM);
+ /* clear the EP0 RX FIFO */
+ outw (UDC_Clr_EP, UDC_CTRL);
+ /* enable the EP0 RX FIFO */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ /* deselect the EP0 RX FIFO */
+ outw (0, UDC_EP_NUM);
+ } else {
+ /* We still have another packet of data to send
+ * in this control read data stage or else we
+ * need a zero-length terminating packet.
+ */
+ UDCDBG ("ACK control read data stage packet");
+ omap1510_write_noniso_tx_fifo (endpoint);
+ /* enable the EP0 tx FIFO to start transmission */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ /* deselect EP0 TX FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ }
+ }
+ } else if (status & UDC_STALL) {
+ UDCDBG ("EP0 stall during TX");
+ /* deselect EP0 TX FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ } else {
+ /* deselect EP0 TX FIFO */
+ outw (UDC_EP_Dir, UDC_EP_NUM);
+ }
+}
+
+/* Handle RX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-27.
+ * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
+ * in the range 1 to 15.
+ */
+static void omap1510_udc_epn_rx (int ep)
+{
+ unsigned short status;
+
+ /* Check endpoint status */
+ status = inw (UDC_STAT_FLG);
+
+ if (status & UDC_ACK) {
+ int nbytes;
+ struct usb_endpoint_instance *endpoint =
+ omap1510_find_ep (ep);
+
+ nbytes = omap1510_read_noniso_rx_fifo (endpoint);
+ usbd_rcv_complete (endpoint, nbytes, 0);
+
+ /* enable rx FIFO to prepare for next packet */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ } else if (status & UDC_STALL) {
+ UDCDBGA ("STALL on RX endpoint %d", ep);
+ } else if (status & UDC_NAK) {
+ UDCDBGA ("NAK on RX ep %d", ep);
+ } else {
+ serial_printf ("omap-bi: RX on ep %d with status %x", ep,
+ status);
+ }
+}
+
+/* Handle TX transaction on non-ISO endpoint.
+ * This function implements TRM Figure 14-29.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void omap1510_udc_epn_tx (int ep)
+{
+ unsigned short status;
+
+ /*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */
+
+ /* Check endpoint status */
+ status = inw (UDC_STAT_FLG);
+
+ if (status & UDC_ACK) {
+ struct usb_endpoint_instance *endpoint =
+ omap1510_find_ep (ep);
+
+ /* We need to transmit a terminating zero-length packet now if
+ * we have sent all of the data in this URB and the transfer
+ * size was an exact multiple of the packet size.
+ */
+ if (endpoint->tx_urb
+ && (endpoint->last == endpoint->tx_packetSize)
+ && (endpoint->tx_urb->actual_length - endpoint->sent -
+ endpoint->last == 0)) {
+ /* Prepare to transmit a zero-length packet. */
+ endpoint->sent += endpoint->last;
+ /* write 0 bytes of data to FIFO */
+ omap1510_write_noniso_tx_fifo (endpoint);
+ /* enable tx FIFO to start transmission */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ } else if (endpoint->tx_urb
+ && endpoint->tx_urb->actual_length) {
+ /* retire the data that was just sent */
+ usbd_tx_complete (endpoint);
+ /* Check to see if we have more data ready to transmit
+ * now.
+ */
+ if (endpoint->tx_urb
+ && endpoint->tx_urb->actual_length) {
+ /* write data to FIFO */
+ omap1510_write_noniso_tx_fifo (endpoint);
+ /* enable tx FIFO to start transmission */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ }
+ }
+ } else if (status & UDC_STALL) {
+ UDCDBGA ("STALL on TX endpoint %d", ep);
+ } else if (status & UDC_NAK) {
+ UDCDBGA ("NAK on TX endpoint %d", ep);
+ } else {
+ /*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */
+ }
+}
+
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+/* Handle general USB interrupts and dispatch according to type.
+ * This function implements TRM Figure 14-13.
+ */
+void omap1510_udc_irq (void)
+{
+ u16 irq_src = inw (UDC_IRQ_SRC);
+ int valid_irq = 0;
+
+ if (!(irq_src & ~UDC_SOF_Flg)) /* ignore SOF interrupts ) */
+ return;
+
+ UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src);
+ /*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */
+
+ if (irq_src & UDC_DS_Chg) {
+ /* Device status changed */
+ omap1510_udc_state_changed ();
+ valid_irq++;
+ }
+ if (irq_src & UDC_EP0_RX) {
+ /* Endpoint 0 receive */
+ outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */
+ omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0);
+ valid_irq++;
+ }
+ if (irq_src & UDC_EP0_TX) {
+ /* Endpoint 0 transmit */
+ outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */
+ omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0);
+ valid_irq++;
+ }
+ if (irq_src & UDC_Setup) {
+ /* Device setup */
+ omap1510_udc_setup (udc_device->bus->endpoint_array + 0);
+ valid_irq++;
+ }
+ /*if (!valid_irq) */
+ /* serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */
+ UDCDBGA ("< IRQ #%d end >", udc_interrupts);
+ udc_interrupts++;
+}
+
+/* This function implements TRM Figure 14-26. */
+void omap1510_udc_noniso_irq (void)
+{
+ unsigned short epnum;
+ unsigned short irq_src = inw (UDC_IRQ_SRC);
+ int valid_irq = 0;
+
+ if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX)))
+ return;
+
+ UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC));
+
+ if (irq_src & UDC_EPn_RX) { /* Endpoint N OUT transaction */
+ /* Determine the endpoint number for this interrupt */
+ epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8;
+ UDCDBGA ("RX on ep %x", epnum);
+
+ /* acknowledge interrupt */
+ outw (UDC_EPn_RX, UDC_IRQ_SRC);
+
+ if (epnum) {
+ /* select the endpoint FIFO */
+ outw (UDC_EP_Sel | epnum, UDC_EP_NUM);
+
+ omap1510_udc_epn_rx (epnum);
+
+ /* deselect the endpoint FIFO */
+ outw (epnum, UDC_EP_NUM);
+ }
+ valid_irq++;
+ }
+ if (irq_src & UDC_EPn_TX) { /* Endpoint N IN transaction */
+ /* Determine the endpoint number for this interrupt */
+ epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN;
+ UDCDBGA ("TX on ep %x", epnum);
+
+ /* acknowledge interrupt */
+ outw (UDC_EPn_TX, UDC_IRQ_SRC);
+
+ if (epnum) {
+ /* select the endpoint FIFO */
+ outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+
+ omap1510_udc_epn_tx (epnum);
+
+ /* deselect the endpoint FIFO */
+ outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+ }
+ valid_irq++;
+ }
+ if (!valid_irq)
+ serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n",
+ irq_src);
+}
+
+/*
+-------------------------------------------------------------------------------
+*/
+
+
+/*
+ * Start of public functions.
+ */
+
+/* Called to start packet transmission. */
+int udc_endpoint_write (struct usb_endpoint_instance *endpoint)
+{
+ unsigned short epnum =
+ endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
+
+ UDCDBGA ("Starting transmit on ep %x", epnum);
+
+ if (endpoint->tx_urb) {
+ /* select the endpoint FIFO */
+ outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
+ /* write data to FIFO */
+ omap1510_write_noniso_tx_fifo (endpoint);
+ /* enable tx FIFO to start transmission */
+ outw (UDC_Set_FIFO_En, UDC_CTRL);
+ /* deselect the endpoint FIFO */
+ outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
+ }
+
+ return 0;
+}
+
+/* Start to initialize h/w stuff */
+int udc_init (void)
+{
+ u16 udc_rev;
+ uchar value;
+ ulong gpio;
+ int i;
+
+ /* Let the device settle down before we start */
+ for (i = 0; i < UDC_INIT_MDELAY; i++) udelay(1000);
+
+ udc_device = NULL;
+
+ UDCDBG ("starting");
+
+ /* Check peripheral reset. Must be 1 to make sure
+ MPU TIPB peripheral reset is inactive */
+ UDCREG (ARM_RSTCT2);
+
+ /* Set and check clock control.
+ * We might ought to be using the clock control API to do
+ * this instead of fiddling with the clock registers directly
+ * here.
+ */
+ outw ((1 << 4) | (1 << 5), CLOCK_CTRL);
+ UDCREG (CLOCK_CTRL);
+
+#ifdef CONFIG_OMAP1510
+ /* This code was originally implemented for OMAP1510 and
+ * therefore is only applicable for OMAP1510 boards. For
+ * OMAP5912 or OMAP16xx the register APLL_CTRL does not
+ * exist and DPLL_CTRL is already configured.
+ */
+
+ /* Set and check APLL */
+ outw (0x0008, APLL_CTRL);
+ UDCREG (APLL_CTRL);
+ /* Set and check DPLL */
+ outw (0x2210, DPLL_CTRL);
+ UDCREG (DPLL_CTRL);
+#endif
+ /* Set and check SOFT
+ * The below line of code has been changed to perform a
+ * read-modify-write instead of a simple write for
+ * configuring the SOFT_REQ register. This allows the code
+ * to be compatible with OMAP5912 and OMAP16xx devices
+ */
+ outw ((1 << 4) | (1 << 3) | 1 | (inw(SOFT_REQ)), SOFT_REQ);
+
+ /* Short delay to wait for DPLL */
+ udelay (1000);
+
+ /* Print banner with device revision */
+ udc_rev = inw (UDC_REV) & 0xff;
+#ifdef CONFIG_OMAP1510
+ printf ("USB: TI OMAP1510 USB function module rev %d.%d\n",
+ udc_rev >> 4, udc_rev & 0xf);
+#endif
+
+#ifdef CONFIG_OMAP1610
+ printf ("USB: TI OMAP5912 USB function module rev %d.%d\n",
+ udc_rev >> 4, udc_rev & 0xf);
+#endif
+
+#ifdef CONFIG_OMAP_SX1
+ i2c_read (0x32, 0x04, 1, &value, 1);
+ value |= 0x04;
+ i2c_write (0x32, 0x04, 1, &value, 1);
+
+ i2c_read (0x32, 0x03, 1, &value, 1);
+ value |= 0x01;
+ i2c_write (0x32, 0x03, 1, &value, 1);
+
+ gpio = inl(GPIO_PIN_CONTROL_REG);
+ gpio |= 0x0002; /* A_IRDA_OFF */
+ gpio |= 0x0800; /* A_SWITCH */
+ gpio |= 0x8000; /* A_USB_ON */
+ outl (gpio, GPIO_PIN_CONTROL_REG);
+
+ gpio = inl(GPIO_DIR_CONTROL_REG);
+ gpio &= ~0x0002; /* A_IRDA_OFF */
+ gpio &= ~0x0800; /* A_SWITCH */
+ gpio &= ~0x8000; /* A_USB_ON */
+ outl (gpio, GPIO_DIR_CONTROL_REG);
+
+ gpio = inl(GPIO_DATA_OUTPUT_REG);
+ gpio |= 0x0002; /* A_IRDA_OFF */
+ gpio &= ~0x0800; /* A_SWITCH */
+ gpio &= ~0x8000; /* A_USB_ON */
+ outl (gpio, GPIO_DATA_OUTPUT_REG);
+#endif
+
+ /* The VBUS_MODE bit selects whether VBUS detection is done via
+ * software (1) or hardware (0). When software detection is
+ * selected, VBUS_CTRL selects whether USB is not connected (0)
+ * or connected (1).
+ */
+ outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+ outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+ UDCREGL (FUNC_MUX_CTRL_0);
+
+ /*
+ * At this point, device is ready for configuration...
+ */
+
+ UDCDBG ("disable USB interrupts");
+ outw (0, UDC_IRQ_EN);
+ UDCREG (UDC_IRQ_EN);
+
+ UDCDBG ("disable USB DMA");
+ outw (0, UDC_DMA_IRQ_EN);
+ UDCREG (UDC_DMA_IRQ_EN);
+
+ UDCDBG ("initialize SYSCON1");
+ outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1);
+ UDCREG (UDC_SYSCON1);
+
+ return 0;
+}
+
+/* Stall endpoint */
+static void udc_stall_ep (unsigned int ep_addr)
+{
+ /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+ int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+ UDCDBGA ("stall ep_addr %d", ep_addr);
+
+ /* REVISIT?
+ * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
+ * is empty before halting the endpoint. The current implementation
+ * doesn't check that the FIFO is empty.
+ */
+
+ if (!ep_num) {
+ outw (UDC_Stall_Cmd, UDC_SYSCON2);
+ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+ /* we have a valid rx endpoint, so halt it */
+ outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
+ outw (UDC_Set_Halt, UDC_CTRL);
+ outw (ep_num, UDC_EP_NUM);
+ }
+ } else {
+ if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+ /* we have a valid tx endpoint, so halt it */
+ outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM);
+ outw (UDC_Set_Halt, UDC_CTRL);
+ outw (ep_num, UDC_EP_NUM);
+ }
+ }
+}
+
+/* Reset endpoint */
+#if 0
+static void udc_reset_ep (unsigned int ep_addr)
+{
+ /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+ int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+ UDCDBGA ("reset ep_addr %d", ep_addr);
+
+ if (!ep_num) {
+ /* control endpoint 0 can't be reset */
+ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num,
+ inw (UDC_EP_RX (ep_num)));
+ if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
+ /* we have a valid rx endpoint, so reset it */
+ outw (ep_num | UDC_EP_Sel, UDC_EP_NUM);
+ outw (UDC_Reset_EP, UDC_CTRL);
+ outw (ep_num, UDC_EP_NUM);
+ UDCDBGA ("OUT endpoint %d reset", ep_num);
+ }
+ } else {
+ UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num,
+ inw (UDC_EP_TX (ep_num)));
+ /* Resetting of tx endpoints seems to be causing the USB function
+ * module to fail, which causes problems when the driver is
+ * uninstalled. We'll skip resetting tx endpoints for now until
+ * we figure out what the problem is.
+ */
+#if 0
+ if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
+ /* we have a valid tx endpoint, so reset it */
+ outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
+ outw (UDC_Reset_EP, UDC_CTRL);
+ outw (ep_num | UDC_EP_Dir, UDC_EP_NUM);
+ UDCDBGA ("IN endpoint %d reset", ep_num);
+ }
+#endif
+ }
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_check_ep - check logical endpoint
+ *
+ * Return physical endpoint number to use for this logical endpoint or zero if not valid.
+ */
+#if 0
+int udc_check_ep (int logical_endpoint, int packetsize)
+{
+ if ((logical_endpoint == 0x80) ||
+ ((logical_endpoint & 0x8f) != logical_endpoint)) {
+ return 0;
+ }
+
+ switch (packetsize) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ break;
+ default:
+ return 0;
+ }
+
+ return EP_ADDR_TO_PHYS_EP (logical_endpoint);
+}
+#endif
+
+/*
+ * udc_setup_ep - setup endpoint
+ *
+ * Associate a physical endpoint with endpoint_instance
+ */
+void udc_setup_ep (struct usb_device_instance *device,
+ unsigned int ep, struct usb_endpoint_instance *endpoint)
+{
+ UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address);
+
+ /* This routine gets called by bi_modinit for endpoint 0 and from
+ * bi_config for all of the other endpoints. bi_config gets called
+ * during the DEVICE_CREATE, DEVICE_CONFIGURED, and
+ * DEVICE_SET_INTERFACE events. We need to reconfigure the OMAP packet
+ * RAM after bi_config scans the selected device configuration and
+ * initializes the endpoint structures, but before this routine enables
+ * the OUT endpoint FIFOs. Since bi_config calls this routine in a
+ * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our
+ * packet RAM here when ep==1.
+ * I really hate to do this here, but it seems like the API exported
+ * by the USB bus interface controller driver to the usbd-bi module
+ * isn't quite right so there is no good place to do this.
+ */
+ if (ep == 1) {
+ omap1510_deconfigure_device ();
+ omap1510_configure_device (device);
+ }
+
+ if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
+ int ep_addr = endpoint->endpoint_address;
+
+ if (!ep_addr) {
+ /* nothing to do for endpoint 0 */
+ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ /* nothing to do for IN (tx) endpoints */
+ } else { /* OUT (rx) endpoint */
+ if (endpoint->rcv_packetSize) {
+ /*struct urb* urb = &(urb_out_array[ep&0xFF]); */
+ /*urb->endpoint = endpoint; */
+ /*urb->device = device; */
+ /*urb->buffer_length = sizeof(urb->buffer); */
+
+ /*endpoint->rcv_urb = urb; */
+ omap1510_prepare_endpoint_for_rx (ep_addr);
+ }
+ }
+ }
+}
+
+/**
+ * udc_disable_ep - disable endpoint
+ * @ep:
+ *
+ * Disable specified endpoint
+ */
+#if 0
+void udc_disable_ep (unsigned int ep_addr)
+{
+ /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
+ int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+ struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr); /*udc_device->bus->endpoint_array + ep; */
+
+ UDCDBGA ("disable ep_addr %d", ep_addr);
+
+ if (!ep_num) {
+ /* nothing to do for endpoint 0 */ ;
+ } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ if (endpoint->tx_packetSize) {
+ /* we have a valid tx endpoint */
+ /*usbd_flush_tx(endpoint); */
+ endpoint->tx_urb = NULL;
+ }
+ } else {
+ if (endpoint->rcv_packetSize) {
+ /* we have a valid rx endpoint */
+ /*usbd_flush_rcv(endpoint); */
+ endpoint->rcv_urb = NULL;
+ }
+ }
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_connected - is the USB cable connected
+ *
+ * Return non-zero if cable is connected.
+ */
+#if 0
+int udc_connected (void)
+{
+ return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
+}
+#endif
+
+/* Turn on the USB connection by enabling the pullup resistor */
+void udc_connect (void)
+{
+ UDCDBG ("connect, enable Pullup");
+ outl (0x00000018, FUNC_MUX_CTRL_D);
+}
+
+/* Turn off the USB connection by disabling the pullup resistor */
+void udc_disconnect (void)
+{
+ UDCDBG ("disconnect, disable Pullup");
+ outl (0x00000000, FUNC_MUX_CTRL_D);
+}
+
+/* ************************************************************************** */
+
+
+/*
+ * udc_disable_interrupts - disable interrupts
+ * switch off interrupts
+ */
+#if 0
+void udc_disable_interrupts (struct usb_device_instance *device)
+{
+ UDCDBG ("disabling all interrupts");
+ outw (0, UDC_IRQ_EN);
+}
+#endif
+
+/* ************************************************************************** */
+
+/**
+ * udc_ep0_packetsize - return ep0 packetsize
+ */
+#if 0
+int udc_ep0_packetsize (void)
+{
+ return EP0_PACKETSIZE;
+}
+#endif
+
+/* Switch on the UDC */
+void udc_enable (struct usb_device_instance *device)
+{
+ UDCDBGA ("enable device %p, status %d", device, device->status);
+
+ /* initialize driver state variables */
+ udc_devstat = 0;
+
+ /* Save the device structure pointer */
+ udc_device = device;
+
+ /* Setup ep0 urb */
+ if (!ep0_urb) {
+ ep0_urb =
+ usbd_alloc_urb (udc_device,
+ udc_device->bus->endpoint_array);
+ } else {
+ serial_printf ("udc_enable: ep0_urb already allocated %p\n",
+ ep0_urb);
+ }
+
+ UDCDBG ("Check clock status");
+ UDCREG (STATUS_REQ);
+
+ /* The VBUS_MODE bit selects whether VBUS detection is done via
+ * software (1) or hardware (0). When software detection is
+ * selected, VBUS_CTRL selects whether USB is not connected (0)
+ * or connected (1).
+ */
+ outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
+ FUNC_MUX_CTRL_0);
+ UDCREGL (FUNC_MUX_CTRL_0);
+
+ omap1510_configure_device (device);
+}
+
+/* Switch off the UDC */
+void udc_disable (void)
+{
+ UDCDBG ("disable UDC");
+
+ omap1510_deconfigure_device ();
+
+ /* The VBUS_MODE bit selects whether VBUS detection is done via
+ * software (1) or hardware (0). When software detection is
+ * selected, VBUS_CTRL selects whether USB is not connected (0)
+ * or connected (1).
+ */
+ outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
+ outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
+ UDCREGL (FUNC_MUX_CTRL_0);
+
+ /* Free ep0 URB */
+ if (ep0_urb) {
+ /*usbd_dealloc_urb(ep0_urb); */
+ ep0_urb = NULL;
+ }
+
+ /* Reset device pointer.
+ * We ought to do this here to balance the initialization of udc_device
+ * in udc_enable, but some of our other exported functions get called
+ * by the bus interface driver after udc_disable, so we have to hang on
+ * to the device pointer to avoid a null pointer dereference. */
+ /* udc_device = NULL; */
+}
+
+/**
+ * udc_startup - allow udc code to do any additional startup
+ */
+void udc_startup_events (struct usb_device_instance *device)
+{
+ /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
+ usbd_device_event_irq (device, DEVICE_INIT, 0);
+
+ /* The DEVICE_CREATE event puts the USB device in the state
+ * STATE_ATTACHED.
+ */
+ usbd_device_event_irq (device, DEVICE_CREATE, 0);
+
+ /* Some USB controller driver implementations signal
+ * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
+ * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
+ * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
+ * The OMAP USB client controller has the capability to detect when the
+ * USB cable is connected to a powered USB bus via the ATT bit in the
+ * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
+ * DEVICE_RESET events until later.
+ */
+
+ udc_enable (device);
+}
+
+/**
+ * udc_irq - do pseudo interrupts
+ */
+void udc_irq(void)
+{
+ /* Loop while we have interrupts.
+ * If we don't do this, the input chain
+ * polling delay is likely to miss
+ * host requests.
+ */
+ while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
+ /* Handle any new IRQs */
+ omap1510_udc_irq ();
+ omap1510_udc_noniso_irq ();
+ }
+}
+
+/* Flow control */
+void udc_set_nak(int epid)
+{
+ /* TODO: implement this functionality in omap1510 */
+}
+
+void udc_unset_nak (int epid)
+{
+ /* TODO: implement this functionality in omap1510 */
+}
--- /dev/null
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_host.a
+
+# ohci
+COBJS-$(CONFIG_USB_OHCI_NEW) += ohci-hcd.o
+COBJS-$(CONFIG_USB_ATMEL) += ohci-at91.o
+COBJS-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
+COBJS-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+COBJS-$(CONFIG_USB_S3C64XX) += s3c64xx-hcd.o
+COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o
+
+# echi
+COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o
+COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
+COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
+COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
+COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef USB_EHCI_CORE_H
+#define USB_EHCI_CORE_H
+
+extern int rootdev;
+extern struct ehci_hccr *hccr;
+extern volatile struct ehci_hcor *hcor;
+
+#endif
--- /dev/null
+/*
+ * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
+ *
+ * Author: Tor Krill tor@excito.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <usb.h>
+#include <mpc83xx.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include "ehci.h"
+#include "ehci-fsl.h"
+#include "ehci-core.h"
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ *
+ * Excerpts from linux ehci fsl driver.
+ */
+int ehci_hcd_init(void)
+{
+ volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
+ uint32_t addr, temp;
+
+ addr = (uint32_t)&(im->usb[0]);
+ hccr = (struct ehci_hccr *)(addr + FSL_SKIP_PCI);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ /* Configure clock */
+ clrsetbits_be32(&(im->clk.sccr), MPC83XX_SCCR_USB_MASK,
+ MPC83XX_SCCR_USB_DRCM_11);
+
+ /* Confgure interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp
+ | REFSEL_16MHZ | UTMI_PHY_EN);
+
+ /* Wait for clock to stabilize */
+ do {
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ udelay(1000);
+ } while (!(temp & PHY_CLK_VALID));
+
+ /* Set to Host mode */
+ temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
+ out_le32((void *)(addr + FSL_SOC_USB_USBMODE), temp | CM_HOST);
+
+ out_be32((void *)(addr + FSL_SOC_USB_SNOOP1), SNOOP_SIZE_2GB);
+ out_be32((void *)(addr + FSL_SOC_USB_SNOOP2),
+ 0x80000000 | SNOOP_SIZE_2GB);
+
+ /* Init phy */
+ /* TODO: handle different phys? */
+ out_le32(&(hcor->or_portsc[0]), PORT_PTS_UTMI);
+
+ /* Enable interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
+
+ out_be32((void *)(addr + FSL_SOC_USB_PRICTRL), 0x0000000c);
+ out_be32((void *)(addr + FSL_SOC_USB_AGECNTTHRSH), 0x00000040);
+ out_be32((void *)(addr + FSL_SOC_USB_SICTRL), 0x00000001);
+
+ /* Enable interface. */
+ temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
+ out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
+
+ temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2005 freescale semiconductor
+ * Copyright (c) 2005 MontaVista Software
+ * Copyright (c) 2008 Excito Elektronik i Sk=E5ne AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _EHCI_FSL_H
+#define _EHCI_FSL_H
+
+/* Global offsets */
+#define FSL_SKIP_PCI 0x100
+
+/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ULPIVP 0x170
+#define FSL_SOC_USB_PORTSC1 0x184
+#define PORT_PTS_MSK (3 << 30)
+#define PORT_PTS_UTMI (0 << 30)
+#define PORT_PTS_ULPI (2 << 30)
+#define PORT_PTS_SERIAL (3 << 30)
+#define PORT_PTS_PTW (1 << 28)
+
+/* USBMODE Register bits */
+#define CM_IDLE (0 << 0)
+#define CM_RESERVED (1 << 0)
+#define CM_DEVICE (2 << 0)
+#define CM_HOST (3 << 0)
+#define USBMODE_RESERVED_2 (0 << 2)
+#define SLOM (1 << 3)
+#define SDIS (1 << 4)
+
+/* CONTROL Register bits */
+#define ULPI_INT_EN (1 << 0)
+#define WU_INT_EN (1 << 1)
+#define USB_EN (1 << 2)
+#define LSF_EN (1 << 3)
+#define KEEP_OTG_ON (1 << 4)
+#define OTG_PORT (1 << 5)
+#define REFSEL_12MHZ (0 << 6)
+#define REFSEL_16MHZ (1 << 6)
+#define REFSEL_48MHZ (2 << 6)
+#define PLL_RESET (1 << 8)
+#define UTMI_PHY_EN (1 << 9)
+#define PHY_CLK_SEL_UTMI (0 << 10)
+#define PHY_CLK_SEL_ULPI (1 << 10)
+#define CLKIN_SEL_USB_CLK (0 << 11)
+#define CLKIN_SEL_USB_CLK2 (1 << 11)
+#define CLKIN_SEL_SYS_CLK (2 << 11)
+#define CLKIN_SEL_SYS_CLK2 (3 << 11)
+#define RESERVED_18 (0 << 13)
+#define RESERVED_17 (0 << 14)
+#define RESERVED_16 (0 << 15)
+#define WU_INT (1 << 16)
+#define PHY_CLK_VALID (1 << 17)
+
+#define FSL_SOC_USB_PORTSC2 0x188
+#define FSL_SOC_USB_USBMODE 0x1a8
+#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
+#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
+#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
+#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
+#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
+#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
+#define SNOOP_SIZE_2GB 0x1e
+
+/* System Clock Control Register */
+#define MPC83XX_SCCR_USB_MASK 0x00f00000
+#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
+#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
+#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
+
+#endif /* _EHCI_FSL_H */
--- /dev/null
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Excito Elektronik i Skåne AB
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <asm/byteorder.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+#include "ehci.h"
+
+int rootdev;
+struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
+volatile struct ehci_hcor *hcor;
+
+static uint16_t portreset;
+static struct QH qh_list __attribute__((aligned(32)));
+
+static struct descriptor {
+ struct usb_hub_descriptor hub;
+ struct usb_device_descriptor device;
+ struct usb_linux_config_descriptor config;
+ struct usb_linux_interface_descriptor interface;
+ struct usb_endpoint_descriptor endpoint;
+} __attribute__ ((packed)) descriptor = {
+ {
+ 0x8, /* bDescLength */
+ 0x29, /* bDescriptorType: hub descriptor */
+ 2, /* bNrPorts -- runtime modified */
+ 0, /* wHubCharacteristics */
+ 0xff, /* bPwrOn2PwrGood */
+ 0, /* bHubCntrCurrent */
+ {}, /* Device removable */
+ {} /* at most 7 ports! XXX */
+ },
+ {
+ 0x12, /* bLength */
+ 1, /* bDescriptorType: UDESC_DEVICE */
+ 0x0002, /* bcdUSB: v2.0 */
+ 9, /* bDeviceClass: UDCLASS_HUB */
+ 0, /* bDeviceSubClass: UDSUBCLASS_HUB */
+ 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
+ 64, /* bMaxPacketSize: 64 bytes */
+ 0x0000, /* idVendor */
+ 0x0000, /* idProduct */
+ 0x0001, /* bcdDevice */
+ 1, /* iManufacturer */
+ 2, /* iProduct */
+ 0, /* iSerialNumber */
+ 1 /* bNumConfigurations: 1 */
+ },
+ {
+ 0x9,
+ 2, /* bDescriptorType: UDESC_CONFIG */
+ cpu_to_le16(0x19),
+ 1, /* bNumInterface */
+ 1, /* bConfigurationValue */
+ 0, /* iConfiguration */
+ 0x40, /* bmAttributes: UC_SELF_POWER */
+ 0 /* bMaxPower */
+ },
+ {
+ 0x9, /* bLength */
+ 4, /* bDescriptorType: UDESC_INTERFACE */
+ 0, /* bInterfaceNumber */
+ 0, /* bAlternateSetting */
+ 1, /* bNumEndpoints */
+ 9, /* bInterfaceClass: UICLASS_HUB */
+ 0, /* bInterfaceSubClass: UISUBCLASS_HUB */
+ 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
+ 0 /* iInterface */
+ },
+ {
+ 0x7, /* bLength */
+ 5, /* bDescriptorType: UDESC_ENDPOINT */
+ 0x81, /* bEndpointAddress:
+ * UE_DIR_IN | EHCI_INTR_ENDPT
+ */
+ 3, /* bmAttributes: UE_INTERRUPT */
+ 8, 0, /* wMaxPacketSize */
+ 255 /* bInterval */
+ },
+};
+
+#if defined(CONFIG_EHCI_IS_TDI)
+#define ehci_is_TDI() (1)
+#else
+#define ehci_is_TDI() (0)
+#endif
+
+#if defined(CONFIG_EHCI_DCACHE)
+/*
+ * Routines to handle (flush/invalidate) the dcache for the QH and qTD
+ * structures and data buffers. This is needed on platforms using this
+ * EHCI support with dcache enabled.
+ */
+static void flush_invalidate(u32 addr, int size, int flush)
+{
+ if (flush)
+ flush_dcache_range(addr, addr + size);
+ else
+ invalidate_dcache_range(addr, addr + size);
+}
+
+static void cache_qtd(struct qTD *qtd, int flush)
+{
+ u32 *ptr = (u32 *)qtd->qt_buffer[0];
+ int len = (qtd->qt_token & 0x7fff0000) >> 16;
+
+ flush_invalidate((u32)qtd, sizeof(struct qTD), flush);
+ if (ptr && len)
+ flush_invalidate((u32)ptr, len, flush);
+}
+
+
+static inline struct QH *qh_addr(struct QH *qh)
+{
+ return (struct QH *)((u32)qh & 0xffffffe0);
+}
+
+static void cache_qh(struct QH *qh, int flush)
+{
+ struct qTD *qtd;
+ struct qTD *next;
+ static struct qTD *first_qtd;
+
+ /*
+ * Walk the QH list and flush/invalidate all entries
+ */
+ while (1) {
+ flush_invalidate((u32)qh_addr(qh), sizeof(struct QH), flush);
+ if ((u32)qh & QH_LINK_TYPE_QH)
+ break;
+ qh = qh_addr(qh);
+ qh = (struct QH *)qh->qh_link;
+ }
+ qh = qh_addr(qh);
+
+ /*
+ * Save first qTD pointer, needed for invalidating pass on this QH
+ */
+ if (flush)
+ first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
+ 0xffffffe0);
+ else
+ qtd = first_qtd;
+
+ /*
+ * Walk the qTD list and flush/invalidate all entries
+ */
+ while (1) {
+ if (qtd == NULL)
+ break;
+ cache_qtd(qtd, flush);
+ next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
+ if (next == qtd)
+ break;
+ qtd = next;
+ }
+}
+
+static inline void ehci_flush_dcache(struct QH *qh)
+{
+ cache_qh(qh, 1);
+}
+
+static inline void ehci_invalidate_dcache(struct QH *qh)
+{
+ cache_qh(qh, 0);
+}
+#else /* CONFIG_EHCI_DCACHE */
+/*
+ *
+ */
+static inline void ehci_flush_dcache(struct QH *qh)
+{
+}
+
+static inline void ehci_invalidate_dcache(struct QH *qh)
+{
+}
+#endif /* CONFIG_EHCI_DCACHE */
+
+static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
+{
+ uint32_t result;
+ do {
+ result = ehci_readl(ptr);
+ if (result == ~(uint32_t)0)
+ return -1;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -1;
+}
+
+static void ehci_free(void *p, size_t sz)
+{
+
+}
+
+static int ehci_reset(void)
+{
+ uint32_t cmd;
+ uint32_t tmp;
+ uint32_t *reg_ptr;
+ int ret = 0;
+
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd |= CMD_RESET;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+ ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail to reset\n");
+ goto out;
+ }
+
+ if (ehci_is_TDI()) {
+ reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE);
+ tmp = ehci_readl(reg_ptr);
+ tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+ tmp |= USBMODE_BE;
+#endif
+ ehci_writel(reg_ptr, tmp);
+ }
+out:
+ return ret;
+}
+
+static void *ehci_alloc(size_t sz, size_t align)
+{
+ static struct QH qh __attribute__((aligned(32)));
+ static struct qTD td[3] __attribute__((aligned (32)));
+ static int ntds;
+ void *p;
+
+ switch (sz) {
+ case sizeof(struct QH):
+ p = &qh;
+ ntds = 0;
+ break;
+ case sizeof(struct qTD):
+ if (ntds == 3) {
+ debug("out of TDs\n");
+ return NULL;
+ }
+ p = &td[ntds];
+ ntds++;
+ break;
+ default:
+ debug("unknown allocation size\n");
+ return NULL;
+ }
+
+ memset(p, sz, 0);
+ return p;
+}
+
+static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
+{
+ uint32_t addr, delta, next;
+ int idx;
+
+ addr = (uint32_t) buf;
+ idx = 0;
+ while (idx < 5) {
+ td->qt_buffer[idx] = cpu_to_hc32(addr);
+ next = (addr + 4096) & ~4095;
+ delta = next - addr;
+ if (delta >= sz)
+ break;
+ sz -= delta;
+ addr = next;
+ idx++;
+ }
+
+ if (idx == 5) {
+ debug("out of buffer pointers (%u bytes left)\n", sz);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *req)
+{
+ struct QH *qh;
+ struct qTD *td;
+ volatile struct qTD *vtd;
+ unsigned long ts;
+ uint32_t *tdp;
+ uint32_t endpt, token, usbsts;
+ uint32_t c, toggle;
+ uint32_t cmd;
+ int ret = 0;
+
+ debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
+ buffer, length, req);
+ if (req != NULL)
+ debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
+ req->request, req->request,
+ req->requesttype, req->requesttype,
+ le16_to_cpu(req->value), le16_to_cpu(req->value),
+ le16_to_cpu(req->index));
+
+ qh = ehci_alloc(sizeof(struct QH), 32);
+ if (qh == NULL) {
+ debug("unable to allocate QH\n");
+ return -1;
+ }
+ qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+ c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
+ usb_pipeendpoint(pipe) == 0) ? 1 : 0;
+ endpt = (8 << 28) |
+ (c << 27) |
+ (usb_maxpacket(dev, pipe) << 16) |
+ (0 << 15) |
+ (1 << 14) |
+ (usb_pipespeed(pipe) << 12) |
+ (usb_pipeendpoint(pipe) << 8) |
+ (0 << 7) | (usb_pipedevice(pipe) << 0);
+ qh->qh_endpt1 = cpu_to_hc32(endpt);
+ endpt = (1 << 30) |
+ (dev->portnr << 23) |
+ (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
+ qh->qh_endpt2 = cpu_to_hc32(endpt);
+ qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+
+ td = NULL;
+ tdp = &qh->qh_overlay.qt_next;
+
+ toggle =
+ usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
+
+ if (req != NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate SETUP td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (0 << 31) |
+ (sizeof(*req) << 16) |
+ (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
+ debug("unable construct SETUP td\n");
+ ehci_free(td, sizeof(*td));
+ goto fail;
+ }
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ toggle = 1;
+ }
+
+ if (length > 0 || req == NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate DATA td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (toggle << 31) |
+ (length << 16) |
+ ((req == NULL ? 1 : 0) << 15) |
+ (0 << 12) |
+ (3 << 10) |
+ ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ if (ehci_td_buffer(td, buffer, length) != 0) {
+ debug("unable construct DATA td\n");
+ ehci_free(td, sizeof(*td));
+ goto fail;
+ }
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ }
+
+ if (req != NULL) {
+ td = ehci_alloc(sizeof(struct qTD), 32);
+ if (td == NULL) {
+ debug("unable to allocate ACK td\n");
+ goto fail;
+ }
+ td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ token = (toggle << 31) |
+ (0 << 16) |
+ (1 << 15) |
+ (0 << 12) |
+ (3 << 10) |
+ ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
+ td->qt_token = cpu_to_hc32(token);
+ *tdp = cpu_to_hc32((uint32_t) td);
+ tdp = &td->qt_next;
+ }
+
+ qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
+
+ /* Flush dcache */
+ ehci_flush_dcache(&qh_list);
+
+ usbsts = ehci_readl(&hcor->or_usbsts);
+ ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
+
+ /* Enable async. schedule. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd |= CMD_ASE;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
+ 100 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail timeout STD_ASS set\n");
+ goto fail;
+ }
+
+ /* Wait for TDs to be processed. */
+ ts = get_timer(0);
+ vtd = td;
+ do {
+ /* Invalidate dcache */
+ ehci_invalidate_dcache(&qh_list);
+ token = hc32_to_cpu(vtd->qt_token);
+ if (!(token & 0x80))
+ break;
+ } while (get_timer(ts) < CONFIG_SYS_HZ);
+
+ /* Disable async schedule. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ cmd &= ~CMD_ASE;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
+ 100 * 1000);
+ if (ret < 0) {
+ printf("EHCI fail timeout STD_ASS reset\n");
+ goto fail;
+ }
+
+ qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+
+ token = hc32_to_cpu(qh->qh_overlay.qt_token);
+ if (!(token & 0x80)) {
+ debug("TOKEN=%#x\n", token);
+ switch (token & 0xfc) {
+ case 0:
+ toggle = token >> 31;
+ usb_settoggle(dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), toggle);
+ dev->status = 0;
+ break;
+ case 0x40:
+ dev->status = USB_ST_STALLED;
+ break;
+ case 0xa0:
+ case 0x20:
+ dev->status = USB_ST_BUF_ERR;
+ break;
+ case 0x50:
+ case 0x10:
+ dev->status = USB_ST_BABBLE_DET;
+ break;
+ default:
+ dev->status = USB_ST_CRC_ERR;
+ break;
+ }
+ dev->act_len = length - ((token >> 16) & 0x7fff);
+ } else {
+ dev->act_len = 0;
+ debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
+ dev->devnum, ehci_readl(&hcor->or_usbsts),
+ ehci_readl(&hcor->or_portsc[0]),
+ ehci_readl(&hcor->or_portsc[1]));
+ }
+
+ return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
+
+fail:
+ td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+ while (td != (void *)QT_NEXT_TERMINATE) {
+ qh->qh_overlay.qt_next = td->qt_next;
+ ehci_free(td, sizeof(*td));
+ td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
+ }
+ ehci_free(qh, sizeof(*qh));
+ return -1;
+}
+
+static inline int min3(int a, int b, int c)
+{
+
+ if (b < a)
+ a = b;
+ if (c < a)
+ a = c;
+ return a;
+}
+
+int
+ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *req)
+{
+ uint8_t tmpbuf[4];
+ u16 typeReq;
+ void *srcptr = NULL;
+ int len, srclen;
+ uint32_t reg;
+ uint32_t *status_reg;
+
+ if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ printf("The request port(%d) is not configured\n",
+ le16_to_cpu(req->index) - 1);
+ return -1;
+ }
+ status_reg = (uint32_t *)&hcor->or_portsc[
+ le16_to_cpu(req->index) - 1];
+ srclen = 0;
+
+ debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
+ req->request, req->request,
+ req->requesttype, req->requesttype,
+ le16_to_cpu(req->value), le16_to_cpu(req->index));
+
+ typeReq = req->request << 8 | req->requesttype;
+
+ switch (le16_to_cpu(typeReq)) {
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch (le16_to_cpu(req->value) >> 8) {
+ case USB_DT_DEVICE:
+ debug("USB_DT_DEVICE request\n");
+ srcptr = &descriptor.device;
+ srclen = 0x12;
+ break;
+ case USB_DT_CONFIG:
+ debug("USB_DT_CONFIG config\n");
+ srcptr = &descriptor.config;
+ srclen = 0x19;
+ break;
+ case USB_DT_STRING:
+ debug("USB_DT_STRING config\n");
+ switch (le16_to_cpu(req->value) & 0xff) {
+ case 0: /* Language */
+ srcptr = "\4\3\1\0";
+ srclen = 4;
+ break;
+ case 1: /* Vendor */
+ srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
+ srclen = 14;
+ break;
+ case 2: /* Product */
+ srcptr = "\52\3E\0H\0C\0I\0 "
+ "\0H\0o\0s\0t\0 "
+ "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
+ srclen = 42;
+ break;
+ default:
+ debug("unknown value DT_STRING %x\n",
+ le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ default:
+ debug("unknown value %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
+ switch (le16_to_cpu(req->value) >> 8) {
+ case USB_DT_HUB:
+ debug("USB_DT_HUB config\n");
+ srcptr = &descriptor.hub;
+ srclen = 0x8;
+ break;
+ default:
+ debug("unknown value %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ break;
+ case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
+ debug("USB_REQ_SET_ADDRESS\n");
+ rootdev = le16_to_cpu(req->value);
+ break;
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ debug("USB_REQ_SET_CONFIGURATION\n");
+ /* Nothing to do */
+ break;
+ case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
+ tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
+ tmpbuf[1] = 0;
+ srcptr = tmpbuf;
+ srclen = 2;
+ break;
+ case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+ memset(tmpbuf, 0, 4);
+ reg = ehci_readl(status_reg);
+ if (reg & EHCI_PS_CS)
+ tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
+ if (reg & EHCI_PS_PE)
+ tmpbuf[0] |= USB_PORT_STAT_ENABLE;
+ if (reg & EHCI_PS_SUSP)
+ tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
+ if (reg & EHCI_PS_OCA)
+ tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
+ if (reg & EHCI_PS_PR &&
+ (portreset & (1 << le16_to_cpu(req->index)))) {
+ int ret;
+ /* force reset to complete */
+ reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
+ ehci_writel(status_reg, reg);
+ ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
+ if (!ret)
+ tmpbuf[0] |= USB_PORT_STAT_RESET;
+ else
+ printf("port(%d) reset error\n",
+ le16_to_cpu(req->index) - 1);
+ }
+ if (reg & EHCI_PS_PP)
+ tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
+
+ if (ehci_is_TDI()) {
+ switch ((reg >> 26) & 3) {
+ case 0:
+ break;
+ case 1:
+ tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
+ break;
+ case 2:
+ default:
+ tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+ break;
+ }
+ } else {
+ tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
+ }
+
+ if (reg & EHCI_PS_CSC)
+ tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
+ if (reg & EHCI_PS_PEC)
+ tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
+ if (reg & EHCI_PS_OCC)
+ tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
+ if (portreset & (1 << le16_to_cpu(req->index)))
+ tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+
+ srcptr = tmpbuf;
+ srclen = 4;
+ break;
+ case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ reg = ehci_readl(status_reg);
+ reg &= ~EHCI_PS_CLEAR;
+ switch (le16_to_cpu(req->value)) {
+ case USB_PORT_FEAT_ENABLE:
+ reg |= EHCI_PS_PE;
+ ehci_writel(status_reg, reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
+ reg |= EHCI_PS_PP;
+ ehci_writel(status_reg, reg);
+ }
+ break;
+ case USB_PORT_FEAT_RESET:
+ if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
+ !ehci_is_TDI() &&
+ EHCI_PS_IS_LOWSPEED(reg)) {
+ /* Low speed device, give up ownership. */
+ debug("port %d low speed --> companion\n",
+ req->index - 1);
+ reg |= EHCI_PS_PO;
+ ehci_writel(status_reg, reg);
+ break;
+ } else {
+ reg |= EHCI_PS_PR;
+ reg &= ~EHCI_PS_PE;
+ ehci_writel(status_reg, reg);
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 specification say 50 ms resets on
+ * root
+ */
+ wait_ms(50);
+ portreset |= 1 << le16_to_cpu(req->index);
+ }
+ break;
+ default:
+ debug("unknown feature %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ /* unblock posted writes */
+ ehci_readl(&hcor->or_usbcmd);
+ break;
+ case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ reg = ehci_readl(status_reg);
+ switch (le16_to_cpu(req->value)) {
+ case USB_PORT_FEAT_ENABLE:
+ reg &= ~EHCI_PS_PE;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
+ reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
+ case USB_PORT_FEAT_C_CONNECTION:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
+ break;
+ case USB_PORT_FEAT_OVER_CURRENT:
+ reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ portreset &= ~(1 << le16_to_cpu(req->index));
+ break;
+ default:
+ debug("unknown feature %x\n", le16_to_cpu(req->value));
+ goto unknown;
+ }
+ ehci_writel(status_reg, reg);
+ /* unblock posted write */
+ ehci_readl(&hcor->or_usbcmd);
+ break;
+ default:
+ debug("Unknown request\n");
+ goto unknown;
+ }
+
+ wait_ms(1);
+ len = min3(srclen, le16_to_cpu(req->length), length);
+ if (srcptr != NULL && len > 0)
+ memcpy(buffer, srcptr, len);
+ else
+ debug("Len is 0\n");
+
+ dev->act_len = len;
+ dev->status = 0;
+ return 0;
+
+unknown:
+ debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
+ req->requesttype, req->request, le16_to_cpu(req->value),
+ le16_to_cpu(req->index), le16_to_cpu(req->length));
+
+ dev->act_len = 0;
+ dev->status = USB_ST_STALLED;
+ return -1;
+}
+
+int usb_lowlevel_stop(void)
+{
+ return ehci_hcd_stop();
+}
+
+int usb_lowlevel_init(void)
+{
+ uint32_t reg;
+ uint32_t cmd;
+
+ if (ehci_hcd_init() != 0)
+ return -1;
+
+ /* EHCI spec section 4.1 */
+ if (ehci_reset() != 0)
+ return -1;
+
+#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
+ if (ehci_hcd_init() != 0)
+ return -1;
+#endif
+
+ /* Set head of reclaim list */
+ memset(&qh_list, 0, sizeof(qh_list));
+ qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
+ qh_list.qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
+ qh_list.qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
+ qh_list.qh_overlay.qt_token = cpu_to_hc32(0x40);
+
+ /* Set async. queue head pointer. */
+ ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&qh_list);
+
+ reg = ehci_readl(&hccr->cr_hcsparams);
+ descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
+ printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
+ /* Port Indicators */
+ if (HCS_INDICATOR(reg))
+ descriptor.hub.wHubCharacteristics |= 0x80;
+ /* Port Power Control */
+ if (HCS_PPC(reg))
+ descriptor.hub.wHubCharacteristics |= 0x01;
+
+ /* Start the host controller. */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ /*
+ * Philips, Intel, and maybe others need CMD_RUN before the
+ * root hub will detect new devices (why?); NEC doesn't
+ */
+ cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
+ cmd |= CMD_RUN;
+ ehci_writel(&hcor->or_usbcmd, cmd);
+
+ /* take control over the ports */
+ cmd = ehci_readl(&hcor->or_configflag);
+ cmd |= FLAG_CF;
+ ehci_writel(&hcor->or_configflag, cmd);
+ /* unblock posted write */
+ cmd = ehci_readl(&hcor->or_usbcmd);
+ wait_ms(5);
+ reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
+ printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
+
+ rootdev = 0;
+
+ return 0;
+}
+
+int
+submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length)
+{
+
+ if (usb_pipetype(pipe) != PIPE_BULK) {
+ debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
+ return -1;
+ }
+ return ehci_submit_async(dev, pipe, buffer, length, NULL);
+}
+
+int
+submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, struct devrequest *setup)
+{
+
+ if (usb_pipetype(pipe) != PIPE_CONTROL) {
+ debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
+ return -1;
+ }
+
+ if (usb_pipedevice(pipe) == rootdev) {
+ if (rootdev == 0)
+ dev->speed = USB_SPEED_HIGH;
+ return ehci_submit_root(dev, pipe, buffer, length, setup);
+ }
+ return ehci_submit_async(dev, pipe, buffer, length, setup);
+}
+
+int
+submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int length, int interval)
+{
+
+ debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
+ dev, pipe, buffer, length, interval);
+ return -1;
+}
--- /dev/null
+/*
+ * (C) Copyright 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ *
+ * Author: Michael Trimarchi <trimarchimichael@yahoo.it>
+ * This code is based on ehci freescale driver
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ hccr = (struct ehci_hccr *)(0xcd000100);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr
+ + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ printf("IXP4XX init hccr %x and hcor %x hc_length %d\n",
+ (uint32_t)hccr, (uint32_t)hcor,
+ (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
--- /dev/null
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <usb.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+#ifdef CONFIG_PCI_EHCI_DEVICE
+static struct pci_device_id ehci_pci_ids[] = {
+ /* Please add supported PCI EHCI controller ids here */
+ {0, 0}
+};
+#endif
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ pci_dev_t pdev;
+ uint32_t addr;
+
+ pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
+ if (pdev == -1) {
+ printf("EHCI host controller not found\n");
+ return -1;
+ }
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &addr);
+ hccr = (struct ehci_hccr *)addr;
+ hcor = (struct ehci_hcor *)((uint32_t) hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
--- /dev/null
+/*
+ * (C) Copyright 2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+int vct_ehci_hcd_init(u32 *hccr, u32 *hcor);
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(void)
+{
+ int ret;
+ u32 vct_hccr;
+ u32 vct_hcor;
+
+ /*
+ * Init VCT specific stuff
+ */
+ ret = vct_ehci_hcd_init(&vct_hccr, &vct_hcor);
+ if (ret)
+ return ret;
+
+ hccr = (struct ehci_hccr *)vct_hccr;
+ hcor = (struct ehci_hcor *)vct_hcor;
+
+ return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(void)
+{
+ return 0;
+}
--- /dev/null
+/*-
+ * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef USB_EHCI_H
+#define USB_EHCI_H
+
+#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
+#endif
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define DeviceOutRequest \
+ ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
+
+#define InterfaceRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointRequest \
+ ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+#define EndpointOutRequest \
+ ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
+
+/*
+ * Register Space.
+ */
+struct ehci_hccr {
+ uint32_t cr_capbase;
+#define HC_LENGTH(p) (((p) >> 0) & 0x00ff)
+#define HC_VERSION(p) (((p) >> 16) & 0xffff)
+ uint32_t cr_hcsparams;
+#define HCS_PPC(p) ((p) & (1 << 4))
+#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */
+#define HCS_N_PORTS(p) (((p) >> 0) & 0xf)
+ uint32_t cr_hccparams;
+ uint8_t cr_hcsp_portrt[8];
+} __attribute__ ((packed));
+
+struct ehci_hcor {
+ uint32_t or_usbcmd;
+#define CMD_PARK (1 << 11) /* enable "park" */
+#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
+#define CMD_ASE (1 << 5) /* async schedule enable */
+#define CMD_LRESET (1 << 7) /* partial reset */
+#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
+#define CMD_PSE (1 << 4) /* periodic schedule enable */
+#define CMD_RESET (1 << 1) /* reset HC not bus */
+#define CMD_RUN (1 << 0) /* start/stop HC */
+ uint32_t or_usbsts;
+#define STD_ASS (1 << 15)
+#define STS_HALT (1 << 12)
+ uint32_t or_usbintr;
+ uint32_t or_frindex;
+ uint32_t or_ctrldssegment;
+ uint32_t or_periodiclistbase;
+ uint32_t or_asynclistaddr;
+ uint32_t _reserved_[9];
+ uint32_t or_configflag;
+#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
+ uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
+ uint32_t or_systune;
+} __attribute__ ((packed));
+
+#define USBMODE 0x68 /* USB Device mode */
+#define USBMODE_SDIS (1 << 3) /* Stream disable */
+#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */
+#define USBMODE_CM_HC (3 << 0) /* host controller mode */
+#define USBMODE_CM_IDLE (0 << 0) /* idle state */
+
+/* Interface descriptor */
+struct usb_linux_interface_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned char bInterfaceNumber;
+ unsigned char bAlternateSetting;
+ unsigned char bNumEndpoints;
+ unsigned char bInterfaceClass;
+ unsigned char bInterfaceSubClass;
+ unsigned char bInterfaceProtocol;
+ unsigned char iInterface;
+} __attribute__ ((packed));
+
+/* Configuration descriptor information.. */
+struct usb_linux_config_descriptor {
+ unsigned char bLength;
+ unsigned char bDescriptorType;
+ unsigned short wTotalLength;
+ unsigned char bNumInterfaces;
+ unsigned char bConfigurationValue;
+ unsigned char iConfiguration;
+ unsigned char bmAttributes;
+ unsigned char MaxPower;
+} __attribute__ ((packed));
+
+#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
+#define ehci_readl(x) (*((volatile u32 *)(x)))
+#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b))
+#else
+#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x))))
+#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \
+ cpu_to_le32(((volatile u32)b)))
+#endif
+
+#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define hc32_to_cpu(x) be32_to_cpu((x))
+#define cpu_to_hc32(x) cpu_to_be32((x))
+#else
+#define hc32_to_cpu(x) le32_to_cpu((x))
+#define cpu_to_hc32(x) cpu_to_le32((x))
+#endif
+
+#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */
+#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */
+#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */
+#define EHCI_PS_PO (1 << 13) /* RW port owner */
+#define EHCI_PS_PP (1 << 12) /* RW,RO port power */
+#define EHCI_PS_LS (3 << 10) /* RO line status */
+#define EHCI_PS_PR (1 << 8) /* RW port reset */
+#define EHCI_PS_SUSP (1 << 7) /* RW suspend */
+#define EHCI_PS_FPR (1 << 6) /* RW force port resume */
+#define EHCI_PS_OCC (1 << 5) /* RWC over current change */
+#define EHCI_PS_OCA (1 << 4) /* RO over current active */
+#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */
+#define EHCI_PS_PE (1 << 2) /* RW port enable */
+#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */
+#define EHCI_PS_CS (1 << 0) /* RO connect status */
+#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
+
+#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10))
+
+/*
+ * Schedule Interface Space.
+ *
+ * IMPORTANT: Software must ensure that no interface data structure
+ * reachable by the EHCI host controller spans a 4K page boundary!
+ *
+ * Periodic transfers (i.e. isochronous and interrupt transfers) are
+ * not supported.
+ */
+
+/* Queue Element Transfer Descriptor (qTD). */
+struct qTD {
+ uint32_t qt_next;
+#define QT_NEXT_TERMINATE 1
+ uint32_t qt_altnext;
+ uint32_t qt_token;
+ uint32_t qt_buffer[5];
+};
+
+/* Queue Head (QH). */
+struct QH {
+ uint32_t qh_link;
+#define QH_LINK_TERMINATE 1
+#define QH_LINK_TYPE_ITD 0
+#define QH_LINK_TYPE_QH 2
+#define QH_LINK_TYPE_SITD 4
+#define QH_LINK_TYPE_FSTN 6
+ uint32_t qh_endpt1;
+ uint32_t qh_endpt2;
+ uint32_t qh_curtd;
+ struct qTD qh_overlay;
+ /*
+ * Add dummy fill value to make the size of this struct
+ * aligned to 32 bytes
+ */
+ uint8_t fill[16];
+};
+
+/* Low level init functions */
+int ehci_hcd_init(void);
+int ehci_hcd_stop(void);
+
+#endif /* USB_EHCI_H */
--- /dev/null
+/*
+ * ISP116x HCD (Host Controller Driver) for u-boot.
+ *
+ * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Derived in part from the SL811 HCD driver "u-boot/drivers/usb/sl811_usb.c"
+ * (original copyright message follows):
+ *
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This code is based on linux driver for sl811hs chip, source at
+ * drivers/usb/host/sl811.c:
+ *
+ * SL811 Host Controller Interface driver for USB.
+ *
+ * Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ * Based on:
+ * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ * Adam Richter, Gregory P. Smith;
+ * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ * [[GNU/GPL disclaimer]]
+ *
+ * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
+ * (original copyright message follows):
+ *
+ * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * [[GNU/GPL disclaimer]]
+ *
+ * Note: Part of this code has been derived from linux
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <malloc.h>
+#include <linux/list.h>
+
+/*
+ * ISP116x chips require certain delays between accesses to its
+ * registers. The following timing options exist.
+ *
+ * 1. Configure your memory controller (the best)
+ * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
+ *
+ * Value is in microseconds.
+ */
+#ifdef ISP116X_HCD_USE_UDELAY
+#define UDELAY 1
+#endif
+
+/*
+ * On some (slowly?) machines an extra delay after data packing into
+ * controller's FIFOs is required, * otherwise you may get the following
+ * error:
+ *
+ * uboot> usb start
+ * (Re)start USB...
+ * USB: scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
+ * isp116x: isp116x_submit_job: ****** FIFO not ready! ******
+ *
+ * USB device not responding, giving up (status=4)
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ * 3 USB Device(s) found
+ * scanning bus for storage devices... 0 Storage Device(s) found
+ *
+ * Value is in milliseconds.
+ */
+#ifdef ISP116X_HCD_USE_EXTRA_DELAY
+#define EXTRA_DELAY 2
+#endif
+
+/*
+ * Enable the following defines if you wish enable debugging messages.
+ */
+#undef DEBUG /* enable debugging messages */
+#undef TRACE /* enable tracing code */
+#undef VERBOSE /* verbose debugging messages */
+
+#include "isp116x.h"
+
+#define DRIVER_VERSION "08 Jan 2007"
+static const char hcd_name[] = "isp116x-hcd";
+
+struct isp116x isp116x_dev;
+struct isp116x_platform_data isp116x_board;
+static int got_rhsc; /* root hub status change */
+struct usb_device *devgone; /* device which was disconnected */
+static int rh_devnum; /* address of Root Hub endpoint */
+
+/* ------------------------------------------------------------------------- */
+
+#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
+#define min_t(type,x,y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+
+/* ------------------------------------------------------------------------- */
+
+static int isp116x_reset(struct isp116x *isp116x);
+
+/* --- Debugging functions ------------------------------------------------- */
+
+#define isp116x_show_reg(d, r) { \
+ if ((r) < 0x20) { \
+ DBG("%-12s[%02x]: %08x", #r, \
+ r, isp116x_read_reg32(d, r)); \
+ } else { \
+ DBG("%-12s[%02x]: %04x", #r, \
+ r, isp116x_read_reg16(d, r)); \
+ } \
+}
+
+#define isp116x_show_regs(d) { \
+ isp116x_show_reg(d, HCREVISION); \
+ isp116x_show_reg(d, HCCONTROL); \
+ isp116x_show_reg(d, HCCMDSTAT); \
+ isp116x_show_reg(d, HCINTSTAT); \
+ isp116x_show_reg(d, HCINTENB); \
+ isp116x_show_reg(d, HCFMINTVL); \
+ isp116x_show_reg(d, HCFMREM); \
+ isp116x_show_reg(d, HCFMNUM); \
+ isp116x_show_reg(d, HCLSTHRESH); \
+ isp116x_show_reg(d, HCRHDESCA); \
+ isp116x_show_reg(d, HCRHDESCB); \
+ isp116x_show_reg(d, HCRHSTATUS); \
+ isp116x_show_reg(d, HCRHPORT1); \
+ isp116x_show_reg(d, HCRHPORT2); \
+ isp116x_show_reg(d, HCHWCFG); \
+ isp116x_show_reg(d, HCDMACFG); \
+ isp116x_show_reg(d, HCXFERCTR); \
+ isp116x_show_reg(d, HCuPINT); \
+ isp116x_show_reg(d, HCuPINTENB); \
+ isp116x_show_reg(d, HCCHIPID); \
+ isp116x_show_reg(d, HCSCRATCH); \
+ isp116x_show_reg(d, HCITLBUFLEN); \
+ isp116x_show_reg(d, HCATLBUFLEN); \
+ isp116x_show_reg(d, HCBUFSTAT); \
+ isp116x_show_reg(d, HCRDITL0LEN); \
+ isp116x_show_reg(d, HCRDITL1LEN); \
+}
+
+#if defined(TRACE)
+
+static int isp116x_get_current_frame_number(struct usb_device *usb_dev)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ return isp116x_read_reg32(isp116x, HCFMNUM);
+}
+
+static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, char *str)
+{
+#if defined(VERBOSE)
+ int i;
+#endif
+
+ DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx",
+ str,
+ isp116x_get_current_frame_number(dev),
+ usb_pipedevice(pipe),
+ usb_pipeendpoint(pipe),
+ usb_pipeout(pipe) ? 'O' : 'I',
+ usb_pipetype(pipe) < 2 ?
+ (usb_pipeint(pipe) ?
+ "INTR" : "ISOC") :
+ (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status);
+#if defined(VERBOSE)
+ if (len > 0 && buffer) {
+ printf(__FILE__ ": data(%d):", len);
+ for (i = 0; i < 16 && i < len; i++)
+ printf(" %02x", ((__u8 *) buffer)[i]);
+ printf("%s\n", i < len ? "..." : "");
+ }
+#endif
+}
+
+#define PTD_DIR_STR(ptd) ({char __c; \
+ switch(PTD_GET_DIR(ptd)){ \
+ case 0: __c = 's'; break; \
+ case 1: __c = 'o'; break; \
+ default: __c = 'i'; break; \
+ }; __c;})
+
+/*
+ Dump PTD info. The code documents the format
+ perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+#if defined(VERBOSE)
+ int k;
+#endif
+
+ DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
+ PTD_GET_CC(ptd),
+ PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+ PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+ PTD_GET_TOGGLE(ptd),
+ PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+#if defined(VERBOSE)
+ printf("isp116x: %s: PTD(byte): ", __FUNCTION__);
+ for (k = 0; k < sizeof(struct ptd); ++k)
+ printf("%02x ", ((u8 *) ptd)[k]);
+ printf("\n");
+#endif
+}
+
+static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type)
+{
+#if defined(VERBOSE)
+ int k;
+
+ if (type == 0 /* 0ut data */ ) {
+ printf("isp116x: %s: out data: ", __FUNCTION__);
+ for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+ printf("%02x ", ((u8 *) buf)[k]);
+ printf("\n");
+ }
+ if (type == 1 /* 1n data */ ) {
+ printf("isp116x: %s: in data: ", __FUNCTION__);
+ for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+ printf("%02x ", ((u8 *) buf)[k]);
+ printf("\n");
+ }
+
+ if (PTD_GET_LAST(ptd))
+ DBG("--- last PTD ---");
+#endif
+}
+
+#else
+
+#define dump_msg(dev, pipe, buffer, len, str) do { } while (0)
+#define dump_pkt(dev, pipe, buffer, len, setup, str, small) do {} while (0)
+
+#define dump_ptd(ptd) do {} while (0)
+#define dump_ptd_data(ptd, buf, type) do {} while (0)
+
+#endif
+
+/* --- Virtual Root Hub ---------------------------------------------------- */
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x02,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] = {
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] = {
+ 0x22, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'S', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'P', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '1', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '1', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '6', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'x', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/*
+ * Hub class-specific descriptor is constructed dynamically
+ */
+
+/* --- Virtual root hub management functions ------------------------------- */
+
+static int rh_check_port_status(struct isp116x *isp116x)
+{
+ u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+ ndp = (temp & RH_A_NDP);
+ for (i = 0; i < ndp; i++) {
+ temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+/* --- HC management functions --------------------------------------------- */
+
+/* Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+ u8 *dp = (u8 *) buf;
+ u16 *dp2 = (u16 *) buf;
+ u16 w;
+ int quot = len % 4;
+
+ if ((unsigned long)dp2 & 1) {
+ /* not aligned */
+ for (; len > 1; len -= 2) {
+ w = *dp++;
+ w |= *dp++ << 8;
+ isp116x_raw_write_data16(isp116x, w);
+ }
+ if (len)
+ isp116x_write_data16(isp116x, (u16) * dp);
+ } else {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ isp116x_raw_write_data16(isp116x, *dp2++);
+ if (len)
+ isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_raw_write_data16(isp116x, 0);
+}
+
+/* Read len bytes from fifo and then read till 32-bit boundary
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+ u8 *dp = (u8 *) buf;
+ u16 *dp2 = (u16 *) buf;
+ u16 w;
+ int quot = len % 4;
+
+ if ((unsigned long)dp2 & 1) {
+ /* not aligned */
+ for (; len > 1; len -= 2) {
+ w = isp116x_raw_read_data16(isp116x);
+ *dp++ = w & 0xff;
+ *dp++ = (w >> 8) & 0xff;
+ }
+ if (len)
+ *dp = 0xff & isp116x_read_data16(isp116x);
+ } else {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ *dp2++ = isp116x_raw_read_data16(isp116x);
+ if (len)
+ *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_raw_read_data16(isp116x);
+}
+
+/* Write PTD's and data for scheduled transfers into the fifo ram.
+ * Fifo must be empty and ready */
+static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+ unsigned long pipe, struct ptd *ptd, int n, void *data,
+ int len)
+{
+ int buflen = n * sizeof(struct ptd) + len;
+ int i, done;
+
+ DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+
+ done = 0;
+ for (i = 0; i < n; i++) {
+ DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+ dump_ptd(&ptd[i]);
+ isp116x_write_data16(isp116x, ptd[i].count);
+ isp116x_write_data16(isp116x, ptd[i].mps);
+ isp116x_write_data16(isp116x, ptd[i].len);
+ isp116x_write_data16(isp116x, ptd[i].faddr);
+
+ dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);
+ write_ptddata_to_fifo(isp116x,
+ (__u8 *) data + done,
+ PTD_GET_LEN(&ptd[i]));
+
+ done += PTD_GET_LEN(&ptd[i]);
+ }
+}
+
+/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
+ * Fifo must be full and done */
+static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+ unsigned long pipe, struct ptd *ptd, int n, void *data,
+ int len)
+{
+ int buflen = n * sizeof(struct ptd) + len;
+ int i, done, cc, ret;
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ isp116x_write_addr(isp116x, HCATLPORT);
+
+ ret = TD_CC_NOERROR;
+ done = 0;
+ for (i = 0; i < n; i++) {
+ DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+ ptd[i].count = isp116x_read_data16(isp116x);
+ ptd[i].mps = isp116x_read_data16(isp116x);
+ ptd[i].len = isp116x_read_data16(isp116x);
+ ptd[i].faddr = isp116x_read_data16(isp116x);
+ dump_ptd(&ptd[i]);
+
+ read_ptddata_from_fifo(isp116x,
+ (__u8 *) data + done,
+ PTD_GET_LEN(&ptd[i]));
+ dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);
+
+ done += PTD_GET_LEN(&ptd[i]);
+
+ cc = PTD_GET_CC(&ptd[i]);
+
+ /* Data underrun means basically that we had more buffer space than
+ * the function had data. It is perfectly normal but upper levels have
+ * to know how much we actually transferred.
+ */
+ if (cc == TD_NOTACCESSED ||
+ (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
+ ret = cc;
+ }
+
+ DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+ return ret;
+}
+
+/* Interrupt handling
+ */
+static int isp116x_interrupt(struct isp116x *isp116x)
+{
+ u16 irqstat;
+ u32 intstat;
+ int ret = 0;
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+ irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+ isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+ DBG(">>>>>> irqstat %x <<<<<<", irqstat);
+
+ if (irqstat & HCuPINT_ATL) {
+ DBG(">>>>>> HCuPINT_ATL <<<<<<");
+ udelay(500);
+ ret = 1;
+ }
+
+ if (irqstat & HCuPINT_OPR) {
+ intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+ isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+ DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);
+
+ if (intstat & HCINT_UE) {
+ ERR("unrecoverable error, controller disabled");
+
+ /* FIXME: be optimistic, hope that bug won't repeat
+ * often. Make some non-interrupt context restart the
+ * controller. Count and limit the retries though;
+ * either hardware or software errors can go forever...
+ */
+ isp116x_reset(isp116x);
+ ret = -1;
+ return -1;
+ }
+
+ if (intstat & HCINT_RHSC) {
+ got_rhsc = 1;
+ ret = 1;
+ /* When root hub or any of its ports is going
+ to come out of suspend, it may take more
+ than 10ms for status bits to stabilize. */
+ wait_ms(20);
+ }
+
+ if (intstat & HCINT_SO) {
+ ERR("schedule overrun");
+ ret = -1;
+ }
+
+ irqstat &= ~HCuPINT_OPR;
+ }
+
+ return ret;
+}
+
+/* With one PTD we can transfer almost 1K in one go;
+ * HC does the splitting into endpoint digestible transactions
+ */
+struct ptd ptd[1];
+
+static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
+{
+ unsigned mpck = usb_maxpacket(dev, pipe);
+
+ /* One PTD can transfer 1023 bytes but try to always
+ * transfer multiples of endpoint buffer size
+ */
+ return 1023 / mpck * mpck;
+}
+
+/* Do an USB transfer
+ */
+static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
+ int dir, void *buffer, int len)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+ int type = usb_pipetype(pipe);
+ int epnum = usb_pipeendpoint(pipe);
+ int max = usb_maxpacket(dev, pipe);
+ int dir_out = usb_pipeout(pipe);
+ int speed_low = usb_pipeslow(pipe);
+ int i, done = 0, stat, timeout, cc;
+
+ /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
+ int retries = 500;
+
+ DBG("------------------------------------------------");
+ dump_msg(dev, pipe, buffer, len, "SUBMIT");
+ DBG("------------------------------------------------");
+
+ if (len >= 1024) {
+ ERR("Too big job");
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ if (isp116x->disabled) {
+ ERR("EPIPE");
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ ERR("ENODEV");
+ dev->status = USB_ST_CRC_ERR;
+ return USB_ST_CRC_ERR;
+ }
+
+ if (!max) {
+ ERR("pipesize for pipe %lx is zero", pipe);
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ if (type == PIPE_ISOCHRONOUS) {
+ ERR("isochronous transfers not supported");
+ dev->status = USB_ST_CRC_ERR;
+ return -1;
+ }
+
+ /* FIFO not empty? */
+ if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {
+ ERR("****** FIFO not empty! ******");
+ dev->status = USB_ST_BUF_ERR;
+ return -1;
+ }
+
+ retry:
+ isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
+
+ /* Prepare the PTD data */
+ ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
+ PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
+ ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
+ ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+ ptd->faddr = PTD_FA(usb_pipedevice(pipe));
+
+retry_same:
+ /* Pack data into FIFO ram */
+ pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+#ifdef EXTRA_DELAY
+ wait_ms(EXTRA_DELAY);
+#endif
+
+ /* Start the data transfer */
+
+ /* Allow more time for a BULK device to react - some are slow */
+ if (usb_pipebulk(pipe))
+ timeout = 5000;
+ else
+ timeout = 100;
+
+ /* Wait for it to complete */
+ for (;;) {
+ /* Check whether the controller is done */
+ stat = isp116x_interrupt(isp116x);
+
+ if (stat < 0) {
+ dev->status = USB_ST_CRC_ERR;
+ break;
+ }
+ if (stat > 0)
+ break;
+
+ /* Check the timeout */
+ if (--timeout)
+ udelay(1);
+ else {
+ ERR("CTL:TIMEOUT ");
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+ }
+
+ /* We got an Root Hub Status Change interrupt */
+ if (got_rhsc) {
+ isp116x_show_regs(isp116x);
+
+ got_rhsc = 0;
+
+ /* Abuse timeout */
+ timeout = rh_check_port_status(isp116x);
+ if (timeout >= 0) {
+ /*
+ * FIXME! NOTE! AAAARGH!
+ * This is potentially dangerous because it assumes
+ * that only one device is ever plugged in!
+ */
+ devgone = dev;
+ }
+ }
+
+ /* Ok, now we can read transfer status */
+
+ /* FIFO not ready? */
+ if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {
+ ERR("****** FIFO not ready! ******");
+ dev->status = USB_ST_BUF_ERR;
+ return -1;
+ }
+
+ /* Unpack data from FIFO ram */
+ cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
+
+ i = PTD_GET_COUNT(ptd);
+ done += i;
+ buffer += i;
+ len -= i;
+
+ /* There was some kind of real problem; Prepare the PTD again
+ * and retry from the failed transaction on
+ */
+ if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {
+ if (retries >= 100) {
+ retries -= 100;
+ /* The chip will have toggled the toggle bit for the failed
+ * transaction too. We have to toggle it back.
+ */
+ usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
+ goto retry;
+ }
+ }
+ /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
+ * the transactions from the first on for the whole frame. It may be busy and we retry
+ * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
+ * PTD didn't make it because the function was busy or the frame ended before the PTD
+ * finished. We prepare the rest of the data and try again.
+ */
+ else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {
+ if (retries) {
+ --retries;
+ if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;
+ usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+ goto retry;
+ }
+ }
+
+ if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {
+ DBG("****** completition code error %x ******", cc);
+ switch (cc) {
+ case TD_CC_BITSTUFFING:
+ dev->status = USB_ST_BIT_ERR;
+ break;
+ case TD_CC_STALL:
+ dev->status = USB_ST_STALLED;
+ break;
+ case TD_BUFFEROVERRUN:
+ case TD_BUFFERUNDERRUN:
+ dev->status = USB_ST_BUF_ERR;
+ break;
+ default:
+ dev->status = USB_ST_CRC_ERR;
+ }
+ return -cc;
+ }
+ else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
+
+ dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
+
+ dev->status = 0;
+ return done;
+}
+
+/* Adapted from au1x00_usb_ohci.c
+ */
+static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *cmd)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+ u32 tmp = 0;
+
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ u32 datab[4];
+ u8 *data_buf = (u8 *) datab;
+ u16 bmRType_bReq;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+
+ if (usb_pipeint(pipe)) {
+ INFO("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = swap_16(cmd->value);
+ wIndex = swap_16(cmd->index);
+ wLength = swap_16(cmd->length);
+
+ DBG("--- HUB ----------------------------------------");
+ DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",
+ bmRType_bReq, wValue, wIndex, wLength);
+ dump_msg(dev, pipe, buffer, transfer_len, "RH");
+ DBG("------------------------------------------------");
+
+ switch (bmRType_bReq) {
+ case RH_GET_STATUS:
+ DBG("RH_GET_STATUS");
+
+ *(__u16 *) data_buf = swap_16(1);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_INTERFACE:
+ DBG("RH_GET_STATUS | RH_INTERFACE");
+
+ *(__u16 *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_ENDPOINT:
+ DBG("RH_GET_STATUS | RH_ENDPOINT");
+
+ *(__u16 *) data_buf = swap_16(0);
+ len = 2;
+ break;
+
+ case RH_GET_STATUS | RH_CLASS:
+ DBG("RH_GET_STATUS | RH_CLASS");
+
+ tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+ *(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
+ len = 4;
+ break;
+
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");
+
+ tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
+ *(__u32 *) data_buf = swap_32(tmp);
+ isp116x_show_regs(isp116x);
+ len = 4;
+ break;
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");
+
+ switch (wValue) {
+ case RH_ENDPOINT_STALL:
+ DBG("C_HUB_ENDPOINT_STALL");
+ len = 0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ DBG("RH_CLEAR_FEATURE | RH_CLASS");
+
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ DBG("C_HUB_LOCAL_POWER");
+ len = 0;
+ break;
+
+ case RH_C_HUB_OVER_CURRENT:
+ DBG("C_HUB_OVER_CURRENT");
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+ len = 0;
+ break;
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");
+
+ switch (wValue) {
+ case RH_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_CCS);
+ len = 0;
+ break;
+
+ case RH_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_POCI);
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_LSDA);
+ len = 0;
+ break;
+
+ case RH_C_PORT_CONNECTION:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_CSC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PESC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PSSC);
+ len = 0;
+ break;
+
+ case RH_C_PORT_OVER_CURRENT:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_POCI);
+ len = 0;
+ break;
+
+ case RH_C_PORT_RESET:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PRSC);
+ len = 0;
+ break;
+
+ default:
+ ERR("invalid wValue");
+ stat = USB_ST_STALLED;
+ }
+
+ isp116x_show_regs(isp116x);
+
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS");
+
+ switch (wValue) {
+ case RH_PORT_SUSPEND:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PSS);
+ len = 0;
+ break;
+
+ case RH_PORT_RESET:
+ /* Spin until any current reset finishes */
+ while (1) {
+ tmp =
+ isp116x_read_reg32(isp116x,
+ HCRHPORT1 + wIndex - 1);
+ if (!(tmp & RH_PS_PRS))
+ break;
+ wait_ms(1);
+ }
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PRS);
+ wait_ms(10);
+
+ len = 0;
+ break;
+
+ case RH_PORT_POWER:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PPS);
+ len = 0;
+ break;
+
+ case RH_PORT_ENABLE:
+ isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+ RH_PS_PES);
+ len = 0;
+ break;
+
+ default:
+ ERR("invalid wValue");
+ stat = USB_ST_STALLED;
+ }
+
+ isp116x_show_regs(isp116x);
+
+ break;
+
+ case RH_SET_ADDRESS:
+ DBG("RH_SET_ADDRESS");
+
+ rh_devnum = wValue;
+ len = 0;
+ break;
+
+ case RH_GET_DESCRIPTOR:
+ DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength);
+
+ switch (wValue) {
+ case (USB_DT_DEVICE << 8): /* device descriptor */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des;
+ break;
+
+ case (USB_DT_CONFIG << 8): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ break;
+
+ case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
+ len = min_t(unsigned int,
+ leni, min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ break;
+
+ default:
+ ERR("invalid wValue");
+ stat = USB_ST_STALLED;
+ }
+
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ DBG("RH_GET_DESCRIPTOR | RH_CLASS");
+
+ tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+ data_buf[0] = 0x09; /* min length; */
+ data_buf[1] = 0x29;
+ data_buf[2] = tmp & RH_A_NDP;
+ data_buf[3] = 0;
+ if (tmp & RH_A_PSM) /* per-port power switching? */
+ data_buf[3] |= 0x01;
+ if (tmp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf[3] |= 0x10;
+ else if (tmp & RH_A_OCPM) /* per-port overcurrent rep? */
+ data_buf[3] |= 0x08;
+
+ /* Corresponds to data_buf[4-7] */
+ datab[1] = 0;
+ data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
+
+ tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+ data_buf[7] = tmp & RH_B_DR;
+ if (data_buf[2] < 7)
+ data_buf[8] = 0xff;
+ else {
+ data_buf[0] += 2;
+ data_buf[8] = (tmp & RH_B_DR) >> 8;
+ data_buf[10] = data_buf[9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf[0], wLength));
+ break;
+
+ case RH_GET_CONFIGURATION:
+ DBG("RH_GET_CONFIGURATION");
+
+ *(__u8 *) data_buf = 0x01;
+ len = 1;
+ break;
+
+ case RH_SET_CONFIGURATION:
+ DBG("RH_SET_CONFIGURATION");
+
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
+ len = 0;
+ break;
+
+ default:
+ ERR("*** *** *** unsupported root hub command *** *** ***");
+ stat = USB_ST_STALLED;
+ }
+
+ len = min_t(int, len, leni);
+ if (buffer != data_buf)
+ memcpy(buffer, data_buf, len);
+
+ dev->act_len = len;
+ dev->status = stat;
+ DBG("dev act_len %d, status %d", dev->act_len, dev->status);
+
+ dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
+
+ return stat;
+}
+
+/* --- Transfer functions -------------------------------------------------- */
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, int interval)
+{
+ DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d",
+ dev, pipe, buffer, len, interval);
+
+ return -1;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, struct devrequest *setup)
+{
+ int devnum = usb_pipedevice(pipe);
+ int epnum = usb_pipeendpoint(pipe);
+ int max = max_transfer_len(dev, pipe);
+ int dir_in = usb_pipein(pipe);
+ int done, ret;
+
+ /* Control message is for the HUB? */
+ if (devnum == rh_devnum)
+ return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
+
+ /* Ok, no HUB message so send the message to the device */
+
+ /* Setup phase */
+ DBG("--- SETUP PHASE --------------------------------");
+ usb_settoggle(dev, epnum, 1, 0);
+ ret = isp116x_submit_job(dev, pipe,
+ PTD_DIR_SETUP,
+ setup, sizeof(struct devrequest));
+ if (ret < 0) {
+ DBG("control setup phase error (ret = %d", ret);
+ return -1;
+ }
+
+ /* Data phase */
+ DBG("--- DATA PHASE ---------------------------------");
+ done = 0;
+ usb_settoggle(dev, epnum, !dir_in, 1);
+ while (done < len) {
+ ret = isp116x_submit_job(dev, pipe,
+ dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
+ (__u8 *) buffer + done,
+ max > len - done ? len - done : max);
+ if (ret < 0) {
+ DBG("control data phase error (ret = %d)", ret);
+ return -1;
+ }
+ done += ret;
+
+ if (dir_in && ret < max) /* short packet */
+ break;
+ }
+
+ /* Status phase */
+ DBG("--- STATUS PHASE -------------------------------");
+ usb_settoggle(dev, epnum, !dir_in, 1);
+ ret = isp116x_submit_job(dev, pipe,
+ !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
+ if (ret < 0) {
+ DBG("control status phase error (ret = %d", ret);
+ return -1;
+ }
+
+ dev->act_len = done;
+
+ dump_msg(dev, pipe, buffer, len, "DEV(ret)");
+
+ return done;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len)
+{
+ int dir_out = usb_pipeout(pipe);
+ int max = max_transfer_len(dev, pipe);
+ int done, ret;
+
+ DBG("--- BULK ---------------------------------------");
+ DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d",
+ usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+ done = 0;
+ while (done < len) {
+ ret = isp116x_submit_job(dev, pipe,
+ !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
+ (__u8 *) buffer + done,
+ max > len - done ? len - done : max);
+ if (ret < 0) {
+ DBG("error on bulk message (ret = %d)", ret);
+ return -1;
+ }
+
+ done += ret;
+
+ if (!dir_out && ret < max) /* short packet */
+ break;
+ }
+
+ dev->act_len = done;
+
+ return 0;
+}
+
+/* --- Basic functions ----------------------------------------------------- */
+
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+ int retries = 15;
+ int ret = 0;
+
+ DBG("");
+
+ isp116x->disabled = 1;
+
+ isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+ isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+ while (--retries) {
+ /* It usually resets within 1 ms */
+ wait_ms(1);
+ if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+ break;
+ }
+ if (!retries) {
+ ERR("software reset timeout");
+ ret = -1;
+ }
+ return ret;
+}
+
+static int isp116x_reset(struct isp116x *isp116x)
+{
+ unsigned long t;
+ u16 clkrdy = 0;
+ int ret, timeout = 15 /* ms */ ;
+
+ DBG("");
+
+ ret = isp116x_sw_reset(isp116x);
+ if (ret)
+ return ret;
+
+ for (t = 0; t < timeout; t++) {
+ clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+ if (clkrdy)
+ break;
+ wait_ms(1);
+ }
+ if (!clkrdy) {
+ ERR("clock not ready after %dms", timeout);
+ /* After sw_reset the clock won't report to be ready, if
+ H_WAKEUP pin is high. */
+ ERR("please make sure that the H_WAKEUP pin is pulled low!");
+ ret = -1;
+ }
+ return ret;
+}
+
+static void isp116x_stop(struct isp116x *isp116x)
+{
+ u32 val;
+
+ DBG("");
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ /* Switch off ports' power, some devices don't come up
+ after next 'start' without this */
+ val = isp116x_read_reg32(isp116x, HCRHDESCA);
+ val &= ~(RH_A_NPS | RH_A_PSM);
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+
+ isp116x_sw_reset(isp116x);
+}
+
+/*
+ * Configure the chip. The chip must be successfully reset by now.
+ */
+static int isp116x_start(struct isp116x *isp116x)
+{
+ struct isp116x_platform_data *board = isp116x->board;
+ u32 val;
+
+ DBG("");
+
+ /* Clear interrupt status and disable all interrupt sources */
+ isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+ isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+ /* Hardware configuration */
+ val = HCHWCFG_DBWIDTH(1);
+ if (board->sel15Kres)
+ val |= HCHWCFG_15KRSEL;
+ /* Remote wakeup won't work without working clock */
+ if (board->remote_wakeup_enable)
+ val |= HCHWCFG_CLKNOTSTOP;
+ if (board->oc_enable)
+ val |= HCHWCFG_ANALOG_OC;
+ isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+ /* --- Root hub configuration */
+ val = (25 << 24) & RH_A_POTPGT;
+ /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+ be always set. Yet, instead, we request individual port
+ power switching. */
+ val |= RH_A_PSM;
+ /* Report overcurrent per port */
+ val |= RH_A_OCPM;
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+ val = RH_B_PPCM;
+ isp116x_write_reg32(isp116x, HCRHDESCB, val);
+ isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+ val = 0;
+ if (board->remote_wakeup_enable)
+ val |= RH_HS_DRWE;
+ isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+ isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+ isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+ /* Go operational */
+ val = HCCONTROL_USB_OPER;
+ if (board->remote_wakeup_enable)
+ val |= HCCONTROL_RWE;
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+ /* Disable ports to avoid race in device enumeration */
+ isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+ isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+ isp116x_show_regs(isp116x);
+
+ isp116x->disabled = 0;
+
+ return 0;
+}
+
+/* --- Init functions ------------------------------------------------------ */
+
+int isp116x_check_id(struct isp116x *isp116x)
+{
+ int val;
+
+ val = isp116x_read_reg16(isp116x, HCCHIPID);
+ if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+ ERR("invalid chip ID %04x", val);
+ return -1;
+ }
+
+ return 0;
+}
+
+int usb_lowlevel_init(void)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ DBG("");
+
+ got_rhsc = rh_devnum = 0;
+
+ /* Init device registers addr */
+ isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
+ isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
+
+ /* Setup specific board settings */
+#ifdef ISP116X_HCD_SEL15kRES
+ isp116x_board.sel15Kres = 1;
+#endif
+#ifdef ISP116X_HCD_OC_ENABLE
+ isp116x_board.oc_enable = 1;
+#endif
+#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
+ isp116x_board.remote_wakeup_enable = 1;
+#endif
+ isp116x->board = &isp116x_board;
+
+ /* Try to get ISP116x silicon chip ID */
+ if (isp116x_check_id(isp116x) < 0)
+ return -1;
+
+ isp116x->disabled = 1;
+ isp116x->sleeping = 0;
+
+ isp116x_reset(isp116x);
+ isp116x_start(isp116x);
+
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ struct isp116x *isp116x = &isp116x_dev;
+
+ DBG("");
+
+ if (!isp116x->disabled)
+ isp116x_stop(isp116x);
+
+ return 0;
+}
--- /dev/null
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef DEBUG
+#define DBG(fmt, args...) \
+ printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+#define DBG(fmt, args...) do {} while (0)
+#endif
+
+#ifdef VERBOSE
+# define VDBG DBG
+#else
+# define VDBG(fmt, args...) do {} while (0)
+#endif
+
+#define ERR(fmt, args...) \
+ printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define WARN(fmt, args...) \
+ printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define INFO(fmt, args...) \
+ printf("isp116x: " fmt "\n" , ## args)
+
+/* ------------------------------------------------------------------------- */
+
+/* us of 1ms frame */
+#define MAX_LOAD_LIMIT 850
+
+/* Full speed: max # of bytes to transfer for a single urb
+ at a time must be < 1024 && must be multiple of 64.
+ 832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED 832
+
+/* Low speed: there is no reason to schedule in very big
+ chunks; often the requested long transfers are for
+ string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED 64
+
+/* Bytetime (us), a rough indication of how much time it
+ would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED 1
+#define BYTE_TIME_LOWSPEED 20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE 4096
+#define ISP116x_ITL_BUFSIZE 0
+#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET 0x80
+
+/* --- ISP116x registers/bits ---------------------------------------------- */
+
+#define HCREVISION 0x00
+#define HCCONTROL 0x01
+#define HCCONTROL_HCFS (3 << 6) /* host controller
+ functional state */
+#define HCCONTROL_USB_RESET (0 << 6)
+#define HCCONTROL_USB_RESUME (1 << 6)
+#define HCCONTROL_USB_OPER (2 << 6)
+#define HCCONTROL_USB_SUSPEND (3 << 6)
+#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */
+#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */
+#define HCCMDSTAT 0x02
+#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */
+#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */
+#define HCINTSTAT 0x03
+#define HCINT_SO (1 << 0) /* scheduling overrun */
+#define HCINT_WDH (1 << 1) /* writeback of done_head */
+#define HCINT_SF (1 << 2) /* start frame */
+#define HCINT_RD (1 << 3) /* resume detect */
+#define HCINT_UE (1 << 4) /* unrecoverable error */
+#define HCINT_FNO (1 << 5) /* frame number overflow */
+#define HCINT_RHSC (1 << 6) /* root hub status change */
+#define HCINT_OC (1 << 30) /* ownership change */
+#define HCINT_MIE (1 << 31) /* master interrupt enable */
+#define HCINTENB 0x04
+#define HCINTDIS 0x05
+#define HCFMINTVL 0x0d
+#define HCFMREM 0x0e
+#define HCFMNUM 0x0f
+#define HCLSTHRESH 0x11
+#define HCRHDESCA 0x12
+#define RH_A_NDP (0x3 << 0) /* # downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* overcurrent protection
+ mode */
+#define RH_A_NOCP (1 << 12) /* no overcurrent protection */
+#define RH_A_POTPGT (0xff << 24) /* power on -> power good
+ time */
+#define HCRHDESCB 0x13
+#define RH_B_DR (0xffff << 0) /* device removable flags */
+#define RH_B_PPCM (0xffff << 16) /* port power control mask */
+#define HCRHSTATUS 0x14
+#define RH_HS_LPS (1 << 0) /* local power status */
+#define RH_HS_OCI (1 << 1) /* over current indicator */
+#define RH_HS_DRWE (1 << 15) /* device remote wakeup
+ enable */
+#define RH_HS_LPSC (1 << 16) /* local power status change */
+#define RH_HS_OCIC (1 << 17) /* over current indicator
+ change */
+#define RH_HS_CRWE (1 << 31) /* clear remote wakeup
+ enable */
+#define HCRHPORT1 0x15
+#define RH_PS_CCS (1 << 0) /* current connect status */
+#define RH_PS_PES (1 << 1) /* port enable status */
+#define RH_PS_PSS (1 << 2) /* port suspend status */
+#define RH_PS_POCI (1 << 3) /* port over current
+ indicator */
+#define RH_PS_PRS (1 << 4) /* port reset status */
+#define RH_PS_PPS (1 << 8) /* port power status */
+#define RH_PS_LSDA (1 << 9) /* low speed device attached */
+#define RH_PS_CSC (1 << 16) /* connect status change */
+#define RH_PS_PESC (1 << 17) /* port enable status change */
+#define RH_PS_PSSC (1 << 18) /* port suspend status
+ change */
+#define RH_PS_OCIC (1 << 19) /* over current indicator
+ change */
+#define RH_PS_PRSC (1 << 20) /* port reset status change */
+#define HCRHPORT_CLRMASK (0x1f << 16)
+#define HCRHPORT2 0x16
+#define HCHWCFG 0x20
+#define HCHWCFG_15KRSEL (1 << 12)
+#define HCHWCFG_CLKNOTSTOP (1 << 11)
+#define HCHWCFG_ANALOG_OC (1 << 10)
+#define HCHWCFG_DACK_MODE (1 << 8)
+#define HCHWCFG_EOT_POL (1 << 7)
+#define HCHWCFG_DACK_POL (1 << 6)
+#define HCHWCFG_DREQ_POL (1 << 5)
+#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
+#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define HCHWCFG_INT_POL (1 << 2)
+#define HCHWCFG_INT_TRIGGER (1 << 1)
+#define HCHWCFG_INT_ENABLE (1 << 0)
+#define HCDMACFG 0x21
+#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
+#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
+#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
+#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
+#define HCDMACFG_DMA_ENABLE (1 << 4)
+#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
+#define HCDMACFG_CTR_SEL (1 << 2)
+#define HCDMACFG_ITLATL_SEL (1 << 1)
+#define HCDMACFG_DMA_RW_SELECT (1 << 0)
+#define HCXFERCTR 0x22
+#define HCuPINT 0x24
+#define HCuPINT_SOF (1 << 0)
+#define HCuPINT_ATL (1 << 1)
+#define HCuPINT_AIIEOT (1 << 2)
+#define HCuPINT_OPR (1 << 4)
+#define HCuPINT_SUSP (1 << 5)
+#define HCuPINT_CLKRDY (1 << 6)
+#define HCuPINTENB 0x25
+#define HCCHIPID 0x27
+#define HCCHIPID_MASK 0xff00
+#define HCCHIPID_MAGIC 0x6100
+#define HCSCRATCH 0x28
+#define HCSWRES 0x29
+#define HCSWRES_MAGIC 0x00f6
+#define HCITLBUFLEN 0x2a
+#define HCATLBUFLEN 0x2b
+#define HCBUFSTAT 0x2c
+#define HCBUFSTAT_ITL0_FULL (1 << 0)
+#define HCBUFSTAT_ITL1_FULL (1 << 1)
+#define HCBUFSTAT_ATL_FULL (1 << 2)
+#define HCBUFSTAT_ITL0_DONE (1 << 3)
+#define HCBUFSTAT_ITL1_DONE (1 << 4)
+#define HCBUFSTAT_ATL_DONE (1 << 5)
+#define HCRDITL0LEN 0x2d
+#define HCRDITL1LEN 0x2e
+#define HCITLPORT 0x40
+#define HCATLPORT 0x41
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
+
+/* Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+ /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+ /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED 0x0F
+
+/* ------------------------------------------------------------------------- */
+
+#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
+#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
+
+/* Philips transfer descriptor */
+struct ptd {
+ u16 count;
+#define PTD_COUNT_MSK (0x3ff << 0)
+#define PTD_TOGGLE_MSK (1 << 10)
+#define PTD_ACTIVE_MSK (1 << 11)
+#define PTD_CC_MSK (0xf << 12)
+ u16 mps;
+#define PTD_MPS_MSK (0x3ff << 0)
+#define PTD_SPD_MSK (1 << 10)
+#define PTD_LAST_MSK (1 << 11)
+#define PTD_EP_MSK (0xf << 12)
+ u16 len;
+#define PTD_LEN_MSK (0x3ff << 0)
+#define PTD_DIR_MSK (3 << 10)
+#define PTD_DIR_SETUP (0)
+#define PTD_DIR_OUT (1)
+#define PTD_DIR_IN (2)
+#define PTD_B5_5_MSK (1 << 13)
+ u16 faddr;
+#define PTD_FA_MSK (0x7f << 0)
+#define PTD_FMT_MSK (1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+struct isp116x_ep {
+ struct usb_device *udev;
+ struct ptd ptd;
+
+ u8 maxpacket;
+ u8 epnum;
+ u8 nextpid;
+
+ u16 length; /* of current packet */
+ unsigned char *data; /* to databuf */
+
+ u16 error_count;
+};
+
+/* URB struct */
+#define N_URB_TD 48
+#define URB_DEL 1
+typedef struct {
+ struct isp116x_ep *ed;
+ void *transfer_buffer; /* (in) associated data buffer */
+ int actual_length; /* (return) actual transfer length */
+ unsigned long pipe; /* (in) pipe information */
+#if 0
+ int state;
+#endif
+} urb_priv_t;
+
+struct isp116x_platform_data {
+ /* Enable internal resistors on downstream ports */
+ unsigned sel15Kres:1;
+ /* On-chip overcurrent detection */
+ unsigned oc_enable:1;
+ /* Enable wakeup by devices on usb bus (e.g. wakeup
+ by attachment/detachment or by device activity
+ such as moving a mouse). When chosen, this option
+ prevents stopping internal clock, increasing
+ thereby power consumption in suspended state. */
+ unsigned remote_wakeup_enable:1;
+};
+
+struct isp116x {
+ u16 *addr_reg;
+ u16 *data_reg;
+
+ struct isp116x_platform_data *board;
+
+ struct dentry *dentry;
+ unsigned long stat1, stat2, stat4, stat8, stat16;
+
+ /* Status flags */
+ unsigned disabled:1;
+ unsigned sleeping:1;
+
+ /* Root hub registers */
+ u32 rhdesca;
+ u32 rhdescb;
+ u32 rhstatus;
+ u32 rhport[2];
+
+ /* Schedule for the current frame */
+ struct isp116x_ep *atl_active;
+ int atl_buflen;
+ int atl_bufshrt;
+ int atl_last_dir;
+ int atl_finishing;
+};
+
+/* ------------------------------------------------- */
+
+/* Inter-io delay (ns). The chip is picky about access timings; it
+ * expects at least:
+ * 150ns delay between consecutive accesses to DATA_REG,
+ * 300ns delay between access to ADDR_REG and DATA_REG
+ * OE, WE MUST NOT be changed during these intervals
+ */
+#if defined(UDELAY)
+#define isp116x_delay(h,d) udelay(d)
+#else
+#define isp116x_delay(h,d) do {} while (0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+ writew(reg & 0xff, isp116x->addr_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+ writew(val, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+ __raw_writew(val, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+ u16 val;
+
+ val = readw(isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+ u16 val;
+
+ val = __raw_readw(isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+ writew(val & 0xffff, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ writew(val >> 16, isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+ u32 val;
+
+ val = (u32) readw(isp116x->data_reg);
+ isp116x_delay(isp116x, UDELAY);
+ val |= ((u32) readw(isp116x->data_reg)) << 16;
+ isp116x_delay(isp116x, UDELAY);
+ return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+ we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+ unsigned val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+ unsigned val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_write_data32(isp116x, (u32) val);
+}
+
+/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
--- /dev/null
+/*
+ * (C) Copyright 2006
+ * DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT)
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/io.h>
+#include <asm/arch/at91_pmc.h>
+
+int usb_cpu_init(void)
+{
+
+#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
+ defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
+ /* Enable PLLB */
+ at91_sys_write(AT91_CKGR_PLLBR, CONFIG_SYS_AT91_PLLB);
+ while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
+ ;
+#endif
+
+ /* Enable USB host clock. */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_UHP);
+#ifdef CONFIG_AT91SAM9261
+ at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP | AT91_PMC_HCK0);
+#else
+ at91_sys_write(AT91_PMC_SCER, AT91_PMC_UHP);
+#endif
+
+ return 0;
+}
+
+int usb_cpu_stop(void)
+{
+ /* Disable USB host clock. */
+ at91_sys_write(AT91_PMC_PCDR, 1 << AT91_ID_UHP);
+#ifdef CONFIG_AT91SAM9261
+ at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_HCK0);
+#else
+ at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP);
+#endif
+
+#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
+ defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20)
+ /* Disable PLLB */
+ at91_sys_write(AT91_CKGR_PLLBR, 0);
+ while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != 0)
+ ;
+#endif
+
+ return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+ return usb_cpu_stop();
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) */
--- /dev/null
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
+ *
+ * Interrupt support is added. Now, it has been tested
+ * on ULI1575 chip and works well with USB keyboard.
+ *
+ * (C) Copyright 2007
+ * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
+ * ebenard@eukrea.com - based on s3c24x0's driver
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - Read doc/README.generic_usb_ohci
+ * 2 - this driver is intended for use with USB Mass Storage Devices
+ * (BBB) and USB keyboard. There is NO support for Isochronous pipes!
+ * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
+ * to activate workaround for bug #41 or this driver will NOT work!
+ */
+
+#include <common.h>
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCI_OHCI)
+# include <pci.h>
+#if !defined(CONFIG_PCI_OHCI_DEVNO)
+#define CONFIG_PCI_OHCI_DEVNO 0
+#endif
+#endif
+
+#include <malloc.h>
+#include <usb.h>
+
+#include "ohci.h"
+
+#ifdef CONFIG_AT91RM9200
+#include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */
+#endif
+
+#if defined(CONFIG_ARM920T) || \
+ defined(CONFIG_S3C2400) || \
+ defined(CONFIG_S3C2410) || \
+ defined(CONFIG_S3C6400) || \
+ defined(CONFIG_440EP) || \
+ defined(CONFIG_PCI_OHCI) || \
+ defined(CONFIG_MPC5200) || \
+ defined(CONFIG_SYS_OHCI_USE_NPS)
+# define OHCI_USE_NPS /* force NoPowerSwitching mode */
+#endif
+
+#undef OHCI_VERBOSE_DEBUG /* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+/*
+ * e.g. PCI controllers need this
+ */
+#ifdef CONFIG_SYS_OHCI_SWAP_REG_ACCESS
+# define readl(a) __swap_32(*((volatile u32 *)(a)))
+# define writel(a, b) (*((volatile u32 *)(b)) = __swap_32((volatile u32)a))
+#else
+# define readl(a) (*((volatile u32 *)(a)))
+# define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
+#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
+
+#define min_t(type, x, y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef CONFIG_PCI_OHCI
+static struct pci_device_id ohci_pci_ids[] = {
+ {0x10b9, 0x5237}, /* ULI1575 PCI OHCI module ids */
+ {0x1033, 0x0035}, /* NEC PCI OHCI module ids */
+ {0x1131, 0x1561}, /* Philips 1561 PCI OHCI module ids */
+ /* Please add supported PCI OHCI controller ids here */
+ {0, 0}
+};
+#endif
+
+#ifdef CONFIG_PCI_EHCI_DEVNO
+static struct pci_device_id ehci_pci_ids[] = {
+ {0x1131, 0x1562}, /* Philips 1562 PCI EHCI module ids */
+ /* Please add supported PCI EHCI controller ids here */
+ {0, 0}
+};
+#endif
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while (0)
+#endif
+
+#ifdef CONFIG_SYS_OHCI_BE_CONTROLLER
+# define m16_swap(x) cpu_to_be16(x)
+# define m32_swap(x) cpu_to_be32(x)
+#else
+# define m16_swap(x) cpu_to_le16(x)
+# define m32_swap(x) cpu_to_le32(x)
+#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* device which was disconnected */
+struct usb_device *devgone;
+
+static inline u32 roothub_a(struct ohci *hc)
+ { return readl(&hc->regs->roothub.a); }
+static inline u32 roothub_b(struct ohci *hc)
+ { return readl(&hc->regs->roothub.b); }
+static inline u32 roothub_status(struct ohci *hc)
+ { return readl(&hc->regs->roothub.status); }
+static inline u32 roothub_portstatus(struct ohci *hc, int i)
+ { return readl(&hc->regs->roothub.portstatus[i]); }
+
+/* forward declaration */
+static int hc_interrupt(void);
+static void td_submit_job(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *setup, urb_priv_t *urb,
+ int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv(urb_priv_t *urb)
+{
+ int i;
+ int last;
+ struct td *td;
+
+ last = urb->length - 1;
+ if (last >= 0) {
+ for (i = 0; i <= last; i++) {
+ td = urb->td[i];
+ if (td) {
+ td->usb_dev = NULL;
+ urb->td[i] = NULL;
+ }
+ }
+ }
+ free(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number(struct usb_device *dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int transfer_len,
+ struct devrequest *setup, char *str, int small)
+{
+ dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
+ str,
+ sohci_get_current_frame_number(dev),
+ usb_pipedevice(pipe),
+ usb_pipeendpoint(pipe),
+ usb_pipeout(pipe)? 'O': 'I',
+ usb_pipetype(pipe) < 2 ? \
+ (usb_pipeint(pipe)? "INTR": "ISOC"): \
+ (usb_pipecontrol(pipe)? "CTRL": "BULK"),
+ (purb ? purb->actual_length : 0),
+ transfer_len, dev->status);
+#ifdef OHCI_VERBOSE_DEBUG
+ if (!small) {
+ int i, len;
+
+ if (usb_pipecontrol(pipe)) {
+ printf(__FILE__ ": cmd(8):");
+ for (i = 0; i < 8 ; i++)
+ printf(" %02x", ((__u8 *) setup) [i]);
+ printf("\n");
+ }
+ if (transfer_len > 0 && buffer) {
+ printf(__FILE__ ": data(%d/%d):",
+ (purb ? purb->actual_length : 0),
+ transfer_len);
+ len = usb_pipeout(pipe)? transfer_len:
+ (purb ? purb->actual_length : 0);
+ for (i = 0; i < 16 && i < len; i++)
+ printf(" %02x", ((__u8 *) buffer) [i]);
+ printf("%s\n", i < len? "...": "");
+ }
+ }
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree
+ * inclusive iso eds */
+void ep_print_int_eds(ohci_t *ohci, char *str)
+{
+ int i, j;
+ __u32 *ed_p;
+ for (i = 0; i < 32; i++) {
+ j = 5;
+ ed_p = &(ohci->hcca->int_table [i]);
+ if (*ed_p == 0)
+ continue;
+ printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+ while (*ed_p != 0 && j--) {
+ ed_t *ed = (ed_t *)m32_swap(ed_p);
+ printf(" ed: %4x;", ed->hwINFO);
+ ed_p = &ed->hwNextED;
+ }
+ printf("\n");
+ }
+}
+
+static void ohci_dump_intr_mask(char *label, __u32 mask)
+{
+ dbg("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+ label,
+ mask,
+ (mask & OHCI_INTR_MIE) ? " MIE" : "",
+ (mask & OHCI_INTR_OC) ? " OC" : "",
+ (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+ (mask & OHCI_INTR_FNO) ? " FNO" : "",
+ (mask & OHCI_INTR_UE) ? " UE" : "",
+ (mask & OHCI_INTR_RD) ? " RD" : "",
+ (mask & OHCI_INTR_SF) ? " SF" : "",
+ (mask & OHCI_INTR_WDH) ? " WDH" : "",
+ (mask & OHCI_INTR_SO) ? " SO" : ""
+ );
+}
+
+static void maybe_print_eds(char *label, __u32 value)
+{
+ ed_t *edp = (ed_t *)value;
+
+ if (value) {
+ dbg("%s %08x", label, value);
+ dbg("%08x", edp->hwINFO);
+ dbg("%08x", edp->hwTailP);
+ dbg("%08x", edp->hwHeadP);
+ dbg("%08x", edp->hwNextED);
+ }
+}
+
+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 "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status(ohci_t *controller)
+{
+ struct ohci_regs *regs = controller->regs;
+ __u32 temp;
+
+ temp = readl(®s->revision) & 0xff;
+ if (temp != 0x10)
+ dbg("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+ temp = readl(®s->control);
+ dbg("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+ (temp & OHCI_CTRL_RWE) ? " RWE" : "",
+ (temp & OHCI_CTRL_RWC) ? " RWC" : "",
+ (temp & OHCI_CTRL_IR) ? " IR" : "",
+ hcfs2string(temp & OHCI_CTRL_HCFS),
+ (temp & OHCI_CTRL_BLE) ? " BLE" : "",
+ (temp & OHCI_CTRL_CLE) ? " CLE" : "",
+ (temp & OHCI_CTRL_IE) ? " IE" : "",
+ (temp & OHCI_CTRL_PLE) ? " PLE" : "",
+ temp & OHCI_CTRL_CBSR
+ );
+
+ temp = readl(®s->cmdstatus);
+ dbg("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+ (temp & OHCI_SOC) >> 16,
+ (temp & OHCI_OCR) ? " OCR" : "",
+ (temp & OHCI_BLF) ? " BLF" : "",
+ (temp & OHCI_CLF) ? " CLF" : "",
+ (temp & OHCI_HCR) ? " HCR" : ""
+ );
+
+ ohci_dump_intr_mask("intrstatus", readl(®s->intrstatus));
+ ohci_dump_intr_mask("intrenable", readl(®s->intrenable));
+
+ maybe_print_eds("ed_periodcurrent", readl(®s->ed_periodcurrent));
+
+ maybe_print_eds("ed_controlhead", readl(®s->ed_controlhead));
+ maybe_print_eds("ed_controlcurrent", readl(®s->ed_controlcurrent));
+
+ maybe_print_eds("ed_bulkhead", readl(®s->ed_bulkhead));
+ maybe_print_eds("ed_bulkcurrent", readl(®s->ed_bulkcurrent));
+
+ maybe_print_eds("donehead", readl(®s->donehead));
+}
+
+static void ohci_dump_roothub(ohci_t *controller, int verbose)
+{
+ __u32 temp, ndp, i;
+
+ temp = roothub_a(controller);
+ ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+ ndp = (ndp == 2) ? 1:0;
+#endif
+ if (verbose) {
+ dbg("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+ ((temp & RH_A_POTPGT) >> 24) & 0xff,
+ (temp & RH_A_NOCP) ? " NOCP" : "",
+ (temp & RH_A_OCPM) ? " OCPM" : "",
+ (temp & RH_A_DT) ? " DT" : "",
+ (temp & RH_A_NPS) ? " NPS" : "",
+ (temp & RH_A_PSM) ? " PSM" : "",
+ ndp
+ );
+ temp = roothub_b(controller);
+ dbg("roothub.b: %08x PPCM=%04x DR=%04x",
+ temp,
+ (temp & RH_B_PPCM) >> 16,
+ (temp & RH_B_DR)
+ );
+ temp = roothub_status(controller);
+ dbg("roothub.status: %08x%s%s%s%s%s%s",
+ temp,
+ (temp & RH_HS_CRWE) ? " CRWE" : "",
+ (temp & RH_HS_OCIC) ? " OCIC" : "",
+ (temp & RH_HS_LPSC) ? " LPSC" : "",
+ (temp & RH_HS_DRWE) ? " DRWE" : "",
+ (temp & RH_HS_OCI) ? " OCI" : "",
+ (temp & RH_HS_LPS) ? " LPS" : ""
+ );
+ }
+
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus(controller, i);
+ dbg("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+ i,
+ temp,
+ (temp & RH_PS_PRSC) ? " PRSC" : "",
+ (temp & RH_PS_OCIC) ? " OCIC" : "",
+ (temp & RH_PS_PSSC) ? " PSSC" : "",
+ (temp & RH_PS_PESC) ? " PESC" : "",
+ (temp & RH_PS_CSC) ? " CSC" : "",
+
+ (temp & RH_PS_LSDA) ? " LSDA" : "",
+ (temp & RH_PS_PPS) ? " PPS" : "",
+ (temp & RH_PS_PRS) ? " PRS" : "",
+ (temp & RH_PS_POCI) ? " POCI" : "",
+ (temp & RH_PS_PSS) ? " PSS" : "",
+
+ (temp & RH_PS_PES) ? " PES" : "",
+ (temp & RH_PS_CCS) ? " CCS" : ""
+ );
+ }
+}
+
+static void ohci_dump(ohci_t *controller, int verbose)
+{
+ dbg("OHCI controller usb-%s state", controller->slot_name);
+
+ /* dumps some of the state we know about */
+ ohci_dump_status(controller);
+ if (verbose)
+ ep_print_int_eds(controller, "hcca");
+ dbg("hcca frame #%04x", controller->hcca->frame_no);
+ ohci_dump_roothub(controller, 1);
+}
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
+{
+ ohci_t *ohci;
+ ed_t *ed;
+ urb_priv_t *purb_priv = urb;
+ int i, size = 0;
+ struct usb_device *dev = urb->dev;
+ unsigned long pipe = urb->pipe;
+ void *buffer = urb->transfer_buffer;
+ int transfer_len = urb->transfer_buffer_length;
+ int interval = urb->interval;
+
+ ohci = &gohci;
+
+ /* when controller's hung, permit only roothub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled) {
+ err("sohci_submit_job: EPIPE");
+ return -1;
+ }
+
+ /* we're about to begin a new transaction here so mark the
+ * URB unfinished */
+ urb->finished = 0;
+
+ /* every endpoint has a ed, locate and fill it */
+ ed = ep_add_ed(dev, pipe, interval, 1);
+ if (!ed) {
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+
+ /* for the private part of the URB we need the number of TDs (size) */
+ switch (usb_pipetype(pipe)) {
+ case PIPE_BULK: /* one TD for every 4096 Byte */
+ size = (transfer_len - 1) / 4096 + 1;
+ break;
+ case PIPE_CONTROL:/* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+ size = (transfer_len == 0)? 2:
+ (transfer_len - 1) / 4096 + 3;
+ break;
+ case PIPE_INTERRUPT: /* 1 TD */
+ size = 1;
+ break;
+ }
+
+ ed->purb = urb;
+
+ if (size >= (N_URB_TD - 1)) {
+ err("need %d TDs, only have %d", size, N_URB_TD);
+ return -1;
+ }
+ purb_priv->pipe = pipe;
+
+ /* fill the private part of the URB */
+ purb_priv->length = size;
+ purb_priv->ed = ed;
+ purb_priv->actual_length = 0;
+
+ /* allocate the TDs */
+ /* note that td[0] was allocated in ep_add_ed */
+ for (i = 0; i < size; i++) {
+ purb_priv->td[i] = td_alloc(dev);
+ if (!purb_priv->td[i]) {
+ purb_priv->length = i;
+ urb_free_priv(purb_priv);
+ err("sohci_submit_job: ENOMEM");
+ return -1;
+ }
+ }
+
+ if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+ urb_free_priv(purb_priv);
+ err("sohci_submit_job: EINVAL");
+ return -1;
+ }
+
+ /* link the ed into a chain if is not already */
+ if (ed->state != ED_OPER)
+ ep_link(ohci, ed);
+
+ /* fill the TDs and link it to the ed */
+ td_submit_job(dev, pipe, buffer, transfer_len,
+ setup, purb_priv, interval);
+
+ return 0;
+}
+
+static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
+{
+ struct ohci_regs *regs = hc->regs;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ /* implicitly requeued */
+ if (urb->dev->irq_handle &&
+ (urb->dev->irq_act_len = urb->actual_length)) {
+ writel(OHCI_INTR_WDH, ®s->intrenable);
+ readl(®s->intrenable); /* PCI posting flush */
+ urb->dev->irq_handle(urb->dev);
+ writel(OHCI_INTR_WDH, ®s->intrdisable);
+ readl(®s->intrdisable); /* PCI posting flush */
+ }
+ urb->actual_length = 0;
+ td_submit_job(
+ urb->dev,
+ urb->pipe,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ NULL,
+ urb,
+ urb->interval);
+ break;
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number(struct usb_device *usb_dev)
+{
+ ohci_t *ohci = &gohci;
+
+ return m16_swap(ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* search for the right branch to insert an interrupt ed into the int tree
+ * do some load ballancing;
+ * returns the branch and
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance(ohci_t *ohci, int interval, int load)
+{
+ int i, branch = 0;
+
+ /* search for the least loaded interrupt endpoint
+ * branch of all 32 branches
+ */
+ for (i = 0; i < 32; i++)
+ if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+ branch = i;
+
+ branch = branch % interval;
+ for (i = branch; i < 32; i += interval)
+ ohci->ohci_int_load [i] += load;
+
+ return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* 2^int( ld (inter)) */
+
+static int ep_2_n_interval(int inter)
+{
+ int i;
+ for (i = 0; ((inter >> i) > 1) && (i < 5); i++);
+ return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree
+ * in order to process it sequentially the indexes of the branches have to
+ * be mapped the mapping reverses the bits of a word of num_bits length */
+static int ep_rev(int num_bits, int word)
+{
+ int i, wout = 0;
+
+ for (i = 0; i < num_bits; i++)
+ wout |= (((word >> i) & 1) << (num_bits - i - 1));
+ return wout;
+}
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link(ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+ int int_branch;
+ int i;
+ int inter;
+ int interval;
+ int load;
+ __u32 *ed_p;
+
+ ed->state = ED_OPER;
+ ed->int_interval = 0;
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ed->hwNextED = 0;
+ if (ohci->ed_controltail == NULL)
+ writel(ed, &ohci->regs->ed_controlhead);
+ else
+ ohci->ed_controltail->hwNextED =
+ m32_swap((unsigned long)ed);
+
+ ed->ed_prev = ohci->ed_controltail;
+ if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_CLE;
+ writel(ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_controltail = edi;
+ break;
+
+ case PIPE_BULK:
+ ed->hwNextED = 0;
+ if (ohci->ed_bulktail == NULL)
+ writel(ed, &ohci->regs->ed_bulkhead);
+ else
+ ohci->ed_bulktail->hwNextED =
+ m32_swap((unsigned long)ed);
+
+ ed->ed_prev = ohci->ed_bulktail;
+ if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
+ ohci->hc_control |= OHCI_CTRL_BLE;
+ writel(ohci->hc_control, &ohci->regs->control);
+ }
+ ohci->ed_bulktail = edi;
+ break;
+
+ case PIPE_INTERRUPT:
+ load = ed->int_load;
+ interval = ep_2_n_interval(ed->int_period);
+ ed->int_interval = interval;
+ int_branch = ep_int_ballance(ohci, interval, load);
+ ed->int_branch = int_branch;
+
+ for (i = 0; i < ep_rev(6, interval); i += inter) {
+ inter = 1;
+ for (ed_p = &(ohci->hcca->int_table[\
+ ep_rev(5, i) + int_branch]);
+ (*ed_p != 0) &&
+ (((ed_t *)ed_p)->int_interval >= interval);
+ ed_p = &(((ed_t *)ed_p)->hwNextED))
+ inter = ep_rev(6,
+ ((ed_t *)ed_p)->int_interval);
+ ed->hwNextED = *ed_p;
+ *ed_p = m32_swap((unsigned long)ed);
+ }
+ break;
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
+ unsigned index, unsigned period)
+{
+ for (; index < NUM_INTS; index += period) {
+ __u32 *ed_p = &ohci->hcca->int_table [index];
+
+ /* ED might have been unlinked through another path */
+ while (*ed_p != 0) {
+ if (((struct ed *)
+ m32_swap((unsigned long)ed_p)) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ ed_p = &(((struct ed *)
+ m32_swap((unsigned long)ed_p))->hwNextED);
+ }
+ }
+}
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink(ohci_t *ohci, ed_t *edi)
+{
+ volatile ed_t *ed = edi;
+ int i;
+
+ ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
+
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_CLE;
+ writel(ohci->hc_control, &ohci->regs->control);
+ }
+ writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+ &ohci->regs->ed_controlhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_controltail == ed) {
+ ohci->ed_controltail = ed->ed_prev;
+ } else {
+ ((ed_t *)m32_swap(
+ *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_BULK:
+ if (ed->ed_prev == NULL) {
+ if (!ed->hwNextED) {
+ ohci->hc_control &= ~OHCI_CTRL_BLE;
+ writel(ohci->hc_control, &ohci->regs->control);
+ }
+ writel(m32_swap(*((__u32 *)&ed->hwNextED)),
+ &ohci->regs->ed_bulkhead);
+ } else {
+ ed->ed_prev->hwNextED = ed->hwNextED;
+ }
+ if (ohci->ed_bulktail == ed) {
+ ohci->ed_bulktail = ed->ed_prev;
+ } else {
+ ((ed_t *)m32_swap(
+ *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ periodic_unlink(ohci, ed, 0, 1);
+ for (i = ed->int_branch; i < 32; i += ed->int_interval)
+ ohci->ohci_int_load[i] -= ed->int_load;
+ break;
+ }
+ ed->state = ED_UNLINK;
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the
+ * usb_set_configuration command, but the USB stack is a little bit
+ * stateless so we do it at every transaction if the state of the ed
+ * is ED_NEW then a dummy td is added and the state is changed to
+ * ED_UNLINK in all other cases the state is left unchanged the ed
+ * info fields are setted anyway even though most of them should not
+ * change
+ */
+static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
+ int interval, int load)
+{
+ td_t *td;
+ ed_t *ed_ret;
+ volatile ed_t *ed;
+
+ ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
+ (usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
+
+ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+ err("ep_add_ed: pending delete");
+ /* pending delete request */
+ return NULL;
+ }
+
+ if (ed->state == ED_NEW) {
+ /* dummy td; end of td list for ed */
+ td = td_alloc(usb_dev);
+ ed->hwTailP = m32_swap((unsigned long)td);
+ ed->hwHeadP = ed->hwTailP;
+ ed->state = ED_UNLINK;
+ ed->type = usb_pipetype(pipe);
+ ohci_dev.ed_cnt++;
+ }
+
+ ed->hwINFO = m32_swap(usb_pipedevice(pipe)
+ | usb_pipeendpoint(pipe) << 7
+ | (usb_pipeisoc(pipe)? 0x8000: 0)
+ | (usb_pipecontrol(pipe)? 0: \
+ (usb_pipeout(pipe)? 0x800: 0x1000))
+ | usb_pipeslow(pipe) << 13
+ | usb_maxpacket(usb_dev, pipe) << 16);
+
+ if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+ ed->int_period = interval;
+ ed->int_load = load;
+ }
+
+ return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill(ohci_t *ohci, unsigned int info,
+ void *data, int len,
+ struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+ volatile td_t *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+ int i;
+#endif
+
+ if (index > urb_priv->length) {
+ err("index > length");
+ return;
+ }
+ /* use this td as the next dummy */
+ td_pt = urb_priv->td [index];
+ td_pt->hwNextTD = 0;
+
+ /* fill the old dummy TD */
+ td = urb_priv->td [index] =
+ (td_t *)(m32_swap(urb_priv->ed->hwTailP) & ~0xf);
+
+ td->ed = urb_priv->ed;
+ td->next_dl_td = NULL;
+ td->index = index;
+ td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+ if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
+ for (i = 0; i < len; i++)
+ printf("td->data[%d] %#2x ", i, ((unsigned char *)td->data)[i]);
+ printf("\n");
+ }
+#endif
+ if (!len)
+ data = 0;
+
+ td->hwINFO = m32_swap(info);
+ td->hwCBP = m32_swap((unsigned long)data);
+ if (data)
+ td->hwBE = m32_swap((unsigned long)(data + len - 1));
+ else
+ td->hwBE = 0;
+
+ td->hwNextTD = m32_swap((unsigned long)td_pt);
+
+ /* append to queue */
+ td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_job(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len,
+ struct devrequest *setup, urb_priv_t *urb,
+ int interval)
+{
+ ohci_t *ohci = &gohci;
+ int data_len = transfer_len;
+ void *data;
+ int cnt = 0;
+ __u32 info = 0;
+ unsigned int toggle = 0;
+
+ /* OHCI handles the DATA-toggles itself, we just use the USB-toggle
+ * bits for reseting */
+ if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+ toggle = TD_T_TOGGLE;
+ } else {
+ toggle = TD_T_DATA0;
+ usb_settoggle(dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), 1);
+ }
+ urb->td_cnt = 0;
+ if (data_len)
+ data = buffer;
+ else
+ data = 0;
+
+ switch (usb_pipetype(pipe)) {
+ case PIPE_BULK:
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+ while (data_len > 4096) {
+ td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle),
+ data, 4096, dev, cnt, urb);
+ data += 4096; data_len -= 4096; cnt++;
+ }
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+ td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle), data,
+ data_len, dev, cnt, urb);
+ cnt++;
+
+ if (!ohci->sleeping) {
+ /* start bulk list */
+ writel(OHCI_BLF, &ohci->regs->cmdstatus);
+ }
+ break;
+
+ case PIPE_CONTROL:
+ /* Setup phase */
+ info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+ td_fill(ohci, info, setup, 8, dev, cnt++, urb);
+
+ /* Optional Data phase */
+ if (data_len > 0) {
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 :
+ TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+ /* NOTE: mishandles transfers >8K, some >4K */
+ td_fill(ohci, info, data, data_len, dev, cnt++, urb);
+ }
+
+ /* Status phase */
+ info = usb_pipeout(pipe)?
+ TD_CC | TD_DP_IN | TD_T_DATA1:
+ TD_CC | TD_DP_OUT | TD_T_DATA1;
+ td_fill(ohci, info, data, 0, dev, cnt++, urb);
+
+ if (!ohci->sleeping) {
+ /* start Control list */
+ writel(OHCI_CLF, &ohci->regs->cmdstatus);
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ info = usb_pipeout(urb->pipe)?
+ TD_CC | TD_DP_OUT | toggle:
+ TD_CC | TD_R | TD_DP_IN | toggle;
+ td_fill(ohci, info, data, data_len, dev, cnt++, urb);
+ break;
+ }
+ if (urb->length != cnt)
+ dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t *td)
+{
+ __u32 tdINFO, tdBE, tdCBP;
+ urb_priv_t *lurb_priv = td->ed->purb;
+
+ tdINFO = m32_swap(td->hwINFO);
+ tdBE = m32_swap(td->hwBE);
+ tdCBP = m32_swap(td->hwCBP);
+
+ if (!(usb_pipecontrol(lurb_priv->pipe) &&
+ ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+ if (tdBE != 0) {
+ if (td->hwCBP == 0)
+ lurb_priv->actual_length += tdBE - td->data + 1;
+ else
+ lurb_priv->actual_length += tdCBP - td->data;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+static void check_status(td_t *td_list)
+{
+ urb_priv_t *lurb_priv = td_list->ed->purb;
+ int urb_len = lurb_priv->length;
+ __u32 *phwHeadP = &td_list->ed->hwHeadP;
+ int cc;
+
+ cc = TD_CC_GET(m32_swap(td_list->hwINFO));
+ if (cc) {
+ err(" USB-error: %s (%x)", cc_to_string[cc], cc);
+
+ if (*phwHeadP & m32_swap(0x1)) {
+ if (lurb_priv &&
+ ((td_list->index + 1) < urb_len)) {
+ *phwHeadP =
+ (lurb_priv->td[urb_len - 1]->hwNextTD &\
+ m32_swap(0xfffffff0)) |
+ (*phwHeadP & m32_swap(0x2));
+
+ lurb_priv->td_cnt += urb_len -
+ td_list->index - 1;
+ } else
+ *phwHeadP &= m32_swap(0xfffffff2);
+ }
+#ifdef CONFIG_MPC5200
+ td_list->hwNextTD = 0;
+#endif
+ }
+}
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+static td_t *dl_reverse_done_list(ohci_t *ohci)
+{
+ __u32 td_list_hc;
+ td_t *td_rev = NULL;
+ td_t *td_list = NULL;
+
+ td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
+ ohci->hcca->done_head = 0;
+
+ while (td_list_hc) {
+ td_list = (td_t *)td_list_hc;
+ check_status(td_list);
+ td_list->next_dl_td = td_rev;
+ td_rev = td_list;
+ td_list_hc = m32_swap(td_list->hwNextTD) & 0xfffffff0;
+ }
+ return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+
+static void finish_urb(ohci_t *ohci, urb_priv_t *urb, int status)
+{
+ if ((status & (ED_OPER | ED_UNLINK)) && (urb->state != URB_DEL))
+ urb->finished = sohci_return_job(ohci, urb);
+ else
+ dbg("finish_urb: strange.., ED state %x, \n", status);
+}
+
+/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames). This bug has been observed on ZF Micro systems.
+ */
+static int takeback_td(ohci_t *ohci, td_t *td_list)
+{
+ ed_t *ed;
+ int cc;
+ int stat = 0;
+ /* urb_t *urb; */
+ urb_priv_t *lurb_priv;
+ __u32 tdINFO, edHeadP, edTailP;
+
+ tdINFO = m32_swap(td_list->hwINFO);
+
+ ed = td_list->ed;
+ lurb_priv = ed->purb;
+
+ dl_transfer_length(td_list);
+
+ lurb_priv->td_cnt++;
+
+ /* error code of transfer */
+ cc = TD_CC_GET(tdINFO);
+ if (cc) {
+ err("USB-error: %s (%x)", cc_to_string[cc], cc);
+ stat = cc_to_error[cc];
+ }
+
+ /* see if this done list makes for all TD's of current URB,
+ * and mark the URB finished if so */
+ if (lurb_priv->td_cnt == lurb_priv->length)
+ finish_urb(ohci, lurb_priv, ed->state);
+
+ dbg("dl_done_list: processing TD %x, len %x\n",
+ lurb_priv->td_cnt, lurb_priv->length);
+
+ if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
+ edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
+ edTailP = m32_swap(ed->hwTailP);
+
+ /* unlink eds if they are not busy */
+ if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+ ep_unlink(ohci, ed);
+ }
+ return stat;
+}
+
+static int dl_done_list(ohci_t *ohci)
+{
+ int stat = 0;
+ td_t *td_list = dl_reverse_done_list(ohci);
+
+ while (td_list) {
+ td_t *td_next = td_list->next_dl_td;
+ stat = takeback_td(ohci, td_list);
+ td_list = td_next;
+ }
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 28, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'O', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'C', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'I', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x) {info("WR:status %#8x", (x)); writel((x), \
+ &gohci.regs->roothub.status); }
+#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \
+ (x)); writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
+#else
+#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), \
+ &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT roothub_status(&gohci)
+#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+ __u32 temp, ndp, i;
+ int res;
+
+ res = -1;
+ temp = roothub_a(controller);
+ ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+ ndp = (ndp == 2) ? 1:0;
+#endif
+ for (i = 0; i < ndp; i++) {
+ temp = roothub_portstatus(controller, i);
+ /* check for a device disconnect */
+ if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+ (RH_PS_PESC | RH_PS_CSC)) &&
+ ((temp & RH_PS_CCS) == 0)) {
+ res = i;
+ break;
+ }
+ }
+ return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ void *data = buffer;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u32 datab[4];
+ __u8 *data_buf = (__u8 *)datab;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+#ifdef DEBUG
+pkt_print(NULL, dev, pipe, buffer, transfer_len,
+ cmd, "SUB(rh)", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if (usb_pipeint(pipe)) {
+ info("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = le16_to_cpu(cmd->value);
+ wIndex = le16_to_cpu(cmd->index);
+ wLength = le16_to_cpu(cmd->length);
+
+ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+ dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *) data_buf = cpu_to_le16(1);
+ OK(2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *) data_buf = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *) data_buf = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *) data_buf = cpu_to_le32(
+ RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+ OK(4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
+ OK(4);
+
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case (RH_ENDPOINT_STALL):
+ OK(0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_LOCAL_POWER:
+ OK(0);
+ case (RH_C_HUB_OVER_CURRENT):
+ WR_RH_STAT(RH_HS_OCIC);
+ OK(0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_CCS); OK(0);
+ case (RH_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_POCI); OK(0);
+ case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_LSDA); OK(0);
+ case (RH_C_PORT_CONNECTION): WR_RH_PORTSTAT(RH_PS_CSC); OK(0);
+ case (RH_C_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_PESC); OK(0);
+ case (RH_C_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_PSSC); OK(0);
+ case (RH_C_PORT_OVER_CURRENT):WR_RH_PORTSTAT(RH_PS_OCIC); OK(0);
+ case (RH_C_PORT_RESET): WR_RH_PORTSTAT(RH_PS_PRSC); OK(0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ WR_RH_PORTSTAT(RH_PS_PSS); OK(0);
+ case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT(RH_PS_PRS);
+ OK(0);
+ case (RH_PORT_POWER):
+ WR_RH_PORTSTAT(RH_PS_PPS);
+ wait_ms(100);
+ OK(0);
+ case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+ if (RD_RH_PORTSTAT & RH_PS_CCS)
+ WR_RH_PORTSTAT(RH_PS_PES);
+ OK(0);
+ }
+ break;
+
+ case RH_SET_ADDRESS:
+ gohci.rh.devnum = wValue;
+ OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ data_buf = root_hub_dev_des; OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ data_buf = root_hub_config_des; OK(len);
+ case (0x03): /* string descriptors */
+ if (wValue == 0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ data_buf = root_hub_str_index0;
+ OK(len);
+ }
+ if (wValue == 0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ data_buf = root_hub_str_index1;
+ OK(len);
+ }
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = roothub_a(&gohci);
+
+ data_buf [0] = 9; /* min length; */
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+ data_buf [2] = (data_buf [2] == 2) ? 1:0;
+#endif
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ /* corresponds to data_buf[4-7] */
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = roothub_b(&gohci);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data_buf [0], wLength));
+ OK(len);
+ }
+
+ case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK(1);
+
+ case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0);
+
+ default:
+ dbg("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+#ifdef DEBUG
+ ohci_dump_roothub(&gohci, 1);
+#else
+ wait_ms(1);
+#endif
+
+ len = min_t(int, len, leni);
+ if (data != data_buf)
+ memcpy(data, data_buf, len);
+ dev->act_len = len;
+ dev->status = stat;
+
+#ifdef DEBUG
+ pkt_print(NULL, dev, pipe, buffer,
+ transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#else
+ wait_ms(1);
+#endif
+
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup, int interval)
+{
+ int stat = 0;
+ int maxsize = usb_maxpacket(dev, pipe);
+ int timeout;
+ urb_priv_t *urb;
+
+ urb = malloc(sizeof(urb_priv_t));
+ memset(urb, 0, sizeof(urb_priv_t));
+
+ urb->dev = dev;
+ urb->pipe = pipe;
+ urb->transfer_buffer = buffer;
+ urb->transfer_buffer_length = transfer_len;
+ urb->interval = interval;
+
+ /* device pulled? Shortcut the action. */
+ if (devgone == dev) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+
+#ifdef DEBUG
+ urb->actual_length = 0;
+ pkt_print(urb, dev, pipe, buffer, transfer_len,
+ setup, "SUB", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if (!maxsize) {
+ err("submit_common_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+
+ if (sohci_submit_job(urb, setup) < 0) {
+ err("sohci_submit_job failed");
+ return -1;
+ }
+
+#if 0
+ wait_ms(10);
+ /* ohci_dump_status(&gohci); */
+#endif
+
+ /* allow more time for a BULK device to react - some are slow */
+#define BULK_TO 5000 /* timeout in milliseconds */
+ if (usb_pipebulk(pipe))
+ timeout = BULK_TO;
+ else
+ timeout = 100;
+
+ /* wait for it to complete */
+ for (;;) {
+ /* check whether the controller is done */
+ stat = hc_interrupt();
+ if (stat < 0) {
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+
+ /* NOTE: since we are not interrupt driven in U-Boot and always
+ * handle only one URB at a time, we cannot assume the
+ * transaction finished on the first successful return from
+ * hc_interrupt().. unless the flag for current URB is set,
+ * meaning that all TD's to/from device got actually
+ * transferred and processed. If the current URB is not
+ * finished we need to re-iterate this loop so as
+ * hc_interrupt() gets called again as there needs to be some
+ * more TD's to process still */
+ if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+
+ if (--timeout) {
+ wait_ms(1);
+ if (!urb->finished)
+ dbg("*");
+
+ } else {
+ err("CTL:TIMEOUT ");
+ dbg("submit_common_msg: TO status %x\n", stat);
+ urb->finished = 1;
+ stat = USB_ST_CRC_ERR;
+ break;
+ }
+ }
+
+ dev->status = stat;
+ dev->act_len = transfer_len;
+
+#ifdef DEBUG
+ pkt_print(urb, dev, pipe, buffer, transfer_len,
+ setup, "RET(ctlr)", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+
+ /* free TDs in urb_priv */
+ if (!usb_pipeint(pipe))
+ urb_free_priv(urb);
+ return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ info("submit_bulk_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, struct devrequest *setup)
+{
+ int maxsize = usb_maxpacket(dev, pipe);
+
+ info("submit_control_msg");
+#ifdef DEBUG
+ pkt_print(NULL, dev, pipe, buffer, transfer_len,
+ setup, "SUB", usb_pipein(pipe));
+#else
+ wait_ms(1);
+#endif
+ if (!maxsize) {
+ err("submit_control_message: pipesize for pipe %lx is zero",
+ pipe);
+ return -1;
+ }
+ if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+ gohci.rh.dev = dev;
+ /* root hub - redirect */
+ return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+ }
+
+ return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ info("submit_int_msg");
+ return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
+ interval);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset(ohci_t *ohci)
+{
+#ifdef CONFIG_PCI_EHCI_DEVNO
+ pci_dev_t pdev;
+#endif
+ int timeout = 30;
+ int smm_timeout = 50; /* 0,5 sec */
+
+ dbg("%s\n", __FUNCTION__);
+
+#ifdef CONFIG_PCI_EHCI_DEVNO
+ /*
+ * Some multi-function controllers (e.g. ISP1562) allow root hub
+ * resetting via EHCI registers only.
+ */
+ pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVNO);
+ if (pdev != -1) {
+ u32 base;
+ int timeout = 1000;
+
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+ writel(readl(base + EHCI_USBCMD_OFF) | EHCI_USBCMD_HCRESET,
+ base + EHCI_USBCMD_OFF);
+
+ while (readl(base + EHCI_USBCMD_OFF) & EHCI_USBCMD_HCRESET) {
+ if (timeout-- <= 0) {
+ printf("USB RootHub reset timed out!");
+ break;
+ }
+ udelay(1);
+ }
+ } else
+ printf("No EHCI func at %d index!\n", CONFIG_PCI_EHCI_DEVNO);
+#endif
+ if (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+ /* SMM owns the HC */
+ writel(OHCI_OCR, &ohci->regs->cmdstatus);/* request ownership */
+ info("USB HC TakeOver from SMM");
+ while (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
+ wait_ms(10);
+ if (--smm_timeout == 0) {
+ err("USB HC TakeOver failed!");
+ return -1;
+ }
+ }
+ }
+
+ /* Disable HC interrupts */
+ writel(OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+ dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
+ ohci->slot_name,
+ readl(&ohci->regs->control));
+
+ /* Reset USB (needed by some controllers) */
+ ohci->hc_control = 0;
+ writel(ohci->hc_control, &ohci->regs->control);
+
+ /* HC Reset requires max 10 us delay */
+ writel(OHCI_HCR, &ohci->regs->cmdstatus);
+ while ((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+ if (--timeout == 0) {
+ err("USB HC reset timed out!");
+ return -1;
+ }
+ udelay(1);
+ }
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start(ohci_t *ohci)
+{
+ __u32 mask;
+ unsigned int fminterval;
+
+ ohci->disabled = 1;
+
+ /* Tell the controller where the control and bulk lists are
+ * The lists are empty now. */
+
+ writel(0, &ohci->regs->ed_controlhead);
+ writel(0, &ohci->regs->ed_bulkhead);
+
+ writel((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+ fminterval = 0x2edf;
+ writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
+ fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+ writel(fminterval, &ohci->regs->fminterval);
+ writel(0x628, &ohci->regs->lsthresh);
+
+ /* start controller operations */
+ ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci->disabled = 0;
+ writel(ohci->hc_control, &ohci->regs->control);
+
+ /* disable all interrupts */
+ mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+ OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+ OHCI_INTR_OC | OHCI_INTR_MIE);
+ writel(mask, &ohci->regs->intrdisable);
+ /* clear all interrupts */
+ mask &= ~OHCI_INTR_MIE;
+ writel(mask, &ohci->regs->intrstatus);
+ /* Choose the interrupts we care about now - but w/o MIE */
+ mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ writel(mask, &ohci->regs->intrenable);
+
+#ifdef OHCI_USE_NPS
+ /* required for AMD-756 and some Mac platforms */
+ writel((roothub_a(ohci) | RH_A_NPS) & ~RH_A_PSM,
+ &ohci->regs->roothub.a);
+ writel(RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif /* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
+ /* POTPGT delay is bits 24-31, in 2 ms units. */
+ mdelay((roothub_a(ohci) >> 23) & 0x1fe);
+
+ /* connect the virtual root hub */
+ ohci->rh.devnum = 0;
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Poll USB interrupt. */
+void usb_event_poll(void)
+{
+ hc_interrupt();
+}
+
+/* an interrupt happens */
+
+static int hc_interrupt(void)
+{
+ ohci_t *ohci = &gohci;
+ struct ohci_regs *regs = ohci->regs;
+ int ints;
+ int stat = -1;
+
+ if ((ohci->hcca->done_head != 0) &&
+ !(m32_swap(ohci->hcca->done_head) & 0x01)) {
+ ints = OHCI_INTR_WDH;
+ } else {
+ ints = readl(®s->intrstatus);
+ if (ints == ~(u32)0) {
+ ohci->disabled++;
+ err("%s device removed!", ohci->slot_name);
+ return -1;
+ } else {
+ ints &= readl(®s->intrenable);
+ if (ints == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+ }
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints,
+ le16_to_cpu(ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC)
+ stat = 0xff;
+
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err("OHCI Unrecoverable Error, controller usb-%s disabled",
+ ohci->slot_name);
+ /* e.g. due to PCI Master/Target Abort */
+
+#ifdef DEBUG
+ ohci_dump(ohci, 1);
+#else
+ wait_ms(1);
+#endif
+ /* FIXME: be optimistic, hope that bug won't repeat often. */
+ /* Make some non-interrupt context restart the controller. */
+ /* Count and limit the retries though; either hardware or */
+ /* software errors can go forever... */
+ hc_reset(ohci);
+ return -1;
+ }
+
+ if (ints & OHCI_INTR_WDH) {
+ wait_ms(1);
+ writel(OHCI_INTR_WDH, ®s->intrdisable);
+ (void)readl(®s->intrdisable); /* flush */
+ stat = dl_done_list(&gohci);
+ writel(OHCI_INTR_WDH, ®s->intrenable);
+ (void)readl(®s->intrdisable); /* flush */
+ }
+
+ if (ints & OHCI_INTR_SO) {
+ dbg("USB Schedule overrun\n");
+ writel(OHCI_INTR_SO, ®s->intrenable);
+ stat = -1;
+ }
+
+ /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
+ if (ints & OHCI_INTR_SF) {
+ unsigned int frame = m16_swap(ohci->hcca->frame_no) & 1;
+ wait_ms(1);
+ writel(OHCI_INTR_SF, ®s->intrdisable);
+ if (ohci->ed_rm_list[frame] != NULL)
+ writel(OHCI_INTR_SF, ®s->intrenable);
+ stat = 0xff;
+ }
+
+ writel(ints, ®s->intrstatus);
+ return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci(ohci_t *ohci)
+{
+ dbg("USB HC release ohci usb-%s", ohci->slot_name);
+
+ if (!ohci->disabled)
+ hc_reset(ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+#ifdef CONFIG_PCI_OHCI
+ pci_dev_t pdev;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+ /* cpu dependant init */
+ if (usb_cpu_init())
+ return -1;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+ /* board dependant init */
+ if (usb_board_init())
+ return -1;
+#endif
+ memset(&gohci, 0, sizeof(ohci_t));
+
+ /* align the storage */
+ if ((__u32)&ghcca[0] & 0xff) {
+ err("HCCA not aligned!!");
+ return -1;
+ }
+ phcca = &ghcca[0];
+ info("aligned ghcca %p", phcca);
+ memset(&ohci_dev, 0, sizeof(struct ohci_device));
+ if ((__u32)&ohci_dev.ed[0] & 0x7) {
+ err("EDs not aligned!!");
+ return -1;
+ }
+ memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+ if ((__u32)gtd & 0x7) {
+ err("TDs not aligned!!");
+ return -1;
+ }
+ ptd = gtd;
+ gohci.hcca = phcca;
+ memset(phcca, 0, sizeof(struct ohci_hcca));
+
+ gohci.disabled = 1;
+ gohci.sleeping = 0;
+ gohci.irq = -1;
+#ifdef CONFIG_PCI_OHCI
+ pdev = pci_find_devices(ohci_pci_ids, CONFIG_PCI_OHCI_DEVNO);
+
+ if (pdev != -1) {
+ u16 vid, did;
+ u32 base;
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
+ printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
+ vid, did, (pdev >> 16) & 0xff,
+ (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+ printf("OHCI regs address 0x%08x\n", base);
+ gohci.regs = (struct ohci_regs *)base;
+ } else
+ return -1;
+#else
+ gohci.regs = (struct ohci_regs *)CONFIG_SYS_USB_OHCI_REGS_BASE;
+#endif
+
+ gohci.flags = 0;
+ gohci.slot_name = CONFIG_SYS_USB_OHCI_SLOT_NAME;
+
+ if (hc_reset (&gohci) < 0) {
+ hc_release_ohci (&gohci);
+ err ("can't reset usb-%s", gohci.slot_name);
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+ /* board dependant cleanup */
+ usb_board_init_fail();
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+ /* cpu dependant cleanup */
+ usb_cpu_init_fail();
+#endif
+ return -1;
+ }
+
+ if (hc_start(&gohci) < 0) {
+ err("can't start usb-%s", gohci.slot_name);
+ hc_release_ohci(&gohci);
+ /* Initialization failed */
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+ /* board dependant cleanup */
+ usb_board_stop();
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+ /* cpu dependant cleanup */
+ usb_cpu_stop();
+#endif
+ return -1;
+ }
+
+#ifdef DEBUG
+ ohci_dump(&gohci, 1);
+#else
+ wait_ms(1);
+#endif
+ ohci_inited = 1;
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ /* this gets called really early - before the controller has */
+ /* even been initialized! */
+ if (!ohci_inited)
+ return 0;
+ /* TODO release any interrupts, etc. */
+ /* call hc_release_ohci() here ? */
+ hc_reset(&gohci);
+
+#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
+ /* board dependant cleanup */
+ if (usb_board_stop())
+ return -1;
+#endif
+
+#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
+ /* cpu dependant cleanup */
+ if (usb_cpu_stop())
+ return -1;
+#endif
+ /* This driver is no longer initialised. It needs a new low-level
+ * init (board/cpu) before it can be used again. */
+ ohci_inited = 0;
+ return 0;
+}
--- /dev/null
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+/* functions for doing board or CPU specific setup/cleanup */
+extern int usb_board_init(void);
+extern int usb_board_stop(void);
+extern int usb_board_init_fail(void);
+
+extern int usb_cpu_init(void);
+extern int usb_cpu_stop(void);
+extern int usb_cpu_init_fail(void);
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+ /* No Error */ 0,
+ /* CRC Error */ USB_ST_CRC_ERR,
+ /* Bit Stuff */ USB_ST_BIT_ERR,
+ /* Data Togg */ USB_ST_CRC_ERR,
+ /* Stall */ USB_ST_STALLED,
+ /* DevNotResp */ -1,
+ /* PIDCheck */ USB_ST_BIT_ERR,
+ /* UnExpPID */ USB_ST_BIT_ERR,
+ /* DataOver */ USB_ST_BUF_ERR,
+ /* DataUnder */ USB_ST_BUF_ERR,
+ /* reservd */ -1,
+ /* reservd */ -1,
+ /* BufferOver */ USB_ST_BUF_ERR,
+ /* BuffUnder */ USB_ST_BUF_ERR,
+ /* Not Access */ -1,
+ /* Not Access */ -1
+};
+
+static const char *cc_to_string[16] = {
+ "No Error",
+ "CRC: Last data packet from endpoint contained a CRC error.",
+ "BITSTUFFING: Last data packet from endpoint contained a bit " \
+ "stuffing violation",
+ "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
+ "that did not match the expected value.",
+ "STALL: TD was moved to the Done Queue because the endpoint returned" \
+ " a STALL PID",
+ "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
+ "not provide a handshake (OUT)",
+ "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
+ "(IN) or handshake (OUT)",
+ "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
+ "value is not defined.",
+ "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
+ "either the size of the maximum data packet allowed\n" \
+ "from the endpoint (found in MaximumPacketSize field\n" \
+ "of ED) or the remaining buffer size.",
+ "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
+ "and that amount was not sufficient to fill the\n" \
+ "specified buffer",
+ "reserved1",
+ "reserved2",
+ "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
+ "than it could be written to system memory",
+ "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
+ "system memory fast enough to keep up with data USB " \
+ "data rate.",
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
+ "on a list to be processed by the HC.(1)",
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
+ "on a list to be processed by the HC.(2)",
+};
+
+/* ED States */
+
+#define ED_NEW 0x00
+#define ED_UNLINK 0x01
+#define ED_OPER 0x02
+#define ED_DEL 0x04
+#define ED_URB_DEL 0x08
+
+/* usb_ohci_ed */
+struct ed {
+ __u32 hwINFO;
+ __u32 hwTailP;
+ __u32 hwHeadP;
+ __u32 hwNextED;
+
+ struct ed *ed_prev;
+ __u8 int_period;
+ __u8 int_branch;
+ __u8 int_load;
+ __u8 int_interval;
+ __u8 state;
+ __u8 type;
+ __u16 last_iso;
+ struct ed *ed_rm_list;
+
+ struct usb_device *usb_dev;
+ void *purb;
+ __u32 unused[2];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC 0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC 0x0C000000
+#define TD_T 0x03000000
+#define TD_T_DATA0 0x02000000
+#define TD_T_DATA1 0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R 0x00040000
+#define TD_DI 0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP 0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN 0x00100000
+#define TD_DP_OUT 0x00080000
+
+#define TD_ISO 0x00010000
+#define TD_DEL 0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+#define TD_NOTACCESSED 0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+ __u32 hwINFO;
+ __u32 hwCBP; /* Current Buffer Pointer */
+ __u32 hwNextTD; /* Next TD Pointer */
+ __u32 hwBE; /* Memory Buffer End Pointer */
+
+/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
+ __u16 hwPSW[MAXPSW];
+/* #endif */
+ __u8 unused;
+ __u8 index;
+ struct ed *ed;
+ struct td *next_dl_td;
+ struct usb_device *usb_dev;
+ int transfer_len;
+ __u32 data;
+
+ __u32 unused2[2];
+} __attribute((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP (1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of. It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32 /* part of the OHCI standard */
+struct ohci_hcca {
+ __u32 int_table[NUM_INTS]; /* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+ __u16 pad1; /* set to 0 on each frame_no change */
+ __u16 frame_no; /* current frame number */
+#else
+ __u16 frame_no; /* current frame number */
+ __u16 pad1; /* set to 0 on each frame_no change */
+#endif
+ __u32 done_head; /* info returned for an interrupt */
+ u8 reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#ifndef CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS
+# error "CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS undefined!"
+#endif
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region. This is Memory Mapped I/O. You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+ /* control and status registers */
+ __u32 revision;
+ __u32 control;
+ __u32 cmdstatus;
+ __u32 intrstatus;
+ __u32 intrenable;
+ __u32 intrdisable;
+ /* memory pointers */
+ __u32 hcca;
+ __u32 ed_periodcurrent;
+ __u32 ed_controlhead;
+ __u32 ed_controlcurrent;
+ __u32 ed_bulkhead;
+ __u32 ed_bulkcurrent;
+ __u32 donehead;
+ /* frame counters */
+ __u32 fminterval;
+ __u32 fmremaining;
+ __u32 fmnumber;
+ __u32 periodicstart;
+ __u32 lsthresh;
+ /* Root hub ports */
+ struct ohci_roothub_regs {
+ __u32 a;
+ __u32 b;
+ __u32 status;
+ __u32 portstatus[CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS];
+ } roothub;
+} __attribute((aligned(32)));
+
+/* Some EHCI controls */
+#define EHCI_USBCMD_OFF 0x20
+#define EHCI_USBCMD_HCRESET (1 << 1)
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
+#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
+#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
+#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
+#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
+#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
+#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
+#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
+#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+# define OHCI_USB_RESET (0 << 6)
+# define OHCI_USB_RESUME (1 << 6)
+# define OHCI_USB_OPER (2 << 6)
+# define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR (1 << 0) /* host controller reset */
+#define OHCI_CLF (1 << 1) /* control list filled */
+#define OHCI_BLF (1 << 2) /* bulk list filled */
+#define OHCI_OCR (1 << 3) /* ownership change request */
+#define OHCI_SOC (3 << 16) /* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
+#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
+#define OHCI_INTR_SF (1 << 2) /* start frame */
+#define OHCI_INTR_RD (1 << 3) /* resume detect */
+#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
+#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
+#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
+#define OHCI_INTR_OC (1 << 30) /* ownership change */
+#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+ int devnum; /* Address of Root Hub endpoint */
+ void *dev; /* was urb */
+ void *int_addr;
+ int send;
+ int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+ ed_t *ed;
+ __u16 length; /* number of tds associated with this request */
+ __u16 td_cnt; /* number of tds already serviced */
+ struct usb_device *dev;
+ int state;
+ unsigned long pipe;
+ void *transfer_buffer;
+ int transfer_buffer_length;
+ int interval;
+ int actual_length;
+ int finished;
+ td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+ struct ohci_hcca *hcca; /* hcca */
+ /*dma_addr_t hcca_dma;*/
+
+ int irq;
+ int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
+ unsigned long flags; /* for HC bugs */
+
+ struct ohci_regs *regs; /* OHCI controller's memory */
+
+ int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
+ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
+ ed_t *ed_bulktail; /* last endpoint of bulk list */
+ ed_t *ed_controltail; /* last endpoint of control list */
+ int intrstatus;
+ __u32 hc_control; /* copy of the hc control reg */
+ struct usb_device *dev[32];
+ struct virt_root_hub rh;
+
+ const char *slot_name;
+} ohci_t;
+
+#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+ ed_t ed[NUM_EDS];
+ int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
+ int interval, int load);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+ int i;
+ struct td *td;
+
+ td = NULL;
+ for (i = 0; i < NUM_TD; i++)
+ {
+ if (ptd[i].usb_dev == NULL)
+ {
+ td = &ptd[i];
+ td->usb_dev = usb_dev;
+ break;
+ }
+ }
+
+ return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+ ed->usb_dev = NULL;
+}
--- /dev/null
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <asm/io.h>
+
+#include "r8a66597.h"
+
+#ifdef R8A66597_DEBUG
+#define R8A66597_DPRINT printf
+#else
+#define R8A66597_DPRINT(...)
+#endif
+
+static const char hcd_name[] = "r8a66597_hcd";
+static unsigned short clock = CONFIG_R8A66597_XTAL;
+static unsigned short vif = CONFIG_R8A66597_LDRV;
+static unsigned short endian = CONFIG_R8A66597_ENDIAN;
+static struct r8a66597 gr8a66597;
+
+static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
+{
+ int i;
+
+ *hub_devnum = 0;
+ *hubport = 0;
+
+ /* check a device connected to root_hub */
+ if ((dev->parent && dev->parent->devnum == 1) ||
+ (dev->devnum == 1))
+ return;
+
+ for (i = 0; i < USB_MAXCHILDREN; i++) {
+ if (dev->parent->children[i] == dev) {
+ *hub_devnum = (u8)dev->parent->devnum;
+ *hubport = i;
+ return;
+ }
+ }
+
+ printf("get_hub_data error.\n");
+}
+
+static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address,
+ struct usb_device *dev, int port)
+{
+ u16 val, usbspd, upphub, hubport;
+ unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
+
+ get_hub_data(dev, &upphub, &hubport);
+ usbspd = r8a66597->speed;
+ val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
+ r8a66597_write(r8a66597, val, devadd_reg);
+}
+
+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) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+#else
+ do {
+ r8a66597_write(r8a66597, USBE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } while ((tmp & USBE) != USBE);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
+
+ i = 0;
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ do {
+ udelay(1000);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 500) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } 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));
+}
+
+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, USBE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, INTL, SOFCFG);
+ r8a66597_write(r8a66597, 0, INTENB0);
+ r8a66597_write(r8a66597, 0, INTENB1);
+ r8a66597_write(r8a66597, 0, INTENB2);
+
+ r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
+ r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
+ r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
+ r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
+
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_enable_port(r8a66597, port);
+
+ return 0;
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+ int i;
+
+ if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
+ return;
+
+ r8a66597_write(r8a66597, 0, INTENB0);
+ r8a66597_write(r8a66597, 0, INTSTS0);
+
+ r8a66597_write(r8a66597, 0, D0FIFOSEL);
+ r8a66597_write(r8a66597, 0, D1FIFOSEL);
+ r8a66597_write(r8a66597, 0, DCPCFG);
+ r8a66597_write(r8a66597, 0x40, DCPMAXP);
+ r8a66597_write(r8a66597, 0, DCPCTR);
+
+ for (i = 0; i <= 10; i++)
+ r8a66597_write(r8a66597, 0, get_devadd_addr(i));
+ for (i = 1; i <= 5; i++) {
+ r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
+ r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
+ }
+ for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
+ r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
+ r8a66597_write(r8a66597, i, PIPESEL);
+ r8a66597_write(r8a66597, 0, PIPECFG);
+ r8a66597_write(r8a66597, 0, PIPEBUF);
+ r8a66597_write(r8a66597, 0, PIPEMAXP);
+ r8a66597_write(r8a66597, 0, PIPEPERI);
+ }
+
+ for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
+ r8a66597_disable_port(r8a66597, i);
+
+ r8a66597_clock_disable(r8a66597);
+}
+
+static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
+ u16 mask, u16 loop)
+{
+ u16 tmp;
+ int i = 0;
+
+ do {
+ tmp = r8a66597_read(r8a66597, reg);
+ if (i++ > 1000000) {
+ printf("register%lx, loop %x is timeout\n", reg, loop);
+ break;
+ }
+ } while ((tmp & mask) != loop);
+}
+
+static void pipe_buffer_setting(struct r8a66597 *r8a66597,
+ struct usb_device *dev, unsigned long pipe)
+{
+ u16 val = 0;
+ u16 pipenum, bufnum, maxpacket;
+
+ if (usb_pipein(pipe)) {
+ pipenum = BULK_IN_PIPENUM;
+ bufnum = BULK_IN_BUFNUM;
+ maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+ } else {
+ pipenum = BULK_OUT_PIPENUM;
+ bufnum = BULK_OUT_BUFNUM;
+ maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+ }
+
+ if (r8a66597->pipe_config & (1 << pipenum))
+ return;
+ r8a66597->pipe_config |= (1 << pipenum);
+
+ r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+ r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+ r8a66597_write(r8a66597, pipenum, PIPESEL);
+
+ /* FIXME: This driver support bulk transfer only. */
+ if (!usb_pipein(pipe))
+ val |= R8A66597_DIR;
+ else
+ val |= R8A66597_SHTNAK;
+ val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
+ r8a66597_write(r8a66597, val, PIPECFG);
+
+ r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
+ r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
+ maxpacket, PIPEMAXP);
+ r8a66597_write(r8a66597, 0, PIPEPERI);
+ r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
+}
+
+static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+ struct devrequest *setup)
+{
+ int i;
+ unsigned short *p = (unsigned short *)setup;
+ unsigned long setup_addr = USBREQ;
+ u16 intsts1;
+ int timeout = 3000;
+ u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
+
+ r8a66597_write(r8a66597, make_devsel(devsel) |
+ (8 << dev->maxpacketsize), DCPMAXP);
+ r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
+
+ for (i = 0; i < 4; i++) {
+ r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
+ setup_addr += 2;
+ }
+ r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+ r8a66597_write(r8a66597, SUREQ, DCPCTR);
+
+ while (1) {
+ intsts1 = r8a66597_read(r8a66597, INTSTS1);
+ if (intsts1 & SACK)
+ break;
+ if (intsts1 & SIGN) {
+ printf("setup packet send error\n");
+ return -1;
+ }
+ if (timeout-- < 0) {
+ printf("setup packet timeout\n");
+ return -1;
+ }
+ udelay(500);
+ }
+
+ return 0;
+}
+
+static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int transfer_len)
+{
+ u16 tmp, bufsize;
+ u16 *buf;
+ size_t size;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
+ MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ /* prepare parameters */
+ bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+ buf = (u16 *)(buffer + dev->act_len);
+ size = min((int)bufsize, transfer_len - dev->act_len);
+
+ /* write fifo */
+ r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+ if (buffer) {
+ r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
+ r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+ }
+
+ /* update parameters */
+ dev->act_len += size;
+
+ r8a66597_mdfy(r8a66597, PID_BUF, PID,
+ get_pipectr_addr(BULK_OUT_PIPENUM));
+
+ while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+
+ if (dev->act_len >= transfer_len)
+ r8a66597_mdfy(r8a66597, PID_NAK, PID,
+ get_pipectr_addr(BULK_OUT_PIPENUM));
+
+ return 0;
+}
+
+static int receive_bulk_packet(struct r8a66597 *r8a66597,
+ struct usb_device *dev,
+ unsigned long pipe,
+ void *buffer, int transfer_len)
+{
+ u16 tmp;
+ u16 *buf;
+ const u16 pipenum = BULK_IN_PIPENUM;
+ int rcv_len;
+ int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ /* prepare */
+ if (dev->act_len == 0) {
+ r8a66597_mdfy(r8a66597, PID_NAK, PID,
+ get_pipectr_addr(pipenum));
+ r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+ r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
+ r8a66597_write(r8a66597,
+ (transfer_len + maxpacket - 1) / maxpacket,
+ get_pipetrn_addr(pipenum));
+ r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
+
+ r8a66597_mdfy(r8a66597, PID_BUF, PID,
+ get_pipectr_addr(pipenum));
+ }
+
+ r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
+
+ while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ buf = (u16 *)(buffer + dev->act_len);
+ rcv_len = tmp & DTLN;
+ dev->act_len += rcv_len;
+
+ if (buffer) {
+ if (rcv_len == 0)
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ else
+ r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
+ }
+
+ return 0;
+}
+
+static int receive_control_packet(struct r8a66597 *r8a66597,
+ struct usb_device *dev,
+ void *buffer, int transfer_len)
+{
+ u16 tmp;
+ int rcv_len;
+
+ /* FIXME: limit transfer size : 64byte or less */
+
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_bset(r8a66597, SQSET, DCPCTR);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+ while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+
+ r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ rcv_len = tmp & DTLN;
+ dev->act_len += rcv_len;
+
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+ if (buffer) {
+ if (rcv_len == 0)
+ r8a66597_write(r8a66597, BCLR, DCPCTR);
+ else
+ r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
+ }
+
+ return 0;
+}
+
+static int send_status_packet(struct r8a66597 *r8a66597,
+ unsigned long pipe)
+{
+ r8a66597_bset(r8a66597, SQSET, DCPCTR);
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+ if (usb_pipein(pipe)) {
+ r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
+ } else {
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ }
+ r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+ while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
+ if (ctrlc())
+ return -1;
+
+ return 0;
+}
+
+static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
+{
+ int count = R8A66597_MAX_SAMPLING;
+ unsigned short syssts, old_syssts;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+ while (count > 0) {
+ wait_ms(R8A66597_RH_POLL_TIME);
+
+ syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+ if (syssts == old_syssts) {
+ count--;
+ } else {
+ count = R8A66597_MAX_SAMPLING;
+ old_syssts = syssts;
+ }
+ }
+}
+
+static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
+{
+ wait_ms(10);
+ r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
+ wait_ms(50);
+ r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
+ wait_ms(50);
+}
+
+static int check_usb_device_connecting(struct r8a66597 *r8a66597)
+{
+ int timeout = 10000; /* 100usec * 10000 = 1sec */
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ /* check a usb cable connect */
+ while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
+ if (timeout-- < 0) {
+ printf("%s timeout.\n", __func__);
+ return -1;
+ }
+ udelay(100);
+ }
+
+ /* check a data line */
+ r8a66597_check_syssts(r8a66597, 0);
+
+ r8a66597_bus_reset(r8a66597, 0);
+ r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
+
+ if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
+ r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
+ r8a66597->port_status = USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_ENABLE;
+ return 0; /* success */
+ }
+
+ R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS1);
+ }
+
+ return -1; /* fail */
+}
+
+/* based on usb_ohci.c */
+#define min_t(type, x, y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes; */
+
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 34, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '8', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'A', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '6', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '6', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '5', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '9', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '7', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+ unsigned char data[32];
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ if (usb_pipeint(pipe)) {
+ printf("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = cpu_to_le16 (cmd->value);
+ wIndex = cpu_to_le16 (cmd->index);
+ wLength = cpu_to_le16 (cmd->length);
+
+ switch (bmRType_bReq) {
+ case RH_GET_STATUS:
+ *(__u16 *)buffer = cpu_to_le16(1);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *)buffer = cpu_to_le16(0);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *)buffer = cpu_to_le16(0);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *)buffer = cpu_to_le32(0);
+ len = 4;
+ break;
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
+ (r8a66597->port_change << 16));
+ len = 4;
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_C_PORT_CONNECTION:
+ r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
+ break;
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ break;
+ case (RH_PORT_RESET):
+ r8a66597_bus_reset(r8a66597, 0);
+ break;
+ case (RH_PORT_POWER):
+ break;
+ case (RH_PORT_ENABLE):
+ break;
+ }
+ break;
+ case RH_SET_ADDRESS:
+ gr8a66597.rh_devnum = wValue;
+ break;
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ memcpy(buffer, root_hub_dev_des, len);
+ break;
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ memcpy(buffer, root_hub_config_des, len);
+ break;
+ case (0x03): /* string descriptors */
+ if (wValue == 0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ memcpy(buffer, root_hub_str_index0, len);
+ }
+ if (wValue == 0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ memcpy(buffer, root_hub_str_index1, len);
+ }
+ break;
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = 0x00000001;
+
+ data[0] = 9; /* min length; */
+ data[1] = 0x29;
+ data[2] = temp & RH_A_NDP;
+ data[3] = 0;
+ if (temp & RH_A_PSM)
+ data[3] |= 0x1;
+ if (temp & RH_A_NOCP)
+ data[3] |= 0x10;
+ else if (temp & RH_A_OCPM)
+ data[3] |= 0x8;
+
+ /* corresponds to data[4-7] */
+ data[5] = (temp & RH_A_POTPGT) >> 24;
+ data[7] = temp & RH_B_DR;
+ if (data[2] < 7) {
+ data[8] = 0xff;
+ } else {
+ data[0] += 2;
+ data[8] = (temp & RH_B_DR) >> 8;
+ data[10] = data[9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data[0], wLength));
+ memcpy(buffer, data, len);
+ break;
+ }
+
+ case RH_GET_CONFIGURATION:
+ *(__u8 *) buffer = 0x01;
+ len = 1;
+ break;
+ case RH_SET_CONFIGURATION:
+ break;
+ default:
+ R8A66597_DPRINT("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+ wait_ms(1);
+
+ len = min_t(int, len, leni);
+
+ dev->act_len = len;
+ dev->status = stat;
+
+ return stat;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ int ret = 0;
+
+ R8A66597_DPRINT("%s\n", __func__);
+ R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
+ pipe, buffer, transfer_len, dev->devnum);
+
+ set_devadd(r8a66597, dev->devnum, dev, 0);
+
+ pipe_buffer_setting(r8a66597, dev, pipe);
+
+ dev->act_len = 0;
+ while (dev->act_len < transfer_len && ret == 0) {
+ if (ctrlc())
+ return -1;
+
+ if (usb_pipein(pipe))
+ ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
+ transfer_len);
+ else
+ ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
+ transfer_len);
+ }
+
+ if (ret == 0)
+ dev->status = 0;
+
+ return ret;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *setup)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
+ 0 : dev->devnum;
+
+ R8A66597_DPRINT("%s\n", __func__);
+ if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
+ return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+
+ R8A66597_DPRINT("%s: setup\n", __func__);
+ set_devadd(r8a66597, r8a66597_address, dev, 0);
+
+ if (send_setup_packet(r8a66597, dev, setup) < 0) {
+ printf("setup packet send error\n");
+ return -1;
+ }
+
+ dev->act_len = 0;
+ if (usb_pipein(pipe))
+ if (receive_control_packet(r8a66597, dev, buffer,
+ transfer_len) < 0)
+ return -1;
+
+ if (send_status_packet(r8a66597, pipe) < 0)
+ return -1;
+
+ dev->status = 0;
+
+ return 0;
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ /* no implement */
+ R8A66597_DPRINT("%s\n", __func__);
+ return 0;
+}
+
+void usb_event_poll(void)
+{
+ /* no implement */
+ R8A66597_DPRINT("%s\n", __func__);
+}
+
+int usb_lowlevel_init(void)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ memset(r8a66597, 0, sizeof(r8a66597));
+ r8a66597->reg = CONFIG_R8A66597_BASE_ADDR;
+
+ disable_controller(r8a66597);
+ wait_ms(100);
+
+ enable_controller(r8a66597);
+ r8a66597_port_power(r8a66597, 0 , 1);
+
+ /* check usb device */
+ check_usb_device_connecting(r8a66597);
+
+ wait_ms(50);
+
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ disable_controller(&gr8a66597);
+
+ return 0;
+}
--- /dev/null
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#define SYSCFG0 0x00
+#define SYSCFG1 0x02
+#define SYSSTS0 0x04
+#define SYSSTS1 0x06
+#define DVSTCTR0 0x08
+#define DVSTCTR1 0x0A
+#define TESTMODE 0x0C
+#define PINCFG 0x0E
+#define DMA0CFG 0x10
+#define DMA1CFG 0x12
+#define CFIFO 0x14
+#define D0FIFO 0x18
+#define D1FIFO 0x1C
+#define CFIFOSEL 0x20
+#define CFIFOCTR 0x22
+#define CFIFOSIE 0x24
+#define D0FIFOSEL 0x28
+#define D0FIFOCTR 0x2A
+#define D1FIFOSEL 0x2C
+#define D1FIFOCTR 0x2E
+#define INTENB0 0x30
+#define INTENB1 0x32
+#define INTENB2 0x34
+#define BRDYENB 0x36
+#define NRDYENB 0x38
+#define BEMPENB 0x3A
+#define SOFCFG 0x3C
+#define INTSTS0 0x40
+#define INTSTS1 0x42
+#define INTSTS2 0x44
+#define BRDYSTS 0x46
+#define NRDYSTS 0x48
+#define BEMPSTS 0x4A
+#define FRMNUM 0x4C
+#define UFRMNUM 0x4E
+#define USBADDR 0x50
+#define USBREQ 0x54
+#define USBVAL 0x56
+#define USBINDX 0x58
+#define USBLENG 0x5A
+#define DCPCFG 0x5C
+#define DCPMAXP 0x5E
+#define DCPCTR 0x60
+#define PIPESEL 0x64
+#define PIPECFG 0x68
+#define PIPEBUF 0x6A
+#define PIPEMAXP 0x6C
+#define PIPEPERI 0x6E
+#define PIPE1CTR 0x70
+#define PIPE2CTR 0x72
+#define PIPE3CTR 0x74
+#define PIPE4CTR 0x76
+#define PIPE5CTR 0x78
+#define PIPE6CTR 0x7A
+#define PIPE7CTR 0x7C
+#define PIPE8CTR 0x7E
+#define PIPE9CTR 0x80
+#define PIPE1TRE 0x90
+#define PIPE1TRN 0x92
+#define PIPE2TRE 0x94
+#define PIPE2TRN 0x96
+#define PIPE3TRE 0x98
+#define PIPE3TRN 0x9A
+#define PIPE4TRE 0x9C
+#define PIPE4TRN 0x9E
+#define PIPE5TRE 0xA0
+#define PIPE5TRN 0xA2
+#define DEVADD0 0xD0
+#define DEVADD1 0xD2
+#define DEVADD2 0xD4
+#define DEVADD3 0xD6
+#define DEVADD4 0xD8
+#define DEVADD5 0xDA
+#define DEVADD6 0xDC
+#define DEVADD7 0xDE
+#define DEVADD8 0xE0
+#define DEVADD9 0xE2
+#define DEVADDA 0xE4
+
+/* System Configuration Control Register */
+#define XTAL 0xC000 /* b15-14: Crystal selection */
+#define XTAL48 0x8000 /* 48MHz */
+#define XTAL24 0x4000 /* 24MHz */
+#define XTAL12 0x0000 /* 12MHz */
+#define XCKE 0x2000 /* b13: External clock enable */
+#define PLLC 0x0800 /* b11: PLL control */
+#define SCKE 0x0400 /* b10: USB clock enable */
+#define PCSDIS 0x0200 /* b9: not CS wakeup */
+#define LPSME 0x0100 /* b8: Low power sleep mode */
+#define HSE 0x0080 /* b7: Hi-speed enable */
+#define DCFM 0x0040 /* b6: Controller function select */
+#define DRPD 0x0020 /* b5: D+/- pull down control */
+#define DPRPU 0x0010 /* b4: D+ pull up control */
+#define USBE 0x0001 /* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define OVCBIT 0x8000 /* b15-14: Over-current bit */
+#define OVCMON 0xC000 /* b15-14: Over-current monitor */
+#define SOFEA 0x0020 /* b5: SOF monitor */
+#define IDMON 0x0004 /* b3: ID-pin monitor */
+#define LNST 0x0003 /* b1-0: D+, D- line status */
+#define SE1 0x0003 /* SE1 */
+#define FS_KSTS 0x0002 /* Full-Speed K State */
+#define FS_JSTS 0x0001 /* Full-Speed J State */
+#define LS_JSTS 0x0002 /* Low-Speed J State */
+#define LS_KSTS 0x0001 /* Low-Speed K State */
+#define SE0 0x0000 /* SE0 */
+
+/* Device State Control Register */
+#define EXTLP0 0x0400 /* b10: External port */
+#define VBOUT 0x0200 /* b9: VBUS output */
+#define WKUP 0x0100 /* b8: Remote wakeup */
+#define RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define USBRST 0x0040 /* b6: USB reset enable */
+#define RESUME 0x0020 /* b5: Resume enable */
+#define UACT 0x0010 /* b4: USB bus enable */
+#define RHST 0x0007 /* b1-0: Reset handshake status */
+#define HSPROC 0x0004 /* HS handshake is processing */
+#define HSMODE 0x0003 /* Hi-Speed mode */
+#define FSMODE 0x0002 /* Full-Speed mode */
+#define LSMODE 0x0001 /* Low-Speed mode */
+#define UNDECID 0x0000 /* Undecided */
+
+/* Test Mode Register */
+#define UTST 0x000F /* b3-0: Test select */
+#define H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define H_TST_K 0x000A /* HOST TEST K */
+#define H_TST_J 0x0009 /* HOST TEST J */
+#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define P_TST_K 0x0002 /* PERI TEST K */
+#define P_TST_J 0x0001 /* PERI TEST J */
+#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define LDRV 0x8000 /* b15: Drive Current Adjust */
+#define VIF1 0x0000 /* VIF = 1.8V */
+#define VIF3 0x8000 /* VIF = 3.3V */
+#define INTA 0x0001 /* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define DREQA 0x4000 /* b14: Dreq active select */
+#define BURST 0x2000 /* b13: Burst mode */
+#define DACKA 0x0400 /* b10: Dack active select */
+#define DFORM 0x0380 /* b9-7: DMA mode select */
+#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define DENDA 0x0040 /* b6: Dend active select */
+#define PKTM 0x0020 /* b5: Packet mode */
+#define DENDE 0x0010 /* b4: Dend enable */
+#define OBUS 0x0004 /* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define RCNT 0x8000 /* b15: Read count mode */
+#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 */
+#define BYTE_LITTLE 0x0000 /* little dendian */
+#define BYTE_BIG 0x0100 /* big endifan */
+#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define CURPIPE 0x000F /* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define BVAL 0x8000 /* b15: Buffer valid flag */
+#define BCLR 0x4000 /* b14: Buffer clear */
+#define FRDY 0x2000 /* b13: FIFO ready */
+#define DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define VBSE 0x8000 /* b15: VBUS interrupt */
+#define RSME 0x4000 /* b14: Resume interrupt */
+#define SOFE 0x2000 /* b13: Frame update interrupt */
+#define DVSE 0x1000 /* b12: Device state transition interrupt */
+#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define OVRCRE 0x8000 /* b15: Over-current interrupt */
+#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
+#define EOFERRE 0x0040 /* b6: EOF error interrupt */
+#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define BRDY9 0x0200 /* b9: PIPE9 */
+#define BRDY8 0x0100 /* b8: PIPE8 */
+#define BRDY7 0x0080 /* b7: PIPE7 */
+#define BRDY6 0x0040 /* b6: PIPE6 */
+#define BRDY5 0x0020 /* b5: PIPE5 */
+#define BRDY4 0x0010 /* b4: PIPE4 */
+#define BRDY3 0x0008 /* b3: PIPE3 */
+#define BRDY2 0x0004 /* b2: PIPE2 */
+#define BRDY1 0x0002 /* b1: PIPE1 */
+#define BRDY0 0x0001 /* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define NRDY9 0x0200 /* b9: PIPE9 */
+#define NRDY8 0x0100 /* b8: PIPE8 */
+#define NRDY7 0x0080 /* b7: PIPE7 */
+#define NRDY6 0x0040 /* b6: PIPE6 */
+#define NRDY5 0x0020 /* b5: PIPE5 */
+#define NRDY4 0x0010 /* b4: PIPE4 */
+#define NRDY3 0x0008 /* b3: PIPE3 */
+#define NRDY2 0x0004 /* b2: PIPE2 */
+#define NRDY1 0x0002 /* b1: PIPE1 */
+#define NRDY0 0x0001 /* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define BEMP9 0x0200 /* b9: PIPE9 */
+#define BEMP8 0x0100 /* b8: PIPE8 */
+#define BEMP7 0x0080 /* b7: PIPE7 */
+#define BEMP6 0x0040 /* b6: PIPE6 */
+#define BEMP5 0x0020 /* b5: PIPE5 */
+#define BEMP4 0x0010 /* b4: PIPE4 */
+#define BEMP3 0x0008 /* b3: PIPE3 */
+#define BEMP2 0x0004 /* b2: PIPE2 */
+#define BEMP1 0x0002 /* b1: PIPE1 */
+#define BEMP0 0x0001 /* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
+#define BRDYM 0x0040 /* b6: BRDY clear timing */
+#define INTL 0x0020 /* b5: Interrupt sense select */
+#define EDGESTS 0x0010 /* b4: */
+#define SOFMODE 0x000C /* b3-2: SOF pin select */
+#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
+#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define VBINT 0x8000 /* b15: VBUS interrupt */
+#define RESM 0x4000 /* b14: Resume interrupt */
+#define SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define DVST 0x1000 /* b12: Device state transition interrupt */
+#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define VBSTS 0x0080 /* b7: VBUS input port */
+#define DVSQ 0x0070 /* b6-4: Device state */
+#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define DS_SUSP 0x0040 /* Suspend */
+#define DS_CNFG 0x0030 /* Configured */
+#define DS_ADDS 0x0020 /* Address */
+#define DS_DFLT 0x0010 /* Default */
+#define DS_POWR 0x0000 /* Powered */
+#define DVSQS 0x0030 /* b5-4: Device state */
+#define VALID 0x0008 /* b3: Setup packet detected flag */
+#define CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define CS_SQER 0x0006 /* Sequence error */
+#define CS_WRND 0x0005 /* Control write nodata status stage */
+#define CS_WRSS 0x0004 /* Control write status stage */
+#define CS_WRDS 0x0003 /* Control write data stage */
+#define CS_RDSS 0x0002 /* Control read status stage */
+#define CS_RDDS 0x0001 /* Control read data stage */
+#define CS_IDST 0x0000 /* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define OVRCR 0x8000 /* b15: Over-current interrupt */
+#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define DTCH 0x1000 /* b12: Detach sense interrupt */
+#define ATTCH 0x0800 /* b11: Attach sense interrupt */
+#define EOFERR 0x0040 /* b6: EOF-error interrupt */
+#define SIGN 0x0020 /* b5: Setup ignore interrupt */
+#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define OVRN 0x8000 /* b15: Overrun error */
+#define CRCE 0x4000 /* b14: Received data error */
+#define FRNM 0x07FF /* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define UFRNM 0x0007 /* b2-0: Micro frame number */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define DEVSEL 0xF000 /* b15-14: Device address select */
+#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define SUREQ 0x4000 /* b14: Send USB request */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define SUREQCLR 0x0800 /* b11: stop setup request */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PINGE 0x0010 /* b4: ping enable */
+#define CCPL 0x0004 /* b2: Enable control transfer complete */
+#define PID 0x0003 /* b1-0: Response PID */
+#define PID_STALL11 0x0003 /* STALL */
+#define PID_STALL 0x0002 /* STALL */
+#define PID_BUF 0x0001 /* BUF */
+#define PID_NAK 0x0000 /* NAK */
+
+/* Pipe Window Select Register */
+#define PIPENM 0x0007 /* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
+#define R8A66597_ISO 0xC000 /* Isochronous */
+#define R8A66597_INT 0x8000 /* Interrupt */
+#define R8A66597_BULK 0x4000 /* Bulk */
+#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
+#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
+#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
+#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
+#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
+#define PIPE0BUF 256
+#define PIPExBUF 64
+
+/* Pipe Maxpacket Size Register */
+#define MXPS 0x07FF /* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
+#define IITV 0x0007 /* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define ATREPM 0x0400 /* b10: Auto repeat mode */
+#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PID 0x0003 /* b1-0: Response PID */
+
+/* PIPExTRE */
+#define TRENB 0x0200 /* b9: Transaction counter enable */
+#define TRCLR 0x0100 /* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define UPPHUB 0x7800
+#define HUBPORT 0x0700
+#define USBSPD 0x00C0
+#define RTPORT 0x0001
+
+#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
+#endif
+#define R8A66597_MAX_SAMPLING 5
+#define R8A66597_RH_POLL_TIME 10
+
+#define BULK_IN_PIPENUM 3
+#define BULK_IN_BUFNUM 8
+
+#define BULK_OUT_PIPENUM 4
+#define BULK_OUT_BUFNUM 40
+
+#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
+#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
+#define make_devsel(addr) (addr << 12)
+
+struct r8a66597 {
+ unsigned long reg;
+ unsigned short pipe_config; /* bit field */
+ unsigned short port_status;
+ unsigned short port_change;
+ u16 speed; /* HSMODE or FSMODE or LSMODE */
+ unsigned char rh_devnum;
+};
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+ return inw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, void *buf,
+ int len)
+{
+ int i;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ unsigned long count;
+ unsigned long *p = buf;
+
+ count = len / 4;
+ for (i = 0; i < count; i++)
+ inl(p[i], r8a66597->reg + offset);
+
+ if (len & 0x00000003) {
+ unsigned long tmp = inl(fifoaddr);
+ memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+ }
+#else
+ unsigned short *p = buf;
+
+ len = (len + 1) / 2;
+ for (i = 0; i < len; i++)
+ p[i] = inw(r8a66597->reg + offset);
+#endif
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+ unsigned long offset)
+{
+ outw(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, void *buf,
+ int len)
+{
+ int i;
+ unsigned long fifoaddr = r8a66597->reg + offset;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long count;
+ unsigned char *pb;
+ unsigned long *p = buf;
+
+ count = len / 4;
+ for (i = 0; i < count; i++)
+ outl(p[i], fifoaddr);
+
+ 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;
+ unsigned short *p = buf;
+
+ len = len / 2;
+ for (i = 0; i < len; i++)
+ outw(p[i], fifoaddr);
+
+ if (odd) {
+ unsigned char *pb = (unsigned char *)(buf + len);
+ outb(*pb, fifoaddr);
+ }
+#endif
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+ u16 val, u16 pat, unsigned long offset)
+{
+ u16 tmp;
+ tmp = r8a66597_read(r8a66597, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, val, 0, offset)
+
+static inline unsigned long get_syscfg_reg(int port)
+{
+ return port == 0 ? SYSCFG0 : SYSCFG1;
+}
+
+static inline unsigned long get_syssts_reg(int port)
+{
+ return port == 0 ? SYSSTS0 : SYSSTS1;
+}
+
+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;
+}
+
+static inline unsigned long get_intsts_reg(int port)
+{
+ return port == 0 ? INTSTS1 : INTSTS2;
+}
+
+static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
+}
+
+static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
+ int power)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ if (power)
+ r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+ else
+ r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+}
+
+#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
+#define get_devadd_addr(address) (DEVADD0 + address * 2)
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h, based on usb_ohci.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+#endif /* __R8A66597_H__ */
--- /dev/null
+/*
+ * URB OHCI HCD (Host Controller Driver) initialization for USB on the S3C64XX.
+ *
+ * Copyright (C) 2008,
+ * Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <s3c6400.h>
+
+int usb_cpu_init(void)
+{
+ OTHERS_REG |= 0x10000;
+ return 0;
+}
+
+int usb_cpu_stop(void)
+{
+ OTHERS_REG &= ~0x10000;
+ return 0;
+}
+
+void usb_cpu_init_fail(void)
+{
+ OTHERS_REG &= ~0x10000;
+}
--- /dev/null
+/*
+ * (C) Copyright 2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * This code is based on linux driver for sl811hs chip, source at
+ * drivers/usb/host/sl811.c:
+ *
+ * SL811 Host Controller Interface driver for USB.
+ *
+ * Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ * Based on:
+ * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ * Adam Richter, Gregory P. Smith;
+ * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <mpc8xx.h>
+#include <usb.h>
+#include "sl811.h"
+
+#include "../../../board/kup/common/kup.h"
+
+#ifdef __PPC__
+# define EIEIO __asm__ volatile ("eieio")
+#else
+# define EIEIO /* nothing */
+#endif
+
+#define SL811_ADR (0x50000000)
+#define SL811_DAT (0x50000001)
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+
+#ifdef SL811_DEBUG
+static int debug = 9;
+#endif
+
+static int root_hub_devnum = 0;
+static struct usb_port_status rh_status = { 0 };/* root hub port status */
+
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+ void *data, int buf_len, struct devrequest *cmd);
+
+static void sl811_write (__u8 index, __u8 data)
+{
+ *(volatile unsigned char *) (SL811_ADR) = index;
+ EIEIO;
+ *(volatile unsigned char *) (SL811_DAT) = data;
+ EIEIO;
+}
+
+static __u8 sl811_read (__u8 index)
+{
+ __u8 data;
+
+ *(volatile unsigned char *) (SL811_ADR) = index;
+ EIEIO;
+ data = *(volatile unsigned char *) (SL811_DAT);
+ EIEIO;
+ return (data);
+}
+
+/*
+ * Read consecutive bytes of data from the SL811H/SL11H buffer
+ */
+static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+ *(volatile unsigned char *) (SL811_ADR) = offset;
+ EIEIO;
+ while (size--) {
+ *buf++ = *(volatile unsigned char *) (SL811_DAT);
+ EIEIO;
+ }
+}
+
+/*
+ * Write consecutive bytes of data to the SL811H/SL11H buffer
+ */
+static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
+{
+ *(volatile unsigned char *) (SL811_ADR) = offset;
+ EIEIO;
+ while (size--) {
+ *(volatile unsigned char *) (SL811_DAT) = *buf++;
+ EIEIO;
+ }
+}
+
+int usb_init_kup4x (void)
+{
+ volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
+ volatile memctl8xx_t *memctl = &immap->im_memctl;
+ int i;
+ unsigned char tmp;
+
+ memctl = &immap->im_memctl;
+ memctl->memc_or7 = 0xFFFF8726;
+ memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */
+ /* BP 14 low = USB ON */
+ immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
+ /* PB 14 nomal port */
+ immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
+ /* output */
+ immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
+
+ puts ("USB: ");
+
+ for (i = 0x10; i < 0xff; i++) {
+ sl811_write(i, i);
+ tmp = (sl811_read(i));
+ if (tmp != i) {
+ printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
+ return (-1);
+ }
+ }
+ printf ("SL811 ready\n");
+ return (0);
+}
+
+/*
+ * This function resets SL811HS controller and detects the speed of
+ * the connecting device
+ *
+ * Return: 0 = no device attached; 1 = USB device attached
+ */
+static int sl811_hc_reset(void)
+{
+ int status ;
+
+ sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+ sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+
+ mdelay(20);
+
+ /* Disable hardware SOF generation, clear all irq status. */
+ sl811_write(SL811_CTRL1, 0);
+ mdelay(2);
+ sl811_write(SL811_INTRSTS, 0xff);
+ status = sl811_read(SL811_INTRSTS);
+
+ if (status & SL811_INTR_NOTPRESENT) {
+ /* Device is not present */
+ PDEBUG(0, "Device not present\n");
+ rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
+ rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+ sl811_write(SL811_INTR, SL811_INTR_INSRMV);
+ return 0;
+ }
+
+ /* Send SOF to address 0, endpoint 0. */
+ sl811_write(SL811_LEN_B, 0);
+ sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
+ sl811_write(SL811_DEV_B, 0x00);
+ sl811_write(SL811_SOFLOW, SL811_12M_LOW);
+
+ if (status & SL811_INTR_SPEED_FULL) {
+ /* full speed device connect directly to root hub */
+ PDEBUG (0, "Full speed Device attached\n");
+
+ sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+ mdelay(20);
+ sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
+ sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
+
+ /* start the SOF or EOP */
+ sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+ rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
+ rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
+ mdelay(2);
+ sl811_write(SL811_INTRSTS, 0xff);
+ } else {
+ /* slow speed device connect directly to root-hub */
+ PDEBUG(0, "Low speed Device attached\n");
+
+ sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
+ mdelay(20);
+ sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
+ sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
+
+ /* start the SOF or EOP */
+ sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
+ rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
+ mdelay(2);
+ sl811_write(SL811_INTRSTS, 0xff);
+ }
+
+ rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
+ sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
+
+ return 1;
+}
+
+int usb_lowlevel_init(void)
+{
+ root_hub_devnum = 0;
+ sl811_hc_reset();
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ sl811_hc_reset();
+ return 0;
+}
+
+static int calc_needed_buswidth(int bytes, int need_preamble)
+{
+ return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
+}
+
+static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
+{
+ __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
+ __u16 status = 0;
+ int err = 0, time_start = get_timer(0);
+ int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+ usb_pipeslow(pipe);
+
+ if (len > 239)
+ return -1;
+
+ if (usb_pipeout(pipe))
+ ctrl |= SL811_USB_CTRL_DIR_OUT;
+ if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
+ ctrl |= SL811_USB_CTRL_TOGGLE_1;
+ if (need_preamble)
+ ctrl |= SL811_USB_CTRL_PREAMBLE;
+
+ sl811_write(SL811_INTRSTS, 0xff);
+
+ while (err < 3) {
+ sl811_write(SL811_ADDR_A, 0x10);
+ sl811_write(SL811_LEN_A, len);
+ if (usb_pipeout(pipe) && len)
+ sl811_write_buf(0x10, buffer, len);
+
+ if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
+ sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
+ ctrl |= SL811_USB_CTRL_SOF;
+ else
+ ctrl &= ~SL811_USB_CTRL_SOF;
+
+ sl811_write(SL811_CTRL_A, ctrl);
+ while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
+ if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
+ printf("USB transmit timed out\n");
+ return -USB_ST_CRC_ERR;
+ }
+ }
+
+ sl811_write(SL811_INTRSTS, 0xff);
+ status = sl811_read(SL811_STS_A);
+
+ if (status & SL811_USB_STS_ACK) {
+ int remainder = sl811_read(SL811_CNT_A);
+ if (remainder) {
+ PDEBUG(0, "usb transfer remainder = %d\n", remainder);
+ len -= remainder;
+ }
+ if (usb_pipein(pipe) && len)
+ sl811_read_buf(0x10, buffer, len);
+ return len;
+ }
+
+ if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
+ continue;
+
+ PDEBUG(0, "usb transfer error %#x\n", (int)status);
+ err++;
+ }
+
+ err = 0;
+
+ if (status & SL811_USB_STS_ERROR)
+ err |= USB_ST_BUF_ERR;
+ if (status & SL811_USB_STS_TIMEOUT)
+ err |= USB_ST_CRC_ERR;
+ if (status & SL811_USB_STS_STALL)
+ err |= USB_ST_STALLED;
+
+ return -err;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int max = usb_maxpacket(dev, pipe);
+ int done = 0;
+
+ PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
+ usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+ dev->status = 0;
+
+ sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
+ sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
+ while (done < len) {
+ int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+ max > len - done ? len - done : max);
+ if (res < 0) {
+ dev->status = -res;
+ return res;
+ }
+
+ if (!dir_out && res < max) /* short packet */
+ break;
+
+ done += res;
+ usb_dotoggle(dev, ep, dir_out);
+ }
+
+ dev->act_len = done;
+
+ return 0;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len,struct devrequest *setup)
+{
+ int done = 0;
+ int devnum = usb_pipedevice(pipe);
+ int ep = usb_pipeendpoint(pipe);
+
+ dev->status = 0;
+
+ if (devnum == root_hub_devnum)
+ return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
+
+ PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
+ devnum, ep, buffer, len, (int)setup->requesttype,
+ (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
+
+ sl811_write(SL811_DEV_A, devnum);
+ sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
+ /* setup phase */
+ usb_settoggle(dev, ep, 1, 0);
+ if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
+ (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
+ int dir_in = usb_pipein(pipe);
+ int max = usb_maxpacket(dev, pipe);
+
+ /* data phase */
+ sl811_write(SL811_PIDEP_A,
+ PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+ usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
+ while (done < len) {
+ int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
+ max > len - done ? len - done : max);
+ if (res < 0) {
+ PDEBUG(0, "status data failed!\n");
+ dev->status = -res;
+ return 0;
+ }
+ done += res;
+ usb_dotoggle(dev, ep, usb_pipeout(pipe));
+ if (dir_in && res < max) /* short packet */
+ break;
+ }
+
+ /* status phase */
+ sl811_write(SL811_PIDEP_A,
+ PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
+ usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
+ if (sl811_send_packet(dev,
+ !dir_in ? usb_rcvctrlpipe(dev, ep) :
+ usb_sndctrlpipe(dev, ep),
+ 0, 0) < 0) {
+ PDEBUG(0, "status phase failed!\n");
+ dev->status = -1;
+ }
+ } else {
+ PDEBUG(0, "setup phase failed!\n");
+ dev->status = -1;
+ }
+
+ dev->act_len = done;
+
+ return done;
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, int interval)
+{
+ PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
+ buffer, len, interval);
+ return -1;
+}
+
+/*
+ * SL811 Virtual Root Hub
+ */
+
+/* Device descriptor */
+static __u8 sl811_rh_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 sl811_rh_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x08, /* __u16 ep_wMaxPacketSize; */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+/* root hub class descriptor*/
+static __u8 sl811_rh_hub_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x01, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00,
+ 0x50, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *s, u8 *utf, int utfmax)
+{
+ int retval;
+
+ for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *s++;
+ *utf++ = 0;
+ }
+ return retval;
+}
+
+/*
+ * root_hub_string is used by each host controller's root hub code,
+ * so that they're identified consistently throughout the system.
+ */
+static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
+{
+ char buf [30];
+
+ /* assert (len > (2 * (sizeof (buf) + 1)));
+ assert (strlen (type) <= 8);*/
+
+ /* language ids */
+ if (id == 0) {
+ *data++ = 4; *data++ = 3; /* 4 bytes data */
+ *data++ = 0; *data++ = 0; /* some language id */
+ return 4;
+
+ /* serial number */
+ } else if (id == 1) {
+ sprintf (buf, "%#x", serial);
+
+ /* product description */
+ } else if (id == 2) {
+ sprintf (buf, "USB %s Root Hub", type);
+
+ /* id 3 == vendor description */
+
+ /* unsupported IDs --> "stall" */
+ } else
+ return 0;
+
+ ascii2utf (buf, data + 2, len - 2);
+ data [0] = 2 + strlen(buf) * 2;
+ data [1] = 3;
+ return data [0];
+}
+
+/* helper macro */
+#define OK(x) len = (x); break
+
+/*
+ * This function handles all USB request to the the virtual root hub
+ */
+static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
+ void *data, int buf_len, struct devrequest *cmd)
+{
+ __u8 data_buf[16];
+ __u8 *bufp = data_buf;
+ int len = 0;
+ int status = 0;
+
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+ if (usb_pipeint(pipe)) {
+ PDEBUG(0, "interrupt transfer unimplemented!\n");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = le16_to_cpu (cmd->value);
+ wIndex = le16_to_cpu (cmd->index);
+ wLength = le16_to_cpu (cmd->length);
+
+ PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
+ bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
+
+ /* Request Destination:
+ without flags: Device,
+ USB_RECIP_INTERFACE: interface,
+ USB_RECIP_ENDPOINT: endpoint,
+ USB_TYPE_CLASS means HUB here,
+ USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
+ */
+ switch (bmRType_bReq) {
+ case RH_GET_STATUS:
+ *(__u16 *)bufp = cpu_to_le16(1);
+ OK(2);
+
+ case RH_GET_STATUS | USB_RECIP_INTERFACE:
+ *(__u16 *)bufp = cpu_to_le16(0);
+ OK(2);
+
+ case RH_GET_STATUS | USB_RECIP_ENDPOINT:
+ *(__u16 *)bufp = cpu_to_le16(0);
+ OK(2);
+
+ case RH_GET_STATUS | USB_TYPE_CLASS:
+ *(__u32 *)bufp = cpu_to_le32(0);
+ OK(4);
+
+ case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
+ *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
+ OK(4);
+
+ case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
+ switch (wValue) {
+ case 1:
+ OK(0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ OK(0);
+
+ case C_HUB_OVER_CURRENT:
+ OK(0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
+ OK(0);
+
+ case USB_PORT_FEAT_SUSPEND:
+ rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
+ OK(0);
+
+ case USB_PORT_FEAT_POWER:
+ rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
+ OK(0);
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
+ OK(0);
+
+ case USB_PORT_FEAT_C_ENABLE:
+ rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
+ OK(0);
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
+ OK(0);
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
+ OK(0);
+
+ case USB_PORT_FEAT_C_RESET:
+ rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
+ OK(0);
+ }
+ break;
+
+ case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
+ OK(0);
+
+ case USB_PORT_FEAT_RESET:
+ rh_status.wPortStatus |= USB_PORT_STAT_RESET;
+ rh_status.wPortChange = 0;
+ rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
+ rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
+ rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+ OK(0);
+
+ case USB_PORT_FEAT_POWER:
+ rh_status.wPortStatus |= USB_PORT_STAT_POWER;
+ OK(0);
+
+ case USB_PORT_FEAT_ENABLE:
+ rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
+ OK(0);
+ }
+ break;
+
+ case RH_SET_ADDRESS:
+ root_hub_devnum = wValue;
+ OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case USB_DT_DEVICE:
+ len = sizeof(sl811_rh_dev_des);
+ bufp = sl811_rh_dev_des;
+ OK(len);
+
+ case USB_DT_CONFIG:
+ len = sizeof(sl811_rh_config_des);
+ bufp = sl811_rh_config_des;
+ OK(len);
+
+ case USB_DT_STRING:
+ len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
+ if (len > 0) {
+ bufp = data;
+ OK(len);
+ }
+
+ default:
+ status = -32;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
+ len = sizeof(sl811_rh_hub_des);
+ bufp = sl811_rh_hub_des;
+ OK(len);
+
+ case RH_GET_CONFIGURATION:
+ bufp[0] = 0x01;
+ OK(1);
+
+ case RH_SET_CONFIGURATION:
+ OK(0);
+
+ default:
+ PDEBUG(1, "unsupported root hub command\n");
+ status = -32;
+ }
+
+ len = min(len, buf_len);
+ if (data != bufp)
+ memcpy(data, bufp, len);
+
+ PDEBUG(5, "len = %d, status = %d\n", len, status);
+
+ usb_dev->status = status;
+ usb_dev->act_len = len;
+
+ return status == 0 ? len : status;
+}
--- /dev/null
+#ifndef __UBOOT_SL811_H
+#define __UBOOT_SL811_H
+
+#undef SL811_DEBUG
+
+#ifdef SL811_DEBUG
+ #define PDEBUG(level, fmt, args...) \
+ if (debug >= (level)) printf("[%s:%d] " fmt, \
+ __PRETTY_FUNCTION__, __LINE__ , ## args)
+#else
+ #define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* Sl811 host control register */
+#define SL811_CTRL_A 0x00
+#define SL811_ADDR_A 0x01
+#define SL811_LEN_A 0x02
+#define SL811_STS_A 0x03 /* read */
+#define SL811_PIDEP_A 0x03 /* write */
+#define SL811_CNT_A 0x04 /* read */
+#define SL811_DEV_A 0x04 /* write */
+#define SL811_CTRL1 0x05
+#define SL811_INTR 0x06
+#define SL811_CTRL_B 0x08
+#define SL811_ADDR_B 0x09
+#define SL811_LEN_B 0x0A
+#define SL811_STS_B 0x0B /* read */
+#define SL811_PIDEP_B 0x0B /* write */
+#define SL811_CNT_B 0x0C /* read */
+#define SL811_DEV_B 0x0C /* write */
+#define SL811_INTRSTS 0x0D /* write clears bitwise */
+#define SL811_HWREV 0x0E /* read */
+#define SL811_SOFLOW 0x0E /* write */
+#define SL811_SOFCNTDIV 0x0F /* read */
+#define SL811_CTRL2 0x0F /* write */
+
+/* USB control register bits (addr 0x00 and addr 0x08) */
+#define SL811_USB_CTRL_ARM 0x01
+#define SL811_USB_CTRL_ENABLE 0x02
+#define SL811_USB_CTRL_DIR_OUT 0x04
+#define SL811_USB_CTRL_ISO 0x10
+#define SL811_USB_CTRL_SOF 0x20
+#define SL811_USB_CTRL_TOGGLE_1 0x40
+#define SL811_USB_CTRL_PREAMBLE 0x80
+
+/* USB status register bits (addr 0x03 and addr 0x0B) */
+#define SL811_USB_STS_ACK 0x01
+#define SL811_USB_STS_ERROR 0x02
+#define SL811_USB_STS_TIMEOUT 0x04
+#define SL811_USB_STS_TOGGLE_1 0x08
+#define SL811_USB_STS_SETUP 0x10
+#define SL811_USB_STS_OVERFLOW 0x20
+#define SL811_USB_STS_NAK 0x40
+#define SL811_USB_STS_STALL 0x80
+
+/* Control register 1 bits (addr 0x05) */
+#define SL811_CTRL1_SOF 0x01
+#define SL811_CTRL1_RESET 0x08
+#define SL811_CTRL1_JKSTATE 0x10
+#define SL811_CTRL1_SPEED_LOW 0x20
+#define SL811_CTRL1_SUSPEND 0x40
+
+/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
+#define SL811_INTR_DONE_A 0x01
+#define SL811_INTR_DONE_B 0x02
+#define SL811_INTR_SOF 0x10
+#define SL811_INTR_INSRMV 0x20
+#define SL811_INTR_DETECT 0x40
+#define SL811_INTR_NOTPRESENT 0x40
+#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */
+
+/* HW rev and SOF lo register bits (addr 0x0E) */
+#define SL811_HWR_HWREV 0xF0
+
+/* SOF counter and control reg 2 (addr 0x0F) */
+#define SL811_CTL2_SOFHI 0x3F
+#define SL811_CTL2_DSWAP 0x40
+#define SL811_CTL2_HOST 0x80
+
+/* Set up for 1-ms SOF time. */
+#define SL811_12M_LOW 0xE0
+#define SL811_12M_HI 0x2E
+
+#define SL811_DATA_START 0x10
+#define SL811_DATA_LIMIT 240
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+
+
+#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
+
+#endif /* __UBOOT_SL811_H */
+++ /dev/null
-/*
- * ISP116x HCD (Host Controller Driver) for u-boot.
- *
- * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
- * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- *
- * Derived in part from the SL811 HCD driver "u-boot/drivers/usb/sl811_usb.c"
- * (original copyright message follows):
- *
- * (C) Copyright 2004
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * This code is based on linux driver for sl811hs chip, source at
- * drivers/usb/host/sl811.c:
- *
- * SL811 Host Controller Interface driver for USB.
- *
- * Copyright (c) 2003/06, Courage Co., Ltd.
- *
- * Based on:
- * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
- * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
- * Adam Richter, Gregory P. Smith;
- * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
- * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
- *
- * [[GNU/GPL disclaimer]]
- *
- * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
- * (original copyright message follows):
- *
- * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
- *
- * (C) Copyright 2003
- * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
- *
- * [[GNU/GPL disclaimer]]
- *
- * Note: Part of this code has been derived from linux
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include <usb.h>
-#include <malloc.h>
-#include <linux/list.h>
-
-/*
- * ISP116x chips require certain delays between accesses to its
- * registers. The following timing options exist.
- *
- * 1. Configure your memory controller (the best)
- * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
- *
- * Value is in microseconds.
- */
-#ifdef ISP116X_HCD_USE_UDELAY
-#define UDELAY 1
-#endif
-
-/*
- * On some (slowly?) machines an extra delay after data packing into
- * controller's FIFOs is required, * otherwise you may get the following
- * error:
- *
- * uboot> usb start
- * (Re)start USB...
- * USB: scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
- * isp116x: isp116x_submit_job: ****** FIFO not ready! ******
- *
- * USB device not responding, giving up (status=4)
- * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- * isp116x: isp116x_submit_job: ****** FIFO not empty! ******
- * 3 USB Device(s) found
- * scanning bus for storage devices... 0 Storage Device(s) found
- *
- * Value is in milliseconds.
- */
-#ifdef ISP116X_HCD_USE_EXTRA_DELAY
-#define EXTRA_DELAY 2
-#endif
-
-/*
- * Enable the following defines if you wish enable debugging messages.
- */
-#undef DEBUG /* enable debugging messages */
-#undef TRACE /* enable tracing code */
-#undef VERBOSE /* verbose debugging messages */
-
-#include "isp116x.h"
-
-#define DRIVER_VERSION "08 Jan 2007"
-static const char hcd_name[] = "isp116x-hcd";
-
-struct isp116x isp116x_dev;
-struct isp116x_platform_data isp116x_board;
-static int got_rhsc; /* root hub status change */
-struct usb_device *devgone; /* device which was disconnected */
-static int rh_devnum; /* address of Root Hub endpoint */
-
-/* ------------------------------------------------------------------------- */
-
-#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL))
-#define min_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-
-/* ------------------------------------------------------------------------- */
-
-static int isp116x_reset(struct isp116x *isp116x);
-
-/* --- Debugging functions ------------------------------------------------- */
-
-#define isp116x_show_reg(d, r) { \
- if ((r) < 0x20) { \
- DBG("%-12s[%02x]: %08x", #r, \
- r, isp116x_read_reg32(d, r)); \
- } else { \
- DBG("%-12s[%02x]: %04x", #r, \
- r, isp116x_read_reg16(d, r)); \
- } \
-}
-
-#define isp116x_show_regs(d) { \
- isp116x_show_reg(d, HCREVISION); \
- isp116x_show_reg(d, HCCONTROL); \
- isp116x_show_reg(d, HCCMDSTAT); \
- isp116x_show_reg(d, HCINTSTAT); \
- isp116x_show_reg(d, HCINTENB); \
- isp116x_show_reg(d, HCFMINTVL); \
- isp116x_show_reg(d, HCFMREM); \
- isp116x_show_reg(d, HCFMNUM); \
- isp116x_show_reg(d, HCLSTHRESH); \
- isp116x_show_reg(d, HCRHDESCA); \
- isp116x_show_reg(d, HCRHDESCB); \
- isp116x_show_reg(d, HCRHSTATUS); \
- isp116x_show_reg(d, HCRHPORT1); \
- isp116x_show_reg(d, HCRHPORT2); \
- isp116x_show_reg(d, HCHWCFG); \
- isp116x_show_reg(d, HCDMACFG); \
- isp116x_show_reg(d, HCXFERCTR); \
- isp116x_show_reg(d, HCuPINT); \
- isp116x_show_reg(d, HCuPINTENB); \
- isp116x_show_reg(d, HCCHIPID); \
- isp116x_show_reg(d, HCSCRATCH); \
- isp116x_show_reg(d, HCITLBUFLEN); \
- isp116x_show_reg(d, HCATLBUFLEN); \
- isp116x_show_reg(d, HCBUFSTAT); \
- isp116x_show_reg(d, HCRDITL0LEN); \
- isp116x_show_reg(d, HCRDITL1LEN); \
-}
-
-#if defined(TRACE)
-
-static int isp116x_get_current_frame_number(struct usb_device *usb_dev)
-{
- struct isp116x *isp116x = &isp116x_dev;
-
- return isp116x_read_reg32(isp116x, HCFMNUM);
-}
-
-static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, char *str)
-{
-#if defined(VERBOSE)
- int i;
-#endif
-
- DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx",
- str,
- isp116x_get_current_frame_number(dev),
- usb_pipedevice(pipe),
- usb_pipeendpoint(pipe),
- usb_pipeout(pipe) ? 'O' : 'I',
- usb_pipetype(pipe) < 2 ?
- (usb_pipeint(pipe) ?
- "INTR" : "ISOC") :
- (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status);
-#if defined(VERBOSE)
- if (len > 0 && buffer) {
- printf(__FILE__ ": data(%d):", len);
- for (i = 0; i < 16 && i < len; i++)
- printf(" %02x", ((__u8 *) buffer)[i]);
- printf("%s\n", i < len ? "..." : "");
- }
-#endif
-}
-
-#define PTD_DIR_STR(ptd) ({char __c; \
- switch(PTD_GET_DIR(ptd)){ \
- case 0: __c = 's'; break; \
- case 1: __c = 'o'; break; \
- default: __c = 'i'; break; \
- }; __c;})
-
-/*
- Dump PTD info. The code documents the format
- perfectly, right :)
-*/
-static inline void dump_ptd(struct ptd *ptd)
-{
-#if defined(VERBOSE)
- int k;
-#endif
-
- DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
- PTD_GET_CC(ptd),
- PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
- PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
- PTD_GET_TOGGLE(ptd),
- PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
-#if defined(VERBOSE)
- printf("isp116x: %s: PTD(byte): ", __FUNCTION__);
- for (k = 0; k < sizeof(struct ptd); ++k)
- printf("%02x ", ((u8 *) ptd)[k]);
- printf("\n");
-#endif
-}
-
-static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type)
-{
-#if defined(VERBOSE)
- int k;
-
- if (type == 0 /* 0ut data */ ) {
- printf("isp116x: %s: out data: ", __FUNCTION__);
- for (k = 0; k < PTD_GET_LEN(ptd); ++k)
- printf("%02x ", ((u8 *) buf)[k]);
- printf("\n");
- }
- if (type == 1 /* 1n data */ ) {
- printf("isp116x: %s: in data: ", __FUNCTION__);
- for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
- printf("%02x ", ((u8 *) buf)[k]);
- printf("\n");
- }
-
- if (PTD_GET_LAST(ptd))
- DBG("--- last PTD ---");
-#endif
-}
-
-#else
-
-#define dump_msg(dev, pipe, buffer, len, str) do { } while (0)
-#define dump_pkt(dev, pipe, buffer, len, setup, str, small) do {} while (0)
-
-#define dump_ptd(ptd) do {} while (0)
-#define dump_ptd_data(ptd, buf, type) do {} while (0)
-
-#endif
-
-/* --- Virtual Root Hub ---------------------------------------------------- */
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] = {
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x01, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] = {
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 0x01, /* __u8 bConfigurationValue; */
- 0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
- 0x00, /* __u8 MaxPower; */
-
- /* interface */
- 0x09, /* __u8 if_bLength; */
- 0x04, /* __u8 if_bDescriptorType; Interface */
- 0x00, /* __u8 if_bInterfaceNumber; */
- 0x00, /* __u8 if_bAlternateSetting; */
- 0x01, /* __u8 if_bNumEndpoints; */
- 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* __u8 if_bInterfaceSubClass; */
- 0x00, /* __u8 if_bInterfaceProtocol; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 0x02,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] = {
- 0x04, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 0x09, /* __u8 lang ID */
- 0x04, /* __u8 lang ID */
-};
-
-static unsigned char root_hub_str_index1[] = {
- 0x22, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 'I', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'S', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'P', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '1', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '1', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '6', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'x', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'R', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 't', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'u', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'b', /* __u8 Unicode */
- 0, /* __u8 Unicode */
-};
-
-/*
- * Hub class-specific descriptor is constructed dynamically
- */
-
-/* --- Virtual root hub management functions ------------------------------- */
-
-static int rh_check_port_status(struct isp116x *isp116x)
-{
- u32 temp, ndp, i;
- int res;
-
- res = -1;
- temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
- ndp = (temp & RH_A_NDP);
- for (i = 0; i < ndp; i++) {
- temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
- /* check for a device disconnect */
- if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
- (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
- res = i;
- break;
- }
- }
- return res;
-}
-
-/* --- HC management functions --------------------------------------------- */
-
-/* Write len bytes to fifo, pad till 32-bit boundary
- */
-static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
-{
- u8 *dp = (u8 *) buf;
- u16 *dp2 = (u16 *) buf;
- u16 w;
- int quot = len % 4;
-
- if ((unsigned long)dp2 & 1) {
- /* not aligned */
- for (; len > 1; len -= 2) {
- w = *dp++;
- w |= *dp++ << 8;
- isp116x_raw_write_data16(isp116x, w);
- }
- if (len)
- isp116x_write_data16(isp116x, (u16) * dp);
- } else {
- /* aligned */
- for (; len > 1; len -= 2)
- isp116x_raw_write_data16(isp116x, *dp2++);
- if (len)
- isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
- }
- if (quot == 1 || quot == 2)
- isp116x_raw_write_data16(isp116x, 0);
-}
-
-/* Read len bytes from fifo and then read till 32-bit boundary
- */
-static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
-{
- u8 *dp = (u8 *) buf;
- u16 *dp2 = (u16 *) buf;
- u16 w;
- int quot = len % 4;
-
- if ((unsigned long)dp2 & 1) {
- /* not aligned */
- for (; len > 1; len -= 2) {
- w = isp116x_raw_read_data16(isp116x);
- *dp++ = w & 0xff;
- *dp++ = (w >> 8) & 0xff;
- }
- if (len)
- *dp = 0xff & isp116x_read_data16(isp116x);
- } else {
- /* aligned */
- for (; len > 1; len -= 2)
- *dp2++ = isp116x_raw_read_data16(isp116x);
- if (len)
- *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
- }
- if (quot == 1 || quot == 2)
- isp116x_raw_read_data16(isp116x);
-}
-
-/* Write PTD's and data for scheduled transfers into the fifo ram.
- * Fifo must be empty and ready */
-static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
- unsigned long pipe, struct ptd *ptd, int n, void *data,
- int len)
-{
- int buflen = n * sizeof(struct ptd) + len;
- int i, done;
-
- DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
-
- isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
- isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
- isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
-
- done = 0;
- for (i = 0; i < n; i++) {
- DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
-
- dump_ptd(&ptd[i]);
- isp116x_write_data16(isp116x, ptd[i].count);
- isp116x_write_data16(isp116x, ptd[i].mps);
- isp116x_write_data16(isp116x, ptd[i].len);
- isp116x_write_data16(isp116x, ptd[i].faddr);
-
- dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);
- write_ptddata_to_fifo(isp116x,
- (__u8 *) data + done,
- PTD_GET_LEN(&ptd[i]));
-
- done += PTD_GET_LEN(&ptd[i]);
- }
-}
-
-/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
- * Fifo must be full and done */
-static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
- unsigned long pipe, struct ptd *ptd, int n, void *data,
- int len)
-{
- int buflen = n * sizeof(struct ptd) + len;
- int i, done, cc, ret;
-
- isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
- isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
- isp116x_write_addr(isp116x, HCATLPORT);
-
- ret = TD_CC_NOERROR;
- done = 0;
- for (i = 0; i < n; i++) {
- DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
-
- ptd[i].count = isp116x_read_data16(isp116x);
- ptd[i].mps = isp116x_read_data16(isp116x);
- ptd[i].len = isp116x_read_data16(isp116x);
- ptd[i].faddr = isp116x_read_data16(isp116x);
- dump_ptd(&ptd[i]);
-
- read_ptddata_from_fifo(isp116x,
- (__u8 *) data + done,
- PTD_GET_LEN(&ptd[i]));
- dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);
-
- done += PTD_GET_LEN(&ptd[i]);
-
- cc = PTD_GET_CC(&ptd[i]);
-
- /* Data underrun means basically that we had more buffer space than
- * the function had data. It is perfectly normal but upper levels have
- * to know how much we actually transferred.
- */
- if (cc == TD_NOTACCESSED ||
- (cc != TD_CC_NOERROR && (ret == TD_CC_NOERROR || ret == TD_DATAUNDERRUN)))
- ret = cc;
- }
-
- DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
-
- return ret;
-}
-
-/* Interrupt handling
- */
-static int isp116x_interrupt(struct isp116x *isp116x)
-{
- u16 irqstat;
- u32 intstat;
- int ret = 0;
-
- isp116x_write_reg16(isp116x, HCuPINTENB, 0);
- irqstat = isp116x_read_reg16(isp116x, HCuPINT);
- isp116x_write_reg16(isp116x, HCuPINT, irqstat);
- DBG(">>>>>> irqstat %x <<<<<<", irqstat);
-
- if (irqstat & HCuPINT_ATL) {
- DBG(">>>>>> HCuPINT_ATL <<<<<<");
- udelay(500);
- ret = 1;
- }
-
- if (irqstat & HCuPINT_OPR) {
- intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
- isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
- DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);
-
- if (intstat & HCINT_UE) {
- ERR("unrecoverable error, controller disabled");
-
- /* FIXME: be optimistic, hope that bug won't repeat
- * often. Make some non-interrupt context restart the
- * controller. Count and limit the retries though;
- * either hardware or software errors can go forever...
- */
- isp116x_reset(isp116x);
- ret = -1;
- return -1;
- }
-
- if (intstat & HCINT_RHSC) {
- got_rhsc = 1;
- ret = 1;
- /* When root hub or any of its ports is going
- to come out of suspend, it may take more
- than 10ms for status bits to stabilize. */
- wait_ms(20);
- }
-
- if (intstat & HCINT_SO) {
- ERR("schedule overrun");
- ret = -1;
- }
-
- irqstat &= ~HCuPINT_OPR;
- }
-
- return ret;
-}
-
-/* With one PTD we can transfer almost 1K in one go;
- * HC does the splitting into endpoint digestible transactions
- */
-struct ptd ptd[1];
-
-static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
-{
- unsigned mpck = usb_maxpacket(dev, pipe);
-
- /* One PTD can transfer 1023 bytes but try to always
- * transfer multiples of endpoint buffer size
- */
- return 1023 / mpck * mpck;
-}
-
-/* Do an USB transfer
- */
-static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
- int dir, void *buffer, int len)
-{
- struct isp116x *isp116x = &isp116x_dev;
- int type = usb_pipetype(pipe);
- int epnum = usb_pipeendpoint(pipe);
- int max = usb_maxpacket(dev, pipe);
- int dir_out = usb_pipeout(pipe);
- int speed_low = usb_pipeslow(pipe);
- int i, done = 0, stat, timeout, cc;
-
- /* 500 frames or 0.5s timeout when function is busy and NAKs transactions for a while */
- int retries = 500;
-
- DBG("------------------------------------------------");
- dump_msg(dev, pipe, buffer, len, "SUBMIT");
- DBG("------------------------------------------------");
-
- if (len >= 1024) {
- ERR("Too big job");
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- if (isp116x->disabled) {
- ERR("EPIPE");
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- /* device pulled? Shortcut the action. */
- if (devgone == dev) {
- ERR("ENODEV");
- dev->status = USB_ST_CRC_ERR;
- return USB_ST_CRC_ERR;
- }
-
- if (!max) {
- ERR("pipesize for pipe %lx is zero", pipe);
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- if (type == PIPE_ISOCHRONOUS) {
- ERR("isochronous transfers not supported");
- dev->status = USB_ST_CRC_ERR;
- return -1;
- }
-
- /* FIFO not empty? */
- if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {
- ERR("****** FIFO not empty! ******");
- dev->status = USB_ST_BUF_ERR;
- return -1;
- }
-
- retry:
- isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
-
- /* Prepare the PTD data */
- ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK |
- PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
- ptd->mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum) | PTD_LAST_MSK;
- ptd->len = PTD_LEN(len) | PTD_DIR(dir);
- ptd->faddr = PTD_FA(usb_pipedevice(pipe));
-
-retry_same:
- /* Pack data into FIFO ram */
- pack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
-#ifdef EXTRA_DELAY
- wait_ms(EXTRA_DELAY);
-#endif
-
- /* Start the data transfer */
-
- /* Allow more time for a BULK device to react - some are slow */
- if (usb_pipebulk(pipe))
- timeout = 5000;
- else
- timeout = 100;
-
- /* Wait for it to complete */
- for (;;) {
- /* Check whether the controller is done */
- stat = isp116x_interrupt(isp116x);
-
- if (stat < 0) {
- dev->status = USB_ST_CRC_ERR;
- break;
- }
- if (stat > 0)
- break;
-
- /* Check the timeout */
- if (--timeout)
- udelay(1);
- else {
- ERR("CTL:TIMEOUT ");
- stat = USB_ST_CRC_ERR;
- break;
- }
- }
-
- /* We got an Root Hub Status Change interrupt */
- if (got_rhsc) {
- isp116x_show_regs(isp116x);
-
- got_rhsc = 0;
-
- /* Abuse timeout */
- timeout = rh_check_port_status(isp116x);
- if (timeout >= 0) {
- /*
- * FIXME! NOTE! AAAARGH!
- * This is potentially dangerous because it assumes
- * that only one device is ever plugged in!
- */
- devgone = dev;
- }
- }
-
- /* Ok, now we can read transfer status */
-
- /* FIFO not ready? */
- if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {
- ERR("****** FIFO not ready! ******");
- dev->status = USB_ST_BUF_ERR;
- return -1;
- }
-
- /* Unpack data from FIFO ram */
- cc = unpack_fifo(isp116x, dev, pipe, ptd, 1, buffer, len);
-
- i = PTD_GET_COUNT(ptd);
- done += i;
- buffer += i;
- len -= i;
-
- /* There was some kind of real problem; Prepare the PTD again
- * and retry from the failed transaction on
- */
- if (cc && cc != TD_NOTACCESSED && cc != TD_DATAUNDERRUN) {
- if (retries >= 100) {
- retries -= 100;
- /* The chip will have toggled the toggle bit for the failed
- * transaction too. We have to toggle it back.
- */
- usb_settoggle(dev, epnum, dir_out, !PTD_GET_TOGGLE(ptd));
- goto retry;
- }
- }
- /* "Normal" errors; TD_NOTACCESSED would mean in effect that the function have NAKed
- * the transactions from the first on for the whole frame. It may be busy and we retry
- * with the same PTD. PTD_ACTIVE (and not TD_NOTACCESSED) would mean that some of the
- * PTD didn't make it because the function was busy or the frame ended before the PTD
- * finished. We prepare the rest of the data and try again.
- */
- else if (cc == TD_NOTACCESSED || PTD_GET_ACTIVE(ptd) || (cc != TD_DATAUNDERRUN && PTD_GET_COUNT(ptd) < PTD_GET_LEN(ptd))) {
- if (retries) {
- --retries;
- if (cc == TD_NOTACCESSED && PTD_GET_ACTIVE(ptd) && !PTD_GET_COUNT(ptd)) goto retry_same;
- usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
- goto retry;
- }
- }
-
- if (cc != TD_CC_NOERROR && cc != TD_DATAUNDERRUN) {
- DBG("****** completition code error %x ******", cc);
- switch (cc) {
- case TD_CC_BITSTUFFING:
- dev->status = USB_ST_BIT_ERR;
- break;
- case TD_CC_STALL:
- dev->status = USB_ST_STALLED;
- break;
- case TD_BUFFEROVERRUN:
- case TD_BUFFERUNDERRUN:
- dev->status = USB_ST_BUF_ERR;
- break;
- default:
- dev->status = USB_ST_CRC_ERR;
- }
- return -cc;
- }
- else usb_settoggle(dev, epnum, dir_out, PTD_GET_TOGGLE(ptd));
-
- dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
-
- dev->status = 0;
- return done;
-}
-
-/* Adapted from au1x00_usb_ohci.c
- */
-static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len,
- struct devrequest *cmd)
-{
- struct isp116x *isp116x = &isp116x_dev;
- u32 tmp = 0;
-
- int leni = transfer_len;
- int len = 0;
- int stat = 0;
- u32 datab[4];
- u8 *data_buf = (u8 *) datab;
- u16 bmRType_bReq;
- u16 wValue;
- u16 wIndex;
- u16 wLength;
-
- if (usb_pipeint(pipe)) {
- INFO("Root-Hub submit IRQ: NOT implemented");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = swap_16(cmd->value);
- wIndex = swap_16(cmd->index);
- wLength = swap_16(cmd->length);
-
- DBG("--- HUB ----------------------------------------");
- DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",
- bmRType_bReq, wValue, wIndex, wLength);
- dump_msg(dev, pipe, buffer, transfer_len, "RH");
- DBG("------------------------------------------------");
-
- switch (bmRType_bReq) {
- case RH_GET_STATUS:
- DBG("RH_GET_STATUS");
-
- *(__u16 *) data_buf = swap_16(1);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_INTERFACE:
- DBG("RH_GET_STATUS | RH_INTERFACE");
-
- *(__u16 *) data_buf = swap_16(0);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_ENDPOINT:
- DBG("RH_GET_STATUS | RH_ENDPOINT");
-
- *(__u16 *) data_buf = swap_16(0);
- len = 2;
- break;
-
- case RH_GET_STATUS | RH_CLASS:
- DBG("RH_GET_STATUS | RH_CLASS");
-
- tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
-
- *(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
- len = 4;
- break;
-
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");
-
- tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
- *(__u32 *) data_buf = swap_32(tmp);
- isp116x_show_regs(isp116x);
- len = 4;
- break;
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");
-
- switch (wValue) {
- case RH_ENDPOINT_STALL:
- DBG("C_HUB_ENDPOINT_STALL");
- len = 0;
- break;
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- DBG("RH_CLEAR_FEATURE | RH_CLASS");
-
- switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- DBG("C_HUB_LOCAL_POWER");
- len = 0;
- break;
-
- case RH_C_HUB_OVER_CURRENT:
- DBG("C_HUB_OVER_CURRENT");
- isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
- len = 0;
- break;
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");
-
- switch (wValue) {
- case RH_PORT_ENABLE:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_CCS);
- len = 0;
- break;
-
- case RH_PORT_SUSPEND:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_POCI);
- len = 0;
- break;
-
- case RH_PORT_POWER:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_LSDA);
- len = 0;
- break;
-
- case RH_C_PORT_CONNECTION:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_CSC);
- len = 0;
- break;
-
- case RH_C_PORT_ENABLE:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PESC);
- len = 0;
- break;
-
- case RH_C_PORT_SUSPEND:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PSSC);
- len = 0;
- break;
-
- case RH_C_PORT_OVER_CURRENT:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_POCI);
- len = 0;
- break;
-
- case RH_C_PORT_RESET:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PRSC);
- len = 0;
- break;
-
- default:
- ERR("invalid wValue");
- stat = USB_ST_STALLED;
- }
-
- isp116x_show_regs(isp116x);
-
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS");
-
- switch (wValue) {
- case RH_PORT_SUSPEND:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PSS);
- len = 0;
- break;
-
- case RH_PORT_RESET:
- /* Spin until any current reset finishes */
- while (1) {
- tmp =
- isp116x_read_reg32(isp116x,
- HCRHPORT1 + wIndex - 1);
- if (!(tmp & RH_PS_PRS))
- break;
- wait_ms(1);
- }
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PRS);
- wait_ms(10);
-
- len = 0;
- break;
-
- case RH_PORT_POWER:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PPS);
- len = 0;
- break;
-
- case RH_PORT_ENABLE:
- isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
- RH_PS_PES);
- len = 0;
- break;
-
- default:
- ERR("invalid wValue");
- stat = USB_ST_STALLED;
- }
-
- isp116x_show_regs(isp116x);
-
- break;
-
- case RH_SET_ADDRESS:
- DBG("RH_SET_ADDRESS");
-
- rh_devnum = wValue;
- len = 0;
- break;
-
- case RH_GET_DESCRIPTOR:
- DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength);
-
- switch (wValue) {
- case (USB_DT_DEVICE << 8): /* device descriptor */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des;
- break;
-
- case (USB_DT_CONFIG << 8): /* configuration descriptor */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des;
- break;
-
- case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_str_index0),
- wLength));
- data_buf = root_hub_str_index0;
- break;
-
- case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */
- len = min_t(unsigned int,
- leni, min_t(unsigned int,
- sizeof(root_hub_str_index1),
- wLength));
- data_buf = root_hub_str_index1;
- break;
-
- default:
- ERR("invalid wValue");
- stat = USB_ST_STALLED;
- }
-
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS:
- DBG("RH_GET_DESCRIPTOR | RH_CLASS");
-
- tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
-
- data_buf[0] = 0x09; /* min length; */
- data_buf[1] = 0x29;
- data_buf[2] = tmp & RH_A_NDP;
- data_buf[3] = 0;
- if (tmp & RH_A_PSM) /* per-port power switching? */
- data_buf[3] |= 0x01;
- if (tmp & RH_A_NOCP) /* no overcurrent reporting? */
- data_buf[3] |= 0x10;
- else if (tmp & RH_A_OCPM) /* per-port overcurrent rep? */
- data_buf[3] |= 0x08;
-
- /* Corresponds to data_buf[4-7] */
- datab[1] = 0;
- data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
-
- tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
-
- data_buf[7] = tmp & RH_B_DR;
- if (data_buf[2] < 7)
- data_buf[8] = 0xff;
- else {
- data_buf[0] += 2;
- data_buf[8] = (tmp & RH_B_DR) >> 8;
- data_buf[10] = data_buf[9] = 0xff;
- }
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data_buf[0], wLength));
- break;
-
- case RH_GET_CONFIGURATION:
- DBG("RH_GET_CONFIGURATION");
-
- *(__u8 *) data_buf = 0x01;
- len = 1;
- break;
-
- case RH_SET_CONFIGURATION:
- DBG("RH_SET_CONFIGURATION");
-
- isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
- len = 0;
- break;
-
- default:
- ERR("*** *** *** unsupported root hub command *** *** ***");
- stat = USB_ST_STALLED;
- }
-
- len = min_t(int, len, leni);
- if (buffer != data_buf)
- memcpy(buffer, data_buf, len);
-
- dev->act_len = len;
- dev->status = stat;
- DBG("dev act_len %d, status %d", dev->act_len, dev->status);
-
- dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
-
- return stat;
-}
-
-/* --- Transfer functions -------------------------------------------------- */
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, int interval)
-{
- DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d",
- dev, pipe, buffer, len, interval);
-
- return -1;
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, struct devrequest *setup)
-{
- int devnum = usb_pipedevice(pipe);
- int epnum = usb_pipeendpoint(pipe);
- int max = max_transfer_len(dev, pipe);
- int dir_in = usb_pipein(pipe);
- int done, ret;
-
- /* Control message is for the HUB? */
- if (devnum == rh_devnum)
- return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
-
- /* Ok, no HUB message so send the message to the device */
-
- /* Setup phase */
- DBG("--- SETUP PHASE --------------------------------");
- usb_settoggle(dev, epnum, 1, 0);
- ret = isp116x_submit_job(dev, pipe,
- PTD_DIR_SETUP,
- setup, sizeof(struct devrequest));
- if (ret < 0) {
- DBG("control setup phase error (ret = %d", ret);
- return -1;
- }
-
- /* Data phase */
- DBG("--- DATA PHASE ---------------------------------");
- done = 0;
- usb_settoggle(dev, epnum, !dir_in, 1);
- while (done < len) {
- ret = isp116x_submit_job(dev, pipe,
- dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
- (__u8 *) buffer + done,
- max > len - done ? len - done : max);
- if (ret < 0) {
- DBG("control data phase error (ret = %d)", ret);
- return -1;
- }
- done += ret;
-
- if (dir_in && ret < max) /* short packet */
- break;
- }
-
- /* Status phase */
- DBG("--- STATUS PHASE -------------------------------");
- usb_settoggle(dev, epnum, !dir_in, 1);
- ret = isp116x_submit_job(dev, pipe,
- !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
- if (ret < 0) {
- DBG("control status phase error (ret = %d", ret);
- return -1;
- }
-
- dev->act_len = done;
-
- dump_msg(dev, pipe, buffer, len, "DEV(ret)");
-
- return done;
-}
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len)
-{
- int dir_out = usb_pipeout(pipe);
- int max = max_transfer_len(dev, pipe);
- int done, ret;
-
- DBG("--- BULK ---------------------------------------");
- DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d",
- usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
-
- done = 0;
- while (done < len) {
- ret = isp116x_submit_job(dev, pipe,
- !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
- (__u8 *) buffer + done,
- max > len - done ? len - done : max);
- if (ret < 0) {
- DBG("error on bulk message (ret = %d)", ret);
- return -1;
- }
-
- done += ret;
-
- if (!dir_out && ret < max) /* short packet */
- break;
- }
-
- dev->act_len = done;
-
- return 0;
-}
-
-/* --- Basic functions ----------------------------------------------------- */
-
-static int isp116x_sw_reset(struct isp116x *isp116x)
-{
- int retries = 15;
- int ret = 0;
-
- DBG("");
-
- isp116x->disabled = 1;
-
- isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
- isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
- while (--retries) {
- /* It usually resets within 1 ms */
- wait_ms(1);
- if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
- break;
- }
- if (!retries) {
- ERR("software reset timeout");
- ret = -1;
- }
- return ret;
-}
-
-static int isp116x_reset(struct isp116x *isp116x)
-{
- unsigned long t;
- u16 clkrdy = 0;
- int ret, timeout = 15 /* ms */ ;
-
- DBG("");
-
- ret = isp116x_sw_reset(isp116x);
- if (ret)
- return ret;
-
- for (t = 0; t < timeout; t++) {
- clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
- if (clkrdy)
- break;
- wait_ms(1);
- }
- if (!clkrdy) {
- ERR("clock not ready after %dms", timeout);
- /* After sw_reset the clock won't report to be ready, if
- H_WAKEUP pin is high. */
- ERR("please make sure that the H_WAKEUP pin is pulled low!");
- ret = -1;
- }
- return ret;
-}
-
-static void isp116x_stop(struct isp116x *isp116x)
-{
- u32 val;
-
- DBG("");
-
- isp116x_write_reg16(isp116x, HCuPINTENB, 0);
-
- /* Switch off ports' power, some devices don't come up
- after next 'start' without this */
- val = isp116x_read_reg32(isp116x, HCRHDESCA);
- val &= ~(RH_A_NPS | RH_A_PSM);
- isp116x_write_reg32(isp116x, HCRHDESCA, val);
- isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
-
- isp116x_sw_reset(isp116x);
-}
-
-/*
- * Configure the chip. The chip must be successfully reset by now.
- */
-static int isp116x_start(struct isp116x *isp116x)
-{
- struct isp116x_platform_data *board = isp116x->board;
- u32 val;
-
- DBG("");
-
- /* Clear interrupt status and disable all interrupt sources */
- isp116x_write_reg16(isp116x, HCuPINT, 0xff);
- isp116x_write_reg16(isp116x, HCuPINTENB, 0);
-
- isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
- isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
-
- /* Hardware configuration */
- val = HCHWCFG_DBWIDTH(1);
- if (board->sel15Kres)
- val |= HCHWCFG_15KRSEL;
- /* Remote wakeup won't work without working clock */
- if (board->remote_wakeup_enable)
- val |= HCHWCFG_CLKNOTSTOP;
- if (board->oc_enable)
- val |= HCHWCFG_ANALOG_OC;
- isp116x_write_reg16(isp116x, HCHWCFG, val);
-
- /* --- Root hub configuration */
- val = (25 << 24) & RH_A_POTPGT;
- /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
- be always set. Yet, instead, we request individual port
- power switching. */
- val |= RH_A_PSM;
- /* Report overcurrent per port */
- val |= RH_A_OCPM;
- isp116x_write_reg32(isp116x, HCRHDESCA, val);
- isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
-
- val = RH_B_PPCM;
- isp116x_write_reg32(isp116x, HCRHDESCB, val);
- isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
-
- val = 0;
- if (board->remote_wakeup_enable)
- val |= RH_HS_DRWE;
- isp116x_write_reg32(isp116x, HCRHSTATUS, val);
- isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
-
- isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
-
- /* Go operational */
- val = HCCONTROL_USB_OPER;
- if (board->remote_wakeup_enable)
- val |= HCCONTROL_RWE;
- isp116x_write_reg32(isp116x, HCCONTROL, val);
-
- /* Disable ports to avoid race in device enumeration */
- isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
- isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
-
- isp116x_show_regs(isp116x);
-
- isp116x->disabled = 0;
-
- return 0;
-}
-
-/* --- Init functions ------------------------------------------------------ */
-
-int isp116x_check_id(struct isp116x *isp116x)
-{
- int val;
-
- val = isp116x_read_reg16(isp116x, HCCHIPID);
- if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
- ERR("invalid chip ID %04x", val);
- return -1;
- }
-
- return 0;
-}
-
-int usb_lowlevel_init(void)
-{
- struct isp116x *isp116x = &isp116x_dev;
-
- DBG("");
-
- got_rhsc = rh_devnum = 0;
-
- /* Init device registers addr */
- isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
- isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
-
- /* Setup specific board settings */
-#ifdef ISP116X_HCD_SEL15kRES
- isp116x_board.sel15Kres = 1;
-#endif
-#ifdef ISP116X_HCD_OC_ENABLE
- isp116x_board.oc_enable = 1;
-#endif
-#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
- isp116x_board.remote_wakeup_enable = 1;
-#endif
- isp116x->board = &isp116x_board;
-
- /* Try to get ISP116x silicon chip ID */
- if (isp116x_check_id(isp116x) < 0)
- return -1;
-
- isp116x->disabled = 1;
- isp116x->sleeping = 0;
-
- isp116x_reset(isp116x);
- isp116x_start(isp116x);
-
- return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
- struct isp116x *isp116x = &isp116x_dev;
-
- DBG("");
-
- if (!isp116x->disabled)
- isp116x_stop(isp116x);
-
- return 0;
-}
+++ /dev/null
-/*
- * ISP116x register declarations and HCD data structures
- *
- * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
- * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
- * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
- * Portions:
- * Copyright (C) 2004 Lothar Wassmann
- * Copyright (C) 2004 Psion Teklogix
- * Copyright (C) 2004 David Brownell
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifdef DEBUG
-#define DBG(fmt, args...) \
- printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#else
-#define DBG(fmt, args...) do {} while (0)
-#endif
-
-#ifdef VERBOSE
-# define VDBG DBG
-#else
-# define VDBG(fmt, args...) do {} while (0)
-#endif
-
-#define ERR(fmt, args...) \
- printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#define WARN(fmt, args...) \
- printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
-#define INFO(fmt, args...) \
- printf("isp116x: " fmt "\n" , ## args)
-
-/* ------------------------------------------------------------------------- */
-
-/* us of 1ms frame */
-#define MAX_LOAD_LIMIT 850
-
-/* Full speed: max # of bytes to transfer for a single urb
- at a time must be < 1024 && must be multiple of 64.
- 832 allows transfering 4kiB within 5 frames. */
-#define MAX_TRANSFER_SIZE_FULLSPEED 832
-
-/* Low speed: there is no reason to schedule in very big
- chunks; often the requested long transfers are for
- string descriptors containing short strings. */
-#define MAX_TRANSFER_SIZE_LOWSPEED 64
-
-/* Bytetime (us), a rough indication of how much time it
- would take to transfer a byte of useful data over USB */
-#define BYTE_TIME_FULLSPEED 1
-#define BYTE_TIME_LOWSPEED 20
-
-/* Buffer sizes */
-#define ISP116x_BUF_SIZE 4096
-#define ISP116x_ITL_BUFSIZE 0
-#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
-
-#define ISP116x_WRITE_OFFSET 0x80
-
-/* --- ISP116x registers/bits ---------------------------------------------- */
-
-#define HCREVISION 0x00
-#define HCCONTROL 0x01
-#define HCCONTROL_HCFS (3 << 6) /* host controller
- functional state */
-#define HCCONTROL_USB_RESET (0 << 6)
-#define HCCONTROL_USB_RESUME (1 << 6)
-#define HCCONTROL_USB_OPER (2 << 6)
-#define HCCONTROL_USB_SUSPEND (3 << 6)
-#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */
-#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */
-#define HCCMDSTAT 0x02
-#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */
-#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */
-#define HCINTSTAT 0x03
-#define HCINT_SO (1 << 0) /* scheduling overrun */
-#define HCINT_WDH (1 << 1) /* writeback of done_head */
-#define HCINT_SF (1 << 2) /* start frame */
-#define HCINT_RD (1 << 3) /* resume detect */
-#define HCINT_UE (1 << 4) /* unrecoverable error */
-#define HCINT_FNO (1 << 5) /* frame number overflow */
-#define HCINT_RHSC (1 << 6) /* root hub status change */
-#define HCINT_OC (1 << 30) /* ownership change */
-#define HCINT_MIE (1 << 31) /* master interrupt enable */
-#define HCINTENB 0x04
-#define HCINTDIS 0x05
-#define HCFMINTVL 0x0d
-#define HCFMREM 0x0e
-#define HCFMNUM 0x0f
-#define HCLSTHRESH 0x11
-#define HCRHDESCA 0x12
-#define RH_A_NDP (0x3 << 0) /* # downstream ports */
-#define RH_A_PSM (1 << 8) /* power switching mode */
-#define RH_A_NPS (1 << 9) /* no power switching */
-#define RH_A_DT (1 << 10) /* device type (mbz) */
-#define RH_A_OCPM (1 << 11) /* overcurrent protection
- mode */
-#define RH_A_NOCP (1 << 12) /* no overcurrent protection */
-#define RH_A_POTPGT (0xff << 24) /* power on -> power good
- time */
-#define HCRHDESCB 0x13
-#define RH_B_DR (0xffff << 0) /* device removable flags */
-#define RH_B_PPCM (0xffff << 16) /* port power control mask */
-#define HCRHSTATUS 0x14
-#define RH_HS_LPS (1 << 0) /* local power status */
-#define RH_HS_OCI (1 << 1) /* over current indicator */
-#define RH_HS_DRWE (1 << 15) /* device remote wakeup
- enable */
-#define RH_HS_LPSC (1 << 16) /* local power status change */
-#define RH_HS_OCIC (1 << 17) /* over current indicator
- change */
-#define RH_HS_CRWE (1 << 31) /* clear remote wakeup
- enable */
-#define HCRHPORT1 0x15
-#define RH_PS_CCS (1 << 0) /* current connect status */
-#define RH_PS_PES (1 << 1) /* port enable status */
-#define RH_PS_PSS (1 << 2) /* port suspend status */
-#define RH_PS_POCI (1 << 3) /* port over current
- indicator */
-#define RH_PS_PRS (1 << 4) /* port reset status */
-#define RH_PS_PPS (1 << 8) /* port power status */
-#define RH_PS_LSDA (1 << 9) /* low speed device attached */
-#define RH_PS_CSC (1 << 16) /* connect status change */
-#define RH_PS_PESC (1 << 17) /* port enable status change */
-#define RH_PS_PSSC (1 << 18) /* port suspend status
- change */
-#define RH_PS_OCIC (1 << 19) /* over current indicator
- change */
-#define RH_PS_PRSC (1 << 20) /* port reset status change */
-#define HCRHPORT_CLRMASK (0x1f << 16)
-#define HCRHPORT2 0x16
-#define HCHWCFG 0x20
-#define HCHWCFG_15KRSEL (1 << 12)
-#define HCHWCFG_CLKNOTSTOP (1 << 11)
-#define HCHWCFG_ANALOG_OC (1 << 10)
-#define HCHWCFG_DACK_MODE (1 << 8)
-#define HCHWCFG_EOT_POL (1 << 7)
-#define HCHWCFG_DACK_POL (1 << 6)
-#define HCHWCFG_DREQ_POL (1 << 5)
-#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
-#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
-#define HCHWCFG_INT_POL (1 << 2)
-#define HCHWCFG_INT_TRIGGER (1 << 1)
-#define HCHWCFG_INT_ENABLE (1 << 0)
-#define HCDMACFG 0x21
-#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
-#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
-#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
-#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
-#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
-#define HCDMACFG_DMA_ENABLE (1 << 4)
-#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
-#define HCDMACFG_CTR_SEL (1 << 2)
-#define HCDMACFG_ITLATL_SEL (1 << 1)
-#define HCDMACFG_DMA_RW_SELECT (1 << 0)
-#define HCXFERCTR 0x22
-#define HCuPINT 0x24
-#define HCuPINT_SOF (1 << 0)
-#define HCuPINT_ATL (1 << 1)
-#define HCuPINT_AIIEOT (1 << 2)
-#define HCuPINT_OPR (1 << 4)
-#define HCuPINT_SUSP (1 << 5)
-#define HCuPINT_CLKRDY (1 << 6)
-#define HCuPINTENB 0x25
-#define HCCHIPID 0x27
-#define HCCHIPID_MASK 0xff00
-#define HCCHIPID_MAGIC 0x6100
-#define HCSCRATCH 0x28
-#define HCSWRES 0x29
-#define HCSWRES_MAGIC 0x00f6
-#define HCITLBUFLEN 0x2a
-#define HCATLBUFLEN 0x2b
-#define HCBUFSTAT 0x2c
-#define HCBUFSTAT_ITL0_FULL (1 << 0)
-#define HCBUFSTAT_ITL1_FULL (1 << 1)
-#define HCBUFSTAT_ATL_FULL (1 << 2)
-#define HCBUFSTAT_ITL0_DONE (1 << 3)
-#define HCBUFSTAT_ITL1_DONE (1 << 4)
-#define HCBUFSTAT_ATL_DONE (1 << 5)
-#define HCRDITL0LEN 0x2d
-#define HCRDITL1LEN 0x2e
-#define HCITLPORT 0x40
-#define HCATLPORT 0x41
-
-/* PTD accessor macros. */
-#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
-#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
-#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
-#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
-#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
-#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
-#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
-#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
-#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
-#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
-#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
-#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
-#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
-#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
-#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
-#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
-#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
-#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
-#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
-#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
-#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
-#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
-#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
-#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
-#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
-#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
-
-/* Hardware transfer status codes -- CC from ptd->count */
-#define TD_CC_NOERROR 0x00
-#define TD_CC_CRC 0x01
-#define TD_CC_BITSTUFFING 0x02
-#define TD_CC_DATATOGGLEM 0x03
-#define TD_CC_STALL 0x04
-#define TD_DEVNOTRESP 0x05
-#define TD_PIDCHECKFAIL 0x06
-#define TD_UNEXPECTEDPID 0x07
-#define TD_DATAOVERRUN 0x08
-#define TD_DATAUNDERRUN 0x09
- /* 0x0A, 0x0B reserved for hardware */
-#define TD_BUFFEROVERRUN 0x0C
-#define TD_BUFFERUNDERRUN 0x0D
- /* 0x0E, 0x0F reserved for HCD */
-#define TD_NOTACCESSED 0x0F
-
-/* ------------------------------------------------------------------------- */
-
-#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
-#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
-
-/* Philips transfer descriptor */
-struct ptd {
- u16 count;
-#define PTD_COUNT_MSK (0x3ff << 0)
-#define PTD_TOGGLE_MSK (1 << 10)
-#define PTD_ACTIVE_MSK (1 << 11)
-#define PTD_CC_MSK (0xf << 12)
- u16 mps;
-#define PTD_MPS_MSK (0x3ff << 0)
-#define PTD_SPD_MSK (1 << 10)
-#define PTD_LAST_MSK (1 << 11)
-#define PTD_EP_MSK (0xf << 12)
- u16 len;
-#define PTD_LEN_MSK (0x3ff << 0)
-#define PTD_DIR_MSK (3 << 10)
-#define PTD_DIR_SETUP (0)
-#define PTD_DIR_OUT (1)
-#define PTD_DIR_IN (2)
-#define PTD_B5_5_MSK (1 << 13)
- u16 faddr;
-#define PTD_FA_MSK (0x7f << 0)
-#define PTD_FMT_MSK (1 << 7)
-} __attribute__ ((packed, aligned(2)));
-
-struct isp116x_ep {
- struct usb_device *udev;
- struct ptd ptd;
-
- u8 maxpacket;
- u8 epnum;
- u8 nextpid;
-
- u16 length; /* of current packet */
- unsigned char *data; /* to databuf */
-
- u16 error_count;
-};
-
-/* URB struct */
-#define N_URB_TD 48
-#define URB_DEL 1
-typedef struct {
- struct isp116x_ep *ed;
- void *transfer_buffer; /* (in) associated data buffer */
- int actual_length; /* (return) actual transfer length */
- unsigned long pipe; /* (in) pipe information */
-#if 0
- int state;
-#endif
-} urb_priv_t;
-
-struct isp116x_platform_data {
- /* Enable internal resistors on downstream ports */
- unsigned sel15Kres:1;
- /* On-chip overcurrent detection */
- unsigned oc_enable:1;
- /* Enable wakeup by devices on usb bus (e.g. wakeup
- by attachment/detachment or by device activity
- such as moving a mouse). When chosen, this option
- prevents stopping internal clock, increasing
- thereby power consumption in suspended state. */
- unsigned remote_wakeup_enable:1;
-};
-
-struct isp116x {
- u16 *addr_reg;
- u16 *data_reg;
-
- struct isp116x_platform_data *board;
-
- struct dentry *dentry;
- unsigned long stat1, stat2, stat4, stat8, stat16;
-
- /* Status flags */
- unsigned disabled:1;
- unsigned sleeping:1;
-
- /* Root hub registers */
- u32 rhdesca;
- u32 rhdescb;
- u32 rhstatus;
- u32 rhport[2];
-
- /* Schedule for the current frame */
- struct isp116x_ep *atl_active;
- int atl_buflen;
- int atl_bufshrt;
- int atl_last_dir;
- int atl_finishing;
-};
-
-/* ------------------------------------------------- */
-
-/* Inter-io delay (ns). The chip is picky about access timings; it
- * expects at least:
- * 150ns delay between consecutive accesses to DATA_REG,
- * 300ns delay between access to ADDR_REG and DATA_REG
- * OE, WE MUST NOT be changed during these intervals
- */
-#if defined(UDELAY)
-#define isp116x_delay(h,d) udelay(d)
-#else
-#define isp116x_delay(h,d) do {} while (0)
-#endif
-
-static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
-{
- writew(reg & 0xff, isp116x->addr_reg);
- isp116x_delay(isp116x, UDELAY);
-}
-
-static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
-{
- writew(val, isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
-}
-
-static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
-{
- __raw_writew(val, isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
-}
-
-static inline u16 isp116x_read_data16(struct isp116x *isp116x)
-{
- u16 val;
-
- val = readw(isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
- return val;
-}
-
-static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
-{
- u16 val;
-
- val = __raw_readw(isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
- return val;
-}
-
-static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
-{
- writew(val & 0xffff, isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
- writew(val >> 16, isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
-}
-
-static inline u32 isp116x_read_data32(struct isp116x *isp116x)
-{
- u32 val;
-
- val = (u32) readw(isp116x->data_reg);
- isp116x_delay(isp116x, UDELAY);
- val |= ((u32) readw(isp116x->data_reg)) << 16;
- isp116x_delay(isp116x, UDELAY);
- return val;
-}
-
-/* Let's keep register access functions out of line. Hint:
- we wait at least 150 ns at every access.
-*/
-static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
-{
- isp116x_write_addr(isp116x, reg);
- return isp116x_read_data16(isp116x);
-}
-
-static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
-{
- isp116x_write_addr(isp116x, reg);
- return isp116x_read_data32(isp116x);
-}
-
-static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
- unsigned val)
-{
- isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
- isp116x_write_data16(isp116x, (u16) (val & 0xffff));
-}
-
-static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
- unsigned val)
-{
- isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
- isp116x_write_data32(isp116x, (u32) val);
-}
-
-/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
--- /dev/null
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libusb_musb.a
+
+COBJS-$(CONFIG_MUSB_HCD) += musb_hcd.o musb_core.o
+COBJS-$(CONFIG_USB_DAVINCI) += davinci.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
--- /dev/null
+/*
+ * TI's Davinci platform specific USB wrapper functions.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include "davinci.h"
+
+/* MUSB platform configuration */
+struct musb_config musb_cfg = {
+ (struct musb_regs *)MENTOR_USB0_BASE,
+ DAVINCI_USB_TIMEOUT,
+ 0
+};
+
+/* MUSB module register overlay */
+struct davinci_usb_regs *dregs;
+
+/*
+ * Enable the USB phy
+ */
+static u8 phy_on(void)
+{
+ u32 timeout;
+
+ /* Wait until the USB phy is turned on */
+ writel(USBPHY_SESNDEN | USBPHY_VBDTCTEN, USBPHY_CTL_PADDR);
+ timeout = musb_cfg.timeout;
+ while (timeout--)
+ if (readl(USBPHY_CTL_PADDR) & USBPHY_PHYCLKGD)
+ return 1;
+
+ /* USB phy was not turned on */
+ return 0;
+}
+
+/*
+ * Disable the USB phy
+ */
+static void phy_off(void)
+{
+ /* powerdown the on-chip PHY and its oscillator */
+ writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, USBPHY_CTL_PADDR);
+}
+
+/*
+ * This function performs Davinci platform specific initialization for usb0.
+ */
+int musb_platform_init(void)
+{
+ u32 revision;
+
+ /* enable USB VBUS */
+ enable_vbus();
+
+ /* start the on-chip USB phy and its pll */
+ if (!phy_on())
+ return -1;
+
+ /* reset the controller */
+ dregs = (struct davinci_usb_regs *)DAVINCI_USB0_BASE;
+ writel(1, &dregs->ctrlr);
+ udelay(5000);
+
+ /* Returns zero if e.g. not clocked */
+ revision = readl(&dregs->version);
+ if (!revision)
+ return -1;
+
+ /* Disable all interrupts */
+ writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_RXINT_MASK |
+ DAVINCI_USB_TXINT_MASK , &dregs->intmsksetr);
+ return 0;
+}
+
+/*
+ * This function performs Davinci platform specific deinitialization for usb0.
+ */
+void musb_platform_deinit(void)
+{
+ /* Turn of the phy */
+ phy_off();
+
+ /* flush any interrupts */
+ writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK |
+ DAVINCI_USB_RXINT_MASK , &dregs->intclrr);
+}
--- /dev/null
+/*
+ * TI's Davinci platform specific USB wrapper functions.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __DAVINCI_USB_H__
+#define __DAVINCI_USB_H__
+
+#include <asm/arch/hardware.h>
+#include "musb_core.h"
+
+/* Base address of DAVINCI usb0 wrapper */
+#define DAVINCI_USB0_BASE 0x01C64000
+
+/* Base address of DAVINCI musb core */
+#define MENTOR_USB0_BASE (DAVINCI_USB0_BASE+0x400)
+
+/*
+ * Davinci platform USB wrapper register overlay. Note: Only the required
+ * registers are included in this structure. It can be expanded as required.
+ */
+struct davinci_usb_regs {
+ u32 version;
+ u32 ctrlr;
+ u32 reserved[0x20];
+ u32 intclrr;
+ u32 intmskr;
+ u32 intmsksetr;
+};
+
+#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */
+#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */
+#define DAVINCI_USB_USBINT_SHIFT 16
+#define DAVINCI_USB_TXINT_SHIFT 0
+#define DAVINCI_USB_RXINT_SHIFT 8
+#define DAVINCI_INTR_DRVVBUS 0x0100
+
+#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */
+#define DAVINCI_USB_TXINT_MASK \
+ (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
+#define DAVINCI_USB_RXINT_MASK \
+ (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
+#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
+ (0x80 + (8*(_bEnd)) + (_bOffset))
+
+/* Integrated highspeed/otg PHY */
+#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define USBPHY_PHYCLKGD (1 << 8)
+#define USBPHY_SESNDEN (1 << 7) /* v(sess_end) comparator */
+#define USBPHY_VBDTCTEN (1 << 6) /* v(bus) comparator */
+#define USBPHY_PHYPLLON (1 << 4) /* override pll suspend */
+#define USBPHY_CLKO1SEL (1 << 3)
+#define USBPHY_OSCPDWN (1 << 2)
+#define USBPHY_PHYPDWN (1 << 0)
+
+/* Timeout for Davinci USB module */
+#define DAVINCI_USB_TIMEOUT 0x3FFFFFF
+
+/* IO Expander I2C address and VBUS enable mask */
+#define IOEXP_I2C_ADDR 0x3A
+#define IOEXP_VBUSEN_MASK 1
+
+/* extern functions */
+extern void lpsc_on(unsigned int id);
+extern int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
+extern int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
+extern void enable_vbus(void);
+#endif /* __DAVINCI_USB_H__ */
--- /dev/null
+/*
+ * Mentor USB OTG Core functionality common for both Host and Device
+ * functionality.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+
+#include "musb_core.h"
+struct musb_regs *musbr;
+
+/*
+ * program the mentor core to start (enable interrupts, dma, etc.)
+ */
+void musb_start(void)
+{
+ u8 devctl;
+
+ /* disable all interrupts */
+ writew(0, &musbr->intrtxe);
+ writew(0, &musbr->intrrxe);
+ writeb(0, &musbr->intrusbe);
+ writeb(0, &musbr->testmode);
+
+ /* put into basic highspeed mode and start session */
+ writeb(MUSB_POWER_HSENAB, &musbr->power);
+#if defined(CONFIG_MUSB_HCD)
+ devctl = readb(&musbr->devctl);
+ writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
+#endif
+}
+
+/*
+ * This function configures the endpoint configuration. The musb hcd or musb
+ * device implementation can use this function to configure the endpoints
+ * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
+ * should not be more than the available FIFO size.
+ *
+ * epinfo - Pointer to EP configuration table
+ * cnt - Number of entries in the EP conf table.
+ */
+void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
+{
+ u16 csr;
+ u16 fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */
+ u32 fifosize;
+ u8 idx;
+
+ while (cnt--) {
+ /* prepare fifosize to write to register */
+ fifosize = epinfo->epsize >> 3;
+ idx = ffs(fifosize) - 1;
+
+ writeb(epinfo->epnum, &musbr->index);
+ if (epinfo->epdir) {
+ /* Configure fifo size and fifo base address */
+ writeb(idx, &musbr->txfifosz);
+ writew(fifoaddr >> 3, &musbr->txfifoadd);
+#if defined(CONFIG_MUSB_HCD)
+ /* clear the data toggle bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
+#endif
+ /* Flush fifo if required */
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+ writew(csr | MUSB_TXCSR_FLUSHFIFO,
+ &musbr->txcsr);
+ } else {
+ /* Configure fifo size and fifo base address */
+ writeb(idx, &musbr->rxfifosz);
+ writew(fifoaddr >> 3, &musbr->rxfifoadd);
+#if defined(CONFIG_MUSB_HCD)
+ /* clear the data toggle bit */
+ csr = readw(&musbr->rxcsr);
+ writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
+#endif
+ /* Flush fifo if required */
+ if (csr & MUSB_RXCSR_RXPKTRDY)
+ writew(csr | MUSB_RXCSR_FLUSHFIFO,
+ &musbr->rxcsr);
+ }
+ fifoaddr += epinfo->epsize;
+ epinfo++;
+ }
+}
+
+/*
+ * This function writes data to endpoint fifo
+ *
+ * ep - endpoint number
+ * length - number of bytes to write to FIFO
+ * fifo_data - Pointer to data buffer that contains the data to write
+ */
+void write_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u8 *data = (u8 *)fifo_data;
+
+ /* select the endpoint index */
+ writeb(ep, &musbr->index);
+
+ /* write the data to the fifo */
+ while (length--)
+ writeb(*data++, &musbr->fifox[ep]);
+}
+
+/*
+ * This function reads data from endpoint fifo
+ *
+ * ep - endpoint number
+ * length - number of bytes to read from FIFO
+ * fifo_data - pointer to data buffer into which data is read
+ */
+void read_fifo(u8 ep, u32 length, void *fifo_data)
+{
+ u8 *data = (u8 *)fifo_data;
+
+ /* select the endpoint index */
+ writeb(ep, &musbr->index);
+
+ /* read the data to the fifo */
+ while (length--)
+ *data++ = readb(&musbr->fifox[ep]);
+}
--- /dev/null
+/******************************************************************
+ * Copyright 2008 Mentor Graphics Corporation
+ * Copyright (C) 2008 by Texas Instruments
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
+ * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
+ * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
+ * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
+ * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
+ * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
+ * GRAPHICS SUPPORT CUSTOMER.
+ ******************************************************************/
+
+#ifndef __MUSB_HDRC_DEFS_H__
+#define __MUSB_HDRC_DEFS_H__
+
+#include <usb.h>
+#include <usb_defs.h>
+#include <asm/io.h>
+
+#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
+
+/* Mentor USB core register overlay structure */
+struct musb_regs {
+ /* common registers */
+ u8 faddr;
+ u8 power;
+ u16 intrtx;
+ u16 intrrx;
+ u16 intrtxe;
+ u16 intrrxe;
+ u8 intrusb;
+ u8 intrusbe;
+ u16 frame;
+ u8 index;
+ u8 testmode;
+ /* indexed registers */
+ u16 txmaxp;
+ u16 txcsr;
+ u16 rxmaxp;
+ u16 rxcsr;
+ u16 rxcount;
+ u8 txtype;
+ u8 txinterval;
+ u8 rxtype;
+ u8 rxinterval;
+ u8 reserved0;
+ u8 fifosize;
+ /* fifo */
+ u32 fifox[16];
+ /* OTG, dynamic FIFO, version & vendor registers */
+ u8 devctl;
+ u8 reserved1;
+ u8 txfifosz;
+ u8 rxfifosz;
+ u16 txfifoadd;
+ u16 rxfifoadd;
+ u32 vcontrol;
+ u16 hwvers;
+ u16 reserved2[5];
+ u8 epinfo;
+ u8 raminfo;
+ u8 linkinfo;
+ u8 vplen;
+ u8 hseof1;
+ u8 fseof1;
+ u8 lseof1;
+ u8 reserved3;
+ /* target address registers */
+ struct musb_tar_regs {
+ u8 txfuncaddr;
+ u8 reserved0;
+ u8 txhubaddr;
+ u8 txhubport;
+ u8 rxfuncaddr;
+ u8 reserved1;
+ u8 rxhubaddr;
+ u8 rxhubport;
+ } tar[16];
+} __attribute((aligned(32)));
+
+/*
+ * MUSB Register bits
+ */
+
+/* POWER */
+#define MUSB_POWER_ISOUPDATE 0x80
+#define MUSB_POWER_SOFTCONN 0x40
+#define MUSB_POWER_HSENAB 0x20
+#define MUSB_POWER_HSMODE 0x10
+#define MUSB_POWER_RESET 0x08
+#define MUSB_POWER_RESUME 0x04
+#define MUSB_POWER_SUSPENDM 0x02
+#define MUSB_POWER_ENSUSPEND 0x01
+#define MUSB_POWER_HSMODE_SHIFT 4
+
+/* INTRUSB */
+#define MUSB_INTR_SUSPEND 0x01
+#define MUSB_INTR_RESUME 0x02
+#define MUSB_INTR_RESET 0x04
+#define MUSB_INTR_BABBLE 0x04
+#define MUSB_INTR_SOF 0x08
+#define MUSB_INTR_CONNECT 0x10
+#define MUSB_INTR_DISCONNECT 0x20
+#define MUSB_INTR_SESSREQ 0x40
+#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
+
+/* DEVCTL */
+#define MUSB_DEVCTL_BDEVICE 0x80
+#define MUSB_DEVCTL_FSDEV 0x40
+#define MUSB_DEVCTL_LSDEV 0x20
+#define MUSB_DEVCTL_VBUS 0x18
+#define MUSB_DEVCTL_VBUS_SHIFT 3
+#define MUSB_DEVCTL_HM 0x04
+#define MUSB_DEVCTL_HR 0x02
+#define MUSB_DEVCTL_SESSION 0x01
+
+/* TESTMODE */
+#define MUSB_TEST_FORCE_HOST 0x80
+#define MUSB_TEST_FIFO_ACCESS 0x40
+#define MUSB_TEST_FORCE_FS 0x20
+#define MUSB_TEST_FORCE_HS 0x10
+#define MUSB_TEST_PACKET 0x08
+#define MUSB_TEST_K 0x04
+#define MUSB_TEST_J 0x02
+#define MUSB_TEST_SE0_NAK 0x01
+
+/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
+#define MUSB_FIFOSZ_DPB 0x10
+/* Allocation size (8, 16, 32, ... 4096) */
+#define MUSB_FIFOSZ_SIZE 0x0f
+
+/* CSR0 */
+#define MUSB_CSR0_FLUSHFIFO 0x0100
+#define MUSB_CSR0_TXPKTRDY 0x0002
+#define MUSB_CSR0_RXPKTRDY 0x0001
+
+/* CSR0 in Peripheral mode */
+#define MUSB_CSR0_P_SVDSETUPEND 0x0080
+#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
+#define MUSB_CSR0_P_SENDSTALL 0x0020
+#define MUSB_CSR0_P_SETUPEND 0x0010
+#define MUSB_CSR0_P_DATAEND 0x0008
+#define MUSB_CSR0_P_SENTSTALL 0x0004
+
+/* CSR0 in Host mode */
+#define MUSB_CSR0_H_DIS_PING 0x0800
+#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
+#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
+#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
+#define MUSB_CSR0_H_STATUSPKT 0x0040
+#define MUSB_CSR0_H_REQPKT 0x0020
+#define MUSB_CSR0_H_ERROR 0x0010
+#define MUSB_CSR0_H_SETUPPKT 0x0008
+#define MUSB_CSR0_H_RXSTALL 0x0004
+
+/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_CSR0_P_WZC_BITS \
+ (MUSB_CSR0_P_SENTSTALL)
+#define MUSB_CSR0_H_WZC_BITS \
+ (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
+ | MUSB_CSR0_RXPKTRDY)
+
+/* TxType/RxType */
+#define MUSB_TYPE_SPEED 0xc0
+#define MUSB_TYPE_SPEED_SHIFT 6
+#define MUSB_TYPE_SPEED_HIGH 1
+#define MUSB_TYPE_SPEED_FULL 2
+#define MUSB_TYPE_SPEED_LOW 3
+#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_SHIFT 4
+#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
+#define MUSB_TYPE_PROTO_BULK 2
+#define MUSB_TYPE_PROTO_INTR 3
+
+/* CONFIGDATA */
+#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
+#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
+#define MUSB_CONFIGDATA_BIGENDIAN 0x20
+#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
+#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
+#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
+#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
+#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
+
+/* TXCSR in Peripheral and Host mode */
+#define MUSB_TXCSR_AUTOSET 0x8000
+#define MUSB_TXCSR_MODE 0x2000
+#define MUSB_TXCSR_DMAENAB 0x1000
+#define MUSB_TXCSR_FRCDATATOG 0x0800
+#define MUSB_TXCSR_DMAMODE 0x0400
+#define MUSB_TXCSR_CLRDATATOG 0x0040
+#define MUSB_TXCSR_FLUSHFIFO 0x0008
+#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
+#define MUSB_TXCSR_TXPKTRDY 0x0001
+
+/* TXCSR in Peripheral mode */
+#define MUSB_TXCSR_P_ISO 0x4000
+#define MUSB_TXCSR_P_INCOMPTX 0x0080
+#define MUSB_TXCSR_P_SENTSTALL 0x0020
+#define MUSB_TXCSR_P_SENDSTALL 0x0010
+#define MUSB_TXCSR_P_UNDERRUN 0x0004
+
+/* TXCSR in Host mode */
+#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
+#define MUSB_TXCSR_H_DATATOGGLE 0x0100
+#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
+#define MUSB_TXCSR_H_RXSTALL 0x0020
+#define MUSB_TXCSR_H_ERROR 0x0004
+#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8
+
+/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_TXCSR_P_WZC_BITS \
+ (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
+ | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
+#define MUSB_TXCSR_H_WZC_BITS \
+ (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+ | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
+
+/* RXCSR in Peripheral and Host mode */
+#define MUSB_RXCSR_AUTOCLEAR 0x8000
+#define MUSB_RXCSR_DMAENAB 0x2000
+#define MUSB_RXCSR_DISNYET 0x1000
+#define MUSB_RXCSR_PID_ERR 0x1000
+#define MUSB_RXCSR_DMAMODE 0x0800
+#define MUSB_RXCSR_INCOMPRX 0x0100
+#define MUSB_RXCSR_CLRDATATOG 0x0080
+#define MUSB_RXCSR_FLUSHFIFO 0x0010
+#define MUSB_RXCSR_DATAERROR 0x0008
+#define MUSB_RXCSR_FIFOFULL 0x0002
+#define MUSB_RXCSR_RXPKTRDY 0x0001
+
+/* RXCSR in Peripheral mode */
+#define MUSB_RXCSR_P_ISO 0x4000
+#define MUSB_RXCSR_P_SENTSTALL 0x0040
+#define MUSB_RXCSR_P_SENDSTALL 0x0020
+#define MUSB_RXCSR_P_OVERRUN 0x0004
+
+/* RXCSR in Host mode */
+#define MUSB_RXCSR_H_AUTOREQ 0x4000
+#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
+#define MUSB_RXCSR_H_DATATOGGLE 0x0200
+#define MUSB_RXCSR_H_RXSTALL 0x0040
+#define MUSB_RXCSR_H_REQPKT 0x0020
+#define MUSB_RXCSR_H_ERROR 0x0004
+#define MUSB_S_RXCSR_H_DATATOGGLE 9
+
+/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
+#define MUSB_RXCSR_P_WZC_BITS \
+ (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
+ | MUSB_RXCSR_RXPKTRDY)
+#define MUSB_RXCSR_H_WZC_BITS \
+ (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
+ | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
+
+/* HUBADDR */
+#define MUSB_HUBADDR_MULTI_TT 0x80
+
+/* Endpoint configuration information. Note: The value of endpoint fifo size
+ * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
+ * values are not supported
+ */
+struct musb_epinfo {
+ u8 epnum; /* endpoint number */
+ u8 epdir; /* endpoint direction */
+ u16 epsize; /* endpoint FIFO size */
+};
+
+/*
+ * Platform specific MUSB configuration. Any platform using the musb
+ * functionality should create one instance of this structure in the
+ * platform specific file.
+ */
+struct musb_config {
+ struct musb_regs *regs;
+ u32 timeout;
+ u8 musb_speed;
+};
+
+/* externally defined data */
+extern struct musb_config musb_cfg;
+extern struct musb_regs *musbr;
+
+/* exported functions */
+extern void musb_start(void);
+extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt);
+extern void write_fifo(u8 ep, u32 length, void *fifo_data);
+extern void read_fifo(u8 ep, u32 length, void *fifo_data);
+
+/* extern functions */
+extern inline void musb_writew(u32 offset, u16 value);
+extern inline void musb_writeb(u32 offset, u8 value);
+extern inline u16 musb_readw(u32 offset);
+extern inline u8 musb_readb(u32 offset);
+
+#endif /* __MUSB_HDRC_DEFS_H__ */
--- /dev/null
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#include <common.h>
+#include "musb_hcd.h"
+
+/* MSC control transfers */
+#define USB_MSC_BBB_RESET 0xFF
+#define USB_MSC_BBB_GET_MAX_LUN 0xFE
+
+/* Endpoint configuration information */
+static struct musb_epinfo epinfo[3] = {
+ {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
+ {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */
+ {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
+};
+
+/*
+ * This function writes the data toggle value.
+ */
+static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
+{
+ u16 toggle = usb_gettoggle(dev, ep, dir_out);
+ u16 csr;
+
+ if (dir_out) {
+ if (!toggle)
+ writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
+ else {
+ csr = readw(&musbr->txcsr);
+ csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
+ writew(csr, &musbr->txcsr);
+ csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
+ writew(csr, &musbr->txcsr);
+ }
+ } else {
+ if (!toggle)
+ writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
+ else {
+ csr = readw(&musbr->rxcsr);
+ csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
+ writew(csr, &musbr->rxcsr);
+ csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
+ writew(csr, &musbr->rxcsr);
+ }
+ }
+}
+
+/*
+ * This function checks if RxStall has occured on the endpoint. If a RxStall
+ * has occured, the RxStall is cleared and 1 is returned. If RxStall has
+ * not occured, 0 is returned.
+ */
+static u8 check_stall(u8 ep, u8 dir_out)
+{
+ u16 csr;
+
+ /* For endpoint 0 */
+ if (!ep) {
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_CSR0_H_RXSTALL) {
+ csr &= ~MUSB_CSR0_H_RXSTALL;
+ writew(csr, &musbr->txcsr);
+ return 1;
+ }
+ } else { /* For non-ep0 */
+ if (dir_out) { /* is it tx ep */
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_TXCSR_H_RXSTALL) {
+ csr &= ~MUSB_TXCSR_H_RXSTALL;
+ writew(csr, &musbr->txcsr);
+ return 1;
+ }
+ } else { /* is it rx ep */
+ csr = readw(&musbr->rxcsr);
+ if (csr & MUSB_RXCSR_H_RXSTALL) {
+ csr &= ~MUSB_RXCSR_H_RXSTALL;
+ writew(csr, &musbr->rxcsr);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
+ * error and -2 for stall.
+ */
+static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
+{
+ u16 csr;
+ int result = 1;
+
+ while (result > 0) {
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_CSR0_H_ERROR) {
+ csr &= ~MUSB_CSR0_H_ERROR;
+ writew(csr, &musbr->txcsr);
+ dev->status = USB_ST_CRC_ERR;
+ result = -1;
+ break;
+ }
+
+ switch (bit_mask) {
+ case MUSB_CSR0_TXPKTRDY:
+ if (!(csr & MUSB_CSR0_TXPKTRDY)) {
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ result = 0;
+ }
+ break;
+
+ case MUSB_CSR0_RXPKTRDY:
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ if (csr & MUSB_CSR0_RXPKTRDY)
+ result = 0;
+ break;
+
+ case MUSB_CSR0_H_REQPKT:
+ if (!(csr & MUSB_CSR0_H_REQPKT)) {
+ if (check_stall(MUSB_CONTROL_EP, 0)) {
+ dev->status = USB_ST_STALLED;
+ result = -2;
+ } else
+ result = 0;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+/*
+ * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_txep_ready(struct usb_device *dev, u8 ep)
+{
+ u16 csr;
+
+ do {
+ if (check_stall(ep, 1)) {
+ dev->status = USB_ST_STALLED;
+ return 0;
+ }
+
+ csr = readw(&musbr->txcsr);
+ if (csr & MUSB_TXCSR_H_ERROR) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+ } while (csr & MUSB_TXCSR_TXPKTRDY);
+ return 1;
+}
+
+/*
+ * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
+ */
+static u8 wait_until_rxep_ready(struct usb_device *dev, u8 ep)
+{
+ u16 csr;
+
+ do {
+ if (check_stall(ep, 0)) {
+ dev->status = USB_ST_STALLED;
+ return 0;
+ }
+
+ csr = readw(&musbr->rxcsr);
+ if (csr & MUSB_RXCSR_H_ERROR) {
+ dev->status = USB_ST_CRC_ERR;
+ return 0;
+ }
+ } while (!(csr & MUSB_RXCSR_RXPKTRDY));
+ return 1;
+}
+
+/*
+ * This function performs the setup phase of the control transfer
+ */
+static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
+{
+ int result;
+ u16 csr;
+
+ /* write the control request to ep0 fifo */
+ write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
+
+ /* enable transfer of setup packet */
+ csr = readw(&musbr->txcsr);
+ csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
+ writew(csr, &musbr->txcsr);
+
+ /* wait until the setup packet is transmitted */
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ dev->act_len = 0;
+ return result;
+}
+
+/*
+ * This function handles the control transfer in data phase
+ */
+static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 rxlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
+ u8 *rxbuff = (u8 *)buffer;
+ u8 rxedlength;
+ int result;
+
+ while (rxlen < len) {
+ /* Determine the next read length */
+ nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
+
+ /* Set the ReqPkt bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
+ if (result < 0)
+ return result;
+
+ /* Actual number of bytes received by usb */
+ rxedlength = readb(&musbr->rxcount);
+
+ /* Read the data from the RxFIFO */
+ read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
+
+ /* Clear the RxPktRdy Bit */
+ csr = readw(&musbr->txcsr);
+ csr &= ~MUSB_CSR0_RXPKTRDY;
+ writew(csr, &musbr->txcsr);
+
+ /* short packet? */
+ if (rxedlength != nextlen) {
+ dev->act_len += rxedlength;
+ break;
+ }
+ rxlen += nextlen;
+ dev->act_len = rxlen;
+ }
+ return 0;
+}
+
+/*
+ * This function handles the control transfer out data phase
+ */
+static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
+{
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
+ u8 *txbuff = (u8 *)buffer;
+ int result = 0;
+
+ while (txlen < len) {
+ /* Determine the next write length */
+ nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
+
+ /* Load the data to send in FIFO */
+ write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
+
+ /* Set TXPKTRDY bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY,
+ &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ if (result < 0)
+ break;
+
+ txlen += nextlen;
+ dev->act_len = txlen;
+ }
+ return result;
+}
+
+/*
+ * This function handles the control transfer out status phase
+ */
+static int ctrlreq_out_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit */
+ csr = readw(&musbr->txcsr);
+ csr |= (MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY |
+ MUSB_CSR0_H_STATUSPKT);
+ writew(csr, &musbr->txcsr);
+
+ /* Wait until TXPKTRDY bit is cleared */
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
+ return result;
+}
+
+/*
+ * This function handles the control transfer in status phase
+ */
+static int ctrlreq_in_status_phase(struct usb_device *dev)
+{
+ u16 csr;
+ int result;
+
+ /* Set the StatusPkt bit and ReqPkt bit */
+ csr = MUSB_CSR0_H_DIS_PING | MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
+ writew(csr, &musbr->txcsr);
+ result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
+
+ /* clear StatusPkt bit and RxPktRdy bit */
+ csr = readw(&musbr->txcsr);
+ csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
+ writew(csr, &musbr->txcsr);
+ return result;
+}
+
+/*
+ * determines the speed of the device (High/Full/Slow)
+ */
+static u8 get_dev_speed(struct usb_device *dev)
+{
+ return (dev->speed & USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
+ ((dev->speed & USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
+ MUSB_TYPE_SPEED_FULL);
+}
+
+/*
+ * configure the hub address and the port address.
+ */
+static void config_hub_port(struct usb_device *dev, u8 ep)
+{
+ u8 chid;
+ u8 hub;
+
+ /* Find out the nearest parent which is high speed */
+ while (dev->parent->parent != NULL)
+ if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH)
+ dev = dev->parent;
+ else
+ break;
+
+ /* determine the port address at that hub */
+ hub = dev->parent->devnum;
+ for (chid = 0; chid < USB_MAXCHILDREN; chid++)
+ if (dev->parent->children[chid] == dev)
+ break;
+
+ /* configure the hub address and the port address */
+ writeb(hub, &musbr->tar[ep].txhubaddr);
+ writeb((chid + 1), &musbr->tar[ep].txhubport);
+ writeb(hub, &musbr->tar[ep].rxhubaddr);
+ writeb((chid + 1), &musbr->tar[ep].rxhubport);
+}
+
+/*
+ * do a control transfer
+ */
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int len, struct devrequest *setup)
+{
+ int devnum = usb_pipedevice(pipe);
+ u16 csr;
+ u8 devspeed;
+
+ /* select control endpoint */
+ writeb(MUSB_CONTROL_EP, &musbr->index);
+ csr = readw(&musbr->txcsr);
+
+ /* target addr and (for multipoint) hub addr/port */
+ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
+ writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ config_hub_port(dev, MUSB_CONTROL_EP);
+ writeb(devspeed << 6, &musbr->txtype);
+ } else {
+ writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
+ }
+
+ /* Control transfer setup phase */
+ if (ctrlreq_setup_phase(dev, setup) < 0)
+ return 0;
+
+ switch (setup->request) {
+ case USB_REQ_GET_DESCRIPTOR:
+ case USB_REQ_GET_CONFIGURATION:
+ case USB_REQ_GET_INTERFACE:
+ case USB_REQ_GET_STATUS:
+ case USB_MSC_BBB_GET_MAX_LUN:
+ /* control transfer in-data-phase */
+ if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
+ return 0;
+ /* control transfer out-status-phase */
+ if (ctrlreq_out_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ case USB_REQ_SET_CONFIGURATION:
+ case USB_REQ_SET_FEATURE:
+ case USB_REQ_SET_INTERFACE:
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_MSC_BBB_RESET:
+ /* control transfer in status phase */
+ if (ctrlreq_in_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ case USB_REQ_SET_DESCRIPTOR:
+ /* control transfer out data phase */
+ if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
+ return 0;
+ /* control transfer in status phase */
+ if (ctrlreq_in_status_phase(dev) < 0)
+ return 0;
+ break;
+
+ default:
+ /* unhandled control transfer */
+ return -1;
+ }
+
+ dev->status = 0;
+ dev->act_len = len;
+ return len;
+}
+
+/*
+ * do a bulk transfer
+ */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int len)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int devnum = usb_pipedevice(pipe);
+ u8 type;
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 devspeed;
+
+ /* select bulk endpoint */
+ writeb(MUSB_BULK_EP, &musbr->index);
+
+ /* write the address of the device */
+ if (dir_out)
+ writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
+ else
+ writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ /*
+ * MUSB is in high speed and the destination device is full
+ * speed device. So configure the hub address and port
+ * address registers.
+ */
+ config_hub_port(dev, MUSB_BULK_EP);
+ } else {
+ if (dir_out) {
+ writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
+ } else {
+ writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
+ }
+ devspeed = musb_cfg.musb_speed;
+ }
+
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ if (dir_out) { /* bulk-out transfer */
+ /* Program the TxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->txtype);
+
+ /* Write maximum packet size to the TxMaxp register */
+ writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
+ (len-txlen) : dev->epmaxpacketout[ep];
+
+ /* Write the data to the FIFO */
+ write_fifo(MUSB_BULK_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Set the TxPktRdy bit */
+ csr = readw(&musbr->txcsr);
+ writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
+
+ /* Wait until the TxPktRdy bit is cleared */
+ if (!wait_until_txep_ready(dev, MUSB_BULK_EP)) {
+ readw(&musbr->txcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+ dev->act_len = txlen;
+ return 0;
+ }
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->txcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
+ } else { /* bulk-in transfer */
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ /* Program the RxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->rxtype);
+
+ /* Write the maximum packet size to the RxMaxp register */
+ writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+ (len-txlen) : dev->epmaxpacketin[ep];
+
+ /* Set the ReqPkt bit */
+ writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+ /* Wait until the RxPktRdy bit is set */
+ if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) {
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ dev->act_len = txlen;
+ return 0;
+ }
+
+ /* Read the data from the FIFO */
+ read_fifo(MUSB_BULK_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Clear the RxPktRdy bit */
+ csr = readw(&musbr->rxcsr);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ }
+
+ /* bulk transfer is complete */
+ dev->status = 0;
+ dev->act_len = len;
+ return 0;
+}
+
+/*
+ * This function initializes the usb controller module.
+ */
+int usb_lowlevel_init(void)
+{
+ u8 power;
+ u32 timeout;
+
+ if (musb_platform_init() == -1)
+ return -1;
+
+ /* Configure all the endpoint FIFO's and start usb controller */
+ musbr = musb_cfg.regs;
+ musb_configure_ep(&epinfo[0],
+ sizeof(epinfo) / sizeof(struct musb_epinfo));
+ musb_start();
+
+ /*
+ * Wait until musb is enabled in host mode with a timeout. There
+ * should be a usb device connected.
+ */
+ timeout = musb_cfg.timeout;
+ while (timeout--)
+ if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
+ break;
+
+ /* if musb core is not in host mode, then return */
+ if (!timeout)
+ return -1;
+
+ /* start usb bus reset */
+ power = readb(&musbr->power);
+ writeb(power | MUSB_POWER_RESET, &musbr->power);
+
+ /* After initiating a usb reset, wait for about 20ms to 30ms */
+ udelay(30000);
+
+ /* stop usb bus reset */
+ power = readb(&musbr->power);
+ power &= ~MUSB_POWER_RESET;
+ writeb(power, &musbr->power);
+
+ /* Determine if the connected device is a high/full/low speed device */
+ musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
+ MUSB_TYPE_SPEED_HIGH :
+ ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
+ MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
+ return 0;
+}
+
+/*
+ * This function stops the operation of the davinci usb module.
+ */
+int usb_lowlevel_stop(void)
+{
+ /* Reset the USB module */
+ musb_platform_deinit();
+ writeb(0, &musbr->devctl);
+ return 0;
+}
+
+/*
+ * This function supports usb interrupt transfers. Currently, usb interrupt
+ * transfers are not supported.
+ */
+int submit_int_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int len, int interval)
+{
+ int dir_out = usb_pipeout(pipe);
+ int ep = usb_pipeendpoint(pipe);
+ int devnum = usb_pipedevice(pipe);
+ u8 type;
+ u16 csr;
+ u32 txlen = 0;
+ u32 nextlen = 0;
+ u8 devspeed;
+
+ /* select interrupt endpoint */
+ writeb(MUSB_INTR_EP, &musbr->index);
+
+ /* write the address of the device */
+ if (dir_out)
+ writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
+ else
+ writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
+
+ /* configure the hub address and the port number as required */
+ devspeed = get_dev_speed(dev);
+ if ((musb_ishighspeed()) && (dev->parent != NULL) &&
+ (devspeed != MUSB_TYPE_SPEED_HIGH)) {
+ /*
+ * MUSB is in high speed and the destination device is full
+ * speed device. So configure the hub address and port
+ * address registers.
+ */
+ config_hub_port(dev, MUSB_INTR_EP);
+ } else {
+ if (dir_out) {
+ writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
+ writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
+ } else {
+ writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
+ writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
+ }
+ devspeed = musb_cfg.musb_speed;
+ }
+
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+
+ if (!dir_out) { /* intrrupt-in transfer */
+ /* Write the saved toggle bit value */
+ write_toggle(dev, ep, dir_out);
+ writeb(interval, &musbr->rxinterval);
+
+ /* Program the RxType register */
+ type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
+ (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
+ (ep & MUSB_TYPE_REMOTE_END);
+ writeb(type, &musbr->rxtype);
+
+ /* Write the maximum packet size to the RxMaxp register */
+ writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
+
+ while (txlen < len) {
+ nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
+ (len-txlen) : dev->epmaxpacketin[ep];
+
+ /* Set the ReqPkt bit */
+ writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
+
+ /* Wait until the RxPktRdy bit is set */
+ if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) {
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ dev->act_len = txlen;
+ return 0;
+ }
+
+ /* Read the data from the FIFO */
+ read_fifo(MUSB_INTR_EP, nextlen,
+ (void *)(((u8 *)buffer) + txlen));
+
+ /* Clear the RxPktRdy bit */
+ csr = readw(&musbr->rxcsr);
+ csr &= ~MUSB_RXCSR_RXPKTRDY;
+ writew(csr, &musbr->rxcsr);
+ txlen += nextlen;
+ }
+
+ /* Keep a copy of the data toggle bit */
+ csr = readw(&musbr->rxcsr);
+ usb_settoggle(dev, ep, dir_out,
+ (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
+ }
+
+ /* interrupt transfer is complete */
+ dev->irq_status = 0;
+ dev->irq_act_len = len;
+ dev->irq_handle(dev);
+ dev->status = 0;
+ dev->act_len = len;
+ return 0;
+}
+
+
+#ifdef CONFIG_SYS_USB_EVENT_POLL
+/*
+ * This function polls for USB keyboard data.
+ */
+void usb_event_poll()
+{
+ device_t *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_interface_descriptor *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe;
+ int maxp;
+
+ /* Get the pointer to USB Keyboard device pointer */
+ dev = device_get_by_name("usbkbd");
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ iface = &usb_kbd_dev->config.if_desc[0];
+ ep = &iface->ep_desc[0];
+ pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+ /* Submit a interrupt transfer request */
+ maxp = usb_maxpacket(usb_kbd_dev, pipe);
+ usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
+ maxp > 8 ? 8 : maxp, ep->bInterval);
+}
+#endif /* CONFIG_SYS_USB_EVENT_POLL */
--- /dev/null
+/*
+ * Mentor USB OTG Core host controller driver.
+ *
+ * Copyright (c) 2008 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
+ */
+
+#ifndef __MUSB_HCD_H__
+#define __MUSB_HCD_H__
+
+#include "musb_core.h"
+#ifdef CONFIG_USB_KEYBOARD
+#include <devices.h>
+extern unsigned char new[];
+#endif
+
+/* This defines the endpoint number used for control transfers */
+#define MUSB_CONTROL_EP 0
+
+/* This defines the endpoint number used for bulk transfer */
+#define MUSB_BULK_EP 1
+
+/* This defines the endpoint number used for interrupt transfer */
+#define MUSB_INTR_EP 2
+
+/* Determine the operating speed of MUSB core */
+#define musb_ishighspeed() \
+ ((readb(&musbr->power) & MUSB_POWER_HSMODE) \
+ >> MUSB_POWER_HSMODE_SHIFT)
+
+/* extern functions */
+extern int musb_platform_init(void);
+extern void musb_platform_deinit(void);
+
+#endif /* __MUSB_HCD_H__ */
+++ /dev/null
-/*
- * Mentor USB OTG Core functionality common for both Host and Device
- * functionality.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <common.h>
-
-#include "musb_core.h"
-struct musb_regs *musbr;
-
-/*
- * program the mentor core to start (enable interrupts, dma, etc.)
- */
-void musb_start(void)
-{
- u8 devctl;
-
- /* disable all interrupts */
- writew(0, &musbr->intrtxe);
- writew(0, &musbr->intrrxe);
- writeb(0, &musbr->intrusbe);
- writeb(0, &musbr->testmode);
-
- /* put into basic highspeed mode and start session */
- writeb(MUSB_POWER_HSENAB, &musbr->power);
-#if defined(CONFIG_MUSB_HCD)
- devctl = readb(&musbr->devctl);
- writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl);
-#endif
-}
-
-/*
- * This function configures the endpoint configuration. The musb hcd or musb
- * device implementation can use this function to configure the endpoints
- * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints
- * should not be more than the available FIFO size.
- *
- * epinfo - Pointer to EP configuration table
- * cnt - Number of entries in the EP conf table.
- */
-void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt)
-{
- u16 csr;
- u16 fifoaddr = 64; /* First 64 bytes of FIFO reserved for EP0 */
- u32 fifosize;
- u8 idx;
-
- while (cnt--) {
- /* prepare fifosize to write to register */
- fifosize = epinfo->epsize >> 3;
- idx = ffs(fifosize) - 1;
-
- writeb(epinfo->epnum, &musbr->index);
- if (epinfo->epdir) {
- /* Configure fifo size and fifo base address */
- writeb(idx, &musbr->txfifosz);
- writew(fifoaddr >> 3, &musbr->txfifoadd);
-#if defined(CONFIG_MUSB_HCD)
- /* clear the data toggle bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
-#endif
- /* Flush fifo if required */
- if (csr & MUSB_TXCSR_TXPKTRDY)
- writew(csr | MUSB_TXCSR_FLUSHFIFO,
- &musbr->txcsr);
- } else {
- /* Configure fifo size and fifo base address */
- writeb(idx, &musbr->rxfifosz);
- writew(fifoaddr >> 3, &musbr->rxfifoadd);
-#if defined(CONFIG_MUSB_HCD)
- /* clear the data toggle bit */
- csr = readw(&musbr->rxcsr);
- writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
-#endif
- /* Flush fifo if required */
- if (csr & MUSB_RXCSR_RXPKTRDY)
- writew(csr | MUSB_RXCSR_FLUSHFIFO,
- &musbr->rxcsr);
- }
- fifoaddr += epinfo->epsize;
- epinfo++;
- }
-}
-
-/*
- * This function writes data to endpoint fifo
- *
- * ep - endpoint number
- * length - number of bytes to write to FIFO
- * fifo_data - Pointer to data buffer that contains the data to write
- */
-void write_fifo(u8 ep, u32 length, void *fifo_data)
-{
- u8 *data = (u8 *)fifo_data;
-
- /* select the endpoint index */
- writeb(ep, &musbr->index);
-
- /* write the data to the fifo */
- while (length--)
- writeb(*data++, &musbr->fifox[ep]);
-}
-
-/*
- * This function reads data from endpoint fifo
- *
- * ep - endpoint number
- * length - number of bytes to read from FIFO
- * fifo_data - pointer to data buffer into which data is read
- */
-void read_fifo(u8 ep, u32 length, void *fifo_data)
-{
- u8 *data = (u8 *)fifo_data;
-
- /* select the endpoint index */
- writeb(ep, &musbr->index);
-
- /* read the data to the fifo */
- while (length--)
- *data++ = readb(&musbr->fifox[ep]);
-}
+++ /dev/null
-/******************************************************************
- * Copyright 2008 Mentor Graphics Corporation
- * Copyright (C) 2008 by Texas Instruments
- *
- * This file is part of the Inventra Controller Driver for Linux.
- *
- * The Inventra Controller Driver for Linux is free software; you
- * can redistribute it and/or modify it under the terms of the GNU
- * General Public License version 2 as published by the Free Software
- * Foundation.
- *
- * The Inventra Controller Driver for Linux is distributed in
- * the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with The Inventra Controller Driver for Linux ; if not,
- * write to the Free Software Foundation, Inc., 59 Temple Place,
- * Suite 330, Boston, MA 02111-1307 USA
- *
- * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
- * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
- * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
- * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
- * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
- * NON-INFRINGEMENT. MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
- * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
- * GRAPHICS SUPPORT CUSTOMER.
- ******************************************************************/
-
-#ifndef __MUSB_HDRC_DEFS_H__
-#define __MUSB_HDRC_DEFS_H__
-
-#include <usb.h>
-#include <usb_defs.h>
-#include <asm/io.h>
-
-#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
-
-/* Mentor USB core register overlay structure */
-struct musb_regs {
- /* common registers */
- u8 faddr;
- u8 power;
- u16 intrtx;
- u16 intrrx;
- u16 intrtxe;
- u16 intrrxe;
- u8 intrusb;
- u8 intrusbe;
- u16 frame;
- u8 index;
- u8 testmode;
- /* indexed registers */
- u16 txmaxp;
- u16 txcsr;
- u16 rxmaxp;
- u16 rxcsr;
- u16 rxcount;
- u8 txtype;
- u8 txinterval;
- u8 rxtype;
- u8 rxinterval;
- u8 reserved0;
- u8 fifosize;
- /* fifo */
- u32 fifox[16];
- /* OTG, dynamic FIFO, version & vendor registers */
- u8 devctl;
- u8 reserved1;
- u8 txfifosz;
- u8 rxfifosz;
- u16 txfifoadd;
- u16 rxfifoadd;
- u32 vcontrol;
- u16 hwvers;
- u16 reserved2[5];
- u8 epinfo;
- u8 raminfo;
- u8 linkinfo;
- u8 vplen;
- u8 hseof1;
- u8 fseof1;
- u8 lseof1;
- u8 reserved3;
- /* target address registers */
- struct musb_tar_regs {
- u8 txfuncaddr;
- u8 reserved0;
- u8 txhubaddr;
- u8 txhubport;
- u8 rxfuncaddr;
- u8 reserved1;
- u8 rxhubaddr;
- u8 rxhubport;
- } tar[16];
-} __attribute((aligned(32)));
-
-/*
- * MUSB Register bits
- */
-
-/* POWER */
-#define MUSB_POWER_ISOUPDATE 0x80
-#define MUSB_POWER_SOFTCONN 0x40
-#define MUSB_POWER_HSENAB 0x20
-#define MUSB_POWER_HSMODE 0x10
-#define MUSB_POWER_RESET 0x08
-#define MUSB_POWER_RESUME 0x04
-#define MUSB_POWER_SUSPENDM 0x02
-#define MUSB_POWER_ENSUSPEND 0x01
-#define MUSB_POWER_HSMODE_SHIFT 4
-
-/* INTRUSB */
-#define MUSB_INTR_SUSPEND 0x01
-#define MUSB_INTR_RESUME 0x02
-#define MUSB_INTR_RESET 0x04
-#define MUSB_INTR_BABBLE 0x04
-#define MUSB_INTR_SOF 0x08
-#define MUSB_INTR_CONNECT 0x10
-#define MUSB_INTR_DISCONNECT 0x20
-#define MUSB_INTR_SESSREQ 0x40
-#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */
-
-/* DEVCTL */
-#define MUSB_DEVCTL_BDEVICE 0x80
-#define MUSB_DEVCTL_FSDEV 0x40
-#define MUSB_DEVCTL_LSDEV 0x20
-#define MUSB_DEVCTL_VBUS 0x18
-#define MUSB_DEVCTL_VBUS_SHIFT 3
-#define MUSB_DEVCTL_HM 0x04
-#define MUSB_DEVCTL_HR 0x02
-#define MUSB_DEVCTL_SESSION 0x01
-
-/* TESTMODE */
-#define MUSB_TEST_FORCE_HOST 0x80
-#define MUSB_TEST_FIFO_ACCESS 0x40
-#define MUSB_TEST_FORCE_FS 0x20
-#define MUSB_TEST_FORCE_HS 0x10
-#define MUSB_TEST_PACKET 0x08
-#define MUSB_TEST_K 0x04
-#define MUSB_TEST_J 0x02
-#define MUSB_TEST_SE0_NAK 0x01
-
-/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */
-#define MUSB_FIFOSZ_DPB 0x10
-/* Allocation size (8, 16, 32, ... 4096) */
-#define MUSB_FIFOSZ_SIZE 0x0f
-
-/* CSR0 */
-#define MUSB_CSR0_FLUSHFIFO 0x0100
-#define MUSB_CSR0_TXPKTRDY 0x0002
-#define MUSB_CSR0_RXPKTRDY 0x0001
-
-/* CSR0 in Peripheral mode */
-#define MUSB_CSR0_P_SVDSETUPEND 0x0080
-#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040
-#define MUSB_CSR0_P_SENDSTALL 0x0020
-#define MUSB_CSR0_P_SETUPEND 0x0010
-#define MUSB_CSR0_P_DATAEND 0x0008
-#define MUSB_CSR0_P_SENTSTALL 0x0004
-
-/* CSR0 in Host mode */
-#define MUSB_CSR0_H_DIS_PING 0x0800
-#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */
-#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */
-#define MUSB_CSR0_H_NAKTIMEOUT 0x0080
-#define MUSB_CSR0_H_STATUSPKT 0x0040
-#define MUSB_CSR0_H_REQPKT 0x0020
-#define MUSB_CSR0_H_ERROR 0x0010
-#define MUSB_CSR0_H_SETUPPKT 0x0008
-#define MUSB_CSR0_H_RXSTALL 0x0004
-
-/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_CSR0_P_WZC_BITS \
- (MUSB_CSR0_P_SENTSTALL)
-#define MUSB_CSR0_H_WZC_BITS \
- (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \
- | MUSB_CSR0_RXPKTRDY)
-
-/* TxType/RxType */
-#define MUSB_TYPE_SPEED 0xc0
-#define MUSB_TYPE_SPEED_SHIFT 6
-#define MUSB_TYPE_SPEED_HIGH 1
-#define MUSB_TYPE_SPEED_FULL 2
-#define MUSB_TYPE_SPEED_LOW 3
-#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */
-#define MUSB_TYPE_PROTO_SHIFT 4
-#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */
-#define MUSB_TYPE_PROTO_BULK 2
-#define MUSB_TYPE_PROTO_INTR 3
-
-/* CONFIGDATA */
-#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */
-#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */
-#define MUSB_CONFIGDATA_BIGENDIAN 0x20
-#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */
-#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */
-#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */
-#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */
-#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */
-
-/* TXCSR in Peripheral and Host mode */
-#define MUSB_TXCSR_AUTOSET 0x8000
-#define MUSB_TXCSR_MODE 0x2000
-#define MUSB_TXCSR_DMAENAB 0x1000
-#define MUSB_TXCSR_FRCDATATOG 0x0800
-#define MUSB_TXCSR_DMAMODE 0x0400
-#define MUSB_TXCSR_CLRDATATOG 0x0040
-#define MUSB_TXCSR_FLUSHFIFO 0x0008
-#define MUSB_TXCSR_FIFONOTEMPTY 0x0002
-#define MUSB_TXCSR_TXPKTRDY 0x0001
-
-/* TXCSR in Peripheral mode */
-#define MUSB_TXCSR_P_ISO 0x4000
-#define MUSB_TXCSR_P_INCOMPTX 0x0080
-#define MUSB_TXCSR_P_SENTSTALL 0x0020
-#define MUSB_TXCSR_P_SENDSTALL 0x0010
-#define MUSB_TXCSR_P_UNDERRUN 0x0004
-
-/* TXCSR in Host mode */
-#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200
-#define MUSB_TXCSR_H_DATATOGGLE 0x0100
-#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080
-#define MUSB_TXCSR_H_RXSTALL 0x0020
-#define MUSB_TXCSR_H_ERROR 0x0004
-#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8
-
-/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_TXCSR_P_WZC_BITS \
- (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \
- | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY)
-#define MUSB_TXCSR_H_WZC_BITS \
- (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
- | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
-
-/* RXCSR in Peripheral and Host mode */
-#define MUSB_RXCSR_AUTOCLEAR 0x8000
-#define MUSB_RXCSR_DMAENAB 0x2000
-#define MUSB_RXCSR_DISNYET 0x1000
-#define MUSB_RXCSR_PID_ERR 0x1000
-#define MUSB_RXCSR_DMAMODE 0x0800
-#define MUSB_RXCSR_INCOMPRX 0x0100
-#define MUSB_RXCSR_CLRDATATOG 0x0080
-#define MUSB_RXCSR_FLUSHFIFO 0x0010
-#define MUSB_RXCSR_DATAERROR 0x0008
-#define MUSB_RXCSR_FIFOFULL 0x0002
-#define MUSB_RXCSR_RXPKTRDY 0x0001
-
-/* RXCSR in Peripheral mode */
-#define MUSB_RXCSR_P_ISO 0x4000
-#define MUSB_RXCSR_P_SENTSTALL 0x0040
-#define MUSB_RXCSR_P_SENDSTALL 0x0020
-#define MUSB_RXCSR_P_OVERRUN 0x0004
-
-/* RXCSR in Host mode */
-#define MUSB_RXCSR_H_AUTOREQ 0x4000
-#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400
-#define MUSB_RXCSR_H_DATATOGGLE 0x0200
-#define MUSB_RXCSR_H_RXSTALL 0x0040
-#define MUSB_RXCSR_H_REQPKT 0x0020
-#define MUSB_RXCSR_H_ERROR 0x0004
-#define MUSB_S_RXCSR_H_DATATOGGLE 9
-
-/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */
-#define MUSB_RXCSR_P_WZC_BITS \
- (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \
- | MUSB_RXCSR_RXPKTRDY)
-#define MUSB_RXCSR_H_WZC_BITS \
- (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \
- | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY)
-
-/* HUBADDR */
-#define MUSB_HUBADDR_MULTI_TT 0x80
-
-/* Endpoint configuration information. Note: The value of endpoint fifo size
- * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other
- * values are not supported
- */
-struct musb_epinfo {
- u8 epnum; /* endpoint number */
- u8 epdir; /* endpoint direction */
- u16 epsize; /* endpoint FIFO size */
-};
-
-/*
- * Platform specific MUSB configuration. Any platform using the musb
- * functionality should create one instance of this structure in the
- * platform specific file.
- */
-struct musb_config {
- struct musb_regs *regs;
- u32 timeout;
- u8 musb_speed;
-};
-
-/* externally defined data */
-extern struct musb_config musb_cfg;
-extern struct musb_regs *musbr;
-
-/* exported functions */
-extern void musb_start(void);
-extern void musb_configure_ep(struct musb_epinfo *epinfo, u8 cnt);
-extern void write_fifo(u8 ep, u32 length, void *fifo_data);
-extern void read_fifo(u8 ep, u32 length, void *fifo_data);
-
-/* extern functions */
-extern inline void musb_writew(u32 offset, u16 value);
-extern inline void musb_writeb(u32 offset, u8 value);
-extern inline u16 musb_readw(u32 offset);
-extern inline u8 musb_readb(u32 offset);
-
-#endif /* __MUSB_HDRC_DEFS_H__ */
+++ /dev/null
-/*
- * Mentor USB OTG Core host controller driver.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <common.h>
-#include "musb_hcd.h"
-
-/* MSC control transfers */
-#define USB_MSC_BBB_RESET 0xFF
-#define USB_MSC_BBB_GET_MAX_LUN 0xFE
-
-/* Endpoint configuration information */
-static struct musb_epinfo epinfo[3] = {
- {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */
- {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */
- {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */
-};
-
-/*
- * This function writes the data toggle value.
- */
-static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out)
-{
- u16 toggle = usb_gettoggle(dev, ep, dir_out);
- u16 csr;
-
- if (dir_out) {
- if (!toggle)
- writew(MUSB_TXCSR_CLRDATATOG, &musbr->txcsr);
- else {
- csr = readw(&musbr->txcsr);
- csr |= MUSB_TXCSR_H_WR_DATATOGGLE;
- writew(csr, &musbr->txcsr);
- csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT);
- writew(csr, &musbr->txcsr);
- }
- } else {
- if (!toggle)
- writew(MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr);
- else {
- csr = readw(&musbr->rxcsr);
- csr |= MUSB_RXCSR_H_WR_DATATOGGLE;
- writew(csr, &musbr->rxcsr);
- csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE);
- writew(csr, &musbr->rxcsr);
- }
- }
-}
-
-/*
- * This function checks if RxStall has occured on the endpoint. If a RxStall
- * has occured, the RxStall is cleared and 1 is returned. If RxStall has
- * not occured, 0 is returned.
- */
-static u8 check_stall(u8 ep, u8 dir_out)
-{
- u16 csr;
-
- /* For endpoint 0 */
- if (!ep) {
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_CSR0_H_RXSTALL) {
- csr &= ~MUSB_CSR0_H_RXSTALL;
- writew(csr, &musbr->txcsr);
- return 1;
- }
- } else { /* For non-ep0 */
- if (dir_out) { /* is it tx ep */
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_TXCSR_H_RXSTALL) {
- csr &= ~MUSB_TXCSR_H_RXSTALL;
- writew(csr, &musbr->txcsr);
- return 1;
- }
- } else { /* is it rx ep */
- csr = readw(&musbr->rxcsr);
- if (csr & MUSB_RXCSR_H_RXSTALL) {
- csr &= ~MUSB_RXCSR_H_RXSTALL;
- writew(csr, &musbr->rxcsr);
- return 1;
- }
- }
- }
- return 0;
-}
-
-/*
- * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout
- * error and -2 for stall.
- */
-static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask)
-{
- u16 csr;
- int result = 1;
-
- while (result > 0) {
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_CSR0_H_ERROR) {
- csr &= ~MUSB_CSR0_H_ERROR;
- writew(csr, &musbr->txcsr);
- dev->status = USB_ST_CRC_ERR;
- result = -1;
- break;
- }
-
- switch (bit_mask) {
- case MUSB_CSR0_TXPKTRDY:
- if (!(csr & MUSB_CSR0_TXPKTRDY)) {
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- result = 0;
- }
- break;
-
- case MUSB_CSR0_RXPKTRDY:
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- if (csr & MUSB_CSR0_RXPKTRDY)
- result = 0;
- break;
-
- case MUSB_CSR0_H_REQPKT:
- if (!(csr & MUSB_CSR0_H_REQPKT)) {
- if (check_stall(MUSB_CONTROL_EP, 0)) {
- dev->status = USB_ST_STALLED;
- result = -2;
- } else
- result = 0;
- }
- break;
- }
- }
- return result;
-}
-
-/*
- * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error.
- */
-static u8 wait_until_txep_ready(struct usb_device *dev, u8 ep)
-{
- u16 csr;
-
- do {
- if (check_stall(ep, 1)) {
- dev->status = USB_ST_STALLED;
- return 0;
- }
-
- csr = readw(&musbr->txcsr);
- if (csr & MUSB_TXCSR_H_ERROR) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
- } while (csr & MUSB_TXCSR_TXPKTRDY);
- return 1;
-}
-
-/*
- * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error.
- */
-static u8 wait_until_rxep_ready(struct usb_device *dev, u8 ep)
-{
- u16 csr;
-
- do {
- if (check_stall(ep, 0)) {
- dev->status = USB_ST_STALLED;
- return 0;
- }
-
- csr = readw(&musbr->rxcsr);
- if (csr & MUSB_RXCSR_H_ERROR) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
- } while (!(csr & MUSB_RXCSR_RXPKTRDY));
- return 1;
-}
-
-/*
- * This function performs the setup phase of the control transfer
- */
-static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup)
-{
- int result;
- u16 csr;
-
- /* write the control request to ep0 fifo */
- write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup);
-
- /* enable transfer of setup packet */
- csr = readw(&musbr->txcsr);
- csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT);
- writew(csr, &musbr->txcsr);
-
- /* wait until the setup packet is transmitted */
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- dev->act_len = 0;
- return result;
-}
-
-/*
- * This function handles the control transfer in data phase
- */
-static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer)
-{
- u16 csr;
- u32 rxlen = 0;
- u32 nextlen = 0;
- u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
- u8 *rxbuff = (u8 *)buffer;
- u8 rxedlength;
- int result;
-
- while (rxlen < len) {
- /* Determine the next read length */
- nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen);
-
- /* Set the ReqPkt bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY);
- if (result < 0)
- return result;
-
- /* Actual number of bytes received by usb */
- rxedlength = readb(&musbr->rxcount);
-
- /* Read the data from the RxFIFO */
- read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]);
-
- /* Clear the RxPktRdy Bit */
- csr = readw(&musbr->txcsr);
- csr &= ~MUSB_CSR0_RXPKTRDY;
- writew(csr, &musbr->txcsr);
-
- /* short packet? */
- if (rxedlength != nextlen) {
- dev->act_len += rxedlength;
- break;
- }
- rxlen += nextlen;
- dev->act_len = rxlen;
- }
- return 0;
-}
-
-/*
- * This function handles the control transfer out data phase
- */
-static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer)
-{
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 maxpktsize = (1 << dev->maxpacketsize) * 8;
- u8 *txbuff = (u8 *)buffer;
- int result = 0;
-
- while (txlen < len) {
- /* Determine the next write length */
- nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen);
-
- /* Load the data to send in FIFO */
- write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]);
-
- /* Set TXPKTRDY bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY,
- &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- if (result < 0)
- break;
-
- txlen += nextlen;
- dev->act_len = txlen;
- }
- return result;
-}
-
-/*
- * This function handles the control transfer out status phase
- */
-static int ctrlreq_out_status_phase(struct usb_device *dev)
-{
- u16 csr;
- int result;
-
- /* Set the StatusPkt bit */
- csr = readw(&musbr->txcsr);
- csr |= (MUSB_CSR0_H_DIS_PING | MUSB_CSR0_TXPKTRDY |
- MUSB_CSR0_H_STATUSPKT);
- writew(csr, &musbr->txcsr);
-
- /* Wait until TXPKTRDY bit is cleared */
- result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY);
- return result;
-}
-
-/*
- * This function handles the control transfer in status phase
- */
-static int ctrlreq_in_status_phase(struct usb_device *dev)
-{
- u16 csr;
- int result;
-
- /* Set the StatusPkt bit and ReqPkt bit */
- csr = MUSB_CSR0_H_DIS_PING | MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT;
- writew(csr, &musbr->txcsr);
- result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT);
-
- /* clear StatusPkt bit and RxPktRdy bit */
- csr = readw(&musbr->txcsr);
- csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT);
- writew(csr, &musbr->txcsr);
- return result;
-}
-
-/*
- * determines the speed of the device (High/Full/Slow)
- */
-static u8 get_dev_speed(struct usb_device *dev)
-{
- return (dev->speed & USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH :
- ((dev->speed & USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW :
- MUSB_TYPE_SPEED_FULL);
-}
-
-/*
- * configure the hub address and the port address.
- */
-static void config_hub_port(struct usb_device *dev, u8 ep)
-{
- u8 chid;
- u8 hub;
-
- /* Find out the nearest parent which is high speed */
- while (dev->parent->parent != NULL)
- if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH)
- dev = dev->parent;
- else
- break;
-
- /* determine the port address at that hub */
- hub = dev->parent->devnum;
- for (chid = 0; chid < USB_MAXCHILDREN; chid++)
- if (dev->parent->children[chid] == dev)
- break;
-
- /* configure the hub address and the port address */
- writeb(hub, &musbr->tar[ep].txhubaddr);
- writeb((chid + 1), &musbr->tar[ep].txhubport);
- writeb(hub, &musbr->tar[ep].rxhubaddr);
- writeb((chid + 1), &musbr->tar[ep].rxhubport);
-}
-
-/*
- * do a control transfer
- */
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, struct devrequest *setup)
-{
- int devnum = usb_pipedevice(pipe);
- u16 csr;
- u8 devspeed;
-
- /* select control endpoint */
- writeb(MUSB_CONTROL_EP, &musbr->index);
- csr = readw(&musbr->txcsr);
-
- /* target addr and (for multipoint) hub addr/port */
- writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr);
- writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr);
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- config_hub_port(dev, MUSB_CONTROL_EP);
- writeb(devspeed << 6, &musbr->txtype);
- } else {
- writeb(musb_cfg.musb_speed << 6, &musbr->txtype);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport);
- }
-
- /* Control transfer setup phase */
- if (ctrlreq_setup_phase(dev, setup) < 0)
- return 0;
-
- switch (setup->request) {
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_GET_STATUS:
- case USB_MSC_BBB_GET_MAX_LUN:
- /* control transfer in-data-phase */
- if (ctrlreq_in_data_phase(dev, len, buffer) < 0)
- return 0;
- /* control transfer out-status-phase */
- if (ctrlreq_out_status_phase(dev) < 0)
- return 0;
- break;
-
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_INTERFACE:
- case USB_REQ_CLEAR_FEATURE:
- case USB_MSC_BBB_RESET:
- /* control transfer in status phase */
- if (ctrlreq_in_status_phase(dev) < 0)
- return 0;
- break;
-
- case USB_REQ_SET_DESCRIPTOR:
- /* control transfer out data phase */
- if (ctrlreq_out_data_phase(dev, len, buffer) < 0)
- return 0;
- /* control transfer in status phase */
- if (ctrlreq_in_status_phase(dev) < 0)
- return 0;
- break;
-
- default:
- /* unhandled control transfer */
- return -1;
- }
-
- dev->status = 0;
- dev->act_len = len;
- return len;
-}
-
-/*
- * do a bulk transfer
- */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int len)
-{
- int dir_out = usb_pipeout(pipe);
- int ep = usb_pipeendpoint(pipe);
- int devnum = usb_pipedevice(pipe);
- u8 type;
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 devspeed;
-
- /* select bulk endpoint */
- writeb(MUSB_BULK_EP, &musbr->index);
-
- /* write the address of the device */
- if (dir_out)
- writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr);
- else
- writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr);
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- /*
- * MUSB is in high speed and the destination device is full
- * speed device. So configure the hub address and port
- * address registers.
- */
- config_hub_port(dev, MUSB_BULK_EP);
- } else {
- if (dir_out) {
- writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport);
- } else {
- writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport);
- }
- devspeed = musb_cfg.musb_speed;
- }
-
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- if (dir_out) { /* bulk-out transfer */
- /* Program the TxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->txtype);
-
- /* Write maximum packet size to the TxMaxp register */
- writew(dev->epmaxpacketout[ep], &musbr->txmaxp);
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ?
- (len-txlen) : dev->epmaxpacketout[ep];
-
- /* Write the data to the FIFO */
- write_fifo(MUSB_BULK_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Set the TxPktRdy bit */
- csr = readw(&musbr->txcsr);
- writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr);
-
- /* Wait until the TxPktRdy bit is cleared */
- if (!wait_until_txep_ready(dev, MUSB_BULK_EP)) {
- readw(&musbr->txcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
- dev->act_len = txlen;
- return 0;
- }
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->txcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1);
- } else { /* bulk-in transfer */
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- /* Program the RxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->rxtype);
-
- /* Write the maximum packet size to the RxMaxp register */
- writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
- (len-txlen) : dev->epmaxpacketin[ep];
-
- /* Set the ReqPkt bit */
- writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
-
- /* Wait until the RxPktRdy bit is set */
- if (!wait_until_rxep_ready(dev, MUSB_BULK_EP)) {
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- dev->act_len = txlen;
- return 0;
- }
-
- /* Read the data from the FIFO */
- read_fifo(MUSB_BULK_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Clear the RxPktRdy bit */
- csr = readw(&musbr->rxcsr);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- }
-
- /* bulk transfer is complete */
- dev->status = 0;
- dev->act_len = len;
- return 0;
-}
-
-/*
- * This function initializes the usb controller module.
- */
-int usb_lowlevel_init(void)
-{
- u8 power;
- u32 timeout;
-
- if (musb_platform_init() == -1)
- return -1;
-
- /* Configure all the endpoint FIFO's and start usb controller */
- musbr = musb_cfg.regs;
- musb_configure_ep(&epinfo[0],
- sizeof(epinfo) / sizeof(struct musb_epinfo));
- musb_start();
-
- /*
- * Wait until musb is enabled in host mode with a timeout. There
- * should be a usb device connected.
- */
- timeout = musb_cfg.timeout;
- while (timeout--)
- if (readb(&musbr->devctl) & MUSB_DEVCTL_HM)
- break;
-
- /* if musb core is not in host mode, then return */
- if (!timeout)
- return -1;
-
- /* start usb bus reset */
- power = readb(&musbr->power);
- writeb(power | MUSB_POWER_RESET, &musbr->power);
-
- /* After initiating a usb reset, wait for about 20ms to 30ms */
- udelay(30000);
-
- /* stop usb bus reset */
- power = readb(&musbr->power);
- power &= ~MUSB_POWER_RESET;
- writeb(power, &musbr->power);
-
- /* Determine if the connected device is a high/full/low speed device */
- musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ?
- MUSB_TYPE_SPEED_HIGH :
- ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ?
- MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW);
- return 0;
-}
-
-/*
- * This function stops the operation of the davinci usb module.
- */
-int usb_lowlevel_stop(void)
-{
- /* Reset the USB module */
- musb_platform_deinit();
- writeb(0, &musbr->devctl);
- return 0;
-}
-
-/*
- * This function supports usb interrupt transfers. Currently, usb interrupt
- * transfers are not supported.
- */
-int submit_int_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int len, int interval)
-{
- int dir_out = usb_pipeout(pipe);
- int ep = usb_pipeendpoint(pipe);
- int devnum = usb_pipedevice(pipe);
- u8 type;
- u16 csr;
- u32 txlen = 0;
- u32 nextlen = 0;
- u8 devspeed;
-
- /* select interrupt endpoint */
- writeb(MUSB_INTR_EP, &musbr->index);
-
- /* write the address of the device */
- if (dir_out)
- writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr);
- else
- writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr);
-
- /* configure the hub address and the port number as required */
- devspeed = get_dev_speed(dev);
- if ((musb_ishighspeed()) && (dev->parent != NULL) &&
- (devspeed != MUSB_TYPE_SPEED_HIGH)) {
- /*
- * MUSB is in high speed and the destination device is full
- * speed device. So configure the hub address and port
- * address registers.
- */
- config_hub_port(dev, MUSB_INTR_EP);
- } else {
- if (dir_out) {
- writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr);
- writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport);
- } else {
- writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr);
- writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport);
- }
- devspeed = musb_cfg.musb_speed;
- }
-
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
-
- if (!dir_out) { /* intrrupt-in transfer */
- /* Write the saved toggle bit value */
- write_toggle(dev, ep, dir_out);
- writeb(interval, &musbr->rxinterval);
-
- /* Program the RxType register */
- type = (devspeed << MUSB_TYPE_SPEED_SHIFT) |
- (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) |
- (ep & MUSB_TYPE_REMOTE_END);
- writeb(type, &musbr->rxtype);
-
- /* Write the maximum packet size to the RxMaxp register */
- writew(dev->epmaxpacketin[ep], &musbr->rxmaxp);
-
- while (txlen < len) {
- nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ?
- (len-txlen) : dev->epmaxpacketin[ep];
-
- /* Set the ReqPkt bit */
- writew(MUSB_RXCSR_H_REQPKT, &musbr->rxcsr);
-
- /* Wait until the RxPktRdy bit is set */
- if (!wait_until_rxep_ready(dev, MUSB_INTR_EP)) {
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- dev->act_len = txlen;
- return 0;
- }
-
- /* Read the data from the FIFO */
- read_fifo(MUSB_INTR_EP, nextlen,
- (void *)(((u8 *)buffer) + txlen));
-
- /* Clear the RxPktRdy bit */
- csr = readw(&musbr->rxcsr);
- csr &= ~MUSB_RXCSR_RXPKTRDY;
- writew(csr, &musbr->rxcsr);
- txlen += nextlen;
- }
-
- /* Keep a copy of the data toggle bit */
- csr = readw(&musbr->rxcsr);
- usb_settoggle(dev, ep, dir_out,
- (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1);
- }
-
- /* interrupt transfer is complete */
- dev->irq_status = 0;
- dev->irq_act_len = len;
- dev->irq_handle(dev);
- dev->status = 0;
- dev->act_len = len;
- return 0;
-}
-
-
-#ifdef CONFIG_SYS_USB_EVENT_POLL
-/*
- * This function polls for USB keyboard data.
- */
-void usb_event_poll()
-{
- device_t *dev;
- struct usb_device *usb_kbd_dev;
- struct usb_interface_descriptor *iface;
- struct usb_endpoint_descriptor *ep;
- int pipe;
- int maxp;
-
- /* Get the pointer to USB Keyboard device pointer */
- dev = device_get_by_name("usbkbd");
- usb_kbd_dev = (struct usb_device *)dev->priv;
- iface = &usb_kbd_dev->config.if_desc[0];
- ep = &iface->ep_desc[0];
- pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
-
- /* Submit a interrupt transfer request */
- maxp = usb_maxpacket(usb_kbd_dev, pipe);
- usb_submit_int_msg(usb_kbd_dev, pipe, &new[0],
- maxp > 8 ? 8 : maxp, ep->bInterval);
-}
-#endif /* CONFIG_SYS_USB_EVENT_POLL */
+++ /dev/null
-/*
- * Mentor USB OTG Core host controller driver.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#ifndef __MUSB_HCD_H__
-#define __MUSB_HCD_H__
-
-#include "musb_core.h"
-#ifdef CONFIG_USB_KEYBOARD
-#include <devices.h>
-extern unsigned char new[];
-#endif
-
-/* This defines the endpoint number used for control transfers */
-#define MUSB_CONTROL_EP 0
-
-/* This defines the endpoint number used for bulk transfer */
-#define MUSB_BULK_EP 1
-
-/* This defines the endpoint number used for interrupt transfer */
-#define MUSB_INTR_EP 2
-
-/* Determine the operating speed of MUSB core */
-#define musb_ishighspeed() \
- ((readb(&musbr->power) & MUSB_POWER_HSMODE) \
- >> MUSB_POWER_HSMODE_SHIFT)
-
-/* extern functions */
-extern int musb_platform_init(void);
-extern void musb_platform_deinit(void);
-
-#endif /* __MUSB_HCD_H__ */
+++ /dev/null
-/*
- * R8A66597 HCD (Host Controller Driver) for u-boot
- *
- * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <common.h>
-#include <usb.h>
-#include <asm/io.h>
-
-#include "r8a66597.h"
-
-#ifdef R8A66597_DEBUG
-#define R8A66597_DPRINT printf
-#else
-#define R8A66597_DPRINT(...)
-#endif
-
-static const char hcd_name[] = "r8a66597_hcd";
-static unsigned short clock = CONFIG_R8A66597_XTAL;
-static unsigned short vif = CONFIG_R8A66597_LDRV;
-static unsigned short endian = CONFIG_R8A66597_ENDIAN;
-static struct r8a66597 gr8a66597;
-
-static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
-{
- int i;
-
- *hub_devnum = 0;
- *hubport = 0;
-
- /* check a device connected to root_hub */
- if ((dev->parent && dev->parent->devnum == 1) ||
- (dev->devnum == 1))
- return;
-
- for (i = 0; i < USB_MAXCHILDREN; i++) {
- if (dev->parent->children[i] == dev) {
- *hub_devnum = (u8)dev->parent->devnum;
- *hubport = i;
- return;
- }
- }
-
- printf("get_hub_data error.\n");
-}
-
-static void set_devadd(struct r8a66597 *r8a66597, u8 r8a66597_address,
- struct usb_device *dev, int port)
-{
- u16 val, usbspd, upphub, hubport;
- unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
-
- get_hub_data(dev, &upphub, &hubport);
- usbspd = r8a66597->speed;
- val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
- r8a66597_write(r8a66597, val, devadd_reg);
-}
-
-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) {
- printf("register access fail.\n");
- return -1;
- }
- } while ((tmp & SCKE) != SCKE);
- r8a66597_write(r8a66597, 0x04, 0x02);
-#else
- do {
- r8a66597_write(r8a66597, USBE, SYSCFG0);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 1000) {
- printf("register access fail.\n");
- return -1;
- }
- } while ((tmp & USBE) != USBE);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
- r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
-
- i = 0;
- r8a66597_bset(r8a66597, XCKE, SYSCFG0);
- do {
- udelay(1000);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 500) {
- printf("register access fail.\n");
- return -1;
- }
- } 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));
-}
-
-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, USBE, SYSCFG0);
-
- r8a66597_bset(r8a66597, INTL, SOFCFG);
- r8a66597_write(r8a66597, 0, INTENB0);
- r8a66597_write(r8a66597, 0, INTENB1);
- r8a66597_write(r8a66597, 0, INTENB2);
-
- r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
- r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
- r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
- r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
-
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
- r8a66597_enable_port(r8a66597, port);
-
- return 0;
-}
-
-static void disable_controller(struct r8a66597 *r8a66597)
-{
- int i;
-
- if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
- return;
-
- r8a66597_write(r8a66597, 0, INTENB0);
- r8a66597_write(r8a66597, 0, INTSTS0);
-
- r8a66597_write(r8a66597, 0, D0FIFOSEL);
- r8a66597_write(r8a66597, 0, D1FIFOSEL);
- r8a66597_write(r8a66597, 0, DCPCFG);
- r8a66597_write(r8a66597, 0x40, DCPMAXP);
- r8a66597_write(r8a66597, 0, DCPCTR);
-
- for (i = 0; i <= 10; i++)
- r8a66597_write(r8a66597, 0, get_devadd_addr(i));
- for (i = 1; i <= 5; i++) {
- r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
- r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
- }
- for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
- r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
- r8a66597_write(r8a66597, i, PIPESEL);
- r8a66597_write(r8a66597, 0, PIPECFG);
- r8a66597_write(r8a66597, 0, PIPEBUF);
- r8a66597_write(r8a66597, 0, PIPEMAXP);
- r8a66597_write(r8a66597, 0, PIPEPERI);
- }
-
- for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
- r8a66597_disable_port(r8a66597, i);
-
- r8a66597_clock_disable(r8a66597);
-}
-
-static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
- u16 mask, u16 loop)
-{
- u16 tmp;
- int i = 0;
-
- do {
- tmp = r8a66597_read(r8a66597, reg);
- if (i++ > 1000000) {
- printf("register%lx, loop %x is timeout\n", reg, loop);
- break;
- }
- } while ((tmp & mask) != loop);
-}
-
-static void pipe_buffer_setting(struct r8a66597 *r8a66597,
- struct usb_device *dev, unsigned long pipe)
-{
- u16 val = 0;
- u16 pipenum, bufnum, maxpacket;
-
- if (usb_pipein(pipe)) {
- pipenum = BULK_IN_PIPENUM;
- bufnum = BULK_IN_BUFNUM;
- maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
- } else {
- pipenum = BULK_OUT_PIPENUM;
- bufnum = BULK_OUT_BUFNUM;
- maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
- }
-
- if (r8a66597->pipe_config & (1 << pipenum))
- return;
- r8a66597->pipe_config |= (1 << pipenum);
-
- r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
- r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
- r8a66597_write(r8a66597, pipenum, PIPESEL);
-
- /* FIXME: This driver support bulk transfer only. */
- if (!usb_pipein(pipe))
- val |= R8A66597_DIR;
- else
- val |= R8A66597_SHTNAK;
- val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
- r8a66597_write(r8a66597, val, PIPECFG);
-
- r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
- r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
- maxpacket, PIPEMAXP);
- r8a66597_write(r8a66597, 0, PIPEPERI);
- r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
-}
-
-static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
- struct devrequest *setup)
-{
- int i;
- unsigned short *p = (unsigned short *)setup;
- unsigned long setup_addr = USBREQ;
- u16 intsts1;
- int timeout = 3000;
- u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
-
- r8a66597_write(r8a66597, make_devsel(devsel) |
- (8 << dev->maxpacketsize), DCPMAXP);
- r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
-
- for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
- setup_addr += 2;
- }
- r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
- r8a66597_write(r8a66597, SUREQ, DCPCTR);
-
- while (1) {
- intsts1 = r8a66597_read(r8a66597, INTSTS1);
- if (intsts1 & SACK)
- break;
- if (intsts1 & SIGN) {
- printf("setup packet send error\n");
- return -1;
- }
- if (timeout-- < 0) {
- printf("setup packet timeout\n");
- return -1;
- }
- udelay(500);
- }
-
- return 0;
-}
-
-static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
- unsigned long pipe, void *buffer, int transfer_len)
-{
- u16 tmp, bufsize;
- u16 *buf;
- size_t size;
-
- R8A66597_DPRINT("%s\n", __func__);
-
- r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
- MBW | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
- tmp = r8a66597_read(r8a66597, CFIFOCTR);
- if ((tmp & FRDY) == 0) {
- printf("%s FRDY is not set (%x)\n", __func__, tmp);
- return -1;
- }
-
- /* prepare parameters */
- bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
- buf = (u16 *)(buffer + dev->act_len);
- size = min((int)bufsize, transfer_len - dev->act_len);
-
- /* write fifo */
- r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
- if (buffer) {
- r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
- r8a66597_write(r8a66597, BVAL, CFIFOCTR);
- }
-
- /* update parameters */
- dev->act_len += size;
-
- r8a66597_mdfy(r8a66597, PID_BUF, PID,
- get_pipectr_addr(BULK_OUT_PIPENUM));
-
- while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
- if (ctrlc())
- return -1;
- r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
-
- if (dev->act_len >= transfer_len)
- r8a66597_mdfy(r8a66597, PID_NAK, PID,
- get_pipectr_addr(BULK_OUT_PIPENUM));
-
- return 0;
-}
-
-static int receive_bulk_packet(struct r8a66597 *r8a66597,
- struct usb_device *dev,
- unsigned long pipe,
- void *buffer, int transfer_len)
-{
- u16 tmp;
- u16 *buf;
- const u16 pipenum = BULK_IN_PIPENUM;
- int rcv_len;
- int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
-
- R8A66597_DPRINT("%s\n", __func__);
-
- /* prepare */
- if (dev->act_len == 0) {
- r8a66597_mdfy(r8a66597, PID_NAK, PID,
- get_pipectr_addr(pipenum));
- r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
-
- r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
- r8a66597_write(r8a66597,
- (transfer_len + maxpacket - 1) / maxpacket,
- get_pipetrn_addr(pipenum));
- r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
-
- r8a66597_mdfy(r8a66597, PID_BUF, PID,
- get_pipectr_addr(pipenum));
- }
-
- r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
-
- while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
- if (ctrlc())
- return -1;
- r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
-
- tmp = r8a66597_read(r8a66597, CFIFOCTR);
- if ((tmp & FRDY) == 0) {
- printf("%s FRDY is not set. (%x)\n", __func__, tmp);
- return -1;
- }
-
- buf = (u16 *)(buffer + dev->act_len);
- rcv_len = tmp & DTLN;
- dev->act_len += rcv_len;
-
- if (buffer) {
- if (rcv_len == 0)
- r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- else
- r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
- }
-
- return 0;
-}
-
-static int receive_control_packet(struct r8a66597 *r8a66597,
- struct usb_device *dev,
- void *buffer, int transfer_len)
-{
- u16 tmp;
- int rcv_len;
-
- /* FIXME: limit transfer size : 64byte or less */
-
- r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
- r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
- r8a66597_bset(r8a66597, SQSET, DCPCTR);
- r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
-
- while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
- if (ctrlc())
- return -1;
- r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
-
- r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
-
- tmp = r8a66597_read(r8a66597, CFIFOCTR);
- if ((tmp & FRDY) == 0) {
- printf("%s FRDY is not set. (%x)\n", __func__, tmp);
- return -1;
- }
-
- rcv_len = tmp & DTLN;
- dev->act_len += rcv_len;
-
- r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
-
- if (buffer) {
- if (rcv_len == 0)
- r8a66597_write(r8a66597, BCLR, DCPCTR);
- else
- r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
- }
-
- return 0;
-}
-
-static int send_status_packet(struct r8a66597 *r8a66597,
- unsigned long pipe)
-{
- r8a66597_bset(r8a66597, SQSET, DCPCTR);
- r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
-
- if (usb_pipein(pipe)) {
- r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
- r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
- r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
- r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
- } else {
- r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
- r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
- r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
- r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- }
- r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
-
- while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
- if (ctrlc())
- return -1;
-
- return 0;
-}
-
-static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
-{
- int count = R8A66597_MAX_SAMPLING;
- unsigned short syssts, old_syssts;
-
- R8A66597_DPRINT("%s\n", __func__);
-
- old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
- while (count > 0) {
- wait_ms(R8A66597_RH_POLL_TIME);
-
- syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
- if (syssts == old_syssts) {
- count--;
- } else {
- count = R8A66597_MAX_SAMPLING;
- old_syssts = syssts;
- }
- }
-}
-
-static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
-{
- wait_ms(10);
- r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
- wait_ms(50);
- r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
- wait_ms(50);
-}
-
-static int check_usb_device_connecting(struct r8a66597 *r8a66597)
-{
- int timeout = 10000; /* 100usec * 10000 = 1sec */
- int i;
-
- for (i = 0; i < 5; i++) {
- /* check a usb cable connect */
- while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
- if (timeout-- < 0) {
- printf("%s timeout.\n", __func__);
- return -1;
- }
- udelay(100);
- }
-
- /* check a data line */
- r8a66597_check_syssts(r8a66597, 0);
-
- r8a66597_bus_reset(r8a66597, 0);
- r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
-
- if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
- r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
- r8a66597->port_status = USB_PORT_STAT_CONNECTION |
- USB_PORT_STAT_ENABLE;
- return 0; /* success */
- }
-
- R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
- r8a66597_write(r8a66597, ~DTCH, INTSTS1);
- }
-
- return -1; /* fail */
-}
-
-/* based on usb_ohci.c */
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x01, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 0x01, /* __u8 bConfigurationValue; */
- 0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes; */
-
- 0x00, /* __u8 MaxPower; */
-
- /* interface */
- 0x09, /* __u8 if_bLength; */
- 0x04, /* __u8 if_bDescriptorType; Interface */
- 0x00, /* __u8 if_bInterfaceNumber; */
- 0x00, /* __u8 if_bAlternateSetting; */
- 0x01, /* __u8 if_bNumEndpoints; */
- 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* __u8 if_bInterfaceSubClass; */
- 0x00, /* __u8 if_bInterfaceProtocol; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 0x00,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] =
-{
- 0x04, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 0x09, /* __u8 lang ID */
- 0x04, /* __u8 lang ID */
-};
-
-static unsigned char root_hub_str_index1[] =
-{
- 34, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 'R', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '8', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'A', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '6', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '6', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '5', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '9', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- '7', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'R', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 't', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'u', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'b', /* __u8 Unicode */
- 0, /* __u8 Unicode */
-};
-
-static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len, struct devrequest *cmd)
-{
- struct r8a66597 *r8a66597 = &gr8a66597;
- int leni = transfer_len;
- int len = 0;
- int stat = 0;
- __u16 bmRType_bReq;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
- unsigned char data[32];
-
- R8A66597_DPRINT("%s\n", __func__);
-
- if (usb_pipeint(pipe)) {
- printf("Root-Hub submit IRQ: NOT implemented");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = cpu_to_le16 (cmd->value);
- wIndex = cpu_to_le16 (cmd->index);
- wLength = cpu_to_le16 (cmd->length);
-
- switch (bmRType_bReq) {
- case RH_GET_STATUS:
- *(__u16 *)buffer = cpu_to_le16(1);
- len = 2;
- break;
- case RH_GET_STATUS | RH_INTERFACE:
- *(__u16 *)buffer = cpu_to_le16(0);
- len = 2;
- break;
- case RH_GET_STATUS | RH_ENDPOINT:
- *(__u16 *)buffer = cpu_to_le16(0);
- len = 2;
- break;
- case RH_GET_STATUS | RH_CLASS:
- *(__u32 *)buffer = cpu_to_le32(0);
- len = 4;
- break;
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- *(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
- (r8a66597->port_change << 16));
- len = 4;
- break;
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- case RH_CLEAR_FEATURE | RH_CLASS:
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case RH_C_PORT_CONNECTION:
- r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
- break;
- }
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_SUSPEND):
- break;
- case (RH_PORT_RESET):
- r8a66597_bus_reset(r8a66597, 0);
- break;
- case (RH_PORT_POWER):
- break;
- case (RH_PORT_ENABLE):
- break;
- }
- break;
- case RH_SET_ADDRESS:
- gr8a66597.rh_devnum = wValue;
- break;
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_dev_des),
- wLength));
- memcpy(buffer, root_hub_dev_des, len);
- break;
- case (0x02): /* configuration descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_config_des),
- wLength));
- memcpy(buffer, root_hub_config_des, len);
- break;
- case (0x03): /* string descriptors */
- if (wValue == 0x0300) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_str_index0),
- wLength));
- memcpy(buffer, root_hub_str_index0, len);
- }
- if (wValue == 0x0301) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_str_index1),
- wLength));
- memcpy(buffer, root_hub_str_index1, len);
- }
- break;
- default:
- stat = USB_ST_STALLED;
- }
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS:
- {
- __u32 temp = 0x00000001;
-
- data[0] = 9; /* min length; */
- data[1] = 0x29;
- data[2] = temp & RH_A_NDP;
- data[3] = 0;
- if (temp & RH_A_PSM)
- data[3] |= 0x1;
- if (temp & RH_A_NOCP)
- data[3] |= 0x10;
- else if (temp & RH_A_OCPM)
- data[3] |= 0x8;
-
- /* corresponds to data[4-7] */
- data[5] = (temp & RH_A_POTPGT) >> 24;
- data[7] = temp & RH_B_DR;
- if (data[2] < 7) {
- data[8] = 0xff;
- } else {
- data[0] += 2;
- data[8] = (temp & RH_B_DR) >> 8;
- data[10] = data[9] = 0xff;
- }
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data[0], wLength));
- memcpy(buffer, data, len);
- break;
- }
-
- case RH_GET_CONFIGURATION:
- *(__u8 *) buffer = 0x01;
- len = 1;
- break;
- case RH_SET_CONFIGURATION:
- break;
- default:
- R8A66597_DPRINT("unsupported root hub command");
- stat = USB_ST_STALLED;
- }
-
- wait_ms(1);
-
- len = min_t(int, len, leni);
-
- dev->act_len = len;
- dev->status = stat;
-
- return stat;
-}
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len)
-{
- struct r8a66597 *r8a66597 = &gr8a66597;
- int ret = 0;
-
- R8A66597_DPRINT("%s\n", __func__);
- R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
- pipe, buffer, transfer_len, dev->devnum);
-
- set_devadd(r8a66597, dev->devnum, dev, 0);
-
- pipe_buffer_setting(r8a66597, dev, pipe);
-
- dev->act_len = 0;
- while (dev->act_len < transfer_len && ret == 0) {
- if (ctrlc())
- return -1;
-
- if (usb_pipein(pipe))
- ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
- transfer_len);
- else
- ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
- transfer_len);
- }
-
- if (ret == 0)
- dev->status = 0;
-
- return ret;
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len, struct devrequest *setup)
-{
- struct r8a66597 *r8a66597 = &gr8a66597;
- u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
- 0 : dev->devnum;
-
- R8A66597_DPRINT("%s\n", __func__);
- if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
- return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len,
- setup);
-
- R8A66597_DPRINT("%s: setup\n", __func__);
- set_devadd(r8a66597, r8a66597_address, dev, 0);
-
- if (send_setup_packet(r8a66597, dev, setup) < 0) {
- printf("setup packet send error\n");
- return -1;
- }
-
- dev->act_len = 0;
- if (usb_pipein(pipe))
- if (receive_control_packet(r8a66597, dev, buffer,
- transfer_len) < 0)
- return -1;
-
- if (send_status_packet(r8a66597, pipe) < 0)
- return -1;
-
- dev->status = 0;
-
- return 0;
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, int interval)
-{
- /* no implement */
- R8A66597_DPRINT("%s\n", __func__);
- return 0;
-}
-
-void usb_event_poll(void)
-{
- /* no implement */
- R8A66597_DPRINT("%s\n", __func__);
-}
-
-int usb_lowlevel_init(void)
-{
- struct r8a66597 *r8a66597 = &gr8a66597;
-
- R8A66597_DPRINT("%s\n", __func__);
-
- memset(r8a66597, 0, sizeof(r8a66597));
- r8a66597->reg = CONFIG_R8A66597_BASE_ADDR;
-
- disable_controller(r8a66597);
- wait_ms(100);
-
- enable_controller(r8a66597);
- r8a66597_port_power(r8a66597, 0 , 1);
-
- /* check usb device */
- check_usb_device_connecting(r8a66597);
-
- wait_ms(50);
-
- return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
- disable_controller(&gr8a66597);
-
- return 0;
-}
+++ /dev/null
-/*
- * R8A66597 HCD (Host Controller Driver) for u-boot
- *
- * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#ifndef __R8A66597_H__
-#define __R8A66597_H__
-
-#define SYSCFG0 0x00
-#define SYSCFG1 0x02
-#define SYSSTS0 0x04
-#define SYSSTS1 0x06
-#define DVSTCTR0 0x08
-#define DVSTCTR1 0x0A
-#define TESTMODE 0x0C
-#define PINCFG 0x0E
-#define DMA0CFG 0x10
-#define DMA1CFG 0x12
-#define CFIFO 0x14
-#define D0FIFO 0x18
-#define D1FIFO 0x1C
-#define CFIFOSEL 0x20
-#define CFIFOCTR 0x22
-#define CFIFOSIE 0x24
-#define D0FIFOSEL 0x28
-#define D0FIFOCTR 0x2A
-#define D1FIFOSEL 0x2C
-#define D1FIFOCTR 0x2E
-#define INTENB0 0x30
-#define INTENB1 0x32
-#define INTENB2 0x34
-#define BRDYENB 0x36
-#define NRDYENB 0x38
-#define BEMPENB 0x3A
-#define SOFCFG 0x3C
-#define INTSTS0 0x40
-#define INTSTS1 0x42
-#define INTSTS2 0x44
-#define BRDYSTS 0x46
-#define NRDYSTS 0x48
-#define BEMPSTS 0x4A
-#define FRMNUM 0x4C
-#define UFRMNUM 0x4E
-#define USBADDR 0x50
-#define USBREQ 0x54
-#define USBVAL 0x56
-#define USBINDX 0x58
-#define USBLENG 0x5A
-#define DCPCFG 0x5C
-#define DCPMAXP 0x5E
-#define DCPCTR 0x60
-#define PIPESEL 0x64
-#define PIPECFG 0x68
-#define PIPEBUF 0x6A
-#define PIPEMAXP 0x6C
-#define PIPEPERI 0x6E
-#define PIPE1CTR 0x70
-#define PIPE2CTR 0x72
-#define PIPE3CTR 0x74
-#define PIPE4CTR 0x76
-#define PIPE5CTR 0x78
-#define PIPE6CTR 0x7A
-#define PIPE7CTR 0x7C
-#define PIPE8CTR 0x7E
-#define PIPE9CTR 0x80
-#define PIPE1TRE 0x90
-#define PIPE1TRN 0x92
-#define PIPE2TRE 0x94
-#define PIPE2TRN 0x96
-#define PIPE3TRE 0x98
-#define PIPE3TRN 0x9A
-#define PIPE4TRE 0x9C
-#define PIPE4TRN 0x9E
-#define PIPE5TRE 0xA0
-#define PIPE5TRN 0xA2
-#define DEVADD0 0xD0
-#define DEVADD1 0xD2
-#define DEVADD2 0xD4
-#define DEVADD3 0xD6
-#define DEVADD4 0xD8
-#define DEVADD5 0xDA
-#define DEVADD6 0xDC
-#define DEVADD7 0xDE
-#define DEVADD8 0xE0
-#define DEVADD9 0xE2
-#define DEVADDA 0xE4
-
-/* System Configuration Control Register */
-#define XTAL 0xC000 /* b15-14: Crystal selection */
-#define XTAL48 0x8000 /* 48MHz */
-#define XTAL24 0x4000 /* 24MHz */
-#define XTAL12 0x0000 /* 12MHz */
-#define XCKE 0x2000 /* b13: External clock enable */
-#define PLLC 0x0800 /* b11: PLL control */
-#define SCKE 0x0400 /* b10: USB clock enable */
-#define PCSDIS 0x0200 /* b9: not CS wakeup */
-#define LPSME 0x0100 /* b8: Low power sleep mode */
-#define HSE 0x0080 /* b7: Hi-speed enable */
-#define DCFM 0x0040 /* b6: Controller function select */
-#define DRPD 0x0020 /* b5: D+/- pull down control */
-#define DPRPU 0x0010 /* b4: D+ pull up control */
-#define USBE 0x0001 /* b0: USB module operation enable */
-
-/* System Configuration Status Register */
-#define OVCBIT 0x8000 /* b15-14: Over-current bit */
-#define OVCMON 0xC000 /* b15-14: Over-current monitor */
-#define SOFEA 0x0020 /* b5: SOF monitor */
-#define IDMON 0x0004 /* b3: ID-pin monitor */
-#define LNST 0x0003 /* b1-0: D+, D- line status */
-#define SE1 0x0003 /* SE1 */
-#define FS_KSTS 0x0002 /* Full-Speed K State */
-#define FS_JSTS 0x0001 /* Full-Speed J State */
-#define LS_JSTS 0x0002 /* Low-Speed J State */
-#define LS_KSTS 0x0001 /* Low-Speed K State */
-#define SE0 0x0000 /* SE0 */
-
-/* Device State Control Register */
-#define EXTLP0 0x0400 /* b10: External port */
-#define VBOUT 0x0200 /* b9: VBUS output */
-#define WKUP 0x0100 /* b8: Remote wakeup */
-#define RWUPE 0x0080 /* b7: Remote wakeup sense */
-#define USBRST 0x0040 /* b6: USB reset enable */
-#define RESUME 0x0020 /* b5: Resume enable */
-#define UACT 0x0010 /* b4: USB bus enable */
-#define RHST 0x0007 /* b1-0: Reset handshake status */
-#define HSPROC 0x0004 /* HS handshake is processing */
-#define HSMODE 0x0003 /* Hi-Speed mode */
-#define FSMODE 0x0002 /* Full-Speed mode */
-#define LSMODE 0x0001 /* Low-Speed mode */
-#define UNDECID 0x0000 /* Undecided */
-
-/* Test Mode Register */
-#define UTST 0x000F /* b3-0: Test select */
-#define H_TST_PACKET 0x000C /* HOST TEST Packet */
-#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
-#define H_TST_K 0x000A /* HOST TEST K */
-#define H_TST_J 0x0009 /* HOST TEST J */
-#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
-#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
-#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
-#define P_TST_K 0x0002 /* PERI TEST K */
-#define P_TST_J 0x0001 /* PERI TEST J */
-#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
-
-/* Data Pin Configuration Register */
-#define LDRV 0x8000 /* b15: Drive Current Adjust */
-#define VIF1 0x0000 /* VIF = 1.8V */
-#define VIF3 0x8000 /* VIF = 3.3V */
-#define INTA 0x0001 /* b1: USB INT-pin active */
-
-/* DMAx Pin Configuration Register */
-#define DREQA 0x4000 /* b14: Dreq active select */
-#define BURST 0x2000 /* b13: Burst mode */
-#define DACKA 0x0400 /* b10: Dack active select */
-#define DFORM 0x0380 /* b9-7: DMA mode select */
-#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
-#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
-#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
-#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
-#define DENDA 0x0040 /* b6: Dend active select */
-#define PKTM 0x0020 /* b5: Packet mode */
-#define DENDE 0x0010 /* b4: Dend enable */
-#define OBUS 0x0004 /* b2: OUTbus mode */
-
-/* CFIFO/DxFIFO Port Select Register */
-#define RCNT 0x8000 /* b15: Read count mode */
-#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 */
-#define BYTE_LITTLE 0x0000 /* little dendian */
-#define BYTE_BIG 0x0100 /* big endifan */
-#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
-#define CURPIPE 0x000F /* b2-0: PIPE select */
-
-/* CFIFO/DxFIFO Port Control Register */
-#define BVAL 0x8000 /* b15: Buffer valid flag */
-#define BCLR 0x4000 /* b14: Buffer clear */
-#define FRDY 0x2000 /* b13: FIFO ready */
-#define DTLN 0x0FFF /* b11-0: FIFO received data length */
-
-/* Interrupt Enable Register 0 */
-#define VBSE 0x8000 /* b15: VBUS interrupt */
-#define RSME 0x4000 /* b14: Resume interrupt */
-#define SOFE 0x2000 /* b13: Frame update interrupt */
-#define DVSE 0x1000 /* b12: Device state transition interrupt */
-#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
-
-/* Interrupt Enable Register 1 */
-#define OVRCRE 0x8000 /* b15: Over-current interrupt */
-#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
-#define DTCHE 0x1000 /* b12: Detach sense interrupt */
-#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
-#define EOFERRE 0x0040 /* b6: EOF error interrupt */
-#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
-#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
-
-/* BRDY Interrupt Enable/Status Register */
-#define BRDY9 0x0200 /* b9: PIPE9 */
-#define BRDY8 0x0100 /* b8: PIPE8 */
-#define BRDY7 0x0080 /* b7: PIPE7 */
-#define BRDY6 0x0040 /* b6: PIPE6 */
-#define BRDY5 0x0020 /* b5: PIPE5 */
-#define BRDY4 0x0010 /* b4: PIPE4 */
-#define BRDY3 0x0008 /* b3: PIPE3 */
-#define BRDY2 0x0004 /* b2: PIPE2 */
-#define BRDY1 0x0002 /* b1: PIPE1 */
-#define BRDY0 0x0001 /* b1: PIPE0 */
-
-/* NRDY Interrupt Enable/Status Register */
-#define NRDY9 0x0200 /* b9: PIPE9 */
-#define NRDY8 0x0100 /* b8: PIPE8 */
-#define NRDY7 0x0080 /* b7: PIPE7 */
-#define NRDY6 0x0040 /* b6: PIPE6 */
-#define NRDY5 0x0020 /* b5: PIPE5 */
-#define NRDY4 0x0010 /* b4: PIPE4 */
-#define NRDY3 0x0008 /* b3: PIPE3 */
-#define NRDY2 0x0004 /* b2: PIPE2 */
-#define NRDY1 0x0002 /* b1: PIPE1 */
-#define NRDY0 0x0001 /* b1: PIPE0 */
-
-/* BEMP Interrupt Enable/Status Register */
-#define BEMP9 0x0200 /* b9: PIPE9 */
-#define BEMP8 0x0100 /* b8: PIPE8 */
-#define BEMP7 0x0080 /* b7: PIPE7 */
-#define BEMP6 0x0040 /* b6: PIPE6 */
-#define BEMP5 0x0020 /* b5: PIPE5 */
-#define BEMP4 0x0010 /* b4: PIPE4 */
-#define BEMP3 0x0008 /* b3: PIPE3 */
-#define BEMP2 0x0004 /* b2: PIPE2 */
-#define BEMP1 0x0002 /* b1: PIPE1 */
-#define BEMP0 0x0001 /* b0: PIPE0 */
-
-/* SOF Pin Configuration Register */
-#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
-#define BRDYM 0x0040 /* b6: BRDY clear timing */
-#define INTL 0x0020 /* b5: Interrupt sense select */
-#define EDGESTS 0x0010 /* b4: */
-#define SOFMODE 0x000C /* b3-2: SOF pin select */
-#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
-#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
-#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
-
-/* Interrupt Status Register 0 */
-#define VBINT 0x8000 /* b15: VBUS interrupt */
-#define RESM 0x4000 /* b14: Resume interrupt */
-#define SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define DVST 0x1000 /* b12: Device state transition interrupt */
-#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define VBSTS 0x0080 /* b7: VBUS input port */
-#define DVSQ 0x0070 /* b6-4: Device state */
-#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
-#define DS_SPD_ADDR 0x0060 /* Suspend Address */
-#define DS_SPD_DFLT 0x0050 /* Suspend Default */
-#define DS_SPD_POWR 0x0040 /* Suspend Powered */
-#define DS_SUSP 0x0040 /* Suspend */
-#define DS_CNFG 0x0030 /* Configured */
-#define DS_ADDS 0x0020 /* Address */
-#define DS_DFLT 0x0010 /* Default */
-#define DS_POWR 0x0000 /* Powered */
-#define DVSQS 0x0030 /* b5-4: Device state */
-#define VALID 0x0008 /* b3: Setup packet detected flag */
-#define CTSQ 0x0007 /* b2-0: Control transfer stage */
-#define CS_SQER 0x0006 /* Sequence error */
-#define CS_WRND 0x0005 /* Control write nodata status stage */
-#define CS_WRSS 0x0004 /* Control write status stage */
-#define CS_WRDS 0x0003 /* Control write data stage */
-#define CS_RDSS 0x0002 /* Control read status stage */
-#define CS_RDDS 0x0001 /* Control read data stage */
-#define CS_IDST 0x0000 /* Idle or setup stage */
-
-/* Interrupt Status Register 1 */
-#define OVRCR 0x8000 /* b15: Over-current interrupt */
-#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
-#define DTCH 0x1000 /* b12: Detach sense interrupt */
-#define ATTCH 0x0800 /* b11: Attach sense interrupt */
-#define EOFERR 0x0040 /* b6: EOF-error interrupt */
-#define SIGN 0x0020 /* b5: Setup ignore interrupt */
-#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
-
-/* Frame Number Register */
-#define OVRN 0x8000 /* b15: Overrun error */
-#define CRCE 0x4000 /* b14: Received data error */
-#define FRNM 0x07FF /* b10-0: Frame number */
-
-/* Micro Frame Number Register */
-#define UFRNM 0x0007 /* b2-0: Micro frame number */
-
-/* Default Control Pipe Maxpacket Size Register */
-/* Pipe Maxpacket Size Register */
-#define DEVSEL 0xF000 /* b15-14: Device address select */
-#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
-
-/* Default Control Pipe Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define SUREQ 0x4000 /* b14: Send USB request */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define SUREQCLR 0x0800 /* b11: stop setup request */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PINGE 0x0010 /* b4: ping enable */
-#define CCPL 0x0004 /* b2: Enable control transfer complete */
-#define PID 0x0003 /* b1-0: Response PID */
-#define PID_STALL11 0x0003 /* STALL */
-#define PID_STALL 0x0002 /* STALL */
-#define PID_BUF 0x0001 /* BUF */
-#define PID_NAK 0x0000 /* NAK */
-
-/* Pipe Window Select Register */
-#define PIPENM 0x0007 /* b2-0: Pipe select */
-
-/* Pipe Configuration Register */
-#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
-#define R8A66597_ISO 0xC000 /* Isochronous */
-#define R8A66597_INT 0x8000 /* Interrupt */
-#define R8A66597_BULK 0x4000 /* Bulk */
-#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
-#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
-#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
-#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
-#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
-
-/* Pipe Buffer Configuration Register */
-#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
-#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
-#define PIPE0BUF 256
-#define PIPExBUF 64
-
-/* Pipe Maxpacket Size Register */
-#define MXPS 0x07FF /* b10-0: Maxpacket size */
-
-/* Pipe Cycle Configuration Register */
-#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define IITV 0x0007 /* b2-0: Isochronous interval */
-
-/* Pipex Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define ATREPM 0x0400 /* b10: Auto repeat mode */
-#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PID 0x0003 /* b1-0: Response PID */
-
-/* PIPExTRE */
-#define TRENB 0x0200 /* b9: Transaction counter enable */
-#define TRCLR 0x0100 /* b8: Transaction counter clear */
-
-/* PIPExTRN */
-#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
-
-/* DEVADDx */
-#define UPPHUB 0x7800
-#define HUBPORT 0x0700
-#define USBSPD 0x00C0
-#define RTPORT 0x0001
-
-#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
-#endif
-#define R8A66597_MAX_SAMPLING 5
-#define R8A66597_RH_POLL_TIME 10
-
-#define BULK_IN_PIPENUM 3
-#define BULK_IN_BUFNUM 8
-
-#define BULK_OUT_PIPENUM 4
-#define BULK_OUT_BUFNUM 40
-
-#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
-#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
-#define make_devsel(addr) (addr << 12)
-
-struct r8a66597 {
- unsigned long reg;
- unsigned short pipe_config; /* bit field */
- unsigned short port_status;
- unsigned short port_change;
- u16 speed; /* HSMODE or FSMODE or LSMODE */
- unsigned char rh_devnum;
-};
-
-static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
-{
- return inw(r8a66597->reg + offset);
-}
-
-static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
- unsigned long offset, void *buf,
- int len)
-{
- int i;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
- unsigned long fifoaddr = r8a66597->reg + offset;
- unsigned long count;
- unsigned long *p = buf;
-
- count = len / 4;
- for (i = 0; i < count; i++)
- inl(p[i], r8a66597->reg + offset);
-
- if (len & 0x00000003) {
- unsigned long tmp = inl(fifoaddr);
- memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
- }
-#else
- unsigned short *p = buf;
-
- len = (len + 1) / 2;
- for (i = 0; i < len; i++)
- p[i] = inw(r8a66597->reg + offset);
-#endif
-}
-
-static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
- unsigned long offset)
-{
- outw(val, r8a66597->reg + offset);
-}
-
-static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
- unsigned long offset, void *buf,
- int len)
-{
- int i;
- unsigned long fifoaddr = r8a66597->reg + offset;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
- unsigned long count;
- unsigned char *pb;
- unsigned long *p = buf;
-
- count = len / 4;
- for (i = 0; i < count; i++)
- outl(p[i], fifoaddr);
-
- 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;
- unsigned short *p = buf;
-
- len = len / 2;
- for (i = 0; i < len; i++)
- outw(p[i], fifoaddr);
-
- if (odd) {
- unsigned char *pb = (unsigned char *)(buf + len);
- outb(*pb, fifoaddr);
- }
-#endif
-}
-
-static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
- u16 val, u16 pat, unsigned long offset)
-{
- u16 tmp;
- tmp = r8a66597_read(r8a66597, offset);
- tmp = tmp & (~pat);
- tmp = tmp | val;
- r8a66597_write(r8a66597, tmp, offset);
-}
-
-#define r8a66597_bclr(r8a66597, val, offset) \
- r8a66597_mdfy(r8a66597, 0, val, offset)
-#define r8a66597_bset(r8a66597, val, offset) \
- r8a66597_mdfy(r8a66597, val, 0, offset)
-
-static inline unsigned long get_syscfg_reg(int port)
-{
- return port == 0 ? SYSCFG0 : SYSCFG1;
-}
-
-static inline unsigned long get_syssts_reg(int port)
-{
- return port == 0 ? SYSSTS0 : SYSSTS1;
-}
-
-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;
-}
-
-static inline unsigned long get_intsts_reg(int port)
-{
- return port == 0 ? INTSTS1 : INTSTS2;
-}
-
-static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
-{
- unsigned long dvstctr_reg = get_dvstctr_reg(port);
-
- return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
-}
-
-static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
- int power)
-{
- unsigned long dvstctr_reg = get_dvstctr_reg(port);
-
- if (power)
- r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
- else
- r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
-}
-
-#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
-#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
-#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
-#define get_devadd_addr(address) (DEVADD0 + address * 2)
-
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h, based on usb_ohci.h) */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS 0x00000001 /* current connect status */
-#define RH_PS_PES 0x00000002 /* port enable status*/
-#define RH_PS_PSS 0x00000004 /* port suspend status */
-#define RH_PS_POCI 0x00000008 /* port over current indicator */
-#define RH_PS_PRS 0x00000010 /* port reset status */
-#define RH_PS_PPS 0x00000100 /* port power status */
-#define RH_PS_LSDA 0x00000200 /* low speed device attached */
-#define RH_PS_CSC 0x00010000 /* connect status change */
-#define RH_PS_PESC 0x00020000 /* port enable status change */
-#define RH_PS_PSSC 0x00040000 /* port suspend status change */
-#define RH_PS_OCIC 0x00080000 /* over current indicator change */
-#define RH_PS_PRSC 0x00100000 /* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS 0x00000001 /* local power status */
-#define RH_HS_OCI 0x00000002 /* over current indicator */
-#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
-#define RH_HS_LPSC 0x00010000 /* local power status change */
-#define RH_HS_OCIC 0x00020000 /* over current indicator change */
-#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR 0x0000ffff /* device removable flags */
-#define RH_B_PPCM 0xffff0000 /* port power control mask */
-
-/* roothub.a masks */
-#define RH_A_NDP (0xff << 0) /* number of downstream ports */
-#define RH_A_PSM (1 << 8) /* power switching mode */
-#define RH_A_NPS (1 << 9) /* no power switching */
-#define RH_A_DT (1 << 10) /* device type (mbz) */
-#define RH_A_OCPM (1 << 11) /* over current protection mode */
-#define RH_A_NOCP (1 << 12) /* no over current protection */
-#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
-
-#endif /* __R8A66597_H__ */
+++ /dev/null
-/*
- * URB OHCI HCD (Host Controller Driver) initialization for USB on the S3C64XX.
- *
- * Copyright (C) 2008,
- * Guennadi Liakhovetski, DENX Software Engineering <lg@denx.de>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-
-#include <common.h>
-#include <s3c6400.h>
-
-int usb_cpu_init(void)
-{
- OTHERS_REG |= 0x10000;
- return 0;
-}
-
-int usb_cpu_stop(void)
-{
- OTHERS_REG &= ~0x10000;
- return 0;
-}
-
-void usb_cpu_init_fail(void)
-{
- OTHERS_REG &= ~0x10000;
-}
+++ /dev/null
-#ifndef __UBOOT_SL811_H
-#define __UBOOT_SL811_H
-
-#undef SL811_DEBUG
-
-#ifdef SL811_DEBUG
- #define PDEBUG(level, fmt, args...) \
- if (debug >= (level)) printf("[%s:%d] " fmt, \
- __PRETTY_FUNCTION__, __LINE__ , ## args)
-#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* Sl811 host control register */
-#define SL811_CTRL_A 0x00
-#define SL811_ADDR_A 0x01
-#define SL811_LEN_A 0x02
-#define SL811_STS_A 0x03 /* read */
-#define SL811_PIDEP_A 0x03 /* write */
-#define SL811_CNT_A 0x04 /* read */
-#define SL811_DEV_A 0x04 /* write */
-#define SL811_CTRL1 0x05
-#define SL811_INTR 0x06
-#define SL811_CTRL_B 0x08
-#define SL811_ADDR_B 0x09
-#define SL811_LEN_B 0x0A
-#define SL811_STS_B 0x0B /* read */
-#define SL811_PIDEP_B 0x0B /* write */
-#define SL811_CNT_B 0x0C /* read */
-#define SL811_DEV_B 0x0C /* write */
-#define SL811_INTRSTS 0x0D /* write clears bitwise */
-#define SL811_HWREV 0x0E /* read */
-#define SL811_SOFLOW 0x0E /* write */
-#define SL811_SOFCNTDIV 0x0F /* read */
-#define SL811_CTRL2 0x0F /* write */
-
-/* USB control register bits (addr 0x00 and addr 0x08) */
-#define SL811_USB_CTRL_ARM 0x01
-#define SL811_USB_CTRL_ENABLE 0x02
-#define SL811_USB_CTRL_DIR_OUT 0x04
-#define SL811_USB_CTRL_ISO 0x10
-#define SL811_USB_CTRL_SOF 0x20
-#define SL811_USB_CTRL_TOGGLE_1 0x40
-#define SL811_USB_CTRL_PREAMBLE 0x80
-
-/* USB status register bits (addr 0x03 and addr 0x0B) */
-#define SL811_USB_STS_ACK 0x01
-#define SL811_USB_STS_ERROR 0x02
-#define SL811_USB_STS_TIMEOUT 0x04
-#define SL811_USB_STS_TOGGLE_1 0x08
-#define SL811_USB_STS_SETUP 0x10
-#define SL811_USB_STS_OVERFLOW 0x20
-#define SL811_USB_STS_NAK 0x40
-#define SL811_USB_STS_STALL 0x80
-
-/* Control register 1 bits (addr 0x05) */
-#define SL811_CTRL1_SOF 0x01
-#define SL811_CTRL1_RESET 0x08
-#define SL811_CTRL1_JKSTATE 0x10
-#define SL811_CTRL1_SPEED_LOW 0x20
-#define SL811_CTRL1_SUSPEND 0x40
-
-/* Interrut enable (addr 0x06) and interrupt status register bits (addr 0x0D) */
-#define SL811_INTR_DONE_A 0x01
-#define SL811_INTR_DONE_B 0x02
-#define SL811_INTR_SOF 0x10
-#define SL811_INTR_INSRMV 0x20
-#define SL811_INTR_DETECT 0x40
-#define SL811_INTR_NOTPRESENT 0x40
-#define SL811_INTR_SPEED_FULL 0x80 /* only in status reg */
-
-/* HW rev and SOF lo register bits (addr 0x0E) */
-#define SL811_HWR_HWREV 0xF0
-
-/* SOF counter and control reg 2 (addr 0x0F) */
-#define SL811_CTL2_SOFHI 0x3F
-#define SL811_CTL2_DSWAP 0x40
-#define SL811_CTL2_HOST 0x80
-
-/* Set up for 1-ms SOF time. */
-#define SL811_12M_LOW 0xE0
-#define SL811_12M_HI 0x2E
-
-#define SL811_DATA_START 0x10
-#define SL811_DATA_LIMIT 240
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-
-
-#define PIDEP(pid, ep) (((pid) & 0x0f) << 4 | (ep))
-
-#endif /* __UBOOT_SL811_H */
+++ /dev/null
-/*
- * (C) Copyright 2004
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * This code is based on linux driver for sl811hs chip, source at
- * drivers/usb/host/sl811.c:
- *
- * SL811 Host Controller Interface driver for USB.
- *
- * Copyright (c) 2003/06, Courage Co., Ltd.
- *
- * Based on:
- * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
- * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
- * Adam Richter, Gregory P. Smith;
- * 2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
- * 3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <mpc8xx.h>
-#include <usb.h>
-#include "sl811.h"
-
-#include "../../board/kup/common/kup.h"
-
-#ifdef __PPC__
-# define EIEIO __asm__ volatile ("eieio")
-#else
-# define EIEIO /* nothing */
-#endif
-
-#define SL811_ADR (0x50000000)
-#define SL811_DAT (0x50000001)
-
-#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
-
-#ifdef SL811_DEBUG
-static int debug = 9;
-#endif
-
-static int root_hub_devnum = 0;
-static struct usb_port_status rh_status = { 0 };/* root hub port status */
-
-static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
- void *data, int buf_len, struct devrequest *cmd);
-
-static void sl811_write (__u8 index, __u8 data)
-{
- *(volatile unsigned char *) (SL811_ADR) = index;
- EIEIO;
- *(volatile unsigned char *) (SL811_DAT) = data;
- EIEIO;
-}
-
-static __u8 sl811_read (__u8 index)
-{
- __u8 data;
-
- *(volatile unsigned char *) (SL811_ADR) = index;
- EIEIO;
- data = *(volatile unsigned char *) (SL811_DAT);
- EIEIO;
- return (data);
-}
-
-/*
- * Read consecutive bytes of data from the SL811H/SL11H buffer
- */
-static void inline sl811_read_buf(__u8 offset, __u8 *buf, __u8 size)
-{
- *(volatile unsigned char *) (SL811_ADR) = offset;
- EIEIO;
- while (size--) {
- *buf++ = *(volatile unsigned char *) (SL811_DAT);
- EIEIO;
- }
-}
-
-/*
- * Write consecutive bytes of data to the SL811H/SL11H buffer
- */
-static void inline sl811_write_buf(__u8 offset, __u8 *buf, __u8 size)
-{
- *(volatile unsigned char *) (SL811_ADR) = offset;
- EIEIO;
- while (size--) {
- *(volatile unsigned char *) (SL811_DAT) = *buf++;
- EIEIO;
- }
-}
-
-int usb_init_kup4x (void)
-{
- volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
- volatile memctl8xx_t *memctl = &immap->im_memctl;
- int i;
- unsigned char tmp;
-
- memctl = &immap->im_memctl;
- memctl->memc_or7 = 0xFFFF8726;
- memctl->memc_br7 = 0x50000401; /* start at 0x50000000 */
- /* BP 14 low = USB ON */
- immap->im_cpm.cp_pbdat &= ~(BP_USB_VCC);
- /* PB 14 nomal port */
- immap->im_cpm.cp_pbpar &= ~(BP_USB_VCC);
- /* output */
- immap->im_cpm.cp_pbdir |= (BP_USB_VCC);
-
- puts ("USB: ");
-
- for (i = 0x10; i < 0xff; i++) {
- sl811_write(i, i);
- tmp = (sl811_read(i));
- if (tmp != i) {
- printf ("SL811 compare error index=0x%02x read=0x%02x\n", i, tmp);
- return (-1);
- }
- }
- printf ("SL811 ready\n");
- return (0);
-}
-
-/*
- * This function resets SL811HS controller and detects the speed of
- * the connecting device
- *
- * Return: 0 = no device attached; 1 = USB device attached
- */
-static int sl811_hc_reset(void)
-{
- int status ;
-
- sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
- sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
-
- mdelay(20);
-
- /* Disable hardware SOF generation, clear all irq status. */
- sl811_write(SL811_CTRL1, 0);
- mdelay(2);
- sl811_write(SL811_INTRSTS, 0xff);
- status = sl811_read(SL811_INTRSTS);
-
- if (status & SL811_INTR_NOTPRESENT) {
- /* Device is not present */
- PDEBUG(0, "Device not present\n");
- rh_status.wPortStatus &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE);
- rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
- sl811_write(SL811_INTR, SL811_INTR_INSRMV);
- return 0;
- }
-
- /* Send SOF to address 0, endpoint 0. */
- sl811_write(SL811_LEN_B, 0);
- sl811_write(SL811_PIDEP_B, PIDEP(USB_PID_SOF, 0));
- sl811_write(SL811_DEV_B, 0x00);
- sl811_write(SL811_SOFLOW, SL811_12M_LOW);
-
- if (status & SL811_INTR_SPEED_FULL) {
- /* full speed device connect directly to root hub */
- PDEBUG (0, "Full speed Device attached\n");
-
- sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
- mdelay(20);
- sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_12M_HI);
- sl811_write(SL811_CTRL1, SL811_CTRL1_SOF);
-
- /* start the SOF or EOP */
- sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
- rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION;
- rh_status.wPortStatus &= ~USB_PORT_STAT_LOW_SPEED;
- mdelay(2);
- sl811_write(SL811_INTRSTS, 0xff);
- } else {
- /* slow speed device connect directly to root-hub */
- PDEBUG(0, "Low speed Device attached\n");
-
- sl811_write(SL811_CTRL1, SL811_CTRL1_RESET);
- mdelay(20);
- sl811_write(SL811_CTRL2, SL811_CTL2_HOST | SL811_CTL2_DSWAP | SL811_12M_HI);
- sl811_write(SL811_CTRL1, SL811_CTRL1_SPEED_LOW | SL811_CTRL1_SOF);
-
- /* start the SOF or EOP */
- sl811_write(SL811_CTRL_B, SL811_USB_CTRL_ARM);
- rh_status.wPortStatus |= USB_PORT_STAT_CONNECTION | USB_PORT_STAT_LOW_SPEED;
- mdelay(2);
- sl811_write(SL811_INTRSTS, 0xff);
- }
-
- rh_status.wPortChange |= USB_PORT_STAT_C_CONNECTION;
- sl811_write(SL811_INTR, /*SL811_INTR_INSRMV*/SL811_INTR_DONE_A);
-
- return 1;
-}
-
-int usb_lowlevel_init(void)
-{
- root_hub_devnum = 0;
- sl811_hc_reset();
- return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
- sl811_hc_reset();
- return 0;
-}
-
-static int calc_needed_buswidth(int bytes, int need_preamble)
-{
- return !need_preamble ? bytes * 8 + 256 : 8 * 8 * bytes + 2048;
-}
-
-static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
-{
- __u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
- __u16 status = 0;
- int err = 0, time_start = get_timer(0);
- int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
- usb_pipeslow(pipe);
-
- if (len > 239)
- return -1;
-
- if (usb_pipeout(pipe))
- ctrl |= SL811_USB_CTRL_DIR_OUT;
- if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
- ctrl |= SL811_USB_CTRL_TOGGLE_1;
- if (need_preamble)
- ctrl |= SL811_USB_CTRL_PREAMBLE;
-
- sl811_write(SL811_INTRSTS, 0xff);
-
- while (err < 3) {
- sl811_write(SL811_ADDR_A, 0x10);
- sl811_write(SL811_LEN_A, len);
- if (usb_pipeout(pipe) && len)
- sl811_write_buf(0x10, buffer, len);
-
- if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
- sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
- ctrl |= SL811_USB_CTRL_SOF;
- else
- ctrl &= ~SL811_USB_CTRL_SOF;
-
- sl811_write(SL811_CTRL_A, ctrl);
- while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
- if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
- printf("USB transmit timed out\n");
- return -USB_ST_CRC_ERR;
- }
- }
-
- sl811_write(SL811_INTRSTS, 0xff);
- status = sl811_read(SL811_STS_A);
-
- if (status & SL811_USB_STS_ACK) {
- int remainder = sl811_read(SL811_CNT_A);
- if (remainder) {
- PDEBUG(0, "usb transfer remainder = %d\n", remainder);
- len -= remainder;
- }
- if (usb_pipein(pipe) && len)
- sl811_read_buf(0x10, buffer, len);
- return len;
- }
-
- if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
- continue;
-
- PDEBUG(0, "usb transfer error %#x\n", (int)status);
- err++;
- }
-
- err = 0;
-
- if (status & SL811_USB_STS_ERROR)
- err |= USB_ST_BUF_ERR;
- if (status & SL811_USB_STS_TIMEOUT)
- err |= USB_ST_CRC_ERR;
- if (status & SL811_USB_STS_STALL)
- err |= USB_ST_STALLED;
-
- return -err;
-}
-
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len)
-{
- int dir_out = usb_pipeout(pipe);
- int ep = usb_pipeendpoint(pipe);
- int max = usb_maxpacket(dev, pipe);
- int done = 0;
-
- PDEBUG(7, "dev = %ld pipe = %ld buf = %p size = %d dir_out = %d\n",
- usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
-
- dev->status = 0;
-
- sl811_write(SL811_DEV_A, usb_pipedevice(pipe));
- sl811_write(SL811_PIDEP_A, PIDEP(!dir_out ? USB_PID_IN : USB_PID_OUT, ep));
- while (done < len) {
- int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
- max > len - done ? len - done : max);
- if (res < 0) {
- dev->status = -res;
- return res;
- }
-
- if (!dir_out && res < max) /* short packet */
- break;
-
- done += res;
- usb_dotoggle(dev, ep, dir_out);
- }
-
- dev->act_len = done;
-
- return 0;
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len,struct devrequest *setup)
-{
- int done = 0;
- int devnum = usb_pipedevice(pipe);
- int ep = usb_pipeendpoint(pipe);
-
- dev->status = 0;
-
- if (devnum == root_hub_devnum)
- return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);
-
- PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
- devnum, ep, buffer, len, (int)setup->requesttype,
- (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);
-
- sl811_write(SL811_DEV_A, devnum);
- sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
- /* setup phase */
- usb_settoggle(dev, ep, 1, 0);
- if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
- (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
- int dir_in = usb_pipein(pipe);
- int max = usb_maxpacket(dev, pipe);
-
- /* data phase */
- sl811_write(SL811_PIDEP_A,
- PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
- usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
- while (done < len) {
- int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
- max > len - done ? len - done : max);
- if (res < 0) {
- PDEBUG(0, "status data failed!\n");
- dev->status = -res;
- return 0;
- }
- done += res;
- usb_dotoggle(dev, ep, usb_pipeout(pipe));
- if (dir_in && res < max) /* short packet */
- break;
- }
-
- /* status phase */
- sl811_write(SL811_PIDEP_A,
- PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
- usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
- if (sl811_send_packet(dev,
- !dir_in ? usb_rcvctrlpipe(dev, ep) :
- usb_sndctrlpipe(dev, ep),
- 0, 0) < 0) {
- PDEBUG(0, "status phase failed!\n");
- dev->status = -1;
- }
- } else {
- PDEBUG(0, "setup phase failed!\n");
- dev->status = -1;
- }
-
- dev->act_len = done;
-
- return done;
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int len, int interval)
-{
- PDEBUG(0, "dev = %p pipe = %#lx buf = %p size = %d int = %d\n", dev, pipe,
- buffer, len, interval);
- return -1;
-}
-
-/*
- * SL811 Virtual Root Hub
- */
-
-/* Device descriptor */
-static __u8 sl811_rh_dev_des[] =
-{
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x02, /* __u8 iProduct; */
- 0x01, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 sl811_rh_config_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 0x01, /* __u8 bConfigurationValue; */
- 0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
- 4..0: resvd */
- 0x00, /* __u8 MaxPower; */
-
- /* interface */
- 0x09, /* __u8 if_bLength; */
- 0x04, /* __u8 if_bDescriptorType; Interface */
- 0x00, /* __u8 if_bInterfaceNumber; */
- 0x00, /* __u8 if_bAlternateSetting; */
- 0x01, /* __u8 if_bNumEndpoints; */
- 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* __u8 if_bInterfaceSubClass; */
- 0x00, /* __u8 if_bInterfaceProtocol; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x08, /* __u16 ep_wMaxPacketSize; */
- 0x00,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-/* root hub class descriptor*/
-static __u8 sl811_rh_hub_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x29, /* __u8 bDescriptorType; Hub-descriptor */
- 0x01, /* __u8 bNbrPorts; */
- 0x00, /* __u16 wHubCharacteristics; */
- 0x00,
- 0x50, /* __u8 bPwrOn2pwrGood; 2ms */
- 0x00, /* __u8 bHubContrCurrent; 0 mA */
- 0xfc, /* __u8 DeviceRemovable; *** 7 Ports max *** */
- 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/*
- * helper routine for returning string descriptors in UTF-16LE
- * input can actually be ISO-8859-1; ASCII is its 7-bit subset
- */
-static int ascii2utf (char *s, u8 *utf, int utfmax)
-{
- int retval;
-
- for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
- *utf++ = *s++;
- *utf++ = 0;
- }
- return retval;
-}
-
-/*
- * root_hub_string is used by each host controller's root hub code,
- * so that they're identified consistently throughout the system.
- */
-static int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
-{
- char buf [30];
-
- /* assert (len > (2 * (sizeof (buf) + 1)));
- assert (strlen (type) <= 8);*/
-
- /* language ids */
- if (id == 0) {
- *data++ = 4; *data++ = 3; /* 4 bytes data */
- *data++ = 0; *data++ = 0; /* some language id */
- return 4;
-
- /* serial number */
- } else if (id == 1) {
- sprintf (buf, "%#x", serial);
-
- /* product description */
- } else if (id == 2) {
- sprintf (buf, "USB %s Root Hub", type);
-
- /* id 3 == vendor description */
-
- /* unsupported IDs --> "stall" */
- } else
- return 0;
-
- ascii2utf (buf, data + 2, len - 2);
- data [0] = 2 + strlen(buf) * 2;
- data [1] = 3;
- return data [0];
-}
-
-/* helper macro */
-#define OK(x) len = (x); break
-
-/*
- * This function handles all USB request to the the virtual root hub
- */
-static int sl811_rh_submit_urb(struct usb_device *usb_dev, unsigned long pipe,
- void *data, int buf_len, struct devrequest *cmd)
-{
- __u8 data_buf[16];
- __u8 *bufp = data_buf;
- int len = 0;
- int status = 0;
-
- __u16 bmRType_bReq;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
-
- if (usb_pipeint(pipe)) {
- PDEBUG(0, "interrupt transfer unimplemented!\n");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = le16_to_cpu (cmd->value);
- wIndex = le16_to_cpu (cmd->index);
- wLength = le16_to_cpu (cmd->length);
-
- PDEBUG(5, "submit rh urb, req = %d(%x) val = %#x index = %#x len=%d\n",
- bmRType_bReq, bmRType_bReq, wValue, wIndex, wLength);
-
- /* Request Destination:
- without flags: Device,
- USB_RECIP_INTERFACE: interface,
- USB_RECIP_ENDPOINT: endpoint,
- USB_TYPE_CLASS means HUB here,
- USB_RECIP_OTHER | USB_TYPE_CLASS almost ever means HUB_PORT here
- */
- switch (bmRType_bReq) {
- case RH_GET_STATUS:
- *(__u16 *)bufp = cpu_to_le16(1);
- OK(2);
-
- case RH_GET_STATUS | USB_RECIP_INTERFACE:
- *(__u16 *)bufp = cpu_to_le16(0);
- OK(2);
-
- case RH_GET_STATUS | USB_RECIP_ENDPOINT:
- *(__u16 *)bufp = cpu_to_le16(0);
- OK(2);
-
- case RH_GET_STATUS | USB_TYPE_CLASS:
- *(__u32 *)bufp = cpu_to_le32(0);
- OK(4);
-
- case RH_GET_STATUS | USB_RECIP_OTHER | USB_TYPE_CLASS:
- *(__u32 *)bufp = cpu_to_le32(rh_status.wPortChange<<16 | rh_status.wPortStatus);
- OK(4);
-
- case RH_CLEAR_FEATURE | USB_RECIP_ENDPOINT:
- switch (wValue) {
- case 1:
- OK(0);
- }
- break;
-
- case RH_CLEAR_FEATURE | USB_TYPE_CLASS:
- switch (wValue) {
- case C_HUB_LOCAL_POWER:
- OK(0);
-
- case C_HUB_OVER_CURRENT:
- OK(0);
- }
- break;
-
- case RH_CLEAR_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- rh_status.wPortStatus &= ~USB_PORT_STAT_ENABLE;
- OK(0);
-
- case USB_PORT_FEAT_SUSPEND:
- rh_status.wPortStatus &= ~USB_PORT_STAT_SUSPEND;
- OK(0);
-
- case USB_PORT_FEAT_POWER:
- rh_status.wPortStatus &= ~USB_PORT_STAT_POWER;
- OK(0);
-
- case USB_PORT_FEAT_C_CONNECTION:
- rh_status.wPortChange &= ~USB_PORT_STAT_C_CONNECTION;
- OK(0);
-
- case USB_PORT_FEAT_C_ENABLE:
- rh_status.wPortChange &= ~USB_PORT_STAT_C_ENABLE;
- OK(0);
-
- case USB_PORT_FEAT_C_SUSPEND:
- rh_status.wPortChange &= ~USB_PORT_STAT_C_SUSPEND;
- OK(0);
-
- case USB_PORT_FEAT_C_OVER_CURRENT:
- rh_status.wPortChange &= ~USB_PORT_STAT_C_OVERCURRENT;
- OK(0);
-
- case USB_PORT_FEAT_C_RESET:
- rh_status.wPortChange &= ~USB_PORT_STAT_C_RESET;
- OK(0);
- }
- break;
-
- case RH_SET_FEATURE | USB_RECIP_OTHER | USB_TYPE_CLASS:
- switch (wValue) {
- case USB_PORT_FEAT_SUSPEND:
- rh_status.wPortStatus |= USB_PORT_STAT_SUSPEND;
- OK(0);
-
- case USB_PORT_FEAT_RESET:
- rh_status.wPortStatus |= USB_PORT_STAT_RESET;
- rh_status.wPortChange = 0;
- rh_status.wPortChange |= USB_PORT_STAT_C_RESET;
- rh_status.wPortStatus &= ~USB_PORT_STAT_RESET;
- rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
- OK(0);
-
- case USB_PORT_FEAT_POWER:
- rh_status.wPortStatus |= USB_PORT_STAT_POWER;
- OK(0);
-
- case USB_PORT_FEAT_ENABLE:
- rh_status.wPortStatus |= USB_PORT_STAT_ENABLE;
- OK(0);
- }
- break;
-
- case RH_SET_ADDRESS:
- root_hub_devnum = wValue;
- OK(0);
-
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case USB_DT_DEVICE:
- len = sizeof(sl811_rh_dev_des);
- bufp = sl811_rh_dev_des;
- OK(len);
-
- case USB_DT_CONFIG:
- len = sizeof(sl811_rh_config_des);
- bufp = sl811_rh_config_des;
- OK(len);
-
- case USB_DT_STRING:
- len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
- if (len > 0) {
- bufp = data;
- OK(len);
- }
-
- default:
- status = -32;
- }
- break;
-
- case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
- len = sizeof(sl811_rh_hub_des);
- bufp = sl811_rh_hub_des;
- OK(len);
-
- case RH_GET_CONFIGURATION:
- bufp[0] = 0x01;
- OK(1);
-
- case RH_SET_CONFIGURATION:
- OK(0);
-
- default:
- PDEBUG(1, "unsupported root hub command\n");
- status = -32;
- }
-
- len = min(len, buf_len);
- if (data != bufp)
- memcpy(data, bufp, len);
-
- PDEBUG(5, "len = %d, status = %d\n", len, status);
-
- usb_dev->status = status;
- usb_dev->act_len = len;
-
- return status == 0 ? len : status;
-}
+++ /dev/null
-/*-
- * Copyright (c) 2007-2008, Juniper Networks, Inc.
- * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef USB_EHCI_H
-#define USB_EHCI_H
-
-#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
-#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
-#endif
-
-/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
-#define DeviceRequest \
- ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
-
-#define DeviceOutRequest \
- ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
-
-#define InterfaceRequest \
- ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
-
-#define EndpointRequest \
- ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
-
-#define EndpointOutRequest \
- ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
-
-/*
- * Register Space.
- */
-struct ehci_hccr {
- uint32_t cr_capbase;
-#define HC_LENGTH(p) (((p) >> 0) & 0x00ff)
-#define HC_VERSION(p) (((p) >> 16) & 0xffff)
- uint32_t cr_hcsparams;
-#define HCS_PPC(p) ((p) & (1 << 4))
-#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */
-#define HCS_N_PORTS(p) (((p) >> 0) & 0xf)
- uint32_t cr_hccparams;
- uint8_t cr_hcsp_portrt[8];
-} __attribute__ ((packed));
-
-struct ehci_hcor {
- uint32_t or_usbcmd;
-#define CMD_PARK (1 << 11) /* enable "park" */
-#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */
-#define CMD_ASE (1 << 5) /* async schedule enable */
-#define CMD_LRESET (1 << 7) /* partial reset */
-#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */
-#define CMD_PSE (1 << 4) /* periodic schedule enable */
-#define CMD_RESET (1 << 1) /* reset HC not bus */
-#define CMD_RUN (1 << 0) /* start/stop HC */
- uint32_t or_usbsts;
-#define STD_ASS (1 << 15)
-#define STS_HALT (1 << 12)
- uint32_t or_usbintr;
- uint32_t or_frindex;
- uint32_t or_ctrldssegment;
- uint32_t or_periodiclistbase;
- uint32_t or_asynclistaddr;
- uint32_t _reserved_[9];
- uint32_t or_configflag;
-#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
- uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
- uint32_t or_systune;
-} __attribute__ ((packed));
-
-#define USBMODE 0x68 /* USB Device mode */
-#define USBMODE_SDIS (1 << 3) /* Stream disable */
-#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */
-#define USBMODE_CM_HC (3 << 0) /* host controller mode */
-#define USBMODE_CM_IDLE (0 << 0) /* idle state */
-
-/* Interface descriptor */
-struct usb_linux_interface_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType;
- unsigned char bInterfaceNumber;
- unsigned char bAlternateSetting;
- unsigned char bNumEndpoints;
- unsigned char bInterfaceClass;
- unsigned char bInterfaceSubClass;
- unsigned char bInterfaceProtocol;
- unsigned char iInterface;
-} __attribute__ ((packed));
-
-/* Configuration descriptor information.. */
-struct usb_linux_config_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType;
- unsigned short wTotalLength;
- unsigned char bNumInterfaces;
- unsigned char bConfigurationValue;
- unsigned char iConfiguration;
- unsigned char bmAttributes;
- unsigned char MaxPower;
-} __attribute__ ((packed));
-
-#if defined CONFIG_EHCI_DESC_BIG_ENDIAN
-#define ehci_readl(x) (*((volatile u32 *)(x)))
-#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b))
-#else
-#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x))))
-#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \
- cpu_to_le32(((volatile u32)b)))
-#endif
-
-#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN
-#define hc32_to_cpu(x) be32_to_cpu((x))
-#define cpu_to_hc32(x) cpu_to_be32((x))
-#else
-#define hc32_to_cpu(x) le32_to_cpu((x))
-#define cpu_to_hc32(x) cpu_to_le32((x))
-#endif
-
-#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */
-#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */
-#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */
-#define EHCI_PS_PO (1 << 13) /* RW port owner */
-#define EHCI_PS_PP (1 << 12) /* RW,RO port power */
-#define EHCI_PS_LS (3 << 10) /* RO line status */
-#define EHCI_PS_PR (1 << 8) /* RW port reset */
-#define EHCI_PS_SUSP (1 << 7) /* RW suspend */
-#define EHCI_PS_FPR (1 << 6) /* RW force port resume */
-#define EHCI_PS_OCC (1 << 5) /* RWC over current change */
-#define EHCI_PS_OCA (1 << 4) /* RO over current active */
-#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */
-#define EHCI_PS_PE (1 << 2) /* RW port enable */
-#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */
-#define EHCI_PS_CS (1 << 0) /* RO connect status */
-#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
-
-#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10))
-
-/*
- * Schedule Interface Space.
- *
- * IMPORTANT: Software must ensure that no interface data structure
- * reachable by the EHCI host controller spans a 4K page boundary!
- *
- * Periodic transfers (i.e. isochronous and interrupt transfers) are
- * not supported.
- */
-
-/* Queue Element Transfer Descriptor (qTD). */
-struct qTD {
- uint32_t qt_next;
-#define QT_NEXT_TERMINATE 1
- uint32_t qt_altnext;
- uint32_t qt_token;
- uint32_t qt_buffer[5];
-};
-
-/* Queue Head (QH). */
-struct QH {
- uint32_t qh_link;
-#define QH_LINK_TERMINATE 1
-#define QH_LINK_TYPE_ITD 0
-#define QH_LINK_TYPE_QH 2
-#define QH_LINK_TYPE_SITD 4
-#define QH_LINK_TYPE_FSTN 6
- uint32_t qh_endpt1;
- uint32_t qh_endpt2;
- uint32_t qh_curtd;
- struct qTD qh_overlay;
- /*
- * Add dummy fill value to make the size of this struct
- * aligned to 32 bytes
- */
- uint8_t fill[16];
-};
-
-/* Low level init functions */
-int ehci_hcd_init(void);
-int ehci_hcd_stop(void);
-
-#endif /* USB_EHCI_H */
+++ /dev/null
-/*-
- * Copyright (c) 2007-2008, Juniper Networks, Inc.
- * Copyright (c) 2008, Excito Elektronik i Skåne AB
- * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <common.h>
-#include <asm/byteorder.h>
-#include <usb.h>
-#include <asm/io.h>
-#include <malloc.h>
-#include "usb_ehci.h"
-
-int rootdev;
-struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
-volatile struct ehci_hcor *hcor;
-
-static uint16_t portreset;
-static struct QH qh_list __attribute__((aligned(32)));
-
-static struct descriptor {
- struct usb_hub_descriptor hub;
- struct usb_device_descriptor device;
- struct usb_linux_config_descriptor config;
- struct usb_linux_interface_descriptor interface;
- struct usb_endpoint_descriptor endpoint;
-} __attribute__ ((packed)) descriptor = {
- {
- 0x8, /* bDescLength */
- 0x29, /* bDescriptorType: hub descriptor */
- 2, /* bNrPorts -- runtime modified */
- 0, /* wHubCharacteristics */
- 0xff, /* bPwrOn2PwrGood */
- 0, /* bHubCntrCurrent */
- {}, /* Device removable */
- {} /* at most 7 ports! XXX */
- },
- {
- 0x12, /* bLength */
- 1, /* bDescriptorType: UDESC_DEVICE */
- 0x0002, /* bcdUSB: v2.0 */
- 9, /* bDeviceClass: UDCLASS_HUB */
- 0, /* bDeviceSubClass: UDSUBCLASS_HUB */
- 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */
- 64, /* bMaxPacketSize: 64 bytes */
- 0x0000, /* idVendor */
- 0x0000, /* idProduct */
- 0x0001, /* bcdDevice */
- 1, /* iManufacturer */
- 2, /* iProduct */
- 0, /* iSerialNumber */
- 1 /* bNumConfigurations: 1 */
- },
- {
- 0x9,
- 2, /* bDescriptorType: UDESC_CONFIG */
- cpu_to_le16(0x19),
- 1, /* bNumInterface */
- 1, /* bConfigurationValue */
- 0, /* iConfiguration */
- 0x40, /* bmAttributes: UC_SELF_POWER */
- 0 /* bMaxPower */
- },
- {
- 0x9, /* bLength */
- 4, /* bDescriptorType: UDESC_INTERFACE */
- 0, /* bInterfaceNumber */
- 0, /* bAlternateSetting */
- 1, /* bNumEndpoints */
- 9, /* bInterfaceClass: UICLASS_HUB */
- 0, /* bInterfaceSubClass: UISUBCLASS_HUB */
- 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */
- 0 /* iInterface */
- },
- {
- 0x7, /* bLength */
- 5, /* bDescriptorType: UDESC_ENDPOINT */
- 0x81, /* bEndpointAddress:
- * UE_DIR_IN | EHCI_INTR_ENDPT
- */
- 3, /* bmAttributes: UE_INTERRUPT */
- 8, 0, /* wMaxPacketSize */
- 255 /* bInterval */
- },
-};
-
-#if defined(CONFIG_EHCI_IS_TDI)
-#define ehci_is_TDI() (1)
-#else
-#define ehci_is_TDI() (0)
-#endif
-
-#if defined(CONFIG_EHCI_DCACHE)
-/*
- * Routines to handle (flush/invalidate) the dcache for the QH and qTD
- * structures and data buffers. This is needed on platforms using this
- * EHCI support with dcache enabled.
- */
-static void flush_invalidate(u32 addr, int size, int flush)
-{
- if (flush)
- flush_dcache_range(addr, addr + size);
- else
- invalidate_dcache_range(addr, addr + size);
-}
-
-static void cache_qtd(struct qTD *qtd, int flush)
-{
- u32 *ptr = (u32 *)qtd->qt_buffer[0];
- int len = (qtd->qt_token & 0x7fff0000) >> 16;
-
- flush_invalidate((u32)qtd, sizeof(struct qTD), flush);
- if (ptr && len)
- flush_invalidate((u32)ptr, len, flush);
-}
-
-
-static inline struct QH *qh_addr(struct QH *qh)
-{
- return (struct QH *)((u32)qh & 0xffffffe0);
-}
-
-static void cache_qh(struct QH *qh, int flush)
-{
- struct qTD *qtd;
- struct qTD *next;
- static struct qTD *first_qtd;
-
- /*
- * Walk the QH list and flush/invalidate all entries
- */
- while (1) {
- flush_invalidate((u32)qh_addr(qh), sizeof(struct QH), flush);
- if ((u32)qh & QH_LINK_TYPE_QH)
- break;
- qh = qh_addr(qh);
- qh = (struct QH *)qh->qh_link;
- }
- qh = qh_addr(qh);
-
- /*
- * Save first qTD pointer, needed for invalidating pass on this QH
- */
- if (flush)
- first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay &
- 0xffffffe0);
- else
- qtd = first_qtd;
-
- /*
- * Walk the qTD list and flush/invalidate all entries
- */
- while (1) {
- if (qtd == NULL)
- break;
- cache_qtd(qtd, flush);
- next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0);
- if (next == qtd)
- break;
- qtd = next;
- }
-}
-
-static inline void ehci_flush_dcache(struct QH *qh)
-{
- cache_qh(qh, 1);
-}
-
-static inline void ehci_invalidate_dcache(struct QH *qh)
-{
- cache_qh(qh, 0);
-}
-#else /* CONFIG_EHCI_DCACHE */
-/*
- *
- */
-static inline void ehci_flush_dcache(struct QH *qh)
-{
-}
-
-static inline void ehci_invalidate_dcache(struct QH *qh)
-{
-}
-#endif /* CONFIG_EHCI_DCACHE */
-
-static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
-{
- uint32_t result;
- do {
- result = ehci_readl(ptr);
- if (result == ~(uint32_t)0)
- return -1;
- result &= mask;
- if (result == done)
- return 0;
- udelay(1);
- usec--;
- } while (usec > 0);
- return -1;
-}
-
-static void ehci_free(void *p, size_t sz)
-{
-
-}
-
-static int ehci_reset(void)
-{
- uint32_t cmd;
- uint32_t tmp;
- uint32_t *reg_ptr;
- int ret = 0;
-
- cmd = ehci_readl(&hcor->or_usbcmd);
- cmd |= CMD_RESET;
- ehci_writel(&hcor->or_usbcmd, cmd);
- ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
- if (ret < 0) {
- printf("EHCI fail to reset\n");
- goto out;
- }
-
- if (ehci_is_TDI()) {
- reg_ptr = (uint32_t *)((u8 *)hcor + USBMODE);
- tmp = ehci_readl(reg_ptr);
- tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
- tmp |= USBMODE_BE;
-#endif
- ehci_writel(reg_ptr, tmp);
- }
-out:
- return ret;
-}
-
-static void *ehci_alloc(size_t sz, size_t align)
-{
- static struct QH qh __attribute__((aligned(32)));
- static struct qTD td[3] __attribute__((aligned (32)));
- static int ntds;
- void *p;
-
- switch (sz) {
- case sizeof(struct QH):
- p = &qh;
- ntds = 0;
- break;
- case sizeof(struct qTD):
- if (ntds == 3) {
- debug("out of TDs\n");
- return NULL;
- }
- p = &td[ntds];
- ntds++;
- break;
- default:
- debug("unknown allocation size\n");
- return NULL;
- }
-
- memset(p, sz, 0);
- return p;
-}
-
-static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
-{
- uint32_t addr, delta, next;
- int idx;
-
- addr = (uint32_t) buf;
- idx = 0;
- while (idx < 5) {
- td->qt_buffer[idx] = cpu_to_hc32(addr);
- next = (addr + 4096) & ~4095;
- delta = next - addr;
- if (delta >= sz)
- break;
- sz -= delta;
- addr = next;
- idx++;
- }
-
- if (idx == 5) {
- debug("out of buffer pointers (%u bytes left)\n", sz);
- return -1;
- }
-
- return 0;
-}
-
-static int
-ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, struct devrequest *req)
-{
- struct QH *qh;
- struct qTD *td;
- volatile struct qTD *vtd;
- unsigned long ts;
- uint32_t *tdp;
- uint32_t endpt, token, usbsts;
- uint32_t c, toggle;
- uint32_t cmd;
- int ret = 0;
-
- debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
- buffer, length, req);
- if (req != NULL)
- debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
- req->request, req->request,
- req->requesttype, req->requesttype,
- le16_to_cpu(req->value), le16_to_cpu(req->value),
- le16_to_cpu(req->index));
-
- qh = ehci_alloc(sizeof(struct QH), 32);
- if (qh == NULL) {
- debug("unable to allocate QH\n");
- return -1;
- }
- qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
- c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
- usb_pipeendpoint(pipe) == 0) ? 1 : 0;
- endpt = (8 << 28) |
- (c << 27) |
- (usb_maxpacket(dev, pipe) << 16) |
- (0 << 15) |
- (1 << 14) |
- (usb_pipespeed(pipe) << 12) |
- (usb_pipeendpoint(pipe) << 8) |
- (0 << 7) | (usb_pipedevice(pipe) << 0);
- qh->qh_endpt1 = cpu_to_hc32(endpt);
- endpt = (1 << 30) |
- (dev->portnr << 23) |
- (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
- qh->qh_endpt2 = cpu_to_hc32(endpt);
- qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
-
- td = NULL;
- tdp = &qh->qh_overlay.qt_next;
-
- toggle =
- usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
-
- if (req != NULL) {
- td = ehci_alloc(sizeof(struct qTD), 32);
- if (td == NULL) {
- debug("unable to allocate SETUP td\n");
- goto fail;
- }
- td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
- token = (0 << 31) |
- (sizeof(*req) << 16) |
- (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
- td->qt_token = cpu_to_hc32(token);
- if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
- debug("unable construct SETUP td\n");
- ehci_free(td, sizeof(*td));
- goto fail;
- }
- *tdp = cpu_to_hc32((uint32_t) td);
- tdp = &td->qt_next;
- toggle = 1;
- }
-
- if (length > 0 || req == NULL) {
- td = ehci_alloc(sizeof(struct qTD), 32);
- if (td == NULL) {
- debug("unable to allocate DATA td\n");
- goto fail;
- }
- td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
- token = (toggle << 31) |
- (length << 16) |
- ((req == NULL ? 1 : 0) << 15) |
- (0 << 12) |
- (3 << 10) |
- ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
- td->qt_token = cpu_to_hc32(token);
- if (ehci_td_buffer(td, buffer, length) != 0) {
- debug("unable construct DATA td\n");
- ehci_free(td, sizeof(*td));
- goto fail;
- }
- *tdp = cpu_to_hc32((uint32_t) td);
- tdp = &td->qt_next;
- }
-
- if (req != NULL) {
- td = ehci_alloc(sizeof(struct qTD), 32);
- if (td == NULL) {
- debug("unable to allocate ACK td\n");
- goto fail;
- }
- td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
- token = (toggle << 31) |
- (0 << 16) |
- (1 << 15) |
- (0 << 12) |
- (3 << 10) |
- ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
- td->qt_token = cpu_to_hc32(token);
- *tdp = cpu_to_hc32((uint32_t) td);
- tdp = &td->qt_next;
- }
-
- qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);
-
- /* Flush dcache */
- ehci_flush_dcache(&qh_list);
-
- usbsts = ehci_readl(&hcor->or_usbsts);
- ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));
-
- /* Enable async. schedule. */
- cmd = ehci_readl(&hcor->or_usbcmd);
- cmd |= CMD_ASE;
- ehci_writel(&hcor->or_usbcmd, cmd);
-
- ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
- 100 * 1000);
- if (ret < 0) {
- printf("EHCI fail timeout STD_ASS set\n");
- goto fail;
- }
-
- /* Wait for TDs to be processed. */
- ts = get_timer(0);
- vtd = td;
- do {
- /* Invalidate dcache */
- ehci_invalidate_dcache(&qh_list);
- token = hc32_to_cpu(vtd->qt_token);
- if (!(token & 0x80))
- break;
- } while (get_timer(ts) < CONFIG_SYS_HZ);
-
- /* Disable async schedule. */
- cmd = ehci_readl(&hcor->or_usbcmd);
- cmd &= ~CMD_ASE;
- ehci_writel(&hcor->or_usbcmd, cmd);
-
- ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
- 100 * 1000);
- if (ret < 0) {
- printf("EHCI fail timeout STD_ASS reset\n");
- goto fail;
- }
-
- qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
-
- token = hc32_to_cpu(qh->qh_overlay.qt_token);
- if (!(token & 0x80)) {
- debug("TOKEN=%#x\n", token);
- switch (token & 0xfc) {
- case 0:
- toggle = token >> 31;
- usb_settoggle(dev, usb_pipeendpoint(pipe),
- usb_pipeout(pipe), toggle);
- dev->status = 0;
- break;
- case 0x40:
- dev->status = USB_ST_STALLED;
- break;
- case 0xa0:
- case 0x20:
- dev->status = USB_ST_BUF_ERR;
- break;
- case 0x50:
- case 0x10:
- dev->status = USB_ST_BABBLE_DET;
- break;
- default:
- dev->status = USB_ST_CRC_ERR;
- break;
- }
- dev->act_len = length - ((token >> 16) & 0x7fff);
- } else {
- dev->act_len = 0;
- debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
- dev->devnum, ehci_readl(&hcor->or_usbsts),
- ehci_readl(&hcor->or_portsc[0]),
- ehci_readl(&hcor->or_portsc[1]));
- }
-
- return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
-
-fail:
- td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
- while (td != (void *)QT_NEXT_TERMINATE) {
- qh->qh_overlay.qt_next = td->qt_next;
- ehci_free(td, sizeof(*td));
- td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next);
- }
- ehci_free(qh, sizeof(*qh));
- return -1;
-}
-
-static inline int min3(int a, int b, int c)
-{
-
- if (b < a)
- a = b;
- if (c < a)
- a = c;
- return a;
-}
-
-int
-ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, struct devrequest *req)
-{
- uint8_t tmpbuf[4];
- u16 typeReq;
- void *srcptr = NULL;
- int len, srclen;
- uint32_t reg;
- uint32_t *status_reg;
-
- if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
- printf("The request port(%d) is not configured\n",
- le16_to_cpu(req->index) - 1);
- return -1;
- }
- status_reg = (uint32_t *)&hcor->or_portsc[
- le16_to_cpu(req->index) - 1];
- srclen = 0;
-
- debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
- req->request, req->request,
- req->requesttype, req->requesttype,
- le16_to_cpu(req->value), le16_to_cpu(req->index));
-
- typeReq = req->request << 8 | req->requesttype;
-
- switch (le16_to_cpu(typeReq)) {
- case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
- switch (le16_to_cpu(req->value) >> 8) {
- case USB_DT_DEVICE:
- debug("USB_DT_DEVICE request\n");
- srcptr = &descriptor.device;
- srclen = 0x12;
- break;
- case USB_DT_CONFIG:
- debug("USB_DT_CONFIG config\n");
- srcptr = &descriptor.config;
- srclen = 0x19;
- break;
- case USB_DT_STRING:
- debug("USB_DT_STRING config\n");
- switch (le16_to_cpu(req->value) & 0xff) {
- case 0: /* Language */
- srcptr = "\4\3\1\0";
- srclen = 4;
- break;
- case 1: /* Vendor */
- srcptr = "\16\3u\0-\0b\0o\0o\0t\0";
- srclen = 14;
- break;
- case 2: /* Product */
- srcptr = "\52\3E\0H\0C\0I\0 "
- "\0H\0o\0s\0t\0 "
- "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0";
- srclen = 42;
- break;
- default:
- debug("unknown value DT_STRING %x\n",
- le16_to_cpu(req->value));
- goto unknown;
- }
- break;
- default:
- debug("unknown value %x\n", le16_to_cpu(req->value));
- goto unknown;
- }
- break;
- case USB_REQ_GET_DESCRIPTOR | ((USB_DIR_IN | USB_RT_HUB) << 8):
- switch (le16_to_cpu(req->value) >> 8) {
- case USB_DT_HUB:
- debug("USB_DT_HUB config\n");
- srcptr = &descriptor.hub;
- srclen = 0x8;
- break;
- default:
- debug("unknown value %x\n", le16_to_cpu(req->value));
- goto unknown;
- }
- break;
- case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8):
- debug("USB_REQ_SET_ADDRESS\n");
- rootdev = le16_to_cpu(req->value);
- break;
- case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- debug("USB_REQ_SET_CONFIGURATION\n");
- /* Nothing to do */
- break;
- case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8):
- tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */
- tmpbuf[1] = 0;
- srcptr = tmpbuf;
- srclen = 2;
- break;
- case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
- memset(tmpbuf, 0, 4);
- reg = ehci_readl(status_reg);
- if (reg & EHCI_PS_CS)
- tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
- if (reg & EHCI_PS_PE)
- tmpbuf[0] |= USB_PORT_STAT_ENABLE;
- if (reg & EHCI_PS_SUSP)
- tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
- if (reg & EHCI_PS_OCA)
- tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
- if (reg & EHCI_PS_PR &&
- (portreset & (1 << le16_to_cpu(req->index)))) {
- int ret;
- /* force reset to complete */
- reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
- ehci_writel(status_reg, reg);
- ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
- if (!ret)
- tmpbuf[0] |= USB_PORT_STAT_RESET;
- else
- printf("port(%d) reset error\n",
- le16_to_cpu(req->index) - 1);
- }
- if (reg & EHCI_PS_PP)
- tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
-
- if (ehci_is_TDI()) {
- switch ((reg >> 26) & 3) {
- case 0:
- break;
- case 1:
- tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
- break;
- case 2:
- default:
- tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
- break;
- }
- } else {
- tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
- }
-
- if (reg & EHCI_PS_CSC)
- tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
- if (reg & EHCI_PS_PEC)
- tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
- if (reg & EHCI_PS_OCC)
- tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
- if (portreset & (1 << le16_to_cpu(req->index)))
- tmpbuf[2] |= USB_PORT_STAT_C_RESET;
-
- srcptr = tmpbuf;
- srclen = 4;
- break;
- case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- reg = ehci_readl(status_reg);
- reg &= ~EHCI_PS_CLEAR;
- switch (le16_to_cpu(req->value)) {
- case USB_PORT_FEAT_ENABLE:
- reg |= EHCI_PS_PE;
- ehci_writel(status_reg, reg);
- break;
- case USB_PORT_FEAT_POWER:
- if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
- reg |= EHCI_PS_PP;
- ehci_writel(status_reg, reg);
- }
- break;
- case USB_PORT_FEAT_RESET:
- if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
- !ehci_is_TDI() &&
- EHCI_PS_IS_LOWSPEED(reg)) {
- /* Low speed device, give up ownership. */
- debug("port %d low speed --> companion\n",
- req->index - 1);
- reg |= EHCI_PS_PO;
- ehci_writel(status_reg, reg);
- break;
- } else {
- reg |= EHCI_PS_PR;
- reg &= ~EHCI_PS_PE;
- ehci_writel(status_reg, reg);
- /*
- * caller must wait, then call GetPortStatus
- * usb 2.0 specification say 50 ms resets on
- * root
- */
- wait_ms(50);
- portreset |= 1 << le16_to_cpu(req->index);
- }
- break;
- default:
- debug("unknown feature %x\n", le16_to_cpu(req->value));
- goto unknown;
- }
- /* unblock posted writes */
- ehci_readl(&hcor->or_usbcmd);
- break;
- case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- reg = ehci_readl(status_reg);
- switch (le16_to_cpu(req->value)) {
- case USB_PORT_FEAT_ENABLE:
- reg &= ~EHCI_PS_PE;
- break;
- case USB_PORT_FEAT_C_ENABLE:
- reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
- break;
- case USB_PORT_FEAT_POWER:
- if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
- reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
- case USB_PORT_FEAT_C_CONNECTION:
- reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
- break;
- case USB_PORT_FEAT_OVER_CURRENT:
- reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
- break;
- case USB_PORT_FEAT_C_RESET:
- portreset &= ~(1 << le16_to_cpu(req->index));
- break;
- default:
- debug("unknown feature %x\n", le16_to_cpu(req->value));
- goto unknown;
- }
- ehci_writel(status_reg, reg);
- /* unblock posted write */
- ehci_readl(&hcor->or_usbcmd);
- break;
- default:
- debug("Unknown request\n");
- goto unknown;
- }
-
- wait_ms(1);
- len = min3(srclen, le16_to_cpu(req->length), length);
- if (srcptr != NULL && len > 0)
- memcpy(buffer, srcptr, len);
- else
- debug("Len is 0\n");
-
- dev->act_len = len;
- dev->status = 0;
- return 0;
-
-unknown:
- debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n",
- req->requesttype, req->request, le16_to_cpu(req->value),
- le16_to_cpu(req->index), le16_to_cpu(req->length));
-
- dev->act_len = 0;
- dev->status = USB_ST_STALLED;
- return -1;
-}
-
-int usb_lowlevel_stop(void)
-{
- return ehci_hcd_stop();
-}
-
-int usb_lowlevel_init(void)
-{
- uint32_t reg;
- uint32_t cmd;
-
- if (ehci_hcd_init() != 0)
- return -1;
-
- /* EHCI spec section 4.1 */
- if (ehci_reset() != 0)
- return -1;
-
-#if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET)
- if (ehci_hcd_init() != 0)
- return -1;
-#endif
-
- /* Set head of reclaim list */
- memset(&qh_list, 0, sizeof(qh_list));
- qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
- qh_list.qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12));
- qh_list.qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE);
- qh_list.qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
- qh_list.qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
- qh_list.qh_overlay.qt_token = cpu_to_hc32(0x40);
-
- /* Set async. queue head pointer. */
- ehci_writel(&hcor->or_asynclistaddr, (uint32_t)&qh_list);
-
- reg = ehci_readl(&hccr->cr_hcsparams);
- descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
- printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
- /* Port Indicators */
- if (HCS_INDICATOR(reg))
- descriptor.hub.wHubCharacteristics |= 0x80;
- /* Port Power Control */
- if (HCS_PPC(reg))
- descriptor.hub.wHubCharacteristics |= 0x01;
-
- /* Start the host controller. */
- cmd = ehci_readl(&hcor->or_usbcmd);
- /*
- * Philips, Intel, and maybe others need CMD_RUN before the
- * root hub will detect new devices (why?); NEC doesn't
- */
- cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
- cmd |= CMD_RUN;
- ehci_writel(&hcor->or_usbcmd, cmd);
-
- /* take control over the ports */
- cmd = ehci_readl(&hcor->or_configflag);
- cmd |= FLAG_CF;
- ehci_writel(&hcor->or_configflag, cmd);
- /* unblock posted write */
- cmd = ehci_readl(&hcor->or_usbcmd);
- wait_ms(5);
- reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
- printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
-
- rootdev = 0;
-
- return 0;
-}
-
-int
-submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length)
-{
-
- if (usb_pipetype(pipe) != PIPE_BULK) {
- debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe));
- return -1;
- }
- return ehci_submit_async(dev, pipe, buffer, length, NULL);
-}
-
-int
-submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, struct devrequest *setup)
-{
-
- if (usb_pipetype(pipe) != PIPE_CONTROL) {
- debug("non-control pipe (type=%lu)", usb_pipetype(pipe));
- return -1;
- }
-
- if (usb_pipedevice(pipe) == rootdev) {
- if (rootdev == 0)
- dev->speed = USB_SPEED_HIGH;
- return ehci_submit_root(dev, pipe, buffer, length, setup);
- }
- return ehci_submit_async(dev, pipe, buffer, length, setup);
-}
-
-int
-submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int length, int interval)
-{
-
- debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d",
- dev, pipe, buffer, length, interval);
- return -1;
-}
+++ /dev/null
-/*-
- * Copyright (c) 2007-2008, Juniper Networks, Inc.
- * Copyright (c) 2008, Excito Elektronik i Skåne AB
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef USB_EHCI_CORE_H
-#define USB_EHCI_CORE_H
-
-extern int rootdev;
-extern struct ehci_hccr *hccr;
-extern volatile struct ehci_hcor *hcor;
-
-#endif
+++ /dev/null
-/*
- * (C) Copyright 2008, Excito Elektronik i Sk=E5ne AB
- *
- * Author: Tor Krill tor@excito.com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <pci.h>
-#include <usb.h>
-#include <mpc83xx.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-#include "usb_ehci.h"
-#include "usb_ehci_fsl.h"
-#include "usb_ehci_core.h"
-
-/*
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- *
- * Excerpts from linux ehci fsl driver.
- */
-int ehci_hcd_init(void)
-{
- volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
- uint32_t addr, temp;
-
- addr = (uint32_t)&(im->usb[0]);
- hccr = (struct ehci_hccr *)(addr + FSL_SKIP_PCI);
- hcor = (struct ehci_hcor *)((uint32_t) hccr +
- HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
- /* Configure clock */
- clrsetbits_be32(&(im->clk.sccr), MPC83XX_SCCR_USB_MASK,
- MPC83XX_SCCR_USB_DRCM_11);
-
- /* Confgure interface. */
- temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
- out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp
- | REFSEL_16MHZ | UTMI_PHY_EN);
-
- /* Wait for clock to stabilize */
- do {
- temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
- udelay(1000);
- } while (!(temp & PHY_CLK_VALID));
-
- /* Set to Host mode */
- temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
- out_le32((void *)(addr + FSL_SOC_USB_USBMODE), temp | CM_HOST);
-
- out_be32((void *)(addr + FSL_SOC_USB_SNOOP1), SNOOP_SIZE_2GB);
- out_be32((void *)(addr + FSL_SOC_USB_SNOOP2),
- 0x80000000 | SNOOP_SIZE_2GB);
-
- /* Init phy */
- /* TODO: handle different phys? */
- out_le32(&(hcor->or_portsc[0]), PORT_PTS_UTMI);
-
- /* Enable interface. */
- temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
- out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
-
- out_be32((void *)(addr + FSL_SOC_USB_PRICTRL), 0x0000000c);
- out_be32((void *)(addr + FSL_SOC_USB_AGECNTTHRSH), 0x00000040);
- out_be32((void *)(addr + FSL_SOC_USB_SICTRL), 0x00000001);
-
- /* Enable interface. */
- temp = in_be32((void *)(addr + FSL_SOC_USB_CTRL));
- out_be32((void *)(addr + FSL_SOC_USB_CTRL), temp | USB_EN);
-
- temp = in_le32((void *)(addr + FSL_SOC_USB_USBMODE));
-
- return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(void)
-{
- return 0;
-}
+++ /dev/null
-/*
- * Copyright (c) 2005 freescale semiconductor
- * Copyright (c) 2005 MontaVista Software
- * Copyright (c) 2008 Excito Elektronik i Sk=E5ne AB
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#ifndef _EHCI_FSL_H
-#define _EHCI_FSL_H
-
-/* Global offsets */
-#define FSL_SKIP_PCI 0x100
-
-/* offsets for the non-ehci registers in the FSL SOC USB controller */
-#define FSL_SOC_USB_ULPIVP 0x170
-#define FSL_SOC_USB_PORTSC1 0x184
-#define PORT_PTS_MSK (3 << 30)
-#define PORT_PTS_UTMI (0 << 30)
-#define PORT_PTS_ULPI (2 << 30)
-#define PORT_PTS_SERIAL (3 << 30)
-#define PORT_PTS_PTW (1 << 28)
-
-/* USBMODE Register bits */
-#define CM_IDLE (0 << 0)
-#define CM_RESERVED (1 << 0)
-#define CM_DEVICE (2 << 0)
-#define CM_HOST (3 << 0)
-#define USBMODE_RESERVED_2 (0 << 2)
-#define SLOM (1 << 3)
-#define SDIS (1 << 4)
-
-/* CONTROL Register bits */
-#define ULPI_INT_EN (1 << 0)
-#define WU_INT_EN (1 << 1)
-#define USB_EN (1 << 2)
-#define LSF_EN (1 << 3)
-#define KEEP_OTG_ON (1 << 4)
-#define OTG_PORT (1 << 5)
-#define REFSEL_12MHZ (0 << 6)
-#define REFSEL_16MHZ (1 << 6)
-#define REFSEL_48MHZ (2 << 6)
-#define PLL_RESET (1 << 8)
-#define UTMI_PHY_EN (1 << 9)
-#define PHY_CLK_SEL_UTMI (0 << 10)
-#define PHY_CLK_SEL_ULPI (1 << 10)
-#define CLKIN_SEL_USB_CLK (0 << 11)
-#define CLKIN_SEL_USB_CLK2 (1 << 11)
-#define CLKIN_SEL_SYS_CLK (2 << 11)
-#define CLKIN_SEL_SYS_CLK2 (3 << 11)
-#define RESERVED_18 (0 << 13)
-#define RESERVED_17 (0 << 14)
-#define RESERVED_16 (0 << 15)
-#define WU_INT (1 << 16)
-#define PHY_CLK_VALID (1 << 17)
-
-#define FSL_SOC_USB_PORTSC2 0x188
-#define FSL_SOC_USB_USBMODE 0x1a8
-#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
-#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
-#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
-#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
-#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
-#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
-#define SNOOP_SIZE_2GB 0x1e
-
-/* System Clock Control Register */
-#define MPC83XX_SCCR_USB_MASK 0x00f00000
-#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
-#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
-#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
-
-#endif /* _EHCI_FSL_H */
+++ /dev/null
-/*
- * (C) Copyright 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
- *
- * Author: Michael Trimarchi <trimarchimichael@yahoo.it>
- * This code is based on ehci freescale driver
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <common.h>
-#include <usb.h>
-#include "usb_ehci.h"
-#include "usb_ehci_core.h"
-/*
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(void)
-{
- hccr = (struct ehci_hccr *)(0xcd000100);
- hcor = (struct ehci_hcor *)((uint32_t) hccr
- + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
- printf("IXP4XX init hccr %x and hcor %x hc_length %d\n",
- (uint32_t)hccr, (uint32_t)hcor,
- (uint32_t)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
- return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(void)
-{
- return 0;
-}
+++ /dev/null
-/*-
- * Copyright (c) 2007-2008, Juniper Networks, Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2 of
- * the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <pci.h>
-#include <usb.h>
-#include "usb_ehci.h"
-#include "usb_ehci_core.h"
-
-#ifdef CONFIG_PCI_EHCI_DEVICE
-static struct pci_device_id ehci_pci_ids[] = {
- /* Please add supported PCI EHCI controller ids here */
- {0, 0}
-};
-#endif
-
-/*
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(void)
-{
- pci_dev_t pdev;
- uint32_t addr;
-
- pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVICE);
- if (pdev == -1) {
- printf("EHCI host controller not found\n");
- return -1;
- }
-
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &addr);
- hccr = (struct ehci_hccr *)addr;
- hcor = (struct ehci_hcor *)((uint32_t) hccr +
- HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
-
- return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(void)
-{
- return 0;
-}
+++ /dev/null
-/*
- * (C) Copyright 2009 Stefan Roese <sr@denx.de>, DENX Software Engineering
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <common.h>
-#include <usb.h>
-
-#include "usb_ehci.h"
-#include "usb_ehci_core.h"
-
-int vct_ehci_hcd_init(u32 *hccr, u32 *hcor);
-
-/*
- * Create the appropriate control structures to manage
- * a new EHCI host controller.
- */
-int ehci_hcd_init(void)
-{
- int ret;
- u32 vct_hccr;
- u32 vct_hcor;
-
- /*
- * Init VCT specific stuff
- */
- ret = vct_ehci_hcd_init(&vct_hccr, &vct_hcor);
- if (ret)
- return ret;
-
- hccr = (struct ehci_hccr *)vct_hccr;
- hcor = (struct ehci_hcor *)vct_hcor;
-
- return 0;
-}
-
-/*
- * Destroy the appropriate control structures corresponding
- * the the EHCI host controller.
- */
-int ehci_hcd_stop(void)
-{
- return 0;
-}
+++ /dev/null
-/*
- * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
- *
- * Interrupt support is added. Now, it has been tested
- * on ULI1575 chip and works well with USB keyboard.
- *
- * (C) Copyright 2007
- * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
- *
- * (C) Copyright 2003
- * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
- *
- * Note: Much of this code has been derived from Linux 2.4
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell
- *
- * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
- * ebenard@eukrea.com - based on s3c24x0's driver
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-/*
- * IMPORTANT NOTES
- * 1 - Read doc/README.generic_usb_ohci
- * 2 - this driver is intended for use with USB Mass Storage Devices
- * (BBB) and USB keyboard. There is NO support for Isochronous pipes!
- * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
- * to activate workaround for bug #41 or this driver will NOT work!
- */
-
-#include <common.h>
-#include <asm/byteorder.h>
-
-#if defined(CONFIG_PCI_OHCI)
-# include <pci.h>
-#if !defined(CONFIG_PCI_OHCI_DEVNO)
-#define CONFIG_PCI_OHCI_DEVNO 0
-#endif
-#endif
-
-#include <malloc.h>
-#include <usb.h>
-#include "usb_ohci.h"
-
-#ifdef CONFIG_AT91RM9200
-#include <asm/arch/hardware.h> /* needed for AT91_USB_HOST_BASE */
-#endif
-
-#if defined(CONFIG_ARM920T) || \
- defined(CONFIG_S3C2400) || \
- defined(CONFIG_S3C2410) || \
- defined(CONFIG_S3C6400) || \
- defined(CONFIG_440EP) || \
- defined(CONFIG_PCI_OHCI) || \
- defined(CONFIG_MPC5200) || \
- defined(CONFIG_SYS_OHCI_USE_NPS)
-# define OHCI_USE_NPS /* force NoPowerSwitching mode */
-#endif
-
-#undef OHCI_VERBOSE_DEBUG /* not always helpful */
-#undef DEBUG
-#undef SHOW_INFO
-#undef OHCI_FILL_TRACE
-
-/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT \
- (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-
-/*
- * e.g. PCI controllers need this
- */
-#ifdef CONFIG_SYS_OHCI_SWAP_REG_ACCESS
-# define readl(a) __swap_32(*((volatile u32 *)(a)))
-# define writel(a, b) (*((volatile u32 *)(b)) = __swap_32((volatile u32)a))
-#else
-# define readl(a) (*((volatile u32 *)(a)))
-# define writel(a, b) (*((volatile u32 *)(b)) = ((volatile u32)a))
-#endif /* CONFIG_SYS_OHCI_SWAP_REG_ACCESS */
-
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#ifdef CONFIG_PCI_OHCI
-static struct pci_device_id ohci_pci_ids[] = {
- {0x10b9, 0x5237}, /* ULI1575 PCI OHCI module ids */
- {0x1033, 0x0035}, /* NEC PCI OHCI module ids */
- {0x1131, 0x1561}, /* Philips 1561 PCI OHCI module ids */
- /* Please add supported PCI OHCI controller ids here */
- {0, 0}
-};
-#endif
-
-#ifdef CONFIG_PCI_EHCI_DEVNO
-static struct pci_device_id ehci_pci_ids[] = {
- {0x1131, 0x1562}, /* Philips 1562 PCI EHCI module ids */
- /* Please add supported PCI EHCI controller ids here */
- {0, 0}
-};
-#endif
-
-#ifdef DEBUG
-#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif /* DEBUG */
-#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
-#ifdef SHOW_INFO
-#define info(format, arg...) printf("INFO: " format "\n", ## arg)
-#else
-#define info(format, arg...) do {} while (0)
-#endif
-
-#ifdef CONFIG_SYS_OHCI_BE_CONTROLLER
-# define m16_swap(x) cpu_to_be16(x)
-# define m32_swap(x) cpu_to_be32(x)
-#else
-# define m16_swap(x) cpu_to_le16(x)
-# define m32_swap(x) cpu_to_le32(x)
-#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
-
-/* global ohci_t */
-static ohci_t gohci;
-/* this must be aligned to a 256 byte boundary */
-struct ohci_hcca ghcca[1];
-/* a pointer to the aligned storage */
-struct ohci_hcca *phcca;
-/* this allocates EDs for all possible endpoints */
-struct ohci_device ohci_dev;
-/* device which was disconnected */
-struct usb_device *devgone;
-
-static inline u32 roothub_a(struct ohci *hc)
- { return readl(&hc->regs->roothub.a); }
-static inline u32 roothub_b(struct ohci *hc)
- { return readl(&hc->regs->roothub.b); }
-static inline u32 roothub_status(struct ohci *hc)
- { return readl(&hc->regs->roothub.status); }
-static inline u32 roothub_portstatus(struct ohci *hc, int i)
- { return readl(&hc->regs->roothub.portstatus[i]); }
-
-/* forward declaration */
-static int hc_interrupt(void);
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len,
- struct devrequest *setup, urb_priv_t *urb,
- int interval);
-
-/*-------------------------------------------------------------------------*
- * URB support functions
- *-------------------------------------------------------------------------*/
-
-/* free HCD-private data associated with this URB */
-
-static void urb_free_priv(urb_priv_t *urb)
-{
- int i;
- int last;
- struct td *td;
-
- last = urb->length - 1;
- if (last >= 0) {
- for (i = 0; i <= last; i++) {
- td = urb->td[i];
- if (td) {
- td->usb_dev = NULL;
- urb->td[i] = NULL;
- }
- }
- }
- free(urb);
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-static int sohci_get_current_frame_number(struct usb_device *dev);
-
-/* debug| print the main components of an URB
- * small: 0) header + data packets 1) just header */
-
-static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
- unsigned long pipe, void *buffer, int transfer_len,
- struct devrequest *setup, char *str, int small)
-{
- dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
- str,
- sohci_get_current_frame_number(dev),
- usb_pipedevice(pipe),
- usb_pipeendpoint(pipe),
- usb_pipeout(pipe)? 'O': 'I',
- usb_pipetype(pipe) < 2 ? \
- (usb_pipeint(pipe)? "INTR": "ISOC"): \
- (usb_pipecontrol(pipe)? "CTRL": "BULK"),
- (purb ? purb->actual_length : 0),
- transfer_len, dev->status);
-#ifdef OHCI_VERBOSE_DEBUG
- if (!small) {
- int i, len;
-
- if (usb_pipecontrol(pipe)) {
- printf(__FILE__ ": cmd(8):");
- for (i = 0; i < 8 ; i++)
- printf(" %02x", ((__u8 *) setup) [i]);
- printf("\n");
- }
- if (transfer_len > 0 && buffer) {
- printf(__FILE__ ": data(%d/%d):",
- (purb ? purb->actual_length : 0),
- transfer_len);
- len = usb_pipeout(pipe)? transfer_len:
- (purb ? purb->actual_length : 0);
- for (i = 0; i < 16 && i < len; i++)
- printf(" %02x", ((__u8 *) buffer) [i]);
- printf("%s\n", i < len? "...": "");
- }
- }
-#endif
-}
-
-/* just for debugging; prints non-empty branches of the int ed tree
- * inclusive iso eds */
-void ep_print_int_eds(ohci_t *ohci, char *str)
-{
- int i, j;
- __u32 *ed_p;
- for (i = 0; i < 32; i++) {
- j = 5;
- ed_p = &(ohci->hcca->int_table [i]);
- if (*ed_p == 0)
- continue;
- printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
- while (*ed_p != 0 && j--) {
- ed_t *ed = (ed_t *)m32_swap(ed_p);
- printf(" ed: %4x;", ed->hwINFO);
- ed_p = &ed->hwNextED;
- }
- printf("\n");
- }
-}
-
-static void ohci_dump_intr_mask(char *label, __u32 mask)
-{
- dbg("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
- label,
- mask,
- (mask & OHCI_INTR_MIE) ? " MIE" : "",
- (mask & OHCI_INTR_OC) ? " OC" : "",
- (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
- (mask & OHCI_INTR_FNO) ? " FNO" : "",
- (mask & OHCI_INTR_UE) ? " UE" : "",
- (mask & OHCI_INTR_RD) ? " RD" : "",
- (mask & OHCI_INTR_SF) ? " SF" : "",
- (mask & OHCI_INTR_WDH) ? " WDH" : "",
- (mask & OHCI_INTR_SO) ? " SO" : ""
- );
-}
-
-static void maybe_print_eds(char *label, __u32 value)
-{
- ed_t *edp = (ed_t *)value;
-
- if (value) {
- dbg("%s %08x", label, value);
- dbg("%08x", edp->hwINFO);
- dbg("%08x", edp->hwTailP);
- dbg("%08x", edp->hwHeadP);
- dbg("%08x", edp->hwNextED);
- }
-}
-
-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 "?";
-}
-
-/* dump control and status registers */
-static void ohci_dump_status(ohci_t *controller)
-{
- struct ohci_regs *regs = controller->regs;
- __u32 temp;
-
- temp = readl(®s->revision) & 0xff;
- if (temp != 0x10)
- dbg("spec %d.%d", (temp >> 4), (temp & 0x0f));
-
- temp = readl(®s->control);
- dbg("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
- (temp & OHCI_CTRL_RWE) ? " RWE" : "",
- (temp & OHCI_CTRL_RWC) ? " RWC" : "",
- (temp & OHCI_CTRL_IR) ? " IR" : "",
- hcfs2string(temp & OHCI_CTRL_HCFS),
- (temp & OHCI_CTRL_BLE) ? " BLE" : "",
- (temp & OHCI_CTRL_CLE) ? " CLE" : "",
- (temp & OHCI_CTRL_IE) ? " IE" : "",
- (temp & OHCI_CTRL_PLE) ? " PLE" : "",
- temp & OHCI_CTRL_CBSR
- );
-
- temp = readl(®s->cmdstatus);
- dbg("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
- (temp & OHCI_SOC) >> 16,
- (temp & OHCI_OCR) ? " OCR" : "",
- (temp & OHCI_BLF) ? " BLF" : "",
- (temp & OHCI_CLF) ? " CLF" : "",
- (temp & OHCI_HCR) ? " HCR" : ""
- );
-
- ohci_dump_intr_mask("intrstatus", readl(®s->intrstatus));
- ohci_dump_intr_mask("intrenable", readl(®s->intrenable));
-
- maybe_print_eds("ed_periodcurrent", readl(®s->ed_periodcurrent));
-
- maybe_print_eds("ed_controlhead", readl(®s->ed_controlhead));
- maybe_print_eds("ed_controlcurrent", readl(®s->ed_controlcurrent));
-
- maybe_print_eds("ed_bulkhead", readl(®s->ed_bulkhead));
- maybe_print_eds("ed_bulkcurrent", readl(®s->ed_bulkcurrent));
-
- maybe_print_eds("donehead", readl(®s->donehead));
-}
-
-static void ohci_dump_roothub(ohci_t *controller, int verbose)
-{
- __u32 temp, ndp, i;
-
- temp = roothub_a(controller);
- ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- ndp = (ndp == 2) ? 1:0;
-#endif
- if (verbose) {
- dbg("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
- ((temp & RH_A_POTPGT) >> 24) & 0xff,
- (temp & RH_A_NOCP) ? " NOCP" : "",
- (temp & RH_A_OCPM) ? " OCPM" : "",
- (temp & RH_A_DT) ? " DT" : "",
- (temp & RH_A_NPS) ? " NPS" : "",
- (temp & RH_A_PSM) ? " PSM" : "",
- ndp
- );
- temp = roothub_b(controller);
- dbg("roothub.b: %08x PPCM=%04x DR=%04x",
- temp,
- (temp & RH_B_PPCM) >> 16,
- (temp & RH_B_DR)
- );
- temp = roothub_status(controller);
- dbg("roothub.status: %08x%s%s%s%s%s%s",
- temp,
- (temp & RH_HS_CRWE) ? " CRWE" : "",
- (temp & RH_HS_OCIC) ? " OCIC" : "",
- (temp & RH_HS_LPSC) ? " LPSC" : "",
- (temp & RH_HS_DRWE) ? " DRWE" : "",
- (temp & RH_HS_OCI) ? " OCI" : "",
- (temp & RH_HS_LPS) ? " LPS" : ""
- );
- }
-
- for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus(controller, i);
- dbg("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
- i,
- temp,
- (temp & RH_PS_PRSC) ? " PRSC" : "",
- (temp & RH_PS_OCIC) ? " OCIC" : "",
- (temp & RH_PS_PSSC) ? " PSSC" : "",
- (temp & RH_PS_PESC) ? " PESC" : "",
- (temp & RH_PS_CSC) ? " CSC" : "",
-
- (temp & RH_PS_LSDA) ? " LSDA" : "",
- (temp & RH_PS_PPS) ? " PPS" : "",
- (temp & RH_PS_PRS) ? " PRS" : "",
- (temp & RH_PS_POCI) ? " POCI" : "",
- (temp & RH_PS_PSS) ? " PSS" : "",
-
- (temp & RH_PS_PES) ? " PES" : "",
- (temp & RH_PS_CCS) ? " CCS" : ""
- );
- }
-}
-
-static void ohci_dump(ohci_t *controller, int verbose)
-{
- dbg("OHCI controller usb-%s state", controller->slot_name);
-
- /* dumps some of the state we know about */
- ohci_dump_status(controller);
- if (verbose)
- ep_print_int_eds(controller, "hcca");
- dbg("hcca frame #%04x", controller->hcca->frame_no);
- ohci_dump_roothub(controller, 1);
-}
-#endif /* DEBUG */
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* get a transfer request */
-
-int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
-{
- ohci_t *ohci;
- ed_t *ed;
- urb_priv_t *purb_priv = urb;
- int i, size = 0;
- struct usb_device *dev = urb->dev;
- unsigned long pipe = urb->pipe;
- void *buffer = urb->transfer_buffer;
- int transfer_len = urb->transfer_buffer_length;
- int interval = urb->interval;
-
- ohci = &gohci;
-
- /* when controller's hung, permit only roothub cleanup attempts
- * such as powering down ports */
- if (ohci->disabled) {
- err("sohci_submit_job: EPIPE");
- return -1;
- }
-
- /* we're about to begin a new transaction here so mark the
- * URB unfinished */
- urb->finished = 0;
-
- /* every endpoint has a ed, locate and fill it */
- ed = ep_add_ed(dev, pipe, interval, 1);
- if (!ed) {
- err("sohci_submit_job: ENOMEM");
- return -1;
- }
-
- /* for the private part of the URB we need the number of TDs (size) */
- switch (usb_pipetype(pipe)) {
- case PIPE_BULK: /* one TD for every 4096 Byte */
- size = (transfer_len - 1) / 4096 + 1;
- break;
- case PIPE_CONTROL:/* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
- size = (transfer_len == 0)? 2:
- (transfer_len - 1) / 4096 + 3;
- break;
- case PIPE_INTERRUPT: /* 1 TD */
- size = 1;
- break;
- }
-
- ed->purb = urb;
-
- if (size >= (N_URB_TD - 1)) {
- err("need %d TDs, only have %d", size, N_URB_TD);
- return -1;
- }
- purb_priv->pipe = pipe;
-
- /* fill the private part of the URB */
- purb_priv->length = size;
- purb_priv->ed = ed;
- purb_priv->actual_length = 0;
-
- /* allocate the TDs */
- /* note that td[0] was allocated in ep_add_ed */
- for (i = 0; i < size; i++) {
- purb_priv->td[i] = td_alloc(dev);
- if (!purb_priv->td[i]) {
- purb_priv->length = i;
- urb_free_priv(purb_priv);
- err("sohci_submit_job: ENOMEM");
- return -1;
- }
- }
-
- if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
- urb_free_priv(purb_priv);
- err("sohci_submit_job: EINVAL");
- return -1;
- }
-
- /* link the ed into a chain if is not already */
- if (ed->state != ED_OPER)
- ep_link(ohci, ed);
-
- /* fill the TDs and link it to the ed */
- td_submit_job(dev, pipe, buffer, transfer_len,
- setup, purb_priv, interval);
-
- return 0;
-}
-
-static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
-{
- struct ohci_regs *regs = hc->regs;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_INTERRUPT:
- /* implicitly requeued */
- if (urb->dev->irq_handle &&
- (urb->dev->irq_act_len = urb->actual_length)) {
- writel(OHCI_INTR_WDH, ®s->intrenable);
- readl(®s->intrenable); /* PCI posting flush */
- urb->dev->irq_handle(urb->dev);
- writel(OHCI_INTR_WDH, ®s->intrdisable);
- readl(®s->intrdisable); /* PCI posting flush */
- }
- urb->actual_length = 0;
- td_submit_job(
- urb->dev,
- urb->pipe,
- urb->transfer_buffer,
- urb->transfer_buffer_length,
- NULL,
- urb,
- urb->interval);
- break;
- case PIPE_CONTROL:
- case PIPE_BULK:
- break;
- default:
- return 0;
- }
- return 1;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number(struct usb_device *usb_dev)
-{
- ohci_t *ohci = &gohci;
-
- return m16_swap(ohci->hcca->frame_no);
-}
-#endif
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* search for the right branch to insert an interrupt ed into the int tree
- * do some load ballancing;
- * returns the branch and
- * sets the interval to interval = 2^integer (ld (interval)) */
-
-static int ep_int_ballance(ohci_t *ohci, int interval, int load)
-{
- int i, branch = 0;
-
- /* search for the least loaded interrupt endpoint
- * branch of all 32 branches
- */
- for (i = 0; i < 32; i++)
- if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
- branch = i;
-
- branch = branch % interval;
- for (i = branch; i < 32; i += interval)
- ohci->ohci_int_load [i] += load;
-
- return branch;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* 2^int( ld (inter)) */
-
-static int ep_2_n_interval(int inter)
-{
- int i;
- for (i = 0; ((inter >> i) > 1) && (i < 5); i++);
- return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* the int tree is a binary tree
- * in order to process it sequentially the indexes of the branches have to
- * be mapped the mapping reverses the bits of a word of num_bits length */
-static int ep_rev(int num_bits, int word)
-{
- int i, wout = 0;
-
- for (i = 0; i < num_bits; i++)
- wout |= (((word >> i) & 1) << (num_bits - i - 1));
- return wout;
-}
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link(ohci_t *ohci, ed_t *edi)
-{
- volatile ed_t *ed = edi;
- int int_branch;
- int i;
- int inter;
- int interval;
- int load;
- __u32 *ed_p;
-
- ed->state = ED_OPER;
- ed->int_interval = 0;
-
- switch (ed->type) {
- case PIPE_CONTROL:
- ed->hwNextED = 0;
- if (ohci->ed_controltail == NULL)
- writel(ed, &ohci->regs->ed_controlhead);
- else
- ohci->ed_controltail->hwNextED =
- m32_swap((unsigned long)ed);
-
- ed->ed_prev = ohci->ed_controltail;
- if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_CLE;
- writel(ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_controltail = edi;
- break;
-
- case PIPE_BULK:
- ed->hwNextED = 0;
- if (ohci->ed_bulktail == NULL)
- writel(ed, &ohci->regs->ed_bulkhead);
- else
- ohci->ed_bulktail->hwNextED =
- m32_swap((unsigned long)ed);
-
- ed->ed_prev = ohci->ed_bulktail;
- if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_BLE;
- writel(ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_bulktail = edi;
- break;
-
- case PIPE_INTERRUPT:
- load = ed->int_load;
- interval = ep_2_n_interval(ed->int_period);
- ed->int_interval = interval;
- int_branch = ep_int_ballance(ohci, interval, load);
- ed->int_branch = int_branch;
-
- for (i = 0; i < ep_rev(6, interval); i += inter) {
- inter = 1;
- for (ed_p = &(ohci->hcca->int_table[\
- ep_rev(5, i) + int_branch]);
- (*ed_p != 0) &&
- (((ed_t *)ed_p)->int_interval >= interval);
- ed_p = &(((ed_t *)ed_p)->hwNextED))
- inter = ep_rev(6,
- ((ed_t *)ed_p)->int_interval);
- ed->hwNextED = *ed_p;
- *ed_p = m32_swap((unsigned long)ed);
- }
- break;
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* scan the periodic table to find and unlink this ED */
-static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
- unsigned index, unsigned period)
-{
- for (; index < NUM_INTS; index += period) {
- __u32 *ed_p = &ohci->hcca->int_table [index];
-
- /* ED might have been unlinked through another path */
- while (*ed_p != 0) {
- if (((struct ed *)
- m32_swap((unsigned long)ed_p)) == ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- ed_p = &(((struct ed *)
- m32_swap((unsigned long)ed_p))->hwNextED);
- }
- }
-}
-
-/* unlink an ed from one of the HC chains.
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink(ohci_t *ohci, ed_t *edi)
-{
- volatile ed_t *ed = edi;
- int i;
-
- ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
-
- switch (ed->type) {
- case PIPE_CONTROL:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_CLE;
- writel(ohci->hc_control, &ohci->regs->control);
- }
- writel(m32_swap(*((__u32 *)&ed->hwNextED)),
- &ohci->regs->ed_controlhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_controltail == ed) {
- ohci->ed_controltail = ed->ed_prev;
- } else {
- ((ed_t *)m32_swap(
- *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
-
- case PIPE_BULK:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_BLE;
- writel(ohci->hc_control, &ohci->regs->control);
- }
- writel(m32_swap(*((__u32 *)&ed->hwNextED)),
- &ohci->regs->ed_bulkhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_bulktail == ed) {
- ohci->ed_bulktail = ed->ed_prev;
- } else {
- ((ed_t *)m32_swap(
- *((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
-
- case PIPE_INTERRUPT:
- periodic_unlink(ohci, ed, 0, 1);
- for (i = ed->int_branch; i < 32; i += ed->int_interval)
- ohci->ohci_int_load[i] -= ed->int_load;
- break;
- }
- ed->state = ED_UNLINK;
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the
- * usb_set_configuration command, but the USB stack is a little bit
- * stateless so we do it at every transaction if the state of the ed
- * is ED_NEW then a dummy td is added and the state is changed to
- * ED_UNLINK in all other cases the state is left unchanged the ed
- * info fields are setted anyway even though most of them should not
- * change
- */
-static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
- int interval, int load)
-{
- td_t *td;
- ed_t *ed_ret;
- volatile ed_t *ed;
-
- ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
- (usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
-
- if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
- err("ep_add_ed: pending delete");
- /* pending delete request */
- return NULL;
- }
-
- if (ed->state == ED_NEW) {
- /* dummy td; end of td list for ed */
- td = td_alloc(usb_dev);
- ed->hwTailP = m32_swap((unsigned long)td);
- ed->hwHeadP = ed->hwTailP;
- ed->state = ED_UNLINK;
- ed->type = usb_pipetype(pipe);
- ohci_dev.ed_cnt++;
- }
-
- ed->hwINFO = m32_swap(usb_pipedevice(pipe)
- | usb_pipeendpoint(pipe) << 7
- | (usb_pipeisoc(pipe)? 0x8000: 0)
- | (usb_pipecontrol(pipe)? 0: \
- (usb_pipeout(pipe)? 0x800: 0x1000))
- | usb_pipeslow(pipe) << 13
- | usb_maxpacket(usb_dev, pipe) << 16);
-
- if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
- ed->int_period = interval;
- ed->int_load = load;
- }
-
- return ed_ret;
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-
-static void td_fill(ohci_t *ohci, unsigned int info,
- void *data, int len,
- struct usb_device *dev, int index, urb_priv_t *urb_priv)
-{
- volatile td_t *td, *td_pt;
-#ifdef OHCI_FILL_TRACE
- int i;
-#endif
-
- if (index > urb_priv->length) {
- err("index > length");
- return;
- }
- /* use this td as the next dummy */
- td_pt = urb_priv->td [index];
- td_pt->hwNextTD = 0;
-
- /* fill the old dummy TD */
- td = urb_priv->td [index] =
- (td_t *)(m32_swap(urb_priv->ed->hwTailP) & ~0xf);
-
- td->ed = urb_priv->ed;
- td->next_dl_td = NULL;
- td->index = index;
- td->data = (__u32)data;
-#ifdef OHCI_FILL_TRACE
- if (usb_pipebulk(urb_priv->pipe) && usb_pipeout(urb_priv->pipe)) {
- for (i = 0; i < len; i++)
- printf("td->data[%d] %#2x ", i, ((unsigned char *)td->data)[i]);
- printf("\n");
- }
-#endif
- if (!len)
- data = 0;
-
- td->hwINFO = m32_swap(info);
- td->hwCBP = m32_swap((unsigned long)data);
- if (data)
- td->hwBE = m32_swap((unsigned long)(data + len - 1));
- else
- td->hwBE = 0;
-
- td->hwNextTD = m32_swap((unsigned long)td_pt);
-
- /* append to queue */
- td->ed->hwTailP = td->hwNextTD;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare all TDs of a transfer */
-
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len,
- struct devrequest *setup, urb_priv_t *urb,
- int interval)
-{
- ohci_t *ohci = &gohci;
- int data_len = transfer_len;
- void *data;
- int cnt = 0;
- __u32 info = 0;
- unsigned int toggle = 0;
-
- /* OHCI handles the DATA-toggles itself, we just use the USB-toggle
- * bits for reseting */
- if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
- toggle = TD_T_TOGGLE;
- } else {
- toggle = TD_T_DATA0;
- usb_settoggle(dev, usb_pipeendpoint(pipe),
- usb_pipeout(pipe), 1);
- }
- urb->td_cnt = 0;
- if (data_len)
- data = buffer;
- else
- data = 0;
-
- switch (usb_pipetype(pipe)) {
- case PIPE_BULK:
- info = usb_pipeout(pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
- while (data_len > 4096) {
- td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle),
- data, 4096, dev, cnt, urb);
- data += 4096; data_len -= 4096; cnt++;
- }
- info = usb_pipeout(pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill(ohci, info | (cnt? TD_T_TOGGLE:toggle), data,
- data_len, dev, cnt, urb);
- cnt++;
-
- if (!ohci->sleeping) {
- /* start bulk list */
- writel(OHCI_BLF, &ohci->regs->cmdstatus);
- }
- break;
-
- case PIPE_CONTROL:
- /* Setup phase */
- info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill(ohci, info, setup, 8, dev, cnt++, urb);
-
- /* Optional Data phase */
- if (data_len > 0) {
- info = usb_pipeout(pipe)?
- TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 :
- TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
- /* NOTE: mishandles transfers >8K, some >4K */
- td_fill(ohci, info, data, data_len, dev, cnt++, urb);
- }
-
- /* Status phase */
- info = usb_pipeout(pipe)?
- TD_CC | TD_DP_IN | TD_T_DATA1:
- TD_CC | TD_DP_OUT | TD_T_DATA1;
- td_fill(ohci, info, data, 0, dev, cnt++, urb);
-
- if (!ohci->sleeping) {
- /* start Control list */
- writel(OHCI_CLF, &ohci->regs->cmdstatus);
- }
- break;
-
- case PIPE_INTERRUPT:
- info = usb_pipeout(urb->pipe)?
- TD_CC | TD_DP_OUT | toggle:
- TD_CC | TD_R | TD_DP_IN | toggle;
- td_fill(ohci, info, data, data_len, dev, cnt++, urb);
- break;
- }
- if (urb->length != cnt)
- dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length(td_t *td)
-{
- __u32 tdINFO, tdBE, tdCBP;
- urb_priv_t *lurb_priv = td->ed->purb;
-
- tdINFO = m32_swap(td->hwINFO);
- tdBE = m32_swap(td->hwBE);
- tdCBP = m32_swap(td->hwCBP);
-
- if (!(usb_pipecontrol(lurb_priv->pipe) &&
- ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
- if (tdBE != 0) {
- if (td->hwCBP == 0)
- lurb_priv->actual_length += tdBE - td->data + 1;
- else
- lurb_priv->actual_length += tdCBP - td->data;
- }
- }
-}
-
-/*-------------------------------------------------------------------------*/
-static void check_status(td_t *td_list)
-{
- urb_priv_t *lurb_priv = td_list->ed->purb;
- int urb_len = lurb_priv->length;
- __u32 *phwHeadP = &td_list->ed->hwHeadP;
- int cc;
-
- cc = TD_CC_GET(m32_swap(td_list->hwINFO));
- if (cc) {
- err(" USB-error: %s (%x)", cc_to_string[cc], cc);
-
- if (*phwHeadP & m32_swap(0x1)) {
- if (lurb_priv &&
- ((td_list->index + 1) < urb_len)) {
- *phwHeadP =
- (lurb_priv->td[urb_len - 1]->hwNextTD &\
- m32_swap(0xfffffff0)) |
- (*phwHeadP & m32_swap(0x2));
-
- lurb_priv->td_cnt += urb_len -
- td_list->index - 1;
- } else
- *phwHeadP &= m32_swap(0xfffffff2);
- }
-#ifdef CONFIG_MPC5200
- td_list->hwNextTD = 0;
-#endif
- }
-}
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
-static td_t *dl_reverse_done_list(ohci_t *ohci)
-{
- __u32 td_list_hc;
- td_t *td_rev = NULL;
- td_t *td_list = NULL;
-
- td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
- ohci->hcca->done_head = 0;
-
- while (td_list_hc) {
- td_list = (td_t *)td_list_hc;
- check_status(td_list);
- td_list->next_dl_td = td_rev;
- td_rev = td_list;
- td_list_hc = m32_swap(td_list->hwNextTD) & 0xfffffff0;
- }
- return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-/*-------------------------------------------------------------------------*/
-
-static void finish_urb(ohci_t *ohci, urb_priv_t *urb, int status)
-{
- if ((status & (ED_OPER | ED_UNLINK)) && (urb->state != URB_DEL))
- urb->finished = sohci_return_job(ohci, urb);
- else
- dbg("finish_urb: strange.., ED state %x, \n", status);
-}
-
-/*
- * Used to take back a TD from the host controller. This would normally be
- * called from within dl_done_list, however it may be called directly if the
- * HC no longer sees the TD and it has not appeared on the donelist (after
- * two frames). This bug has been observed on ZF Micro systems.
- */
-static int takeback_td(ohci_t *ohci, td_t *td_list)
-{
- ed_t *ed;
- int cc;
- int stat = 0;
- /* urb_t *urb; */
- urb_priv_t *lurb_priv;
- __u32 tdINFO, edHeadP, edTailP;
-
- tdINFO = m32_swap(td_list->hwINFO);
-
- ed = td_list->ed;
- lurb_priv = ed->purb;
-
- dl_transfer_length(td_list);
-
- lurb_priv->td_cnt++;
-
- /* error code of transfer */
- cc = TD_CC_GET(tdINFO);
- if (cc) {
- err("USB-error: %s (%x)", cc_to_string[cc], cc);
- stat = cc_to_error[cc];
- }
-
- /* see if this done list makes for all TD's of current URB,
- * and mark the URB finished if so */
- if (lurb_priv->td_cnt == lurb_priv->length)
- finish_urb(ohci, lurb_priv, ed->state);
-
- dbg("dl_done_list: processing TD %x, len %x\n",
- lurb_priv->td_cnt, lurb_priv->length);
-
- if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
- edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
- edTailP = m32_swap(ed->hwTailP);
-
- /* unlink eds if they are not busy */
- if ((edHeadP == edTailP) && (ed->state == ED_OPER))
- ep_unlink(ohci, ed);
- }
- return stat;
-}
-
-static int dl_done_list(ohci_t *ohci)
-{
- int stat = 0;
- td_t *td_list = dl_reverse_done_list(ohci);
-
- while (td_list) {
- td_t *td_next = td_list->next_dl_td;
- stat = takeback_td(ohci, td_list);
- td_list = td_next;
- }
- return stat;
-}
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x01, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 0x01, /* __u8 bConfigurationValue; */
- 0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
- 0x00, /* __u8 MaxPower; */
-
- /* interface */
- 0x09, /* __u8 if_bLength; */
- 0x04, /* __u8 if_bDescriptorType; Interface */
- 0x00, /* __u8 if_bInterfaceNumber; */
- 0x00, /* __u8 if_bAlternateSetting; */
- 0x01, /* __u8 if_bNumEndpoints; */
- 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* __u8 if_bInterfaceSubClass; */
- 0x00, /* __u8 if_bInterfaceProtocol; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 0x00,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] =
-{
- 0x04, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 0x09, /* __u8 lang ID */
- 0x04, /* __u8 lang ID */
-};
-
-static unsigned char root_hub_str_index1[] =
-{
- 28, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 'O', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'C', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'I', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'R', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 't', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'u', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'b', /* __u8 Unicode */
- 0, /* __u8 Unicode */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x) len = (x); break
-#ifdef DEBUG
-#define WR_RH_STAT(x) {info("WR:status %#8x", (x)); writel((x), \
- &gohci.regs->roothub.status); }
-#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \
- (x)); writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
-#else
-#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
-#define WR_RH_PORTSTAT(x) writel((x), \
- &gohci.regs->roothub.portstatus[wIndex-1])
-#endif
-#define RD_RH_STAT roothub_status(&gohci)
-#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1)
-
-/* request to virtual root hub */
-
-int rh_check_port_status(ohci_t *controller)
-{
- __u32 temp, ndp, i;
- int res;
-
- res = -1;
- temp = roothub_a(controller);
- ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- ndp = (ndp == 2) ? 1:0;
-#endif
- for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus(controller, i);
- /* check for a device disconnect */
- if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
- (RH_PS_PESC | RH_PS_CSC)) &&
- ((temp & RH_PS_CCS) == 0)) {
- res = i;
- break;
- }
- }
- return res;
-}
-
-static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len, struct devrequest *cmd)
-{
- void *data = buffer;
- int leni = transfer_len;
- int len = 0;
- int stat = 0;
- __u32 datab[4];
- __u8 *data_buf = (__u8 *)datab;
- __u16 bmRType_bReq;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
-
-#ifdef DEBUG
-pkt_print(NULL, dev, pipe, buffer, transfer_len,
- cmd, "SUB(rh)", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if (usb_pipeint(pipe)) {
- info("Root-Hub submit IRQ: NOT implemented");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = le16_to_cpu(cmd->value);
- wIndex = le16_to_cpu(cmd->index);
- wLength = le16_to_cpu(cmd->length);
-
- info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
- dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
-
- switch (bmRType_bReq) {
- /* Request Destination:
- without flags: Device,
- RH_INTERFACE: interface,
- RH_ENDPOINT: endpoint,
- RH_CLASS means HUB here,
- RH_OTHER | RH_CLASS almost ever means HUB_PORT here
- */
-
- case RH_GET_STATUS:
- *(__u16 *) data_buf = cpu_to_le16(1);
- OK(2);
- case RH_GET_STATUS | RH_INTERFACE:
- *(__u16 *) data_buf = cpu_to_le16(0);
- OK(2);
- case RH_GET_STATUS | RH_ENDPOINT:
- *(__u16 *) data_buf = cpu_to_le16(0);
- OK(2);
- case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32(
- RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
- OK(4);
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- *(__u32 *) data_buf = cpu_to_le32(RD_RH_PORTSTAT);
- OK(4);
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- switch (wValue) {
- case (RH_ENDPOINT_STALL):
- OK(0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- OK(0);
- case (RH_C_HUB_OVER_CURRENT):
- WR_RH_STAT(RH_HS_OCIC);
- OK(0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_CCS); OK(0);
- case (RH_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_POCI); OK(0);
- case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_LSDA); OK(0);
- case (RH_C_PORT_CONNECTION): WR_RH_PORTSTAT(RH_PS_CSC); OK(0);
- case (RH_C_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_PESC); OK(0);
- case (RH_C_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_PSSC); OK(0);
- case (RH_C_PORT_OVER_CURRENT):WR_RH_PORTSTAT(RH_PS_OCIC); OK(0);
- case (RH_C_PORT_RESET): WR_RH_PORTSTAT(RH_PS_PRSC); OK(0);
- }
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT(RH_PS_PSS); OK(0);
- case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT(RH_PS_PRS);
- OK(0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT(RH_PS_PPS);
- wait_ms(100);
- OK(0);
- case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT(RH_PS_PES);
- OK(0);
- }
- break;
-
- case RH_SET_ADDRESS:
- gohci.rh.devnum = wValue;
- OK(0);
-
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des; OK(len);
- case (0x02): /* configuration descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des; OK(len);
- case (0x03): /* string descriptors */
- if (wValue == 0x0300) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_str_index0),
- wLength));
- data_buf = root_hub_str_index0;
- OK(len);
- }
- if (wValue == 0x0301) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof(root_hub_str_index1),
- wLength));
- data_buf = root_hub_str_index1;
- OK(len);
- }
- default:
- stat = USB_ST_STALLED;
- }
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS:
- {
- __u32 temp = roothub_a(&gohci);
-
- data_buf [0] = 9; /* min length; */
- data_buf [1] = 0x29;
- data_buf [2] = temp & RH_A_NDP;
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- data_buf [2] = (data_buf [2] == 2) ? 1:0;
-#endif
- data_buf [3] = 0;
- if (temp & RH_A_PSM) /* per-port power switching? */
- data_buf [3] |= 0x1;
- if (temp & RH_A_NOCP) /* no overcurrent reporting? */
- data_buf [3] |= 0x10;
- else if (temp & RH_A_OCPM)/* per-port overcurrent reporting? */
- data_buf [3] |= 0x8;
-
- /* corresponds to data_buf[4-7] */
- datab [1] = 0;
- data_buf [5] = (temp & RH_A_POTPGT) >> 24;
- temp = roothub_b(&gohci);
- data_buf [7] = temp & RH_B_DR;
- if (data_buf [2] < 7) {
- data_buf [8] = 0xff;
- } else {
- data_buf [0] += 2;
- data_buf [8] = (temp & RH_B_DR) >> 8;
- data_buf [10] = data_buf [9] = 0xff;
- }
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data_buf [0], wLength));
- OK(len);
- }
-
- case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK(1);
-
- case RH_SET_CONFIGURATION: WR_RH_STAT(0x10000); OK(0);
-
- default:
- dbg("unsupported root hub command");
- stat = USB_ST_STALLED;
- }
-
-#ifdef DEBUG
- ohci_dump_roothub(&gohci, 1);
-#else
- wait_ms(1);
-#endif
-
- len = min_t(int, len, leni);
- if (data != data_buf)
- memcpy(data, data_buf, len);
- dev->act_len = len;
- dev->status = stat;
-
-#ifdef DEBUG
- pkt_print(NULL, dev, pipe, buffer,
- transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
-#else
- wait_ms(1);
-#endif
-
- return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* common code for handling submit messages - used for all but root hub */
-/* accesses. */
-int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup, int interval)
-{
- int stat = 0;
- int maxsize = usb_maxpacket(dev, pipe);
- int timeout;
- urb_priv_t *urb;
-
- urb = malloc(sizeof(urb_priv_t));
- memset(urb, 0, sizeof(urb_priv_t));
-
- urb->dev = dev;
- urb->pipe = pipe;
- urb->transfer_buffer = buffer;
- urb->transfer_buffer_length = transfer_len;
- urb->interval = interval;
-
- /* device pulled? Shortcut the action. */
- if (devgone == dev) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
-
-#ifdef DEBUG
- urb->actual_length = 0;
- pkt_print(urb, dev, pipe, buffer, transfer_len,
- setup, "SUB", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if (!maxsize) {
- err("submit_common_message: pipesize for pipe %lx is zero",
- pipe);
- return -1;
- }
-
- if (sohci_submit_job(urb, setup) < 0) {
- err("sohci_submit_job failed");
- return -1;
- }
-
-#if 0
- wait_ms(10);
- /* ohci_dump_status(&gohci); */
-#endif
-
- /* allow more time for a BULK device to react - some are slow */
-#define BULK_TO 5000 /* timeout in milliseconds */
- if (usb_pipebulk(pipe))
- timeout = BULK_TO;
- else
- timeout = 100;
-
- /* wait for it to complete */
- for (;;) {
- /* check whether the controller is done */
- stat = hc_interrupt();
- if (stat < 0) {
- stat = USB_ST_CRC_ERR;
- break;
- }
-
- /* NOTE: since we are not interrupt driven in U-Boot and always
- * handle only one URB at a time, we cannot assume the
- * transaction finished on the first successful return from
- * hc_interrupt().. unless the flag for current URB is set,
- * meaning that all TD's to/from device got actually
- * transferred and processed. If the current URB is not
- * finished we need to re-iterate this loop so as
- * hc_interrupt() gets called again as there needs to be some
- * more TD's to process still */
- if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
- /* 0xff is returned for an SF-interrupt */
- break;
- }
-
- if (--timeout) {
- wait_ms(1);
- if (!urb->finished)
- dbg("*");
-
- } else {
- err("CTL:TIMEOUT ");
- dbg("submit_common_msg: TO status %x\n", stat);
- urb->finished = 1;
- stat = USB_ST_CRC_ERR;
- break;
- }
- }
-
- dev->status = stat;
- dev->act_len = transfer_len;
-
-#ifdef DEBUG
- pkt_print(urb, dev, pipe, buffer, transfer_len,
- setup, "RET(ctlr)", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
-
- /* free TDs in urb_priv */
- if (!usb_pipeint(pipe))
- urb_free_priv(urb);
- return 0;
-}
-
-/* submit routines called from usb.c */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len)
-{
- info("submit_bulk_msg");
- return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup)
-{
- int maxsize = usb_maxpacket(dev, pipe);
-
- info("submit_control_msg");
-#ifdef DEBUG
- pkt_print(NULL, dev, pipe, buffer, transfer_len,
- setup, "SUB", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if (!maxsize) {
- err("submit_control_message: pipesize for pipe %lx is zero",
- pipe);
- return -1;
- }
- if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
- gohci.rh.dev = dev;
- /* root hub - redirect */
- return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
- setup);
- }
-
- return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, int interval)
-{
- info("submit_int_msg");
- return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
- interval);
-}
-
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC and BUS */
-
-static int hc_reset(ohci_t *ohci)
-{
-#ifdef CONFIG_PCI_EHCI_DEVNO
- pci_dev_t pdev;
-#endif
- int timeout = 30;
- int smm_timeout = 50; /* 0,5 sec */
-
- dbg("%s\n", __FUNCTION__);
-
-#ifdef CONFIG_PCI_EHCI_DEVNO
- /*
- * Some multi-function controllers (e.g. ISP1562) allow root hub
- * resetting via EHCI registers only.
- */
- pdev = pci_find_devices(ehci_pci_ids, CONFIG_PCI_EHCI_DEVNO);
- if (pdev != -1) {
- u32 base;
- int timeout = 1000;
-
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
- writel(readl(base + EHCI_USBCMD_OFF) | EHCI_USBCMD_HCRESET,
- base + EHCI_USBCMD_OFF);
-
- while (readl(base + EHCI_USBCMD_OFF) & EHCI_USBCMD_HCRESET) {
- if (timeout-- <= 0) {
- printf("USB RootHub reset timed out!");
- break;
- }
- udelay(1);
- }
- } else
- printf("No EHCI func at %d index!\n", CONFIG_PCI_EHCI_DEVNO);
-#endif
- if (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
- /* SMM owns the HC */
- writel(OHCI_OCR, &ohci->regs->cmdstatus);/* request ownership */
- info("USB HC TakeOver from SMM");
- while (readl(&ohci->regs->control) & OHCI_CTRL_IR) {
- wait_ms(10);
- if (--smm_timeout == 0) {
- err("USB HC TakeOver failed!");
- return -1;
- }
- }
- }
-
- /* Disable HC interrupts */
- writel(OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
- dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
- ohci->slot_name,
- readl(&ohci->regs->control));
-
- /* Reset USB (needed by some controllers) */
- ohci->hc_control = 0;
- writel(ohci->hc_control, &ohci->regs->control);
-
- /* HC Reset requires max 10 us delay */
- writel(OHCI_HCR, &ohci->regs->cmdstatus);
- while ((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
- if (--timeout == 0) {
- err("USB HC reset timed out!");
- return -1;
- }
- udelay(1);
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts
- * connect the virtual root hub */
-
-static int hc_start(ohci_t *ohci)
-{
- __u32 mask;
- unsigned int fminterval;
-
- ohci->disabled = 1;
-
- /* Tell the controller where the control and bulk lists are
- * The lists are empty now. */
-
- writel(0, &ohci->regs->ed_controlhead);
- writel(0, &ohci->regs->ed_bulkhead);
-
- writel((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
-
- fminterval = 0x2edf;
- writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
- fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
- writel(fminterval, &ohci->regs->fminterval);
- writel(0x628, &ohci->regs->lsthresh);
-
- /* start controller operations */
- ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci->disabled = 0;
- writel(ohci->hc_control, &ohci->regs->control);
-
- /* disable all interrupts */
- mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
- OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
- OHCI_INTR_OC | OHCI_INTR_MIE);
- writel(mask, &ohci->regs->intrdisable);
- /* clear all interrupts */
- mask &= ~OHCI_INTR_MIE;
- writel(mask, &ohci->regs->intrstatus);
- /* Choose the interrupts we care about now - but w/o MIE */
- mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
- writel(mask, &ohci->regs->intrenable);
-
-#ifdef OHCI_USE_NPS
- /* required for AMD-756 and some Mac platforms */
- writel((roothub_a(ohci) | RH_A_NPS) & ~RH_A_PSM,
- &ohci->regs->roothub.a);
- writel(RH_HS_LPSC, &ohci->regs->roothub.status);
-#endif /* OHCI_USE_NPS */
-
-#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
- /* POTPGT delay is bits 24-31, in 2 ms units. */
- mdelay((roothub_a(ohci) >> 23) & 0x1fe);
-
- /* connect the virtual root hub */
- ohci->rh.devnum = 0;
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Poll USB interrupt. */
-void usb_event_poll(void)
-{
- hc_interrupt();
-}
-
-/* an interrupt happens */
-
-static int hc_interrupt(void)
-{
- ohci_t *ohci = &gohci;
- struct ohci_regs *regs = ohci->regs;
- int ints;
- int stat = -1;
-
- if ((ohci->hcca->done_head != 0) &&
- !(m32_swap(ohci->hcca->done_head) & 0x01)) {
- ints = OHCI_INTR_WDH;
- } else {
- ints = readl(®s->intrstatus);
- if (ints == ~(u32)0) {
- ohci->disabled++;
- err("%s device removed!", ohci->slot_name);
- return -1;
- } else {
- ints &= readl(®s->intrenable);
- if (ints == 0) {
- dbg("hc_interrupt: returning..\n");
- return 0xff;
- }
- }
- }
-
- /* dbg("Interrupt: %x frame: %x", ints,
- le16_to_cpu(ohci->hcca->frame_no)); */
-
- if (ints & OHCI_INTR_RHSC)
- stat = 0xff;
-
- if (ints & OHCI_INTR_UE) {
- ohci->disabled++;
- err("OHCI Unrecoverable Error, controller usb-%s disabled",
- ohci->slot_name);
- /* e.g. due to PCI Master/Target Abort */
-
-#ifdef DEBUG
- ohci_dump(ohci, 1);
-#else
- wait_ms(1);
-#endif
- /* FIXME: be optimistic, hope that bug won't repeat often. */
- /* Make some non-interrupt context restart the controller. */
- /* Count and limit the retries though; either hardware or */
- /* software errors can go forever... */
- hc_reset(ohci);
- return -1;
- }
-
- if (ints & OHCI_INTR_WDH) {
- wait_ms(1);
- writel(OHCI_INTR_WDH, ®s->intrdisable);
- (void)readl(®s->intrdisable); /* flush */
- stat = dl_done_list(&gohci);
- writel(OHCI_INTR_WDH, ®s->intrenable);
- (void)readl(®s->intrdisable); /* flush */
- }
-
- if (ints & OHCI_INTR_SO) {
- dbg("USB Schedule overrun\n");
- writel(OHCI_INTR_SO, ®s->intrenable);
- stat = -1;
- }
-
- /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
- if (ints & OHCI_INTR_SF) {
- unsigned int frame = m16_swap(ohci->hcca->frame_no) & 1;
- wait_ms(1);
- writel(OHCI_INTR_SF, ®s->intrdisable);
- if (ohci->ed_rm_list[frame] != NULL)
- writel(OHCI_INTR_SF, ®s->intrenable);
- stat = 0xff;
- }
-
- writel(ints, ®s->intrstatus);
- return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci(ohci_t *ohci)
-{
- dbg("USB HC release ohci usb-%s", ohci->slot_name);
-
- if (!ohci->disabled)
- hc_reset(ohci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * low level initalisation routine, called from usb.c
- */
-static char ohci_inited = 0;
-
-int usb_lowlevel_init(void)
-{
-#ifdef CONFIG_PCI_OHCI
- pci_dev_t pdev;
-#endif
-
-#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
- /* cpu dependant init */
- if (usb_cpu_init())
- return -1;
-#endif
-
-#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
- /* board dependant init */
- if (usb_board_init())
- return -1;
-#endif
- memset(&gohci, 0, sizeof(ohci_t));
-
- /* align the storage */
- if ((__u32)&ghcca[0] & 0xff) {
- err("HCCA not aligned!!");
- return -1;
- }
- phcca = &ghcca[0];
- info("aligned ghcca %p", phcca);
- memset(&ohci_dev, 0, sizeof(struct ohci_device));
- if ((__u32)&ohci_dev.ed[0] & 0x7) {
- err("EDs not aligned!!");
- return -1;
- }
- memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
- if ((__u32)gtd & 0x7) {
- err("TDs not aligned!!");
- return -1;
- }
- ptd = gtd;
- gohci.hcca = phcca;
- memset(phcca, 0, sizeof(struct ohci_hcca));
-
- gohci.disabled = 1;
- gohci.sleeping = 0;
- gohci.irq = -1;
-#ifdef CONFIG_PCI_OHCI
- pdev = pci_find_devices(ohci_pci_ids, CONFIG_PCI_OHCI_DEVNO);
-
- if (pdev != -1) {
- u16 vid, did;
- u32 base;
- pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
- pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
- printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
- vid, did, (pdev >> 16) & 0xff,
- (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
- pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
- printf("OHCI regs address 0x%08x\n", base);
- gohci.regs = (struct ohci_regs *)base;
- } else
- return -1;
-#else
- gohci.regs = (struct ohci_regs *)CONFIG_SYS_USB_OHCI_REGS_BASE;
-#endif
-
- gohci.flags = 0;
- gohci.slot_name = CONFIG_SYS_USB_OHCI_SLOT_NAME;
-
- if (hc_reset (&gohci) < 0) {
- hc_release_ohci (&gohci);
- err ("can't reset usb-%s", gohci.slot_name);
-#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
- /* board dependant cleanup */
- usb_board_init_fail();
-#endif
-
-#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
- /* cpu dependant cleanup */
- usb_cpu_init_fail();
-#endif
- return -1;
- }
-
- if (hc_start(&gohci) < 0) {
- err("can't start usb-%s", gohci.slot_name);
- hc_release_ohci(&gohci);
- /* Initialization failed */
-#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
- /* board dependant cleanup */
- usb_board_stop();
-#endif
-
-#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
- /* cpu dependant cleanup */
- usb_cpu_stop();
-#endif
- return -1;
- }
-
-#ifdef DEBUG
- ohci_dump(&gohci, 1);
-#else
- wait_ms(1);
-#endif
- ohci_inited = 1;
- return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
- /* this gets called really early - before the controller has */
- /* even been initialized! */
- if (!ohci_inited)
- return 0;
- /* TODO release any interrupts, etc. */
- /* call hc_release_ohci() here ? */
- hc_reset(&gohci);
-
-#ifdef CONFIG_SYS_USB_OHCI_BOARD_INIT
- /* board dependant cleanup */
- if (usb_board_stop())
- return -1;
-#endif
-
-#ifdef CONFIG_SYS_USB_OHCI_CPU_INIT
- /* cpu dependant cleanup */
- if (usb_cpu_stop())
- return -1;
-#endif
- /* This driver is no longer initialised. It needs a new low-level
- * init (board/cpu) before it can be used again. */
- ohci_inited = 0;
- return 0;
-}
+++ /dev/null
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- *
- * usb-ohci.h
- */
-
-/* functions for doing board or CPU specific setup/cleanup */
-extern int usb_board_init(void);
-extern int usb_board_stop(void);
-extern int usb_board_init_fail(void);
-
-extern int usb_cpu_init(void);
-extern int usb_cpu_stop(void);
-extern int usb_cpu_init_fail(void);
-
-
-static int cc_to_error[16] = {
-
-/* mapping of the OHCI CC status to error codes */
- /* No Error */ 0,
- /* CRC Error */ USB_ST_CRC_ERR,
- /* Bit Stuff */ USB_ST_BIT_ERR,
- /* Data Togg */ USB_ST_CRC_ERR,
- /* Stall */ USB_ST_STALLED,
- /* DevNotResp */ -1,
- /* PIDCheck */ USB_ST_BIT_ERR,
- /* UnExpPID */ USB_ST_BIT_ERR,
- /* DataOver */ USB_ST_BUF_ERR,
- /* DataUnder */ USB_ST_BUF_ERR,
- /* reservd */ -1,
- /* reservd */ -1,
- /* BufferOver */ USB_ST_BUF_ERR,
- /* BuffUnder */ USB_ST_BUF_ERR,
- /* Not Access */ -1,
- /* Not Access */ -1
-};
-
-static const char *cc_to_string[16] = {
- "No Error",
- "CRC: Last data packet from endpoint contained a CRC error.",
- "BITSTUFFING: Last data packet from endpoint contained a bit " \
- "stuffing violation",
- "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
- "that did not match the expected value.",
- "STALL: TD was moved to the Done Queue because the endpoint returned" \
- " a STALL PID",
- "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
- "not provide a handshake (OUT)",
- "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
- "(IN) or handshake (OUT)",
- "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
- "value is not defined.",
- "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
- "either the size of the maximum data packet allowed\n" \
- "from the endpoint (found in MaximumPacketSize field\n" \
- "of ED) or the remaining buffer size.",
- "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
- "and that amount was not sufficient to fill the\n" \
- "specified buffer",
- "reserved1",
- "reserved2",
- "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
- "than it could be written to system memory",
- "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
- "system memory fast enough to keep up with data USB " \
- "data rate.",
- "NOT ACCESSED: This code is set by software before the TD is placed" \
- "on a list to be processed by the HC.(1)",
- "NOT ACCESSED: This code is set by software before the TD is placed" \
- "on a list to be processed by the HC.(2)",
-};
-
-/* ED States */
-
-#define ED_NEW 0x00
-#define ED_UNLINK 0x01
-#define ED_OPER 0x02
-#define ED_DEL 0x04
-#define ED_URB_DEL 0x08
-
-/* usb_ohci_ed */
-struct ed {
- __u32 hwINFO;
- __u32 hwTailP;
- __u32 hwHeadP;
- __u32 hwNextED;
-
- struct ed *ed_prev;
- __u8 int_period;
- __u8 int_branch;
- __u8 int_load;
- __u8 int_interval;
- __u8 state;
- __u8 type;
- __u16 last_iso;
- struct ed *ed_rm_list;
-
- struct usb_device *usb_dev;
- void *purb;
- __u32 unused[2];
-} __attribute((aligned(16)));
-typedef struct ed ed_t;
-
-
-/* TD info field */
-#define TD_CC 0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC 0x0C000000
-#define TD_T 0x03000000
-#define TD_T_DATA0 0x02000000
-#define TD_T_DATA1 0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R 0x00040000
-#define TD_DI 0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP 0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN 0x00100000
-#define TD_DP_OUT 0x00080000
-
-#define TD_ISO 0x00010000
-#define TD_DEL 0x00020000
-
-/* CC Codes */
-#define TD_CC_NOERROR 0x00
-#define TD_CC_CRC 0x01
-#define TD_CC_BITSTUFFING 0x02
-#define TD_CC_DATATOGGLEM 0x03
-#define TD_CC_STALL 0x04
-#define TD_DEVNOTRESP 0x05
-#define TD_PIDCHECKFAIL 0x06
-#define TD_UNEXPECTEDPID 0x07
-#define TD_DATAOVERRUN 0x08
-#define TD_DATAUNDERRUN 0x09
-#define TD_BUFFEROVERRUN 0x0C
-#define TD_BUFFERUNDERRUN 0x0D
-#define TD_NOTACCESSED 0x0F
-
-
-#define MAXPSW 1
-
-struct td {
- __u32 hwINFO;
- __u32 hwCBP; /* Current Buffer Pointer */
- __u32 hwNextTD; /* Next TD Pointer */
- __u32 hwBE; /* Memory Buffer End Pointer */
-
-/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
- __u16 hwPSW[MAXPSW];
-/* #endif */
- __u8 unused;
- __u8 index;
- struct ed *ed;
- struct td *next_dl_td;
- struct usb_device *usb_dev;
- int transfer_len;
- __u32 data;
-
- __u32 unused2[2];
-} __attribute((aligned(32)));
-typedef struct td td_t;
-
-#define OHCI_ED_SKIP (1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of. It must be 256-byte aligned.
- */
-
-#define NUM_INTS 32 /* part of the OHCI standard */
-struct ohci_hcca {
- __u32 int_table[NUM_INTS]; /* Interrupt ED table */
-#if defined(CONFIG_MPC5200)
- __u16 pad1; /* set to 0 on each frame_no change */
- __u16 frame_no; /* current frame number */
-#else
- __u16 frame_no; /* current frame number */
- __u16 pad1; /* set to 0 on each frame_no change */
-#endif
- __u32 done_head; /* info returned for an interrupt */
- u8 reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-
-/*
- * Maximum number of root hub ports.
- */
-#ifndef CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS
-# error "CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS undefined!"
-#endif
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region. This is Memory Mapped I/O. You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
- /* control and status registers */
- __u32 revision;
- __u32 control;
- __u32 cmdstatus;
- __u32 intrstatus;
- __u32 intrenable;
- __u32 intrdisable;
- /* memory pointers */
- __u32 hcca;
- __u32 ed_periodcurrent;
- __u32 ed_controlhead;
- __u32 ed_controlcurrent;
- __u32 ed_bulkhead;
- __u32 ed_bulkcurrent;
- __u32 donehead;
- /* frame counters */
- __u32 fminterval;
- __u32 fmremaining;
- __u32 fmnumber;
- __u32 periodicstart;
- __u32 lsthresh;
- /* Root hub ports */
- struct ohci_roothub_regs {
- __u32 a;
- __u32 b;
- __u32 status;
- __u32 portstatus[CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS];
- } roothub;
-} __attribute((aligned(32)));
-
-/* Some EHCI controls */
-#define EHCI_USBCMD_OFF 0x20
-#define EHCI_USBCMD_HCRESET (1 << 1)
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
-#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
-#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
-#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
-#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
-#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
-#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
-#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
-#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-# define OHCI_USB_RESET (0 << 6)
-# define OHCI_USB_RESUME (1 << 6)
-# define OHCI_USB_OPER (2 << 6)
-# define OHCI_USB_SUSPEND (3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR (1 << 0) /* host controller reset */
-#define OHCI_CLF (1 << 1) /* control list filled */
-#define OHCI_BLF (1 << 2) /* bulk list filled */
-#define OHCI_OCR (1 << 3) /* ownership change request */
-#define OHCI_SOC (3 << 16) /* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
-#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
-#define OHCI_INTR_SF (1 << 2) /* start frame */
-#define OHCI_INTR_RD (1 << 3) /* resume detect */
-#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
-#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
-#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
-#define OHCI_INTR_OC (1 << 30) /* ownership change */
-#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
- int devnum; /* Address of Root Hub endpoint */
- void *dev; /* was urb */
- void *int_addr;
- int send;
- int interval;
-};
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
-
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS 0x00000001 /* current connect status */
-#define RH_PS_PES 0x00000002 /* port enable status*/
-#define RH_PS_PSS 0x00000004 /* port suspend status */
-#define RH_PS_POCI 0x00000008 /* port over current indicator */
-#define RH_PS_PRS 0x00000010 /* port reset status */
-#define RH_PS_PPS 0x00000100 /* port power status */
-#define RH_PS_LSDA 0x00000200 /* low speed device attached */
-#define RH_PS_CSC 0x00010000 /* connect status change */
-#define RH_PS_PESC 0x00020000 /* port enable status change */
-#define RH_PS_PSSC 0x00040000 /* port suspend status change */
-#define RH_PS_OCIC 0x00080000 /* over current indicator change */
-#define RH_PS_PRSC 0x00100000 /* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS 0x00000001 /* local power status */
-#define RH_HS_OCI 0x00000002 /* over current indicator */
-#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
-#define RH_HS_LPSC 0x00010000 /* local power status change */
-#define RH_HS_OCIC 0x00020000 /* over current indicator change */
-#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR 0x0000ffff /* device removable flags */
-#define RH_B_PPCM 0xffff0000 /* port power control mask */
-
-/* roothub.a masks */
-#define RH_A_NDP (0xff << 0) /* number of downstream ports */
-#define RH_A_PSM (1 << 8) /* power switching mode */
-#define RH_A_NPS (1 << 9) /* no power switching */
-#define RH_A_DT (1 << 10) /* device type (mbz) */
-#define RH_A_OCPM (1 << 11) /* over current protection mode */
-#define RH_A_NOCP (1 << 12) /* no over current protection */
-#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
-
-/* urb */
-#define N_URB_TD 48
-typedef struct
-{
- ed_t *ed;
- __u16 length; /* number of tds associated with this request */
- __u16 td_cnt; /* number of tds already serviced */
- struct usb_device *dev;
- int state;
- unsigned long pipe;
- void *transfer_buffer;
- int transfer_buffer_length;
- int interval;
- int actual_length;
- int finished;
- td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
-} urb_priv_t;
-#define URB_DEL 1
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
- struct ohci_hcca *hcca; /* hcca */
- /*dma_addr_t hcca_dma;*/
-
- int irq;
- int disabled; /* e.g. got a UE, we're hung */
- int sleeping;
- unsigned long flags; /* for HC bugs */
-
- struct ohci_regs *regs; /* OHCI controller's memory */
-
- int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/
- ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
- ed_t *ed_bulktail; /* last endpoint of bulk list */
- ed_t *ed_controltail; /* last endpoint of control list */
- int intrstatus;
- __u32 hc_control; /* copy of the hc control reg */
- struct usb_device *dev[32];
- struct virt_root_hub rh;
-
- const char *slot_name;
-} ohci_t;
-
-#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
-
-struct ohci_device {
- ed_t ed[NUM_EDS];
- int ed_cnt;
-};
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
- int interval, int load);
-
-/*-------------------------------------------------------------------------*/
-
-/* we need more TDs than EDs */
-#define NUM_TD 64
-
-/* +1 so we can align the storage */
-td_t gtd[NUM_TD+1];
-/* pointers to aligned storage */
-td_t *ptd;
-
-/* TDs ... */
-static inline struct td *
-td_alloc (struct usb_device *usb_dev)
-{
- int i;
- struct td *td;
-
- td = NULL;
- for (i = 0; i < NUM_TD; i++)
- {
- if (ptd[i].usb_dev == NULL)
- {
- td = &ptd[i];
- td->usb_dev = usb_dev;
- break;
- }
- }
-
- return td;
-}
-
-static inline void
-ed_free (struct ed *ed)
-{
- ed->usb_dev = NULL;
-}
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usbd/usbd.c.c - USB Device Core Layer
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <malloc.h>
-#include "usbdcore.h"
-
-#define MAX_INTERFACES 2
-
-
-int maxstrings = 20;
-
-/* Global variables ************************************************************************** */
-
-struct usb_string_descriptor **usb_strings;
-
-int usb_devices;
-
-extern struct usb_function_driver ep0_driver;
-
-int registered_functions;
-int registered_devices;
-
-char *usbd_device_events[] = {
- "DEVICE_UNKNOWN",
- "DEVICE_INIT",
- "DEVICE_CREATE",
- "DEVICE_HUB_CONFIGURED",
- "DEVICE_RESET",
- "DEVICE_ADDRESS_ASSIGNED",
- "DEVICE_CONFIGURED",
- "DEVICE_SET_INTERFACE",
- "DEVICE_SET_FEATURE",
- "DEVICE_CLEAR_FEATURE",
- "DEVICE_DE_CONFIGURED",
- "DEVICE_BUS_INACTIVE",
- "DEVICE_BUS_ACTIVITY",
- "DEVICE_POWER_INTERRUPTION",
- "DEVICE_HUB_RESET",
- "DEVICE_DESTROY",
- "DEVICE_FUNCTION_PRIVATE",
-};
-
-char *usbd_device_states[] = {
- "STATE_INIT",
- "STATE_CREATED",
- "STATE_ATTACHED",
- "STATE_POWERED",
- "STATE_DEFAULT",
- "STATE_ADDRESSED",
- "STATE_CONFIGURED",
- "STATE_UNKNOWN",
-};
-
-char *usbd_device_requests[] = {
- "GET STATUS", /* 0 */
- "CLEAR FEATURE", /* 1 */
- "RESERVED", /* 2 */
- "SET FEATURE", /* 3 */
- "RESERVED", /* 4 */
- "SET ADDRESS", /* 5 */
- "GET DESCRIPTOR", /* 6 */
- "SET DESCRIPTOR", /* 7 */
- "GET CONFIGURATION", /* 8 */
- "SET CONFIGURATION", /* 9 */
- "GET INTERFACE", /* 10 */
- "SET INTERFACE", /* 11 */
- "SYNC FRAME", /* 12 */
-};
-
-char *usbd_device_descriptors[] = {
- "UNKNOWN", /* 0 */
- "DEVICE", /* 1 */
- "CONFIG", /* 2 */
- "STRING", /* 3 */
- "INTERFACE", /* 4 */
- "ENDPOINT", /* 5 */
- "DEVICE QUALIFIER", /* 6 */
- "OTHER SPEED", /* 7 */
- "INTERFACE POWER", /* 8 */
-};
-
-char *usbd_device_status[] = {
- "USBD_OPENING",
- "USBD_OK",
- "USBD_SUSPENDED",
- "USBD_CLOSING",
-};
-
-
-/* Descriptor support functions ************************************************************** */
-
-
-/**
- * usbd_get_string - find and return a string descriptor
- * @index: string index to return
- *
- * Find an indexed string and return a pointer to a it.
- */
-struct usb_string_descriptor *usbd_get_string (__u8 index)
-{
- if (index >= maxstrings) {
- return NULL;
- }
- return usb_strings[index];
-}
-
-
-/* Access to device descriptor functions ***************************************************** */
-
-
-/* *
- * usbd_device_configuration_instance - find a configuration instance for this device
- * @device:
- * @configuration: index to configuration, 0 - N-1
- *
- * Get specifed device configuration. Index should be bConfigurationValue-1.
- */
-static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device,
- unsigned int port, unsigned int configuration)
-{
- if (configuration >= device->configurations)
- return NULL;
-
- return device->configuration_instance_array + configuration;
-}
-
-
-/* *
- * usbd_device_interface_instance
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface)
-{
- struct usb_configuration_instance *configuration_instance;
-
- if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) {
- return NULL;
- }
- if (interface >= configuration_instance->interfaces) {
- return NULL;
- }
- return configuration_instance->interface_instance_array + interface;
-}
-
-/* *
- * usbd_device_alternate_descriptor_list
- * @device:
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified alternate descriptor for the specified device.
- */
-struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate)
-{
- struct usb_interface_instance *interface_instance;
-
- if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) {
- return NULL;
- }
-
- if (alternate >= interface_instance->alternates) {
- return NULL;
- }
-
- return interface_instance->alternates_instance_array + alternate;
-}
-
-
-/* *
- * usbd_device_device_descriptor
- * @device: which device
- * @configuration: index to configuration, 0 - N-1
- * @port: which port
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port)
-{
- return (device->device_descriptor);
-}
-
-
-/**
- * usbd_device_configuration_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- *
- * Return the specified configuration descriptor for the specified device.
- */
-struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct
- usb_device_instance
- *device, int port, int configuration)
-{
- struct usb_configuration_instance *configuration_instance;
- if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) {
- return NULL;
- }
- return (configuration_instance->configuration_descriptor);
-}
-
-
-/**
- * usbd_device_interface_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- *
- * Return the specified interface descriptor for the specified device.
- */
-struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate)
-{
- struct usb_interface_instance *interface_instance;
- if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) {
- return NULL;
- }
- if ((alternate < 0) || (alternate >= interface_instance->alternates)) {
- return NULL;
- }
- return (interface_instance->alternates_instance_array[alternate].interface_descriptor);
-}
-
-/**
- * usbd_device_endpoint_descriptor_index
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: index setting
- * @index: which index
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance
- *device, int port, int configuration, int interface, int alternate, int index)
-{
- struct usb_alternate_instance *alternate_instance;
-
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return NULL;
- }
- if (index >= alternate_instance->endpoints) {
- return NULL;
- }
- return *(alternate_instance->endpoints_descriptor_array + index);
-}
-
-
-/**
- * usbd_device_endpoint_transfersize
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @index: which index
- *
- * Return the specified endpoint transfer size;
- */
-int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index)
-{
- struct usb_alternate_instance *alternate_instance;
-
- if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) {
- return 0;
- }
- if (index >= alternate_instance->endpoints) {
- return 0;
- }
- return *(alternate_instance->endpoint_transfersize_array + index);
-}
-
-
-/**
- * usbd_device_endpoint_descriptor
- * @device: which device
- * @port: which port
- * @configuration: index to configuration, 0 - N-1
- * @interface: index to interface
- * @alternate: alternate setting
- * @endpoint: which endpoint
- *
- * Return the specified endpoint descriptor for the specified device.
- */
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint)
-{
- struct usb_endpoint_descriptor *endpoint_descriptor;
- int i;
-
- for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) {
- if (endpoint_descriptor->bEndpointAddress == endpoint) {
- return endpoint_descriptor;
- }
- }
- return NULL;
-}
-
-/**
- * usbd_endpoint_halted
- * @device: point to struct usb_device_instance
- * @endpoint: endpoint to check
- *
- * Return non-zero if endpoint is halted.
- */
-int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint)
-{
- return (device->status == USB_STATUS_HALT);
-}
-
-
-/**
- * usbd_rcv_complete - complete a receive
- * @endpoint:
- * @len:
- * @urb_bad:
- *
- * Called from rcv interrupt to complete.
- */
-void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad)
-{
- if (endpoint) {
- struct urb *rcv_urb;
-
- /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */
-
- /* if we had an urb then update actual_length, dispatch if neccessary */
- if ((rcv_urb = endpoint->rcv_urb)) {
-
- /*usbdbg("actual: %d buffer: %d\n", */
- /*rcv_urb->actual_length, rcv_urb->buffer_length); */
-
- /* check the urb is ok, are we adding data less than the packetsize */
- if (!urb_bad && (len <= endpoint->rcv_packetSize)) {
- /*usbdbg("updating actual_length by %d\n",len); */
-
- /* increment the received data size */
- rcv_urb->actual_length += len;
-
- } else {
- usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n",
- rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad);
-
- rcv_urb->actual_length = 0;
- rcv_urb->status = RECV_ERROR;
- }
- } else {
- usberr("no rcv_urb!");
- }
- } else {
- usberr("no endpoint!");
- }
-
-}
-
-/**
- * usbd_tx_complete - complete a transmit
- * @endpoint:
- * @resetart:
- *
- * Called from tx interrupt to complete.
- */
-void usbd_tx_complete (struct usb_endpoint_instance *endpoint)
-{
- if (endpoint) {
- struct urb *tx_urb;
-
- /* if we have a tx_urb advance or reset, finish if complete */
- if ((tx_urb = endpoint->tx_urb)) {
- int sent = endpoint->last;
- endpoint->sent += sent;
- endpoint->last -= sent;
-
- if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) {
- tx_urb->actual_length = 0;
- endpoint->sent = 0;
- endpoint->last = 0;
-
- /* Remove from active, save for re-use */
- urb_detach(tx_urb);
- urb_append(&endpoint->done, tx_urb);
- /*usbdbg("done->next %p, tx_urb %p, done %p", */
- /* endpoint->done.next, tx_urb, &endpoint->done); */
-
- endpoint->tx_urb = first_urb_detached(&endpoint->tx);
- if( endpoint->tx_urb ) {
- endpoint->tx_queue--;
- usbdbg("got urb from tx list");
- }
- if( !endpoint->tx_urb ) {
- /*usbdbg("taking urb from done list"); */
- endpoint->tx_urb = first_urb_detached(&endpoint->done);
- }
- if( !endpoint->tx_urb ) {
- usbdbg("allocating new urb for tx_urb");
- endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint);
- }
- }
- }
- }
-}
-
-/* URB linked list functions ***************************************************** */
-
-/*
- * Initialize an urb_link to be a single element list.
- * If the urb_link is being used as a distinguished list head
- * the list is empty when the head is the only link in the list.
- */
-void urb_link_init (urb_link * ul)
-{
- if (ul) {
- ul->prev = ul->next = ul;
- }
-}
-
-/*
- * Detach an urb_link from a list, and set it
- * up as a single element list, so no dangling
- * pointers can be followed, and so it can be
- * joined to another list if so desired.
- */
-void urb_detach (struct urb *urb)
-{
- if (urb) {
- urb_link *ul = &urb->link;
- ul->next->prev = ul->prev;
- ul->prev->next = ul->next;
- urb_link_init (ul);
- }
-}
-
-/*
- * Return the first urb_link in a list with a distinguished
- * head "hd", or NULL if the list is empty. This will also
- * work as a predicate, returning NULL if empty, and non-NULL
- * otherwise.
- */
-urb_link *first_urb_link (urb_link * hd)
-{
- urb_link *nx;
- if (NULL != hd && NULL != (nx = hd->next) && nx != hd) {
- /* There is at least one element in the list */
- /* (besides the distinguished head). */
- return (nx);
- }
- /* The list is empty */
- return (NULL);
-}
-
-/*
- * Return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- */
-struct urb *first_urb (urb_link * hd)
-{
- urb_link *nx;
- if (NULL == (nx = first_urb_link (hd))) {
- /* The list is empty */
- return (NULL);
- }
- return (p2surround (struct urb, link, nx));
-}
-
-/*
- * Detach and return the first urb in a list with a distinguished
- * head "hd", or NULL if the list is empty.
- *
- */
-struct urb *first_urb_detached (urb_link * hd)
-{
- struct urb *urb;
- if ((urb = first_urb (hd))) {
- urb_detach (urb);
- }
- return urb;
-}
-
-
-/*
- * Append an urb_link (or a whole list of
- * urb_links) to the tail of another list
- * of urb_links.
- */
-void urb_append (urb_link * hd, struct urb *urb)
-{
- if (hd && urb) {
- urb_link *new = &urb->link;
-
- /* This allows the new urb to be a list of urbs, */
- /* with new pointing at the first, but the link */
- /* must be initialized. */
- /* Order is important here... */
- urb_link *pul = hd->prev;
- new->prev->next = hd;
- hd->prev = new->prev;
- new->prev = pul;
- pul->next = new;
- }
-}
-
-/* URB create/destroy functions ***************************************************** */
-
-/**
- * usbd_alloc_urb - allocate an URB appropriate for specified endpoint
- * @device: device instance
- * @endpoint: endpoint
- *
- * Allocate an urb structure. The usb device urb structure is used to
- * contain all data associated with a transfer, including a setup packet for
- * control transfers.
- *
- * NOTE: endpoint_address MUST contain a direction flag.
- */
-struct urb *usbd_alloc_urb (struct usb_device_instance *device,
- struct usb_endpoint_instance *endpoint)
-{
- struct urb *urb;
-
- if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) {
- usberr (" F A T A L: malloc(%zu) FAILED!!!!",
- sizeof (struct urb));
- return NULL;
- }
-
- /* Fill in known fields */
- memset (urb, 0, sizeof (struct urb));
- urb->endpoint = endpoint;
- urb->device = device;
- urb->buffer = (u8 *) urb->buffer_data;
- urb->buffer_length = sizeof (urb->buffer_data);
-
- urb_link_init (&urb->link);
-
- return urb;
-}
-
-/**
- * usbd_dealloc_urb - deallocate an URB and associated buffer
- * @urb: pointer to an urb structure
- *
- * Deallocate an urb structure and associated data.
- */
-void usbd_dealloc_urb (struct urb *urb)
-{
- if (urb) {
- free (urb);
- }
-}
-
-/* Event signaling functions ***************************************************** */
-
-/**
- * usbd_device_event - called to respond to various usb events
- * @device: pointer to struct device
- * @event: event to respond to
- *
- * Used by a Bus driver to indicate an event.
- */
-void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data)
-{
- usb_device_state_t state;
-
- if (!device || !device->bus) {
- usberr("(%p,%d) NULL device or device->bus", device, event);
- return;
- }
-
- state = device->device_state;
-
- usbinfo("%s", usbd_device_events[event]);
-
- switch (event) {
- case DEVICE_UNKNOWN:
- break;
- case DEVICE_INIT:
- device->device_state = STATE_INIT;
- break;
-
- case DEVICE_CREATE:
- device->device_state = STATE_ATTACHED;
- break;
-
- case DEVICE_HUB_CONFIGURED:
- device->device_state = STATE_POWERED;
- break;
-
- case DEVICE_RESET:
- device->device_state = STATE_DEFAULT;
- device->address = 0;
- break;
-
- case DEVICE_ADDRESS_ASSIGNED:
- device->device_state = STATE_ADDRESSED;
- break;
-
- case DEVICE_CONFIGURED:
- device->device_state = STATE_CONFIGURED;
- break;
-
- case DEVICE_DE_CONFIGURED:
- device->device_state = STATE_ADDRESSED;
- break;
-
- case DEVICE_BUS_INACTIVE:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_SUSPENDED;
- }
- break;
- case DEVICE_BUS_ACTIVITY:
- if (device->status != USBD_CLOSING) {
- device->status = USBD_OK;
- }
- break;
-
- case DEVICE_SET_INTERFACE:
- break;
- case DEVICE_SET_FEATURE:
- break;
- case DEVICE_CLEAR_FEATURE:
- break;
-
- case DEVICE_POWER_INTERRUPTION:
- device->device_state = STATE_POWERED;
- break;
- case DEVICE_HUB_RESET:
- device->device_state = STATE_ATTACHED;
- break;
- case DEVICE_DESTROY:
- device->device_state = STATE_UNKNOWN;
- break;
-
- case DEVICE_FUNCTION_PRIVATE:
- break;
-
- default:
- usbdbg("event %d - not handled",event);
- break;
- }
- /*usbdbg("%s event: %d oldstate: %d newstate: %d status: %d address: %d",
- device->name, event, state,
- device->device_state, device->status, device->address); */
-
- /* tell the bus interface driver */
- if( device->event ) {
- /* usbdbg("calling device->event"); */
- device->event(device, event, data);
- }
-}
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * (C) Copyright 2006
- * Bryan O'Donoghue, deckard@CodeHermit.ie
- *
- * Based on
- * linux/drivers/usbd/ep0.c
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
- * This is the builtin ep0 control function. It implements all required functionality
- * for responding to control requests (SETUP packets).
- *
- * XXX
- *
- * Currently we do not pass any SETUP packets (or other) to the configured
- * function driver. This may need to change.
- *
- * XXX
- *
- * As alluded to above, a simple callback cdc_recv_setup has been implemented
- * in the usb_device data structure to facilicate passing
- * Common Device Class packets to a function driver.
- *
- * XXX
- */
-
-#include <common.h>
-#include "usbdcore.h"
-
-#if 0
-#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args)
-#else
-#define dbg_ep0(lvl,fmt,args...)
-#endif
-
-/* EP0 Configuration Set ********************************************************************* */
-
-
-/**
- * ep0_get_status - fill in URB data with appropriate status
- * @device:
- * @urb:
- * @index:
- * @requesttype:
- *
- */
-static int ep0_get_status (struct usb_device_instance *device,
- struct urb *urb, int index, int requesttype)
-{
- char *cp;
-
- urb->actual_length = 2;
- cp = (char*)urb->buffer;
- cp[0] = cp[1] = 0;
-
- switch (requesttype) {
- case USB_REQ_RECIPIENT_DEVICE:
- cp[0] = USB_STATUS_SELFPOWERED;
- break;
- case USB_REQ_RECIPIENT_INTERFACE:
- break;
- case USB_REQ_RECIPIENT_ENDPOINT:
- cp[0] = usbd_endpoint_halted (device, index);
- break;
- case USB_REQ_RECIPIENT_OTHER:
- urb->actual_length = 0;
- default:
- break;
- }
- dbg_ep0 (2, "%02x %02x", cp[0], cp[1]);
- return 0;
-}
-
-/**
- * ep0_get_one
- * @device:
- * @urb:
- * @result:
- *
- * Set a single byte value in the urb send buffer. Return non-zero to signal
- * a request error.
- */
-static int ep0_get_one (struct usb_device_instance *device, struct urb *urb,
- __u8 result)
-{
- urb->actual_length = 1; /* XXX 2? */
- ((char *) urb->buffer)[0] = result;
- return 0;
-}
-
-/**
- * copy_config
- * @urb: pointer to urb
- * @data: pointer to configuration data
- * @length: length of data
- *
- * Copy configuration data to urb transfer buffer if there is room for it.
- */
-void copy_config (struct urb *urb, void *data, int max_length,
- int max_buf)
-{
- int available;
- int length;
-
- /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */
- /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */
-
- if (!data) {
- dbg_ep0 (1, "data is NULL");
- return;
- }
- length = max_length;
-
- if (length > max_length) {
- dbg_ep0 (1, "length: %d >= max_length: %d", length,
- max_length);
- return;
- }
- /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */
-
- if ((available =
- /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) {
- return;
- }
- /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
- if (length > available) {
- length = available;
- }
- /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */
- /* urb->actual_length, urb->buffer_length, max_buf, length, available); */
-
- memcpy (urb->buffer + urb->actual_length, data, length);
- urb->actual_length += length;
-
- dbg_ep0 (3,
- "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d",
- urb->actual_length, urb->buffer_length, max_buf, max_length,
- available);
-}
-
-/**
- * ep0_get_descriptor
- * @device:
- * @urb:
- * @max:
- * @descriptor_type:
- * @index:
- *
- * Called by ep0_rx_process for a get descriptor device command. Determine what
- * descriptor is being requested, copy to send buffer. Return zero if ok to send,
- * return non-zero to signal a request error.
- */
-static int ep0_get_descriptor (struct usb_device_instance *device,
- struct urb *urb, int max, int descriptor_type,
- int index)
-{
- int port = 0; /* XXX compound device */
- char *cp;
-
- /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */
-
- if (!urb || !urb->buffer || !urb->buffer_length
- || (urb->buffer_length < 255)) {
- dbg_ep0 (2, "invalid urb %p", urb);
- return -1L;
- }
-
- /* setup tx urb */
- urb->actual_length = 0;
- cp = (char*)urb->buffer;
-
- dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
-
- switch (descriptor_type) {
- case USB_DESCRIPTOR_TYPE_DEVICE:
- {
- struct usb_device_descriptor *device_descriptor;
- if (!
- (device_descriptor =
- usbd_device_device_descriptor (device, port))) {
- return -1;
- }
- /* copy descriptor for this device */
- copy_config (urb, device_descriptor,
- sizeof (struct usb_device_descriptor),
- max);
-
- /* correct the correct control endpoint 0 max packet size into the descriptor */
- device_descriptor =
- (struct usb_device_descriptor *) urb->buffer;
-
- }
- dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
- break;
-
- case USB_DESCRIPTOR_TYPE_CONFIGURATION:
- {
- struct usb_configuration_descriptor
- *configuration_descriptor;
- struct usb_device_descriptor *device_descriptor;
- if (!
- (device_descriptor =
- usbd_device_device_descriptor (device, port))) {
- return -1;
- }
- /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */
- if (index >= device_descriptor->bNumConfigurations) {
- dbg_ep0 (0, "index too large: %d >= %d", index,
- device_descriptor->
- bNumConfigurations);
- return -1;
- }
-
- if (!
- (configuration_descriptor =
- usbd_device_configuration_descriptor (device,
- port,
- index))) {
- dbg_ep0 (0,
- "usbd_device_configuration_descriptor failed: %d",
- index);
- return -1;
- }
- dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
- copy_config (urb, configuration_descriptor,
-
- cpu_to_le16(configuration_descriptor->wTotalLength),
- max);
- }
-
- break;
-
- case USB_DESCRIPTOR_TYPE_STRING:
- {
- struct usb_string_descriptor *string_descriptor;
- if (!(string_descriptor = usbd_get_string (index))) {
- serial_printf("Invalid string index %d\n", index);
- return -1;
- }
- dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
- copy_config (urb, string_descriptor, string_descriptor->bLength, max);
- }
- break;
- case USB_DESCRIPTOR_TYPE_INTERFACE:
- serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
- return -1;
- case USB_DESCRIPTOR_TYPE_ENDPOINT:
- serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
- return -1;
- case USB_DESCRIPTOR_TYPE_HID:
- {
- serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
- return -1; /* unsupported at this time */
-#if 0
- int bNumInterface =
- le16_to_cpu (urb->device_request.wIndex);
- int bAlternateSetting = 0;
- int class = 0;
- struct usb_class_descriptor *class_descriptor;
-
- if (!(class_descriptor =
- usbd_device_class_descriptor_index (device,
- port, 0,
- bNumInterface,
- bAlternateSetting,
- class))
- || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) {
- dbg_ep0 (3, "[%d] interface is not HID",
- bNumInterface);
- return -1;
- }
- /* copy descriptor for this class */
- copy_config (urb, class_descriptor,
- class_descriptor->descriptor.hid.bLength,
- max);
-#endif
- }
- break;
- case USB_DESCRIPTOR_TYPE_REPORT:
- {
- serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
- return -1; /* unsupported at this time */
-#if 0
- int bNumInterface =
- le16_to_cpu (urb->device_request.wIndex);
- int bAlternateSetting = 0;
- int class = 0;
- struct usb_class_report_descriptor *report_descriptor;
-
- if (!(report_descriptor =
- usbd_device_class_report_descriptor_index
- (device, port, 0, bNumInterface,
- bAlternateSetting, class))
- || report_descriptor->bDescriptorType !=
- USB_DT_REPORT) {
- dbg_ep0 (3, "[%d] descriptor is not REPORT",
- bNumInterface);
- return -1;
- }
- /* copy report descriptor for this class */
- /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */
- if (max - urb->actual_length > 0) {
- int length =
- MIN (report_descriptor->wLength,
- max - urb->actual_length);
- memcpy (urb->buffer + urb->actual_length,
- &report_descriptor->bData[0], length);
- urb->actual_length += length;
- }
-#endif
- }
- break;
- case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
- {
- /* If a USB device supports both a full speed and low speed operation
- * we must send a Device_Qualifier descriptor here
- */
- return -1;
- }
- default:
- return -1;
- }
-
-
- dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
- urb->buffer, urb->buffer_length, urb->actual_length,
- device->bus->endpoint_array[0].tx_packetSize);
-/*
- if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) {
- dbg_ep0(0, "adding null byte");
- urb->buffer[urb->actual_length++] = 0;
- dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d",
- urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize);
- }
-*/
- return 0;
-
-}
-
-/**
- * ep0_recv_setup - called to indicate URB has been received
- * @urb: pointer to struct urb
- *
- * Check if this is a setup packet, process the device request, put results
- * back into the urb and return zero or non-zero to indicate success (DATA)
- * or failure (STALL).
- *
- */
-int ep0_recv_setup (struct urb *urb)
-{
- /*struct usb_device_request *request = urb->buffer; */
- /*struct usb_device_instance *device = urb->device; */
-
- struct usb_device_request *request;
- struct usb_device_instance *device;
- int address;
-
- dbg_ep0 (0, "entering ep0_recv_setup()");
- if (!urb || !urb->device) {
- dbg_ep0 (3, "invalid URB %p", urb);
- return -1;
- }
-
- request = &urb->device_request;
- device = urb->device;
-
- dbg_ep0 (3, "urb: %p device: %p", urb, urb->device);
-
-
- /*dbg_ep0(2, "- - - - - - - - - -"); */
-
- dbg_ep0 (2,
- "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s",
- request->bmRequestType, request->bRequest,
- le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex),
- le16_to_cpu (request->wLength),
- USBD_DEVICE_REQUESTS (request->bRequest));
-
- /* handle USB Standard Request (c.f. USB Spec table 9-2) */
- if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
- if(device->device_state <= STATE_CONFIGURED){
- /* Attempt to handle a CDC specific request if we are
- * in the configured state.
- */
- return device->cdc_recv_setup(request,urb);
- }
- dbg_ep0 (1, "non standard request: %x",
- request->bmRequestType & USB_REQ_TYPE_MASK);
- return -1; /* Stall here */
- }
-
- switch (device->device_state) {
- case STATE_CREATED:
- case STATE_ATTACHED:
- case STATE_POWERED:
- /* It actually is important to allow requests in these states,
- * Windows will request descriptors before assigning an
- * address to the client.
- */
-
- /*dbg_ep0 (1, "request %s not allowed in this state: %s", */
- /* USBD_DEVICE_REQUESTS(request->bRequest), */
- /* usbd_device_states[device->device_state]); */
- /*return -1; */
- break;
-
- case STATE_INIT:
- case STATE_DEFAULT:
- switch (request->bRequest) {
- case USB_REQ_GET_STATUS:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_DESCRIPTOR:
- /* case USB_REQ_SET_CONFIGURATION: */
- case USB_REQ_SET_INTERFACE:
- dbg_ep0 (1,
- "request %s not allowed in DEFAULT state: %s",
- USBD_DEVICE_REQUESTS (request->bRequest),
- usbd_device_states[device->device_state]);
- return -1;
-
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- break;
- }
- case STATE_ADDRESSED:
- case STATE_CONFIGURED:
- break;
- case STATE_UNKNOWN:
- dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s",
- USBD_DEVICE_REQUESTS (request->bRequest),
- usbd_device_states[device->device_state]);
- return -1;
- }
-
- /* handle all requests that return data (direction bit set on bm RequestType) */
- if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) {
-
- dbg_ep0 (3, "Device-to-Host");
-
- switch (request->bRequest) {
-
- case USB_REQ_GET_STATUS:
- return ep0_get_status (device, urb, request->wIndex,
- request->bmRequestType &
- USB_REQ_RECIPIENT_MASK);
-
- case USB_REQ_GET_DESCRIPTOR:
- return ep0_get_descriptor (device, urb,
- le16_to_cpu (request->wLength),
- le16_to_cpu (request->wValue) >> 8,
- le16_to_cpu (request->wValue) & 0xff);
-
- case USB_REQ_GET_CONFIGURATION:
- serial_printf("get config %d\n", device->configuration);
- return ep0_get_one (device, urb,
- device->configuration);
-
- case USB_REQ_GET_INTERFACE:
- return ep0_get_one (device, urb, device->alternate);
-
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- return -1;
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- case USB_REQ_SET_ADDRESS:
- case USB_REQ_SET_DESCRIPTOR:
- case USB_REQ_SET_CONFIGURATION:
- case USB_REQ_SET_INTERFACE:
- return -1;
- }
- }
- /* handle the requests that do not return data */
- else {
-
-
- /*dbg_ep0(3, "Host-to-Device"); */
- switch (request->bRequest) {
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- dbg_ep0 (0, "Host-to-Device");
- switch (request->
- bmRequestType & USB_REQ_RECIPIENT_MASK) {
- case USB_REQ_RECIPIENT_DEVICE:
- /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */
- /* XXX fall through for now as we do not support either */
- case USB_REQ_RECIPIENT_INTERFACE:
- case USB_REQ_RECIPIENT_OTHER:
- dbg_ep0 (0, "request %s not",
- USBD_DEVICE_REQUESTS (request->bRequest));
- default:
- return -1;
-
- case USB_REQ_RECIPIENT_ENDPOINT:
- dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue));
- if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) {
- /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */
- /* request->bRequest == USB_REQ_SET_FEATURE); */
- /* NEED TO IMPLEMENT THIS!!! */
- return -1;
- } else {
- dbg_ep0 (1, "request %s bad wValue: %04x",
- USBD_DEVICE_REQUESTS
- (request->bRequest),
- le16_to_cpu (request->wValue));
- return -1;
- }
- }
-
- case USB_REQ_SET_ADDRESS:
- /* check if this is a re-address, reset first if it is (this shouldn't be possible) */
- if (device->device_state != STATE_DEFAULT) {
- dbg_ep0 (1, "set_address: %02x state: %s",
- le16_to_cpu (request->wValue),
- usbd_device_states[device->device_state]);
- return -1;
- }
- address = le16_to_cpu (request->wValue);
- if ((address & 0x7f) != address) {
- dbg_ep0 (1, "invalid address %04x %04x",
- address, address & 0x7f);
- return -1;
- }
- device->address = address;
-
- /*dbg_ep0(2, "address: %d %d %d", */
- /* request->wValue, le16_to_cpu(request->wValue), device->address); */
-
- return 0;
-
- case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */
- dbg_ep0 (0, "set descriptor: NOT SUPPORTED");
- return -1;
-
- case USB_REQ_SET_CONFIGURATION:
- /* c.f. 9.4.7 - the top half of wValue is reserved */
- device->configuration = le16_to_cpu(request->wValue) & 0xff;
-
- /* reset interface and alternate settings */
- device->interface = device->alternate = 0;
-
- /*dbg_ep0(2, "set configuration: %d", device->configuration); */
- /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */
- return 0;
-
- case USB_REQ_SET_INTERFACE:
- device->interface = le16_to_cpu (request->wIndex);
- device->alternate = le16_to_cpu (request->wValue);
- /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */
- serial_printf ("DEVICE_SET_INTERFACE.. event?\n");
- return 0;
-
- case USB_REQ_GET_STATUS:
- case USB_REQ_GET_DESCRIPTOR:
- case USB_REQ_GET_CONFIGURATION:
- case USB_REQ_GET_INTERFACE:
- case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */
- return -1;
- }
- }
- return -1;
-}
+++ /dev/null
-/*
- * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit
- * bodonoghue@CodeHermit.ie
- *
- * References
- * DasUBoot/drivers/usb/usbdcore_omap1510.c, for design and implementation
- * ideas.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-/*
- * Notes :
- * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX
- * packet to force the USB re-transmit protocol.
- *
- * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console
- * be careful that tracing doesn't create Hiesen-bugs with respect to
- * response timeouts to control requests.
- *
- * 3. This driver should be able to support any higher level driver that
- * that wants to do either of the two standard UDC implementations
- * Control-Bulk-Interrupt or Bulk-IN/Bulk-Out standards. Hence
- * gserial and cdc_acm should work with this code.
- *
- * 4. NAK events never actually get raised at all, the documentation
- * is just wrong !
- *
- * 5. For some reason, cbd_datlen is *always* +2 the value it should be.
- * this means that having an RX cbd of 16 bytes is not possible, since
- * the same size is reported for 14 bytes received as 16 bytes received
- * until we can find out why this happens, RX cbds must be limited to 8
- * bytes. TODO: check errata for this behaviour.
- *
- * 6. Right now this code doesn't support properly powering up with the USB
- * cable attached to the USB host my development board the Adder87x doesn't
- * have a pull-up fitted to allow this, so it is necessary to power the
- * board and *then* attached the USB cable to the host. However somebody
- * with a different design in their board may be able to keep the cable
- * constantly connected and simply enable/disable a pull-up re
- * figure 31.1 in MPC885RM.pdf instead of having to power up the board and
- * then attach the cable !
- *
- */
-#include <common.h>
-#include <config.h>
-#include <commproc.h>
-#include "usbdcore.h"
-#include "usbdcore_mpc8xx.h"
-#include "usbdcore_ep0.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-#define ERR(fmt, args...)\
- serial_printf("ERROR : [%s] %s:%d: "fmt,\
- __FILE__,__FUNCTION__,__LINE__, ##args)
-#ifdef __DEBUG_UDC__
-#define DBG(fmt,args...)\
- serial_printf("[%s] %s:%d: "fmt,\
- __FILE__,__FUNCTION__,__LINE__, ##args)
-#else
-#define DBG(fmt,args...)
-#endif
-
-/* Static Data */
-#ifdef __SIMULATE_ERROR__
-static char err_poison_test = 0;
-#endif
-static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];
-static u32 address_base = STATE_NOT_READY;
-static mpc8xx_udc_state_t udc_state = 0;
-static struct usb_device_instance *udc_device = 0;
-static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];
-static volatile cbd_t *tx_cbd[TX_RING_SIZE];
-static volatile cbd_t *rx_cbd[RX_RING_SIZE];
-static volatile immap_t *immr = 0;
-static volatile cpm8xx_t *cp = 0;
-static volatile usb_pram_t *usb_paramp = 0;
-static volatile usb_t *usbp = 0;
-static int rx_ct = 0;
-static int tx_ct = 0;
-
-/* Static Function Declarations */
-static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
- usb_device_state_t final);
-static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
- usb_device_state_t final);
-static void mpc8xx_udc_stall (unsigned int ep);
-static void mpc8xx_udc_flush_tx_fifo (int epid);
-static void mpc8xx_udc_flush_rx_fifo (void);
-static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);
-static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
- struct urb *tx_urb);
-static void mpc8xx_udc_dump_request (struct usb_device_request *request);
-static void mpc8xx_udc_clock_init (volatile immap_t * immr,
- volatile cpm8xx_t * cp);
-static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);
-static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);
-static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp);
-static void mpc8xx_udc_cbd_init (void);
-static void mpc8xx_udc_endpoint_init (void);
-static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);
-static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);
-static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);
-static void mpc8xx_udc_set_nak (unsigned int ep);
-static short mpc8xx_udc_handle_txerr (void);
-static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid);
-
-/******************************************************************************
- Global Linkage
- *****************************************************************************/
-
-/* udc_init
- *
- * Do initial bus gluing
- */
-int udc_init (void)
-{
- /* Init various pointers */
- immr = (immap_t *) CONFIG_SYS_IMMR;
- cp = (cpm8xx_t *) & (immr->im_cpm);
- usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]);
- usbp = (usb_t *) & (cp->cp_scc[0]);
-
- memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS));
-
- udc_device = 0;
- udc_state = STATE_NOT_READY;
-
- usbp->usmod = 0x00;
- usbp->uscom = 0;
-
- /* Set USB Frame #0, Respond at Address & Get a clock source */
- usbp->usaddr = 0x00;
- mpc8xx_udc_clock_init (immr, cp);
-
- /* PA15, PA14 as perhiperal USBRXD and USBOE */
- immr->im_ioport.iop_padir &= ~0x0003;
- immr->im_ioport.iop_papar |= 0x0003;
-
- /* PC11/PC10 as peripheral USBRXP USBRXN */
- immr->im_ioport.iop_pcso |= 0x0030;
-
- /* PC7/PC6 as perhiperal USBTXP and USBTXN */
- immr->im_ioport.iop_pcdir |= 0x0300;
- immr->im_ioport.iop_pcpar |= 0x0300;
-
- /* Set the base address */
- address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE);
-
- /* Initialise endpoints and circular buffers */
- mpc8xx_udc_endpoint_init ();
- mpc8xx_udc_cbd_init ();
-
- /* Assign allocated Dual Port Endpoint descriptors */
- usb_paramp->ep0ptr = (u32) endpoints[0];
- usb_paramp->ep1ptr = (u32) endpoints[1];
- usb_paramp->ep2ptr = (u32) endpoints[2];
- usb_paramp->ep3ptr = (u32) endpoints[3];
- usb_paramp->frame_n = 0;
-
- DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",
- usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,
- usb_paramp->ep3ptr);
-
- return 0;
-}
-
-/* udc_irq
- *
- * Poll for whatever events may have occured
- */
-void udc_irq (void)
-{
- int epid = 0;
- volatile cbd_t *rx_cbdp = 0;
- volatile cbd_t *rx_cbdp_base = 0;
-
- if (udc_state != STATE_READY) {
- return;
- }
-
- if (usbp->usber & USB_E_BSY) {
- /* This shouldn't happen. If it does then it's a bug ! */
- usbp->usber |= USB_E_BSY;
- mpc8xx_udc_flush_rx_fifo ();
- }
-
- /* Scan all RX/Bidirectional Endpoints for RX data. */
- for (epid = 0; epid < MAX_ENDPOINTS; epid++) {
- if (!ep_ref[epid].prx) {
- continue;
- }
- rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;
-
- do {
- if (!(rx_cbdp->cbd_sc & RX_BD_E)) {
-
- if (rx_cbdp->cbd_sc & 0x1F) {
- /* Corrupt data discard it.
- * Controller has NAK'd this packet.
- */
- mpc8xx_udc_clear_rxbd (rx_cbdp);
-
- } else {
- if (!epid) {
- mpc8xx_udc_ep0_rx (rx_cbdp);
-
- } else {
- /* Process data */
- mpc8xx_udc_set_nak (epid);
- mpc8xx_udc_epn_rx (epid, rx_cbdp);
- mpc8xx_udc_clear_rxbd (rx_cbdp);
- }
- }
-
- /* Advance RX CBD pointer */
- mpc8xx_udc_advance_rx (&rx_cbdp, epid);
- ep_ref[epid].prx = rx_cbdp;
- } else {
- /* Advance RX CBD pointer */
- mpc8xx_udc_advance_rx (&rx_cbdp, epid);
- }
-
- } while (rx_cbdp != rx_cbdp_base);
- }
-
- /* Handle TX events as appropiate, the correct place to do this is
- * in a tx routine. Perhaps TX on epn was pre-empted by ep0
- */
-
- if (usbp->usber & USB_E_TXB) {
- usbp->usber |= USB_E_TXB;
- }
-
- if (usbp->usber & (USB_TX_ERRMASK)) {
- mpc8xx_udc_handle_txerr ();
- }
-
- /* Switch to the default state, respond at the default address */
- if (usbp->usber & USB_E_RESET) {
- usbp->usber |= USB_E_RESET;
- usbp->usaddr = 0x00;
- udc_device->device_state = STATE_DEFAULT;
- }
-
- /* if(usbp->usber&USB_E_IDLE){
- We could suspend here !
- usbp->usber|=USB_E_IDLE;
- DBG("idle state change\n");
- }
- if(usbp->usbs){
- We could resume here when IDLE is deasserted !
- Not worth doing, so long as we are self powered though.
- }
- */
-
- return;
-}
-
-/* udc_endpoint_write
- *
- * Write some data to an endpoint
- */
-int udc_endpoint_write (struct usb_endpoint_instance *epi)
-{
- int ep = 0;
- short epid = 1, unnak = 0, ret = 0;
-
- if (udc_state != STATE_READY) {
- ERR ("invalid udc_state != STATE_READY!\n");
- return -1;
- }
-
- if (!udc_device || !epi) {
- return -1;
- }
-
- if (udc_device->device_state != STATE_CONFIGURED) {
- return -1;
- }
-
- ep = epi->endpoint_address & 0x03;
- if (ep >= MAX_ENDPOINTS) {
- return -1;
- }
-
- /* Set NAK for all RX endpoints during TX */
- for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
-
- /* Don't set NAK on DATA IN/CONTROL endpoints */
- if (ep_ref[epid].sc & USB_DIR_IN) {
- continue;
- }
-
- if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) {
- unnak |= 1 << epid;
- }
-
- mpc8xx_udc_set_nak (epid);
- }
-
- mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep],
- epi->tx_urb);
- ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]);
-
- /* Remove temporary NAK */
- for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
- if (unnak & (1 << epid)) {
- udc_unset_nak (epid);
- }
- }
-
- return ret;
-}
-
-/* mpc8xx_udc_assign_urb
- *
- * Associate a given urb to an endpoint TX or RX transmit/receive buffers
- */
-static int mpc8xx_udc_assign_urb (int ep, char direction)
-{
- struct usb_endpoint_instance *epi = 0;
-
- if (ep >= MAX_ENDPOINTS) {
- goto err;
- }
- epi = &udc_device->bus->endpoint_array[ep];
- if (!epi) {
- goto err;
- }
-
- if (!ep_ref[ep].urb) {
- ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array);
- if (!ep_ref[ep].urb) {
- goto err;
- }
- } else {
- ep_ref[ep].urb->actual_length = 0;
- }
-
- switch (direction) {
- case USB_DIR_IN:
- epi->tx_urb = ep_ref[ep].urb;
- break;
- case USB_DIR_OUT:
- epi->rcv_urb = ep_ref[ep].urb;
- break;
- default:
- goto err;
- }
- return 0;
-
- err:
- udc_state = STATE_ERROR;
- return -1;
-}
-
-/* udc_setup_ep
- *
- * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram
- * Isochronous endpoints aren't yet supported!
- */
-void udc_setup_ep (struct usb_device_instance *device, unsigned int ep,
- struct usb_endpoint_instance *epi)
-{
- uchar direction = 0;
- int ep_attrib = 0;
-
- if (epi && (ep < MAX_ENDPOINTS)) {
-
- if (ep == 0) {
- if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL
- || epi->tx_attributes !=
- USB_ENDPOINT_XFER_CONTROL) {
-
- /* ep0 must be a control endpoint */
- udc_state = STATE_ERROR;
- return;
-
- }
- if (!(ep_ref[ep].sc & EP_ATTACHED)) {
- mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize,
- epi->rcv_packetSize);
- }
- usbp->usep[ep] = 0x0000;
- return;
- }
-
- if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) {
-
- direction = 1;
- ep_attrib = epi->tx_attributes;
- epi->rcv_packetSize = 0;
- ep_ref[ep].sc |= USB_DIR_IN;
- } else {
-
- direction = 0;
- ep_attrib = epi->rcv_attributes;
- epi->tx_packetSize = 0;
- ep_ref[ep].sc &= ~USB_DIR_IN;
- }
-
- if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address
- & USB_ENDPOINT_DIR_MASK)) {
- return;
- }
-
- switch (ep_attrib) {
- case USB_ENDPOINT_XFER_CONTROL:
- if (!(ep_ref[ep].sc & EP_ATTACHED)) {
- mpc8xx_udc_cbd_attach (ep,
- epi->tx_packetSize,
- epi->rcv_packetSize);
- }
- usbp->usep[ep] = ep << 12;
- epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;
-
- break;
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- if (!(ep_ref[ep].sc & EP_ATTACHED)) {
- if (direction) {
- mpc8xx_udc_cbd_attach (ep,
- epi->tx_packetSize,
- 0);
- } else {
- mpc8xx_udc_cbd_attach (ep,
- 0,
- epi->rcv_packetSize);
- }
- }
- usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8);
-
- break;
- case USB_ENDPOINT_XFER_ISOC:
- default:
- serial_printf ("Error endpoint attrib %d>3\n", ep_attrib);
- udc_state = STATE_ERROR;
- break;
- }
- }
-
-}
-
-/* udc_connect
- *
- * Move state, switch on the USB
- */
-void udc_connect (void)
-{
- /* Enable pull-up resistor on D+
- * TODO: fit a pull-up resistor to drive SE0 for > 2.5us
- */
-
- if (udc_state != STATE_ERROR) {
- udc_state = STATE_READY;
- usbp->usmod |= USMOD_EN;
- }
-}
-
-/* udc_disconnect
- *
- * Disconnect is not used but, is included for completeness
- */
-void udc_disconnect (void)
-{
- /* Disable pull-up resistor on D-
- * TODO: fix a pullup resistor to control this
- */
-
- if (udc_state != STATE_ERROR) {
- udc_state = STATE_NOT_READY;
- }
- usbp->usmod &= ~USMOD_EN;
-}
-
-/* udc_enable
- *
- * Grab an EP0 URB, register interest in a subset of USB events
- */
-void udc_enable (struct usb_device_instance *device)
-{
- if (udc_state == STATE_ERROR) {
- return;
- }
-
- udc_device = device;
-
- if (!ep_ref[0].urb) {
- ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array);
- }
-
- /* Register interest in all events except SOF, enable transceiver */
- usbp->usber = 0x03FF;
- usbp->usbmr = 0x02F7;
-
- return;
-}
-
-/* udc_disable
- *
- * disable the currently hooked device
- */
-void udc_disable (void)
-{
- int i = 0;
-
- if (udc_state == STATE_ERROR) {
- DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n");
- return;
- }
-
- udc_device = 0;
-
- for (; i < MAX_ENDPOINTS; i++) {
- if (ep_ref[i].urb) {
- usbd_dealloc_urb (ep_ref[i].urb);
- ep_ref[i].urb = 0;
- }
- }
-
- usbp->usbmr = 0x00;
- usbp->usmod = ~USMOD_EN;
- udc_state = STATE_NOT_READY;
-}
-
-/* udc_startup_events
- *
- * Enable the specified device
- */
-void udc_startup_events (struct usb_device_instance *device)
-{
- udc_enable (device);
- if (udc_state == STATE_READY) {
- usbd_device_event_irq (device, DEVICE_CREATE, 0);
- }
-}
-
-/* udc_set_nak
- *
- * Allow upper layers to signal lower layers should not accept more RX data
- *
- */
-void udc_set_nak (int epid)
-{
- if (epid) {
- mpc8xx_udc_set_nak (epid);
- }
-}
-
-/* udc_unset_nak
- *
- * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
- * Switch off NAKing on this endpoint to accept more data output from host.
- *
- */
-void udc_unset_nak (int epid)
-{
- if (epid > MAX_ENDPOINTS) {
- return;
- }
-
- if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) {
- usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK);
- __asm__ ("eieio");
- }
-}
-
-/******************************************************************************
- Static Linkage
-******************************************************************************/
-
-/* udc_state_transition_up
- * udc_state_transition_down
- *
- * Helper functions to implement device state changes. The device states and
- * the events that transition between them are:
- *
- * STATE_ATTACHED
- * || /\
- * \/ ||
- * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET
- * || /\
- * \/ ||
- * STATE_POWERED
- * || /\
- * \/ ||
- * DEVICE_RESET DEVICE_POWER_INTERRUPTION
- * || /\
- * \/ ||
- * STATE_DEFAULT
- * || /\
- * \/ ||
- * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET
- * || /\
- * \/ ||
- * STATE_ADDRESSED
- * || /\
- * \/ ||
- * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED
- * || /\
- * \/ ||
- * STATE_CONFIGURED
- *
- * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
- * to STATE_CONFIGURED) from the specified initial state to the specified final
- * state, passing through each intermediate state on the way. If the initial
- * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
- * no state transitions will take place.
- *
- * udc_state_transition_down transitions down (in the direction from
- * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
- * specified final state, passing through each intermediate state on the way.
- * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
- * state, then no state transitions will take place.
- *
- */
-
-static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
- usb_device_state_t final)
-{
- if (initial < final) {
- switch (initial) {
- case STATE_ATTACHED:
- usbd_device_event_irq (udc_device,
- DEVICE_HUB_CONFIGURED, 0);
- if (final == STATE_POWERED)
- break;
- case STATE_POWERED:
- usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
- if (final == STATE_DEFAULT)
- break;
- case STATE_DEFAULT:
- usbd_device_event_irq (udc_device,
- DEVICE_ADDRESS_ASSIGNED, 0);
- if (final == STATE_ADDRESSED)
- break;
- case STATE_ADDRESSED:
- usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
- 0);
- case STATE_CONFIGURED:
- break;
- default:
- break;
- }
- }
-}
-
-static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
- usb_device_state_t final)
-{
- if (initial > final) {
- switch (initial) {
- case STATE_CONFIGURED:
- usbd_device_event_irq (udc_device,
- DEVICE_DE_CONFIGURED, 0);
- if (final == STATE_ADDRESSED)
- break;
- case STATE_ADDRESSED:
- usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
- if (final == STATE_DEFAULT)
- break;
- case STATE_DEFAULT:
- usbd_device_event_irq (udc_device,
- DEVICE_POWER_INTERRUPTION, 0);
- if (final == STATE_POWERED)
- break;
- case STATE_POWERED:
- usbd_device_event_irq (udc_device, DEVICE_HUB_RESET,
- 0);
- case STATE_ATTACHED:
- break;
- default:
- break;
- }
- }
-}
-
-/* mpc8xx_udc_stall
- *
- * Force returning of STALL tokens on the given endpoint. Protocol or function
- * STALL conditions are permissable here
- */
-static void mpc8xx_udc_stall (unsigned int ep)
-{
- usbp->usep[ep] |= STALL_BITMASK;
-}
-
-/* mpc8xx_udc_set_nak
- *
- * Force returning of NAK responses for the given endpoint as a kind of very
- * simple flow control
- */
-static void mpc8xx_udc_set_nak (unsigned int ep)
-{
- usbp->usep[ep] |= NAK_BITMASK;
- __asm__ ("eieio");
-}
-
-/* mpc8xx_udc_handle_txerr
- *
- * Handle errors relevant to TX. Return a status code to allow calling
- * indicative of what if anything happened
- */
-static short mpc8xx_udc_handle_txerr ()
-{
- short ep = 0, ret = 0;
-
- for (; ep < TX_RING_SIZE; ep++) {
- if (usbp->usber & (0x10 << ep)) {
-
- /* Timeout or underrun */
- if (tx_cbd[ep]->cbd_sc & 0x06) {
- ret = 1;
- mpc8xx_udc_flush_tx_fifo (ep);
-
- } else {
- if (usbp->usep[ep] & STALL_BITMASK) {
- if (!ep) {
- usbp->usep[ep] &= ~STALL_BITMASK;
- }
- } /* else NAK */
- }
- usbp->usber |= (0x10 << ep);
- }
- }
- return ret;
-}
-
-/* mpc8xx_udc_advance_rx
- *
- * Advance cbd rx
- */
-static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid)
-{
- if ((*rx_cbdp)->cbd_sc & RX_BD_W) {
- *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CONFIG_SYS_IMMR);
-
- } else {
- (*rx_cbdp)++;
- }
-}
-
-
-/* mpc8xx_udc_flush_tx_fifo
- *
- * Flush a given TX fifo. Assumes one tx cbd per endpoint
- */
-static void mpc8xx_udc_flush_tx_fifo (int epid)
-{
- volatile cbd_t *tx_cbdp = 0;
-
- if (epid > MAX_ENDPOINTS) {
- return;
- }
-
- /* TX stop */
- immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01);
- __asm__ ("eieio");
- while (immr->im_cpm.cp_cpcr & 0x01);
-
- usbp->uscom = 0x40 | 0;
-
- /* reset ring */
- tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CONFIG_SYS_IMMR);
- tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
-
-
- endpoints[epid]->tptr = endpoints[epid]->tbase;
- endpoints[epid]->tstate = 0x00;
- endpoints[epid]->tbcnt = 0x00;
-
- /* TX start */
- immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01);
- __asm__ ("eieio");
- while (immr->im_cpm.cp_cpcr & 0x01);
-
- return;
-}
-
-/* mpc8xx_udc_flush_rx_fifo
- *
- * For the sake of completeness of the namespace, it seems like
- * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo();
- * If RX_BD_E is true => a driver bug either here or in an upper layer
- * not polling frequently enough. If RX_BD_E is true we have told the host
- * we have accepted data but, the CPM found it had no-where to put that data
- * which needless to say would be a bad thing.
- */
-static void mpc8xx_udc_flush_rx_fifo ()
-{
- int i = 0;
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
- ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n",
- rx_cbd[i], rx_cbd[i]->cbd_datlen,
- rx_cbd[i]->cbd_sc);
-
- }
- }
- ERR ("BUG : Input over-run\n");
-}
-
-/* mpc8xx_udc_clear_rxbd
- *
- * Release control of RX CBD to CP.
- */
-static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp)
-{
- rx_cbdp->cbd_datlen = 0x0000;
- rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I));
- __asm__ ("eieio");
-}
-
-/* mpc8xx_udc_tx_irq
- *
- * Parse for tx timeout, control RX or USB reset/busy conditions
- * Return -1 on timeout, -2 on fatal error, else return zero
- */
-static int mpc8xx_udc_tx_irq (int ep)
-{
- int i = 0;
-
- if (usbp->usber & (USB_TX_ERRMASK)) {
- if (mpc8xx_udc_handle_txerr ()) {
- /* Timeout, controlling function must retry send */
- return -1;
- }
- }
-
- if (usbp->usber & (USB_E_RESET | USB_E_BSY)) {
- /* Fatal, abandon TX transaction */
- return -2;
- }
-
- if (usbp->usber & USB_E_RXB) {
- for (i = 0; i < RX_RING_SIZE; i++) {
- if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
- if ((rx_cbd[i] == ep_ref[0].prx) || ep) {
- return -2;
- }
- }
- }
- }
-
- return 0;
-}
-
-/* mpc8xx_udc_ep_tx
- *
- * Transmit in a re-entrant fashion outbound USB packets.
- * Implement retry/timeout mechanism described in USB specification
- * Toggle DATA0/DATA1 pids as necessary
- * Introduces non-standard tx_retry. The USB standard has no scope for slave
- * devices to give up TX, however tx_retry stops us getting stuck in an endless
- * TX loop.
- */
-static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
-{
- struct urb *urb = epi->tx_urb;
- volatile cbd_t *tx_cbdp = 0;
- unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0;
- int ret = 0;
-
- if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) {
- return -1;
- }
-
- ep = epi->endpoint_address & 0x03;
- tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
-
- if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) {
- mpc8xx_udc_flush_tx_fifo (ep);
- usbp->usber |= USB_E_TXB;
- };
-
- while (tx_retry++ < 100) {
- ret = mpc8xx_udc_tx_irq (ep);
- if (ret == -1) {
- /* ignore timeout here */
- } else if (ret == -2) {
- /* Abandon TX */
- mpc8xx_udc_flush_tx_fifo (ep);
- return -1;
- }
-
- tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR);
- while (tx_cbdp->cbd_sc & TX_BD_R) {
- };
- tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W);
-
- pkt_len = urb->actual_length - epi->sent;
-
- if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) {
- pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT);
- }
-
- for (x = 0; x < pkt_len; x++) {
- *((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) =
- urb->buffer[epi->sent + x];
- }
- tx_cbdp->cbd_datlen = pkt_len;
- tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid);
- __asm__ ("eieio");
-
-#ifdef __SIMULATE_ERROR__
- if (++err_poison_test == 2) {
- err_poison_test = 0;
- tx_cbdp->cbd_sc &= ~TX_BD_TC;
- }
-#endif
-
- usbp->uscom = (USCOM_STR | ep);
-
- while (!(usbp->usber & USB_E_TXB)) {
- ret = mpc8xx_udc_tx_irq (ep);
- if (ret == -1) {
- /* TX timeout */
- break;
- } else if (ret == -2) {
- if (usbp->usber & USB_E_TXB) {
- usbp->usber |= USB_E_TXB;
- }
- mpc8xx_udc_flush_tx_fifo (ep);
- return -1;
- }
- };
-
- if (usbp->usber & USB_E_TXB) {
- usbp->usber |= USB_E_TXB;
- }
-
- /* ACK must be present <= 18bit times from TX */
- if (ret == -1) {
- continue;
- }
-
- /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
- epi->sent += pkt_len;
- epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize);
- TOGGLE_TX_PID (ep_ref[ep].pid);
-
- if (epi->sent >= epi->tx_urb->actual_length) {
-
- epi->tx_urb->actual_length = 0;
- epi->sent = 0;
-
- if (ep_ref[ep].sc & EP_SEND_ZLP) {
- ep_ref[ep].sc &= ~EP_SEND_ZLP;
- } else {
- return 0;
- }
- }
- }
-
- ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent,
- epi->tx_urb->actual_length);
-
- return -1;
-}
-
-/* mpc8xx_udc_dump_request
- *
- * Dump a control request to console
- */
-static void mpc8xx_udc_dump_request (struct usb_device_request *request)
-{
- DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x "
- "wIndex:%04x wLength:%04x ?\n",
- request->bmRequestType,
- request->bRequest,
- request->wValue, request->wIndex, request->wLength);
-
- return;
-}
-
-/* mpc8xx_udc_ep0_rx_setup
- *
- * Decode received ep0 SETUP packet. return non-zero on error
- */
-static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp)
-{
- unsigned int x = 0;
- struct urb *purb = ep_ref[0].urb;
- struct usb_endpoint_instance *epi =
- &udc_device->bus->endpoint_array[0];
-
- for (; x < rx_cbdp->cbd_datlen; x++) {
- *(((unsigned char *) &ep_ref[0].urb->device_request) + x) =
- *((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
- }
-
- mpc8xx_udc_clear_rxbd (rx_cbdp);
-
- if (ep0_recv_setup (purb)) {
- mpc8xx_udc_dump_request (&purb->device_request);
- return -1;
- }
-
- if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
- == USB_REQ_HOST2DEVICE) {
-
- switch (purb->device_request.bRequest) {
- case USB_REQ_SET_ADDRESS:
- /* Send the Status OUT ZLP */
- ep_ref[0].pid = TX_BD_PID_DATA1;
- purb->actual_length = 0;
- mpc8xx_udc_init_tx (epi, purb);
- mpc8xx_udc_ep_tx (epi);
-
- /* Move to the addressed state */
- usbp->usaddr = udc_device->address;
- mpc8xx_udc_state_transition_up (udc_device->device_state,
- STATE_ADDRESSED);
- return 0;
-
- case USB_REQ_SET_CONFIGURATION:
- if (!purb->device_request.wValue) {
- /* Respond at default address */
- usbp->usaddr = 0x00;
- mpc8xx_udc_state_transition_down (udc_device->device_state,
- STATE_ADDRESSED);
- } else {
- /* TODO: Support multiple configurations */
- mpc8xx_udc_state_transition_up (udc_device->device_state,
- STATE_CONFIGURED);
- for (x = 1; x < MAX_ENDPOINTS; x++) {
- if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) {
- ep_ref[x].pid = TX_BD_PID_DATA0;
- } else {
- ep_ref[x].pid = RX_BD_PID_DATA0;
- }
- /* Set configuration must unstall endpoints */
- usbp->usep[x] &= ~STALL_BITMASK;
- }
- }
- break;
- default:
- /* CDC/Vendor specific */
- break;
- }
-
- /* Send ZLP as ACK in Status OUT phase */
- ep_ref[0].pid = TX_BD_PID_DATA1;
- purb->actual_length = 0;
- mpc8xx_udc_init_tx (epi, purb);
- mpc8xx_udc_ep_tx (epi);
-
- } else {
-
- if (purb->actual_length) {
- ep_ref[0].pid = TX_BD_PID_DATA1;
- mpc8xx_udc_init_tx (epi, purb);
-
- if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) {
- ep_ref[0].sc |= EP_SEND_ZLP;
- }
-
- if (purb->device_request.wValue ==
- USB_DESCRIPTOR_TYPE_DEVICE) {
- if (le16_to_cpu (purb->device_request.wLength)
- > purb->actual_length) {
- /* Send EP0_MAX_PACKET_SIZE bytes
- * unless correct size requested.
- */
- if (purb->actual_length > epi->tx_packetSize) {
- purb->actual_length = epi->tx_packetSize;
- }
- }
- }
- mpc8xx_udc_ep_tx (epi);
-
- } else {
- /* Corrupt SETUP packet? */
- ERR ("Zero length data or SETUP with DATA-IN phase ?\n");
- return 1;
- }
- }
- return 0;
-}
-
-/* mpc8xx_udc_init_tx
- *
- * Setup some basic parameters for a TX transaction
- */
-static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
- struct urb *tx_urb)
-{
- epi->sent = 0;
- epi->last = 0;
- epi->tx_urb = tx_urb;
-}
-
-/* mpc8xx_udc_ep0_rx
- *
- * Receive ep0/control USB data. Parse and possibly send a response.
- */
-static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp)
-{
- if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) {
-
- /* Unconditionally accept SETUP packets */
- if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) {
- mpc8xx_udc_stall (0);
- }
-
- } else {
-
- mpc8xx_udc_clear_rxbd (rx_cbdp);
-
- if ((rx_cbdp->cbd_datlen - 2)) {
- /* SETUP with a DATA phase
- * outside of SETUP packet.
- * Reply with STALL.
- */
- mpc8xx_udc_stall (0);
- }
- }
-}
-
-/* mpc8xx_udc_epn_rx
- *
- * Receive some data from cbd into USB system urb data abstraction
- * Upper layers should NAK if there is insufficient RX data space
- */
-static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp)
-{
- struct usb_endpoint_instance *epi = 0;
- struct urb *urb = 0;
- unsigned int x = 0;
-
- if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) {
- return 0;
- }
-
- /* USB 2.0 PDF section 8.6.4
- * Discard data with invalid PID it is a resend.
- */
- if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) {
- return 1;
- }
- TOGGLE_RX_PID (ep_ref[epid].pid);
-
- epi = &udc_device->bus->endpoint_array[epid];
- urb = epi->rcv_urb;
-
- for (; x < (rx_cbdp->cbd_datlen - 2); x++) {
- *((unsigned char *) (urb->buffer + urb->actual_length + x)) =
- *((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
- }
-
- if (x) {
- usbd_rcv_complete (epi, x, 0);
- if (ep_ref[epid].urb->status == RECV_ERROR) {
- DBG ("RX error unset NAK\n");
- udc_unset_nak (epid);
- }
- }
- return x;
-}
-
-/* mpc8xx_udc_clock_init
- *
- * Obtain a clock reference for Full Speed Signaling
- */
-static void mpc8xx_udc_clock_init (volatile immap_t * immr,
- volatile cpm8xx_t * cp)
-{
-
-#if defined(CONFIG_SYS_USB_EXTC_CLK)
-
- /* This has been tested with a 48MHz crystal on CLK6 */
- switch (CONFIG_SYS_USB_EXTC_CLK) {
- case 1:
- immr->im_ioport.iop_papar |= 0x0100;
- immr->im_ioport.iop_padir &= ~0x0100;
- cp->cp_sicr |= 0x24;
- break;
- case 2:
- immr->im_ioport.iop_papar |= 0x0200;
- immr->im_ioport.iop_padir &= ~0x0200;
- cp->cp_sicr |= 0x2D;
- break;
- case 3:
- immr->im_ioport.iop_papar |= 0x0400;
- immr->im_ioport.iop_padir &= ~0x0400;
- cp->cp_sicr |= 0x36;
- break;
- case 4:
- immr->im_ioport.iop_papar |= 0x0800;
- immr->im_ioport.iop_padir &= ~0x0800;
- cp->cp_sicr |= 0x3F;
- break;
- default:
- udc_state = STATE_ERROR;
- break;
- }
-
-#elif defined(CONFIG_SYS_USB_BRGCLK)
-
- /* This has been tested with brgclk == 50MHz */
- int divisor = 0;
-
- if (gd->cpu_clk < 48000000L) {
- ERR ("brgclk is too slow for full-speed USB!\n");
- udc_state = STATE_ERROR;
- return;
- }
-
- /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48MHz)
- * but, can /probably/ live with close-ish alternative rates.
- */
- divisor = (gd->cpu_clk / 48000000L) - 1;
- cp->cp_sicr &= ~0x0000003F;
-
- switch (CONFIG_SYS_USB_BRGCLK) {
- case 1:
- cp->cp_brgc1 |= (divisor | CPM_BRG_EN);
- cp->cp_sicr &= ~0x2F;
- break;
- case 2:
- cp->cp_brgc2 |= (divisor | CPM_BRG_EN);
- cp->cp_sicr |= 0x00000009;
- break;
- case 3:
- cp->cp_brgc3 |= (divisor | CPM_BRG_EN);
- cp->cp_sicr |= 0x00000012;
- break;
- case 4:
- cp->cp_brgc4 = (divisor | CPM_BRG_EN);
- cp->cp_sicr |= 0x0000001B;
- break;
- default:
- udc_state = STATE_ERROR;
- break;
- }
-
-#else
-#error "CONFIG_SYS_USB_EXTC_CLK or CONFIG_SYS_USB_BRGCLK must be defined"
-#endif
-
-}
-
-/* mpc8xx_udc_cbd_attach
- *
- * attach a cbd to and endpoint
- */
-static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size)
-{
-
- if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) {
- udc_state = STATE_ERROR;
- return;
- }
-
- if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT ||
- (!tx_size && !rx_size)) {
- udc_state = STATE_ERROR;
- return;
- }
-
- /* Attach CBD to appropiate Parameter RAM Endpoint data structure */
- if (rx_size) {
- endpoints[ep]->rbase = (u32) rx_cbd[rx_ct];
- endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
- rx_ct++;
-
- if (!ep) {
-
- endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
- rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
- rx_ct++;
-
- } else {
- rx_ct += 2;
- endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
- rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
- rx_ct++;
- }
-
- /* Where we expect to RX data on this endpoint */
- ep_ref[ep].prx = rx_cbd[rx_ct - 1];
- } else {
-
- ep_ref[ep].prx = 0;
- endpoints[ep]->rbase = 0;
- endpoints[ep]->rbptr = 0;
- }
-
- if (tx_size) {
- endpoints[ep]->tbase = (u32) tx_cbd[tx_ct];
- endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct];
- tx_ct++;
- } else {
- endpoints[ep]->tbase = 0;
- endpoints[ep]->tbptr = 0;
- }
-
- endpoints[ep]->tstate = 0;
- endpoints[ep]->tbcnt = 0;
- endpoints[ep]->mrblr = EP_MAX_PKT;
- endpoints[ep]->rfcr = 0x18;
- endpoints[ep]->tfcr = 0x18;
- ep_ref[ep].sc |= EP_ATTACHED;
-
- DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n",
- ep, endpoints[ep]->rbase, endpoints[ep]->rbptr,
- endpoints[ep]->tbase, endpoints[ep]->tbptr,
- ep_ref[ep].prx);
-
- return;
-}
-
-/* mpc8xx_udc_cbd_init
- *
- * Allocate space for a cbd and allocate TX/RX data space
- */
-static void mpc8xx_udc_cbd_init (void)
-{
- int i = 0;
-
- for (; i < TX_RING_SIZE; i++) {
- tx_cbd[i] = (cbd_t *)
- mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
- }
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- rx_cbd[i] = (cbd_t *)
- mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
- }
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- tx_cbd[i]->cbd_bufaddr =
- mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
-
- tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W);
- tx_cbd[i]->cbd_datlen = 0x0000;
- }
-
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- rx_cbd[i]->cbd_bufaddr =
- mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
- rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E);
- rx_cbd[i]->cbd_datlen = 0x0000;
-
- }
-
- return;
-}
-
-/* mpc8xx_udc_endpoint_init
- *
- * Attach an endpoint to some dpram
- */
-static void mpc8xx_udc_endpoint_init (void)
-{
- int i = 0;
-
- for (; i < MAX_ENDPOINTS; i++) {
- endpoints[i] = (usb_epb_t *)
- mpc8xx_udc_alloc (sizeof (usb_epb_t), 32);
- }
-}
-
-/* mpc8xx_udc_alloc
- *
- * Grab the address of some dpram
- */
-static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
-{
- u32 retaddr = address_base;
-
- while (retaddr % alignment) {
- retaddr++;
- }
- address_base += data_size;
-
- return retaddr;
-}
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usb/device/bi/omap.c
- * TI OMAP1510 USB bus interface driver
- *
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- * (C) Copyright 2002
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <common.h>
-#include <asm/io.h>
-#ifdef CONFIG_OMAP_SX1
-#include <i2c.h>
-#endif
-
-#include "usbdcore.h"
-#include "usbdcore_omap1510.h"
-#include "usbdcore_ep0.h"
-
-
-#define UDC_INIT_MDELAY 80 /* Device settle delay */
-#define UDC_MAX_ENDPOINTS 31 /* Number of endpoints on this UDC */
-
-/* Some kind of debugging output... */
-#if 1
-#define UDCDBG(str)
-#define UDCDBGA(fmt,args...)
-#else /* The bugs still exists... */
-#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__)
-#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args)
-#endif
-
-#if 1
-#define UDCREG(name)
-#define UDCREGL(name)
-#else /* The bugs still exists... */
-#define UDCREG(name) serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name)) /* For 16-bit regs */
-#define UDCREGL(name) serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name)) /* For 32-bit regs */
-#endif
-
-
-static struct urb *ep0_urb = NULL;
-
-static struct usb_device_instance *udc_device; /* Used in interrupt handler */
-static u16 udc_devstat = 0; /* UDC status (DEVSTAT) */
-static u32 udc_interrupts = 0;
-
-static void udc_stall_ep (unsigned int ep_addr);
-
-
-static struct usb_endpoint_instance *omap1510_find_ep (int ep)
-{
- int i;
-
- for (i = 0; i < udc_device->bus->max_endpoints; i++) {
- if (udc_device->bus->endpoint_array[i].endpoint_address == ep)
- return &udc_device->bus->endpoint_array[i];
- }
- return NULL;
-}
-
-/* ************************************************************************** */
-/* IO
- */
-
-/*
- * omap1510_prepare_endpoint_for_rx
- *
- * This function implements TRM Figure 14-11.
- *
- * The endpoint to prepare for transfer is specified as a physical endpoint
- * number. For OUT (rx) endpoints 1 through 15, the corresponding endpoint
- * configuration register is checked to see if the endpoint is ISO or not.
- * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled.
- * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30.
- */
-static void omap1510_prepare_endpoint_for_rx (int ep_addr)
-{
- int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
- UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr);
- if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) {
- if ((inw (UDC_EP_RX (ep_num)) &
- (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) ==
- UDC_EPn_RX_Valid) {
- /* rx endpoint is valid, non-ISO, so enable its FIFO */
- outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- outw (0, UDC_EP_NUM);
- }
- }
-}
-
-/* omap1510_configure_endpoints
- *
- * This function implements TRM Figure 14-10.
- */
-static void omap1510_configure_endpoints (struct usb_device_instance *device)
-{
- int ep;
- struct usb_bus_instance *bus;
- struct usb_endpoint_instance *endpoint;
- unsigned short ep_ptr;
- unsigned short ep_size;
- unsigned short ep_isoc;
- unsigned short ep_doublebuffer;
- int ep_addr;
- int packet_size;
- int buffer_size;
- int attributes;
-
- bus = device->bus;
-
- /* There is a dedicated 2048 byte buffer for USB packets that may be
- * arbitrarily partitioned among the endpoints on 8-byte boundaries.
- * The first 8 bytes are reserved for receiving setup packets on
- * endpoint 0.
- */
- ep_ptr = 8; /* reserve the first 8 bytes for the setup fifo */
-
- for (ep = 0; ep < bus->max_endpoints; ep++) {
- endpoint = bus->endpoint_array + ep;
- ep_addr = endpoint->endpoint_address;
- if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- /* IN endpoint */
- packet_size = endpoint->tx_packetSize;
- attributes = endpoint->tx_attributes;
- } else {
- /* OUT endpoint */
- packet_size = endpoint->rcv_packetSize;
- attributes = endpoint->rcv_attributes;
- }
-
- switch (packet_size) {
- case 0:
- ep_size = 0;
- break;
- case 8:
- ep_size = 0;
- break;
- case 16:
- ep_size = 1;
- break;
- case 32:
- ep_size = 2;
- break;
- case 64:
- ep_size = 3;
- break;
- case 128:
- ep_size = 4;
- break;
- case 256:
- ep_size = 5;
- break;
- case 512:
- ep_size = 6;
- break;
- default:
- UDCDBGA ("ep 0x%02x has bad packet size %d",
- ep_addr, packet_size);
- packet_size = 0;
- ep_size = 0;
- break;
- }
-
- switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_CONTROL:
- case USB_ENDPOINT_XFER_BULK:
- case USB_ENDPOINT_XFER_INT:
- default:
- /* A non-isochronous endpoint may optionally be
- * double-buffered. For now we disable
- * double-buffering.
- */
- ep_doublebuffer = 0;
- ep_isoc = 0;
- if (packet_size > 64)
- packet_size = 0;
- if (!ep || !ep_doublebuffer)
- buffer_size = packet_size;
- else
- buffer_size = packet_size * 2;
- break;
- case USB_ENDPOINT_XFER_ISOC:
- /* Isochronous endpoints are always double-
- * buffered, but the double-buffering bit
- * in the endpoint configuration register
- * becomes the msb of the endpoint size so we
- * set the double-buffering flag to zero.
- */
- ep_doublebuffer = 0;
- ep_isoc = 1;
- buffer_size = packet_size * 2;
- break;
- }
-
- /* check to see if our packet buffer RAM is exhausted */
- if ((ep_ptr + buffer_size) > 2048) {
- UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size);
- buffer_size = packet_size = 0;
- }
-
- /* force a default configuration for endpoint 0 since it is
- * always enabled
- */
- if (!ep && ((packet_size < 8) || (packet_size > 64))) {
- buffer_size = packet_size = 64;
- ep_size = 3;
- }
-
- if (!ep) {
- /* configure endpoint 0 */
- outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0);
- /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */
- /* ep_ptr, packet_size); */
- } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- /* IN endpoint */
- if (packet_size) {
- outw ((1 << 15) | (ep_doublebuffer << 14) |
- (ep_size << 12) | (ep_isoc << 11) |
- (ep_ptr >> 3),
- UDC_EP_TX (ep_addr &
- USB_ENDPOINT_NUMBER_MASK));
- UDCDBGA ("IN ep %d buffer offset 0x%03x"
- " packet size 0x%03x",
- ep_addr & USB_ENDPOINT_NUMBER_MASK,
- ep_ptr, packet_size);
- } else {
- outw (0,
- UDC_EP_TX (ep_addr &
- USB_ENDPOINT_NUMBER_MASK));
- }
- } else {
- /* OUT endpoint */
- if (packet_size) {
- outw ((1 << 15) | (ep_doublebuffer << 14) |
- (ep_size << 12) | (ep_isoc << 11) |
- (ep_ptr >> 3),
- UDC_EP_RX (ep_addr &
- USB_ENDPOINT_NUMBER_MASK));
- UDCDBGA ("OUT ep %d buffer offset 0x%03x"
- " packet size 0x%03x",
- ep_addr & USB_ENDPOINT_NUMBER_MASK,
- ep_ptr, packet_size);
- } else {
- outw (0,
- UDC_EP_RX (ep_addr &
- USB_ENDPOINT_NUMBER_MASK));
- }
- }
- ep_ptr += buffer_size;
- }
-}
-
-/* omap1510_deconfigure_device
- *
- * This function balances omap1510_configure_device.
- */
-static void omap1510_deconfigure_device (void)
-{
- int epnum;
-
- UDCDBG ("clear Cfg_Lock");
- outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1);
- UDCREG (UDC_SYSCON1);
-
- /* deconfigure all endpoints */
- for (epnum = 1; epnum <= 15; epnum++) {
- outw (0, UDC_EP_RX (epnum));
- outw (0, UDC_EP_TX (epnum));
- }
-}
-
-/* omap1510_configure_device
- *
- * This function implements TRM Figure 14-9.
- */
-static void omap1510_configure_device (struct usb_device_instance *device)
-{
- omap1510_configure_endpoints (device);
-
-
- /* Figure 14-9 indicates we should enable interrupts here, but we have
- * other routines (udc_all_interrupts, udc_suspended_interrupts) to
- * do that.
- */
-
- UDCDBG ("set Cfg_Lock");
- outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1);
- UDCREG (UDC_SYSCON1);
-}
-
-/* omap1510_write_noniso_tx_fifo
- *
- * This function implements TRM Figure 14-30.
- *
- * If the endpoint has an active tx_urb, then the next packet of data from the
- * URB is written to the tx FIFO. The total amount of data in the urb is given
- * by urb->actual_length. The maximum amount of data that can be sent in any
- * one packet is given by endpoint->tx_packetSize. The number of data bytes
- * from this URB that have already been transmitted is given by endpoint->sent.
- * endpoint->last is updated by this routine with the number of data bytes
- * transmitted in this packet.
- *
- * In accordance with Figure 14-30, the EP_NUM register must already have been
- * written with the value to select the appropriate tx FIFO before this routine
- * is called.
- */
-static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance
- *endpoint)
-{
- struct urb *urb = endpoint->tx_urb;
-
- if (urb) {
- unsigned int last, i;
-
- UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d",
- urb->buffer, urb->buffer_length, urb->actual_length);
- if ((last =
- MIN (urb->actual_length - endpoint->sent,
- endpoint->tx_packetSize))) {
- u8 *cp = urb->buffer + endpoint->sent;
-
- UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last);
-
- if (((u32) cp & 1) == 0) { /* word aligned? */
- outsw (UDC_DATA, cp, last >> 1);
- } else { /* byte aligned. */
- for (i = 0; i < (last >> 1); i++) {
- u16 w = ((u16) cp[2 * i + 1] << 8) |
- (u16) cp[2 * i];
- outw (w, UDC_DATA);
- }
- }
- if (last & 1) {
- outb (*(cp + last - 1), UDC_DATA);
- }
- }
- endpoint->last = last;
- }
-}
-
-/* omap1510_read_noniso_rx_fifo
- *
- * This function implements TRM Figure 14-28.
- *
- * If the endpoint has an active rcv_urb, then the next packet of data is read
- * from the rcv FIFO and written to rcv_urb->buffer at offset
- * rcv_urb->actual_length to append the packet data to the data from any
- * previous packets for this transfer. We assume that there is sufficient room
- * left in the buffer to hold an entire packet of data.
- *
- * The return value is the number of bytes read from the FIFO for this packet.
- *
- * In accordance with Figure 14-28, the EP_NUM register must already have been
- * written with the value to select the appropriate rcv FIFO before this routine
- * is called.
- */
-static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance
- *endpoint)
-{
- struct urb *urb = endpoint->rcv_urb;
- int len = 0;
-
- if (urb) {
- len = inw (UDC_RXFSTAT);
-
- if (len) {
- unsigned char *cp = urb->buffer + urb->actual_length;
-
- insw (UDC_DATA, cp, len >> 1);
- if (len & 1)
- *(cp + len - 1) = inb (UDC_DATA);
- }
- }
- return len;
-}
-
-/* omap1510_prepare_for_control_write_status
- *
- * This function implements TRM Figure 14-17.
- *
- * We have to deal here with non-autodecoded control writes that haven't already
- * been dealt with by ep0_recv_setup. The non-autodecoded standard control
- * write requests are: set/clear endpoint feature, set configuration, set
- * interface, and set descriptor. ep0_recv_setup handles set/clear requests for
- * ENDPOINT_HALT by halting the endpoint for a set request and resetting the
- * endpoint for a clear request. ep0_recv_setup returns an error for
- * SET_DESCRIPTOR requests which causes them to be terminated with a stall by
- * the setup handler. A SET_INTERFACE request is handled by ep0_recv_setup by
- * generating a DEVICE_SET_INTERFACE event. This leaves only the
- * SET_CONFIGURATION event for us to deal with here.
- *
- */
-static void omap1510_prepare_for_control_write_status (struct urb *urb)
-{
- struct usb_device_request *request = &urb->device_request;;
-
- /* check for a SET_CONFIGURATION request */
- if (request->bRequest == USB_REQ_SET_CONFIGURATION) {
- int configuration = le16_to_cpu (request->wValue) & 0xff;
- unsigned short devstat = inw (UDC_DEVSTAT);
-
- if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) {
- /* device is currently in ADDRESSED state */
- if (configuration) {
- /* Assume the specified non-zero configuration
- * value is valid and switch to the CONFIGURED
- * state.
- */
- outw (UDC_Dev_Cfg, UDC_SYSCON2);
- }
- } else if ((devstat & UDC_CFG) == UDC_CFG) {
- /* device is currently in CONFIGURED state */
- if (!configuration) {
- /* Switch to ADDRESSED state. */
- outw (UDC_Clr_Cfg, UDC_SYSCON2);
- }
- }
- }
-
- /* select EP0 tx FIFO */
- outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
- /* clear endpoint (no data bytes in status stage) */
- outw (UDC_Clr_EP, UDC_CTRL);
- /* enable the EP0 tx FIFO */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- /* deselect the endpoint */
- outw (UDC_EP_Dir, UDC_EP_NUM);
-}
-
-/* udc_state_transition_up
- * udc_state_transition_down
- *
- * Helper functions to implement device state changes. The device states and
- * the events that transition between them are:
- *
- * STATE_ATTACHED
- * || /\
- * \/ ||
- * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET
- * || /\
- * \/ ||
- * STATE_POWERED
- * || /\
- * \/ ||
- * DEVICE_RESET DEVICE_POWER_INTERRUPTION
- * || /\
- * \/ ||
- * STATE_DEFAULT
- * || /\
- * \/ ||
- * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET
- * || /\
- * \/ ||
- * STATE_ADDRESSED
- * || /\
- * \/ ||
- * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED
- * || /\
- * \/ ||
- * STATE_CONFIGURED
- *
- * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
- * to STATE_CONFIGURED) from the specified initial state to the specified final
- * state, passing through each intermediate state on the way. If the initial
- * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
- * no state transitions will take place.
- *
- * udc_state_transition_down transitions down (in the direction from
- * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
- * specified final state, passing through each intermediate state on the way.
- * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
- * state, then no state transitions will take place.
- *
- * These functions must only be called with interrupts disabled.
- */
-static void udc_state_transition_up (usb_device_state_t initial,
- usb_device_state_t final)
-{
- if (initial < final) {
- switch (initial) {
- case STATE_ATTACHED:
- usbd_device_event_irq (udc_device,
- DEVICE_HUB_CONFIGURED, 0);
- if (final == STATE_POWERED)
- break;
- case STATE_POWERED:
- usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
- if (final == STATE_DEFAULT)
- break;
- case STATE_DEFAULT:
- usbd_device_event_irq (udc_device,
- DEVICE_ADDRESS_ASSIGNED, 0);
- if (final == STATE_ADDRESSED)
- break;
- case STATE_ADDRESSED:
- usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
- 0);
- case STATE_CONFIGURED:
- break;
- default:
- break;
- }
- }
-}
-
-static void udc_state_transition_down (usb_device_state_t initial,
- usb_device_state_t final)
-{
- if (initial > final) {
- switch (initial) {
- case STATE_CONFIGURED:
- usbd_device_event_irq (udc_device, DEVICE_DE_CONFIGURED, 0);
- if (final == STATE_ADDRESSED)
- break;
- case STATE_ADDRESSED:
- usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
- if (final == STATE_DEFAULT)
- break;
- case STATE_DEFAULT:
- usbd_device_event_irq (udc_device, DEVICE_POWER_INTERRUPTION, 0);
- if (final == STATE_POWERED)
- break;
- case STATE_POWERED:
- usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, 0);
- case STATE_ATTACHED:
- break;
- default:
- break;
- }
- }
-}
-
-/* Handle all device state changes.
- * This function implements TRM Figure 14-21.
- */
-static void omap1510_udc_state_changed (void)
-{
- u16 bits;
- u16 devstat = inw (UDC_DEVSTAT);
-
- UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat);
-
- bits = devstat ^ udc_devstat;
- if (bits) {
- if (bits & UDC_ATT) {
- if (devstat & UDC_ATT) {
- UDCDBG ("device attached and powered");
- udc_state_transition_up (udc_device->device_state, STATE_POWERED);
- } else {
- UDCDBG ("device detached or unpowered");
- udc_state_transition_down (udc_device->device_state, STATE_ATTACHED);
- }
- }
- if (bits & UDC_USB_Reset) {
- if (devstat & UDC_USB_Reset) {
- UDCDBG ("device reset in progess");
- udc_state_transition_down (udc_device->device_state, STATE_POWERED);
- } else {
- UDCDBG ("device reset completed");
- }
- }
- if (bits & UDC_DEF) {
- if (devstat & UDC_DEF) {
- UDCDBG ("device entering default state");
- udc_state_transition_up (udc_device->device_state, STATE_DEFAULT);
- } else {
- UDCDBG ("device leaving default state");
- udc_state_transition_down (udc_device->device_state, STATE_POWERED);
- }
- }
- if (bits & UDC_SUS) {
- if (devstat & UDC_SUS) {
- UDCDBG ("entering suspended state");
- usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0);
- } else {
- UDCDBG ("leaving suspended state");
- usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0);
- }
- }
- if (bits & UDC_R_WK_OK) {
- UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK)
- ? "enabled" : "disabled");
- }
- if (bits & UDC_ADD) {
- if (devstat & UDC_ADD) {
- UDCDBG ("default -> addressed");
- udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED);
- } else {
- UDCDBG ("addressed -> default");
- udc_state_transition_down (udc_device->device_state, STATE_DEFAULT);
- }
- }
- if (bits & UDC_CFG) {
- if (devstat & UDC_CFG) {
- UDCDBG ("device configured");
- /* The ep0_recv_setup function generates the
- * DEVICE_CONFIGURED event when a
- * USB_REQ_SET_CONFIGURATION setup packet is
- * received, so we should already be in the
- * state STATE_CONFIGURED.
- */
- udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED);
- } else {
- UDCDBG ("device deconfigured");
- udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED);
- }
- }
- }
-
- /* Clear interrupt source */
- outw (UDC_DS_Chg, UDC_IRQ_SRC);
-
- /* Save current DEVSTAT */
- udc_devstat = devstat;
-}
-
-/* Handle SETUP USB interrupt.
- * This function implements TRM Figure 14-14.
- */
-static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint)
-{
- UDCDBG ("-> Entering device setup");
-
- do {
- const int setup_pktsize = 8;
- unsigned char *datap =
- (unsigned char *) &ep0_urb->device_request;
-
- /* Gain access to EP 0 setup FIFO */
- outw (UDC_Setup_Sel, UDC_EP_NUM);
-
- /* Read control request data */
- insb (UDC_DATA, datap, setup_pktsize);
-
- UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]",
- *(datap + 0), *(datap + 1), *(datap + 2),
- *(datap + 3), *(datap + 4), *(datap + 5),
- *(datap + 6), *(datap + 7));
-
- /* Reset EP0 setup FIFO */
- outw (0, UDC_EP_NUM);
- } while (inw (UDC_IRQ_SRC) & UDC_Setup);
-
- /* Try to process setup packet */
- if (ep0_recv_setup (ep0_urb)) {
- /* Not a setup packet, stall next EP0 transaction */
- udc_stall_ep (0);
- UDCDBG ("can't parse setup packet, still waiting for setup");
- return;
- }
-
- /* Check direction */
- if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
- == USB_REQ_HOST2DEVICE) {
- UDCDBG ("control write on EP0");
- if (le16_to_cpu (ep0_urb->device_request.wLength)) {
- /* We don't support control write data stages.
- * The only standard control write request with a data
- * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't
- * support that so we just stall those requests. A
- * function driver might support a non-standard
- * write request with a data stage, but it isn't
- * obvious what we would do with the data if we read it
- * so we'll just stall it. It seems like the API isn't
- * quite right here.
- */
-#if 0
- /* Here is what we would do if we did support control
- * write data stages.
- */
- ep0_urb->actual_length = 0;
- outw (0, UDC_EP_NUM);
- /* enable the EP0 rx FIFO */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
-#else
- /* Stall this request */
- UDCDBG ("Stalling unsupported EP0 control write data "
- "stage.");
- udc_stall_ep (0);
-#endif
- } else {
- omap1510_prepare_for_control_write_status (ep0_urb);
- }
- } else {
- UDCDBG ("control read on EP0");
- /* The ep0_recv_setup function has already placed our response
- * packet data in ep0_urb->buffer and the packet length in
- * ep0_urb->actual_length.
- */
- endpoint->tx_urb = ep0_urb;
- endpoint->sent = 0;
- /* select the EP0 tx FIFO */
- outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
- /* Write packet data to the FIFO. omap1510_write_noniso_tx_fifo
- * will update endpoint->last with the number of bytes written
- * to the FIFO.
- */
- omap1510_write_noniso_tx_fifo (endpoint);
- /* enable the FIFO to start the packet transmission */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- /* deselect the EP0 tx FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- }
-
- UDCDBG ("<- Leaving device setup");
-}
-
-/* Handle endpoint 0 RX interrupt
- * This routine implements TRM Figure 14-16.
- */
-static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint)
-{
- unsigned short status;
-
- UDCDBG ("RX on EP0");
- /* select EP0 rx FIFO */
- outw (UDC_EP_Sel, UDC_EP_NUM);
-
- status = inw (UDC_STAT_FLG);
-
- if (status & UDC_ACK) {
- /* Check direction */
- if ((ep0_urb->device_request.bmRequestType
- & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {
- /* This rx interrupt must be for a control write data
- * stage packet.
- *
- * We don't support control write data stages.
- * We should never end up here.
- */
-
- /* clear the EP0 rx FIFO */
- outw (UDC_Clr_EP, UDC_CTRL);
-
- /* deselect the EP0 rx FIFO */
- outw (0, UDC_EP_NUM);
-
- UDCDBG ("Stalling unexpected EP0 control write "
- "data stage packet");
- udc_stall_ep (0);
- } else {
- /* This rx interrupt must be for a control read status
- * stage packet.
- */
- UDCDBG ("ACK on EP0 control read status stage packet");
- /* deselect EP0 rx FIFO */
- outw (0, UDC_EP_NUM);
- }
- } else if (status & UDC_STALL) {
- UDCDBG ("EP0 stall during RX");
- /* deselect EP0 rx FIFO */
- outw (0, UDC_EP_NUM);
- } else {
- /* deselect EP0 rx FIFO */
- outw (0, UDC_EP_NUM);
- }
-}
-
-/* Handle endpoint 0 TX interrupt
- * This routine implements TRM Figure 14-18.
- */
-static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint)
-{
- unsigned short status;
- struct usb_device_request *request = &ep0_urb->device_request;
-
- UDCDBG ("TX on EP0");
- /* select EP0 TX FIFO */
- outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
-
- status = inw (UDC_STAT_FLG);
- if (status & UDC_ACK) {
- /* Check direction */
- if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) ==
- USB_REQ_HOST2DEVICE) {
- /* This tx interrupt must be for a control write status
- * stage packet.
- */
- UDCDBG ("ACK on EP0 control write status stage packet");
- /* deselect EP0 TX FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- } else {
- /* This tx interrupt must be for a control read data
- * stage packet.
- */
- int wLength = le16_to_cpu (request->wLength);
-
- /* Update our count of bytes sent so far in this
- * transfer.
- */
- endpoint->sent += endpoint->last;
-
- /* We are finished with this transfer if we have sent
- * all of the bytes in our tx urb (urb->actual_length)
- * unless we need a zero-length terminating packet. We
- * need a zero-length terminating packet if we returned
- * fewer bytes than were requested (wLength) by the host,
- * and the number of bytes we returned is an exact
- * multiple of the packet size endpoint->tx_packetSize.
- */
- if ((endpoint->sent == ep0_urb->actual_length)
- && ((ep0_urb->actual_length == wLength)
- || (endpoint->last !=
- endpoint->tx_packetSize))) {
- /* Done with control read data stage. */
- UDCDBG ("control read data stage complete");
- /* deselect EP0 TX FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- /* select EP0 RX FIFO to prepare for control
- * read status stage.
- */
- outw (UDC_EP_Sel, UDC_EP_NUM);
- /* clear the EP0 RX FIFO */
- outw (UDC_Clr_EP, UDC_CTRL);
- /* enable the EP0 RX FIFO */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- /* deselect the EP0 RX FIFO */
- outw (0, UDC_EP_NUM);
- } else {
- /* We still have another packet of data to send
- * in this control read data stage or else we
- * need a zero-length terminating packet.
- */
- UDCDBG ("ACK control read data stage packet");
- omap1510_write_noniso_tx_fifo (endpoint);
- /* enable the EP0 tx FIFO to start transmission */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- /* deselect EP0 TX FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- }
- }
- } else if (status & UDC_STALL) {
- UDCDBG ("EP0 stall during TX");
- /* deselect EP0 TX FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- } else {
- /* deselect EP0 TX FIFO */
- outw (UDC_EP_Dir, UDC_EP_NUM);
- }
-}
-
-/* Handle RX transaction on non-ISO endpoint.
- * This function implements TRM Figure 14-27.
- * The ep argument is a physical endpoint number for a non-ISO OUT endpoint
- * in the range 1 to 15.
- */
-static void omap1510_udc_epn_rx (int ep)
-{
- unsigned short status;
-
- /* Check endpoint status */
- status = inw (UDC_STAT_FLG);
-
- if (status & UDC_ACK) {
- int nbytes;
- struct usb_endpoint_instance *endpoint =
- omap1510_find_ep (ep);
-
- nbytes = omap1510_read_noniso_rx_fifo (endpoint);
- usbd_rcv_complete (endpoint, nbytes, 0);
-
- /* enable rx FIFO to prepare for next packet */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- } else if (status & UDC_STALL) {
- UDCDBGA ("STALL on RX endpoint %d", ep);
- } else if (status & UDC_NAK) {
- UDCDBGA ("NAK on RX ep %d", ep);
- } else {
- serial_printf ("omap-bi: RX on ep %d with status %x", ep,
- status);
- }
-}
-
-/* Handle TX transaction on non-ISO endpoint.
- * This function implements TRM Figure 14-29.
- * The ep argument is a physical endpoint number for a non-ISO IN endpoint
- * in the range 16 to 30.
- */
-static void omap1510_udc_epn_tx (int ep)
-{
- unsigned short status;
-
- /*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */
-
- /* Check endpoint status */
- status = inw (UDC_STAT_FLG);
-
- if (status & UDC_ACK) {
- struct usb_endpoint_instance *endpoint =
- omap1510_find_ep (ep);
-
- /* We need to transmit a terminating zero-length packet now if
- * we have sent all of the data in this URB and the transfer
- * size was an exact multiple of the packet size.
- */
- if (endpoint->tx_urb
- && (endpoint->last == endpoint->tx_packetSize)
- && (endpoint->tx_urb->actual_length - endpoint->sent -
- endpoint->last == 0)) {
- /* Prepare to transmit a zero-length packet. */
- endpoint->sent += endpoint->last;
- /* write 0 bytes of data to FIFO */
- omap1510_write_noniso_tx_fifo (endpoint);
- /* enable tx FIFO to start transmission */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- } else if (endpoint->tx_urb
- && endpoint->tx_urb->actual_length) {
- /* retire the data that was just sent */
- usbd_tx_complete (endpoint);
- /* Check to see if we have more data ready to transmit
- * now.
- */
- if (endpoint->tx_urb
- && endpoint->tx_urb->actual_length) {
- /* write data to FIFO */
- omap1510_write_noniso_tx_fifo (endpoint);
- /* enable tx FIFO to start transmission */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- }
- }
- } else if (status & UDC_STALL) {
- UDCDBGA ("STALL on TX endpoint %d", ep);
- } else if (status & UDC_NAK) {
- UDCDBGA ("NAK on TX endpoint %d", ep);
- } else {
- /*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */
- }
-}
-
-
-/*
--------------------------------------------------------------------------------
-*/
-
-/* Handle general USB interrupts and dispatch according to type.
- * This function implements TRM Figure 14-13.
- */
-void omap1510_udc_irq (void)
-{
- u16 irq_src = inw (UDC_IRQ_SRC);
- int valid_irq = 0;
-
- if (!(irq_src & ~UDC_SOF_Flg)) /* ignore SOF interrupts ) */
- return;
-
- UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src);
- /*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */
-
- if (irq_src & UDC_DS_Chg) {
- /* Device status changed */
- omap1510_udc_state_changed ();
- valid_irq++;
- }
- if (irq_src & UDC_EP0_RX) {
- /* Endpoint 0 receive */
- outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */
- omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0);
- valid_irq++;
- }
- if (irq_src & UDC_EP0_TX) {
- /* Endpoint 0 transmit */
- outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */
- omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0);
- valid_irq++;
- }
- if (irq_src & UDC_Setup) {
- /* Device setup */
- omap1510_udc_setup (udc_device->bus->endpoint_array + 0);
- valid_irq++;
- }
- /*if (!valid_irq) */
- /* serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */
- UDCDBGA ("< IRQ #%d end >", udc_interrupts);
- udc_interrupts++;
-}
-
-/* This function implements TRM Figure 14-26. */
-void omap1510_udc_noniso_irq (void)
-{
- unsigned short epnum;
- unsigned short irq_src = inw (UDC_IRQ_SRC);
- int valid_irq = 0;
-
- if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX)))
- return;
-
- UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC));
-
- if (irq_src & UDC_EPn_RX) { /* Endpoint N OUT transaction */
- /* Determine the endpoint number for this interrupt */
- epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8;
- UDCDBGA ("RX on ep %x", epnum);
-
- /* acknowledge interrupt */
- outw (UDC_EPn_RX, UDC_IRQ_SRC);
-
- if (epnum) {
- /* select the endpoint FIFO */
- outw (UDC_EP_Sel | epnum, UDC_EP_NUM);
-
- omap1510_udc_epn_rx (epnum);
-
- /* deselect the endpoint FIFO */
- outw (epnum, UDC_EP_NUM);
- }
- valid_irq++;
- }
- if (irq_src & UDC_EPn_TX) { /* Endpoint N IN transaction */
- /* Determine the endpoint number for this interrupt */
- epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN;
- UDCDBGA ("TX on ep %x", epnum);
-
- /* acknowledge interrupt */
- outw (UDC_EPn_TX, UDC_IRQ_SRC);
-
- if (epnum) {
- /* select the endpoint FIFO */
- outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
-
- omap1510_udc_epn_tx (epnum);
-
- /* deselect the endpoint FIFO */
- outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
- }
- valid_irq++;
- }
- if (!valid_irq)
- serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n",
- irq_src);
-}
-
-/*
--------------------------------------------------------------------------------
-*/
-
-
-/*
- * Start of public functions.
- */
-
-/* Called to start packet transmission. */
-int udc_endpoint_write (struct usb_endpoint_instance *endpoint)
-{
- unsigned short epnum =
- endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK;
-
- UDCDBGA ("Starting transmit on ep %x", epnum);
-
- if (endpoint->tx_urb) {
- /* select the endpoint FIFO */
- outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM);
- /* write data to FIFO */
- omap1510_write_noniso_tx_fifo (endpoint);
- /* enable tx FIFO to start transmission */
- outw (UDC_Set_FIFO_En, UDC_CTRL);
- /* deselect the endpoint FIFO */
- outw (UDC_EP_Dir | epnum, UDC_EP_NUM);
- }
-
- return 0;
-}
-
-/* Start to initialize h/w stuff */
-int udc_init (void)
-{
- u16 udc_rev;
- uchar value;
- ulong gpio;
- int i;
-
- /* Let the device settle down before we start */
- for (i = 0; i < UDC_INIT_MDELAY; i++) udelay(1000);
-
- udc_device = NULL;
-
- UDCDBG ("starting");
-
- /* Check peripheral reset. Must be 1 to make sure
- MPU TIPB peripheral reset is inactive */
- UDCREG (ARM_RSTCT2);
-
- /* Set and check clock control.
- * We might ought to be using the clock control API to do
- * this instead of fiddling with the clock registers directly
- * here.
- */
- outw ((1 << 4) | (1 << 5), CLOCK_CTRL);
- UDCREG (CLOCK_CTRL);
-
-#ifdef CONFIG_OMAP1510
- /* This code was originally implemented for OMAP1510 and
- * therefore is only applicable for OMAP1510 boards. For
- * OMAP5912 or OMAP16xx the register APLL_CTRL does not
- * exist and DPLL_CTRL is already configured.
- */
-
- /* Set and check APLL */
- outw (0x0008, APLL_CTRL);
- UDCREG (APLL_CTRL);
- /* Set and check DPLL */
- outw (0x2210, DPLL_CTRL);
- UDCREG (DPLL_CTRL);
-#endif
- /* Set and check SOFT
- * The below line of code has been changed to perform a
- * read-modify-write instead of a simple write for
- * configuring the SOFT_REQ register. This allows the code
- * to be compatible with OMAP5912 and OMAP16xx devices
- */
- outw ((1 << 4) | (1 << 3) | 1 | (inw(SOFT_REQ)), SOFT_REQ);
-
- /* Short delay to wait for DPLL */
- udelay (1000);
-
- /* Print banner with device revision */
- udc_rev = inw (UDC_REV) & 0xff;
-#ifdef CONFIG_OMAP1510
- printf ("USB: TI OMAP1510 USB function module rev %d.%d\n",
- udc_rev >> 4, udc_rev & 0xf);
-#endif
-
-#ifdef CONFIG_OMAP1610
- printf ("USB: TI OMAP5912 USB function module rev %d.%d\n",
- udc_rev >> 4, udc_rev & 0xf);
-#endif
-
-#ifdef CONFIG_OMAP_SX1
- i2c_read (0x32, 0x04, 1, &value, 1);
- value |= 0x04;
- i2c_write (0x32, 0x04, 1, &value, 1);
-
- i2c_read (0x32, 0x03, 1, &value, 1);
- value |= 0x01;
- i2c_write (0x32, 0x03, 1, &value, 1);
-
- gpio = inl(GPIO_PIN_CONTROL_REG);
- gpio |= 0x0002; /* A_IRDA_OFF */
- gpio |= 0x0800; /* A_SWITCH */
- gpio |= 0x8000; /* A_USB_ON */
- outl (gpio, GPIO_PIN_CONTROL_REG);
-
- gpio = inl(GPIO_DIR_CONTROL_REG);
- gpio &= ~0x0002; /* A_IRDA_OFF */
- gpio &= ~0x0800; /* A_SWITCH */
- gpio &= ~0x8000; /* A_USB_ON */
- outl (gpio, GPIO_DIR_CONTROL_REG);
-
- gpio = inl(GPIO_DATA_OUTPUT_REG);
- gpio |= 0x0002; /* A_IRDA_OFF */
- gpio &= ~0x0800; /* A_SWITCH */
- gpio &= ~0x8000; /* A_USB_ON */
- outl (gpio, GPIO_DATA_OUTPUT_REG);
-#endif
-
- /* The VBUS_MODE bit selects whether VBUS detection is done via
- * software (1) or hardware (0). When software detection is
- * selected, VBUS_CTRL selects whether USB is not connected (0)
- * or connected (1).
- */
- outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
- outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
- UDCREGL (FUNC_MUX_CTRL_0);
-
- /*
- * At this point, device is ready for configuration...
- */
-
- UDCDBG ("disable USB interrupts");
- outw (0, UDC_IRQ_EN);
- UDCREG (UDC_IRQ_EN);
-
- UDCDBG ("disable USB DMA");
- outw (0, UDC_DMA_IRQ_EN);
- UDCREG (UDC_DMA_IRQ_EN);
-
- UDCDBG ("initialize SYSCON1");
- outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1);
- UDCREG (UDC_SYSCON1);
-
- return 0;
-}
-
-/* Stall endpoint */
-static void udc_stall_ep (unsigned int ep_addr)
-{
- /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
- int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
- UDCDBGA ("stall ep_addr %d", ep_addr);
-
- /* REVISIT?
- * The OMAP TRM section 14.2.4.2 says we must check that the FIFO
- * is empty before halting the endpoint. The current implementation
- * doesn't check that the FIFO is empty.
- */
-
- if (!ep_num) {
- outw (UDC_Stall_Cmd, UDC_SYSCON2);
- } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
- /* we have a valid rx endpoint, so halt it */
- outw (UDC_EP_Sel | ep_num, UDC_EP_NUM);
- outw (UDC_Set_Halt, UDC_CTRL);
- outw (ep_num, UDC_EP_NUM);
- }
- } else {
- if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
- /* we have a valid tx endpoint, so halt it */
- outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM);
- outw (UDC_Set_Halt, UDC_CTRL);
- outw (ep_num, UDC_EP_NUM);
- }
- }
-}
-
-/* Reset endpoint */
-#if 0
-static void udc_reset_ep (unsigned int ep_addr)
-{
- /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
- int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
-
- UDCDBGA ("reset ep_addr %d", ep_addr);
-
- if (!ep_num) {
- /* control endpoint 0 can't be reset */
- } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num,
- inw (UDC_EP_RX (ep_num)));
- if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) {
- /* we have a valid rx endpoint, so reset it */
- outw (ep_num | UDC_EP_Sel, UDC_EP_NUM);
- outw (UDC_Reset_EP, UDC_CTRL);
- outw (ep_num, UDC_EP_NUM);
- UDCDBGA ("OUT endpoint %d reset", ep_num);
- }
- } else {
- UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num,
- inw (UDC_EP_TX (ep_num)));
- /* Resetting of tx endpoints seems to be causing the USB function
- * module to fail, which causes problems when the driver is
- * uninstalled. We'll skip resetting tx endpoints for now until
- * we figure out what the problem is.
- */
-#if 0
- if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) {
- /* we have a valid tx endpoint, so reset it */
- outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM);
- outw (UDC_Reset_EP, UDC_CTRL);
- outw (ep_num | UDC_EP_Dir, UDC_EP_NUM);
- UDCDBGA ("IN endpoint %d reset", ep_num);
- }
-#endif
- }
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_check_ep - check logical endpoint
- *
- * Return physical endpoint number to use for this logical endpoint or zero if not valid.
- */
-#if 0
-int udc_check_ep (int logical_endpoint, int packetsize)
-{
- if ((logical_endpoint == 0x80) ||
- ((logical_endpoint & 0x8f) != logical_endpoint)) {
- return 0;
- }
-
- switch (packetsize) {
- case 8:
- case 16:
- case 32:
- case 64:
- case 128:
- case 256:
- case 512:
- break;
- default:
- return 0;
- }
-
- return EP_ADDR_TO_PHYS_EP (logical_endpoint);
-}
-#endif
-
-/*
- * udc_setup_ep - setup endpoint
- *
- * Associate a physical endpoint with endpoint_instance
- */
-void udc_setup_ep (struct usb_device_instance *device,
- unsigned int ep, struct usb_endpoint_instance *endpoint)
-{
- UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address);
-
- /* This routine gets called by bi_modinit for endpoint 0 and from
- * bi_config for all of the other endpoints. bi_config gets called
- * during the DEVICE_CREATE, DEVICE_CONFIGURED, and
- * DEVICE_SET_INTERFACE events. We need to reconfigure the OMAP packet
- * RAM after bi_config scans the selected device configuration and
- * initializes the endpoint structures, but before this routine enables
- * the OUT endpoint FIFOs. Since bi_config calls this routine in a
- * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our
- * packet RAM here when ep==1.
- * I really hate to do this here, but it seems like the API exported
- * by the USB bus interface controller driver to the usbd-bi module
- * isn't quite right so there is no good place to do this.
- */
- if (ep == 1) {
- omap1510_deconfigure_device ();
- omap1510_configure_device (device);
- }
-
- if (endpoint && (ep < UDC_MAX_ENDPOINTS)) {
- int ep_addr = endpoint->endpoint_address;
-
- if (!ep_addr) {
- /* nothing to do for endpoint 0 */
- } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- /* nothing to do for IN (tx) endpoints */
- } else { /* OUT (rx) endpoint */
- if (endpoint->rcv_packetSize) {
- /*struct urb* urb = &(urb_out_array[ep&0xFF]); */
- /*urb->endpoint = endpoint; */
- /*urb->device = device; */
- /*urb->buffer_length = sizeof(urb->buffer); */
-
- /*endpoint->rcv_urb = urb; */
- omap1510_prepare_endpoint_for_rx (ep_addr);
- }
- }
- }
-}
-
-/**
- * udc_disable_ep - disable endpoint
- * @ep:
- *
- * Disable specified endpoint
- */
-#if 0
-void udc_disable_ep (unsigned int ep_addr)
-{
- /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */
- int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK;
- struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr); /*udc_device->bus->endpoint_array + ep; */
-
- UDCDBGA ("disable ep_addr %d", ep_addr);
-
- if (!ep_num) {
- /* nothing to do for endpoint 0 */ ;
- } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- if (endpoint->tx_packetSize) {
- /* we have a valid tx endpoint */
- /*usbd_flush_tx(endpoint); */
- endpoint->tx_urb = NULL;
- }
- } else {
- if (endpoint->rcv_packetSize) {
- /* we have a valid rx endpoint */
- /*usbd_flush_rcv(endpoint); */
- endpoint->rcv_urb = NULL;
- }
- }
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_connected - is the USB cable connected
- *
- * Return non-zero if cable is connected.
- */
-#if 0
-int udc_connected (void)
-{
- return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT);
-}
-#endif
-
-/* Turn on the USB connection by enabling the pullup resistor */
-void udc_connect (void)
-{
- UDCDBG ("connect, enable Pullup");
- outl (0x00000018, FUNC_MUX_CTRL_D);
-}
-
-/* Turn off the USB connection by disabling the pullup resistor */
-void udc_disconnect (void)
-{
- UDCDBG ("disconnect, disable Pullup");
- outl (0x00000000, FUNC_MUX_CTRL_D);
-}
-
-/* ************************************************************************** */
-
-
-/*
- * udc_disable_interrupts - disable interrupts
- * switch off interrupts
- */
-#if 0
-void udc_disable_interrupts (struct usb_device_instance *device)
-{
- UDCDBG ("disabling all interrupts");
- outw (0, UDC_IRQ_EN);
-}
-#endif
-
-/* ************************************************************************** */
-
-/**
- * udc_ep0_packetsize - return ep0 packetsize
- */
-#if 0
-int udc_ep0_packetsize (void)
-{
- return EP0_PACKETSIZE;
-}
-#endif
-
-/* Switch on the UDC */
-void udc_enable (struct usb_device_instance *device)
-{
- UDCDBGA ("enable device %p, status %d", device, device->status);
-
- /* initialize driver state variables */
- udc_devstat = 0;
-
- /* Save the device structure pointer */
- udc_device = device;
-
- /* Setup ep0 urb */
- if (!ep0_urb) {
- ep0_urb =
- usbd_alloc_urb (udc_device,
- udc_device->bus->endpoint_array);
- } else {
- serial_printf ("udc_enable: ep0_urb already allocated %p\n",
- ep0_urb);
- }
-
- UDCDBG ("Check clock status");
- UDCREG (STATUS_REQ);
-
- /* The VBUS_MODE bit selects whether VBUS detection is done via
- * software (1) or hardware (0). When software detection is
- * selected, VBUS_CTRL selects whether USB is not connected (0)
- * or connected (1).
- */
- outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE,
- FUNC_MUX_CTRL_0);
- UDCREGL (FUNC_MUX_CTRL_0);
-
- omap1510_configure_device (device);
-}
-
-/* Switch off the UDC */
-void udc_disable (void)
-{
- UDCDBG ("disable UDC");
-
- omap1510_deconfigure_device ();
-
- /* The VBUS_MODE bit selects whether VBUS detection is done via
- * software (1) or hardware (0). When software detection is
- * selected, VBUS_CTRL selects whether USB is not connected (0)
- * or connected (1).
- */
- outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0);
- outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0);
- UDCREGL (FUNC_MUX_CTRL_0);
-
- /* Free ep0 URB */
- if (ep0_urb) {
- /*usbd_dealloc_urb(ep0_urb); */
- ep0_urb = NULL;
- }
-
- /* Reset device pointer.
- * We ought to do this here to balance the initialization of udc_device
- * in udc_enable, but some of our other exported functions get called
- * by the bus interface driver after udc_disable, so we have to hang on
- * to the device pointer to avoid a null pointer dereference. */
- /* udc_device = NULL; */
-}
-
-/**
- * udc_startup - allow udc code to do any additional startup
- */
-void udc_startup_events (struct usb_device_instance *device)
-{
- /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
- usbd_device_event_irq (device, DEVICE_INIT, 0);
-
- /* The DEVICE_CREATE event puts the USB device in the state
- * STATE_ATTACHED.
- */
- usbd_device_event_irq (device, DEVICE_CREATE, 0);
-
- /* Some USB controller driver implementations signal
- * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here.
- * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED,
- * and DEVICE_RESET causes a transition to the state STATE_DEFAULT.
- * The OMAP USB client controller has the capability to detect when the
- * USB cable is connected to a powered USB bus via the ATT bit in the
- * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and
- * DEVICE_RESET events until later.
- */
-
- udc_enable (device);
-}
-
-/**
- * udc_irq - do pseudo interrupts
- */
-void udc_irq(void)
-{
- /* Loop while we have interrupts.
- * If we don't do this, the input chain
- * polling delay is likely to miss
- * host requests.
- */
- while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
- /* Handle any new IRQs */
- omap1510_udc_irq ();
- omap1510_udc_noniso_irq ();
- }
-}
-
-/* Flow control */
-void udc_set_nak(int epid)
-{
- /* TODO: implement this functionality in omap1510 */
-}
-
-void udc_unset_nak (int epid)
-{
- /* TODO: implement this functionality in omap1510 */
-}
--- /dev/null
+/*
+ * Copyright (C) 2006 Bryan O'Donoghue, CodeHermit
+ * bodonoghue@codehermit.ie
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <commproc.h>
+
+/* Mode Register */
+#define USMOD_EN 0x01
+#define USMOD_HOST 0x02
+#define USMOD_TEST 0x04
+#define USMOD_SFTE 0x08
+#define USMOD_RESUME 0x40
+#define USMOD_LSS 0x80
+
+/* Endpoint Registers */
+#define USEP_RHS_NORM 0x00
+#define USEP_RHS_IGNORE 0x01
+#define USEP_RHS_NAK 0x02
+#define USEP_RHS_STALL 0x03
+
+#define USEP_THS_NORM 0x00
+#define USEP_THS_IGNORE 0x04
+#define USEP_THS_NAK 0x08
+#define USEP_THS_STALL 0x0C
+
+#define USEP_RTE 0x10
+#define USEP_MF 0x20
+
+#define USEP_TM_CONTROL 0x00
+#define USEP_TM_INT 0x100
+#define USEP_TM_BULK 0x200
+#define USEP_TM_ISO 0x300
+
+/* Command Register */
+#define USCOM_EP0 0x00
+#define USCOM_EP1 0x01
+#define USCOM_EP2 0x02
+#define USCOM_EP3 0x03
+
+#define USCOM_FLUSH 0x40
+#define USCOM_STR 0x80
+
+/* Event Register */
+#define USB_E_RXB 0x0001
+#define USB_E_TXB 0x0002
+#define USB_E_BSY 0x0004
+#define USB_E_SOF 0x0008
+#define USB_E_TXE1 0x0010
+#define USB_E_TXE2 0x0020
+#define USB_E_TXE3 0x0040
+#define USB_E_TXE4 0x0080
+#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4)
+#define USB_E_IDLE 0x0100
+#define USB_E_RESET 0x0200
+
+/* Mask Register */
+#define USBS_IDLE 0x01
+
+/* RX Buffer Descriptor */
+#define RX_BD_OV 0x02
+#define RX_BD_CR 0x04
+#define RX_BD_AB 0x08
+#define RX_BD_NO 0x10
+#define RX_BD_PID_DATA0 0x00
+#define RX_BD_PID_DATA1 0x40
+#define RX_BD_PID_SETUP 0x80
+#define RX_BD_F 0x400
+#define RX_BD_L 0x800
+#define RX_BD_I 0x1000
+#define RX_BD_W 0x2000
+#define RX_BD_E 0x8000
+
+/* Useful masks */
+#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP)
+#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL)
+#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK)
+#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF)
+
+/* TX Buffer Descriptor */
+#define TX_BD_UN 0x02
+#define TX_BD_TO 0x04
+#define TX_BD_NO_PID 0x00
+#define TX_BD_PID_DATA0 0x80
+#define TX_BD_PID_DATA1 0xC0
+#define TX_BD_CNF 0x200
+#define TX_BD_TC 0x400
+#define TX_BD_L 0x800
+#define TX_BD_I 0x1000
+#define TX_BD_W 0x2000
+#define TX_BD_R 0x8000
+
+/* Implementation specific defines */
+
+#define EP_MIN_PACKET_SIZE 0x08
+#define MAX_ENDPOINTS 0x04
+#define FIFO_SIZE 0x10
+#define EP_MAX_PKT FIFO_SIZE
+#define TX_RING_SIZE 0x04
+#define RX_RING_SIZE 0x06
+#define USB_MAX_PKT 0x40
+#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80
+#define TOGGLE_RX_PID(x) x^= 0x40
+#define EP_ATTACHED 0x01 /* Endpoint has a urb attached or not */
+#define EP_SEND_ZLP 0x02 /* Send ZLP y/n ? */
+
+#define PROFF_USB 0x00000000
+#define CPM_USB_BASE 0x00000A00
+
+/* UDC device defines */
+#define EP0_MAX_PACKET_SIZE EP_MAX_PKT
+#define UDC_OUT_ENDPOINT 0x02
+#define UDC_OUT_PACKET_SIZE EP_MIN_PACKET_SIZE
+#define UDC_IN_ENDPOINT 0x03
+#define UDC_IN_PACKET_SIZE EP_MIN_PACKET_SIZE
+#define UDC_INT_ENDPOINT 0x01
+#define UDC_INT_PACKET_SIZE UDC_IN_PACKET_SIZE
+#define UDC_BULK_PACKET_SIZE EP_MIN_PACKET_SIZE
+
+struct mpc8xx_ep {
+ struct urb * urb;
+ unsigned char pid;
+ unsigned char sc;
+ volatile cbd_t * prx;
+};
+
+typedef struct mpc8xx_usb{
+ char usmod; /* Mode Register */
+ char usaddr; /* Slave Address Register */
+ char uscom; /* Command Register */
+ char res1; /* Reserved */
+ ushort usep[4];
+ ulong res2; /* Reserved */
+ ushort usber; /* Event Register */
+ ushort res3; /* Reserved */
+ ushort usbmr; /* Mask Register */
+ char res4; /* Reserved */
+ char usbs; /* Status Register */
+ char res5[8]; /* Reserved */
+}usb_t;
+
+typedef struct mpc8xx_parameter_ram{
+ ushort ep0ptr; /* Endpoint Pointer Register 0 */
+ ushort ep1ptr; /* Endpoint Pointer Register 1 */
+ ushort ep2ptr; /* Endpoint Pointer Register 2 */
+ ushort ep3ptr; /* Endpoint Pointer Register 3 */
+ uint rstate; /* Receive state */
+ uint rptr; /* Receive internal data pointer */
+ ushort frame_n; /* Frame number */
+ ushort rbcnt; /* Receive byte count */
+ uint rtemp; /* Receive temp cp use only */
+ uint rxusb; /* Rx Data Temp */
+ ushort rxuptr; /* Rx microcode return address temp */
+}usb_pram_t;
+
+typedef struct endpoint_parameter_block_pointer{
+ ushort rbase; /* RxBD base address */
+ ushort tbase; /* TxBD base address */
+ char rfcr; /* Rx Function code */
+ char tfcr; /* Tx Function code */
+ ushort mrblr; /* Maximum Receive Buffer Length */
+ ushort rbptr; /* RxBD pointer Next Buffer Descriptor */
+ ushort tbptr; /* TxBD pointer Next Buffer Descriptor */
+ ulong tstate; /* Transmit internal state */
+ ulong tptr; /* Transmit internal data pointer */
+ ushort tcrc; /* Transmit temp CRC */
+ ushort tbcnt; /* Transmit internal bye count */
+ ulong ttemp; /* Tx temp */
+ ushort txuptr; /* Tx microcode return address */
+ ushort res1; /* Reserved */
+}usb_epb_t;
+
+typedef enum mpc8xx_udc_state{
+ STATE_NOT_READY,
+ STATE_ERROR,
+ STATE_READY,
+}mpc8xx_udc_state_t;
+
+/* Declarations */
+int udc_init(void);
+void udc_irq(void);
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *endpoint);
+void udc_connect(void);
+void udc_disconnect(void);
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+void udc_startup_events(struct usb_device_instance *device);
+
+/* Flow control */
+void udc_set_nak(int epid);
+void udc_unset_nak (int epid);
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on
+ * linux/drivers/usb/device/bi/omap.h
+ * Register definitions for TI OMAP1510 USB bus interface driver
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __USBDCORE_OMAP1510_H__
+#define __USBDCORE_OMAP1510_H__
+
+
+/*
+ * 13.2 MPU Register Map
+ */
+
+/* Table 13-1. USB Function Module Registers (endpoint) */
+#define UDC_BASE 0xFFFB4000
+#define UDC_OFFSET(offset) (UDC_BASE + (offset))
+#define UDC_REV UDC_OFFSET(0x0) /* Revision */
+#define UDC_EP_NUM UDC_OFFSET(0x4) /* Endpoint selection */
+#define UDC_DATA UDC_OFFSET(0x08) /* Data */
+#define UDC_CTRL UDC_OFFSET(0x0C) /* Control */
+#define UDC_STAT_FLG UDC_OFFSET(0x10) /* Status flag */
+#define UDC_RXFSTAT UDC_OFFSET(0x14) /* Receive FIFO status */
+#define UDC_SYSCON1 UDC_OFFSET(0x18) /* System configuration 1 */
+#define UDC_SYSCON2 UDC_OFFSET(0x1C) /* System configuration 2 */
+#define UDC_DEVSTAT UDC_OFFSET(0x20) /* Device status */
+#define UDC_SOF UDC_OFFSET(0x24) /* Start of frame */
+#define UDC_IRQ_EN UDC_OFFSET(0x28) /* Interrupt enable */
+#define UDC_DMA_IRQ_EN UDC_OFFSET(0x2C) /* DMA interrupt enable */
+#define UDC_IRQ_SRC UDC_OFFSET(0x30) /* Interrupt source */
+#define UDC_EPN_STAT UDC_OFFSET(0x34) /* Endpoint interrupt status */
+#define UDC_DMAN_STAT UDC_OFFSET(0x3C) /* DMA endpoint interrupt status */
+
+/* IRQ_EN register fields */
+#define UDC_Sof_IE (1 << 7) /* Start-of-frame interrupt enabled */
+#define UDC_EPn_RX_IE (1 << 5) /* Receive endpoint interrupt enabled */
+#define UDC_EPn_TX_IE (1 << 4) /* Transmit endpoint interrupt enabled */
+#define UDC_DS_Chg_IE (1 << 3) /* Device state changed interrupt enabled */
+#define UDC_EP0_IE (1 << 0) /* EP0 transaction interrupt enabled */
+
+/* IRQ_SRC register fields */
+#define UDC_TXn_Done (1 << 10) /* Transmit DMA channel n done */
+#define UDC_RXn_Cnt (1 << 9) /* Receive DMA channel n transactions count */
+#define UDC_RXn_EOT (1 << 8) /* Receive DMA channel n end of transfer */
+#define UDC_SOF_Flg (1 << 7) /* Start-of-frame interrupt flag */
+#define UDC_EPn_RX (1 << 5) /* Endpoint n OUT transaction */
+#define UDC_EPn_TX (1 << 4) /* Endpoint n IN transaction */
+#define UDC_DS_Chg (1 << 3) /* Device state changed */
+#define UDC_Setup (1 << 2) /* Setup transaction */
+#define UDC_EP0_RX (1 << 1) /* EP0 OUT transaction */
+#define UDC_EP0_TX (1 << 0) /* EP0 IN transaction */
+
+/* DEVSTAT register fields, 14.2.9 */
+#define UDC_R_WK_OK (1 << 6) /* Remote wakeup granted */
+#define UDC_USB_Reset (1 << 5) /* USB reset signalling is active */
+#define UDC_SUS (1 << 4) /* Suspended state */
+#define UDC_CFG (1 << 3) /* Configured state */
+#define UDC_ADD (1 << 2) /* Addressed state */
+#define UDC_DEF (1 << 1) /* Default state */
+#define UDC_ATT (1 << 0) /* Attached state */
+
+/* SYSCON1 register fields */
+#define UDC_Cfg_Lock (1 << 8) /* Device configuration locked */
+#define UDC_Nak_En (1 << 4) /* NAK enable */
+#define UDC_Self_Pwr (1 << 2) /* Device is self-powered */
+#define UDC_Soff_Dis (1 << 1) /* Shutoff disabled */
+#define UDC_Pullup_En (1 << 0) /* External pullup enabled */
+
+/* SYSCON2 register fields */
+#define UDC_Rmt_Wkp (1 << 6) /* Remote wakeup */
+#define UDC_Stall_Cmd (1 << 5) /* Stall endpoint */
+#define UDC_Dev_Cfg (1 << 3) /* Device configured */
+#define UDC_Clr_Cfg (1 << 2) /* Clear configured */
+
+/*
+ * Select and enable endpoints
+ */
+
+/* Table 13-1. USB Function Module Registers (endpoint configuration) */
+#define UDC_EPBASE UDC_OFFSET(0x80) /* Endpoints base address */
+#define UDC_EP0 UDC_EPBASE /* Control endpoint configuration */
+#define UDC_EP_RX_BASE UDC_OFFSET(0x84) /* Receive endpoints base address */
+#define UDC_EP_RX(endpoint) (UDC_EP_RX_BASE + ((endpoint) - 1) * 4)
+#define UDC_EP_TX_BASE UDC_OFFSET(0xC4) /* Transmit endpoints base address */
+#define UDC_EP_TX(endpoint) (UDC_EP_TX_BASE + ((endpoint) - 1) * 4)
+
+/* EP_NUM register fields */
+#define UDC_Setup_Sel (1 << 6) /* Setup FIFO select */
+#define UDC_EP_Sel (1 << 5) /* TX/RX FIFO select */
+#define UDC_EP_Dir (1 << 4) /* Endpoint direction */
+
+/* CTRL register fields */
+#define UDC_Clr_Halt (1 << 7) /* Clear halt endpoint */
+#define UDC_Set_Halt (1 << 6) /* Set halt endpoint */
+#define UDC_Set_FIFO_En (1 << 2) /* Set FIFO enable */
+#define UDC_Clr_EP (1 << 1) /* Clear endpoint */
+#define UDC_Reset_EP (1 << 0) /* Reset endpoint */
+
+/* STAT_FLG register fields */
+#define UDC_Miss_In (1 << 14)
+#define UDC_Data_Flush (1 << 13)
+#define UDC_ISO_Err (1 << 12)
+#define UDC_ISO_FIFO_Empty (1 << 9)
+#define UDC_ISO_FIFO_Full (1 << 8)
+#define UDC_EP_Halted (1 << 6)
+#define UDC_STALL (1 << 5)
+#define UDC_NAK (1 << 4)
+#define UDC_ACK (1 << 3)
+#define UDC_FIFO_En (1 << 2)
+#define UDC_Non_ISO_FIFO_Empty (1 << 1)
+#define UDC_Non_ISO_FIFO_Full (1 << 0)
+
+/* EPn_RX register fields */
+#define UDC_EPn_RX_Valid (1 << 15) /* valid */
+#define UDC_EPn_RX_Db (1 << 14) /* double-buffer */
+#define UDC_EPn_RX_Iso (1 << 11) /* isochronous */
+
+/* EPn_TX register fields */
+#define UDC_EPn_TX_Valid (1 << 15) /* valid */
+#define UDC_EPn_TX_Db (1 << 14) /* double-buffer */
+#define UDC_EPn_TX_Iso (1 << 11) /* isochronous */
+
+#define EP0_PACKETSIZE 0x40
+
+/* physical to logical endpoint mapping
+ * Physical endpoints are an index into device->bus->endpoint_array.
+ * Logical endpoints are endpoints 0 to 15 IN and OUT as defined in
+ * the USB specification.
+ *
+ * physical ep logical ep direction endpoint_address
+ * 0 0 IN and OUT 0x00
+ * 1 to 15 1 to 15 OUT 0x01 to 0x0f
+ * 16 to 30 1 to 15 IN 0x81 to 0x8f
+ */
+#define PHYS_EP_TO_EP_ADDR(ep) (((ep) < 16) ? (ep) : (((ep) - 15) | 0x80))
+#define EP_ADDR_TO_PHYS_EP(a) (((a) & 0x80) ? (((a) & ~0x80) + 15) : (a))
+
+/* MOD_CONF_CTRL_0 bits (FIXME: move to board hardware.h ?) */
+#define CONF_MOD_USB_W2FC_VBUS_MODE_R (1 << 17)
+
+/* Other registers (may be) related to USB */
+
+#define CLOCK_CTRL (0xFFFE0830)
+#define APLL_CTRL (0xFFFE084C)
+#define DPLL_CTRL (0xFFFE083C)
+#define SOFT_REQ (0xFFFE0834)
+#define STATUS_REQ (0xFFFE0840)
+
+/* FUNC_MUX_CTRL_0 bits related to USB */
+#define UDC_VBUS_CTRL (1 << 19)
+#define UDC_VBUS_MODE (1 << 18)
+
+/* OMAP Endpoint parameters */
+#define EP0_MAX_PACKET_SIZE 64
+#define UDC_OUT_ENDPOINT 2
+#define UDC_OUT_PACKET_SIZE 64
+#define UDC_IN_ENDPOINT 1
+#define UDC_IN_PACKET_SIZE 64
+#define UDC_INT_ENDPOINT 5
+#define UDC_INT_PACKET_SIZE 16
+#define UDC_BULK_PACKET_SIZE 16
+
+void udc_irq (void);
+/* Flow control */
+void udc_set_nak(int epid);
+void udc_unset_nak (int epid);
+
+/* Higher level functions for abstracting away from specific device */
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
+
+int udc_init (void);
+
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+
+void udc_connect(void);
+void udc_disconnect(void);
+
+void udc_startup_events(struct usb_device_instance *device);
+void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint);
+
+#endif
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on linux/drivers/usbd/usbd.h
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __USBDCORE_H__
-#define __USBDCORE_H__
-
-#include <common.h>
-#include "usbdescriptors.h"
-
-
-#define MAX_URBS_QUEUED 5
-
-
-#if 1
-#define usberr(fmt,args...) serial_printf("ERROR: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
-#else
-#define usberr(fmt,args...) do{}while(0)
-#endif
-
-#if 0
-#define usbdbg(fmt,args...) serial_printf("debug: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
-#else
-#define usbdbg(fmt,args...) do{}while(0)
-#endif
-
-#if 0
-#define usbinfo(fmt,args...) serial_printf("info: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
-#else
-#define usbinfo(fmt,args...) do{}while(0)
-#endif
-
-#ifndef le16_to_cpu
-#define le16_to_cpu(x) (x)
-#endif
-
-#ifndef inb
-#define inb(p) (*(volatile u8*)(p))
-#endif
-
-#ifndef outb
-#define outb(val,p) (*(volatile u8*)(p) = (val))
-#endif
-
-#ifndef inw
-#define inw(p) (*(volatile u16*)(p))
-#endif
-
-#ifndef outw
-#define outw(val,p) (*(volatile u16*)(p) = (val))
-#endif
-
-#ifndef inl
-#define inl(p) (*(volatile u32*)(p))
-#endif
-
-#ifndef outl
-#define outl(val,p) (*(volatile u32*)(p) = (val))
-#endif
-
-#ifndef insw
-#define insw(p,to,len) mmio_insw(p,to,len)
-#endif
-
-#ifndef outsw
-#define outsw(p,from,len) mmio_outsw(p,from,len)
-#endif
-
-#ifndef insb
-#define insb(p,to,len) mmio_insb(p,to,len)
-#endif
-
-#ifndef mmio_insw
-#define mmio_insw(r,b,l) ({ int __i ; \
- u16 *__b2; \
- __b2 = (u16 *) b; \
- for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = inw(r); \
- }; \
- })
-#endif
-
-#ifndef mmio_outsw
-#define mmio_outsw(r,b,l) ({ int __i; \
- u16 *__b2; \
- __b2 = (u16 *) b; \
- for (__i = 0; __i < l; __i++) { \
- outw( *(__b2 + __i), r); \
- } \
- })
-#endif
-
-#ifndef mmio_insb
-#define mmio_insb(r,b,l) ({ int __i ; \
- u8 *__b2; \
- __b2 = (u8 *) b; \
- for (__i = 0; __i < l; __i++) { \
- *(__b2 + __i) = inb(r); \
- }; \
- })
-#endif
-
-/*
- * Structure member address manipulation macros.
- * These are used by client code (code using the urb_link routines), since
- * the urb_link structure is embedded in the client data structures.
- *
- * Note: a macro offsetof equivalent to member_offset is defined in stddef.h
- * but this is kept here for the sake of portability.
- *
- * p2surround returns a pointer to the surrounding structure given
- * type of the surrounding structure, the name memb of the structure
- * member pointed at by ptr. For example, if you have:
- *
- * struct foo {
- * int x;
- * float y;
- * char z;
- * } thingy;
- *
- * char *cp = &thingy.z;
- *
- * then
- *
- * &thingy == p2surround(struct foo, z, cp)
- *
- * Clear?
- */
-#define _cv_(ptr) ((char*)(void*)(ptr))
-#define member_offset(type,memb) (_cv_(&(((type*)0)->memb))-(char*)0)
-#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
-
-struct urb;
-
-struct usb_endpoint_instance;
-struct usb_interface_instance;
-struct usb_configuration_instance;
-struct usb_device_instance;
-struct usb_bus_instance;
-
-/*
- * Device and/or Interface Class codes
- */
-#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
-#define USB_CLASS_AUDIO 1
-#define USB_CLASS_COMM 2
-#define USB_CLASS_HID 3
-#define USB_CLASS_PHYSICAL 5
-#define USB_CLASS_PRINTER 7
-#define USB_CLASS_MASS_STORAGE 8
-#define USB_CLASS_HUB 9
-#define USB_CLASS_DATA 10
-#define USB_CLASS_APP_SPEC 0xfe
-#define USB_CLASS_VENDOR_SPEC 0xff
-
-/*
- * USB types
- */
-#define USB_TYPE_STANDARD (0x00 << 5)
-#define USB_TYPE_CLASS (0x01 << 5)
-#define USB_TYPE_VENDOR (0x02 << 5)
-#define USB_TYPE_RESERVED (0x03 << 5)
-
-/*
- * USB recipients
- */
-#define USB_RECIP_DEVICE 0x00
-#define USB_RECIP_INTERFACE 0x01
-#define USB_RECIP_ENDPOINT 0x02
-#define USB_RECIP_OTHER 0x03
-
-/*
- * USB directions
- */
-#define USB_DIR_OUT 0
-#define USB_DIR_IN 0x80
-
-/*
- * Descriptor types
- */
-#define USB_DT_DEVICE 0x01
-#define USB_DT_CONFIG 0x02
-#define USB_DT_STRING 0x03
-#define USB_DT_INTERFACE 0x04
-#define USB_DT_ENDPOINT 0x05
-
-#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
-#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
-#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
-#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
-
-/*
- * Descriptor sizes per descriptor type
- */
-#define USB_DT_DEVICE_SIZE 18
-#define USB_DT_CONFIG_SIZE 9
-#define USB_DT_INTERFACE_SIZE 9
-#define USB_DT_ENDPOINT_SIZE 7
-#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
-#define USB_DT_HUB_NONVAR_SIZE 7
-#define USB_DT_HID_SIZE 9
-
-/*
- * Endpoints
- */
-#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
-#define USB_ENDPOINT_DIR_MASK 0x80
-
-#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
-#define USB_ENDPOINT_XFER_CONTROL 0
-#define USB_ENDPOINT_XFER_ISOC 1
-#define USB_ENDPOINT_XFER_BULK 2
-#define USB_ENDPOINT_XFER_INT 3
-
-/*
- * USB Packet IDs (PIDs)
- */
-#define USB_PID_UNDEF_0 0xf0
-#define USB_PID_OUT 0xe1
-#define USB_PID_ACK 0xd2
-#define USB_PID_DATA0 0xc3
-#define USB_PID_PING 0xb4 /* USB 2.0 */
-#define USB_PID_SOF 0xa5
-#define USB_PID_NYET 0x96 /* USB 2.0 */
-#define USB_PID_DATA2 0x87 /* USB 2.0 */
-#define USB_PID_SPLIT 0x78 /* USB 2.0 */
-#define USB_PID_IN 0x69
-#define USB_PID_NAK 0x5a
-#define USB_PID_DATA1 0x4b
-#define USB_PID_PREAMBLE 0x3c /* Token mode */
-#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
-#define USB_PID_SETUP 0x2d
-#define USB_PID_STALL 0x1e
-#define USB_PID_MDATA 0x0f /* USB 2.0 */
-
-/*
- * Standard requests
- */
-#define USB_REQ_GET_STATUS 0x00
-#define USB_REQ_CLEAR_FEATURE 0x01
-#define USB_REQ_SET_FEATURE 0x03
-#define USB_REQ_SET_ADDRESS 0x05
-#define USB_REQ_GET_DESCRIPTOR 0x06
-#define USB_REQ_SET_DESCRIPTOR 0x07
-#define USB_REQ_GET_CONFIGURATION 0x08
-#define USB_REQ_SET_CONFIGURATION 0x09
-#define USB_REQ_GET_INTERFACE 0x0A
-#define USB_REQ_SET_INTERFACE 0x0B
-#define USB_REQ_SYNCH_FRAME 0x0C
-
-#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
-
-/*
- * HID requests
- */
-#define USB_REQ_GET_REPORT 0x01
-#define USB_REQ_GET_IDLE 0x02
-#define USB_REQ_GET_PROTOCOL 0x03
-#define USB_REQ_SET_REPORT 0x09
-#define USB_REQ_SET_IDLE 0x0A
-#define USB_REQ_SET_PROTOCOL 0x0B
-
-
-/*
- * USB Spec Release number
- */
-
-#define USB_BCD_VERSION 0x0110
-
-
-/*
- * Device Requests (c.f Table 9-2)
- */
-
-#define USB_REQ_DIRECTION_MASK 0x80
-#define USB_REQ_TYPE_MASK 0x60
-#define USB_REQ_RECIPIENT_MASK 0x1f
-
-#define USB_REQ_DEVICE2HOST 0x80
-#define USB_REQ_HOST2DEVICE 0x00
-
-#define USB_REQ_TYPE_STANDARD 0x00
-#define USB_REQ_TYPE_CLASS 0x20
-#define USB_REQ_TYPE_VENDOR 0x40
-
-#define USB_REQ_RECIPIENT_DEVICE 0x00
-#define USB_REQ_RECIPIENT_INTERFACE 0x01
-#define USB_REQ_RECIPIENT_ENDPOINT 0x02
-#define USB_REQ_RECIPIENT_OTHER 0x03
-
-/*
- * get status bits
- */
-
-#define USB_STATUS_SELFPOWERED 0x01
-#define USB_STATUS_REMOTEWAKEUP 0x02
-
-#define USB_STATUS_HALT 0x01
-
-/*
- * descriptor types
- */
-
-#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
-#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
-#define USB_DESCRIPTOR_TYPE_STRING 0x03
-#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
-#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
-#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06
-#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07
-#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08
-#define USB_DESCRIPTOR_TYPE_HID 0x21
-#define USB_DESCRIPTOR_TYPE_REPORT 0x22
-
-#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
- usbd_device_descriptors[x] : "UNKNOWN")
-
-/*
- * standard feature selectors
- */
-#define USB_ENDPOINT_HALT 0x00
-#define USB_DEVICE_REMOTE_WAKEUP 0x01
-#define USB_TEST_MODE 0x02
-
-
-/* USB Requests
- *
- */
-
-struct usb_device_request {
- u8 bmRequestType;
- u8 bRequest;
- u16 wValue;
- u16 wIndex;
- u16 wLength;
-} __attribute__ ((packed));
-
-
-/* USB Status
- *
- */
-typedef enum urb_send_status {
- SEND_IN_PROGRESS,
- SEND_FINISHED_OK,
- SEND_FINISHED_ERROR,
- RECV_READY,
- RECV_OK,
- RECV_ERROR
-} urb_send_status_t;
-
-/*
- * Device State (c.f USB Spec 2.0 Figure 9-1)
- *
- * What state the usb device is in.
- *
- * Note the state does not change if the device is suspended, we simply set a
- * flag to show that it is suspended.
- *
- */
-typedef enum usb_device_state {
- STATE_INIT, /* just initialized */
- STATE_CREATED, /* just created */
- STATE_ATTACHED, /* we are attached */
- STATE_POWERED, /* we have seen power indication (electrical bus signal) */
- STATE_DEFAULT, /* we been reset */
- STATE_ADDRESSED, /* we have been addressed (in default configuration) */
- STATE_CONFIGURED, /* we have seen a set configuration device command */
- STATE_UNKNOWN, /* destroyed */
-} usb_device_state_t;
-
-#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
-
-/*
- * Device status
- *
- * Overall state
- */
-typedef enum usb_device_status {
- USBD_OPENING, /* we are currently opening */
- USBD_OK, /* ok to use */
- USBD_SUSPENDED, /* we are currently suspended */
- USBD_CLOSING, /* we are currently closing */
-} usb_device_status_t;
-
-#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
-
-/*
- * Device Events
- *
- * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
- *
- * There are additional events defined to handle some extra actions we need
- * to have handled.
- *
- */
-typedef enum usb_device_event {
-
- DEVICE_UNKNOWN, /* bi - unknown event */
- DEVICE_INIT, /* bi - initialize */
- DEVICE_CREATE, /* bi - */
- DEVICE_HUB_CONFIGURED, /* bi - bus has been plugged int */
- DEVICE_RESET, /* bi - hub has powered our port */
-
- DEVICE_ADDRESS_ASSIGNED, /* ep0 - set address setup received */
- DEVICE_CONFIGURED, /* ep0 - set configure setup received */
- DEVICE_SET_INTERFACE, /* ep0 - set interface setup received */
-
- DEVICE_SET_FEATURE, /* ep0 - set feature setup received */
- DEVICE_CLEAR_FEATURE, /* ep0 - clear feature setup received */
-
- DEVICE_DE_CONFIGURED, /* ep0 - set configure setup received for ?? */
-
- DEVICE_BUS_INACTIVE, /* bi - bus in inactive (no SOF packets) */
- DEVICE_BUS_ACTIVITY, /* bi - bus is active again */
-
- DEVICE_POWER_INTERRUPTION, /* bi - hub has depowered our port */
- DEVICE_HUB_RESET, /* bi - bus has been unplugged */
- DEVICE_DESTROY, /* bi - device instance should be destroyed */
-
- DEVICE_HOTPLUG, /* bi - a hotplug event has occured */
-
- DEVICE_FUNCTION_PRIVATE, /* function - private */
-
-} usb_device_event_t;
-
-
-typedef struct urb_link {
- struct urb_link *next;
- struct urb_link *prev;
-} urb_link;
-
-/* USB Data structure - for passing data around.
- *
- * This is used for both sending and receiving data.
- *
- * The callback function is used to let the function driver know when
- * transmitted data has been sent.
- *
- * The callback function is set by the alloc_recv function when an urb is
- * allocated for receiving data for an endpoint and used to call the
- * function driver to inform it that data has arrived.
- */
-
-#define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
-struct urb {
-
- struct usb_endpoint_instance *endpoint;
- struct usb_device_instance *device;
-
- struct usb_device_request device_request; /* contents of received SETUP packet */
-
- struct urb_link link; /* embedded struct for circular doubly linked list of urbs */
-
- u8* buffer;
- unsigned int buffer_length;
- unsigned int actual_length;
-
- urb_send_status_t status;
- int data;
-
- u16 buffer_data[URB_BUF_SIZE]; /* data received (OUT) or being sent (IN) */
-};
-
-/* Endpoint configuration
- *
- * Per endpoint configuration data. Used to track which function driver owns
- * an endpoint.
- *
- */
-struct usb_endpoint_instance {
- int endpoint_address; /* logical endpoint address */
-
- /* control */
- int status; /* halted */
- int state; /* available for use by bus interface driver */
-
- /* receive side */
- struct urb_link rcv; /* received urbs */
- struct urb_link rdy; /* empty urbs ready to receive */
- struct urb *rcv_urb; /* active urb */
- int rcv_attributes; /* copy of bmAttributes from endpoint descriptor */
- int rcv_packetSize; /* maximum packet size from endpoint descriptor */
- int rcv_transferSize; /* maximum transfer size from function driver */
- int rcv_queue;
-
- /* transmit side */
- struct urb_link tx; /* urbs ready to transmit */
- struct urb_link done; /* transmitted urbs */
- struct urb *tx_urb; /* active urb */
- int tx_attributes; /* copy of bmAttributes from endpoint descriptor */
- int tx_packetSize; /* maximum packet size from endpoint descriptor */
- int tx_transferSize; /* maximum transfer size from function driver */
- int tx_queue;
-
- int sent; /* data already sent */
- int last; /* data sent in last packet XXX do we need this */
-};
-
-struct usb_alternate_instance {
- struct usb_interface_descriptor *interface_descriptor;
-
- int endpoints;
- int *endpoint_transfersize_array;
- struct usb_endpoint_descriptor **endpoints_descriptor_array;
-};
-
-struct usb_interface_instance {
- int alternates;
- struct usb_alternate_instance *alternates_instance_array;
-};
-
-struct usb_configuration_instance {
- int interfaces;
- struct usb_configuration_descriptor *configuration_descriptor;
- struct usb_interface_instance *interface_instance_array;
-};
-
-
-/* USB Device Instance
- *
- * For each physical bus interface we create a logical device structure. This
- * tracks all of the required state to track the USB HOST's view of the device.
- *
- * Keep track of the device configuration for a real physical bus interface,
- * this includes the bus interface, multiple function drivers, the current
- * configuration and the current state.
- *
- * This will show:
- * the specific bus interface driver
- * the default endpoint 0 driver
- * the configured function driver
- * device state
- * device status
- * endpoint list
- */
-
-struct usb_device_instance {
-
- /* generic */
- char *name;
- struct usb_device_descriptor *device_descriptor; /* per device descriptor */
-
- void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data);
-
- /* Do cdc device specific control requests */
- int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb);
-
- /* bus interface */
- struct usb_bus_instance *bus; /* which bus interface driver */
-
- /* configuration descriptors */
- int configurations;
- struct usb_configuration_instance *configuration_instance_array;
-
- /* device state */
- usb_device_state_t device_state; /* current USB Device state */
- usb_device_state_t device_previous_state; /* current USB Device state */
-
- u8 address; /* current address (zero is default) */
- u8 configuration; /* current show configuration (zero is default) */
- u8 interface; /* current interface (zero is default) */
- u8 alternate; /* alternate flag */
-
- usb_device_status_t status; /* device status */
-
- int urbs_queued; /* number of submitted urbs */
-
- /* Shouldn't need to make this atomic, all we need is a change indicator */
- unsigned long usbd_rxtx_timestamp;
- unsigned long usbd_last_rxtx_timestamp;
-
-};
-
-/* Bus Interface configuration structure
- *
- * This is allocated for each configured instance of a bus interface driver.
- *
- * The privdata pointer may be used by the bus interface driver to store private
- * per instance state information.
- */
-struct usb_bus_instance {
-
- struct usb_device_instance *device;
- struct usb_endpoint_instance *endpoint_array; /* array of available configured endpoints */
-
- int max_endpoints; /* maximimum number of rx enpoints */
- unsigned char maxpacketsize;
-
- unsigned int serial_number;
- char *serial_number_str;
- void *privdata; /* private data for the bus interface */
-
-};
-
-extern char *usbd_device_events[];
-extern char *usbd_device_states[];
-extern char *usbd_device_status[];
-extern char *usbd_device_requests[];
-extern char *usbd_device_descriptors[];
-
-void urb_link_init (urb_link * ul);
-void urb_detach (struct urb *urb);
-urb_link *first_urb_link (urb_link * hd);
-struct urb *first_urb (urb_link * hd);
-struct urb *first_urb_detached (urb_link * hd);
-void urb_append (urb_link * hd, struct urb *urb);
-
-struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint);
-void usbd_dealloc_urb (struct urb *urb);
-
-/*
- * usbd_device_event is used by bus interface drivers to tell the higher layers that
- * certain events have taken place.
- */
-void usbd_device_event_irq (struct usb_device_instance *conf, usb_device_event_t, int);
-void usbd_device_event (struct usb_device_instance *conf, usb_device_event_t, int);
-
-/* descriptors
- *
- * Various ways of finding descriptors based on the current device and any
- * possible configuration / interface / endpoint for it.
- */
-struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct usb_device_instance *, int, int);
-struct usb_function_instance *usbd_device_function_instance (struct usb_device_instance *, unsigned int);
-struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *, int, int, int);
-struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *, int, int, int, int);
-struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance *, int, int, int, int);
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
-struct usb_class_descriptor *usbd_device_class_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
-struct usb_class_report_descriptor *usbd_device_class_report_descriptor_index( struct usb_device_instance *, int , int , int , int , int );
-struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *, int, int, int, int, int);
-int usbd_device_endpoint_transfersize (struct usb_device_instance *, int, int, int, int, int);
-struct usb_string_descriptor *usbd_get_string (u8);
-struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *, int);
-
-int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint);
-void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad);
-void usbd_tx_complete (struct usb_endpoint_instance *endpoint);
-
-#endif
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usbd/ep0.c
- *
- * Copyright (c) 2000, 2001, 2002 Lineo
- * Copyright (c) 2001 Hewlett Packard
- *
- * By:
- * Stuart Lynne <sl@lineo.com>,
- * Tom Rushworth <tbr@lineo.com>,
- * Bruce Balden <balden@lineo.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef __USBDCORE_EP0_H__
-#define __USBDCORE_EP0_H__
-
-
-int ep0_recv_setup (struct urb *urb);
-
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2006 Bryan O'Donoghue, CodeHermit
- * bodonoghue@codehermit.ie
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include <commproc.h>
-
-/* Mode Register */
-#define USMOD_EN 0x01
-#define USMOD_HOST 0x02
-#define USMOD_TEST 0x04
-#define USMOD_SFTE 0x08
-#define USMOD_RESUME 0x40
-#define USMOD_LSS 0x80
-
-/* Endpoint Registers */
-#define USEP_RHS_NORM 0x00
-#define USEP_RHS_IGNORE 0x01
-#define USEP_RHS_NAK 0x02
-#define USEP_RHS_STALL 0x03
-
-#define USEP_THS_NORM 0x00
-#define USEP_THS_IGNORE 0x04
-#define USEP_THS_NAK 0x08
-#define USEP_THS_STALL 0x0C
-
-#define USEP_RTE 0x10
-#define USEP_MF 0x20
-
-#define USEP_TM_CONTROL 0x00
-#define USEP_TM_INT 0x100
-#define USEP_TM_BULK 0x200
-#define USEP_TM_ISO 0x300
-
-/* Command Register */
-#define USCOM_EP0 0x00
-#define USCOM_EP1 0x01
-#define USCOM_EP2 0x02
-#define USCOM_EP3 0x03
-
-#define USCOM_FLUSH 0x40
-#define USCOM_STR 0x80
-
-/* Event Register */
-#define USB_E_RXB 0x0001
-#define USB_E_TXB 0x0002
-#define USB_E_BSY 0x0004
-#define USB_E_SOF 0x0008
-#define USB_E_TXE1 0x0010
-#define USB_E_TXE2 0x0020
-#define USB_E_TXE3 0x0040
-#define USB_E_TXE4 0x0080
-#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4)
-#define USB_E_IDLE 0x0100
-#define USB_E_RESET 0x0200
-
-/* Mask Register */
-#define USBS_IDLE 0x01
-
-/* RX Buffer Descriptor */
-#define RX_BD_OV 0x02
-#define RX_BD_CR 0x04
-#define RX_BD_AB 0x08
-#define RX_BD_NO 0x10
-#define RX_BD_PID_DATA0 0x00
-#define RX_BD_PID_DATA1 0x40
-#define RX_BD_PID_SETUP 0x80
-#define RX_BD_F 0x400
-#define RX_BD_L 0x800
-#define RX_BD_I 0x1000
-#define RX_BD_W 0x2000
-#define RX_BD_E 0x8000
-
-/* Useful masks */
-#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP)
-#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL)
-#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK)
-#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF)
-
-/* TX Buffer Descriptor */
-#define TX_BD_UN 0x02
-#define TX_BD_TO 0x04
-#define TX_BD_NO_PID 0x00
-#define TX_BD_PID_DATA0 0x80
-#define TX_BD_PID_DATA1 0xC0
-#define TX_BD_CNF 0x200
-#define TX_BD_TC 0x400
-#define TX_BD_L 0x800
-#define TX_BD_I 0x1000
-#define TX_BD_W 0x2000
-#define TX_BD_R 0x8000
-
-/* Implementation specific defines */
-
-#define EP_MIN_PACKET_SIZE 0x08
-#define MAX_ENDPOINTS 0x04
-#define FIFO_SIZE 0x10
-#define EP_MAX_PKT FIFO_SIZE
-#define TX_RING_SIZE 0x04
-#define RX_RING_SIZE 0x06
-#define USB_MAX_PKT 0x40
-#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80
-#define TOGGLE_RX_PID(x) x^= 0x40
-#define EP_ATTACHED 0x01 /* Endpoint has a urb attached or not */
-#define EP_SEND_ZLP 0x02 /* Send ZLP y/n ? */
-
-#define PROFF_USB 0x00000000
-#define CPM_USB_BASE 0x00000A00
-
-/* UDC device defines */
-#define EP0_MAX_PACKET_SIZE EP_MAX_PKT
-#define UDC_OUT_ENDPOINT 0x02
-#define UDC_OUT_PACKET_SIZE EP_MIN_PACKET_SIZE
-#define UDC_IN_ENDPOINT 0x03
-#define UDC_IN_PACKET_SIZE EP_MIN_PACKET_SIZE
-#define UDC_INT_ENDPOINT 0x01
-#define UDC_INT_PACKET_SIZE UDC_IN_PACKET_SIZE
-#define UDC_BULK_PACKET_SIZE EP_MIN_PACKET_SIZE
-
-struct mpc8xx_ep {
- struct urb * urb;
- unsigned char pid;
- unsigned char sc;
- volatile cbd_t * prx;
-};
-
-typedef struct mpc8xx_usb{
- char usmod; /* Mode Register */
- char usaddr; /* Slave Address Register */
- char uscom; /* Command Register */
- char res1; /* Reserved */
- ushort usep[4];
- ulong res2; /* Reserved */
- ushort usber; /* Event Register */
- ushort res3; /* Reserved */
- ushort usbmr; /* Mask Register */
- char res4; /* Reserved */
- char usbs; /* Status Register */
- char res5[8]; /* Reserved */
-}usb_t;
-
-typedef struct mpc8xx_parameter_ram{
- ushort ep0ptr; /* Endpoint Pointer Register 0 */
- ushort ep1ptr; /* Endpoint Pointer Register 1 */
- ushort ep2ptr; /* Endpoint Pointer Register 2 */
- ushort ep3ptr; /* Endpoint Pointer Register 3 */
- uint rstate; /* Receive state */
- uint rptr; /* Receive internal data pointer */
- ushort frame_n; /* Frame number */
- ushort rbcnt; /* Receive byte count */
- uint rtemp; /* Receive temp cp use only */
- uint rxusb; /* Rx Data Temp */
- ushort rxuptr; /* Rx microcode return address temp */
-}usb_pram_t;
-
-typedef struct endpoint_parameter_block_pointer{
- ushort rbase; /* RxBD base address */
- ushort tbase; /* TxBD base address */
- char rfcr; /* Rx Function code */
- char tfcr; /* Tx Function code */
- ushort mrblr; /* Maximum Receive Buffer Length */
- ushort rbptr; /* RxBD pointer Next Buffer Descriptor */
- ushort tbptr; /* TxBD pointer Next Buffer Descriptor */
- ulong tstate; /* Transmit internal state */
- ulong tptr; /* Transmit internal data pointer */
- ushort tcrc; /* Transmit temp CRC */
- ushort tbcnt; /* Transmit internal bye count */
- ulong ttemp; /* Tx temp */
- ushort txuptr; /* Tx microcode return address */
- ushort res1; /* Reserved */
-}usb_epb_t;
-
-typedef enum mpc8xx_udc_state{
- STATE_NOT_READY,
- STATE_ERROR,
- STATE_READY,
-}mpc8xx_udc_state_t;
-
-/* Declarations */
-int udc_init(void);
-void udc_irq(void);
-int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
-void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
- struct usb_endpoint_instance *endpoint);
-void udc_connect(void);
-void udc_disconnect(void);
-void udc_enable(struct usb_device_instance *device);
-void udc_disable(void);
-void udc_startup_events(struct usb_device_instance *device);
-
-/* Flow control */
-void udc_set_nak(int epid);
-void udc_unset_nak (int epid);
+++ /dev/null
-/*
- * (C) Copyright 2003
- * Gerry Hamel, geh@ti.com, Texas Instruments
- *
- * Based on
- * linux/drivers/usb/device/bi/omap.h
- * Register definitions for TI OMAP1510 USB bus interface driver
- *
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2003 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __USBDCORE_OMAP1510_H__
-#define __USBDCORE_OMAP1510_H__
-
-
-/*
- * 13.2 MPU Register Map
- */
-
-/* Table 13-1. USB Function Module Registers (endpoint) */
-#define UDC_BASE 0xFFFB4000
-#define UDC_OFFSET(offset) (UDC_BASE + (offset))
-#define UDC_REV UDC_OFFSET(0x0) /* Revision */
-#define UDC_EP_NUM UDC_OFFSET(0x4) /* Endpoint selection */
-#define UDC_DATA UDC_OFFSET(0x08) /* Data */
-#define UDC_CTRL UDC_OFFSET(0x0C) /* Control */
-#define UDC_STAT_FLG UDC_OFFSET(0x10) /* Status flag */
-#define UDC_RXFSTAT UDC_OFFSET(0x14) /* Receive FIFO status */
-#define UDC_SYSCON1 UDC_OFFSET(0x18) /* System configuration 1 */
-#define UDC_SYSCON2 UDC_OFFSET(0x1C) /* System configuration 2 */
-#define UDC_DEVSTAT UDC_OFFSET(0x20) /* Device status */
-#define UDC_SOF UDC_OFFSET(0x24) /* Start of frame */
-#define UDC_IRQ_EN UDC_OFFSET(0x28) /* Interrupt enable */
-#define UDC_DMA_IRQ_EN UDC_OFFSET(0x2C) /* DMA interrupt enable */
-#define UDC_IRQ_SRC UDC_OFFSET(0x30) /* Interrupt source */
-#define UDC_EPN_STAT UDC_OFFSET(0x34) /* Endpoint interrupt status */
-#define UDC_DMAN_STAT UDC_OFFSET(0x3C) /* DMA endpoint interrupt status */
-
-/* IRQ_EN register fields */
-#define UDC_Sof_IE (1 << 7) /* Start-of-frame interrupt enabled */
-#define UDC_EPn_RX_IE (1 << 5) /* Receive endpoint interrupt enabled */
-#define UDC_EPn_TX_IE (1 << 4) /* Transmit endpoint interrupt enabled */
-#define UDC_DS_Chg_IE (1 << 3) /* Device state changed interrupt enabled */
-#define UDC_EP0_IE (1 << 0) /* EP0 transaction interrupt enabled */
-
-/* IRQ_SRC register fields */
-#define UDC_TXn_Done (1 << 10) /* Transmit DMA channel n done */
-#define UDC_RXn_Cnt (1 << 9) /* Receive DMA channel n transactions count */
-#define UDC_RXn_EOT (1 << 8) /* Receive DMA channel n end of transfer */
-#define UDC_SOF_Flg (1 << 7) /* Start-of-frame interrupt flag */
-#define UDC_EPn_RX (1 << 5) /* Endpoint n OUT transaction */
-#define UDC_EPn_TX (1 << 4) /* Endpoint n IN transaction */
-#define UDC_DS_Chg (1 << 3) /* Device state changed */
-#define UDC_Setup (1 << 2) /* Setup transaction */
-#define UDC_EP0_RX (1 << 1) /* EP0 OUT transaction */
-#define UDC_EP0_TX (1 << 0) /* EP0 IN transaction */
-
-/* DEVSTAT register fields, 14.2.9 */
-#define UDC_R_WK_OK (1 << 6) /* Remote wakeup granted */
-#define UDC_USB_Reset (1 << 5) /* USB reset signalling is active */
-#define UDC_SUS (1 << 4) /* Suspended state */
-#define UDC_CFG (1 << 3) /* Configured state */
-#define UDC_ADD (1 << 2) /* Addressed state */
-#define UDC_DEF (1 << 1) /* Default state */
-#define UDC_ATT (1 << 0) /* Attached state */
-
-/* SYSCON1 register fields */
-#define UDC_Cfg_Lock (1 << 8) /* Device configuration locked */
-#define UDC_Nak_En (1 << 4) /* NAK enable */
-#define UDC_Self_Pwr (1 << 2) /* Device is self-powered */
-#define UDC_Soff_Dis (1 << 1) /* Shutoff disabled */
-#define UDC_Pullup_En (1 << 0) /* External pullup enabled */
-
-/* SYSCON2 register fields */
-#define UDC_Rmt_Wkp (1 << 6) /* Remote wakeup */
-#define UDC_Stall_Cmd (1 << 5) /* Stall endpoint */
-#define UDC_Dev_Cfg (1 << 3) /* Device configured */
-#define UDC_Clr_Cfg (1 << 2) /* Clear configured */
-
-/*
- * Select and enable endpoints
- */
-
-/* Table 13-1. USB Function Module Registers (endpoint configuration) */
-#define UDC_EPBASE UDC_OFFSET(0x80) /* Endpoints base address */
-#define UDC_EP0 UDC_EPBASE /* Control endpoint configuration */
-#define UDC_EP_RX_BASE UDC_OFFSET(0x84) /* Receive endpoints base address */
-#define UDC_EP_RX(endpoint) (UDC_EP_RX_BASE + ((endpoint) - 1) * 4)
-#define UDC_EP_TX_BASE UDC_OFFSET(0xC4) /* Transmit endpoints base address */
-#define UDC_EP_TX(endpoint) (UDC_EP_TX_BASE + ((endpoint) - 1) * 4)
-
-/* EP_NUM register fields */
-#define UDC_Setup_Sel (1 << 6) /* Setup FIFO select */
-#define UDC_EP_Sel (1 << 5) /* TX/RX FIFO select */
-#define UDC_EP_Dir (1 << 4) /* Endpoint direction */
-
-/* CTRL register fields */
-#define UDC_Clr_Halt (1 << 7) /* Clear halt endpoint */
-#define UDC_Set_Halt (1 << 6) /* Set halt endpoint */
-#define UDC_Set_FIFO_En (1 << 2) /* Set FIFO enable */
-#define UDC_Clr_EP (1 << 1) /* Clear endpoint */
-#define UDC_Reset_EP (1 << 0) /* Reset endpoint */
-
-/* STAT_FLG register fields */
-#define UDC_Miss_In (1 << 14)
-#define UDC_Data_Flush (1 << 13)
-#define UDC_ISO_Err (1 << 12)
-#define UDC_ISO_FIFO_Empty (1 << 9)
-#define UDC_ISO_FIFO_Full (1 << 8)
-#define UDC_EP_Halted (1 << 6)
-#define UDC_STALL (1 << 5)
-#define UDC_NAK (1 << 4)
-#define UDC_ACK (1 << 3)
-#define UDC_FIFO_En (1 << 2)
-#define UDC_Non_ISO_FIFO_Empty (1 << 1)
-#define UDC_Non_ISO_FIFO_Full (1 << 0)
-
-/* EPn_RX register fields */
-#define UDC_EPn_RX_Valid (1 << 15) /* valid */
-#define UDC_EPn_RX_Db (1 << 14) /* double-buffer */
-#define UDC_EPn_RX_Iso (1 << 11) /* isochronous */
-
-/* EPn_TX register fields */
-#define UDC_EPn_TX_Valid (1 << 15) /* valid */
-#define UDC_EPn_TX_Db (1 << 14) /* double-buffer */
-#define UDC_EPn_TX_Iso (1 << 11) /* isochronous */
-
-#define EP0_PACKETSIZE 0x40
-
-/* physical to logical endpoint mapping
- * Physical endpoints are an index into device->bus->endpoint_array.
- * Logical endpoints are endpoints 0 to 15 IN and OUT as defined in
- * the USB specification.
- *
- * physical ep logical ep direction endpoint_address
- * 0 0 IN and OUT 0x00
- * 1 to 15 1 to 15 OUT 0x01 to 0x0f
- * 16 to 30 1 to 15 IN 0x81 to 0x8f
- */
-#define PHYS_EP_TO_EP_ADDR(ep) (((ep) < 16) ? (ep) : (((ep) - 15) | 0x80))
-#define EP_ADDR_TO_PHYS_EP(a) (((a) & 0x80) ? (((a) & ~0x80) + 15) : (a))
-
-/* MOD_CONF_CTRL_0 bits (FIXME: move to board hardware.h ?) */
-#define CONF_MOD_USB_W2FC_VBUS_MODE_R (1 << 17)
-
-/* Other registers (may be) related to USB */
-
-#define CLOCK_CTRL (0xFFFE0830)
-#define APLL_CTRL (0xFFFE084C)
-#define DPLL_CTRL (0xFFFE083C)
-#define SOFT_REQ (0xFFFE0834)
-#define STATUS_REQ (0xFFFE0840)
-
-/* FUNC_MUX_CTRL_0 bits related to USB */
-#define UDC_VBUS_CTRL (1 << 19)
-#define UDC_VBUS_MODE (1 << 18)
-
-/* OMAP Endpoint parameters */
-#define EP0_MAX_PACKET_SIZE 64
-#define UDC_OUT_ENDPOINT 2
-#define UDC_OUT_PACKET_SIZE 64
-#define UDC_IN_ENDPOINT 1
-#define UDC_IN_PACKET_SIZE 64
-#define UDC_INT_ENDPOINT 5
-#define UDC_INT_PACKET_SIZE 16
-#define UDC_BULK_PACKET_SIZE 16
-
-void udc_irq (void);
-/* Flow control */
-void udc_set_nak(int epid);
-void udc_unset_nak (int epid);
-
-/* Higher level functions for abstracting away from specific device */
-int udc_endpoint_write(struct usb_endpoint_instance *endpoint);
-
-int udc_init (void);
-
-void udc_enable(struct usb_device_instance *device);
-void udc_disable(void);
-
-void udc_connect(void);
-void udc_disconnect(void);
-
-void udc_startup_events(struct usb_device_instance *device);
-void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, struct usb_endpoint_instance *endpoint);
-
-#endif
--- /dev/null
+/*
+ * (C) Copyright 2003
+ * Gerry Hamel, geh@ti.com, Texas Instruments
+ *
+ * Based on linux/drivers/usbd/usbd.h
+ *
+ * Copyright (c) 2000, 2001, 2002 Lineo
+ * Copyright (c) 2001 Hewlett Packard
+ *
+ * By:
+ * Stuart Lynne <sl@lineo.com>,
+ * Tom Rushworth <tbr@lineo.com>,
+ * Bruce Balden <balden@lineo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __USBDCORE_H__
+#define __USBDCORE_H__
+
+#include <common.h>
+#include "usbdescriptors.h"
+
+
+#define MAX_URBS_QUEUED 5
+
+
+#if 1
+#define usberr(fmt,args...) serial_printf("ERROR: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
+#else
+#define usberr(fmt,args...) do{}while(0)
+#endif
+
+#if 0
+#define usbdbg(fmt,args...) serial_printf("debug: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
+#else
+#define usbdbg(fmt,args...) do{}while(0)
+#endif
+
+#if 0
+#define usbinfo(fmt,args...) serial_printf("info: %s(), %d: "fmt"\n",__FUNCTION__,__LINE__,##args)
+#else
+#define usbinfo(fmt,args...) do{}while(0)
+#endif
+
+#ifndef le16_to_cpu
+#define le16_to_cpu(x) (x)
+#endif
+
+#ifndef inb
+#define inb(p) (*(volatile u8*)(p))
+#endif
+
+#ifndef outb
+#define outb(val,p) (*(volatile u8*)(p) = (val))
+#endif
+
+#ifndef inw
+#define inw(p) (*(volatile u16*)(p))
+#endif
+
+#ifndef outw
+#define outw(val,p) (*(volatile u16*)(p) = (val))
+#endif
+
+#ifndef inl
+#define inl(p) (*(volatile u32*)(p))
+#endif
+
+#ifndef outl
+#define outl(val,p) (*(volatile u32*)(p) = (val))
+#endif
+
+#ifndef insw
+#define insw(p,to,len) mmio_insw(p,to,len)
+#endif
+
+#ifndef outsw
+#define outsw(p,from,len) mmio_outsw(p,from,len)
+#endif
+
+#ifndef insb
+#define insb(p,to,len) mmio_insb(p,to,len)
+#endif
+
+#ifndef mmio_insw
+#define mmio_insw(r,b,l) ({ int __i ; \
+ u16 *__b2; \
+ __b2 = (u16 *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = inw(r); \
+ }; \
+ })
+#endif
+
+#ifndef mmio_outsw
+#define mmio_outsw(r,b,l) ({ int __i; \
+ u16 *__b2; \
+ __b2 = (u16 *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ outw( *(__b2 + __i), r); \
+ } \
+ })
+#endif
+
+#ifndef mmio_insb
+#define mmio_insb(r,b,l) ({ int __i ; \
+ u8 *__b2; \
+ __b2 = (u8 *) b; \
+ for (__i = 0; __i < l; __i++) { \
+ *(__b2 + __i) = inb(r); \
+ }; \
+ })
+#endif
+
+/*
+ * Structure member address manipulation macros.
+ * These are used by client code (code using the urb_link routines), since
+ * the urb_link structure is embedded in the client data structures.
+ *
+ * Note: a macro offsetof equivalent to member_offset is defined in stddef.h
+ * but this is kept here for the sake of portability.
+ *
+ * p2surround returns a pointer to the surrounding structure given
+ * type of the surrounding structure, the name memb of the structure
+ * member pointed at by ptr. For example, if you have:
+ *
+ * struct foo {
+ * int x;
+ * float y;
+ * char z;
+ * } thingy;
+ *
+ * char *cp = &thingy.z;
+ *
+ * then
+ *
+ * &thingy == p2surround(struct foo, z, cp)
+ *
+ * Clear?
+ */
+#define _cv_(ptr) ((char*)(void*)(ptr))
+#define member_offset(type,memb) (_cv_(&(((type*)0)->memb))-(char*)0)
+#define p2surround(type,memb,ptr) ((type*)(void*)(_cv_(ptr)-member_offset(type,memb)))
+
+struct urb;
+
+struct usb_endpoint_instance;
+struct usb_interface_instance;
+struct usb_configuration_instance;
+struct usb_device_instance;
+struct usb_bus_instance;
+
+/*
+ * Device and/or Interface Class codes
+ */
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_DATA 10
+#define USB_CLASS_APP_SPEC 0xfe
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/*
+ * USB types
+ */
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+/*
+ * USB recipients
+ */
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * USB directions
+ */
+#define USB_DIR_OUT 0
+#define USB_DIR_IN 0x80
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+
+#define USB_DT_HID (USB_TYPE_CLASS | 0x01)
+#define USB_DT_REPORT (USB_TYPE_CLASS | 0x02)
+#define USB_DT_PHYSICAL (USB_TYPE_CLASS | 0x03)
+#define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
+
+/*
+ * Descriptor sizes per descriptor type
+ */
+#define USB_DT_DEVICE_SIZE 18
+#define USB_DT_CONFIG_SIZE 9
+#define USB_DT_INTERFACE_SIZE 9
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+#define USB_DT_HUB_NONVAR_SIZE 7
+#define USB_DT_HID_SIZE 9
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+#define USB_PID_UNDEF_0 0xf0
+#define USB_PID_OUT 0xe1
+#define USB_PID_ACK 0xd2
+#define USB_PID_DATA0 0xc3
+#define USB_PID_PING 0xb4 /* USB 2.0 */
+#define USB_PID_SOF 0xa5
+#define USB_PID_NYET 0x96 /* USB 2.0 */
+#define USB_PID_DATA2 0x87 /* USB 2.0 */
+#define USB_PID_SPLIT 0x78 /* USB 2.0 */
+#define USB_PID_IN 0x69
+#define USB_PID_NAK 0x5a
+#define USB_PID_DATA1 0x4b
+#define USB_PID_PREAMBLE 0x3c /* Token mode */
+#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
+#define USB_PID_SETUP 0x2d
+#define USB_PID_STALL 0x1e
+#define USB_PID_MDATA 0x0f /* USB 2.0 */
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USBD_DEVICE_REQUESTS(x) (((unsigned int)x <= USB_REQ_SYNCH_FRAME) ? usbd_device_requests[x] : "UNKNOWN")
+
+/*
+ * HID requests
+ */
+#define USB_REQ_GET_REPORT 0x01
+#define USB_REQ_GET_IDLE 0x02
+#define USB_REQ_GET_PROTOCOL 0x03
+#define USB_REQ_SET_REPORT 0x09
+#define USB_REQ_SET_IDLE 0x0A
+#define USB_REQ_SET_PROTOCOL 0x0B
+
+
+/*
+ * USB Spec Release number
+ */
+
+#define USB_BCD_VERSION 0x0110
+
+
+/*
+ * Device Requests (c.f Table 9-2)
+ */
+
+#define USB_REQ_DIRECTION_MASK 0x80
+#define USB_REQ_TYPE_MASK 0x60
+#define USB_REQ_RECIPIENT_MASK 0x1f
+
+#define USB_REQ_DEVICE2HOST 0x80
+#define USB_REQ_HOST2DEVICE 0x00
+
+#define USB_REQ_TYPE_STANDARD 0x00
+#define USB_REQ_TYPE_CLASS 0x20
+#define USB_REQ_TYPE_VENDOR 0x40
+
+#define USB_REQ_RECIPIENT_DEVICE 0x00
+#define USB_REQ_RECIPIENT_INTERFACE 0x01
+#define USB_REQ_RECIPIENT_ENDPOINT 0x02
+#define USB_REQ_RECIPIENT_OTHER 0x03
+
+/*
+ * get status bits
+ */
+
+#define USB_STATUS_SELFPOWERED 0x01
+#define USB_STATUS_REMOTEWAKEUP 0x02
+
+#define USB_STATUS_HALT 0x01
+
+/*
+ * descriptor types
+ */
+
+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define USB_DESCRIPTOR_TYPE_STRING 0x03
+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
+#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06
+#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07
+#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08
+#define USB_DESCRIPTOR_TYPE_HID 0x21
+#define USB_DESCRIPTOR_TYPE_REPORT 0x22
+
+#define USBD_DEVICE_DESCRIPTORS(x) (((unsigned int)x <= USB_DESCRIPTOR_TYPE_INTERFACE_POWER) ? \
+ usbd_device_descriptors[x] : "UNKNOWN")
+
+/*
+ * standard feature selectors
+ */
+#define USB_ENDPOINT_HALT 0x00
+#define USB_DEVICE_REMOTE_WAKEUP 0x01
+#define USB_TEST_MODE 0x02
+
+
+/* USB Requests
+ *
+ */
+
+struct usb_device_request {
+ u8 bmRequestType;
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+} __attribute__ ((packed));
+
+
+/* USB Status
+ *
+ */
+typedef enum urb_send_status {
+ SEND_IN_PROGRESS,
+ SEND_FINISHED_OK,
+ SEND_FINISHED_ERROR,
+ RECV_READY,
+ RECV_OK,
+ RECV_ERROR
+} urb_send_status_t;
+
+/*
+ * Device State (c.f USB Spec 2.0 Figure 9-1)
+ *
+ * What state the usb device is in.
+ *
+ * Note the state does not change if the device is suspended, we simply set a
+ * flag to show that it is suspended.
+ *
+ */
+typedef enum usb_device_state {
+ STATE_INIT, /* just initialized */
+ STATE_CREATED, /* just created */
+ STATE_ATTACHED, /* we are attached */
+ STATE_POWERED, /* we have seen power indication (electrical bus signal) */
+ STATE_DEFAULT, /* we been reset */
+ STATE_ADDRESSED, /* we have been addressed (in default configuration) */
+ STATE_CONFIGURED, /* we have seen a set configuration device command */
+ STATE_UNKNOWN, /* destroyed */
+} usb_device_state_t;
+
+#define USBD_DEVICE_STATE(x) (((unsigned int)x <= STATE_UNKNOWN) ? usbd_device_states[x] : "UNKNOWN")
+
+/*
+ * Device status
+ *
+ * Overall state
+ */
+typedef enum usb_device_status {
+ USBD_OPENING, /* we are currently opening */
+ USBD_OK, /* ok to use */
+ USBD_SUSPENDED, /* we are currently suspended */
+ USBD_CLOSING, /* we are currently closing */
+} usb_device_status_t;
+
+#define USBD_DEVICE_STATUS(x) (((unsigned int)x <= USBD_CLOSING) ? usbd_device_status[x] : "UNKNOWN")
+
+/*
+ * Device Events
+ *
+ * These are defined in the USB Spec (c.f USB Spec 2.0 Figure 9-1).
+ *
+ * There are additional events defined to handle some extra actions we need
+ * to have handled.
+ *
+ */
+typedef enum usb_device_event {
+
+ DEVICE_UNKNOWN, /* bi - unknown event */
+ DEVICE_INIT, /* bi - initialize */
+ DEVICE_CREATE, /* bi - */
+ DEVICE_HUB_CONFIGURED, /* bi - bus has been plugged int */
+ DEVICE_RESET, /* bi - hub has powered our port */
+
+ DEVICE_ADDRESS_ASSIGNED, /* ep0 - set address setup received */
+ DEVICE_CONFIGURED, /* ep0 - set configure setup received */
+ DEVICE_SET_INTERFACE, /* ep0 - set interface setup received */
+
+ DEVICE_SET_FEATURE, /* ep0 - set feature setup received */
+ DEVICE_CLEAR_FEATURE, /* ep0 - clear feature setup received */
+
+ DEVICE_DE_CONFIGURED, /* ep0 - set configure setup received for ?? */
+
+ DEVICE_BUS_INACTIVE, /* bi - bus in inactive (no SOF packets) */
+ DEVICE_BUS_ACTIVITY, /* bi - bus is active again */
+
+ DEVICE_POWER_INTERRUPTION, /* bi - hub has depowered our port */
+ DEVICE_HUB_RESET, /* bi - bus has been unplugged */
+ DEVICE_DESTROY, /* bi - device instance should be destroyed */
+
+ DEVICE_HOTPLUG, /* bi - a hotplug event has occured */
+
+ DEVICE_FUNCTION_PRIVATE, /* function - private */
+
+} usb_device_event_t;
+
+
+typedef struct urb_link {
+ struct urb_link *next;
+ struct urb_link *prev;
+} urb_link;
+
+/* USB Data structure - for passing data around.
+ *
+ * This is used for both sending and receiving data.
+ *
+ * The callback function is used to let the function driver know when
+ * transmitted data has been sent.
+ *
+ * The callback function is set by the alloc_recv function when an urb is
+ * allocated for receiving data for an endpoint and used to call the
+ * function driver to inform it that data has arrived.
+ */
+
+#define URB_BUF_SIZE 128 /* in linux we'd malloc this, but in u-boot we prefer static data */
+struct urb {
+
+ struct usb_endpoint_instance *endpoint;
+ struct usb_device_instance *device;
+
+ struct usb_device_request device_request; /* contents of received SETUP packet */
+
+ struct urb_link link; /* embedded struct for circular doubly linked list of urbs */
+
+ u8* buffer;
+ unsigned int buffer_length;
+ unsigned int actual_length;
+
+ urb_send_status_t status;
+ int data;
+
+ u16 buffer_data[URB_BUF_SIZE]; /* data received (OUT) or being sent (IN) */
+};
+
+/* Endpoint configuration
+ *
+ * Per endpoint configuration data. Used to track which function driver owns
+ * an endpoint.
+ *
+ */
+struct usb_endpoint_instance {
+ int endpoint_address; /* logical endpoint address */
+
+ /* control */
+ int status; /* halted */
+ int state; /* available for use by bus interface driver */
+
+ /* receive side */
+ struct urb_link rcv; /* received urbs */
+ struct urb_link rdy; /* empty urbs ready to receive */
+ struct urb *rcv_urb; /* active urb */
+ int rcv_attributes; /* copy of bmAttributes from endpoint descriptor */
+ int rcv_packetSize; /* maximum packet size from endpoint descriptor */
+ int rcv_transferSize; /* maximum transfer size from function driver */
+ int rcv_queue;
+
+ /* transmit side */
+ struct urb_link tx; /* urbs ready to transmit */
+ struct urb_link done; /* transmitted urbs */
+ struct urb *tx_urb; /* active urb */
+ int tx_attributes; /* copy of bmAttributes from endpoint descriptor */
+ int tx_packetSize; /* maximum packet size from endpoint descriptor */
+ int tx_transferSize; /* maximum transfer size from function driver */
+ int tx_queue;
+
+ int sent; /* data already sent */
+ int last; /* data sent in last packet XXX do we need this */
+};
+
+struct usb_alternate_instance {
+ struct usb_interface_descriptor *interface_descriptor;
+
+ int endpoints;
+ int *endpoint_transfersize_array;
+ struct usb_endpoint_descriptor **endpoints_descriptor_array;
+};
+
+struct usb_interface_instance {
+ int alternates;
+ struct usb_alternate_instance *alternates_instance_array;
+};
+
+struct usb_configuration_instance {
+ int interfaces;
+ struct usb_configuration_descriptor *configuration_descriptor;
+ struct usb_interface_instance *interface_instance_array;
+};
+
+
+/* USB Device Instance
+ *
+ * For each physical bus interface we create a logical device structure. This
+ * tracks all of the required state to track the USB HOST's view of the device.
+ *
+ * Keep track of the device configuration for a real physical bus interface,
+ * this includes the bus interface, multiple function drivers, the current
+ * configuration and the current state.
+ *
+ * This will show:
+ * the specific bus interface driver
+ * the default endpoint 0 driver
+ * the configured function driver
+ * device state
+ * device status
+ * endpoint list
+ */
+
+struct usb_device_instance {
+
+ /* generic */
+ char *name;
+ struct usb_device_descriptor *device_descriptor; /* per device descriptor */
+
+ void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data);
+
+ /* Do cdc device specific control requests */
+ int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb);
+
+ /* bus interface */
+ struct usb_bus_instance *bus; /* which bus interface driver */
+
+ /* configuration descriptors */
+ int configurations;
+ struct usb_configuration_instance *configuration_instance_array;
+
+ /* device state */
+ usb_device_state_t device_state; /* current USB Device state */
+ usb_device_state_t device_previous_state; /* current USB Device state */
+
+ u8 address; /* current address (zero is default) */
+ u8 configuration; /* current show configuration (zero is default) */
+ u8 interface; /* current interface (zero is default) */
+ u8 alternate; /* alternate flag */
+
+ usb_device_status_t status; /* device status */
+
+ int urbs_queued; /* number of submitted urbs */
+
+ /* Shouldn't need to make this atomic, all we need is a change indicator */
+ unsigned long usbd_rxtx_timestamp;
+ unsigned long usbd_last_rxtx_timestamp;
+
+};
+
+/* Bus Interface configuration structure
+ *
+ * This is allocated for each configured instance of a bus interface driver.
+ *
+ * The privdata pointer may be used by the bus interface driver to store private
+ * per instance state information.
+ */
+struct usb_bus_instance {
+
+ struct usb_device_instance *device;
+ struct usb_endpoint_instance *endpoint_array; /* array of available configured endpoints */
+
+ int max_endpoints; /* maximimum number of rx enpoints */
+ unsigned char maxpacketsize;
+
+ unsigned int serial_number;
+ char *serial_number_str;
+ void *privdata; /* private data for the bus interface */
+
+};
+
+extern char *usbd_device_events[];
+extern char *usbd_device_states[];
+extern char *usbd_device_status[];
+extern char *usbd_device_requests[];
+extern char *usbd_device_descriptors[];
+
+void urb_link_init (urb_link * ul);
+void urb_detach (struct urb *urb);
+urb_link *first_urb_link (urb_link * hd);
+struct urb *first_urb (urb_link * hd);
+struct urb *first_urb_detached (urb_link * hd);
+void urb_append (urb_link * hd, struct urb *urb);
+
+struct urb *usbd_alloc_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint);
+void usbd_dealloc_urb (struct urb *urb);
+
+/*
+ * usbd_device_event is used by bus interface drivers to tell the higher layers that
+ * certain events have taken place.
+ */
+void usbd_device_event_irq (struct usb_device_instance *conf, usb_device_event_t, int);
+void usbd_device_event (struct usb_device_instance *conf, usb_device_event_t, int);
+
+/* descriptors
+ *
+ * Various ways of finding descriptors based on the current device and any
+ * possible configuration / interface / endpoint for it.
+ */
+struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct usb_device_instance *, int, int);
+struct usb_function_instance *usbd_device_function_instance (struct usb_device_instance *, unsigned int);
+struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *, int, int, int);
+struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *, int, int, int, int);
+struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance *, int, int, int, int);
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
+struct usb_class_descriptor *usbd_device_class_descriptor_index (struct usb_device_instance *, int, int, int, int, int);
+struct usb_class_report_descriptor *usbd_device_class_report_descriptor_index( struct usb_device_instance *, int , int , int , int , int );
+struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *, int, int, int, int, int);
+int usbd_device_endpoint_transfersize (struct usb_device_instance *, int, int, int, int, int);
+struct usb_string_descriptor *usbd_get_string (u8);
+struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *, int);
+
+int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint);
+void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad);
+void usbd_tx_complete (struct usb_endpoint_instance *endpoint);
+
+#endif