summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/host/Kconfig22
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/isp1763-hal-interface.h312
-rw-r--r--drivers/usb/host/isp1763-hal.c1757
-rw-r--r--drivers/usb/host/isp1763-hal.h85
-rw-r--r--drivers/usb/host/isp1763-hcd.c6534
-rw-r--r--drivers/usb/host/isp1763-hcd.h755
-rw-r--r--drivers/usb/host/isp1763-itdptd.c2156
-rw-r--r--drivers/usb/host/isp1763-mem.c355
-rw-r--r--drivers/usb/host/isp1763-otg.c189
-rw-r--r--drivers/usb/host/isp1763-qtdptd.c1315
-rw-r--r--drivers/usb/host/isp1763.h224
13 files changed, 13708 insertions, 0 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 30ddf8dc4f7..31d46a1c342 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -21,6 +21,8 @@ obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
+obj-$(CONFIG_USB_ISP1763_HAL) += host/
+obj-$(CONFIG_USB_ISP1763_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ab085f12d57..d9d93699711 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -269,6 +269,28 @@ config USB_ISP1362_HCD
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
+config USB_ISP1763_HAL
+ tristate "ISP1763 HAL driver"
+ depends on USB
+ default N
+ ---help---
+ ISP1763 Hardware Abstraction Layer driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1763-hal.
+
+config USB_ISP1763_HCD
+ tristate "ISP1763 Host Controller"
+ depends on USB && USB_ISP1763_HAL
+ default N
+ ---help---
+ Supports for the ISP1763 chip as a host controller
+
+ This driver does not support isochronous transfers well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1763-hcd.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 624a362f2fe..7fbe65f1123 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o
+obj-$(CONFIG_USB_ISP1763_HAL) += isp1763-hal.o
+obj-$(CONFIG_USB_ISP1763_HCD) += isp1763-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
diff --git a/drivers/usb/host/isp1763-hal-interface.h b/drivers/usb/host/isp1763-hal-interface.h
new file mode 100644
index 00000000000..c19d6506a43
--- /dev/null
+++ b/drivers/usb/host/isp1763-hal-interface.h
@@ -0,0 +1,312 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : hal
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a hardware abstraction layer header file.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#ifndef HAL_INTF_H
+#define HAL_INTF_H
+
+
+#define HCD_PACKAGE
+
+#define NON_PCI
+#undef PXA300
+
+//#define MSEC_INT_BASED
+#ifdef MSEC_INT_BASED
+#define THREAD_BASED
+#endif
+
+//#ifndef DATABUS_WIDTH_16
+#define DATABUS_WIDTH_16
+//#endif
+
+#ifdef DATABUS_WIDTH_16
+/*DMA SUPPORT */
+//#define ENABLE_PLX_DMA
+#undef ENABLE_PLX_DMA
+#endif
+
+#define EDGE_INTERRUPT
+#define POL_HIGH_INTERRUPT
+
+#define DMA_BUF_SIZE (4096 * 2)
+
+#define ISP1763_CHIPID 0x176320
+
+/* Values for id_flags filed of isp1763_driver_t */
+#define ISP1763_HC 0 /* Host Controller Driver */
+#define ISP1763_DC 1 /* Device Controller Driver */
+#define ISP1763_OTG 2 /* Otg Controller Driver */
+#define ISP1763_LAST_DEV (ISP1763_OTG + 1)
+#define ISP1763_1ST_DEV (ISP1763_HC)
+
+#ifdef PXA300
+#define HC_SPARAMS_REG (0x04<<1) /* Structural Parameters Register */
+#define HC_CPARAMS_REG (0x08<<1) /* Capability Parameters Register */
+
+#define HC_USBCMD_REG (0x8C<<1) /* USB Command Register */
+#define HC_USBSTS_REG (0x90<<1) /* USB Status Register */
+#define HC_INTERRUPT_REG_EHCI (0x94<<1) /* INterrupt Enable Register */
+#define HC_FRINDEX_REG (0x98<<1) /* Frame Index Register */
+
+#define HC_CONFIGFLAG_REG (0x9C<<1) /* Conigured Flag Register */
+#define HC_PORTSC1_REG (0xA0<<1) /* Port Status Control for Port1 */
+
+/*ISO Transfer Registers */
+#define HC_ISO_PTD_DONEMAP_REG (0xA4<<1) /* ISO PTD Done Map Register */
+#define HC_ISO_PTD_SKIPMAP_REG (0xA6<<1) /* ISO PTD Skip Map Register */
+#define HC_ISO_PTD_LASTPTD_REG (0xA8<<1) /* ISO PTD Last PTD Register */
+
+/*INT Transfer Registers */
+#define HC_INT_PTD_DONEMAP_REG (0xAA<<1) /* INT PTD Done Map Register */
+#define HC_INT_PTD_SKIPMAP_REG (0xAC<<1) /* INT PTD Skip Map Register */
+#define HC_INT_PTD_LASTPTD_REG (0xAE<<1) /* INT PTD Last PTD Register */
+
+/*ATL Transfer Registers */
+#define HC_ATL_PTD_DONEMAP_REG (0xB0<<1) /* ATL PTD Last PTD Register */
+#define HC_ATL_PTD_SKIPMAP_REG (0xB2<<1) /* ATL PTD Last PTD Register */
+#define HC_ATL_PTD_LASTPTD_REG (0xB4<<1) /* ATL PTD Last PTD Register */
+
+/*General Purpose Registers */
+#define HC_HW_MODE_REG (0x0C<<1) /* H/W Mode Register */
+#define HC_CHIP_ID_REG (0x70<<1) /* Chip ID Register */
+#define HC_SCRATCH_REG (0x78<<1) /* Scratch Register */
+#define HC_RESET_REG (0xB8<<1) /* HC Reset Register */
+#define HC_HWMODECTRL_REG (0xB6<<1)
+#define HC_UNLOCK_DEVICE (0x7C<<1)
+
+/* Interrupt Registers */
+#define HC_INTERRUPT_REG (0xD4<<1) /* Interrupt Register */
+#define HC_INTENABLE_REG (0xD6<<1) /* Interrupt enable Register */
+#define HC_ISO_IRQ_MASK_OR_REG (0xD8<<1) /* ISO Mask OR Register */
+#define HC_INT_IRQ_MASK_OR_REG (0xDA<<1) /* INT Mask OR Register */
+#define HC_ATL_IRQ_MASK_OR_REG (0xDC<<1) /* ATL Mask OR Register */
+#define HC_ISO_IRQ_MASK_AND_REG (0xDE<<1) /* ISO Mask AND Register */
+#define HC_INT_IRQ_MASK_AND_REG (0xE0<<1) /* INT Mask AND Register */
+#define HC_ATL_IRQ_MASK_AND_REG (0xE2<<1) /* ATL Mask AND Register */
+
+/*power control reg */
+#define HC_POWER_DOWN_CONTROL_REG (0xD0<<1)
+
+/*RAM Registers */
+#define HC_DMACONFIG_REG (0xBC<<1) /* DMA Config Register */
+#define HC_MEM_READ_REG (0xC4<<1) /* Memory Register */
+#define HC_DATA_REG (0xC6<<1) /* Data Register */
+
+#define OTG_CTRL_SET_REG (0xE4<<1)
+#define OTG_CTRL_CLEAR_REG (0xE6<<1)
+#define OTG_SOURCE_REG (0xE8<<1)
+
+#define OTG_INTR_EN_F_SET_REG (0xF0<<1)
+#define OTG_INTR_EN_R_SET_REG (0xF4<<1) /* OTG Interrupt Enable Rise register */
+
+#else
+#define HC_SPARAMS_REG 0x04 /* Structural Parameters Register */
+#define HC_CPARAMS_REG 0x08 /* Capability Parameters Register */
+
+#define HC_USBCMD_REG 0x8C /* USB Command Register */
+#define HC_USBSTS_REG 0x90 /* USB Status Register */
+#define HC_INTERRUPT_REG_EHCI 0x94 /* INterrupt Enable Register */
+#define HC_FRINDEX_REG 0x98 /* Frame Index Register */
+
+#define HC_CONFIGFLAG_REG 0x9C /* Conigured Flag Register */
+#define HC_PORTSC1_REG 0xA0 /* Port Status Control for Port1 */
+
+/*ISO Transfer Registers */
+#define HC_ISO_PTD_DONEMAP_REG 0xA4 /* ISO PTD Done Map Register */
+#define HC_ISO_PTD_SKIPMAP_REG 0xA6 /* ISO PTD Skip Map Register */
+#define HC_ISO_PTD_LASTPTD_REG 0xA8 /* ISO PTD Last PTD Register */
+
+/*INT Transfer Registers */
+#define HC_INT_PTD_DONEMAP_REG 0xAA /* INT PTD Done Map Register */
+#define HC_INT_PTD_SKIPMAP_REG 0xAC /* INT PTD Skip Map Register */
+#define HC_INT_PTD_LASTPTD_REG 0xAE /* INT PTD Last PTD Register */
+
+/*ATL Transfer Registers */
+#define HC_ATL_PTD_DONEMAP_REG 0xB0 /* ATL PTD Last PTD Register */
+#define HC_ATL_PTD_SKIPMAP_REG 0xB2 /* ATL PTD Last PTD Register */
+#define HC_ATL_PTD_LASTPTD_REG 0xB4 /* ATL PTD Last PTD Register */
+
+/*General Purpose Registers */
+#define HC_HW_MODE_REG 0x0C //0xB6 /* H/W Mode Register */
+#define HC_CHIP_ID_REG 0x70 /* Chip ID Register */
+#define HC_SCRATCH_REG 0x78 /* Scratch Register */
+#define HC_RESET_REG 0xB8 /* HC Reset Register */
+#define HC_HWMODECTRL_REG 0xB6 //0x0C /* H/W Mode control Register */
+#define HC_UNLOCK_DEVICE 0x7C
+
+/* Interrupt Registers */
+#define HC_INTERRUPT_REG 0xD4 /* Interrupt Register */
+#define HC_INTENABLE_REG 0xD6 /* Interrupt enable Register */
+#define HC_ISO_IRQ_MASK_OR_REG 0xD8 /* ISO Mask OR Register */
+#define HC_INT_IRQ_MASK_OR_REG 0xDA /* INT Mask OR Register */
+#define HC_ATL_IRQ_MASK_OR_REG 0xDC /* ATL Mask OR Register */
+#define HC_ISO_IRQ_MASK_AND_REG 0xDE /* ISO Mask AND Register */
+#define HC_INT_IRQ_MASK_AND_REG 0xE0 /* INT Mask AND Register */
+#define HC_ATL_IRQ_MASK_AND_REG 0xE2 /* ATL Mask AND Register */
+
+/*power control reg */
+#define HC_POWER_DOWN_CONTROL_REG 0xD0
+
+/*RAM Registers */
+#define HC_DMACONFIG_REG 0xBC /* DMA Config Register */
+#define HC_MEM_READ_REG 0xC4 /* Memory Register */
+#define HC_DATA_REG 0xC6 /* Data Register */
+
+#define OTG_CTRL_SET_REG 0xE4
+#define OTG_CTRL_CLEAR_REG 0xE6
+#define OTG_SOURCE_REG 0xE8
+
+#define OTG_INTR_EN_F_SET_REG 0xF0 /* OTG Interrupt Enable Fall register */
+#define OTG_INTR_EN_R_SET_REG 0xF4 /* OTG Interrupt Enable Rise register */
+
+#endif
+
+#define OTG_CTRL_DPPULLUP 0x0001
+#define OTG_CTRL_DPPULLDOWN 0x0002
+#define OTG_CTRL_DMPULLDOWN 0x0004
+#define OTG_CTRL_VBUS_DRV 0x0010
+#define OTG_CTRL_VBUS_DISCHRG 0x0020
+#define OTG_CTRL_VBUS_CHRG 0x0040
+#define OTG_CTRL_SW_SEL_HC_DC 0x0080
+#define OTG_CTRL_BDIS_ACON_EN 0x0100
+#define OTG_CTRL_OTG_SE0_EN 0x0200
+#define OTG_CTRL_OTG_DISABLE 0x0400
+#define OTG_CTRL_VBUS_DRV_PORT2 0x1000
+#define OTG_CTRL_SW_SEL_HC_2 0x8000
+
+/*interrupt count and buffer status register*/
+
+
+#ifdef PXA300
+#define HC_BUFFER_STATUS_REG (0xBA<<1)
+#define HC_INT_THRESHOLD_REG (0xC8<<1)
+#else
+#define HC_BUFFER_STATUS_REG 0xBA
+#define HC_INT_THRESHOLD_REG 0xC8
+#endif
+
+#define HC_OTG_INTERRUPT 0x400
+
+#ifdef PXA300
+#define DC_CHIPID (0x70<<1)
+#else
+#define DC_CHIPID 0x70
+#endif
+
+
+#ifdef PXA300
+#define FPGA_CONFIG_REG (0x100<<1)
+#else
+#define FPGA_CONFIG_REG 0x100
+#endif
+
+#define HC_HW_MODE_GOBAL_INTR_ENABLE 0x01
+#define HC_HW_MODE_INTR_EDGE 0x02
+#define HC_HW_MODE_INTR_POLARITY_HIGH 0x04
+#define HC_HW_MODE_LOCK 0x08
+#define HC_HW_MODE_DATABUSWIDTH_8 0x10
+#define HC_HW_MODE_DREQ_POL_HIGH 0x20
+#define HC_HW_MODE_DACK_POL_HIGH 0x40
+#define HC_HW_MODE_COMN_INT 0x80
+
+struct isp1763_driver;
+typedef struct _isp1763_id {
+ u16 idVendor;
+ u16 idProduct;
+ u32 driver_info;
+} isp1763_id;
+
+typedef struct isp1763_dev {
+ /*added for pci device */
+#ifdef NON_PCI
+ struct platform_device *dev;
+#else /*PCI*/
+ struct pci_dev *pcidev;
+#endif
+ struct isp1763_driver *driver; /* which driver has allocated this device */
+ void *driver_data; /* data private to the host controller driver */
+ void *otg_driver_data; /*data private for otg controler */
+ unsigned char index; /* local controller (HC/DC/OTG) */
+ unsigned int irq; /*Interrupt Channel allocated for this device */
+ void (*handler) (struct isp1763_dev * dev, void *isr_data); /* Interrupt Serrvice Routine */
+ void *isr_data; /* isr data of the driver */
+ unsigned long int_reg; /* Interrupt register */
+ unsigned long alt_int_reg; /* Interrupt register 2 */
+ unsigned long start;
+ unsigned long length;
+ struct resource *mem_res;
+ unsigned long io_base; /* Start Io address space for this device */
+ unsigned long io_len; /* IO address space length for this device */
+
+ unsigned long chip_id; /* Chip Id */
+
+ char name[80]; /* device name */
+ int active; /* device status */
+
+ /* DMA resources should come here */
+ unsigned long dma;
+ u8 *baseaddress; /*base address for i/o ops */
+ u8 *dmabase;
+ isp1763_id *id;
+} isp1763_dev_t;
+
+
+typedef struct isp1763_driver {
+ char *name;
+ unsigned long index; /* HC or DC or OTG */
+ isp1763_id *id; /*device ids */
+ int (*probe) (struct isp1763_dev * dev, isp1763_id * id); /* New device inserted */
+ void (*remove) (struct isp1763_dev * dev); /* Device removed (NULL if not a hot-plug capable driver) */
+
+ void (*suspend) (struct isp1763_dev * dev); /* Device suspended */
+ void (*resume) (struct isp1763_dev * dev); /* Device woken up */
+ void (*remotewakeup) (struct isp1763_dev *dev); /* Remote Wakeup */
+ void (*powerup) (struct isp1763_dev *dev); /* Device poweup mode */
+ void (*powerdown) (struct isp1763_dev *dev); /* Device power down mode */
+} isp_1763_driver_t;
+
+struct usb_device *phci_register_otg_device(struct isp1763_dev *dev);
+
+/*otg exported function from host*/
+int phci_suspend_otg_port(struct isp1763_dev *dev, u32 command);
+int phci_enumerate_otg_port(struct isp1763_dev *dev, u32 command);
+
+extern int isp1763_register_driver(struct isp1763_driver *drv);
+extern void isp1763_unregister_driver(struct isp1763_driver *drv);
+extern int isp1763_request_irq(void (*handler)(struct isp1763_dev * dev, void *isr_data),
+ struct isp1763_dev *dev, void *isr_data);
+extern void isp1763_free_irq(struct isp1763_dev *dev, void *isr_data);
+
+extern u32 isp1763_reg_read32(isp1763_dev_t * dev, u16 reg, u32 data);
+extern u16 isp1763_reg_read16(isp1763_dev_t * dev, u16 reg, u16 data);
+extern u8 isp1763_reg_read8(struct isp1763_dev *dev, u16 reg, u8 data);
+extern void isp1763_reg_write32(isp1763_dev_t * dev, u16 reg, u32 data);
+extern void isp1763_reg_write16(isp1763_dev_t * dev, u16 reg, u16 data);
+extern void isp1763_reg_write8(struct isp1763_dev *dev, u16 reg, u8 data);
+extern int isp1763_mem_read(isp1763_dev_t * dev, u32 start_add,
+ u32 end_add, u32 * buffer, u32 length, u16 dir);
+extern int isp1763_mem_write(isp1763_dev_t * dev, u32 start_add,
+ u32 end_add, u32 * buffer, u32 length, u16 dir);
+
+#endif /* __HAL_INTF_H__ */
diff --git a/drivers/usb/host/isp1763-hal.c b/drivers/usb/host/isp1763-hal.c
new file mode 100644
index 00000000000..388bf5a0072
--- /dev/null
+++ b/drivers/usb/host/isp1763-hal.c
@@ -0,0 +1,1757 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : hal
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is the main hardware abstraction layer file. Hardware initialization, interupt
+* processing and read/write routines are handled here.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+//#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+#include <linux/version.h>
+/*--------------------------------------------------------------*
+ * linux system include files
+ *--------------------------------------------------------------*/
+#include "isp1763-hal.h"
+#include "isp1763-hal-interface.h"
+#include "isp1763.h"
+
+/*--------------------------------------------------------------*
+ * Local variable Definitions
+ *--------------------------------------------------------------*/
+#ifdef ENABLE_PLX_DMA
+u32 plx9054_reg_read(u32 reg);
+void plx9054_reg_write(u32 reg, u32 data);
+
+u8 *g_pDMA_Write_Buf = 0;
+u8 *g_pDMA_Read_Buf = 0;
+
+#endif
+
+struct isp1763_dev isp1763_loc_dev[ISP1763_LAST_DEV];
+static u32 pci_io_base = 0;
+void *iobase = 0;
+int iolength = 0;
+
+#ifdef NON_PCI
+#else
+static u32 pci_mem_phy0 = 0;
+static u32 pci_mem_len = 0x20000;
+static int isp1763_pci_latency;
+#endif
+
+/*--------------------------------------------------------------*
+ * Local # Definitions
+ *--------------------------------------------------------------*/
+#define PCI_ACCESS_RETRY_COUNT 20
+
+#ifdef NON_PCI
+#define isp1763_driver_name "1763-plat"
+#else
+#define ISP1763_DRIVER_NAME "1763-pci"
+#endif
+
+/*--------------------------------------------------------------*
+ * Local Function
+ *--------------------------------------------------------------*/
+#ifdef NON_PCI
+static void __devexit isp1763_remove (struct device *dev);
+static int __devinit isp1763_probe (struct device *dev);
+//static irqreturn_t isp1763_non_pci_isr (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t isp1763_non_pci_isr (int irq, void *dev_id);
+#else /*PCI*/
+static void __devexit isp1763_pci_remove(struct pci_dev *dev);
+static int __devinit isp1763_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id);
+
+static irqreturn_t isp1763_pci_isr(int irq, void *dev_id);
+#endif
+
+
+
+/*--------------------------------------------------------------*
+ * ISP1763 Interrupt Service Routine
+ *--------------------------------------------------------------*/
+/*Interrupt Service Routine for device controller*/
+irqreturn_t
+isp1763_pci_dc_isr(int irq, void *data)
+{
+ struct isp1763_dev *dev;
+ u32 int_enable=0;
+ dev = &isp1763_loc_dev[ISP1763_DC];
+
+ hal_entry("%s: Entered\n", __FUNCTION__);
+ /*not ready yet */
+ if (dev->active == 0) {
+ printk("isp1763_pci_dc_isr: dev->active is NULL \n");
+ return IRQ_NONE;
+ }
+
+ /*unblock the device interrupt */
+ isp1763_reg_write16(dev, DEV_UNLOCK_REGISTER, 0xaa37);
+ dev->int_reg =
+ isp1763_reg_read32(dev, DEV_INTERRUPT_REGISTER, dev->int_reg);
+ int_enable = isp1763_reg_read32(dev, INT_ENABLE_REGISTER, int_enable);
+ hal_int("isp1763_pci_dc_isr:INTERRUPT_REGISTER 0x%x\n", dev->int_reg);
+
+ /*clear the interrupt source */
+ isp1763_reg_write32(dev, DEV_INTERRUPT_REGISTER, dev->int_reg);
+ if (dev->int_reg) {
+ if (dev->handler) {
+ dev->handler(dev, dev->isr_data);
+ }
+ }
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ return IRQ_HANDLED;
+}
+
+/* Interrupt Service Routine of isp1763
+ * Reads the source of interrupt and calls the corresponding driver's ISR.
+ * Before calling the driver's ISR clears the source of interrupt.
+ * The drivers can get the source of interrupt from the dev->int_reg field
+ */
+#ifdef NON_PCI
+// irqreturn_t isp1763_non_pci_isr(int irq, void *__data, struct pt_regs *r)
+irqreturn_t isp1763_non_pci_isr(int irq, void *__data)
+#else /*PCI*/
+irqreturn_t
+isp1763_pci_isr(int irq, void *__data)
+#endif
+{
+ u32 irq_mask = 0;
+ struct isp1763_dev *dev;
+ u32 otg_int;
+ hal_entry("%s: Entered\n", __FUNCTION__);
+ /* Process the Host Controller Driver */
+ dev = &isp1763_loc_dev[ISP1763_HC];
+ /* Get the source of interrupts for Host Controller */
+ dev->int_reg = 0;
+ dev->int_reg = isp1763_reg_read16(dev, HC_INTERRUPT_REG, dev->int_reg);
+
+ isp1763_reg_write16(dev, HC_INTERRUPT_REG, dev->int_reg);
+ irq_mask = isp1763_reg_read16(dev, HC_INTENABLE_REG, irq_mask);
+ dev->int_reg &= irq_mask;
+
+ /*process otg interrupt if there is any */
+ if (dev->int_reg & HC_OTG_INTERRUPT) {
+ otg_int = (dev->int_reg & HC_OTG_INTERRUPT);
+ /* Process OTG controller Driver
+ * Since OTG is part of HC interrupt register,
+ * the interrupt source will be HC interrupt Register
+ * */
+ dev = &isp1763_loc_dev[ISP1763_OTG];
+ /* Read the source of OTG_INT and clear the
+ interrupt source */
+ if (dev->handler) {
+ dev->int_reg = otg_int;
+ dev->handler(dev, dev->isr_data);
+ }
+ }
+ dev = &isp1763_loc_dev[ISP1763_HC];
+ if (dev->int_reg & ~HC_OTG_INTERRUPT) {
+ if (dev->handler) {
+ dev->handler(dev, dev->isr_data);
+ }
+ }
+
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ return IRQ_HANDLED;
+} /* End of isp1763_pci_isr */
+
+#ifdef NON_PCI
+/*--------------------------------------------------------------*
+ i* NON_PCI Driver Interface Functions
+ *--------------------------------------------------------------*/
+
+#define ISP1763_ID -1
+
+/* Important fields to initialize for Non-PCI based driver*/
+
+/* The base physical memory address assigned for the ISP176x */
+#define ISP176x_MEM_BASE 0x54000000 //base address
+
+/* The memory range assigned for the ISP176x */
+#define ISP176x_MEM_RANGE 0x10000
+
+/* The IRQ number assigned to the ISP176x */
+#define ISP176x_IRQ_NUM 191
+
+static struct resource isp1763_resources[] = {
+ [0] = {
+ .start= ISP176x_MEM_BASE,
+ .end= (ISP176x_MEM_BASE | ISP176x_MEM_RANGE),
+ .flags= IORESOURCE_MEM,
+ },
+ [1] = {
+ .start= ISP176x_IRQ_NUM,
+ .end= ISP176x_IRQ_NUM,
+ .flags= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+
+static void isp1763_device_release(struct device *dev)
+{
+ /* Keep this function empty. */
+}
+
+static struct platform_device isp1763_device = {
+ .name = "isp176x_hal",
+ .id = ISP1763_ID,
+ .dev = {
+ .release = isp1763_device_release,
+ },
+
+ .num_resources = ARRAY_SIZE(isp1763_resources),
+ .resource = isp1763_resources,
+};
+
+static struct device_driver isp1763_driver = {
+ .name = "isp176x_hal",
+ .bus = &platform_bus_type,
+ .probe = isp1763_probe,
+ .remove = isp1763_remove,
+#ifndef NON_PCI
+ .suspend = isp1763a_pci_suspend,
+ .resume = isp1763a_pci_resume,
+#endif
+ };
+
+#else /*PCI*/
+
+/*--------------------------------------------------------------*
+ * PCI Driver Interface Functions
+ *--------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata isp1763_pci_ids[] = {
+ {
+ /* handle PCI BRIDE manufactured by PLX */
+ class:((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)),
+ class_mask:~0,
+ /* no matter who makes it */
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ },
+ { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, isp1763_pci_ids);
+
+/* Pci driver interface functions */
+static struct pci_driver isp1763_pci_driver = {
+ name:"isp1763-hal",
+ id_table:&isp1763_pci_ids[0],
+ probe:isp1763_pci_probe,
+ remove:isp1763_pci_remove,
+};
+
+#endif
+
+
+/*--------------------------------------------------------------*
+ * ISP1763 Read write routine
+ *--------------------------------------------------------------*/
+
+/* Write a 32 bit Register of isp1763 */
+void
+isp1763_reg_write32(struct isp1763_dev *dev, u16 reg, u32 data)
+{
+ /* Write the 32bit to the register address given to us */
+
+#ifdef DATABUS_WIDTH_16
+ writew((u16) data, dev->baseaddress + ((reg) << 1 ));
+ writew((u16) (data >> 16), dev->baseaddress + (((reg + 2) << 1)));
+#else
+ writeb((u8) data, dev->baseaddress + (reg));
+ writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1)));
+ writeb((u8) (data >> 16), dev->baseaddress + ((reg + 2)));
+ writeb((u8) (data >> 24), dev->baseaddress + ((reg + 3)));
+#endif
+}
+EXPORT_SYMBOL(isp1763_reg_write32);
+
+/* Read a 32 bit Register of isp1763 */
+u32
+isp1763_reg_read32(struct isp1763_dev *dev, u16 reg, u32 data)
+{
+#ifdef DATABUS_WIDTH_16
+ u16 wvalue1, wvalue2;
+#else
+ u8 bval1, bval2, bval3, bval4;
+#endif
+ data = 0;
+
+#ifdef DATABUS_WIDTH_16
+ wvalue1 = readw(dev->baseaddress + ((reg << 1))) & 0xFFFF ;
+ wvalue2 = readw(dev->baseaddress + (((reg + 2) << 1))) & 0xFFFF ;
+ data |= wvalue2;
+ data <<= 16;
+ data |= wvalue1;
+#else
+ bval1 = readb(dev->baseaddress + (reg));
+ bval2 = readb(dev->baseaddress + (reg + 1));
+ bval3 = readb(dev->baseaddress + (reg + 2));
+ bval4 = readb(dev->baseaddress + (reg + 3));
+ data = 0;
+ data |= bval4;
+ data <<= 8;
+ data |= bval3;
+ data <<= 8;
+ data |= bval2;
+ data <<= 8;
+ data |= bval1;
+
+#endif
+
+ return data;
+}
+EXPORT_SYMBOL(isp1763_reg_read32);
+
+
+/* Read a 16 bit Register of isp1763 */
+u16
+isp1763_reg_read16(struct isp1763_dev * dev, u16 reg, u16 data)
+{
+#ifdef DATABUS_WIDTH_16
+#else
+ u8 bval1, bval2;
+#endif
+
+#ifdef DATABUS_WIDTH_16
+// data = readw(dev->baseaddress + ((reg)));
+ data = (readw(dev->baseaddress + (reg << 1 )));
+#else
+ bval1 = readb(dev->baseaddress + (reg));
+ if (reg == HC_DATA_REG)
+ bval2 = readb(dev->baseaddress + (reg));
+ else
+ bval2 = readb(dev->baseaddress + ((reg + 1)));
+ data = 0;
+ data |= bval2;
+ data <<= 8;
+ data |= bval1;
+
+#endif
+ return data;
+}
+EXPORT_SYMBOL(isp1763_reg_read16);
+
+/* Write a 16 bit Register of isp1763 */
+void
+isp1763_reg_write16(struct isp1763_dev *dev, u16 reg, u16 data)
+{
+#ifdef DATABUS_WIDTH_16
+// writew(data, dev->baseaddress + ((reg)));
+ writew(data, dev->baseaddress + ((reg << 1)));
+#else
+ writeb((u8) data, dev->baseaddress + (reg));
+ if (reg == HC_DATA_REG)
+ writeb((u8) (data >> 8), dev->baseaddress + (reg));
+ else
+ writeb((u8) (data >> 8), dev->baseaddress + ((reg + 1)));
+#endif
+}
+EXPORT_SYMBOL(isp1763_reg_write16);
+
+/* Read a 8 bit Register of isp1763 */
+u8
+isp1763_reg_read8(struct isp1763_dev *dev, u16 reg, u8 data)
+{
+ data = readb((dev->baseaddress + (reg << 1)));
+ return data;
+}
+EXPORT_SYMBOL(isp1763_reg_read8);
+
+/* Write a 8 bit Register of isp1763 */
+void
+isp1763_reg_write8(struct isp1763_dev *dev, u16 reg, u8 data)
+{
+ writeb(data, (dev->baseaddress + (reg << 1)));
+}
+EXPORT_SYMBOL(isp1763_reg_write8);
+/* Access PLX9054 Register */
+void
+plx9054_reg_write(u32 reg, u32 data)
+{
+ writel(data, iobase + (reg));
+}
+EXPORT_SYMBOL(plx9054_reg_write);
+
+
+void
+plx9054_reg_writeb(u32 reg, u32 data)
+{
+ writeb(data, iobase + (reg));
+}
+EXPORT_SYMBOL(plx9054_reg_writeb);
+
+u32
+plx9054_reg_read(u32 reg)
+{
+ u32 uData;
+
+ uData = readl(iobase + (reg));
+
+ return uData;
+}
+EXPORT_SYMBOL(plx9054_reg_read);
+
+u8
+plx9054_reg_readb(u32 reg)
+{
+ u8 bData;
+
+ bData = readb(iobase + (reg));
+
+ return bData;
+}
+EXPORT_SYMBOL(plx9054_reg_readb);
+
+#ifdef ENABLE_PLX_DMA
+
+int
+isp1763_mem_read_dma(struct isp1763_dev *dev, u32 start_add,
+ u32 end_add, u32 * buffer, u32 length, u16 dir)
+{
+ u8 *pDMABuffer = 0;
+ u32 uPhyAddress = 0;
+ u32 ulDmaCmdStatus, fDone = 0;
+
+
+ /* Set start memory location for write*/
+ isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
+ udelay(1);
+
+ /* Malloc DMA safe buffer and convert to PHY Address*/
+ pDMABuffer = g_pDMA_Read_Buf;
+
+ if (pDMABuffer == NULL) {
+ printk("Cannnot allocate DMA safe memory for DMA read\n");
+ return -1;
+ }
+ uPhyAddress = virt_to_phys(pDMABuffer);
+
+ /* Program DMA transfer*/
+
+ /*DMA CHANNEL 1 PCI ADDRESS */
+ plx9054_reg_write(0x98, uPhyAddress);
+
+ /*DMA CHANNEL 1 LOCAL ADDRESS */
+ plx9054_reg_write(0x9C, 0x40);
+
+ /*DMA CHANNEL 1 TRANSFER SIZE */
+ plx9054_reg_write(0xA0, length);
+
+ /*DMA CHANNEL 1 DESCRIPTOR POINTER */
+ plx9054_reg_write(0xA4, 0x08);
+
+ /*DMA THRESHOLD */
+ plx9054_reg_write(0xB0, 0x77220000);
+
+ /*DMA CHANNEL 1 COMMAND STATUS */
+ plx9054_reg_writeb(0xA9, 0x03);
+
+
+ do {
+ ulDmaCmdStatus = plx9054_reg_read(0xA8);
+
+ if ((ulDmaCmdStatus & 0x00001000)) {
+ ulDmaCmdStatus |= 0x00000800;
+ plx9054_reg_write(0xA8, ulDmaCmdStatus);
+ fDone = 1;
+ } else {
+
+ fDone = 0;
+ }
+ } while (fDone == 0);
+
+ /* Copy DMA buffer to upper layer buffer*/
+ memcpy(buffer, pDMABuffer, length);
+
+
+ return 0;
+}
+
+int
+isp1763_mem_write_dma(struct isp1763_dev *dev,
+ u32 start_add, u32 end_add, u32 * buffer, u32 length, u16 dir)
+{
+ u8 *pDMABuffer = 0;
+ u8 bDmaCmdStatus = 0;
+ u32 uPhyAddress;
+ u32 ulDmaCmdStatus,fDone = 0;
+
+ isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
+ udelay(1);
+
+ /* Malloc DMA safe buffer and convert to PHY Address*/
+ pDMABuffer = g_pDMA_Write_Buf;
+
+ if (pDMABuffer == NULL) {
+ printk("Cannnot allocate DMA safe memory for DMA write\n");
+ return -1;
+ }
+ /* Copy content to DMA safe buffer*/
+ memcpy(pDMABuffer, buffer, length);
+ uPhyAddress = virt_to_phys(pDMABuffer);
+
+
+ /*DMA CHANNEL 1 PCI ADDRESS */
+ plx9054_reg_write(0x98, uPhyAddress);
+
+ /*DMA CHANNEL 1 LOCAL ADDRESS */
+ plx9054_reg_write(0x9C, 0x40);
+
+ /*DMA CHANNEL 1 TRANSFER SIZE */
+ plx9054_reg_write(0xA0, length);
+
+ /*DMA CHANNEL 1 DESCRIPTOR POINTER */
+ plx9054_reg_write(0xA4, 0x00);
+
+ /*DMA THRESHOLD */
+ plx9054_reg_write(0xB0, 0x77220000);
+
+ /*DMA CHANNEL 1 COMMAND STATUS */
+ bDmaCmdStatus = plx9054_reg_readb(0xA9);
+ bDmaCmdStatus |= 0x03;
+ plx9054_reg_writeb(0xA9, bDmaCmdStatus);
+
+
+ do {
+ ulDmaCmdStatus = plx9054_reg_read(0xA8);
+
+ if ((ulDmaCmdStatus & 0x00001000)){
+ ulDmaCmdStatus |= 0x00000800;
+ plx9054_reg_write(0xA8, ulDmaCmdStatus);
+ fDone = 1;
+ } else {
+ fDone = 0;
+ }
+ } while (fDone == 0);
+
+ return 0;
+}
+
+#endif
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_mem_read
+ *
+ * Memory read using PIO method.
+ *
+ * Input: struct isp1763_driver *drv --> Driver structure.
+ * u32 start_add --> Starting address of memory
+ * u32 end_add ---> End address
+ *
+ * u32 * buffer --> Buffer pointer.
+ * u32 length ---> Length
+ * u16 dir ---> Direction ( Inc or Dec)
+ *
+ * Output int Length ----> Number of bytes read
+ *
+ * Called by: system function
+ *
+ *
+ *--------------------------------------------------------------*/
+/* Memory read function PIO */
+
+int
+isp1763_mem_read(struct isp1763_dev *dev, u32 start_add,
+ u32 end_add, u32 * buffer, u32 length, u16 dir)
+{
+ u8 *temp_base_mem = 0;
+#ifdef ENABLE_PLX_DMA
+#else
+ u8 *one = (u8 *) buffer;
+ u16 *two = (u16 *) buffer;
+ u32 w;
+ u32 w2;
+// u8 bvalue;
+// u16 wvalue;
+#endif
+ u32 a = (u32) length;
+
+
+#ifdef NON_PCI // not sure why
+ temp_base_mem= (u8 *)(dev->baseaddress + start_add);
+#else /*PCI*/
+ temp_base_mem = (dev->baseaddress + (start_add));
+#endif
+
+ if (buffer == 0) {
+ printk("Buffer address zero\n");
+ return 0;
+ }
+#ifdef ENABLE_PLX_DMA
+
+ isp1763_mem_read_dma(dev, start_add, end_add, buffer, length, dir);
+ a = 0;
+
+#else
+ isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
+
+ last:
+ w = isp1763_reg_read16(dev, HC_DATA_REG, w);
+ w2 = isp1763_reg_read16(dev, HC_DATA_REG, w);
+ w2 <<= 16;
+ w = w | w2;
+ if (a == 1) {
+ *one = (u8) w;
+ return 0;
+ }
+ if (a == 2) {
+ *two = (u16) w;
+ return 0;
+ }
+
+ if (a == 3) {
+ *two = (u16) w;
+ two += 1;
+ w >>= 16;
+ *two = (u8) (w);
+ return 0;
+
+ }
+ while (a > 0) {
+ *buffer = w;
+ a -= 4;
+ if (a <= 0)
+ break;
+ if (a < 4) {
+ buffer += 1;
+ one = (u8 *) buffer;
+ two = (u16 *) buffer;
+ goto last;
+ }
+ buffer += 1;
+ w = isp1763_reg_read16(dev, HC_DATA_REG, w);
+ w2 = isp1763_reg_read16(dev, HC_DATA_REG, w);
+ w2 <<= 16;
+ w = w | w2;
+ }
+#endif
+ return ((a < 0) || (a == 0)) ? 0 : (-1);
+
+}
+EXPORT_SYMBOL(isp1763_mem_read);
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_mem_write
+ *
+ * Memory write using PIO method.
+ *
+ * Input: struct isp1763_driver *drv --> Driver structure.
+ * u32 start_add --> Starting address of memory
+ * u32 end_add ---> End address
+ *
+ * u32 * buffer --> Buffer pointer.
+ * u32 length ---> Length
+ * u16 dir ---> Direction ( Inc or Dec)
+ *
+ * Output int Length ----> Number of bytes read
+ *
+ * Called by: system function
+ *
+ *
+ *--------------------------------------------------------------*/
+
+/* Memory read function IO */
+int
+isp1763_mem_write(struct isp1763_dev *dev,
+ u32 start_add, u32 end_add,
+ u32 * buffer, u32 length, u16 dir)
+{
+#ifdef ENABLE_PLX_DMA
+#else
+ u8 *temp_base_mem = 0;
+// u8 *temp = (u8 *) buffer;
+ u8 one = (u8) (*buffer);
+ u16 two = (u16) (*buffer);
+#endif
+ int a = length;
+
+#ifdef ENABLE_PLX_DMA
+
+ isp1763_mem_write_dma(dev, start_add, end_add, buffer, length, dir);
+ a = 0;
+
+#else
+ isp1763_reg_write16(dev, HC_MEM_READ_REG, start_add);
+
+#ifdef NON_PCI
+ temp_base_mem= (u8 *)(dev->baseaddress + start_add);
+#else /*PCI*/
+ temp_base_mem = (dev->baseaddress + (start_add));
+#endif
+
+ if (a == 1) {
+ isp1763_reg_write16(dev, HC_DATA_REG, one);
+ return 0;
+ }
+ if (a == 2) {
+ isp1763_reg_write16(dev, HC_DATA_REG, two);
+ return 0;
+ }
+
+ while (a > 0) {
+ isp1763_reg_write16(dev, HC_DATA_REG, (u16) (*buffer));
+ if (a >= 3)
+ isp1763_reg_write16(dev, HC_DATA_REG,
+ (u16) ((*buffer) >> 16));
+ temp_base_mem = temp_base_mem + 4;
+ start_add += 4;
+ a -= 4;
+ if (a <= 0)
+ break;
+ buffer += 1;
+
+ }
+#endif
+ return ((a < 0) || (a == 0)) ? 0 : (-1);
+
+}
+EXPORT_SYMBOL(isp1763_mem_write);
+
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_request_irq
+ *
+ * This function registers the ISR of driver with this driver.
+ * Since there is only one interrupt line, when the first driver
+ * is registerd, will call the system function request_irq. The PLX
+ * bridge needs enabling of interrupt in the interrupt control register to
+ * pass the local interrupts to the PCI (cpu).
+ * For later registrations will just update the variables. On ISR, this driver
+ * will look for registered handlers and calls the corresponding driver's
+ * ISR "handler" function with "isr_data" as parameter.
+ *
+ * Input: struct
+ * (void (*handler)(struct isp1763_dev *, void *)-->handler.
+ * isp1763_driver *drv --> Driver structure.
+ * Output result
+ * 0= complete
+ * 1= error.
+ *
+ * Called by: system function module_init
+ *
+ *
+ *--------------------------------------------------------------*/
+
+int
+isp1763_request_irq(void (*handler) (struct isp1763_dev *, void *),
+ struct isp1763_dev *dev, void *isr_data)
+{
+ int result = 0;
+#ifndef NON_PCI
+ u32 intcsr = 0;
+#endif
+
+ hal_entry("%s: Entered\n", __FUNCTION__);
+ hal_int("isp1763_request_irq: dev->index %x\n", dev->index);
+
+#ifdef NON_PCI
+
+ result= request_irq(dev->irq, isp1763_non_pci_isr,IRQF_SHARED, dev->name, isr_data);
+ hal_int(KERN_NOTICE "isp1763_request_irq result: %x for IRQ %i\n",result, dev->irq);
+#else /* PCI MODE */
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (dev->index == ISP1763_DC) {
+ result = request_irq(dev->irq, isp1763_pci_dc_isr,
+ SA_SHIRQ, dev->name, isr_data);
+ } else if (dev->index == ISP1763_HC) {
+ result = request_irq(dev->irq, isp1763_pci_isr,
+ SA_SHIRQ, dev->name, isr_data);
+ }
+#else
+ if (dev->index == ISP1763_DC) {
+ result = request_irq(dev->irq,
+ isp1763_pci_dc_isr,
+ IRQF_SHARED,
+ dev->name,
+ isr_data);
+ } else if (dev->index == ISP1763_HC) {
+ result = request_irq(dev->irq,
+ isp1763_pci_isr,
+ IRQF_SHARED,
+ dev->name,
+ isr_data);
+ }
+#endif
+
+#endif
+
+
+
+#ifdef NON_PCI
+#else /*PCI*/
+ /*CONFIGURE PCI/PLX interrupt */
+ intcsr = readl(iobase + 0x68);
+ intcsr |= 0x900;
+ writel(intcsr, iobase + 0x68);
+#endif
+
+
+
+ udelay(30);
+ /*Interrupt handler routine */
+ dev->handler = handler;
+ dev->isr_data = isr_data;
+ hal_int("isp1763_request_irq: dev->handler %s\n", dev->handler);
+ hal_int("isp1763_request_irq: dev->isr_data %x\n", dev->isr_data);
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ return result;
+} /* End of isp1763_request_irq */
+EXPORT_SYMBOL(isp1763_request_irq);
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_free_irq
+ *
+ * This function de-registers the ISR of driver with this driver.
+ * Since there is only one interrupt line, when the last driver
+ * is de-registerd, will call the system function free_irq. The PLX
+ * bridge needs disabling of interrupt in the interrupt control register to
+ * block the local interrupts to the PCI (cpu).
+ *
+ * Input: struct
+ * (void (*handler)(struct isp1763_dev *, void *)-->handler.
+ * isp1763_driver *drv --> Driver structure.
+ * Output result
+ * 0= complete
+ * 1= error.
+ *
+ * Called by: system function module_init
+ *
+ *
+ *--------------------------------------------------------------*/
+
+void
+isp1763_free_irq(struct isp1763_dev *dev, void *isr_data)
+{
+
+
+#ifdef NON_PCI
+ free_irq(dev->irq,isr_data);
+#else /*PCI*/
+ u32 intcsr;
+ hal_int(("isp1763_free_irq(dev=%p,isr_data=%p)\n", dev, isr_data));
+ free_irq(dev->irq, isr_data);
+ /*disable the plx/pci interrupt */
+ intcsr = readl(iobase + 0x68);
+ intcsr &= ~0x900;
+ writel(intcsr, iobase + 0x68);
+#endif
+
+
+} /* isp1763_free_irq */
+EXPORT_SYMBOL(isp1763_free_irq);
+
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_register_driver
+ *
+ * This function is used by top driver (OTG, HCD, DCD) to register
+ * their communication functions (probe, remove, suspend, resume) using
+ * the drv data structure.
+ * This function will call the probe function of the driver if the ISP1763
+ * corresponding to the driver is enabled
+ *
+ * Input: struct isp1763_driver *drv --> Driver structure.
+ * Output result
+ * 0= complete
+ * 1= error.
+ *
+ * Called by: system function module_init
+ *
+ *
+ *--------------------------------------------------------------*/
+
+int
+isp1763_register_driver(struct isp1763_driver *drv)
+{
+ struct isp1763_dev *dev;
+ int result;
+ isp1763_id *id;
+
+ hal_entry("%s: Entered\n", __FUNCTION__);
+ info("isp1763_register_driver(drv=%p) \n", drv);
+
+ if (!drv)
+ return -EINVAL;
+ dev = &isp1763_loc_dev[drv->index];
+ if (drv->index == ISP1763_DC) {
+ dev->id = drv->id;
+ result = drv->probe(dev, drv->id);
+ } else {
+ id = drv->id;
+ dev->id = drv->id;
+ if (dev->active)
+ result = drv->probe(dev, id);
+ else
+ result = -ENODEV;
+ }
+
+ if (result >= 0) {
+ dev->driver = drv;
+ }
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ return result;
+} /* End of isp1763_register_driver */
+EXPORT_SYMBOL(isp1763_register_driver);
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_unregister_driver
+ *
+ * This function is used by top driver (OTG, HCD, DCD) to de-register
+ * their communication functions (probe, remove, suspend, resume) using
+ * the drv data structure.
+ * This function will check whether the driver is registered or not and
+ * call the remove function of the driver if registered
+ *
+ * Input: struct isp1763_driver *drv --> Driver structure.
+ * Output result
+ * 0= complete
+ * 1= error.
+ *
+ * Called by: system function module_init
+ *
+ *
+ *--------------------------------------------------------------*/
+
+
+void
+isp1763_unregister_driver(struct isp1763_driver *drv)
+{
+ struct isp1763_dev *dev;
+ hal_entry("%s: Entered\n", __FUNCTION__);
+
+ info("isp1763_unregister_driver(drv=%p)\n", drv);
+ dev = &isp1763_loc_dev[drv->index];
+ if (dev->driver == drv) {
+ /* driver registered is same as the requestig driver */
+ drv->remove(dev);
+ dev->driver = NULL;
+ info(": De-registered Driver %s\n", drv->name);
+ return;
+ }
+ hal_entry("%s: Exit\n", __FUNCTION__);
+} /* End of isp1763_unregister_driver */
+EXPORT_SYMBOL(isp1763_unregister_driver);
+
+/*--------------------------------------------------------------*
+ * ISP1763 PCI driver interface routine.
+ *--------------------------------------------------------------*/
+
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_pci_module_init
+ *
+ * This is the module initialization function. It registers to
+ * PCI driver for a PLX PCI bridge device. And also resets the
+ * internal data structures before registering to PCI driver.
+ *
+ * Input: void
+ * Output result
+ * 0= complete
+ * 1= error.
+ *
+ * Called by: system function module_init
+ *
+ *
+ *
+ -------------------------------------------------------------------*/
+#ifdef NON_PCI
+static int __init
+ isp1763_module_init (void)
+#else /*PCI*/
+static int __init
+isp1763_pci_module_init(void)
+#endif
+{
+ int result = 0;
+ hal_entry("%s: Entered\n", __FUNCTION__);
+#ifdef NON_PCI
+ hal_entry(KERN_NOTICE "+isp1763_module_init \n");
+#else
+ hal_entry(KERN_NOTICE "+isp1763_pci_module_init \n");
+#endif
+ memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev));
+
+#ifdef NON_PCI
+if((result = platform_device_register(&isp1763_device)) == 0) {
+
+ hal_init(KERN_NOTICE "platform_device_register() success: result :0x%08x\n", result); // jimmy
+
+ if((result = driver_register(&isp1763_driver)) < 0) {
+ platform_device_unregister(&isp1763_device);
+ hal_init(KERN_NOTICE "driver_register() fail: result :0x%08x\n", result); // jimmy
+ return result;
+ } else {
+ hal_init(KERN_NOTICE "driver_register() success: result :0x%08x\n", result); // jimmy
+ }
+} else { // platform_device_register failed!
+ hal_init(KERN_NOTICE "platform_device_register() fail: result :0x%08x\n", result); // jimmy
+ return result;
+}
+
+ hal_init(KERN_NOTICE "-isp1763_module_init \n");
+
+#else /*PCI*/
+ if ((result = pci_register_driver(&isp1763_pci_driver)) < 0) {
+ hal_init("PCI Iinitialization Fail(error = %d)\n", result);
+ return result;
+ } else
+ hal_init(": %s PCI Initialization Success \n", ISP1763_DRIVER_NAME);
+#endif
+
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ return result;
+}
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_pci_module_cleanup
+ *
+ * This is the module cleanup function. It de-registers from
+ * PCI driver and resets the internal data structures.
+ *
+ * Input: void
+ * Output void
+ *
+ * Called by: system function module_cleanup
+ *
+ *
+ *
+ --------------------------------------------------------------*/
+
+#ifdef NON_PCI
+static void __exit isp1763_module_cleanup (void)
+{
+ hal_init("Hal Module Cleanup\n");
+ driver_unregister(&isp1763_driver);
+ platform_device_unregister(&isp1763_device);
+ memset(isp1763_loc_dev,0,sizeof(isp1763_loc_dev));
+}
+#else /*PCI*/
+static void __exit
+isp1763_pci_module_cleanup(void)
+{
+ hal_init("Hal Module Cleanup\n");
+ pci_unregister_driver(&isp1763_pci_driver);
+ memset(isp1763_loc_dev, 0, sizeof(isp1763_loc_dev));
+}
+#endif
+
+
+#ifdef MEMORY_TEST
+static void
+Ph1763MemoryTest(struct isp1763_dev *loc_dev, u32 ulMemBaseAddr, u32 ulMemLen)
+{
+ u32 dwNumDwords;
+ u16 wValue;
+ u16 wlRegData;
+ u16 wTestCnt;
+ u16 wlTestData;
+
+ dwNumDwords = 0;
+ wlRegData = 0;
+
+ if (ulMemLen % 4) {
+ dwNumDwords = (ulMemLen / 4) + 1;
+ } else {
+ dwNumDwords = (ulMemLen / 4);
+ }
+
+ hal_init(KERN_NOTICE "Base Addr %x and MemLen %x\n", ulMemBaseAddr,
+ ulMemLen);
+
+ isp1763_reg_write16(loc_dev, HC_MEM_READ_REG, ulMemBaseAddr);
+
+ wTestCnt = 0;
+ wlTestData = 0x0;
+ for (wlRegData = 0; wlRegData < dwNumDwords * 2; wlRegData++) {
+ isp1763_reg_write16(loc_dev, HC_DATA_REG, wlTestData);
+ wTestCnt += 2;
+ wlTestData++;
+ }
+
+ isp1763_reg_write16(loc_dev, HC_MEM_READ_REG, ulMemBaseAddr);
+ wTestCnt = 0;
+ wlTestData = 0;
+ for (wlRegData = 0; wlRegData < dwNumDwords * 2; wlRegData++) {
+ wValue = isp1763_reg_read16(loc_dev, HC_DATA_REG, wValue);
+ if (wlTestData != wValue) {
+ if (ulMemBaseAddr == 0xC00) {
+ printk(KERN_NOTICE
+ "ATLTD Init Error at address 0x%x:Expected value is0x%x:Current Value %x\n",
+ (ulMemBaseAddr + wTestCnt), wlTestData,
+ wValue);
+ } else if (ulMemBaseAddr == 0x400) {
+ printk(KERN_NOTICE
+ "INTLTD Init Error at address 0x%x:Expected value is0x%x:Current Value %x\n",
+ (ulMemBaseAddr + wTestCnt), wlTestData,
+ wValue);
+ } else if (ulMemBaseAddr == 0x800) {
+ printk(KERN_NOTICE
+ "ISOTD Init Error at address 0x%x:Expected value is0x%x:Current Value %x\n",
+ (ulMemBaseAddr + wTestCnt), wlTestData,
+ wValue);
+ } else {
+ printk(KERN_NOTICE
+ "Payload Init Error at address 0x%x:Expected value is0x%x:Current Value %x\n",
+ (ulMemBaseAddr + wTestCnt), wlTestData,
+ wValue);
+ }
+
+ }
+ wTestCnt += 2;
+ wlTestData++;
+ }
+
+
+}
+#endif
+
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_pci_probe
+ *
+ * PCI probe function of ISP1763
+ * This function is called from PCI Driver as an initialization function
+ * when it founds the PCI device. This functions initializes the information
+ * for the 3 Controllers with the assigned resources and tests the register
+ * access to these controllers and do a software reset and makes them ready
+ * for the drivers to play with them.
+ *
+ * Input:
+ * struct pci_dev *dev ----> PCI Devie data structure
+ * const struct pci_device_id *id ----> PCI Device ID
+ * Output void
+ *
+ * Called by: system function module_cleanup
+ *
+ *
+ *
+ --------------------------------------------------------------**/
+#ifdef NON_PCI
+static int __devinit isp1763_probe (struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct isp1763_dev *loc_dev;
+ void *address = 0;
+ int status = 1;
+ unsigned long word32 = 0;
+#ifndef NON_PCI
+ unsigned long base_addr;
+#endif
+ unsigned long temp, i;
+
+ /* Get the Host Controller IO and INT resources
+ */
+ loc_dev = &(isp1763_loc_dev[ISP1763_HC]);
+
+ if (loc_dev != NULL)
+ hal_init("loc_dev: 0x%08x\n", loc_dev);
+ else
+ hal_init("loc_dev is NULL");
+
+ if (pdev != NULL)
+ {
+ hal_init("pdev->resource[0].start 0x%x\n", pdev->resource[0].start);
+ hal_init("pdev->resource[0].end 0x%x\n", pdev->resource[0].end);
+ hal_init("Range: 0x%x\n", (pdev->resource[0].end - pdev->resource[0].start -1));
+ }
+ else
+ hal_init("pdev is NULL");
+
+ loc_dev->irq = platform_get_irq(pdev, 0);
+ if (loc_dev != NULL)
+ hal_init("loc_dev->irq: 0x%x\n", loc_dev->irq);
+ else
+ hal_init("loc_dev is NULL");
+
+ loc_dev->io_base = pdev->resource[0].start;
+ loc_dev->start = pdev->resource[0].start;
+ loc_dev->length = (pdev->resource[0].end - pdev->resource[0].start -1);
+ loc_dev->io_len = (pdev->resource[0].end - pdev->resource[0].start -1); /*64K*/
+ loc_dev->index = ISP1763_HC;/*zero*/
+
+ loc_dev->io_len = ISP176x_MEM_RANGE;
+ if(check_mem_region(loc_dev->io_base, loc_dev->length) < 0) {
+ hal_init("host controller already in use\n");
+ return -EBUSY;
+ }
+ if(!request_mem_region(loc_dev->io_base, loc_dev->length, isp1763_driver_name)){
+ hal_init("host controller already in use\n");
+ return -EBUSY;
+ }
+
+ /*map available memory*/
+// address = IO_ADDRESS(loc_dev->io_base); // jimmy
+ address = ioremap(loc_dev->start, loc_dev->length);
+
+ if(address == NULL){
+ err("memory map problem\n");
+ release_mem_region(loc_dev->io_base, loc_dev->length);
+ return -ENOMEM;
+ }
+ if (loc_dev != NULL)
+ hal_init("Base: 0x%x with Range: 0x%x remapped to 0x%x\n", loc_dev->io_base, loc_dev->length, address);
+ else
+ hal_init("loc_dev is NULL");
+
+ loc_dev->baseaddress = (u8*)address;
+ loc_dev->dmabase = (u8*) 0;
+
+ if (loc_dev != NULL)
+ hal_init("isp1763 HC MEM Base= %p irq = %d\n",
+ loc_dev->baseaddress,loc_dev->irq);
+ else
+ hal_init("loc_dev is NULL");
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+ loc_dev = &(isp1763_loc_dev[ISP1763_HC]);
+
+
+
+ hal_init("Initiating Scratch register test\n");
+
+
+ for(i = 0, word32 = 1; i < 16; i ++)
+ {
+ word32 = (1 << i);
+ isp1763_reg_write16(loc_dev, HC_SCRATCH_REG, (__u16)word32);
+// isp1763_reg_write32(loc_dev, HC_SCRATCH_REG, (__u16)word32);
+ udelay(1);
+
+ temp = 0;
+ temp = isp1763_reg_read32(loc_dev, DC_CHIPID, temp);
+ udelay(1);
+
+ hal_init("Chip ID is 0x%08x\n", temp);
+
+ if (temp != 0x176320) //For ES2
+ {
+ hal_init("Index%d: Chip ID mismatch after writing 0x%04x read=0x%08x\n", i, (__u16)word32, temp);
+ }
+ else
+ hal_init("Index%d: Chip ID is 0x%08x\n", i, temp);
+
+ temp = 0;
+ temp = isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, (__u16)temp);
+// temp = isp1763_reg_read32(loc_dev, HC_SCRATCH_REG, (__u16)temp);
+ udelay(1);
+
+ if(temp != word32)
+ {
+ hal_init("ERROR ====> Writing 0x%08x to Scrath Reg failed! read=0x%08x\n", word32, temp);
+ }
+ }
+
+ hal_init("Scratch test completed...have a nice day!\n");
+
+ memcpy(loc_dev->name, isp1763_driver_name, sizeof(isp1763_driver_name));
+ loc_dev->name[sizeof(isp1763_driver_name)] = 0;
+ loc_dev->active = 1;
+
+ loc_dev->dev = pdev;
+
+// hal_data.irq_usage = 0;
+ dev_set_drvdata(dev, loc_dev);
+ hal_init("Exiting HAL initialization....SUCCESS!!!\n");
+
+ hal_entry("%s: Exit\n",__FUNCTION__);
+ return 0;
+
+clean://check why?
+// release_mem_region(loc_dev->io_base, loc_dev->io_len);
+ iounmap(loc_dev->baseaddress);
+ hal_entry("%s: Exit\n",__FUNCTION__);
+ return status;
+} /* End of isp1763_probe */
+
+#else /*PCI*/
+
+static int __devinit
+isp1763_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u8 latency, limit;
+ u32 reg_data = 0;
+ int retry_count;
+ struct isp1763_dev *loc_dev;
+ void *address = 0;
+ int length = 0;
+ int status = 1;
+ u32 ul_busregion_descr = 0;
+ u32 hwmodectrl = 0, chipid=0;
+ u16 us_fpga_conf=0;
+#ifdef ENABLE_PLX_DMA
+ u32 ulDmaModeCh1;
+#endif
+ u32 temp = 0;
+
+
+ hal_entry("%s: Entered\n", __FUNCTION__);
+
+ hal_init(("isp1763_pci_probe(dev=%p)\n", dev));
+ hal_init(KERN_NOTICE "+isp1763_pci_probe \n");
+ if (pci_enable_device(dev) < 0) {
+ err("failed in enabing the device\n");
+ return -ENODEV;
+ }
+ if (!dev->irq) {
+ err("found ISP1763 device with no IRQ assigned.");
+ err("check BIOS settings!");
+ return -ENODEV;
+ }
+ /* Grab the PLX PCI mem maped port start address we need */
+ pci_io_base = pci_resource_start(dev, 0);
+ hal_init(("isp1763 pci IO Base= %x\n", pci_io_base));;
+
+ iolength = pci_resource_len(dev, 0);
+ hal_init(KERN_NOTICE "isp1763 pci io length %x\n", iolength);
+ hal_init(("isp1763 pci io length %d\n", iolength));
+
+ if (!request_mem_region(pci_io_base, iolength, "ISP1763 IO MEM")) {
+ err("host controller already in use1\n");
+ return -EBUSY;
+ }
+ iobase = ioremap_nocache(pci_io_base, iolength);
+ if (!iobase) {
+ err("can not map io memory to system memory\n");
+ release_mem_region(pci_io_base, iolength);
+ return -ENOMEM;
+ }
+ /* Grab the PLX PCI shared memory of the ISP1763 we need */
+ pci_mem_phy0 = pci_resource_start(dev, 3);
+ hal_init(("isp1763 pci base address = %x\n", pci_mem_phy0));
+
+ /* Get the Host Controller IO and INT resources
+ */
+ loc_dev = &(isp1763_loc_dev[ISP1763_HC]);
+ loc_dev->irq = dev->irq;
+ loc_dev->io_base = pci_mem_phy0;
+ loc_dev->start = pci_mem_phy0;
+ loc_dev->length = pci_mem_len;
+ loc_dev->io_len = pci_mem_len; /*64K */
+ loc_dev->index = ISP1763_HC; /*zero */
+
+ length = pci_resource_len(dev, 3);
+ hal_init(KERN_NOTICE "isp1763 pci resource length %x\n", length);
+ if (length < pci_mem_len) {
+ err("memory length for this resource is less than required\n");
+ release_mem_region(pci_io_base, iolength);
+ iounmap(iobase);
+ return -ENOMEM;
+
+ }
+ loc_dev->io_len = length;
+ if (check_mem_region(loc_dev->io_base, length) < 0) {
+ err("host controller already in use\n");
+ release_mem_region(pci_io_base, iolength);
+ iounmap(iobase);
+ return -EBUSY;
+ }
+ if (!request_mem_region(loc_dev->io_base, length, ISP1763_DRIVER_NAME)) {
+ err("host controller already in use\n");
+ release_mem_region(pci_io_base, iolength);
+ iounmap(iobase);
+ return -EBUSY;
+
+ }
+
+ /*map available memory */
+ address = ioremap_nocache(pci_mem_phy0, length);
+ if (address == NULL) {
+ err("memory map problem\n");
+ release_mem_region(pci_io_base, iolength);
+ iounmap(iobase);
+ release_mem_region(loc_dev->io_base, length);
+ return -ENOMEM;
+ }
+
+ loc_dev->baseaddress = (u8 *) address;
+ loc_dev->dmabase = (u8 *) iobase;
+
+ hal_init(("isp1763 HC MEM Base= %p irq = %d\n",
+ loc_dev->baseaddress, loc_dev->irq));
+
+#ifdef DATABUS_WIDTH_16
+
+ ul_busregion_descr = readl(iobase + 0xF8);
+ hal_init(KERN_NOTICE "setting plx bus width to 16:BusRegionDesc %x \n",
+ ul_busregion_descr);
+ ul_busregion_descr &= 0xFFFFFFFC;
+ ul_busregion_descr |= 0x00000001;
+ writel(ul_busregion_descr, iobase + 0xF8);
+ ul_busregion_descr = readl(iobase + 0xF8);
+ hal_init(KERN_NOTICE "BusRegionDesc %x \n", ul_busregion_descr);
+
+#ifdef ENABLE_PLX_DMA
+
+ ulDmaModeCh1 = plx9054_reg_read(0x94);
+
+ /* Set as 16 bit mode */
+ ulDmaModeCh1 &= 0xFFFFFFFC;
+ ulDmaModeCh1 |= 0x00020401;
+
+ ulDmaModeCh1 |= 0x00000800; /*Holds local address bus constant*/
+
+ plx9054_reg_write(0x94, ulDmaModeCh1);
+
+
+#endif /*ENABLE_PLX_DMA*/
+
+#else
+
+ ul_busregion_descr = readl(iobase + 0xF8);
+ hal_init(KERN_NOTICE "setting plx bus width to 8:BusRegionDesc %x \n",
+ ul_busregion_descr);
+ ul_busregion_descr &= 0xFFFFFFFC;
+ writel(ul_busregion_descr, iobase + 0xF8);
+ hal_init(KERN_NOTICE "BusRegionDesc %x \n", ul_busregion_descr);
+
+#endif
+
+
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ hal_init("After setting plx, chip id:%x \n", chipid);
+
+
+#ifdef DATABUS_WIDTH_16
+
+ isp1763_reg_write16(loc_dev, FPGA_CONFIG_REG, 0xBf);
+ us_fpga_conf =
+ isp1763_reg_read16(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 1 %x \n", us_fpga_conf);
+ isp1763_reg_write16(loc_dev, FPGA_CONFIG_REG, 0x3f);
+ us_fpga_conf =
+ isp1763_reg_read16(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 2 %x \n", us_fpga_conf);
+ mdelay(5);
+ isp1763_reg_write16(loc_dev, FPGA_CONFIG_REG, 0xFf);
+ us_fpga_conf =
+ isp1763_reg_read16(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 3 %x \n", us_fpga_conf);
+
+#else
+
+ us_fpga_conf =
+ isp1763_reg_read8(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "INIT FPGA CONF REG 1 %x \n", us_fpga_conf);
+ isp1763_reg_write8(loc_dev, FPGA_CONFIG_REG, 0xB7);
+ us_fpga_conf =
+ isp1763_reg_read8(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 1 %x \n", us_fpga_conf);
+
+ isp1763_reg_write8(loc_dev, FPGA_CONFIG_REG, 0x37);
+ us_fpga_conf =
+ isp1763_reg_read8(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 2 %x \n", us_fpga_conf);
+ mdelay(5);
+
+ isp1763_reg_write8(loc_dev, FPGA_CONFIG_REG, 0xF7);
+ us_fpga_conf =
+ isp1763_reg_read8(loc_dev, FPGA_CONFIG_REG, us_fpga_conf);
+ hal_init(KERN_NOTICE "FPGA CONF REG 3 %x \n", us_fpga_conf);
+ mdelay(1);
+
+#endif
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ hal_init("After setting fpga, chip id:%x \n", chipid);
+
+
+
+
+#ifdef ISP1763_DEVICE
+
+ /*initialize device controller framework */
+ loc_dev = &(isp1763_loc_dev[ISP1763_DC]);
+ loc_dev->irq = dev->irq;
+ loc_dev->io_base = pci_mem_phy0;
+ loc_dev->start = pci_mem_phy0;
+ loc_dev->length = pci_mem_len;
+ loc_dev->io_len = pci_mem_len;
+ loc_dev->index = ISP1763_DC;
+ loc_dev->baseaddress = address;
+ loc_dev->active = 1;
+ memcpy(loc_dev->name, "isp1763_dev", 11);
+ loc_dev->name[12] = '\0';
+ {
+ /*reset the host controller */
+ temp |= 0x1;
+ isp1763_reg_write16(loc_dev, HC_RESET_REG, temp); //0xB8
+ mdelay(20);
+ temp = 0;
+ temp |= 0x2;
+ isp1763_reg_write16(loc_dev, HC_RESET_REG, temp);
+
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ hal_init("After hc reset, chip id:%x \n", chipid);
+ hwmodectrl =
+ isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
+ hal_init(KERN_NOTICE "Mode Ctrl Value : %x\n", hwmodectrl);
+#ifdef DATABUS_WIDTH_16
+ hwmodectrl &= 0xFFEF; /*enable the 16 bit bus */
+#else
+ hwmodectrl |= 0x0010; /*enable the 8 bit bus */
+#endif
+ isp1763_reg_write16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
+ hwmodectrl =
+ isp1763_reg_read16(loc_dev, HC_HWMODECTRL_REG, hwmodectrl);
+ hal_init(KERN_NOTICE "Mode Ctrl Value after buswidth: %x\n",
+ hwmodectrl);
+
+ }
+
+ {
+ u32 chipid = 0;
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ hal_init("After hwmode, chip id:%x \n", chipid);
+ info("pid %04x, vid %04x\n", (chipid & 0xffff), (chipid >> 16));
+ }
+ hal_init(("isp1763 DC MEM Base= %lx irq = %d\n",
+ loc_dev->io_base, loc_dev->irq));
+ /* Get the OTG Controller IO and INT resources
+ * OTG controller resources are same as Host Controller resources
+ */
+ loc_dev = &(isp1763_loc_dev[ISP1763_OTG]);
+ loc_dev->irq = dev->irq; /*same irq also */
+ loc_dev->io_base = pci_mem_phy0;
+ loc_dev->start = pci_mem_phy0;
+ loc_dev->length = pci_mem_len;
+ loc_dev->io_len = pci_mem_len;
+ loc_dev->index = ISP1763_OTG;
+ loc_dev->baseaddress = address; /*having the same address as of host */
+ loc_dev->active = 1;
+ memcpy(loc_dev->name, "isp1763_otg", 11);
+ loc_dev->name[12] = '\0';
+
+ hal_init(("isp1763 OTG MEM Base= %lx irq = %x\n",
+ loc_dev->io_base, loc_dev->irq));
+
+#endif
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency) {
+ dbg("PCI latency reduced to max %d", limit);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+ isp1763_pci_latency = limit;
+ } else {
+ /* it might already have been reduced */
+ isp1763_pci_latency = latency;
+ }
+ }
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+
+ loc_dev = &(isp1763_loc_dev[ISP1763_HC]);
+ retry_count = PCI_ACCESS_RETRY_COUNT;
+ reg_data = 0;
+
+// while (reg_data < 0xFFFF)
+ {
+ u16 ureadVal = 0;
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+ isp1763_reg_write16(loc_dev, HC_SCRATCH_REG, reg_data);
+
+ udelay(1);
+ {
+ u32 chipid = 0;
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ if (chipid != ISP1763_CHIPID) {
+ printk(KERN_NOTICE
+ "CHIP ID WRONG: 0x%X at No. %d\n",
+ chipid, reg_data);
+ }
+ }
+ udelay(1);
+ ureadVal =
+ isp1763_reg_read16(loc_dev, HC_SCRATCH_REG, ureadVal);
+ if (reg_data != ureadVal) {
+ printk(KERN_NOTICE
+ "MisMatch Scratch Value %x ActVal %x\n",
+ ureadVal, reg_data);
+ }
+
+ reg_data++;
+
+ }
+
+ chipid = isp1763_reg_read32(loc_dev, DC_CHIPID, chipid);
+ hal_init(KERN_NOTICE "isp1763_pci_probe:read chipid: 0x%X \n", chipid);
+
+ memcpy(loc_dev->name, ISP1763_DRIVER_NAME, sizeof(ISP1763_DRIVER_NAME));
+ loc_dev->name[sizeof(ISP1763_DRIVER_NAME)] = 0;
+ loc_dev->active = 1;
+
+ info("controller address %p\n", &dev->dev);
+ /*keep a copy of pcidevice */
+ loc_dev->pcidev = dev;
+
+ pci_set_master(dev);
+ pci_set_drvdata(dev, loc_dev);
+ hal_init(KERN_NOTICE "-isp1763_pci_probe \n");
+ hal_entry("%s: Exit\n", __FUNCTION__);
+ /* PLX DMA Test */
+#ifdef ENABLE_PLX_DMA
+
+ g_pDMA_Read_Buf = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+ g_pDMA_Write_Buf = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
+
+ if (g_pDMA_Read_Buf == NULL || g_pDMA_Write_Buf == NULL) {
+ printk("Cannot allocate memory for DMA operations!\n");
+ return -2;
+ }
+#endif
+ return 1;
+
+
+ release_mem_region(pci_io_base, iolength);
+ iounmap(iobase);
+ release_mem_region(loc_dev->io_base, loc_dev->io_len);
+ iounmap(loc_dev->baseaddress);
+ hal_entry("%s: Exit\n", __FUNCTION__);
+
+ return status;
+} /* End of isp1763_pci_probe */
+#endif
+
+
+/*--------------------------------------------------------------*
+ *
+ * Module details: isp1763_pci_remove
+ *
+ * PCI cleanup function of ISP1763
+ * This function is called from PCI Driver as an removal function
+ * in the absence of PCI device or a de-registration of driver.
+ * This functions checks the registerd drivers (HCD, DCD, OTG) and calls
+ * the corresponding removal functions. Also initializes the local variables
+ * to zero.
+ *
+ * Input:
+ * struct pci_dev *dev ----> PCI Devie data structure
+ *
+ * Output void
+ *
+ * Called by: system function module_cleanup
+ *
+ *
+ *
+ --------------------------------------------------------------*/
+#ifdef NON_PCI
+static void __devexit isp1763_remove (struct device *dev)
+{
+ struct isp1763_dev *loc_dev;
+
+ if (dev != NULL)
+ hal_init(("isp1763_pci_remove(dev=%p)\n",dev));
+ else
+ hal_init("dev is NULL\n");
+
+ /*Lets handle the host first*/
+ loc_dev = &isp1763_loc_dev[ISP1763_HC];
+
+ /*free the memory occupied by host*/
+ release_mem_region(loc_dev->io_base, loc_dev->io_len);
+
+ /*unmap the occupied memory resources*/
+// iounmap(loc_dev->baseaddress); // jimmy
+
+ return;
+} /* End of isp1763_remove */
+#else /*PCI*/
+static void __devexit
+isp1763_pci_remove(struct pci_dev *dev)
+{
+ struct isp1763_dev *loc_dev;
+ hal_init(("isp1763_pci_remove(dev=%p)\n", dev));
+#ifdef ENABLE_PLX_DMA
+ if (g_pDMA_Read_Buf != NULL){
+ kfree(g_pDMA_Read_Buf);
+ }
+ if (g_pDMA_Write_Buf != NULL){
+ kfree(g_pDMA_Write_Buf);
+ }
+#endif
+ /*Lets handle the host first */
+ loc_dev = &isp1763_loc_dev[ISP1763_HC];
+ /*free the memory occupied by host */
+ release_mem_region(loc_dev->io_base, loc_dev->io_len);
+ release_mem_region(pci_io_base, iolength);
+ /*unmap the occupied memory resources */
+ iounmap(loc_dev->baseaddress);
+ /* unmap the occupied io resources */
+ iounmap(iobase);
+ return;
+} /* End of isp1763_pci_remove */
+#endif
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+
+#ifdef NON_PCI
+module_init (isp1763_module_init);
+module_exit (isp1763_module_cleanup);
+#else /*PCI*/
+module_init(isp1763_pci_module_init);
+module_exit(isp1763_pci_module_cleanup);
+#endif
diff --git a/drivers/usb/host/isp1763-hal.h b/drivers/usb/host/isp1763-hal.h
new file mode 100644
index 00000000000..c1847ca464f
--- /dev/null
+++ b/drivers/usb/host/isp1763-hal.h
@@ -0,0 +1,85 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : hal
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a hardware abstraction layer header file.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#ifndef HAL_X86_H
+#define HAL_X86_H
+
+#define DRIVER_AUTHOR "ST-ERICSSON "
+#define DRIVER_DESC "ISP1763 bus driver"
+
+/* Driver tuning, per ST-ERICSSON requirements: */
+
+#define MEM_TO_CHECK 4096 /*bytes, must be multiple of 2 */
+
+/* BIT defines */
+#define BIT0 (1 << 0)
+#define BIT1 (1 << 1)
+#define BIT2 (1 << 2)
+#define BIT3 (1 << 3)
+#define BIT4 (1 << 4)
+#define BIT5 (1 << 5)
+#define BIT6 (1 << 6)
+#define BIT7 (1 << 7)
+#define BIT8 (1 << 8)
+#define BIT9 (1 << 9)
+#define BIT10 (1 << 10)
+#define BIT11 (1 << 11)
+#define BIT12 (1 << 12)
+#define BIT13 (1 << 13)
+#define BIT14 (1 << 14)
+#define BIT15 (1 << 15)
+#define BIT16 (1 << 16)
+#define BIT17 (1 << 17)
+#define BIT18 (1 << 18)
+#define BIT19 (1 << 19)
+#define BIT20 (1 << 20)
+#define BIT21 (1 << 21)
+#define BIT22 (1 << 22)
+#define BIT23 (1 << 23)
+#define BIT24 (1 << 24)
+#define BIT25 (1 << 26)
+#define BIT27 (1 << 27)
+#define BIT28 (1 << 28)
+#define BIT29 (1 << 29)
+#define BIT30 (1 << 30)
+#define BIT31 (1 << 31)
+
+/* Definitions Related to Chip Address and CPU Physical Address
+ * cpu_phy_add: CPU Physical Address , it uses 32 bit data per address
+ * chip_add : Chip Address, it uses double word(64) bit data per address
+ */
+#define chip_add(cpu_phy_add) (((cpu_phy_add) - 0x400) / 8)
+#define cpu_phy_add(chip_add) ((8 * (chip_add)) + 0x400)
+
+/* for getting end add, and start add, provided we have one address with us */
+/* IMPORTANT length hex(base16) and dec(base10) works fine*/
+#define end_add(start_add, length) (start_add + (length - 4))
+#define start_add(end_add, length) (end_add - (length - 4))
+
+/* Device Registers*/
+#define DEV_UNLOCK_REGISTER 0x7C
+#define DEV_INTERRUPT_REGISTER 0x18
+#define INT_ENABLE_REGISTER 0x14
+
+#endif /*_HAL_X86_H_ */
diff --git a/drivers/usb/host/isp1763-hcd.c b/drivers/usb/host/isp1763-hcd.c
new file mode 100644
index 00000000000..91fde67132a
--- /dev/null
+++ b/drivers/usb/host/isp1763-hcd.c
@@ -0,0 +1,6534 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Refer to the follwing files in ~/drivers/usb/host for copyright owners:
+* ehci-dbg.c, ehci-hcd.c, ehci-hub.c, ehci-mem.c, ehci-q.c and ehic-sched.c (kernel version 2.6.9)
+* Code is modified for ST-Ericsson product
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+//#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <stdarg.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <linux/version.h>
+
+#include "isp1763.h"
+#include "isp1763-hcd.h"
+#include "isp1763-hal-interface.h"
+
+extern int No_Data_Phase;
+extern int No_Status_Phase;
+#define EHCI_TUNE_CERR 3
+#define URB_NO_INTERRUPT 0x0080
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_RL_HS 0
+#define EHCI_TUNE_MULT_HS 1
+
+
+#define POWER_DOWN_CTRL_NORMAL_VALUE 0xffff1ba0
+#define POWER_DOWN_CTRL_SUSPEND_VALUE 0xffff08b0
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
+//This macro is not supported in linux-2.6.35
+#define USB_PORT_FEAT_HIGHSPEED 10
+#endif
+
+#ifdef CONFIG_ISO_SUPPORT
+
+#define FALSE 0
+#define TRUE (!FALSE)
+extern void *phcd_iso_sitd_to_ptd(phci_hcd * hcd,
+ struct ehci_sitd *sitd,
+ struct urb *urb, void *ptd);
+extern void *phcd_iso_itd_to_ptd(phci_hcd * hcd,
+ struct ehci_itd *itd,
+ struct urb *urb, void *ptd);
+
+extern unsigned long phcd_submit_iso(phci_hcd * hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+#else
+#endif
+ struct urb *urb, unsigned long *status);
+void pehci_hcd_iso_schedule(phci_hcd * hcd, struct urb *);
+unsigned long lgFrameIndex = 0;
+unsigned long lgScheduledPTDIndex = 0;
+int igNumOfPkts = 0;
+#endif /* CONFIG_ISO_SUPPORT */
+
+struct isp1763_dev *isp1763_hcd;
+
+#ifdef HCD_PACKAGE
+/*file operation*/
+struct fasync_struct *fasync_q;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static void
+pehci_hcd_urb_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map, struct pt_regs *regs);
+#else
+static void
+pehci_hcd_urb_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map);
+#endif
+
+#include "isp1763-otg.c" /*OTG and HCD package needs it */
+
+
+int hcdpowerdown = 0;
+int portchange=0; //for remotewakeup
+EXPORT_SYMBOL(hcdpowerdown);
+unsigned char otg_se0_enable;
+EXPORT_SYMBOL(otg_se0_enable);
+
+
+/*Enable all other interrupt.*/
+
+#ifdef MSEC_INT_BASED
+#ifdef THREAD_BASED//This is to test interrupt mapping problem
+//#define INTR_ENABLE_MASK (HC_OPR_REG_INT|HC_CLK_RDY_INT )
+#define INTR_ENABLE_MASK (/*HC_MSEC_INT |*/ HC_INTL_INT | HC_ATL_INT| HC_ISO_INT /*| HC_EOT_INT | HC_ISO_INT*/)
+#else
+#define INTR_ENABLE_MASK (HC_MSEC_INT|HC_OPR_REG_INT|HC_CLK_RDY_INT )
+#endif
+#else
+#define INTR_ENABLE_MASK ( HC_INTL_INT | HC_ATL_INT |HC_ISO_INT| HC_EOT_INT|HC_OPR_REG_INT|HC_CLK_RDY_INT)
+#endif
+
+
+
+#ifdef THREAD_BASED
+
+#define NO_SOF_REQ_IN_TSK 0x1
+#define NO_SOF_REQ_IN_ISR 0x2
+#define NO_SOF_REQ_IN_REQ 0x3
+#define MSEC_INTERVAL_CHECKING 5
+
+typedef struct _st_UsbIt_Msg_Struc {
+ struct usb_hcd *usb_hcd;
+ u8 uIntStatus;
+ struct list_head list;
+} st_UsbIt_Msg_Struc, *pst_UsbIt_Msg_Struc ;
+
+typedef struct _st_UsbIt_Thread {
+ wait_queue_head_t ulThrdWaitQhead;
+ int lThrdWakeUpNeeded;
+ struct task_struct *phThreadTask;
+ spinlock_t lock;
+} st_UsbIt_Thread, *pst_UsbIt_Thread;
+
+st_UsbIt_Thread g_stUsbItThreadHandler;
+
+st_UsbIt_Msg_Struc g_messList;
+st_UsbIt_Msg_Struc g_enqueueMessList;
+spinlock_t enqueue_lock;
+
+int pehci_hcd_process_irq_it_handle(struct usb_hcd* usb_hcd_);
+int pehci_hcd_process_irq_in_thread(struct usb_hcd *usb_hcd_);
+
+#endif /*THREAD_BASED*/
+
+#ifdef THREAD_BASED
+phci_hcd *g_pehci_hcd;
+#endif
+
+
+
+/*---------------------------------------------------
+ * Globals for EHCI
+ -----------------------------------------------------*/
+
+/* used when updating hcd data */
+//static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(hcd_data_lock);
+
+static const char hcd_name[] = "ST-Ericsson ISP1763";
+static td_ptd_map_buff_t td_ptd_map_buff[TD_PTD_TOTAL_BUFF_TYPES]; /* td-ptd map buffer for all 1362 buffers */
+
+static u8 td_ptd_pipe_x_buff_type[TD_PTD_TOTAL_BUFF_TYPES] = {
+ TD_PTD_BUFF_TYPE_ATL,
+ TD_PTD_BUFF_TYPE_INTL,
+ TD_PTD_BUFF_TYPE_ISTL
+};
+
+
+/*global memory blocks*/
+isp1763_mem_addr_t memalloc[BLK_TOTAL];
+#include "isp1763-mem.c"
+#include "isp1763-qtdptd.c"
+
+#ifdef CONFIG_ISO_SUPPORT
+#include "isp1763-itdptd.c"
+#endif /* CONFIG_ISO_SUPPORT */
+
+static int
+pehci_rh_control(struct usb_hcd *usb_hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength);
+
+static int pehci_bus_suspend(struct usb_hcd *usb_hcd);
+static int pehci_bus_resume(struct usb_hcd *usb_hcd);
+/*----------------------------------------------------*/
+static void
+pehci_complete_device_removal(phci_hcd * hcd, struct ehci_qh *qh)
+{
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *td_ptd_buff;
+ struct urb * urb;
+ urb_priv_t *urb_priv;
+ struct ehci_qtd *qtd = 0;
+// struct usb_hcd *usb_hcd=&hcd->usb_hcd;
+ u16 skipmap=0;
+
+ if (qh->type == TD_PTD_BUFF_TYPE_ISTL) {
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&qh->memory_addr);
+#endif
+ return;
+ }
+
+ td_ptd_buff = &td_ptd_map_buff[qh->type];
+ td_ptd_map = &td_ptd_buff->map_list[qh->qtd_ptd_index];
+
+ /*this flag should only be set when device is going */
+ td_ptd_map->state = TD_PTD_REMOVE;
+ /*if nothing there */
+ if (list_empty(&qh->qtd_list)) {
+ if (td_ptd_map->state != TD_PTD_NEW) {
+ phci_hcd_release_td_ptd_index(qh);
+ }
+ qha_free(qha_cache, qh);
+ qh = 0;
+ return;
+ } else {
+
+ if(!list_empty(&qh->qtd_list)){
+ qtd=NULL;
+ qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list);
+ if(qtd){
+ urb=qtd->urb;
+ urb_priv= urb->hcpriv;
+
+ if(urb)
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ break;
+ case PIPE_INTERRUPT:
+ td_ptd_buff = &td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL];
+ td_ptd_map = &td_ptd_buff->map_list[qh->qtd_ptd_index];
+
+ /*urb is already been removed */
+ // if (td_ptd_map->state == TD_PTD_NEW) {
+ // kfree(urb_priv);
+ // break;
+ // }
+
+ /* These TDs are not pending anymore */
+ td_ptd_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+ td_ptd_map->state = TD_PTD_REMOVE;
+ urb_priv->state |= DELETE_URB;
+
+ /*read the skipmap, to see if this transfer has to be rescheduled */
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap | td_ptd_map->ptd_bitmap);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map, NULL);
+#else
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map);
+#endif
+ break;
+ }
+
+
+ }else{
+ //break;
+ }
+ }
+ qha_free(qha_cache, qh);
+ qh = 0;
+ return;
+ }
+ /*MUST not come down below this */
+ err("Never Error: Should not come to this portion of code\n");
+
+ return;
+}
+
+/*functions looks for the values in register
+ specified in ptr, if register values masked
+ with the mask and result is equal to done,
+ operation is successful else fails with timeout*/
+static int
+pehci_hcd_handshake(phci_hcd * hcd, u32 ptr, u32 mask, u32 done, int usec)
+{
+ u32 result = 0;
+ do {
+ result = isp1763_reg_read16(hcd->dev, ptr, result);
+ pehci_print(KERN_NOTICE "Registr %x val is %x\n", ptr, result);
+ if (result == ~(u32) 0) {/* card removed */
+ return -ENODEV;
+ }
+ result &= mask;
+ if (result == done) {
+ return 0;
+ }
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+
+ return -ETIMEDOUT;
+}
+
+#ifndef MSEC_INT_BASED
+/*schedule atl and interrupt tds,
+ only when we are not running on sof interrupt
+ */
+static void
+pehci_hcd_td_ptd_submit_urb(phci_hcd * hcd, struct ehci_qh *qh, u8 bufftype)
+{
+ unsigned long flags=0;
+ struct ehci_qtd *qtd = 0;
+ struct urb *urb = 0;
+ struct _isp1763_qha *qha = 0;
+ u16 location = 0;
+ u16 skipmap = 0;
+ u16 buffstatus = 0;
+ u16 ormask = 0;
+ u16 intormask = 0;
+ u32 length = 0;
+ struct list_head *head;
+
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct isp1763_mem_addr *mem_addr = 0;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ pehci_print("Buuffer type %d\n", bufftype);
+
+ spin_lock_irqsave(&hcd->lock, flags);
+ ptd_map_buff = &td_ptd_map_buff[bufftype];
+
+ qha = &hcd->qha;
+
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+ break;
+ case TD_PTD_BUFF_TYPE_INTL:
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+
+ intormask =
+ isp1763_reg_read16(hcd->dev, hcd->regs.int_irq_mask_or,
+ intormask);
+ break;
+ default:
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.isotdskipmap,
+ skipmap);
+ break;
+
+ }
+
+
+ buffstatus =
+ isp1763_reg_read16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus);
+
+ /*header, qtd, and urb of current transfer */
+ location = qh->qtd_ptd_index;
+ td_ptd_map = &ptd_map_buff->map_list[location];
+
+ if (!(qh->qh_state & QH_STATE_TAKE_NEXT)) {
+ pehci_check("qh will schdule from interrupt routine,map %x\n",
+ td_ptd_map->ptd_bitmap);
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ return;
+ }
+ head = &qh->qtd_list;
+ qtd = list_entry(head->next, struct ehci_qtd, qtd_list);
+
+ /*already scheduled, may be from interrupt */
+ if (!(qtd->state & QTD_STATE_NEW)) {
+ pehci_check("qtd already in, state %x\n", qtd->state);
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ return;
+ }
+
+ qtd->state &= ~QTD_STATE_NEW;
+ qtd->state |= QTD_STATE_SCHEDULED;
+
+ qh->qh_state &= ~QH_STATE_TAKE_NEXT;
+ /*take the first td */
+ td_ptd_map->qtd = qtd;
+ /*take the urb */
+ urb = qtd->urb;
+ ptd_map_buff->active_ptds++;
+
+ /*trust the atl worker, at this location there wont be any td */
+ /*if this td is the last one */
+ if (qtd->state & QTD_STATE_LAST) {
+ qh->hw_current = cpu_to_le32(0);
+ /*else update the hw_next of qh to the next td */
+ } else {
+ qh->hw_current = qtd->hw_next;
+ }
+ memset(qha, 0, sizeof(isp1763_qha));
+
+ pehci_check("td being scheduled : length: %d, device: %d, map: %x\n",
+ qtd->length, urb->dev->devnum, td_ptd_map->ptd_bitmap);
+ /*NEW, now need to get the memory for this transfer */
+ length = qtd->length;
+ mem_addr = &qtd->mem_addr;
+ phci_hcd_mem_alloc(length, mem_addr, 0);
+ if (length && ((mem_addr->phy_addr == 0) || (mem_addr->virt_addr == 0))) {
+ err("Never Error: Can not allocate memory for the current td,length %d\n", length);
+ /*should not happen */
+ /*can happen only when we exceed the limit of devices we support
+ MAX 4 mass storage at a time */
+ }
+ phci_hcd_qha_from_qtd(hcd, qtd, qtd->urb, (void *) qha,
+ td_ptd_map->ptd_ram_data_addr, qh);
+ if (qh->type == TD_PTD_BUFF_TYPE_INTL) {
+ phci_hcd_qhint_schedule(hcd, qh, qtd, (isp1763_qhint *) qha,
+ qtd->urb);
+ }
+ /*write qha into the header of the host controller */
+ isp1763_mem_write(hcd->dev, td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH, 0);
+
+ /*if this is SETUP/OUT token , then need to write into the buffer */
+ /*length should be valid and supported by the ptd */
+ if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)){
+ switch (PTD_PID(qha->td_info2)) {
+ case OUT_PID:
+ case SETUP_PID:
+
+ isp1763_mem_write(hcd->dev, (u32) mem_addr->phy_addr, 0,
+ (void *) qtd->hw_buf[0], length, 0);
+
+
+#if 0
+ int i=0;
+ int *data_addr= qtd->hw_buf[0];
+ printk("\n");
+ for(i=0;i<length;i+=4) printk("[0x%X] ",*data_addr++);
+ printk("\n");
+#endif
+
+
+
+ break;
+ }
+ }
+
+ /*unskip the tds at this location */
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ /*enable atl interrupts on donemap */
+ ormask |= td_ptd_map->ptd_bitmap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+ break;
+
+ case TD_PTD_BUFF_TYPE_INTL:
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ intormask |= td_ptd_map->ptd_bitmap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_or,
+ intormask);
+ break;
+
+ case TD_PTD_BUFF_TYPE_ISTL:
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap, skipmap);
+ break;
+ }
+
+ /*if any new schedule, enable the atl buffer */
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | ATL_BUFFER);
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap, skipmap);
+ buffstatus |= ATL_BUFFER;
+ break;
+ case TD_PTD_BUFF_TYPE_INTL:
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | INT_BUFFER);
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap, skipmap);
+ break;
+ case TD_PTD_BUFF_TYPE_ISTL:
+ /*not supposed to be seen here */
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | ISO_BUFFER);
+ break;
+ }
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ return;
+
+}
+#endif
+
+
+
+#ifdef MSEC_INT_BASED
+/*schedule next (atl/int)tds and any pending tds*/
+static void
+pehci_hcd_schedule_pending_ptds(phci_hcd * hcd, u16 donemap, u8 bufftype,
+ u16 only)
+{
+ struct ehci_qtd *qtd = 0;
+ struct ehci_qh *qh = 0;
+ struct list_head *qtd_list = 0;
+ struct _isp1763_qha allqha;
+ struct _isp1763_qha *qha = 0;
+ u16 mask = 0x1, index = 0;
+ u16 location = 0;
+ u16 skipmap = 0;
+ u32 newschedule = 0;
+ u16 buffstatus = 0;
+ u16 schedulemap = 0;
+#ifndef CONFIG_ISO_SUPPORT
+ u16 lasttd = 1;
+#endif
+ u16 lastmap = 0;
+ struct urb *urb = 0;
+ urb_priv_t *urbpriv = 0;
+ int length = 0;
+ u16 ormask = 0, andmask = 0;
+ u16 intormask = 0;
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct isp1763_mem_addr *mem_addr = 0;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ pehci_print("Buffer type %d\n", bufftype);
+
+ /*need to hold this lock if another interrupt is comming
+ for previously scheduled transfer, while scheduling new tds
+ */
+ spin_lock(&hcd_data_lock);
+ ptd_map_buff = &td_ptd_map_buff[bufftype];
+ qha = &allqha;
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+ rmb();
+
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+
+ andmask =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atl_irq_mask_and,
+ andmask);
+ break;
+ case TD_PTD_BUFF_TYPE_INTL:
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+ /*read the interrupt mask registers */
+
+ intormask =
+ isp1763_reg_read16(hcd->dev, hcd->regs.int_irq_mask_or,
+ intormask);
+ break;
+ default:
+ err("Never Error: Bogus type of bufer\n");
+ return;
+ }
+
+ buffstatus =
+ isp1763_reg_read16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus);
+ /*td headers need attention */
+ schedulemap = donemap;
+ while (schedulemap) {
+ index = schedulemap & mask;
+ schedulemap &= ~mask;
+ mask <<= 1;
+
+ if (!index) {
+ location++;
+ continue;
+ }
+
+ td_ptd_map = &ptd_map_buff->map_list[location];
+ /* can happen if donemap comes after
+ removal of the urb and associated tds
+ */
+ if ((td_ptd_map->state == TD_PTD_NEW) ||
+ (td_ptd_map->state == TD_PTD_REMOVE)) {
+ qh = td_ptd_map->qh;
+ pehci_check
+ ("should not come here, map %x,pending map %x\n",
+ td_ptd_map->ptd_bitmap,
+ ptd_map_buff->pending_ptd_bitmap);
+
+ pehci_check("buffer type %s\n",
+ (bufftype == 0) ? "ATL" : "INTL");
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ /*clear the pending map */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ /*no endpoint at this location */
+ if (!(td_ptd_map->qh)) {
+ err("queue head can not be null here\n");
+ /*move to the next location */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ /*current endpoint */
+ qh = td_ptd_map->qh;
+ if (!(skipmap & td_ptd_map->ptd_bitmap)) {
+ /*should not happen, if happening, then */
+ pehci_check("buffertype %d,td_ptd_map %x,skipnap %x\n",
+ bufftype, td_ptd_map->ptd_bitmap, skipmap);
+ lastmap = td_ptd_map->ptd_bitmap;
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ /*if we processed all the tds in ths transfer */
+ if (td_ptd_map->lasttd) {
+ err("should not show map %x,qtd %p\n",
+ td_ptd_map->ptd_bitmap, td_ptd_map->qtd);
+ /*this can happen in case the transfer is not being
+ * procesed by the host , tho the transfer is there
+ * */
+ qh->hw_current = cpu_to_le32(td_ptd_map->qtd);
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ /*if we have ptd that is going for reload */
+ if ((td_ptd_map->qtd) && (td_ptd_map->state & TD_PTD_RELOAD)) {
+ warn("%s: reload td\n", __FUNCTION__);
+ td_ptd_map->state &= ~TD_PTD_RELOAD;
+ qtd = td_ptd_map->qtd;
+ goto loadtd;
+ }
+
+ /* qh is there but no qtd so it means fresh transfer */
+ if ((td_ptd_map->qh) && !(td_ptd_map->qtd)) {
+ if (list_empty(&qh->qtd_list)) {
+ /*should not hapen again, as it comes here
+ when it has td in its map
+ */
+ pehci_check
+ ("must not come here any more, td map %x\n",
+ td_ptd_map->ptd_bitmap);
+ /*this location is idle and can be free next time if
+ no new transfers are comming for this */
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ td_ptd_map->state |= TD_PTD_IDLE;
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+ qtd_list = &qh->qtd_list;
+ qtd = td_ptd_map->qtd =
+ list_entry(qtd_list->next, struct ehci_qtd,
+ qtd_list);
+ /*got the td, now goto reload */
+ goto loadtd;
+ }
+
+ /*if there is already one qtd there in the transfer */
+ if (td_ptd_map->qtd) {
+ /*new schedule */
+ qtd = td_ptd_map->qtd;
+ }
+ loadtd:
+ /*should not happen */
+ if (!qtd) {
+ err("this piece of code should not be executed\n");
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ ptd_map_buff->active_ptds++;
+ /*clear the pending map here */
+ ptd_map_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+
+
+ /*if this td is the last one */
+ if (qtd->state & QTD_STATE_LAST) {
+ /*no qtd anymore */
+ qh->hw_current = cpu_to_le32(0);
+
+ /*else update the hw_next of qh to the next td */
+ } else {
+ qh->hw_current = qtd->hw_next;
+ }
+
+ if (location != qh->qtd_ptd_index) {
+ err("Never Error: Endpoint header location and scheduling information are not same\n");
+ }
+
+ /*next location */
+ location++;
+ /*found new transfer */
+ newschedule = 1;
+ /*take the urb */
+ urb = qtd->urb;
+ /*sometimes we miss due to skipmap
+ so to make sure that we dont put again the
+ same stuff
+ */
+ if (!(qtd->state & QTD_STATE_NEW)) {
+ err("Never Error: We should not put the same stuff\n");
+ continue;
+ }
+
+ urbpriv = (urb_priv_t *) urb->hcpriv;
+ urbpriv->timeout = 0;
+
+ /*no more new */
+ qtd->state &= ~QTD_STATE_NEW;
+ qtd->state |= QTD_STATE_SCHEDULED;
+
+
+
+ /*NEW, now need to get the memory for this transfer */
+ length = qtd->length;
+ mem_addr = &qtd->mem_addr;
+ phci_hcd_mem_alloc(length, mem_addr, 0);
+ if (length && ((mem_addr->phy_addr == 0)
+ || (mem_addr->virt_addr == 0))) {
+
+ err("Never Error: Can not allocate memory for the current td,length %d\n", length);
+ location++;
+ continue;
+ }
+
+ pehci_check("qtd being scheduled %p, device %d,map %x\n", qtd,
+ urb->dev->devnum, td_ptd_map->ptd_bitmap);
+
+
+ memset(qha, 0, sizeof(isp1763_qha));
+ /*convert qtd to qha */
+ phci_hcd_qha_from_qtd(hcd, qtd, qtd->urb, (void *) qha,
+ td_ptd_map->ptd_ram_data_addr, qh);
+
+ if (qh->type == TD_PTD_BUFF_TYPE_INTL) {
+ phci_hcd_qhint_schedule(hcd, qh, qtd,
+ (isp1763_qhint *) qha,
+ qtd->urb);
+
+ }
+
+
+ length = PTD_XFERRED_LENGTH(qha->td_info1 >> 3);
+ if (length > HC_ATL_PL_SIZE) {
+ err("Never Error: Bogus length,length %d(max %d)\n",
+ qtd->length, HC_ATL_PL_SIZE);
+ }
+
+ /*write qha into the header of the host controller */
+ isp1763_mem_write(hcd->dev, td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH, 0);
+
+#ifdef PTD_DUMP_SCHEDULE
+ printk("SCHEDULE next (atl/int)tds PTD header\n");
+ printk("DW0: 0x%08X\n", qha->td_info1);
+ printk("DW1: 0x%08X\n", qha->td_info2);
+ printk("DW2: 0x%08X\n", qha->td_info3);
+ printk("DW3: 0x%08X\n", qha->td_info4);
+#endif
+
+ /*if this is SETUP/OUT token , then need to write into the buffer */
+ /*length should be valid */
+ if (qtd->length && (length <= HC_ATL_PL_SIZE)){
+ switch (PTD_PID(qha->td_info2)) {
+ case OUT_PID:
+ case SETUP_PID:
+
+ isp1763_mem_write(hcd->dev,
+ (u32) mem_addr->phy_addr, 0,
+ (void *) qtd->hw_buf[0],
+ length, 0);
+#if 0
+ int i=0;
+ int *data_addr= qtd->hw_buf[0];
+ printk("\n");
+ for(i=0;i<length;i+=4) printk("[0x%X] ",*data_addr++);
+ printk("\n");
+#endif
+
+
+
+ break;
+ }
+ }
+
+ /*unskip the tds at this location */
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ lastmap = td_ptd_map->ptd_bitmap;
+ /*try to reduce the interrupts */
+ ormask |= td_ptd_map->ptd_bitmap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+ break;
+
+ case TD_PTD_BUFF_TYPE_INTL:
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ lastmap = td_ptd_map->ptd_bitmap;
+ intormask |= td_ptd_map->ptd_bitmap;
+ ;
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_or,
+ intormask);
+ break;
+
+ case TD_PTD_BUFF_TYPE_ISTL:
+#ifdef CONFIG_ISO_SUPPORT
+ iso_dbg(ISO_DBG_INFO,
+ "Never Error: Should not come here\n");
+#else
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap,
+ skipmap);
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdlastmap,
+ lasttd);
+#endif /* CONFIG_ISO_SUPPORT */
+ break;
+ }
+
+
+ }
+ /*if any new schedule, enable the atl buffer */
+
+ if (newschedule) {
+ switch (bufftype) {
+ case TD_PTD_BUFF_TYPE_ATL:
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | ATL_BUFFER);
+ /*i am comming here to only those tds that has to be scheduled */
+ /*so skip map must be in place */
+ if (skipmap & donemap) {
+ pehci_check
+ ("must be both ones compliment of each other\n");
+ pehci_check
+ ("problem, skipmap %x, donemap %x,\n",
+ skipmap, donemap);
+
+ }
+ skipmap &= ~donemap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+
+ break;
+ case TD_PTD_BUFF_TYPE_INTL:
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | INT_BUFFER);
+ skipmap &= ~donemap;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+ break;
+ case TD_PTD_BUFF_TYPE_ISTL:
+#ifndef CONFIG_ISO_SUPPORT
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus | ISO_BUFFER);
+#endif
+ break;
+ }
+ }
+ spin_unlock(&hcd_data_lock);
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+#endif
+
+
+
+static void
+pehci_hcd_qtd_schedule(phci_hcd * hcd, struct ehci_qtd *qtd,
+ struct ehci_qh *qh, td_ptd_map_t * td_ptd_map)
+{
+ struct urb *urb;
+ urb_priv_t *urbpriv = 0;
+ u32 length=0;
+ struct isp1763_mem_addr *mem_addr = 0;
+ struct _isp1763_qha *qha, qhtemp;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ if (qtd->state & QTD_STATE_SCHEDULED) {
+ return;
+ }
+ /*redundant */
+ qha = &qhtemp;
+
+ /*if this td is the last one */
+ if (qtd->state & QTD_STATE_LAST) {
+ /*no qtd anymore */
+ qh->hw_current = cpu_to_le32(0);
+
+ /*else update the hw_next of qh to the next td */
+ } else {
+ qh->hw_current = qtd->hw_next;
+ }
+
+ urb = qtd->urb;
+ urbpriv = (urb_priv_t *) urb->hcpriv;
+ urbpriv->timeout = 0;
+
+ /*NEW, now need to get the memory for this transfer */
+ length = qtd->length;
+ mem_addr = &qtd->mem_addr;
+ phci_hcd_mem_alloc(length, mem_addr, 0);
+ if (length && ((mem_addr->phy_addr == 0) || (mem_addr->virt_addr == 0))) {
+ err("Never Error: Cannot allocate memory for the current td,length %d\n", length);
+ return;
+ }
+
+ pehci_check("newqtd being scheduled, device: %d,map: %x\n",
+ urb->dev->devnum, td_ptd_map->ptd_bitmap);
+
+ //udelay(100);
+
+ memset(qha, 0, sizeof(isp1763_qha));
+ /*convert qtd to qha */
+ phci_hcd_qha_from_qtd(hcd, qtd, qtd->urb, (void *) qha,
+ td_ptd_map->ptd_ram_data_addr, qh
+ /*td_ptd_map->datatoggle */ );
+
+ if (qh->type == TD_PTD_BUFF_TYPE_INTL) {
+ phci_hcd_qhint_schedule(hcd, qh, qtd, (isp1763_qhint *) qha,
+ qtd->urb);
+ }
+
+
+ length = PTD_XFERRED_LENGTH(qha->td_info1 >> 3);
+ if (length > HC_ATL_PL_SIZE) {
+ err("Never Error: Bogus length,length %d(max %d)\n",
+ qtd->length, HC_ATL_PL_SIZE);
+ }
+
+ /*write qha into the header of the host controller */
+ isp1763_mem_write(hcd->dev, td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH, 0);
+
+#if 0 //def PTD_DUMP_SCHEDULE
+ printk("SCHEDULE Next qtd\n");
+ printk("DW0: 0x%08X\n", qha->td_info1);
+ printk("DW1: 0x%08X\n", qha->td_info2);
+ printk("DW2: 0x%08X\n", qha->td_info3);
+ printk("DW3: 0x%08X\n", qha->td_info4);
+#endif
+
+ /*if this is SETUP/OUT token , then need to write into the buffer */
+ /*length should be valid */
+ if (qtd->length && (length <= HC_ATL_PL_SIZE)){
+ switch (PTD_PID(qha->td_info2)) {
+ case OUT_PID:
+ case SETUP_PID:
+
+ isp1763_mem_write(hcd->dev, (u32) mem_addr->phy_addr, 0,
+ (void *) qtd->hw_buf[0], length, 0);
+
+#if 0
+ int i=0;
+ int *data_addr= qtd->hw_buf[0];
+ printk("\n");
+ for(i=0;i<length;i+=4) printk("[0x%X] ",*data_addr++);
+ printk("\n");
+#endif
+
+
+ break;
+ }
+ }
+ /*qtd is scheduled */
+ qtd->state &= ~QTD_STATE_NEW;
+ qtd->state |= QTD_STATE_SCHEDULED;
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ return;
+}
+#ifdef USBNET
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static void
+pehci_hcd_urb_delayed_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map, struct pt_regs *regs)
+#else
+static void
+pehci_hcd_urb_delayed_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map)
+#endif
+{
+ static u32 remove = 0;
+ static u32 qh_state = 0;
+
+ urb_priv_t *urb_priv = (urb_priv_t *) urb->hcpriv;
+
+#ifdef USBNET
+ struct isp1763_async_cleanup_urb *urb_st = 0;
+#endif
+
+
+
+ urb_priv->timeout = 0;
+
+ if((td_ptd_map->state == TD_PTD_REMOVE ) ||
+ (urb_priv->state == DELETE_URB) ||
+ !HCD_IS_RUNNING(hcd->state)){
+ remove=1;
+ }
+ qh_state=qh->qh_state;
+ qh->qh_state = QH_STATE_COMPLETING;
+ /*remove the done tds */
+ spin_lock(&hcd_data_lock);
+ phci_hcd_urb_free_priv(hcd, urb_priv, qh);
+ spin_unlock(&hcd_data_lock);
+
+ urb_priv->timeout = 0;
+ kfree(urb_priv);
+ urb->hcpriv = 0;
+
+
+ /*if normal completion */
+ if (urb->status == -EINPROGRESS) {
+ urb->status = 0;
+ }
+
+ if(remove)
+ if (list_empty(&qh->qtd_list)) {
+ phci_hcd_release_td_ptd_index(qh);
+ }
+ remove=0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(!usb_hcd_check_unlink_urb(&hcd->usb_hcd, urb,0))
+ usb_hcd_unlink_urb_from_ep(&hcd->usb_hcd,urb);
+#endif
+
+//if(qh_state!=QH_STATE_COMPLETING)
+{
+// spin_unlock(&hcd->lock);
+ /* assume interrupt has been disabled and has acquired hcd->lock */
+ urb_st = (struct isp1763_async_cleanup_urb *)kmalloc(sizeof(struct isp1763_async_cleanup_urb), GFP_ATOMIC);
+ urb_st->urb = urb;
+ list_add_tail(&urb_st->urb_list, &(hcd->cleanup_urb.urb_list));
+
+// isp1763_reg_write16(hcd->dev, hcd->regs.interruptenable, INTR_ENABLE_MASK | HC_SOF_INT);
+ isp1763_reg_write16(hcd->dev, hcd->regs.interruptenable, HC_MSOF_INT);
+// spin_lock(&hcd->lock);
+}
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static void
+pehci_hcd_urb_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map, struct pt_regs *regs)
+#else
+static void
+pehci_hcd_urb_complete(phci_hcd * hcd, struct ehci_qh *qh, struct urb *urb,
+ td_ptd_map_t * td_ptd_map)
+#endif
+{
+ static u32 remove = 0;
+ static u32 qh_state = 0;
+ urb_priv_t *urb_priv = (urb_priv_t *) urb->hcpriv;
+
+ BUG_ON(urb_priv==NULL);
+
+ pehci_check("complete the td , length: %d\n", td_ptd_map->qtd->length);
+ urb_priv->timeout = 0;
+
+ if((td_ptd_map->state == TD_PTD_REMOVE ) ||
+ (urb_priv->state == DELETE_URB) ||
+ !HCD_IS_RUNNING(hcd->state)){
+ remove=1;
+ }
+
+
+ qh_state=qh->qh_state;
+
+ qh->qh_state = QH_STATE_COMPLETING;
+ /*remove the done tds */
+ spin_lock(&hcd_data_lock);
+ phci_hcd_urb_free_priv(hcd, urb_priv, qh);
+ spin_unlock(&hcd_data_lock);
+
+ urb_priv->timeout = 0;
+ kfree(urb_priv);
+ urb->hcpriv = 0;
+
+
+ /*if normal completion */
+ if (urb->status == -EINPROGRESS) {
+ urb->status = 0;
+ }
+
+ if(remove)
+ if (list_empty(&qh->qtd_list)) {
+ phci_hcd_release_td_ptd_index(qh);
+ }
+ remove=0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(!usb_hcd_check_unlink_urb(&hcd->usb_hcd, urb,0))
+ {
+ usb_hcd_unlink_urb_from_ep(&hcd->usb_hcd,urb);
+ }
+#endif
+ spin_unlock(&hcd->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb);
+#else
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb, urb->status);
+#endif
+ spin_lock(&hcd->lock);
+exit:
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+
+}
+
+/*update the error status of the td*/
+static void
+pehci_hcd_update_error_status(u32 ptdstatus, struct urb *urb)
+{
+ /*if ptd status is halted */
+ if (ptdstatus & PTD_STATUS_HALTED) {
+ if (ptdstatus & PTD_XACT_ERROR) {
+ /*transaction error results due to retry count goes to zero */
+ if (PTD_RETRY(ptdstatus)) {
+ /*halt the endpoint */
+ printk("transaction error , retries %d\n",
+ PTD_RETRY(ptdstatus));
+ urb->status = -EPIPE;
+ } else {
+ printk("transaction error , retries %d\n",
+ PTD_RETRY(ptdstatus));
+ /*protocol error */
+ urb->status = -EPROTO;
+ }
+ } else if (ptdstatus & PTD_BABBLE) {
+ printk("babble error, qha %x\n", ptdstatus);
+ /*babble error */
+ urb->status = -EOVERFLOW;
+ } else if (PTD_RETRY(ptdstatus)) {
+ printk("endpoint halted with retrie remaining %d\n",
+ PTD_RETRY(ptdstatus));
+ urb->status = -EPIPE;
+ } else { /*unknown error, i will report it as halted, as i will never see xact error bit set */
+ printk("protocol error, qha %x\n", ptdstatus);
+ urb->status = -EPIPE;
+ }
+
+ /*if halted need to recover */
+ if (urb->status == -EPIPE) {
+ }
+ }
+}
+
+#ifdef CONFIG_ISO_SUPPORT /* New code for ISO support */
+
+/*******************************************************************
+ * phcd_iso_handler - ISOCHRONOUS Transfer handler
+ *
+ * phci_hcd *hcd,
+ * Host controller driver structure which contains almost all data
+ * needed by the host controller driver to process data and interact
+ * with the host controller.
+ *
+ * struct pt_regs *regs
+ *
+ * API Description
+ * This is the ISOCHRONOUS Transfer handler, mainly responsible for:
+ * - Checking the periodic list if there are any ITDs for scheduling or
+ * removal.
+ * - For ITD scheduling, converting an ITD into a PTD, which is the data
+ * structure that the host contrtoller can understand and process.
+ * - For ITD completion, checking the transfer status and performing the
+ * required actions depending on status.
+ * - Freeing up memory used by an ITDs once it is not needed anymore.
+ ************************************************************************/
+void
+pehci_hcd_iso_sitd_schedule(phci_hcd *hcd,struct urb* urb,struct ehci_sitd* sitd){
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct _isp1763_isoptd *iso_ptd;
+ u32 ormask = 0, skip_map = 0,last_map=0,buff_stat=0;
+ struct isp1763_mem_addr *mem_addr;
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
+
+ /* Get the PTD allocated for this SITD. */
+ td_ptd_map =
+ &ptd_map_buff->map_list[sitd->
+ sitd_index];
+ iso_ptd = &hcd->isotd;
+
+ memset(iso_ptd, 0, sizeof(struct _isp1763_isoptd));
+ /* Read buffer status register to check later if the ISO buffer is
+ filled or not */
+ buff_stat =
+ isp1763_reg_read16(hcd->dev, hcd->regs.buffer_status,buff_stat);
+
+ /* Read the contents of the ISO skipmap register */
+ skip_map =
+ isp1763_reg_read16(hcd->dev, hcd->regs.isotdskipmap,
+ skip_map);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_sitd_schedule]: Read skip map: 0x%08x\n",
+ (unsigned int) skip_map);
+
+ /* Read the contents of the ISO lastmap register */
+ last_map =
+ isp1763_reg_read16(hcd->dev, hcd->regs.isotdlastmap,
+ last_map);
+
+ /* Read the contents of the ISO ormask register */
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.iso_irq_mask_or,
+ ormask);
+
+ /* Create a PTD from an SITD */
+ phcd_iso_sitd_to_ptd(hcd, sitd, sitd->urb,
+ (void *) iso_ptd);
+ /* Indicate that this SITD's PTD have been
+ filled up */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+
+ /*
+ * Place the newly initialized ISO PTD structure into
+ the location allocated for this PTD in the ISO PTD
+ memory region.
+ */
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd, PHCI_QHA_LENGTH, 0,
+ PTD_HED);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd,PHCI_QHA_LENGTH, 0);
+#endif
+
+ /*
+ * Set this flag to avoid unlinking before
+ schedule at particular frame number
+ */
+ td_ptd_map->state = TD_PTD_IN_SCHEDULE;
+
+ /*
+ * If the length is not zero and the direction is
+ OUT then copy the data to be transferred
+ into the PAYLOAD memory area.
+ */
+ if (sitd->length) {
+ switch (PTD_PID(iso_ptd->td_info2)) {
+ case OUT_PID:
+ /* Get the Payload memory
+ allocated for this PTD */
+ mem_addr = &sitd->mem_addr;
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr-> phy_addr,
+ 0, (u32*)
+ ((sitd->hw_bufp[0])),
+ sitd->length, 0,
+ PTD_PAY);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr->phy_addr,
+ 0, (u32 *)
+ sitd->hw_bufp[0],
+ sitd->length, 0);
+#endif
+ break;
+ }
+ /* switch(PTD_PID(iso_ptd->td_info2))*/
+ }
+
+ /* if(sitd->length) */
+ /* If this is the last td, indicate to complete
+ the URB */
+ if (sitd->hw_next == EHCI_LIST_END) {
+ td_ptd_map->lasttd = 1;
+ }
+
+ /*
+ * Clear the bit corresponding to this PTD in
+ the skip map so that it will be processed on
+ the next schedule traversal.
+ */
+ skip_map &= ~td_ptd_map->ptd_bitmap;
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_sitd_schedule]: Skip map:0x%08x\n",(unsigned int) skip_map);
+
+ /*
+ * Update the last map register to indicate
+ that the newly created PTD is the last PTD
+ added only if it is larger than the previous
+ bitmap.
+ */
+ if (last_map < td_ptd_map->ptd_bitmap) {
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdlastmap,
+ td_ptd_map->ptd_bitmap);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_sitd_schedule]:Last Map: 0x%08x\n",
+ td_ptd_map->ptd_bitmap);
+ }
+
+ /*
+ * Set the ISO_BUF_FILL bit to 1 to indicate
+ that there is a PTD for ISO that needs to
+ * be processed.
+ */
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.buffer_status,
+ (buff_stat | ISO_BUFFER));
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap,skip_map);
+
+}
+
+/*******************************************************************
+ * phcd_iso_handler - ISOCHRONOUS Transfer handler
+ *
+ * phci_hcd *hcd,
+ * Host controller driver structure which contains almost all data
+ * needed by the host controller driver to process data and interact
+ * with the host controller.
+ *
+ * struct pt_regs *regs
+ *
+ * API Description
+ * This is the ISOCHRONOUS Transfer handler, mainly responsible for:
+ * - Checking the periodic list if there are any ITDs for scheduling or
+ * removal.
+ * - For ITD scheduling, converting an ITD into a PTD, which is the data
+ * structure that the host contrtoller can understand and process.
+ * - For ITD completion, checking the transfer status and performing the
+ * required actions depending on status.
+ * - Freeing up memory used by an ITDs once it is not needed anymore.
+ ************************************************************************/
+void
+pehci_hcd_iso_schedule(phci_hcd * hcd, struct urb *urb)
+{
+ struct list_head *sitd_itd_sched, *position;
+ struct ehci_itd *itd;
+ struct ehci_sitd *sitd;
+ td_ptd_map_t *td_ptd_map;
+ unsigned long last_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct _isp1763_isoptd *iso_ptd;
+ unsigned long buff_stat;
+ struct isp1763_mem_addr *mem_addr;
+ u32 ormask = 0, skip_map = 0;
+ u32 iNumofPkts;
+ unsigned int iNumofSlots = 0, mult = 0;
+ struct ehci_qh *qhead;
+
+ buff_stat = 0;
+ iso_dbg(ISO_DBG_ENTRY, "[pehci_hcd_iso_schedule]: Enter\n");
+ iso_ptd = &hcd->isotd;
+
+ last_map = 0;
+ /* Check if there are any ITDs scheduled for processing */
+ if (hcd->periodic_sched == 0) {
+ return;
+ }
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ mult = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ mult = 1 + ((mult >> 11) & 0x3);
+ iNumofSlots = NUMMICROFRAME / urb->interval;
+ /*number of PTDs need to schedule for this PTD */
+ iNumofPkts = (urb->number_of_packets / mult) / iNumofSlots;
+ if ((urb->number_of_packets / mult) % iNumofSlots != 0){
+ /*get remainder */
+ iNumofPkts += 1;
+ }
+ } else{
+ iNumofPkts = urb->number_of_packets;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead = urb->hcpriv;
+#else
+ qhead = urb->ep->hcpriv;
+#endif
+ if (!qhead) {
+ iso_dbg(ISO_DBG_ENTRY,
+ "[pehci_hcd_iso_schedule]: Qhead==NULL\n");
+ return ;
+ }
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
+
+ while (iNumofPkts > 0) {
+ /* Read buffer status register to check later if the ISO buffer is
+ filled or not */
+ buff_stat =
+ isp1763_reg_read16(hcd->dev, hcd->regs.buffer_status,buff_stat);
+
+ /* Read the contents of the ISO skipmap register */
+ skip_map =
+ isp1763_reg_read16(hcd->dev, hcd->regs.isotdskipmap,
+ skip_map);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]: Read skip map: 0x%08x\n",
+ (unsigned int) skip_map);
+
+ /* Read the contents of the ISO lastmap register */
+ last_map =
+ isp1763_reg_read16(hcd->dev, hcd->regs.isotdlastmap,
+ last_map);
+
+ /* Read the contents of the ISO ormask register */
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.iso_irq_mask_or,
+ ormask);
+
+ /* Process ITDs linked to this frame, checking if there are any that needs to
+ be scheduled */
+ sitd_itd_sched = &qhead->periodic_list.sitd_itd_head;
+ if (list_empty(sitd_itd_sched)) {
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_schedule]: ISO schedule list's empty. Nothing to schedule.\n");
+ return;
+ }
+
+ list_for_each(position, sitd_itd_sched) {
+ if (qhead->periodic_list.high_speed == 0){
+ /* Get an SITD in the list for processing */
+ sitd = list_entry(position, struct ehci_sitd,
+ sitd_list);
+ iNumofPkts--;
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]: SITD Index:%d\n", sitd->sitd_index);
+ if(sitd->sitd_index==TD_PTD_INV_PTD_INDEX)
+ continue;
+ /* Get the PTD allocated for this SITD. */
+ td_ptd_map =
+ &ptd_map_buff->map_list[sitd->
+ sitd_index];
+ memset(iso_ptd, 0,
+ sizeof(struct _isp1763_isoptd));
+
+ /* Create a PTD from an SITD */
+ phcd_iso_sitd_to_ptd(hcd, sitd, sitd->urb,
+ (void *) iso_ptd);
+
+ /* Indicate that this SITD's PTD have been
+ filled up */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+
+ /*
+ * Place the newly initialized ISO PTD structure into
+ the location allocated for this PTD in the ISO PTD
+ memory region.
+ */
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd, PHCI_QHA_LENGTH, 0,
+ PTD_HED);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd,PHCI_QHA_LENGTH, 0);
+#endif
+
+ /*
+ * Set this flag to avoid unlinking before
+ schedule at particular frame number
+ */
+ td_ptd_map->state = TD_PTD_IN_SCHEDULE;
+
+ /*
+ * If the length is not zero and the direction is
+ OUT then copy the data to be transferred
+ into the PAYLOAD memory area.
+ */
+ if (sitd->length) {
+ switch (PTD_PID(iso_ptd->td_info2)) {
+ case OUT_PID:
+ /* Get the Payload memory
+ allocated for this PTD */
+ mem_addr = &sitd->mem_addr;
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr-> phy_addr,
+ 0, (u32*)
+ ((sitd->hw_bufp[0])),
+ sitd->length, 0,
+ PTD_PAY);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr->phy_addr,
+ 0, (u32 *)
+ sitd->hw_bufp[0],
+ sitd->length, 0);
+#endif
+ break;
+ }
+ /* switch(PTD_PID(iso_ptd->td_info2))*/
+ }
+
+ /* if(sitd->length) */
+ /* If this is the last td, indicate to complete
+ the URB */
+ if (sitd->hw_next == EHCI_LIST_END) {
+ td_ptd_map->lasttd = 1;
+ }
+
+ /*
+ * Clear the bit corresponding to this PTD in
+ the skip map so that it will be processed on
+ the next schedule traversal.
+ */
+ skip_map &= ~td_ptd_map->ptd_bitmap;
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]: Skip map:0x%08x\n",(unsigned int) skip_map);
+
+ /*
+ * Update the last map register to indicate
+ that the newly created PTD is the last PTD
+ added only if it is larger than the previous
+ bitmap.
+ */
+ if (last_map < td_ptd_map->ptd_bitmap) {
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdlastmap,
+ td_ptd_map->ptd_bitmap);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]:Last Map: 0x%08x\n",
+ td_ptd_map->ptd_bitmap);
+ }
+
+ /*
+ * Set the ISO_BUF_FILL bit to 1 to indicate
+ that there is a PTD for ISO that needs to
+ * be processed.
+ */
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.buffer_status,
+ (buff_stat | ISO_BUFFER));
+
+ } else { /*HIGH SPEED */
+
+ /* Get an ITD in the list for processing */
+ itd = list_entry(position, struct ehci_itd,
+ itd_list);
+ iNumofPkts--;
+
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]: ITD Index: %d\n", itd->itd_index);
+ /* Get the PTD allocated for this ITD. */
+ td_ptd_map =
+ &ptd_map_buff->map_list[itd->itd_index];
+ memset(iso_ptd, 0,
+ sizeof(struct _isp1763_isoptd));
+
+ /* Create a PTD from an ITD */
+ phcd_iso_itd_to_ptd(hcd, itd, itd->urb,
+ (void *) iso_ptd);
+
+ /* Indicate that this SITD's PTD have been
+ filled up */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+
+ /*
+ * Place the newly initialized ISO PTD
+ structure into the location allocated
+ * for this PTD in the ISO PTD memory region.
+ */
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd,PHCI_QHA_LENGTH, 0,
+ PTD_HED);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) iso_ptd,PHCI_QHA_LENGTH, 0);
+#endif
+ /*
+ * Set this flag to avoid unlinking before schedule
+ * at particular frame number
+ */
+ td_ptd_map->state = TD_PTD_IN_SCHEDULE;
+
+ /*
+ * If the length is not zero and the direction
+ is OUT then copy the data to be transferred
+ into the PAYLOAD memory area.
+ */
+ if (itd->length) {
+ switch (PTD_PID(iso_ptd->td_info2)) {
+ case OUT_PID:
+ /* Get the Payload memory
+ allocated for this PTD */
+ mem_addr = &itd->mem_addr;
+#ifdef SWAP
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr->phy_addr, 0,
+ (u32*)
+ ((itd->hw_bufp[0])),
+ itd->length, 0,
+ PTD_PAY);
+#else /* NO_SWAP */
+ isp1763_mem_write(hcd->dev,
+ (unsigned long)
+ mem_addr->phy_addr, 0,
+ (u32 *)itd->hw_bufp[0],
+ itd->length, 0);
+#endif
+ break;
+ }
+ /* switch(PTD_PID(iso_ptd->td_info2)) */
+ }
+
+
+ /* If this is the last td, indicate to
+ complete the URB */
+ if (itd->hw_next == EHCI_LIST_END) {
+ td_ptd_map->lasttd = 1;
+ }
+
+ /*
+ * Clear the bit corresponding to this PT D
+ in the skip map so that it will be processed
+ on the next schedule traversal.
+ */
+ skip_map &= ~td_ptd_map->ptd_bitmap;
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]: Skip map:0x%08x\n",(unsigned int) skip_map);
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdskipmap,
+ skip_map);
+
+ /*
+ * Update the last map register to indicate
+ that the newly created PTD is the last PTD
+ added only if it is larger than the previous
+ bitmap.
+ */
+ if (last_map < td_ptd_map->ptd_bitmap) {
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdlastmap,
+ td_ptd_map->ptd_bitmap);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_schedule]:Last Map: 0x%08x\n",
+ td_ptd_map->ptd_bitmap);
+ }
+
+ /*
+ * Set the ISO_BUF_FILL bit to 1 to indicate
+ that there is a PTD for ISO that needs to
+ * be processed.
+ */
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.buffer_status,
+ (buff_stat | ISO_BUFFER));
+ }
+ } /* list_for_each(position, itd_sched) */
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap,skip_map);
+ }/*end of while (igNumOfPkts) */
+
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_schedule]: ISO-Frame scheduling done\n");
+ iso_dbg(ISO_DBG_ENTRY, "[pehci_hcd_iso_schedule]: Exit\n");
+}
+
+/*******************************************************************
+ * phcd_iso_handler - ISOCHRONOUS Transfer handler
+ *
+ * phci_hcd *hcd,
+ * Host controller driver structure which contains almost all data
+ * needed by the host controller driver to process data and interact
+ * with the host controller.
+ *
+ * struct pt_regs *regs
+ *
+ * API Description
+ * This is the ISOCHRONOUS Transfer handler, mainly responsible for:
+ * - Checking the periodic list if there are any ITDs for scheduling or
+ * removal.
+ * - For ITD scheduling, converting an ITD into a PTD, which is the data
+ * structure that the host contrtoller can understand and process.
+ * - For ITD completion, checking the transfer status and performing the
+ * required actions depending on status.
+ * - Freeing up memory used by an ITDs once it is not needed anymore.
+ ************************************************************************/
+
+int debugiso = 0;
+
+void
+pehci_hcd_iso_worker(phci_hcd * hcd)
+{
+ u32 donemap = 0, skipmap = 0; /*ormask = 0, buff_stat = 0;*/
+ u32 pendingmap = 0;
+ u32 mask = 0x1, index = 0, donetoclear = 0;
+ u32 uFrIndex = 0;
+ unsigned char last_td = FALSE, iReject = 0;
+ struct isp1763_mem_addr *mem_addr;
+ struct _isp1763_isoptd *iso_ptd;
+ unsigned long length = 0, uframe_cnt, usof_stat;
+ struct ehci_qh *qhead;
+ struct ehci_itd *itd, *current_itd;
+ struct ehci_sitd *sitd=0, *current_sitd=0;
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct list_head *sitd_itd_remove, *position;// *lst_temp;
+ struct urb *urb;
+ u8 i = 0;
+ unsigned long startAdd = 0;
+ int ret = 0;
+
+
+ iso_ptd = &hcd->isotd;
+
+ /* Check if there are any ITDs scheduled for processing */
+ if (hcd->periodic_sched == 0) {
+ goto exit;
+ }
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
+ pendingmap = ptd_map_buff->pending_ptd_bitmap;
+
+
+ /*read the done map for interrupt transfers */
+ donemap = isp1763_reg_read16(hcd->dev, hcd->regs.isotddonemap, donemap);
+
+ iso_dbg(ISO_DBG_ENTRY, "[pehci_hcd_iso_worker]: Enter %x \n", donemap);
+ if (!donemap) { /*there isnt any completed PTD */
+ goto exit;
+ }
+ donetoclear = donemap;
+ uFrIndex = 0;
+ while (donetoclear) {
+ mask = 0x1 << uFrIndex;
+ index = uFrIndex;
+ uFrIndex++;
+ if (!(donetoclear & mask))
+ continue;
+ donetoclear &= ~mask;
+ iso_dbg(ISO_DBG_DATA, "[pehci_hcd_iso_worker]: uFrIndex = %d\n", index);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]:donetoclear = 0x%x mask = 0x%x\n",
+ donetoclear, mask);
+
+
+ if (ptd_map_buff->map_list[index].sitd) {
+ urb = ptd_map_buff->map_list[index].sitd->urb;
+ if (!urb) {
+ printk("ERROR : URB is NULL \n");
+ continue;
+ }
+ sitd = ptd_map_buff->map_list[index].sitd;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+#else
+ qhead = urb->ep->hcpriv;
+#endif
+ if (!qhead) {
+ printk("ERROR : Qhead is NULL \n");
+ continue;
+ }
+
+ sitd_itd_remove = &qhead->periodic_list.sitd_itd_head;
+ } else if (ptd_map_buff->map_list[index].itd) {
+ urb = ptd_map_buff->map_list[index].itd->urb;
+ if (!urb) {
+ printk("ERROR : URB is NULL \n");
+ continue;
+ }
+ itd = ptd_map_buff->map_list[index].itd;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+#else
+ qhead = urb->ep->hcpriv;
+#endif
+ if (!qhead) {
+ printk("ERROR : Qhead is NULL \n");
+ continue;
+ }
+
+ sitd_itd_remove = &qhead->periodic_list.sitd_itd_head;
+
+ } else {
+ printk("ERROR : NO sitd in that PTD location : \n");
+ continue;
+ }
+ /* Process ITDs linked to this frame, checking for completed ITDs */
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: Removal Frame number: %d\n",
+ (int) index);
+ if (list_empty(sitd_itd_remove)) {
+ continue;
+ }
+
+ if (urb) {
+ last_td = FALSE;
+ if (qhead->periodic_list.high_speed == 0)/*FULL SPEED*/
+ {
+
+ /* Get the PTD that was allocated for this
+ particular SITD*/
+ td_ptd_map =
+ &ptd_map_buff->map_list[sitd->
+ sitd_index];
+
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker]: PTD is done,%d\n",index);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: SITD Index: %d\n",sitd->sitd_index);
+ urb = sitd->urb;
+
+ /*
+ * Get the base address of the memory allocated
+ in the PAYLOAD region for this SITD
+ */
+ mem_addr = &sitd->mem_addr;
+ memset(iso_ptd, 0,
+ sizeof(struct _isp1763_isoptd));
+
+ /*
+ * Read this ptd from the ram address,
+ address is in the td_ptd_map->ptd_header_addr
+ */
+
+ isp1763_mem_read(hcd->dev,
+ td_ptd_map->ptd_header_addr,
+ 0, (u32 *) iso_ptd,
+ PHCI_QHA_LENGTH, 0);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD0 = 0x%08x\n", iso_ptd->td_info1);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD1 = 0x%08x\n", iso_ptd->td_info2);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD2 = 0x%08x\n", iso_ptd->td_info3);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD3 = 0x%08x\n", iso_ptd->td_info4);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD4 = 0x%08x\n", iso_ptd->td_info5);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD5 = 0x%08x\n", iso_ptd->td_info6);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD6 = 0x%08x\n", iso_ptd->td_info7);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD7 = 0x%08x\n", iso_ptd->td_info8);
+
+ /* Go over the status of each of the 8 Micro Frames */
+ for (uframe_cnt = 0; uframe_cnt < 8;
+ uframe_cnt++) {
+ /*
+ * We go over the status one at a time. The status bits and their
+ * equivalent status are:
+ * Bit 0 - Transaction Error (IN and OUT)
+ * Bit 1 - Babble (IN token only)
+ * Bit 2 - Underrun (OUT token only)
+ */
+ usof_stat =
+ iso_ptd->td_info5 >> (8 +
+ (uframe_cnt * 3));
+
+ switch (usof_stat & 0x7) {
+ case INT_UNDERRUN:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Buffer underrun\n");
+ urb->error_count++;
+ break;
+ case INT_EXACT:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Transaction error\n");
+ printk("[pehci_hcd_iso_worker Error]: Transaction error\n");
+ urb->error_count++;
+ break;
+ case INT_BABBLE:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Babble error\n");
+ printk("[pehci_hcd_iso_worker Error]: Babble error\n");
+ urb->iso_frame_desc[sitd->sitd_index].status
+ = -EOVERFLOW;
+ urb->error_count++;
+ break;
+ } /* switch(usof_stat & 0x7) */
+ } /* end of for( ulMicroFrmCnt = 0; ulMicroFrmCnt < 8; ulMicroFrmCnt++) */
+
+ /*
+ * Get the number of bytes transferred. This indicates the number of
+ * bytes sent or received for this transaction.
+ */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* Length is 1K for full/low speed device */
+ length = PTD_XFERRED_NONHSLENGTH
+ (iso_ptd->td_info4);
+ } else {
+ /* Length is 32K for high speed device */
+ length = PTD_XFERRED_LENGTH(iso_ptd->
+ td_info4);
+ }
+
+ /* Halted, need to finish all the transfer on this endpoint */
+ if (iso_ptd->td_info4 & PTD_STATUS_HALTED) {
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error] PTD Halted\n");
+ printk("[pehci_hcd_iso_worker Error] PTD Halted\n");
+ /*
+ * When there is an error, do not process the other PTDs.
+ * Stop at the PTD with the error and remove all other PTDs.
+ */
+ td_ptd_map->lasttd = 1;
+
+ /*
+ * In case of halt, next transfer will start with toggle zero,
+ * USB specs, 5.8.5
+ */
+ td_ptd_map->datatoggle = 0;
+ }
+
+ /* if(iso_ptd->td_info4 & PTD_STATUS_HALTED) */
+ /* Update the actual length of the transfer from the data we got earlier */
+ urb->iso_frame_desc[sitd->index].actual_length =
+ length;
+
+ /* If the PTD have been executed properly the V bit should be cleared */
+ if (iso_ptd->td_info1 & QHA_VALID) {
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Valid bit not cleared\n");
+ printk("[pehci_hcd_iso_worker Error]: Valid bit not cleared\n");
+ urb->iso_frame_desc[sitd->index].
+ status = -ENOSPC;
+ } else {
+ urb->iso_frame_desc[sitd->index].
+ status = 0;
+ }
+
+ /* Check if this is the last SITD either due to some error or normal completion */
+ if ((td_ptd_map->lasttd)
+ || (sitd->hw_next == EHCI_LIST_END)) {
+ last_td = TRUE;
+ }
+
+ /* Copy data to/from */
+ if (length && (length <= MAX_PTD_BUFFER_SIZE)) {
+ switch (PTD_PID(iso_ptd->td_info2)) {
+ case IN_PID:
+ /*
+ * Get the data from the PAYLOAD area and place it into
+ * the buffer provided by the requestor.
+ */
+
+ isp1763_mem_read(hcd->dev,
+ (unsigned long)mem_addr->
+ phy_addr, 0,(u32 *)
+ sitd->hw_bufp[0],
+ length, 0);
+
+ case OUT_PID:
+ /*
+ * urb->actual length was initialized to zero, so for the first
+ * uFrame having it incremented immediately is not a problem.
+ */
+ urb->actual_length += length;
+ break;
+ }/* switch(PTD_PID(iso_ptd->td_info2)) */
+ }
+ /* if(length && (length <= MAX_PTD_BUFFER_SIZE)) */
+// removesitd:
+ /*read skip-map */
+ skipmap =
+ isp1763_reg_read16(hcd->dev,
+ hcd->regs.isotdskipmap,
+ skipmap);
+ iso_dbg(ISO_DBG_DATA,
+ "[%s] : read skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+ if (last_td == TRUE) {
+ /* Start removing the ITDs in the list */
+ while (1) {
+ /*
+ * This indicates that we are processing the tail PTD.
+ * Perform cleanup procedure on this last PTD
+ */
+ if (sitd->hw_next == EHCI_LIST_END) {
+ td_ptd_map =
+ &ptd_map_buff->
+ map_list[sitd->
+ sitd_index];
+
+ /*
+ * Free up our allocation in the PAYLOAD area so that others can use
+ * it.
+ */
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free
+ (&sitd->
+ mem_addr);
+#endif
+ /* Remove this SITD entry in the SITD list */
+ list_del(&sitd->
+ sitd_list);
+
+ /* Free up the memory allocated for the SITD structure */
+ qha_free(qha_cache,
+ sitd);
+
+ /* Indicate that the PTD we have used is now free */
+ td_ptd_map->state =
+ TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+
+ /* Decrease the number of active PTDs scheduled */
+ hcd->periodic_sched--;
+
+ /* Skip this PTD during the next PTD processing. */
+ skipmap |=
+ td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16
+ (hcd->dev,
+ hcd->regs.
+ isotdskipmap,
+ skipmap);
+
+ /* All ITDs in this list have been successfully removed. */
+ break;
+ } else {
+ /*
+ * This indicates that we stopped due to an error on a PTD that is
+ * not the last in the list. We need to free up this PTD as well as
+ * the PTDs after it.
+ */
+ /*
+ * Put the current SITD error onto this variable.
+ * We will be unlinking this from the list and free up its
+ * resources later.
+ */
+ current_sitd = sitd;
+
+ td_ptd_map =
+ &ptd_map_buff->
+ map_list[sitd->
+ sitd_index];
+
+ /*
+ * Get the next SITD, and place it to the sitd variable.
+ * In a way we are moving forward in the SITD list.
+ */
+ sitd = (struct ehci_sitd
+ *)
+ (current_sitd->
+ hw_next);
+ /* Free up the current SITD's resources */
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free
+ (&current_sitd->
+ mem_addr);
+#endif
+ /* Remove this SITD entry in the SITD list */
+ list_del(&current_sitd->
+ sitd_list);
+
+ /* Free up the memory allocated for the SITD structure */
+ qha_free(qha_cache,
+ current_sitd);
+
+ /* Inidicate that the PTD we have used is now free */
+ td_ptd_map->state =
+ TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+
+ /* Decrease the number of active PTDs scheduled */
+ hcd->periodic_sched--;
+
+ /* Sine it is done, skip this PTD during the next PTD processing. */
+ skipmap |=
+ td_ptd_map->
+ ptd_bitmap;
+ isp1763_reg_write16
+ (hcd->dev,
+ hcd->regs.
+ isotdskipmap,
+ skipmap);
+ /*
+ * Start all over again until it gets to the tail of the
+ * list of PTDs/ITDs
+ */
+ continue;
+ } /* else of if(sitd->hw_next == EHCI_LIST_END) */
+
+ /* It should never get here, but I put this as a precaution */
+ break;
+ } /*end of while(1) */
+
+ /* Check if there were ITDs that were not processed due to the error */
+ if (urb->status == -EINPROGRESS) {
+ if ((urb->actual_length !=
+ urb->transfer_buffer_length)
+ && (urb->transfer_flags &
+ URB_SHORT_NOT_OK)) {
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Short Packet\n");
+ urb->status =
+ -EREMOTEIO;
+ } else {
+ urb->status = 0;
+ }
+ }
+
+ urb->hcpriv = 0;
+ iso_dbg(ISO_DBG_DATA,
+ "[%s] : remain skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&qhead->memory_addr);
+#endif
+ /* We need to unlock this here, since this was locked when we are called
+ * from the interrupt handler */
+ spin_unlock(&hcd->lock);
+ /* Perform URB cleanup */
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker] Complete a URB\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(!usb_hcd_check_unlink_urb(&hcd->usb_hcd, urb,0))
+ usb_hcd_unlink_urb_from_ep(&hcd->usb_hcd,
+ urb);
+#endif
+ hcd->periodic_more_urb = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+ if (!list_empty(&qhead->ep->urb_list))
+#else
+ if (!list_empty(&urb->ep->urb_list))
+#endif
+ hcd->periodic_more_urb = 1;
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb);
+#else
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb, urb->status);
+#endif
+
+ spin_lock(&hcd->lock);
+ continue;
+ }
+
+ /* if( last_td == TRUE ) */
+ /*
+ * If the last_td is not set then we do not need to check for errors and directly
+ * proceed with the cleaning sequence.
+ */
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker]: last_td is not set\n");
+ /*update skipmap */
+ skipmap |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdskipmap,
+ skipmap);
+ iso_dbg(ISO_DBG_DATA,
+ "%s : remain skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+
+ /* Decrement the count of active PTDs */
+ hcd->periodic_sched--;
+ /*schedule next PTD for this URB */
+ if(qhead->actualptds<qhead->totalptds)
+ {
+ sitd_itd_remove = &qhead->periodic_list.sitd_itd_head;
+ /* find sitd to schedule */
+ list_for_each(position, sitd_itd_remove) {
+
+ if (qhead->periodic_list.high_speed == 0){
+ /* Get an SITD in the list for processing */
+ current_sitd= list_entry(position, struct ehci_sitd,
+ sitd_list);
+ if(current_sitd->sitd_index==TD_PTD_INV_PTD_INDEX)
+ break;
+ }
+ }
+ if(current_sitd->sitd_index==TD_PTD_INV_PTD_INDEX){
+ qhead->actualptds++;
+ /*allocate memory and PTD index */
+ memcpy(&current_sitd->mem_addr,&sitd->mem_addr,sizeof(struct isp1763_mem_addr));
+// printk("current %x\n",sitd->sitd_index);
+ current_sitd->sitd_index=sitd->sitd_index;
+ /*schedule PTD */
+ td_ptd_map->sitd = current_sitd;
+ hcd->periodic_sched++;
+ pehci_hcd_iso_sitd_schedule(hcd, urb,current_sitd);
+ }
+
+ /* Remove this SITD from the list of active ITDs */
+ list_del(&sitd->sitd_list);
+
+ /* Free up the memory we allocated for the SITD structure */
+ qha_free(qha_cache, sitd);
+
+
+ }else{
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free(&sitd->mem_addr);
+#endif
+ /* Remove this SITD from the list of active ITDs */
+ list_del(&sitd->sitd_list);
+
+ /* Free up the memory we allocated for the SITD structure */
+ qha_free(qha_cache, sitd);
+
+ /*
+ * Clear the bit associated with this PTD from the grouptdmap and
+ * make this PTD available for other transfers
+ */
+ td_ptd_map->state = TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+
+ }
+
+
+
+ } else { /*HIGH SPEED */
+
+ /* Get an ITD in the list for processing */
+ itd = ptd_map_buff->map_list[index].itd;
+
+ /* Get the PTD that was allocated for this particular ITD. */
+ td_ptd_map =
+ &ptd_map_buff->map_list[itd->itd_index];
+
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker]: PTD is done , %d\n",
+ index);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: ITD Index: %d\n",
+ itd->itd_index);
+
+ urb = itd->urb;
+
+ /*
+ * Get the base address of the memory allocated in the
+ * PAYLOAD region for this ITD
+ */
+ mem_addr = &itd->mem_addr;
+ memset(iso_ptd, 0,
+ sizeof(struct _isp1763_isoptd));
+
+ /*
+ * Read this ptd from the ram address,address is in the
+ * td_ptd_map->ptd_header_addr
+ */
+
+ isp1763_mem_read(hcd->dev,
+ td_ptd_map->ptd_header_addr,
+ 0, (u32 *) iso_ptd,
+ PHCI_QHA_LENGTH, 0);
+
+ /*
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD0 =
+ 0x%08x\n", iso_ptd->td_info1);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD1 =
+ 0x%08x\n", iso_ptd->td_info2);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD2 =
+ 0x%08x\n", iso_ptd->td_info3);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD3 =
+ 0x%08x\n", iso_ptd->td_info4);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD4 =
+ 0x%08x\n",iso_ptd->td_info5);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD5 =
+ 0x%08x\n", iso_ptd->td_info6);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD6 =
+ 0x%08x\n", iso_ptd->td_info7);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_iso_worker]: DWORD7 =
+ 0x%08x\n", iso_ptd->td_info8);
+ */
+
+
+ /* If the PTD have been executed properly,
+ the V bit should be cleared */
+ if (iso_ptd->td_info1 & QHA_VALID) {
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Valid bit not cleared\n");
+ for(i = 0; i<itd->num_of_pkts; i++){
+ urb->iso_frame_desc[itd->index
+ + i].status = -ENOSPC;
+ }
+ } else {
+ for (i = 0; i<itd->num_of_pkts; i++){
+ urb->iso_frame_desc[itd->index
+ +i].status = 0;
+ }
+ }
+
+ /* Go over the status of each of the 8 Micro Frames */
+ for (uframe_cnt = 0; (uframe_cnt < 8)
+ && (uframe_cnt < itd->num_of_pkts);
+ uframe_cnt++) {
+ /*
+ * We go over the status one at a time. The status bits and their
+ * equivalent status are:
+ * Bit 0 - Transaction Error (IN and OUT)
+ * Bit 1 - Babble (IN token only)
+ * Bit 2 - Underrun (OUT token only)
+ */
+ usof_stat =
+ iso_ptd->td_info5 >> (8 +
+ (uframe_cnt * 3));
+
+ switch (usof_stat & 0x7) {
+ case INT_UNDERRUN:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Buffer underrun\n");
+ urb->iso_frame_desc[itd->index +
+ uframe_cnt].
+ status = -ECOMM;
+ urb->error_count++;
+ break;
+ case INT_EXACT:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: %p Transaction error\n",
+ urb);
+ urb->iso_frame_desc[itd->index +
+ uframe_cnt].
+ status = -EPROTO;
+ urb->error_count++;
+ debugiso = 25;
+ break;
+ case INT_BABBLE:
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Babble error\n");
+ urb->iso_frame_desc[itd->index +
+ uframe_cnt].
+ status = -EOVERFLOW;
+ urb->error_count++;
+ break;
+ }/* switch(usof_stat & 0x7) */
+ }/* end of for( ulMicroFrmCnt = 0; ulMicroFrmCnt < 8; ulMicroFrmCnt++) */
+
+ /*
+ * Get the number of bytes transferred. This indicates the number of
+ * bytes sent or received for this transaction.
+ */
+
+ /* Length is 32K for high speed device */
+ length = PTD_XFERRED_LENGTH(iso_ptd->td_info4);
+
+ /* Halted, need to finish all the transfer on this endpoint */
+ if (iso_ptd->td_info4 & PTD_STATUS_HALTED) {
+
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error] PTD Halted\n");
+ printk("[pehci_hcd_iso_worker Error] PTD Halted===============\n");
+ /*
+ * When there is an error, do not process the other PTDs.
+ * Stop at the PTD with the error and remove all other PTDs.
+ */
+ td_ptd_map->lasttd = 1;
+
+ /*
+ * In case of halt, next transfer will start with toggle zero,
+ * USB specs, 5.8.5
+ */
+ td_ptd_map->datatoggle = 0;
+ }
+ /* if(iso_ptd->td_info4 & PTD_STATUS_HALTED) */
+ /* Update the actual length of the transfer from the data we got earlier */
+ if (PTD_PID(iso_ptd->td_info2) == OUT_PID) {
+ for (i = 0; i < itd->num_of_pkts; i++){
+ urb->iso_frame_desc[itd->index +
+ i].actual_length =(unsigned int)
+ length / itd->num_of_pkts;
+ }
+ } else{
+ iso_dbg(ISO_DBG_DATA,
+ "itd->num_of_pkts = %d, itd->ssplit = %x\n",
+ itd->num_of_pkts, itd->ssplit);
+ urb->iso_frame_desc[itd->index +
+ 0].actual_length =
+ iso_ptd->td_info6 & 0x00000FFF;
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[0] = %d\n",
+ urb->iso_frame_desc[itd->index +0].
+ actual_length);
+
+ if((itd->num_of_pkts > 1)
+ && ((itd->ssplit & 0x2) == 0x2)
+ && (urb->iso_frame_desc[itd->index +
+ 1].status ==0)) {
+
+ urb->iso_frame_desc[itd->index +1].
+ actual_length = (iso_ptd->
+ td_info6 & 0x00FFF000)>> 12;
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[1] = %d\n",
+ urb->
+ iso_frame_desc[itd->
+ index + 1].
+ actual_length);
+ }else{
+ urb->iso_frame_desc[itd->index +1].
+ actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 2)
+ && ((itd->ssplit & 0x4) == 0x4)
+ && (urb->
+ iso_frame_desc[itd->index +
+ 2].status ==0)) {
+
+ urb->iso_frame_desc[itd->index +
+ 2].actual_length =
+ ((iso_ptd->td_info6 &
+ 0xFF000000 )>> 24)
+ | ((iso_ptd->td_info7
+ & 0x0000000F)<< 8);
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[2] = %d\n",
+ urb->iso_frame_desc[itd->
+ index + 2].actual_length);
+ } else{
+ urb->iso_frame_desc[itd->index +2].
+ actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 3)
+ && ((itd->ssplit & 0x8) == 0x8)
+ && (urb->iso_frame_desc[itd->index +
+ 3].status == 0)) {
+
+ urb->iso_frame_desc[itd->index + 3].
+ actual_length =(iso_ptd->
+ td_info7 & 0x0000FFF0)>> 4;
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[3] = %d\n",
+ urb->iso_frame_desc[itd->
+ index + 3].actual_length);
+ } else {
+ urb->iso_frame_desc[itd->index +3].
+ actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 4)
+ && ((itd->ssplit & 0x10) == 0x10)
+ && (urb->
+ iso_frame_desc[itd->index +
+ 4].status ==0)) {
+
+ urb->iso_frame_desc[itd->index +
+ 4].actual_length =
+ (iso_ptd->
+ td_info7 & 0x0FFF0000) >> 16;
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[4] = %d\n",
+ urb->iso_frame_desc[itd->index +
+ 4].actual_length);
+ } else {
+ urb->iso_frame_desc[itd->index +
+ 4].actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 5)
+ && ((itd->ssplit & 0x20) == 0x20)
+ && (urb->
+ iso_frame_desc[itd->index +
+ 5].status ==
+ 0)) {
+
+ urb->iso_frame_desc[itd->index +
+ 5].actual_length =
+ ((iso_ptd->
+ td_info7 & 0xF0000000) >> 28) |
+ ((iso_ptd->td_info8 &
+ 0x000000FF)
+ << 4);
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[5] = %d\n",
+ urb->
+ iso_frame_desc[itd->
+ index +
+ 5].actual_length);
+ } else {
+ urb->iso_frame_desc[itd->index +
+ 5].actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 6)
+ && ((itd->ssplit & 0x40) == 0x40)
+ && (urb->
+ iso_frame_desc[itd->index +
+ 6].status ==0)) {
+
+ urb->iso_frame_desc[itd->index +
+ 6].actual_length =
+ (iso_ptd->
+ td_info8 & 0x000FFF00)
+ >> 8;
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[6] = %d\n",
+ urb->
+ iso_frame_desc[itd->
+ index +
+ 6].actual_length);
+ } else {
+ urb->iso_frame_desc[itd->index +
+ 6].actual_length = 0;
+ }
+
+ if ((itd->num_of_pkts > 7)
+ && ((itd->ssplit & 0x80) == 0x80)
+ && (urb->
+ iso_frame_desc[itd->index +
+ 7].status ==
+ 0)) {
+
+ urb->iso_frame_desc[itd->index +
+ 7].actual_length =
+ (iso_ptd->
+ td_info8 & 0xFFF00000) >> 20;
+
+ iso_dbg(ISO_DBG_DATA,
+ "actual length[7] = %d\n",
+ urb->
+ iso_frame_desc[itd->
+ index +
+ 7].actual_length);
+ } else {
+ urb->iso_frame_desc[itd->index +
+ 7].actual_length = 0;
+ }
+ }
+ /* Check if this is the last ITD either due to some error or normal completion */
+ if ((td_ptd_map->lasttd)
+ || (itd->hw_next == EHCI_LIST_END)) {
+
+ last_td = TRUE;
+
+ }
+
+ /* Copy data to/from */
+ if (length && (length <= MAX_PTD_BUFFER_SIZE)) {
+ switch (PTD_PID(iso_ptd->td_info2)) {
+ case IN_PID:
+ /*
+ * Get the data from the PAYLOAD area and place it into
+ * the buffer provided by the requestor.
+ */
+ /*for first packet*/
+ startAdd = mem_addr->phy_addr;
+ iso_dbg(ISO_DBG_DATA,
+ "start add = %ld hw_bufp[0] = 0x%08x length = %d\n",
+ startAdd,
+ itd->hw_bufp[0],
+ urb->
+ iso_frame_desc[itd->
+ index].actual_length);
+ if (urb->
+ iso_frame_desc[itd->index].
+ status == 0) {
+
+ if (itd->hw_bufp[0] ==0) {
+ dma_addr_t
+ buff_dma;
+
+ buff_dma =
+ (u32) ((unsigned char *) urb->transfer_buffer +
+ urb->iso_frame_desc[itd->index].offset);
+ itd->buf_dma =
+ buff_dma;
+ itd->hw_bufp[0]
+ =
+ buff_dma;
+ }
+ if (itd->hw_bufp[0] !=0) {
+
+ ret = isp1763_mem_read(hcd->dev, (unsigned long)
+ startAdd,
+ 0,(u32*)itd->
+ hw_bufp[0],
+ urb->
+ iso_frame_desc
+ [itd->
+ index].
+ actual_length,
+ 0);
+
+ } else {
+ printk("isp1763_mem_read data payload fail\n");
+ printk("start add = %ld hw_bufp[0] = 0x%08x length = %d\n",
+ startAdd, itd->hw_bufp[0],
+ urb->iso_frame_desc[itd->index].actual_length);
+ urb->iso_frame_desc[itd->index].status = -EPROTO;
+ urb->error_count++;
+ }
+ }
+
+
+ for (i = 1;
+ i < itd->num_of_pkts;
+ i++) {
+ startAdd +=
+ (unsigned
+ long) (urb->
+ iso_frame_desc
+ [itd->
+ index +
+ i - 1].
+ actual_length);
+
+ iso_dbg(ISO_DBG_DATA,
+ "start add = %ld hw_bufp[%d] = 0x%08x length = %d\n",
+ startAdd, i,
+ itd->hw_bufp[i],
+ urb->
+ iso_frame_desc
+ [itd->index +
+ i].
+ actual_length);
+ if (urb->
+ iso_frame_desc[itd->
+ index + i].
+ status == 0) {
+
+ isp1763_mem_read
+ (hcd->dev,
+ startAdd,
+ 0,(u32*)
+ itd->
+ hw_bufp
+ [i],urb->
+ iso_frame_desc
+ [itd->
+ index + i].
+ actual_length,
+ 0);
+
+ if (ret == -EINVAL){
+ printk("isp1763_mem_read data payload fail %d\n", i);
+ }
+ }
+ }
+
+ case OUT_PID:
+ /*
+ * urb->actual length was initialized to zero, so for the first
+ * uFrame having it incremented immediately is not a problem.
+ */
+ urb->actual_length += length;
+ break;
+ } /* switch(PTD_PID(iso_ptd->td_info2)) */
+ }
+
+ /* if(length && (length <= MAX_PTD_BUFFER_SIZE)) */
+// removeitd:
+ /*read skip-map */
+ skipmap =
+ isp1763_reg_read16(hcd->dev,
+ hcd->regs.isotdskipmap,
+ skipmap);
+
+ iso_dbg(ISO_DBG_DATA,
+ "[%s] : read skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+ if (last_td == TRUE) {
+ /* Start removing the ITDs in the list */
+ while (1) {
+ /*
+ * This indicates that we are processing the tail PTD.
+ * Perform cleanup procedure on this last PTD
+ */
+ if (itd->hw_next ==
+ EHCI_LIST_END) {
+ td_ptd_map =
+ &ptd_map_buff->
+ map_list[itd->
+ itd_index];
+
+ /*
+ * Free up our allocation in the PAYLOAD area so that others can use
+ * it.
+ */
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free(&itd->
+ mem_addr);
+#endif
+
+ /* Remove this ITD entry in the ITD list */
+ list_del(&itd->
+ itd_list);
+
+ /* Free up the memory allocated for the ITD structure */
+ qha_free(qha_cache,
+ itd);
+
+ /* Indicate that the PTD we have used is now free */
+ td_ptd_map->state =
+ TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+
+ /* Decrease the number of active PTDs scheduled */
+ hcd->periodic_sched--;
+
+ /* Skip this PTD during the next PTD processing. */
+ skipmap |=
+ td_ptd_map->
+ ptd_bitmap;
+
+ isp1763_reg_write16
+ (hcd->dev,
+ hcd->regs.
+ isotdskipmap,
+ skipmap);
+
+ /* All ITDs in this list have been successfully removed. */
+ break;
+ }
+ /* if(itd->hw_next == EHCI_LIST_END) */
+ /*
+ * This indicates that we stopped due to an error on a PTD that is
+ * not the last in the list. We need to free up this PTD as well as
+ * the PTDs after it.
+ */
+ else {
+ /*
+ * Put the current ITD error onto this variable.
+ * We will be unlinking this from the list and free up its
+ * resources later.
+ */
+ current_itd = itd;
+
+ td_ptd_map =
+ &ptd_map_buff->
+ map_list[itd->
+ itd_index];
+
+ /*
+ * Get the next ITD, and place it to the itd variable.
+ * In a way we are moving forward in the ITD list.
+ */
+ itd = (struct ehci_itd
+ *) (current_itd->
+ hw_next);
+#ifndef COMMON_MEMORY
+ /* Free up the current ITD's resources */
+ phci_hcd_mem_free
+ (&current_itd->
+ mem_addr);
+#endif
+
+ /* Remove this ITD entry in the ITD list */
+ list_del(&current_itd->
+ itd_list);
+
+ /* Free up the memory allocated for the ITD structure */
+ qha_free(qha_cache,
+ current_itd);
+
+ /* Inidicate that the PTD we have used is now free */
+ td_ptd_map->state =
+ TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+
+ /* Decrease the number of active PTDs scheduled */
+ hcd->periodic_sched--;
+
+ /* Sine it is done, skip this PTD during the next PTD processing. */
+ skipmap |=
+ td_ptd_map->
+ ptd_bitmap;
+ isp1763_reg_write16
+ (hcd->dev,
+ hcd->regs.
+ isotdskipmap,
+ skipmap);
+ /*
+ * Start all over again until it gets to the tail of the
+ * list of PTDs/ITDs
+ */
+ continue;
+ }/* else of if(itd->hw_next == EHCI_LIST_END) */
+ /* It should never get here, but I put this as a precaution */
+ break;
+ } /*end of while(1) */
+ /* Check if there were ITDs that were not processed due to the error */
+ if (urb->status == -EINPROGRESS) {
+ if ((urb->actual_length !=
+ urb->transfer_buffer_length)
+ && (urb->
+ transfer_flags &
+ URB_SHORT_NOT_OK)) {
+
+ iso_dbg(ISO_DBG_ERR,
+ "[pehci_hcd_iso_worker Error]: Short Packet\n");
+
+ urb->status =
+ -EREMOTEIO;
+ } else {
+ urb->status = 0;
+ }
+ }
+
+ urb->hcpriv = 0;
+ iso_dbg(ISO_DBG_DATA,
+ "[%s] : remain skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
+// if (urb->reject.counter) {
+ if (unlikely(atomic_read(&urb->reject))) {// kernel reference code hcd.c
+ iso_dbg("ISO_DBG_INFO, [%s] urb reject\n", __FUNCTION__);
+ iReject = 1;
+ }
+#else
+ if (unlikely(urb->reject)) {
+ iso_dbg("ISO_DBG_INFO, [%s] urb reject\n", __FUNCTION__);
+ iReject = 1;
+ }
+#endif
+
+/*
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,28)
+
+ if (urb->reject.counter) {
+ iso_dbg("ISO_DBG_INFO, [%s] urb reject\n", __FUNCTION__);
+ iReject = 1;
+ }
+#else
+ if (unlikely(urb->reject)) {
+
+
+ iso_dbg("ISO_DBG_INFO, [%s] urb reject\n", __FUNCTION__);
+ iReject = 1;
+ }
+#endif
+*/
+
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&qhead->memory_addr);
+#endif
+ /* We need to unlock this here, since this was locked when we are called */
+ /* from the interrupt handler */
+ spin_unlock(&hcd->lock);
+ /* Perform URB cleanup */
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker] Complete a URB\n");
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(!usb_hcd_check_unlink_urb(&hcd->usb_hcd, urb,0))
+ usb_hcd_unlink_urb_from_ep(&hcd->usb_hcd, urb);
+#endif
+ hcd->periodic_more_urb = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+ if (!list_empty(&qhead->ep->urb_list)){
+
+#else
+ if (!list_empty(&urb->ep->urb_list)){
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (urb->hcpriv== periodic_ep[0]){
+#else
+ if (urb->ep == periodic_ep[0]){
+#endif
+ hcd->periodic_more_urb =
+ 1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ } else if (urb->hcpriv==
+ periodic_ep[1]){
+#else
+ } else if (urb->ep ==
+ periodic_ep[1]){
+#endif
+ hcd->periodic_more_urb =
+ 2;
+ } else {
+ hcd->periodic_more_urb =
+ 0;
+ }
+
+
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb);
+#else
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb,
+ urb->status);
+#endif
+
+ spin_lock(&hcd->lock);
+ continue;
+ }
+ /* if( last_td == TRUE ) */
+ /*
+ * If the last_td is not set then we do not need to check for errors and directly
+ * proceed with the cleaning sequence.
+ */
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker]: last_td is not set\n");
+ /*update skipmap */
+ skipmap |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.isotdskipmap,
+ skipmap);
+ iso_dbg(ISO_DBG_DATA,
+ "%s : remain skipmap =0x%x\n",
+ __FUNCTION__, skipmap);
+
+ /* Decrement the count of active PTDs */
+ hcd->periodic_sched--;
+#ifndef COMMON_MEMORY
+ /* Free up the memory we allocated in the PAYLOAD area */
+ phci_hcd_mem_free(&itd->mem_addr);
+#endif
+ /* Remove this ITD from the list of active ITDs */
+ list_del(&itd->itd_list);
+
+ /* Free up the memory we allocated for the ITD structure */
+ qha_free(qha_cache, itd);
+ /*
+ * Clear the bit associated with this PTD from the grouptdmap and
+ * make this PTD available for other transfers
+ */
+ td_ptd_map->state = TD_PTD_NEW;
+ td_ptd_map->sitd = NULL;
+ td_ptd_map->itd = NULL;
+ } /*end of HIGH SPEED */
+ } /* end of list_for_each_safe(position, lst_temp, itd_remove) */
+ iso_dbg(ISO_DBG_INFO,
+ "[pehci_hcd_iso_worker]: ISO-Frame removal done\n");
+
+
+ } /* while donetoclear */
+
+
+ if (iReject) {
+ spin_unlock(&hcd->lock);
+ if (hcd->periodic_more_urb) {
+
+ if(periodic_ep[hcd->periodic_more_urb])
+ while (&periodic_ep[hcd->periodic_more_urb - 1]->
+ urb_list) {
+
+ urb = container_of(periodic_ep
+ [hcd->periodic_more_urb -
+ 1]->urb_list.next,
+ struct urb, urb_list);
+
+ if (urb) {
+ urb->status = -ENOENT;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(!usb_hcd_check_unlink_urb(&hcd->usb_hcd, urb,0))
+ usb_hcd_unlink_urb_from_ep(&hcd->
+ usb_hcd,urb);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb);
+#else
+ usb_hcd_giveback_urb(&hcd->usb_hcd, urb,
+ urb->status);
+#endif
+ }
+ }
+ }
+
+ spin_lock(&hcd->lock);
+ }
+
+ /* When there is no more PTDs queued for scheduling or removal
+ * clear the buffer status to indicate there are no more PTDs for
+ * processing and set the skip map to 1 to indicate that the first
+ * PTD is also the last PTD.
+ */
+
+ if (hcd->periodic_more_urb) {
+ int status = 0;
+ iso_dbg(ISO_DBG_INFO,
+ "[phcd_iso_handler]: No more PTDs queued\n");
+ hcd->periodic_sched = 0;
+ phcd_store_urb_pending(hcd, hcd->periodic_more_urb, NULL,
+ &status);
+ hcd->periodic_more_urb = 0;
+ }
+exit:
+ iso_dbg(ISO_DBG_ENTRY, "-- %s: Exit\n", __FUNCTION__);
+} /* end of pehci_hcd_iso_worker */
+
+#endif /* CONFIG_ISO_SUPPORT */
+
+/*interrupt transfer handler*/
+/********************************************************
+ 1. read done map
+ 2. read the ptd to see any errors
+ 3. copy the payload to and from
+ 4. update ehci td
+ 5. make new ptd if transfer there and earlier done
+ 6. schedule
+ *********************************************************/
+static void
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+pehci_hcd_intl_worker(phci_hcd * hcd, struct pt_regs *regs)
+#else
+pehci_hcd_intl_worker(phci_hcd * hcd)
+#endif
+{
+ int i = 0;
+ u16 donemap = 0, donetoclear;
+ u16 mask = 0x1, index = 0;
+ u16 pendingmap = 0;
+ u16 location = 0;
+ u32 length = 0;
+ u16 skipmap = 0;
+ u16 ormask = 0;
+ u32 usofstatus = 0;
+ struct urb *urb;
+ struct ehci_qtd *qtd = 0;
+ struct ehci_qh *qh = 0;
+
+ struct _isp1763_qhint *qhint = &hcd->qhint;
+
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct isp1763_mem_addr *mem_addr = 0;
+ u16 dontschedule = 0;
+
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL]);
+ pendingmap = ptd_map_buff->pending_ptd_bitmap;
+
+ /*read the done map for interrupt transfers */
+ donetoclear = donemap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttddonemap, donemap);
+ if (donemap) {
+ /*skip done tds */
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+ skipmap |= donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap, skipmap);
+ donemap |= pendingmap;
+ }
+ /*if sof interrupt is enabled */
+#ifdef MSEC_INT_BASED
+ else {
+ /*if there is something pending , put this transfer in */
+ if (ptd_map_buff->pending_ptd_bitmap) {
+ pehci_hcd_schedule_pending_ptds(hcd, pendingmap, (u8)
+ TD_PTD_BUFF_TYPE_INTL,
+ 1);
+ }
+ //return 0;
+ goto exit;
+ }
+#else
+ else {
+ goto exit;
+ //return 0;
+ }
+
+#endif
+
+
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.int_irq_mask_or,
+ ormask);
+ /*process all the endpoints first those are done */
+ donetoclear = donemap;
+ while (donetoclear) {
+ /*index is the number of endpoints open currently */
+ index = donetoclear & mask;
+ donetoclear &= ~mask;
+ mask <<= 1;
+ /*what if we are in the middle of schedule
+ where nothing is done */
+ if (!index) {
+ location++;
+ continue;
+ }
+
+ /*read our td_ptd_map */
+ td_ptd_map = &ptd_map_buff->map_list[location];
+
+ /*if this one is already in the removal */
+ if (td_ptd_map->state == TD_PTD_REMOVE ||
+ td_ptd_map->state == TD_PTD_NEW) {
+ pehci_check("interrupt td is being removed\n");
+ /*this will be handled by urb_remove */
+ /*if this is last urb no need to complete it again */
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ /*if there is something pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ continue;
+ }
+
+
+ /*if we found something already in */
+ if (!(skipmap & td_ptd_map->ptd_bitmap)) {
+ pehci_check("intr td_ptd_map %x,skipnap %x\n",
+ td_ptd_map->ptd_bitmap, skipmap);
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;;
+ location++;
+ continue;
+ }
+
+
+ if (td_ptd_map->state == TD_PTD_NEW) {
+ pehci_check
+ ("interrupt not come here, map %x,location %d\n",
+ td_ptd_map->ptd_bitmap, location);
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ location++;
+ continue;
+ }
+
+ /*move to the next schedule */
+ location++;
+ /*endpoint, td, urb and memory
+ * for current transfer*/
+ qh = td_ptd_map->qh;
+ qtd = td_ptd_map->qtd;
+ if (qtd->state & QTD_STATE_NEW) {
+ /*we need to schedule it */
+ goto schedule;
+ }
+ urb = qtd->urb;
+ mem_addr = &qtd->mem_addr;
+
+ /*clear the irq mask for this transfer */
+ ormask &= ~td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_or,
+ ormask);
+
+ ptd_map_buff->active_ptds--;
+ memset(qhint, 0, sizeof(struct _isp1763_qhint));
+
+ /*read this ptd from the ram address,address is in the
+ td_ptd_map->ptd_header_addr */
+ isp1763_mem_read(hcd->dev, td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qhint), PHCI_QHA_LENGTH, 0);
+
+#ifdef PTD_DUMP_COMPLETE
+ printk("INTL PTD header after COMPLETION\n");
+ printk("CDW0: 0x%08X\n", qhint->td_info1);
+ printk("CDW1: 0x%08X\n", qhint->td_info2);
+ printk("CDW2: 0x%08X\n", qhint->td_info3);
+ printk("CDW3: 0x%08X\n", qhint->td_info4);
+#endif
+
+ /*statuc of 8 uframes */
+ for (i = 0; i < 8; i++) {
+ /*take care of errors */
+ usofstatus = qhint->td_info5 >> (8 + i * 3);
+ switch (usofstatus & 0x7) {
+ case INT_UNDERRUN:
+ pehci_print("under run , %x\n", usofstatus);
+ break;
+ case INT_EXACT:
+ pehci_print("transaction error, %x\n",
+ usofstatus);
+ break;
+ case INT_BABBLE:
+ pehci_print("babble error, %x\n", usofstatus);
+ break;
+ }
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /*length is 1K for full/low speed device */
+ length = PTD_XFERRED_NONHSLENGTH(qhint->td_info4);
+ } else {
+ /*length is 32K for high speed device */
+ length = PTD_XFERRED_LENGTH(qhint->td_info4);
+ }
+
+ pehci_hcd_update_error_status(qhint->td_info4, urb);
+ /*halted, need to finish all the transfer on this endpoint */
+ if (qhint->td_info4 & PTD_STATUS_HALTED) {
+ qtd->state |= QTD_STATE_LAST;
+ /*in case of halt, next transfer will start with toggle zero,
+ *USB speck, 5.8.5*/
+ qh->datatoggle = td_ptd_map->datatoggle = 0;
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ dontschedule = 1;
+ goto copylength;
+ }
+
+
+ copylength:
+ /*preserve the current data toggle */
+ qh->datatoggle = td_ptd_map->datatoggle =
+ PTD_NEXTTOGGLE(qhint->td_info4);
+ /*copy data from the host */
+ switch (PTD_PID(qhint->td_info2)) {
+ case IN_PID:
+ if (length && (length <= MAX_PTD_BUFFER_SIZE))
+ /*do read only when there is somedata */
+ isp1763_mem_read(hcd->dev,
+ (u32) mem_addr->phy_addr, 0,
+ urb->transfer_buffer +
+ urb->actual_length, length, 0);
+
+ case OUT_PID:
+ urb->actual_length += length;
+ qh->hw_current = qtd->hw_next;
+ phci_hcd_mem_free(&qtd->mem_addr);
+ qtd->state &= ~QTD_STATE_NEW;
+ qtd->state |= QTD_STATE_DONE;
+ break;
+ }
+
+ if (qtd->state & QTD_STATE_LAST) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map, regs);
+#else
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map);
+#endif
+ if (dontschedule) { /*cleanup will start from drivers */
+ dontschedule = 0;
+ continue;
+ }
+
+ /*take the next if in the queue */
+ if (!list_empty(&qh->qtd_list)) {
+ struct list_head *head;
+ /*last td of previous urb */
+ head = &qh->qtd_list;
+ qtd = list_entry(head->next, struct ehci_qtd,
+ qtd_list);
+ td_ptd_map->qtd = qtd;
+ qh->hw_current = cpu_to_le32(qtd);
+ qh->qh_state = QH_STATE_LINKED;
+
+ } else {
+ td_ptd_map->qtd =
+ (struct ehci_qtd *) le32_to_cpu(0);
+ qh->hw_current = cpu_to_le32(0);
+ qh->qh_state = QH_STATE_IDLE;
+ donemap &= ~td_ptd_map->ptd_bitmap;
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ td_ptd_map->state=TD_PTD_NEW;
+ continue;
+ }
+
+ }
+
+ schedule:
+ {
+ /*current td comes from qh->hw_current */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ~td_ptd_map->ptd_bitmap;
+ ormask |= td_ptd_map->ptd_bitmap;
+ ptd_map_buff->active_ptds++;
+ pehci_check
+ ("inter schedule next qtd %p, active tds %d\n",
+ qtd, ptd_map_buff->active_ptds);
+ pehci_hcd_qtd_schedule(hcd, qtd, qh, td_ptd_map);
+ }
+
+ } /*end of while */
+
+
+ /*clear all the tds inside this routine */
+ skipmap &= ~donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap, skipmap);
+ ormask |= donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_or, ormask);
+exit:
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+
+// return (int)0;
+}
+
+/*atl(bulk/control) transfer handler*/
+/*1. read done map
+ 2. read the ptd to see any errors
+ 3. copy the payload to and from
+ 4. update ehci td
+ 5. make new ptd if transfer there and earlier done
+ 6. schedule
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static void
+pehci_hcd_atl_worker(phci_hcd * hcd, struct pt_regs *regs)
+#else
+static void
+pehci_hcd_atl_worker(phci_hcd * hcd)
+#endif
+{
+ u16 donemap = 0, donetoclear = 0;
+ u16 pendingmap = 0;
+ u32 rl = 0;
+ u16 mask = 0x1, index = 0;
+ u16 location = 0;
+ u32 nakcount = 0;
+ u32 active = 0;
+ u32 length = 0;
+ u16 skipmap = 0;
+ u16 tempskipmap = 0;
+ u16 ormask = 0;
+ struct urb *urb;
+ struct ehci_qtd *qtd = 0;
+ struct ehci_qh *qh;
+ struct _isp1763_qha atlqha;
+ struct _isp1763_qha *qha;
+ td_ptd_map_t *td_ptd_map;
+ td_ptd_map_buff_t *ptd_map_buff;
+ urb_priv_t *urbpriv = 0;
+ struct isp1763_mem_addr *mem_addr = 0;
+ u16 dontschedule = 0;
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL]);
+ pendingmap = ptd_map_buff->pending_ptd_bitmap;
+
+#ifdef MSEC_INT_BASED
+ /*running on skipmap rather donemap,
+ some cases donemap may not be set
+ for complete transfer
+ */
+ skipmap = isp1763_reg_read16(hcd->dev, hcd->regs.atltdskipmap, skipmap);
+ tempskipmap = ~skipmap;
+ tempskipmap &= 0xffff;
+
+ if (tempskipmap) {
+ donemap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atltddonemap,
+ donemap);
+ skipmap |= donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap, skipmap);
+ qha = &atlqha;
+ donemap |= pendingmap;
+ tempskipmap &= ~donemap;
+ } else {
+
+ /*if sof interrupt enabled */
+
+ /*if there is something pending , put this transfer in */
+ if (pendingmap) {
+ pehci_hcd_schedule_pending_ptds(hcd, pendingmap, (u8)
+ TD_PTD_BUFF_TYPE_ATL,
+ 1);
+ }
+ goto exit;
+ }
+#else
+
+ donemap = isp1763_reg_read16(hcd->dev, hcd->regs.atltddonemap, donemap);
+ if (donemap) {
+
+
+ pehci_info("DoneMap Value in ATL Worker %x\n", donemap);
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+ skipmap |= donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap, skipmap);
+ qha = &atlqha;
+ } else {
+ pehci_info("Done Map Value is 0x%X \n", donemap);
+ pehci_entry("-- %s: Exit abnormally with DoneMap all zero \n",
+ __FUNCTION__);
+ goto exit;
+
+ }
+#endif
+
+ /*read the interrupt mask registers */
+ ormask = isp1763_reg_read16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+
+
+ /*this map is used only to update and
+ * scheduling for the tds who are not
+ * complete. the tds those are complete
+ * new schedule will happen from
+ * td_ptd_submit_urb routine
+ * */
+ donetoclear = donemap;
+ /*we will be processing skipped tds also */
+ donetoclear |= tempskipmap;
+ /*process all the endpoints first those are done */
+ while (donetoclear) {
+ /*index is the number of endpoint open currently */
+ index = donetoclear & mask;
+ donetoclear &= ~mask;
+ mask <<= 1;
+ /*what if we are in the middle of schedule
+ where nothing is done
+ */
+ if (!index) {
+ location++;
+ continue;
+ }
+
+ /*read our td_ptd_map */
+ td_ptd_map = &ptd_map_buff->map_list[location];
+
+ /*urb is in remove */
+ if (td_ptd_map->state == TD_PTD_NEW ||
+ td_ptd_map->state == TD_PTD_REMOVE) {
+ pehci_check
+ ("atl td is being removed,map %x, skipmap %x\n",
+ td_ptd_map->ptd_bitmap, skipmap);
+ pehci_check("temp skipmap %x, pendign map %x,done %x\n",
+ tempskipmap, pendingmap, donemap);
+
+ /*unlink urb will take care of this */
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ location++;
+ continue;
+ }
+
+
+ /*move to the next endpoint */
+ location++;
+ /*endpoint, td, urb and memory
+ * for current endpoint*/
+ qh = td_ptd_map->qh;
+ qtd = td_ptd_map->qtd;
+ if (!qh || !qtd) {
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ continue;
+ }
+#ifdef MSEC_INT_BASED
+ /*new td must be scheduled */
+ if ((qtd->state & QTD_STATE_NEW) /*&&
+ (pendingmap & td_ptd_map->ptd_bitmap) */ ) {
+ /*this td will come here first time from
+ *pending tds, so its qh->hw_current needs to
+ * adjusted
+ */
+ qh->hw_current = QTD_NEXT(qtd->qtd_dma);
+ goto schedule;
+ }
+#endif
+ urb = qtd->urb;
+ if (urb == NULL) {
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ continue;
+ }
+ urbpriv = (urb_priv_t *) urb->hcpriv;
+ mem_addr = &qtd->mem_addr;
+
+#ifdef MSEC_INT_BASED
+ /*check here for the td if its done */
+ if (donemap & td_ptd_map->ptd_bitmap) {
+ /*nothing to do */
+ ;
+ } else {
+ /*if td is not done, lets check how long
+ its been scheduled
+ */
+ if (tempskipmap & td_ptd_map->ptd_bitmap) {
+ /*i will give 20 msec to complete */
+ if (urbpriv->timeout < 20) {
+ urbpriv->timeout++;
+ continue;
+ }
+ urbpriv->timeout++;
+ /*otherwise check its status */
+ }
+
+ }
+#endif
+ memset(qha, 0, sizeof(struct _isp1763_qha));
+
+ /*read this ptd from the ram address,address is in the
+ td_ptd_map->ptd_header_addr */
+ isp1763_mem_read(hcd->dev, td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH, 0);
+
+#ifdef PTD_DUMP_COMPLETE
+ printk("ATL PTD header after COMPLETION\n");
+ printk("CDW0: 0x%08X\n", qha->td_info1);
+ printk("CDW1: 0x%08X\n", qha->td_info2);
+ printk("CDW2: 0x%08X\n", qha->td_info3);
+ printk("CDW3: 0x%08X\n", qha->td_info4);
+#endif
+
+#ifdef MSEC_INT_BASED
+ /*since we are running on skipmap
+ tds will be checked for completion state
+ */
+ if ((qha->td_info1 & QHA_VALID)) {
+
+ pehci_check
+ ("pendign map %x, donemap %x, tempskipmap %x\n",
+ pendingmap, donemap, tempskipmap);
+ /*this could be one of the unprotected urbs, clear it */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*here also we need to increment the tds timeout count */
+ urbpriv->timeout++;
+ continue;
+ } else {
+ /*this td is going to be done,
+ this td could be the one un-skipped but no donemap or
+ maybe it could be one of those where we get unprotected urbs,
+ so checking against tempskipmap may not give us correct td
+ */
+
+ skipmap |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+
+ /*of course this is going to be as good
+ as td that is done and donemap is set
+ also skipmap is set
+ */
+ donemap |= td_ptd_map->ptd_bitmap;
+ }
+#endif
+ /*clear the corrosponding mask register */
+ ormask &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+
+ ptd_map_buff->active_ptds--;
+
+ urbpriv->timeout = 0;
+
+ /*take care of errors */
+ pehci_hcd_update_error_status(qha->td_info4, urb);
+ /*halted, need to finish all the transfer on this endpoint */
+ if (qha->td_info4 & PTD_STATUS_HALTED) {
+
+ printk(KERN_NOTICE "Endpoint is halted\n");
+ qtd->state |= QTD_STATE_LAST;
+
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*in case pending */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*in case of halt, next transfer will start with toggle
+ zero,USB speck, 5.8.5 */
+ qh->datatoggle = td_ptd_map->datatoggle = 0;
+ /*cleanup the ping */
+ qh->ping = 0;
+ /*force cleanup after this */
+ dontschedule = 1;
+ goto copylength;
+ }
+
+
+
+ /*read the reload count */
+ rl = (qha->td_info3 >> 23);
+ rl &= 0xf;
+
+
+
+ /*if there is a transaction error and the status is not halted,
+ * process whatever the length we got.if the length is what we
+ * expected complete the transfer*/
+ if ((qha->td_info4 & PTD_XACT_ERROR) &&
+ !(qha->td_info4 & PTD_STATUS_HALTED) &&
+ (qha->td_info4 & QHA_ACTIVE)) {
+
+ if (PTD_XFERRED_LENGTH(qha->td_info4) == qtd->length) {
+ ; /*nothing to do its fake */
+ } else {
+
+ pehci_print
+ ("xact error, info1 0x%08x,info4 0x%08x\n",
+ qha->td_info1, qha->td_info4);
+
+ /*if this is the case then we need to
+ resubmit the td again */
+ qha->td_info1 |= QHA_VALID;
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ ormask |= td_ptd_map->ptd_bitmap;
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+
+ /*set the retry count to 3 again */
+ qha->td_info4 |= (rl << 19);
+ /*set the active bit, if cleared, will be cleared if we have some length */
+ qha->td_info4 |= QHA_ACTIVE;
+
+ /*clear the xact error */
+ qha->td_info4 &= ~PTD_XACT_ERROR;
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.atl_irq_mask_or,
+ ormask);
+
+ /*copy back into the header, payload is already
+ * present no need to write again
+ */
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->ptd_header_addr,
+ 0, (u32 *) (qha),
+ PHCI_QHA_LENGTH, 0);
+ /*unskip this td */
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.atltdskipmap,
+ skipmap);
+ continue;
+ }
+ goto copylength;
+ }
+
+ /*check for the nak count and active condition
+ * to reload the ptd if needed*/
+ nakcount = qha->td_info4 >> 19;
+ nakcount &= 0xf;
+ active = qha->td_info4 & QHA_ACTIVE;
+ /*if nak count is zero and active bit is set , it
+ *means that device is naking and need to reload
+ *the same td*/
+ if (!nakcount && active) {
+ pehci_info("%s: ptd is going for reload,length %d\n",
+ __FUNCTION__, length);
+ /*make this td valid */
+ qha->td_info1 |= QHA_VALID;
+ donemap &= ((~td_ptd_map->ptd_bitmap & 0xffff));
+ /*just like fresh td */
+
+ /*set the retry count to 3 again */
+ qha->td_info4 |= (rl << 19);
+ qha->td_info4 &= ~0x3;
+ qha->td_info4 |= (0x2 << 23);
+ ptd_map_buff->active_ptds++;
+ skipmap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ ormask |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or,
+ ormask);
+ /*copy back into the header, payload is already
+ * present no need to write again */
+ isp1763_mem_write(hcd->dev, td_ptd_map->ptd_header_addr,
+ 0, (u32 *) (qha), PHCI_QHA_LENGTH, 0);
+ /*unskip this td */
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+ continue;
+ }
+
+ copylength:
+ /*read the length transferred */
+ length = PTD_XFERRED_LENGTH(qha->td_info4);
+
+
+ /*short complete in case of BULK only */
+ if ((length < qtd->length) && usb_pipebulk(urb->pipe)) {
+
+ /*if current ptd is not able to fetech enough data as
+ * been asked then device has no data, so complete this transfer
+ * */
+ /*can we complete our transfer here */
+ if ((urb->transfer_flags & URB_SHORT_NOT_OK)) {
+ pehci_check
+ ("short read, length %d(expected %d)\n",
+ length, qtd->length);
+ urb->status = -EREMOTEIO;
+ /*if this is the only td,donemap will be cleared
+ at completion, otherwise take the next one
+ */
+ donemap &= ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ /*force the cleanup from here */
+ dontschedule = 1;
+ }
+
+ /*this will be the last td,in case of short read/write */
+ /*donemap, pending maps will be handled at the while scheduling or completion */
+ qtd->state |= QTD_STATE_LAST;
+
+ }
+ /*preserve the current data toggle */
+ qh->datatoggle = td_ptd_map->datatoggle =
+ PTD_NEXTTOGGLE(qha->td_info4);
+ qh->ping = PTD_PING_STATE(qha->td_info4);
+ /*copy data from */
+ switch (PTD_PID(qha->td_info2)) {
+ case IN_PID:
+ qh->ping = 0;
+ /*do read only when there is some data */
+ if (length && (length <= HC_ATL_PL_SIZE)) {
+ isp1763_mem_read(hcd->dev,
+ (u32) mem_addr->phy_addr, 0,
+ (u32*) (le32_to_cpu(qtd->hw_buf[0])), length, 0);
+#if 0
+ // printk("IN PayLoad length:%d\n", length);
+ if(length<=4) {
+ int i=0;
+ int *data_addr= qtd->hw_buf[0];
+ printk("\n");
+ for(i=0;i<length;i+=4) printk("[0x%X] ",*data_addr++);
+ printk("\n");
+ }
+#endif
+ }
+
+ case OUT_PID:
+ urb->actual_length += length;
+ qh->hw_current = qtd->hw_next;
+ phci_hcd_mem_free(&qtd->mem_addr);
+ qtd->state |= QTD_STATE_DONE;
+
+ break;
+ case SETUP_PID:
+ qh->hw_current = qtd->hw_next;
+ phci_hcd_mem_free(&qtd->mem_addr);
+ qtd->state |= QTD_STATE_DONE;
+ break;
+ }
+
+ if (qtd->state & QTD_STATE_LAST) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map, regs);
+#else
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map);
+#endif
+ if (dontschedule) { /*cleanup will start from drivers */
+ dontschedule = 0;
+ /*so that we can take next one */
+ qh->qh_state = QH_STATE_TAKE_NEXT;
+ continue;
+ }
+ /*take the next if in the queue */
+ if (!list_empty(&qh->qtd_list)) {
+ struct list_head *head;
+ /*last td of previous urb */
+ head = &qh->qtd_list;
+ qtd = list_entry(head->next, struct ehci_qtd,
+ qtd_list);
+ td_ptd_map->qtd = qtd;
+ qh->hw_current = cpu_to_le32(qtd);
+ qh->qh_state = QH_STATE_LINKED;
+
+ } else {
+ td_ptd_map->qtd =
+ (struct ehci_qtd *) le32_to_cpu(0);
+ qh->hw_current = cpu_to_le32(0);
+ qh->qh_state = QH_STATE_TAKE_NEXT;
+ donemap &= ((~td_ptd_map->ptd_bitmap & 0xffff));
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ continue;
+ }
+ }
+
+#ifdef MSEC_INT_BASED
+ schedule:
+#endif
+ {
+ /*current td comes from qh->hw_current */
+ ptd_map_buff->pending_ptd_bitmap &=
+ ((~td_ptd_map->ptd_bitmap) & 0xffff);
+ td_ptd_map->qtd =
+ (struct ehci_qtd
+ *) (le32_to_cpu(qh->hw_current));
+ qtd = td_ptd_map->qtd;
+ ormask |= td_ptd_map->ptd_bitmap;
+ ptd_map_buff->active_ptds++;
+ pehci_hcd_qtd_schedule(hcd, qtd, qh, td_ptd_map);
+ }
+
+ } /*end of while */
+
+/*clear all the tds inside this routine*/
+ skipmap &= ((~donemap) & 0xffff);
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap, skipmap);
+ ormask |= donemap;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or, ormask);
+exit:
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+
+/*--------------------------------------------------------*
+ root hub functions
+ *--------------------------------------------------------*/
+
+/*return root hub descriptor, can not fail*/
+static void
+pehci_hub_descriptor(phci_hcd * hcd, struct usb_hub_descriptor *desc)
+{
+ u32 ports = 0;
+ u16 temp = 0;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ ports = 0x11;
+ ports = ports & 0xf;
+
+ pehci_info("%s: number of ports %d\n", __FUNCTION__, ports);
+
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = 10;
+
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+
+// memset(&desc->DeviceRemovable[0], 0, temp);
+// memset(&desc->PortPwrCtrlMask[temp], 0xff, temp);
+ memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+ memset(&desc->u.hs.PortPwrCtrlMask[temp], 0xff, temp);
+
+
+ temp = 0x0008; /* per-port overcurrent reporting */
+ temp |= 0x0001; /* per-port power control */
+ temp |= 0x0080; /* per-port indicators (LEDs) */
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+
+/*after reset on root hub,
+ * device high speed or non-high speed
+ * */
+static int
+phci_check_reset_complete(phci_hcd * hcd, int index, int port_status)
+{
+ pehci_print("check reset complete\n");
+ if (!(port_status & PORT_CONNECT)) {
+ hcd->reset_done[index] = 0;
+ return port_status;
+ }
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+ printk("port %d full speed --> companion\n", index + 1);
+ port_status |= PORT_OWNER;
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[index],
+ port_status);
+
+ } else {
+ pehci_print("port %d high speed\n", index + 1);
+ }
+
+ return port_status;
+
+}
+
+/*----------------------------------------------*
+ host controller initialization, removal functions
+ *----------------------------------------------*/
+
+
+/*initialize all three buffer(iso/atl/int) type headers*/
+static void
+pehci_hcd_init_map_buffers(phci_hcd * phci)
+{
+ td_ptd_map_buff_t *ptd_map_buff;
+ u8 buff_type, ptd_index;
+ u32 bitmap;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ pehci_print("phci_init_map_buffers(phci = 0x%p)\n", phci);
+ /* initialize for each buffer type */
+ for (buff_type = 0; buff_type < TD_PTD_TOTAL_BUFF_TYPES; buff_type++) {
+ ptd_map_buff = &(td_ptd_map_buff[buff_type]);
+ ptd_map_buff->buffer_type = buff_type;
+ ptd_map_buff->active_ptds = 0;
+ ptd_map_buff->total_ptds = 0;
+ /*each bufer type can have atleast 32 ptds */
+ ptd_map_buff->max_ptds = 16;
+ ptd_map_buff->active_ptd_bitmap = 0;
+ /*everything skipped */
+ /*nothing is pending */
+ ptd_map_buff->pending_ptd_bitmap = 0x00000000;
+
+ /* For each ptd index of this buffer, set the fiedls */
+ bitmap = 0x00000001;
+ for (ptd_index = 0; ptd_index < TD_PTD_MAX_BUFF_TDS;
+ ptd_index++) {
+ /*datatoggle zero */
+ ptd_map_buff->map_list[ptd_index].datatoggle = 0;
+ /*td state is not used */
+ ptd_map_buff->map_list[ptd_index].state = TD_PTD_NEW;
+ /*no endpoint, no qtd */
+ ptd_map_buff->map_list[ptd_index].qh = NULL;
+ ptd_map_buff->map_list[ptd_index].qtd = NULL;
+ ptd_map_buff->map_list[ptd_index].ptd_header_addr =
+ 0xFFFF;
+ } /* for( ptd_index */
+ } /* for(buff_type */
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+} /* phci_init_map_buffers */
+
+
+/*put the host controller into operational mode
+ * called phci_hcd_start routine,
+ * return 0, success else
+ * timeout, fails*/
+
+static int
+pehci_hcd_start_controller(phci_hcd * hcd)
+{
+ u32 temp = 0;
+ u32 command = 0;
+ int retval = 0;
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ printk(KERN_NOTICE "++ %s: Entered\n", __FUNCTION__);
+
+
+ command = isp1763_reg_read16(hcd->dev, hcd->regs.command, command);
+ printk(KERN_NOTICE "HC Command Reg val ...1 %x\n", command);
+
+ /*initialize the host controller */
+ command |= CMD_RUN;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.command, command);
+
+
+ command &= 0;
+
+ command = isp1763_reg_read16(hcd->dev, hcd->regs.command, command);
+ printk(KERN_NOTICE "HC Command Reg val ...2 %x\n", command);
+
+ /*should be in operation in 1000 usecs */
+ if ((retval =
+ pehci_hcd_handshake(hcd, hcd->regs.command, CMD_RUN, CMD_RUN,
+ 100000))) {
+ err("Host is not up(CMD_RUN) in 1000 usecs\n");
+ return retval;
+ }
+
+ printk(KERN_NOTICE "ISP1763 HC is running \n");
+
+
+ /*put the host controller to ehci mode */
+ command &= 0;
+ command |= 1;
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.configflag, command);
+ mdelay(5);
+
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.configflag, temp);
+ pehci_print("%s: Config Flag reg value: 0x%08x\n", __FUNCTION__, temp);
+
+ /*check if ehci mode switching is correct or not */
+ if ((retval =
+ pehci_hcd_handshake(hcd, hcd->regs.configflag, 1, 1, 100))) {
+ err("Host is not into ehci mode in 100 usecs\n");
+ return retval;
+ }
+
+ mdelay(5);
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ printk(KERN_NOTICE "-- %s: Exit\n", __FUNCTION__);
+ return retval;
+}
+
+
+/*enable the interrupts
+ *called phci_1763_start routine
+ * return void*/
+static void
+pehci_hcd_enable_interrupts(phci_hcd * hcd)
+{
+ u32 temp = 0;
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ printk(KERN_NOTICE "++ %s: Entered\n", __FUNCTION__);
+ /*disable the interrupt source */
+ temp &= 0;
+ /*clear all the interrupts that may be there */
+ temp |= INTR_ENABLE_MASK;
+ isp1763_reg_write16(hcd->dev, hcd->regs.interrupt, temp);
+
+ /*enable interrupts */
+ temp = 0;
+
+#ifdef OTG_PACKAGE
+ temp |= INTR_ENABLE_MASK | HC_OTG_INT;
+#else
+ temp |= INTR_ENABLE_MASK;
+#endif
+ pehci_print("%s: enabled mask 0x%08x\n", __FUNCTION__, temp);
+ isp1763_reg_write16(hcd->dev, hcd->regs.interruptenable, temp);
+
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.interruptenable, temp);
+ pehci_print("%s: Intr enable reg value: 0x%08x\n", __FUNCTION__, temp);
+
+#ifdef HCD_PACKAGE
+ temp = 0;
+ temp = isp1763_reg_read32(hcd->dev, HC_INT_THRESHOLD_REG, temp);
+// temp |= 0x0800000F;
+ temp |= 0x0100000F;//125 micro second minimum width between two edge interrupts, 500ns int will remain low
+ // 15/30MHz=500 ns
+ isp1763_reg_write32(hcd->dev, HC_INT_THRESHOLD_REG, temp);
+#endif
+ /*enable the global interrupt */
+ temp &= 0;
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.hwmodecontrol, temp);
+ temp |= 0x01; /*enable the global interrupt */
+#ifdef EDGE_INTERRUPT
+ temp |= 0x02; /*enable the edge interrupt */
+#endif
+
+#ifdef POL_HIGH_INTERRUPT
+ temp |= 0x04; /* enable interrupt polarity high */
+#endif
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.hwmodecontrol, temp);
+
+ /*maximum rate is one msec */
+ /*enable the atl interrupts OR and AND mask */
+ temp = 0;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_and, temp);
+ temp = 0;
+ isp1763_reg_write16(hcd->dev, hcd->regs.atl_irq_mask_or, temp);
+ temp = 0;
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_and, temp);
+ temp = 0x0;
+ isp1763_reg_write16(hcd->dev, hcd->regs.int_irq_mask_or, temp);
+ temp = 0;
+ isp1763_reg_write16(hcd->dev, hcd->regs.iso_irq_mask_and, temp);
+ temp = 0xffff;
+ isp1763_reg_write16(hcd->dev, hcd->regs.iso_irq_mask_or, temp);
+
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.iso_irq_mask_or, temp);
+ pehci_print("%s:Iso irq mask reg value: 0x%08x\n", __FUNCTION__, temp);
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+
+/*initialize the host controller register map from Isp1763 to EHCI */
+static void
+pehci_hcd_init_reg(phci_hcd * hcd)
+{
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ /* scratch pad for the test */
+ hcd->regs.scratch = HC_SCRATCH_REG;
+
+ /*make a copy of our interrupt locations */
+ hcd->regs.command = HC_USBCMD_REG;
+ hcd->regs.usbstatus = HC_USBSTS_REG;
+ hcd->regs.usbinterrupt = HC_INTERRUPT_REG_EHCI;
+
+ hcd->regs.hcsparams = HC_SPARAMS_REG;
+ hcd->regs.frameindex = HC_FRINDEX_REG;
+
+ /*transfer specific registers */
+ hcd->regs.hwmodecontrol = HC_HWMODECTRL_REG;
+ hcd->regs.interrupt = HC_INTERRUPT_REG;
+ hcd->regs.interruptenable = HC_INTENABLE_REG;
+ hcd->regs.atl_irq_mask_and = HC_ATL_IRQ_MASK_AND_REG;
+ hcd->regs.atl_irq_mask_or = HC_ATL_IRQ_MASK_OR_REG;
+
+ hcd->regs.int_irq_mask_and = HC_INT_IRQ_MASK_AND_REG;
+ hcd->regs.int_irq_mask_or = HC_INT_IRQ_MASK_OR_REG;
+ hcd->regs.iso_irq_mask_and = HC_ISO_IRQ_MASK_AND_REG;
+ hcd->regs.iso_irq_mask_or = HC_ISO_IRQ_MASK_OR_REG;
+ hcd->regs.buffer_status = HC_BUFFER_STATUS_REG;
+ hcd->regs.interruptthreshold = HC_INT_THRESHOLD_REG;
+ /*initialization specific */
+ hcd->regs.reset = HC_RESET_REG;
+ hcd->regs.configflag = HC_CONFIGFLAG_REG;
+ hcd->regs.ports[0] = HC_PORTSC1_REG;
+ hcd->regs.ports[1] = 0; /*port1,port2,port3 status reg are removed */
+ hcd->regs.ports[2] = 0;
+ hcd->regs.ports[3] = 0;
+ hcd->regs.pwrdwn_ctrl = HC_POWER_DOWN_CONTROL_REG;
+ /*transfer registers */
+ hcd->regs.isotddonemap = HC_ISO_PTD_DONEMAP_REG;
+ hcd->regs.isotdskipmap = HC_ISO_PTD_SKIPMAP_REG;
+ hcd->regs.isotdlastmap = HC_ISO_PTD_LASTPTD_REG;
+
+ hcd->regs.inttddonemap = HC_INT_PTD_DONEMAP_REG;
+
+ hcd->regs.inttdskipmap = HC_INT_PTD_SKIPMAP_REG;
+ hcd->regs.inttdlastmap = HC_INT_PTD_LASTPTD_REG;
+
+ hcd->regs.atltddonemap = HC_ATL_PTD_DONEMAP_REG;
+ hcd->regs.atltdskipmap = HC_ATL_PTD_SKIPMAP_REG;
+ hcd->regs.atltdlastmap = HC_ATL_PTD_LASTPTD_REG;
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+}
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static void
+pehci_interrupt_handler(phci_hcd * hcd, struct pt_regs *regs)
+{
+ spin_lock(&hcd->lock);
+#ifdef CONFIG_ISO_SUPPORT
+ phcd_iso_handler(hcd, regs);
+#endif
+ pehci_hcd_intl_worker(hcd, regs);
+ pehci_hcd_atl_worker(hcd, regs);
+ spin_unlock(&hcd->lock);
+ return;
+}
+#else
+static void
+pehci_interrupt_handler(phci_hcd * hcd)
+{
+ spin_lock(&hcd->lock);
+#ifdef CONFIG_ISO_SUPPORT
+ pehci_hcd_iso_worker(hcd);
+#endif
+ pehci_hcd_intl_worker(hcd);
+ pehci_hcd_atl_worker(hcd);
+ spin_unlock(&hcd->lock);
+ return;
+}
+#endif
+irqreturn_t
+pehci_hcd_irq(struct isp1763_dev * dev, void *__irq_data, struct pt_regs * regs)
+{
+
+ int work = 0;
+ phci_hcd *pehci_hcd;
+ u32 intr = 0;
+ u32 resume=0;
+ u32 temp=0;
+ u32 irq_mask = 0;
+
+ struct usb_hcd *usb_hcd = (struct usb_hcd *) __irq_data;
+
+ if (!(usb_hcd->state & USB_STATE_READY)) {
+ info("interrupt handler state not ready yet\n");
+ usb_hcd->state=USB_STATE_READY;
+ // return IRQ_NONE;
+ }
+
+ /*our host */
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ dev = pehci_hcd->dev;
+
+ intr = dev->int_reg;
+
+
+ if (atomic_read(&pehci_hcd->nuofsofs)) {
+ return IRQ_HANDLED;
+ }
+ atomic_inc(&pehci_hcd->nuofsofs);
+
+ irq_mask=isp1763_reg_read32(dev,HC_USBSTS_REG,0);
+ isp1763_reg_write32(dev,HC_USBSTS_REG,irq_mask);
+ if(irq_mask & 0x4){ // port status register.
+ if(intr & 0x50) { // OPR register change
+ temp=isp1763_reg_read32(dev,HC_PORTSC1_REG,0);
+ if(temp & 0x4){ // Force resume bit is set
+ if (dev) {
+ if (dev->driver) {
+ if (dev->driver->resume) {
+
+ spin_lock(&pehci_hcd->lock);/*This spin lock will be depends on syspem can be moved start of the function also*/
+ dev->driver->resume(dev);
+ spin_unlock(&pehci_hcd->lock);
+ resume=1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);
+
+#ifndef THREAD_BASED
+/*-----------------------------------------------------------*/
+#ifdef MSEC_INT_BASED
+ work = 1;
+#else
+ if (intr & (HC_MSEC_INT & INTR_ENABLE_MASK)) {
+ work = 1; /* phci_iso_worker(hcd); */
+ }
+
+#ifdef USBNET
+ if (intr & HC_MSOF_INT ) {
+ struct list_head *pos, *q;
+
+ list_for_each_safe(pos, q, &pehci_hcd->cleanup_urb.urb_list) {
+ struct isp1763_async_cleanup_urb *tmp;
+
+ tmp = list_entry(pos, struct isp1763_async_cleanup_urb, urb_list);
+ if (tmp) {
+ usb_hcd_giveback_urb(usb_hcd, tmp->urb, tmp->urb->status);
+ list_del(pos);
+ if(tmp)
+ kfree(tmp);
+ }
+ }
+ isp1763_reg_write16(dev, HC_INTENABLE_REG, INTR_ENABLE_MASK );
+ }
+#endif
+
+
+ if (intr & (HC_INTL_INT & INTR_ENABLE_MASK)) {
+ spin_lock(&pehci_hcd->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_intl_worker(pehci_hcd, regs);
+#else
+ pehci_hcd_intl_worker(pehci_hcd);
+#endif
+ spin_unlock(&pehci_hcd->lock);
+ work = 0; /*phci_intl_worker(hcd); */
+ }
+
+ if (intr & (HC_ATL_INT & INTR_ENABLE_MASK)) {
+ spin_lock(&pehci_hcd->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_atl_worker(pehci_hcd, regs);
+#else
+ pehci_hcd_atl_worker(pehci_hcd);
+#endif
+ spin_unlock(&pehci_hcd->lock);
+ work = 0; /*phci_atl_worker(hcd); */
+ }
+#ifdef CONFIG_ISO_SUPPORT
+ if (intr & (HC_ISO_INT & INTR_ENABLE_MASK)) {
+ spin_lock(&pehci_hcd->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_iso_worker(pehci_hcd);
+#else
+ pehci_hcd_iso_worker(pehci_hcd);
+#endif
+ spin_unlock(&pehci_hcd->lock);
+ work = 0; /*phci_atl_worker(hcd); */
+ }
+#endif
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (work){
+ pehci_interrupt_handler(pehci_hcd, regs);
+ }
+#else
+ if (work){
+ pehci_interrupt_handler(pehci_hcd);
+ }
+#endif
+
+/*-----------------------------------------------------------*/
+#else
+ if ((intr & (HC_INTL_INT & INTR_ENABLE_MASK)) ||(intr & (HC_ATL_INT & INTR_ENABLE_MASK)))
+ { //send
+ st_UsbIt_Msg_Struc *stUsbItMsgSnd ;
+
+ stUsbItMsgSnd = (st_UsbIt_Msg_Struc *)kmalloc(sizeof(st_UsbIt_Msg_Struc), GFP_ATOMIC);
+ if (!stUsbItMsgSnd) return -ENOMEM;
+
+ memset(stUsbItMsgSnd, 0, sizeof(stUsbItMsgSnd));
+
+ stUsbItMsgSnd->usb_hcd = usb_hcd;
+ stUsbItMsgSnd->uIntStatus = NO_SOF_REQ_IN_ISR;
+ list_add_tail(&(stUsbItMsgSnd->list), &(g_messList.list));
+
+ pehci_print("\n------------- send mess : %d------------\n",stUsbItMsgSnd->uIntStatus);
+ if ((g_stUsbItThreadHandler.phThreadTask != NULL) && (g_stUsbItThreadHandler.lThrdWakeUpNeeded == 0))
+ {
+ pehci_print("\n------- wake up thread : %d-----\n",stUsbItMsgSnd->uIntStatus);
+ g_stUsbItThreadHandler.lThrdWakeUpNeeded = 1;
+ wake_up(&(g_stUsbItThreadHandler.ulThrdWaitQhead));
+ }
+ }
+/*-----------------------------------------------------------*/
+#endif
+
+ atomic_dec(&pehci_hcd->nuofsofs);
+ if(resume){
+ usb_hcd_poll_rh_status(usb_hcd);
+ }
+ return IRQ_HANDLED;
+}
+
+/*reset the host controller
+ *called phci_hcd_start routine
+ *return 0, success else
+ *timeout, fails*/
+static int
+pehci_hcd_reset(struct usb_hcd *usb_hcd)
+{
+ u32 command = 0;
+ u32 temp = 0;
+ phci_hcd *hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ printk(KERN_NOTICE "++ %s: Entered\n", __FUNCTION__);
+ pehci_hcd_init_reg(hcd);
+ printk("chipid %x \n", isp1763_reg_read32(hcd->dev, HC_CHIP_ID_REG, temp)); //0x70
+
+ /*reset the atx controller */
+ temp &= 0;
+ temp |= 8;
+ isp1763_reg_write16(hcd->dev, hcd->regs.reset, temp);
+ mdelay(10);
+
+ /*reset the host controller */
+ temp &= 0;
+ temp |= 1;
+ isp1763_reg_write16(hcd->dev, hcd->regs.reset, temp);
+
+ command = 0;
+ do {
+
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.reset, temp);
+ mdelay(10);
+ command++;
+ if (command > 100) {
+ printk("not able to reset\n");
+ break;
+ }
+ } while (temp & 0x01);
+
+
+ /*reset the ehci controller registers */
+ temp = 0;
+ temp |= (1 << 1);
+ isp1763_reg_write16(hcd->dev, hcd->regs.reset, temp);
+ command = 0;
+ do {
+ temp = isp1763_reg_read16(hcd->dev, hcd->regs.reset, temp);
+ mdelay(10);
+ command++;
+ if (command > 100) {
+ printk("not able to reset\n");
+ break;
+ }
+ } while (temp & 0x02);
+
+ /*read the command register */
+ command = isp1763_reg_read16(hcd->dev, hcd->regs.command, command);
+
+ command |= CMD_RESET;
+ /*write back and wait for, 250 msec */
+ isp1763_reg_write16(hcd->dev, hcd->regs.command, command);
+ /*wait for maximum 250 msecs */
+ mdelay(200);
+ printk("command %x\n",
+ isp1763_reg_read16(hcd->dev, hcd->regs.command, command));
+ printk(KERN_NOTICE "-- %s: Exit \n", __FUNCTION__);
+ return 0;
+}
+
+/*host controller initialize routine,
+ *called by phci_hcd_probe
+ * */
+static int
+pehci_hcd_start(struct usb_hcd *usb_hcd)
+{
+
+ int retval;
+ int count = 0;
+ phci_hcd *pehci_hcd = NULL;
+ u32 temp = 0;
+ u32 hwmodectrl = 0;
+ u32 ul_scratchval = 0;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+
+ spin_lock_init(&pehci_hcd->lock);
+ atomic_set(&pehci_hcd->nuofsofs, 0);
+ atomic_set(&pehci_hcd->missedsofs, 0);
+
+ /*Initialize host controller registers */
+ pehci_hcd_init_reg(pehci_hcd);
+
+ /*reset the host controller */
+ retval = pehci_hcd_reset(usb_hcd);
+ if (retval) {
+ err("phci_1763_start: error failing with status %x\n", retval);
+ return retval;
+ }
+
+ hwmodectrl =
+ isp1763_reg_read16(pehci_hcd->dev,
+ pehci_hcd->regs.hwmodecontrol, hwmodectrl);
+#ifdef DATABUS_WIDTH_16
+ printk(KERN_NOTICE "Mode Ctrl Value before 16width: %x\n", hwmodectrl);
+ hwmodectrl &= 0xFFEF; /*enable the 16 bit bus */
+ hwmodectrl |= 0x0400; /*enable common int */
+#else
+ printk(KERN_NOTICE "Mode Ctrl Value before 8width : %x\n", hwmodectrl);
+ hwmodectrl |= 0x0010; /*enable the 8 bit bus */
+ hwmodectrl |= 0x0400; /*enable common int */
+#endif
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.hwmodecontrol,
+ hwmodectrl);
+
+ hwmodectrl =
+ isp1763_reg_read16(pehci_hcd->dev,
+ pehci_hcd->regs.hwmodecontrol, hwmodectrl);
+ hwmodectrl |=0x9; //lock interface and enable global interrupt.
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.hwmodecontrol,
+ hwmodectrl);
+ printk(KERN_NOTICE "Mode Ctrl Value after buswidth: %x\n", hwmodectrl);
+
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.scratch, 0x3344);
+
+ ul_scratchval =
+ isp1763_reg_read16(pehci_hcd->dev, pehci_hcd->regs.scratch,
+ ul_scratchval);
+ printk(KERN_NOTICE "Scratch Reg Value : %x\n", ul_scratchval);
+ if (ul_scratchval != 0x3344) {
+ printk(KERN_NOTICE "Scratch Reg Value Mismatch: %x\n",
+ ul_scratchval);
+
+ }
+
+
+ /*initialize the host controller initial values */
+ /*disable all the buffer */
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.buffer_status, 0);
+ /*skip all the transfers */
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.atltdskipmap,
+ NO_TRANSFER_ACTIVE);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.inttdskipmap,
+ NO_TRANSFER_ACTIVE);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.isotdskipmap,
+ NO_TRANSFER_ACTIVE);
+ /*clear done map */
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.atltddonemap,
+ NO_TRANSFER_DONE);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.inttddonemap,
+ NO_TRANSFER_DONE);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.isotddonemap,
+ NO_TRANSFER_DONE);
+
+#ifdef HCD_PACKAGE
+ /*port1 as Host */
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_SET_REG, 0x0400);
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_CLEAR_REG, 0x0080);
+ /*port2 as Host */
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_SET_REG, 0x0000);
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_CLEAR_REG, 0x8000);
+
+ #if 0 /* do not use bit 1&2 for pure host application */
+ ul_scratchval = isp1763_reg_read32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG,0);
+ ul_scratchval |= 0x006;
+ isp1763_reg_write32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG,ul_scratchval);
+ #endif
+
+#elif defined(HCD_DCD_PACKAGE)
+
+ /*port1 as device */
+ isp1763_reg_write16(pehci_hcd->dev,OTG_CTRL_SET_REG,
+ OTG_CTRL_DMPULLDOWN |OTG_CTRL_DPPULLDOWN |
+ OTG_CTRL_SW_SEL_HC_DC |OTG_CTRL_OTG_DISABLE); /* pure Device Mode and OTG disabled */
+
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_SET_REG, 0x0480);
+ /*port2 as host */
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_SET_REG, 0x0000);
+ isp1763_reg_write16(pehci_hcd->dev, OTG_CTRL_CLEAR_REG, 0x8000);
+ ul_scratchval =
+ isp1763_reg_read32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG,
+ 0);
+#endif
+
+ /*enable interrupts */
+ pehci_hcd_enable_interrupts(pehci_hcd);
+
+ /*put controller into operational mode */
+ retval = pehci_hcd_start_controller(pehci_hcd);
+ if (retval) {
+ err("phci_1763_start: error failing with status %x\n", retval);
+ return retval;
+ }
+
+ /*Init the phci qtd <-> ptd map buffers */
+ pehci_hcd_init_map_buffers(pehci_hcd);
+
+ /*set last maps, for iso its only 1, else 32 tds bitmap */
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.atltdlastmap,
+ 0x8000);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.inttdlastmap, 0x80);
+ isp1763_reg_write16(pehci_hcd->dev, pehci_hcd->regs.isotdlastmap, 0x01);
+ /*iso transfers are not active */
+ pehci_hcd->next_uframe = -1;
+ pehci_hcd->periodic_sched = 0;
+ hwmodectrl =
+ isp1763_reg_read16(pehci_hcd->dev,
+ pehci_hcd->regs.hwmodecontrol, hwmodectrl);
+
+ /*initialize the periodic list */
+ for (count = 0; count < PTD_PERIODIC_SIZE; count++) {
+ pehci_hcd->periodic_list[count].framenumber = 0;
+ INIT_LIST_HEAD(&pehci_hcd->periodic_list[count].sitd_itd_head);
+ }
+
+
+ /*set the state of the host to ready,
+ * start processing interrupts
+ * */
+
+ usb_hcd->state = HC_STATE_RUNNING;
+ pehci_hcd->state = HC_STATE_RUNNING;
+
+
+ /*initialize root hub timer */
+ init_timer(&pehci_hcd->rh_timer);
+ /*initialize watchdog */
+ init_timer(&pehci_hcd->watchdog);
+
+ temp = isp1763_reg_read32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG,
+ temp);
+
+ temp = 0x3e81bA0;
+#if 0
+ temp |= 0x306;
+#endif
+ isp1763_reg_write32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG, temp);
+ temp = isp1763_reg_read32(pehci_hcd->dev, HC_POWER_DOWN_CONTROL_REG,
+ temp);
+ printk(" Powerdown Reg Val: %x\n", temp);
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+
+ return 0;
+}
+
+static void
+pehci_hcd_stop(struct usb_hcd *usb_hcd)
+{
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ /* no more interrupts ... */
+ if (usb_hcd->state == USB_STATE_RUNNING) {
+ mdelay(2);
+ }
+ if (in_interrupt()) { /* must not happen!! */
+ pehci_info("stopped in_interrupt!\n");
+
+ return;
+ }
+
+ /*power off our root hub */
+ pehci_rh_control(usb_hcd, ClearPortFeature, USB_PORT_FEAT_POWER,
+ 1, NULL, 0);
+
+ /*let the roothub power go off */
+ mdelay(20);
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+
+ return;
+}
+
+
+/*submit urb , other than root hub*/
+static int
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+pehci_hcd_urb_enqueue(struct usb_hcd *usb_hcd, struct usb_host_endpoint *ep,
+ struct urb *urb, gfp_t mem_flags)
+#else
+pehci_hcd_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, gfp_t mem_flags)
+#endif
+{
+
+ struct list_head qtd_list;
+ struct ehci_qh *qh = 0;
+ phci_hcd *pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ int status = 0;
+ int temp = 0, max = 0, num_tds = 0, mult = 0;
+ urb_priv_t *urb_priv = NULL;
+ unsigned long flags;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+
+ if (unlikely(atomic_read(&urb->reject)))
+ return -EINVAL;
+
+ INIT_LIST_HEAD(&qtd_list);
+ urb->transfer_flags &= ~EHCI_STATE_UNLINK;
+
+
+ temp = usb_pipetype(urb->pipe);
+ max = usb_maxpacket(urb->dev, urb->pipe, !usb_pipein(urb->pipe));
+
+
+ if (hcdpowerdown == 1) {
+ printk("Enqueue hcd power down\n");
+ return -EINVAL;
+ }
+
+
+ /*pathch to get the otg device */
+ if (!hubdev ||
+ (urb->dev->parent==usb_hcd->self.root_hub &&
+ hubdev!=urb->dev)) {
+ if(urb->dev->parent== usb_hcd->self.root_hub) {
+ hubdev = urb->dev;
+ }
+ }
+
+ switch (temp) {
+ case PIPE_INTERRUPT:
+ /*only one td */
+ num_tds = 1;
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x07ff;
+ max *= mult;
+
+ if (urb->transfer_buffer_length > max) {
+ err("interrupt urb length is greater then %d\n", max);
+ return -EINVAL;
+ }
+
+ if (hubdev && urb->dev->parent == usb_hcd->self.root_hub) {
+ huburb = urb;
+ }
+
+ break;
+
+ case PIPE_CONTROL:
+ /*calculate the number of tds, follow 1 pattern */
+ if (No_Data_Phase && No_Status_Phase) {
+ printk("Only SetUP Phase\n");
+ num_tds = (urb->transfer_buffer_length == 0) ? 1 :
+ ((urb->transfer_buffer_length -
+ 1) / HC_ATL_PL_SIZE + 1);
+ } else if (!No_Data_Phase && No_Status_Phase) {
+ printk("SetUP Phase and Data Phase\n");
+ num_tds = (urb->transfer_buffer_length == 0) ? 2 :
+ ((urb->transfer_buffer_length -
+ 1) / HC_ATL_PL_SIZE + 3);
+ } else if (!No_Data_Phase && !No_Status_Phase) {
+ num_tds = (urb->transfer_buffer_length == 0) ? 2 :
+ ((urb->transfer_buffer_length -
+ 1) / HC_ATL_PL_SIZE + 3);
+ }
+
+ break;
+
+ case PIPE_BULK:
+ num_tds =
+ (urb->transfer_buffer_length - 1) / HC_ATL_PL_SIZE + 1;
+ if ((urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % max)) {
+ num_tds++;
+ }
+
+ break;
+
+#ifdef CONFIG_ISO_SUPPORT
+ case PIPE_ISOCHRONOUS:
+ /* Don't need to do anything here */
+ break;
+#endif
+ default:
+ return -EINVAL; /*not supported isoc transfers */
+
+
+ }
+
+#ifdef CONFIG_ISO_SUPPORT
+ if (temp != PIPE_ISOCHRONOUS) {
+#endif
+ /*make number of tds required */
+ urb_priv = kmalloc(sizeof(urb_priv_t) +
+ num_tds * sizeof(struct ehci_qtd),
+ mem_flags);
+ if (!urb_priv) {
+ err("memory allocation error\n");
+ return -ENOMEM;
+ }
+
+ memset(urb_priv, 0, sizeof(urb_priv_t) +
+ num_tds * sizeof(struct ehci_qtd));
+ INIT_LIST_HEAD(&urb_priv->qtd_list);
+ urb_priv->qtd[0] = NULL;
+ urb_priv->length = num_tds;
+ {
+ int i = 0;
+ /*allocate number of tds here. better to do this in qtd_make routine */
+ for (i = 0; i < num_tds; i++) {
+ urb_priv->qtd[i] =
+ phci_hcd_qtd_allocate(mem_flags);
+ if (!urb_priv->qtd[i]) {
+ phci_hcd_urb_free_priv(pehci_hcd,
+ urb_priv, NULL);
+ return -ENOMEM;
+ }
+ }
+ }
+ /*keep a copy of this */
+ urb->hcpriv = urb_priv;
+#ifdef CONFIG_ISO_SUPPORT
+ }
+#endif
+
+ switch (temp) {
+ case PIPE_INTERRUPT:
+ phci_hcd_make_qtd(pehci_hcd, &urb_priv->qtd_list, urb, &status);
+ if (status < 0) {
+ return status;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qh = phci_hcd_submit_interrupt(pehci_hcd, ep, &urb_priv->qtd_list, urb,
+ &status);
+#else
+ qh = phci_hcd_submit_interrupt(pehci_hcd, &urb_priv->qtd_list, urb,
+ &status);
+#endif
+ if (status < 0)
+ return status;
+ break;
+
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+
+#ifdef THREAD_BASED
+ spin_lock_irqsave (&pehci_hcd->lock, flags);
+#endif
+ phci_hcd_make_qtd(pehci_hcd, &qtd_list, urb, &status);
+ if (status < 0) {
+ return status;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qh = phci_hcd_submit_async(pehci_hcd, ep, &qtd_list, urb,
+ &status);
+#else
+ qh = phci_hcd_submit_async(pehci_hcd, &qtd_list, urb, &status);
+#endif
+
+#ifdef THREAD_BASED
+ spin_unlock_irqrestore (&pehci_hcd->lock, flags);
+#endif
+
+ if (status < 0) {
+ return status;
+ }
+ break;
+#ifdef CONFIG_ISO_SUPPORT
+ case PIPE_ISOCHRONOUS:
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_urb_enqueue]: URB Transfer buffer: 0x%08x\n",
+ (long) urb->transfer_buffer);
+ iso_dbg(ISO_DBG_DATA,
+ "[pehci_hcd_urb_enqueue]: URB Buffer Length: %d\n",
+ (long) urb->transfer_buffer_length);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ phcd_submit_iso(pehci_hcd, ep, urb, (unsigned long *) &status);
+#else
+ spin_lock_irqsave(&pehci_hcd->lock, flags);
+ phcd_store_urb_pending(pehci_hcd, 0, urb, (int *) &status);
+ spin_unlock_irqrestore(&pehci_hcd->lock, flags);
+#endif
+
+ return status;
+
+ break;
+#endif
+ default:
+ return -ENODEV;
+ } /*end of switch */
+
+#if (defined MSEC_INT_BASED)
+ return 0;
+#elif (defined THREAD_BASED)
+{ //send
+ st_UsbIt_Msg_Struc *stUsbItMsgSnd ;
+ unsigned long flags;
+ spin_lock_irqsave(&pehci_hcd->lock,flags);
+
+ //local_irq_save(flags); /*disable interrupt*/
+ stUsbItMsgSnd = (st_UsbIt_Msg_Struc *)kmalloc(sizeof(st_UsbIt_Msg_Struc), GFP_ATOMIC);
+ if (!stUsbItMsgSnd)
+ {
+ return -ENOMEM;
+ }
+
+ memset(stUsbItMsgSnd, 0, sizeof(stUsbItMsgSnd));
+
+ stUsbItMsgSnd->usb_hcd = usb_hcd;
+ stUsbItMsgSnd->uIntStatus = NO_SOF_REQ_IN_REQ;
+ spin_lock(&enqueue_lock);
+ if(list_empty(&g_enqueueMessList.list))
+ list_add_tail(&(stUsbItMsgSnd->list), &(g_enqueueMessList.list));
+ spin_unlock(&enqueue_lock);
+
+ pehci_print("\n------------- send mess : %d------------\n",stUsbItMsgSnd->uIntStatus);
+
+ //local_irq_restore(flags); /*disable interrupt*/
+
+ spin_lock(&g_stUsbItThreadHandler.lock);
+ if ((g_stUsbItThreadHandler.phThreadTask != NULL) && (g_stUsbItThreadHandler.lThrdWakeUpNeeded == 0))
+ {
+ pehci_print("\n------- wake up thread : %d-----\n",stUsbItMsgSnd->uIntStatus);
+ g_stUsbItThreadHandler.lThrdWakeUpNeeded = 1;
+ wake_up(&(g_stUsbItThreadHandler.ulThrdWaitQhead));
+ }
+ spin_unlock(&g_stUsbItThreadHandler.lock);
+
+ spin_unlock_irqrestore(&pehci_hcd->lock,flags);
+ }
+ pehci_entry("-- %s: Exit\n",__FUNCTION__);
+ return 0;
+#else
+ /*submit tds but iso */
+ if (temp != PIPE_ISOCHRONOUS)
+ pehci_hcd_td_ptd_submit_urb(pehci_hcd, qh, qh->type);
+#endif
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ return 0;
+
+}
+
+/*---------------------------------------------*
+ io request handlers
+ *---------------------------------------------*/
+
+/*unlink urb*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+static int
+pehci_hcd_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb)
+#else
+static int
+pehci_hcd_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ int status = 0;
+#endif
+ int retval = 0;
+ td_ptd_map_buff_t *td_ptd_buf;
+ td_ptd_map_t *td_ptd_map;
+ struct ehci_qh *qh = 0;
+ u32 skipmap = 0;
+ u32 buffstatus = 0;
+ unsigned long flags;
+ struct ehci_qtd *qtd = 0;
+ struct usb_host_endpoint *ep;
+
+ struct ehci_qtd *cancel_qtd = 0; /*added for stopping ptd*/
+ struct urb *cancel_urb = 0; /*added for stopping ptd*/
+ urb_priv_t *cancel_urb_priv = 0; /* added for stopping ptd */
+ struct _isp1763_qha atlqha;
+ struct _isp1763_qha *qha;
+ struct isp1763_mem_addr *mem_addr = 0;
+ u32 ormask = 0;
+ struct list_head *qtd_list = 0;
+ urb_priv_t *urb_priv = (urb_priv_t *) urb->hcpriv;
+ phci_hcd *hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ pehci_info("device %d\n", urb->dev->devnum);
+
+ if(urb_priv==NULL){
+ printk("*******urb_priv is NULL******* %s: Entered\n", __FUNCTION__);
+ return 0;
+ }
+ spin_lock_irqsave(&hcd->lock, flags);
+
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ // status = 0;
+ qh = urb_priv->qh;
+ if(qh==NULL)
+ break;
+
+ td_ptd_buf = &td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL];
+ td_ptd_map = &td_ptd_buf->map_list[qh->qtd_ptd_index];
+
+ /*if its already been removed */
+ if (td_ptd_map->state == TD_PTD_NEW) {
+ break;
+ }
+/* patch added for stopping Full speed PTD */
+/* patch starts ere */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+
+ cancel_qtd = td_ptd_map->qtd;
+ if (!qh || !cancel_qtd) {
+ err("Never Error:QH and QTD must not be zero\n");
+ } else {
+ cancel_urb = cancel_qtd->urb;
+ cancel_urb_priv =
+ (urb_priv_t *) cancel_urb->hcpriv;
+ mem_addr = &cancel_qtd->mem_addr;
+ qha = &atlqha;
+ memset(qha, 0, sizeof(struct _isp1763_qha));
+
+ skipmap =
+ isp1763_reg_read16(hcd->dev,
+ hcd->regs.
+ atltdskipmap,
+ skipmap);
+ skipmap |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.atltdskipmap,
+ skipmap);
+
+ /*read this ptd from the ram address,address is in the
+ td_ptd_map->ptd_header_addr */
+ isp1763_mem_read(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH,
+ 0);
+ if ((qha->td_info1 & QHA_VALID)
+ || (qha->td_info4 & QHA_ACTIVE)) {
+
+ qha->td_info2 |= 0x00008000;
+ qha->td_info1 |= QHA_VALID;
+ qha->td_info4 |= QHA_ACTIVE;
+ skipmap &= ~td_ptd_map->ptd_bitmap;
+ ormask |= td_ptd_map->ptd_bitmap;
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.
+ atl_irq_mask_or,
+ ormask);
+ /* copy back into the header, payload is already
+ * present no need to write again */
+ isp1763_mem_write(hcd->dev,
+ td_ptd_map->
+ ptd_header_addr, 0,
+ (u32 *) (qha),
+ PHCI_QHA_LENGTH, 0);
+ /*unskip this td */
+ isp1763_reg_write16(hcd->dev,
+ hcd->regs.
+ atltdskipmap,
+ skipmap);
+ udelay(100);
+ }
+
+ isp1763_mem_read(hcd->dev,
+ td_ptd_map->ptd_header_addr, 0,
+ (u32 *) (qha), PHCI_QHA_LENGTH,
+ 0);
+ if (!(qha->td_info1 & QHA_VALID)
+ && !(qha->td_info4 & QHA_ACTIVE)) {
+ printk(KERN_NOTICE
+ "ptd has been retired \n");
+ }
+
+ }
+ }
+
+/* Patch Ends */
+ /* These TDs are not pending anymore */
+ td_ptd_buf->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+ /*tell atl worker this urb is going to be removed */
+ td_ptd_map->state = TD_PTD_REMOVE;
+ /* These TDs are not pending anymore */
+ td_ptd_buf->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+ /*tell atl worker this urb is going to be removed */
+ td_ptd_map->state = TD_PTD_REMOVE;
+ urb_priv->state |= DELETE_URB;
+
+ /*read the skipmap, to see if this transfer has to be rescheduled */
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap);
+ pehci_check("remove skip map %x, ptd map %x\n", skipmap,
+ td_ptd_map->ptd_bitmap);
+
+ buffstatus =
+ isp1763_reg_read16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus);
+
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.atltdskipmap,
+ skipmap | td_ptd_map->ptd_bitmap);
+
+ while (!(skipmap & td_ptd_map->ptd_bitmap)) {
+ udelay(125);
+
+ skipmap = isp1763_reg_read16(hcd->dev,
+ hcd->regs.atltdskipmap,
+ skipmap);
+ }
+
+ /* if all transfers skipped,
+ * then disable the atl buffer,
+ * so that new transfer can come in
+ * need to see the side effects
+ * */
+ if (skipmap == NO_TRANSFER_ACTIVE) {
+ /*disable the buffer */
+ pehci_info("disable the atl buffer\n");
+ buffstatus &= ~ATL_BUFFER;
+ isp1763_reg_write16(hcd->dev, hcd->regs.buffer_status,
+ buffstatus);
+ }
+
+ qtd_list = &qh->qtd_list;
+ /*this should remove all pending transfers */
+ pehci_check("num tds %d, urb length %d,device %d\n",
+ urb_priv->length, urb->transfer_buffer_length,
+ urb->dev->devnum);
+
+ pehci_check("remove first qtd address %p\n", urb_priv->qtd[0]);
+ pehci_check("length of the urb %d, completed %d\n",
+ urb->transfer_buffer_length, urb->actual_length);
+ qtd = urb_priv->qtd[urb_priv->length - 1];
+ pehci_check("qtd state is %x\n", qtd->state);
+
+
+ urb->status=status;
+ status = 0;
+#ifdef USBNET
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_delayed_complete(hcd, qh, urb, td_ptd_map, NULL);
+#else
+ pehci_hcd_urb_delayed_complete(hcd, qh, urb, td_ptd_map);
+#endif
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map, NULL);
+#else
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map);
+#endif
+
+#endif
+ break;
+
+ case PIPE_INTERRUPT:
+ pehci_check("phci_1763_urb_dequeue: INTR needs to be done\n");
+ urb->status = status; //-ENOENT;//This will allow to suspend the system. in auto suspend mode
+ status = 0;
+ qh = urb_priv->qh;
+ if(qh==NULL)
+ break;
+
+ td_ptd_buf = &td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL];
+ td_ptd_map = &td_ptd_buf->map_list[qh->qtd_ptd_index];
+
+ /*urb is already been removed */
+ if (td_ptd_map->state == TD_PTD_NEW) {
+ kfree(urb_priv);
+ break;
+ }
+
+ /* These TDs are not pending anymore */
+ td_ptd_buf->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+ td_ptd_map->state = TD_PTD_REMOVE;
+ urb_priv->state |= DELETE_URB;
+
+ /*read the skipmap, to see if this transfer has to be rescheduled */
+ skipmap =
+ isp1763_reg_read16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap);
+
+ isp1763_reg_write16(hcd->dev, hcd->regs.inttdskipmap,
+ skipmap | td_ptd_map->ptd_bitmap);
+ qtd_list = &qh->qtd_list;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map, NULL);
+#else
+ pehci_hcd_urb_complete(hcd, qh, urb, td_ptd_map);
+#endif
+ break;
+#ifdef CONFIG_ISO_SUPPORT
+ case PIPE_ISOCHRONOUS:
+ pehci_info("urb dequeue %x %x\n", urb,urb->pipe);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ if(urb->dev->speed==USB_SPEED_HIGH){
+ retval = usb_hcd_check_unlink_urb(usb_hcd, urb, status);
+ if (!retval) {
+ pehci_info("[pehci_hcd_urb_dequeue] usb_hcd_unlink_urb_from_ep with status = %d\n", status);
+ usb_hcd_unlink_urb_from_ep(usb_hcd, urb);
+
+
+ }
+ }
+#endif
+
+
+ status = 0;
+ ep=urb->ep;
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ mdelay(100);
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (urb->hcpriv!= periodic_ep[0]){
+#else
+ if (urb->ep != periodic_ep[0]){
+#endif
+ if(!list_empty(&ep->urb_list)){
+ while(!list_empty(&ep->urb_list)){
+ urb=container_of(ep->urb_list.next,struct urb,urb_list);
+ pehci_info("list is not empty %x %x\n",urb,urb->dev->state);
+ if(urb){
+ retval = usb_hcd_check_unlink_urb(usb_hcd, urb,0);
+ if (!retval) {
+ pehci_info("[pehci_hcd_urb_dequeue] usb_hcd_unlink_urb_from_ep with status = %d\n", status);
+ usb_hcd_unlink_urb_from_ep(usb_hcd, urb);
+ }
+ urb->status=-ESHUTDOWN;
+ #if LINUX_VERSION_CODE <KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(usb_hcd,urb);
+ #else
+ usb_hcd_giveback_urb(usb_hcd,urb,urb->status);
+ #endif
+
+ }
+ }
+ }else{
+ if(urb){
+ pehci_info("list empty %x\n",urb->dev->state);
+ phcd_clean_urb_pending(hcd, urb);
+ retval = usb_hcd_check_unlink_urb(usb_hcd, urb,0);
+ if (!retval) {
+ pehci_info("[pehci_hcd_urb_dequeue] usb_hcd_unlink_urb_from_ep with status = %d\n", status);
+ usb_hcd_unlink_urb_from_ep(usb_hcd, urb);
+ }
+ urb->status=-ESHUTDOWN;
+ #if LINUX_VERSION_CODE <KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(usb_hcd,urb);
+ #else
+ usb_hcd_giveback_urb(usb_hcd,urb,urb->status);
+ #endif
+
+ }
+
+ }
+ }
+#endif
+ return 0;
+ /*nothing to do here, wait till all transfers are done in iso worker */
+ break;
+ }
+
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ pehci_info("status %d\n", status);
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ return status;
+}
+
+/* bulk qh holds the data toggle */
+
+static void
+pehci_hcd_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ phci_hcd *ehci = usb_hcd_to_pehci_hcd(usb_hcd);
+ struct urb *urb;
+
+ unsigned long flags;
+ struct ehci_qh *qh;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ /* ASSERT: any requests/urbs are being unlinked */
+ /* ASSERT: nobody can be submitting urbs for this any more */
+
+#ifdef CONFIG_ISO_SUPPORT
+ mdelay(100); //delay for ISO
+#endif
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ qh = ep->hcpriv;
+
+ if (!qh) {
+ goto done;
+ } else {
+#ifdef CONFIG_ISO_SUPPORT
+ pehci_info("disable endpoint %x %x\n", ep->desc.bEndpointAddress,qh->type);
+
+
+ if (qh->type == TD_PTD_BUFF_TYPE_ISTL) {
+
+ /*wait for urb to get complete*/
+ pehci_info("disable %x \n", list_empty(&ep->urb_list));
+ while (!list_empty(&ep->urb_list)) {
+
+ urb = container_of(ep->urb_list.next,
+ struct urb, urb_list);
+ if (urb) {
+ phcd_clean_urb_pending(ehci, urb);
+ spin_unlock_irqrestore(&ehci->lock,
+ flags);
+
+ urb->status = -ESHUTDOWN;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_hcd_giveback_urb(usb_hcd, urb);
+#else
+ usb_hcd_giveback_urb(usb_hcd, urb,
+ urb->status);
+#endif
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ }
+
+ }
+ }
+#endif
+ /*i will complete whatever left on this endpoint */
+ pehci_complete_device_removal(ehci, qh);
+#ifdef CONFIG_ISO_SUPPORT
+ phcd_clean_periodic_ep();
+#endif
+ ep->hcpriv = NULL;
+
+ goto done;
+ }
+ done:
+
+ ep->hcpriv = NULL;
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ printk("disable endpoint exit\n");
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ return;
+}
+
+/*called by core, for current frame number*/
+static int
+pehci_hcd_get_frame_number(struct usb_hcd *usb_hcd)
+{
+ u32 framenumber = 0;
+ phci_hcd *pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ framenumber =
+ isp1763_reg_read16(pehci_hcd->dev, pehci_hcd->regs.frameindex,
+ framenumber);
+ return framenumber;
+}
+
+/*root hub status data, called by root hub timer
+ *return 0, if no change, else
+ * 1, incase of high speed device
+ */
+static int
+pehci_rh_status_data(struct usb_hcd *usb_hcd, char *buf)
+{
+
+ u32 temp = 0, status = 0;
+ u32 ports = 0, i, retval = 1;
+ unsigned long flags;
+ phci_hcd *hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+
+ if (hcdpowerdown == 1)
+ return 0;
+
+ buf[0] = 0;
+ if(portchange==1){
+ printk("Remotewakeup-enumerate again \n");
+ buf[0] |= 2;
+ hcd->reset_done[0] = 0;
+ return 1;
+ }
+ /* init status to no-changes */
+ buf[0] = 0;
+ /*number of ports */
+ ports = 0x1;
+ spin_lock_irqsave(&hcd->lock, flags);
+ /*read the port status registers */
+ for (i = 0; i < ports; i++) {
+ temp = isp1763_reg_read32(hcd->dev, hcd->regs.ports[i], temp);
+ if (temp & PORT_OWNER) {
+ /* dont report the port status change in case of CC HCD
+ * but clear the port status , if there is any*/
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ isp1763_reg_write32(hcd->dev,
+ hcd->regs.ports[i], temp);
+ continue;
+ }
+ }
+
+ if (!(temp & PORT_CONNECT)) {
+ hcd->reset_done[i] = 0;
+ }
+ if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
+ if (i < 7) {
+ buf[0] |= 1 << (i + 1);
+ } else {
+ buf[1] |= 1 << (i - 7);
+ }
+ status = STS_PCD;
+ }
+ }
+
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ return status ? retval : 0;
+}
+
+/*root hub control requests*/
+static int
+pehci_rh_control(struct usb_hcd *usb_hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ u32 ports = 0;
+ u32 temp = 0, status;
+ unsigned long flags;
+ int retval = 0;
+ phci_hcd *hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+
+ ports = 0x11;
+
+ printk("%s: request %x,wValuse:0x%x, wIndex:0x%x \n",__func__, typeReq,wValue,wIndex);
+
+ spin_lock_irqsave(&hcd->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ pehci_print("ClearPortFeature:0x%x\n", ClearPortFeature);
+ if (!wIndex || wIndex > (ports & 0xf)) {
+ pehci_info
+ ("ClearPortFeature not valid port number %d, should be %d\n",
+ wIndex, (ports & 0xf));
+ goto error;
+ }
+ wIndex--;
+ temp = isp1763_reg_read32(hcd->dev, hcd->regs.ports[wIndex],
+ temp);
+ if (temp & PORT_OWNER) {
+ printk("port is owned by the CC host\n");
+ break;
+ }
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ pehci_print("enable the port\n");
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp & ~PORT_PE);
+
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ printk("disable the port\n");
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp | PORT_PEC);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ case USB_PORT_FEAT_C_SUSPEND:
+ printk("clear feature suspend \n");
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (ports & 0x10) { /*port has has power control switches */
+ isp1763_reg_write32(hcd->dev,
+ hcd->regs.ports[wIndex],
+ temp & ~PORT_POWER);
+ }
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ pehci_print("connect change, status is 0x%08x\n", temp);
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp | PORT_CSC);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp | PORT_OCC);
+ break;
+ default:
+ goto error;
+
+ }
+ break;
+
+ case GetHubDescriptor:
+ pehci_hub_descriptor(hcd, (struct usb_hub_descriptor *) buf);
+ break;
+
+ case GetHubStatus:
+ pehci_print("GetHubStatus:0x%x\n", GetHubStatus);
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ pehci_print("GetPortStatus:0x%x\n", GetPortStatus);
+ if (!wIndex || wIndex > (ports & 0xf)) {
+ pehci_info
+ ("GetPortStatus,not valid port number %d, should be %d\n",
+ wIndex, (ports & 0xf));
+ goto error;
+ }
+ wIndex--;
+ status = 0;
+ temp = isp1763_reg_read32(hcd->dev, hcd->regs.ports[wIndex],
+ temp);
+ printk("root port status:0x%x\n", temp);
+ /*connect status chnage */
+ if (temp & PORT_CSC) {
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+ pehci_print("feature CSC 0x%08x and status 0x%08x \n",
+ temp, status);
+ }
+ if(portchange){
+ portchange=0;
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+ }
+ /*port enable change */
+ if (temp & PORT_PEC) {
+ status |= 1 << USB_PORT_FEAT_C_ENABLE;
+ pehci_print("feature PEC 0x%08x and status 0x%08x \n",
+ temp, status);
+ }
+ /*port over-current */
+ if (temp & PORT_OCC) {
+ status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+ pehci_print("feature OCC 0x%08x and status 0x%08x \n",
+ temp, status);
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET) && jiffies > hcd->reset_done[wIndex]) {
+ status |= 1 << USB_PORT_FEAT_C_RESET;
+ pehci_print("feature reset 0x%08x and status 0x%08x\n",
+ temp, status);
+ printk(KERN_NOTICE
+ "feature reset 0x%08x and status 0x%08x\n", temp,
+ status);
+ /* force reset to complete */
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp & ~PORT_RESET);
+ do {
+ mdelay(20);
+ temp = isp1763_reg_read32(hcd->dev,
+ hcd->regs.
+ ports[wIndex], temp);
+ } while (temp & PORT_RESET);
+
+ /* see what we found out */
+ printk(KERN_NOTICE "after portreset: %x\n", temp);
+
+ temp = phci_check_reset_complete(hcd, wIndex, temp);
+ printk(KERN_NOTICE "after checkportreset: %x\n", temp);
+ }
+
+ /* don't show wPortStatus if it's owned by a companion hc */
+
+ if (!(temp & PORT_OWNER)) {
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ status |= 1 << USB_PORT_FEAT_HIGHSPEED;
+ }
+ if (temp & PORT_PE) {
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ }
+ if (temp & PORT_SUSPEND) {
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ }
+ if (temp & PORT_OC) {
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ }
+ if (temp & PORT_RESET) {
+ status |= 1 << USB_PORT_FEAT_RESET;
+ }
+ if (temp & PORT_POWER) {
+ status |= 1 << USB_PORT_FEAT_POWER;
+ }
+ }
+
+ /* This alignment is good, caller used kmalloc() */
+ *((u32 *) buf) = cpu_to_le32(status);
+ break;
+
+ case SetHubFeature:
+ pehci_print("SetHubFeature:0x%x\n", SetHubFeature);
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ pehci_print("SetPortFeature:%x\n", SetPortFeature);
+ if (!wIndex || wIndex > (ports & 0xf)) {
+ pehci_info
+ ("SetPortFeature not valid port number %d, should be %d\n",
+ wIndex, (ports & 0xf));
+ goto error;
+ }
+ wIndex--;
+ temp = isp1763_reg_read32(hcd->dev, hcd->regs.ports[wIndex],
+ temp);
+ pehci_print("SetPortFeature:PortSc Val 0x%x\n", temp);
+ if (temp & PORT_OWNER) {
+ break;
+ }
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ /*enable the port */
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp | PORT_PE);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+
+ #if 0 /* Port suspend will be added in suspend function */
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp | PORT_SUSPEND);
+ #endif
+
+ break;
+ case USB_PORT_FEAT_POWER:
+ pehci_print("Set Port Power 0x%x and Ports %x\n",
+ USB_PORT_FEAT_POWER, ports);
+ if (ports & 0x10) {
+ printk(KERN_NOTICE
+ "PortSc Reg %x an Value %x\n",
+ hcd->regs.ports[wIndex],
+ (temp | PORT_POWER));
+
+ isp1763_reg_write32(hcd->dev,
+ hcd->regs.ports[wIndex],
+ temp | PORT_POWER);
+ }
+ break;
+ case USB_PORT_FEAT_RESET:
+ pehci_print("Set Port Reset 0x%x\n",
+ USB_PORT_FEAT_RESET);
+ if ((temp & (PORT_PE | PORT_CONNECT)) == PORT_CONNECT
+ && PORT_USB11(temp)) {
+ printk("error:port %d low speed --> companion\n", wIndex + 1);
+ temp |= PORT_OWNER;
+ } else {
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ hcd->reset_done[wIndex] = jiffies
+ + ((50 /* msec */ * HZ) / 1000);
+ }
+ isp1763_reg_write32(hcd->dev, hcd->regs.ports[wIndex],
+ temp);
+ break;
+ default:
+ goto error;
+ }
+ break;
+ default:
+ pehci_print("this request doesnt fit anywhere\n");
+ error:
+ /* "stall" on error */
+ pehci_info
+ ("unhandled root hub request: typereq 0x%08x, wValue %d, wIndex %d\n",
+ typeReq, wValue, wIndex);
+ retval = -EPIPE;
+ }
+
+ pehci_info("rh_control:exit\n");
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ return retval;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver pehci_driver = {
+ .description = hcd_name,
+ .product_desc = "ST-ERICSSON ISP1763",
+ .hcd_priv_size = sizeof(phci_hcd),
+ .irq = NULL,
+
+ /*
+ * generic hardware linkage
+ */
+ .flags = HCD_USB2 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = pehci_hcd_reset,
+ .start = pehci_hcd_start,
+ .bus_suspend = pehci_bus_suspend,
+ .bus_resume = pehci_bus_resume,
+ .stop = pehci_hcd_stop,
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = pehci_hcd_urb_enqueue,
+ .urb_dequeue = pehci_hcd_urb_dequeue,
+ .endpoint_disable = pehci_hcd_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = pehci_hcd_get_frame_number,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = pehci_rh_status_data,
+ .hub_control = pehci_rh_control,
+};
+
+/*probe the PCI host*/
+
+#ifdef THREAD_BASED
+int pehci_hcd_process_irq_it_handle(struct usb_hcd* usb_hcd_)
+{
+ int istatus;
+
+ struct usb_hcd *usb_hcd;
+ char uIntStatus;
+ phci_hcd *pehci_hcd;
+
+ struct list_head *pos, *lst_tmp;
+ st_UsbIt_Msg_Struc *mess;
+ unsigned long flags;
+
+ g_stUsbItThreadHandler.phThreadTask = current;
+ siginitsetinv(&((g_stUsbItThreadHandler.phThreadTask)->blocked), sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
+ pehci_info("pehci_hcd_process_irq_it_thread ID : %d\n", g_stUsbItThreadHandler.phThreadTask->pid);
+
+ while (1)
+ {
+ if (signal_pending(g_stUsbItThreadHandler.phThreadTask))
+ {
+ printk("thread handler: Thread received signal\n");
+ break;
+ }
+
+ spin_lock(&g_stUsbItThreadHandler.lock);
+ g_stUsbItThreadHandler.lThrdWakeUpNeeded = 0;
+ spin_unlock(&g_stUsbItThreadHandler.lock);
+
+ /* Wait until a signal arrives or we are woken up or timeout (5second)*/
+ istatus = wait_event_interruptible_timeout(g_stUsbItThreadHandler.ulThrdWaitQhead, (g_stUsbItThreadHandler.lThrdWakeUpNeeded== 1), msecs_to_jiffies(MSEC_INTERVAL_CHECKING));
+
+ local_irq_save(flags); /*disable interrupt*/
+ spin_lock(&g_stUsbItThreadHandler.lock);
+ g_stUsbItThreadHandler.lThrdWakeUpNeeded = 1;
+ spin_unlock(&g_stUsbItThreadHandler.lock);
+ //receive mess
+ if (!list_empty(&g_messList.list)) //mess list not empty
+ {
+
+ list_for_each_safe(pos, lst_tmp, &(g_messList.list))
+ {
+ mess = list_entry(pos, st_UsbIt_Msg_Struc, list);
+
+ usb_hcd = mess->usb_hcd;
+ uIntStatus = mess->uIntStatus;
+ //pehci_print("-------------receive mess : %d------------\n",uIntStatus);
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ if((uIntStatus & NO_SOF_REQ_IN_TSK) || (uIntStatus & NO_SOF_REQ_IN_ISR) || (uIntStatus & NO_SOF_REQ_IN_REQ))
+ pehci_interrupt_handler(pehci_hcd);
+ spin_lock(&g_stUsbItThreadHandler.lock);
+ list_del(pos);
+ kfree(mess);
+ spin_unlock(&g_stUsbItThreadHandler.lock);
+ }
+ }
+ else if(!list_empty(&g_enqueueMessList.list))
+ {
+ mess = list_first_entry(&(g_enqueueMessList.list), st_UsbIt_Msg_Struc, list);
+ usb_hcd = mess->usb_hcd;
+ uIntStatus = mess->uIntStatus;
+
+ pehci_print("-------------receive mess : %d------------\n",uIntStatus);
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ if((uIntStatus & NO_SOF_REQ_IN_REQ))
+ {
+ pehci_interrupt_handler(pehci_hcd);
+ }
+
+ {
+ spin_lock(&enqueue_lock);
+ list_del((g_enqueueMessList.list).next);
+ kfree(mess);
+ spin_unlock(&enqueue_lock);
+ }
+ }
+ else if(istatus == 0) //timeout
+ {
+ pehci_hcd = NULL;
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd_);
+ pehci_interrupt_handler(pehci_hcd);
+
+ }
+ local_irq_restore(flags); /*enable interrupt*/
+ }
+
+ flush_signals(g_stUsbItThreadHandler.phThreadTask);
+ g_stUsbItThreadHandler.phThreadTask = NULL;
+ return 0;
+
+}
+
+int pehci_hcd_process_irq_in_thread(struct usb_hcd* usb_hcd_)
+{
+
+ //status = msgq_create("usb_it_queue", 10, sizeof(st_UsbIt_Msg_Struc), &uUsbIt_MsgQueId);
+ INIT_LIST_HEAD(&g_messList.list);
+ INIT_LIST_HEAD(&g_enqueueMessList.list);
+ spin_lock_init(&enqueue_lock);
+
+ memset(&g_stUsbItThreadHandler, 0, sizeof(st_UsbIt_Thread));
+ init_waitqueue_head(&(g_stUsbItThreadHandler.ulThrdWaitQhead));
+ g_stUsbItThreadHandler.lThrdWakeUpNeeded = 0;
+ spin_lock_init(&g_stUsbItThreadHandler.lock);
+ kernel_thread(pehci_hcd_process_irq_it_handle, usb_hcd_, 0);
+
+ return 0;
+}
+#endif
+
+
+/*probe the PCI host*/
+int
+pehci_hcd_probe(struct isp1763_dev *isp1763_dev, isp1763_id * ids)
+{
+#ifdef NON_PCI
+ struct platform_device *dev = isp1763_dev->dev;
+#else /* PCI */
+ struct pci_dev *dev = isp1763_dev->pcidev;
+#endif
+ struct usb_hcd *usb_hcd;
+ phci_hcd *pehci_hcd;
+ int status = 0;
+
+#ifndef NON_PCI
+ u32 intcsr=0;
+#endif
+ u16 wvalue1, wvalue2;
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ if (usb_disabled()) {
+ return -ENODEV;
+ }
+
+ usb_hcd = usb_create_hcd(&pehci_driver,&dev->dev, "ISP1763");
+
+ if (usb_hcd == NULL) {
+ status = -ENOMEM;
+ goto clean;
+ }
+
+ /* this is our host */
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ pehci_hcd->dev = isp1763_dev;
+ pehci_hcd->iobase = (u8 *) isp1763_dev->baseaddress;
+ pehci_hcd->iolength = isp1763_dev->length;
+ pehci_hcd->plxiobase = (u8 *) isp1763_dev->dmabase;
+ pehci_hcd->plxiolength = isp1763_dev->length;
+
+
+ /* lets keep our host here */
+ isp1763_dev->driver_data = usb_hcd;
+#ifdef NON_PCI
+//Do nothing
+#else
+ /* Enable the interrupts from PLX to PCI */
+ /* CONFIGURE PCI/PLX interrupt */
+#ifdef DATABUS_WIDTH_16
+ wvalue1 = readw(pehci_hcd->plxiobase + 0x68);
+ wvalue2 = readw(pehci_hcd->plxiobase + 0x68 + 2);
+ intcsr |= wvalue2;
+ intcsr <<= 16;
+ intcsr |= wvalue1;
+ printk(KERN_NOTICE "Enable PCI Intr: %x \n", intcsr);
+ intcsr |= 0x900;
+ writew((u16) intcsr, pehci_hcd->plxiobase + 0x68);
+ writew((u16) (intcsr >> 16), pehci_hcd->plxiobase + 0x68 + 2);
+#else
+ bvalue1 = readb(pehci_hcd->plxiobase + 0x68);
+ bvalue2 = readb(pehci_hcd->plxiobase + 0x68 + 1);
+ bvalue3 = readb(pehci_hcd->plxiobase + 0x68 + 2);
+ bvalue4 = readb(pehci_hcd->plxiobase + 0x68 + 3);
+ intcsr |= bvalue4;
+ intcsr <<= 8;
+ intcsr |= bvalue3;
+ intcsr <<= 8;
+ intcsr |= bvalue2;
+ intcsr <<= 8;
+ intcsr |= bvalue1;
+ writeb((u8) intcsr, pehci_hcd->plxiobase + 0x68);
+ writeb((u8) (intcsr >> 8), pehci_hcd->plxiobase + 0x68 + 1);
+ writeb((u8) (intcsr >> 16), pehci_hcd->plxiobase + 0x68 + 2);
+ writeb((u8) (intcsr >> 24), pehci_hcd->plxiobase + 0x68 + 3);
+#endif
+#endif
+
+ No_Data_Phase = 0;
+ No_Status_Phase = 0;
+ usb_hcd->self.controller->dma_mask = 0;
+ usb_hcd->self.otg_port = 1;
+ #ifndef THREAD_BASED
+ status = isp1763_request_irq((void*)pehci_hcd_irq, isp1763_dev, usb_hcd);
+ #endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (status == 0) {
+ status = usb_add_hcd(usb_hcd, isp1763_dev->irq, SA_SHIRQ);
+ }
+#else /* Linux 2.6.28*/
+ usb_hcd->self.uses_dma = 0;
+ if (status == 0){
+ status = usb_add_hcd(usb_hcd, isp1763_dev->irq,
+ IRQF_SHARED | IRQF_DISABLED);
+ }
+#endif
+
+#ifdef THREAD_BASED
+ g_pehci_hcd = pehci_hcd;
+#endif
+
+#ifdef USBNET
+ // initialize clean up urb list
+ INIT_LIST_HEAD(&(pehci_hcd->cleanup_urb.urb_list));
+#endif
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+ isp1763_hcd=isp1763_dev;
+ return status;
+
+ clean:
+ return status;
+
+}
+/*--------------------------------------------------------------*
+ *
+ * Module details: pehci_hcd_powerup
+ *
+ * This function powerdown the chip completely, which make chip works in minimal power
+ *
+ * Input: struct isp1763_Dev *
+ *
+ *
+ *
+ *
+ * Called by: IOCTL function
+ *
+ *
+ --------------------------------------------------------------*/
+void
+pehci_hcd_powerup(struct isp1763_dev *dev)
+{
+ printk("%s\n", __FUNCTION__);
+ hcdpowerdown = 0;
+ dev->driver->probe(dev,dev->driver->id);
+
+
+}
+void
+pehci_hcd_powerdown(struct isp1763_dev *dev)
+{
+ struct usb_hcd *usb_hcd;
+
+ phci_hcd *hcd = NULL;
+ u32 temp;
+ usb_hcd = (struct usb_hcd *) dev->driver_data;
+ if (!usb_hcd) {
+ return;
+ }
+
+ printk("%s\n", __FUNCTION__);
+ hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+
+ temp = isp1763_reg_read16(dev, HC_USBCMD_REG, 0);
+ temp &= ~0x01; /* stop the controller first */
+ isp1763_reg_write16(dev, HC_USBCMD_REG, temp);
+ printk("++ %s: Entered\n", __FUNCTION__);
+
+ isp1763_free_irq(dev,usb_hcd);
+ usb_remove_hcd(usb_hcd);
+ dev->driver_data = NULL;
+
+
+ temp = isp1763_reg_read16(dev, HC_INTENABLE_REG, temp); //0xD6
+ temp &= ~0x400; /*disable otg interrupt*/
+ isp1763_reg_write16(dev, HC_INTENABLE_REG, temp); //0xD6
+
+ isp1763_reg_write16(dev, HC_UNLOCK_DEVICE, 0xAA37); /*unlock the device 0x7c*/
+ mdelay(1);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+
+
+ if ((temp & 0x1005) == 0x1005) {
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, 0x1000);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ mdelay(10);
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, 0x1104);
+ mdelay(10);
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, 0x1007);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ mdelay(10);
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, 0x1005);
+
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ }
+
+ printk("port status %x\n ", temp);
+ temp &= ~0x2;
+ temp &= ~0x40; /*force port resume*/
+ temp |= 0x80; /*suspend*/
+
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+ printk("port status %x\n ", temp);
+ mdelay(200);
+
+ temp = isp1763_reg_read16(dev, HC_HW_MODE_REG, 0); /*suspend the device first 0xc*/
+ temp |= 0x2c;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp); //0xc
+ mdelay(20);
+
+ temp = isp1763_reg_read16(dev, HC_HW_MODE_REG, 0); //0xc
+ temp = 0xc;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp); //0xc
+
+ isp1763_reg_write32(dev, HC_POWER_DOWN_CONTROL_REG, 0xffff0800);
+
+ hcdpowerdown = 1;
+
+}
+
+static int pehci_bus_suspend(struct usb_hcd *usb_hcd)
+{
+ u32 temp=0;
+ unsigned long flags;
+ phci_hcd *pehci_hcd = NULL;
+ struct isp1763_dev *dev = NULL;
+
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+
+ dev = pehci_hcd->dev;
+
+ if (!usb_hcd) {
+ return -EBUSY;
+ }
+
+ printk("++ %s \n",__FUNCTION__);
+
+ if(hcdpowerdown){
+ return 0;
+ }
+
+ spin_lock_irqsave(&pehci_hcd->lock, flags);
+
+ isp1763_reg_write32(dev, HC_USBSTS_REG, 0x4); //0x90
+ isp1763_reg_write32(dev, HC_INTERRUPT_REG_EHCI, 0x4); //0x94
+ isp1763_reg_write16(dev, HC_INTERRUPT_REG, INTR_ENABLE_MASK); //0xd4
+
+ temp=isp1763_reg_read16(dev, HC_INTERRUPT_REG, 0); //0xd4
+
+ isp1763_reg_write16(dev,HC_INTENABLE_REG,INTR_ENABLE_MASK);
+ temp=isp1763_reg_read16(dev,HC_INTENABLE_REG,0);
+
+ hcdpowerdown = 1;
+
+ /* stop the controller first */
+ temp = isp1763_reg_read16(dev, HC_USBCMD_REG, 0);
+ temp &= ~0x01;
+ isp1763_reg_write16(dev, HC_USBCMD_REG, temp);
+
+ /* suspend root port which will suspend host controller of the ISP1763A */
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ temp |= (PORT_SUSPEND);//0x80
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+
+ /* suspend device controller of the ISP1763a*/
+ temp = isp1763_reg_read16(dev, HC_HW_MODE_REG, 0);
+ temp |= 0x20;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp);
+ mdelay(1); // make sure there will not be huge delay here max is 1 ms
+ temp &= ~0x20;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp);
+ /* put host controoler into low power mode */
+ isp1763_reg_write32(dev, HC_POWER_DOWN_CONTROL_REG, POWER_DOWN_CTRL_SUSPEND_VALUE);
+
+// usb_hcd->state = HC_STATE_SUSPENDED;
+
+ spin_unlock_irqrestore(&pehci_hcd->lock, flags);
+
+ printk("-- %s \n",__FUNCTION__);
+
+ return 0;
+
+
+}
+
+static int pehci_bus_resume(struct usb_hcd *usb_hcd)
+{
+ u32 temp,i;
+ phci_hcd *pehci_hcd = NULL;
+ struct isp1763_dev *dev = NULL;
+ unsigned long flags;
+ u32 usbsts, portsc1;
+ u32 int_reg=0, irq_mask;
+
+ printk("%s Enter \n",__func__);
+
+ if (!usb_hcd) {
+ return -EBUSY;
+ }
+
+ if(hcdpowerdown ==0){
+ printk("%s already executed\n ",__func__);
+ return 0;
+ }
+
+ pehci_hcd = usb_hcd_to_pehci_hcd(usb_hcd);
+ dev = pehci_hcd->dev;
+ spin_lock_irqsave(&pehci_hcd->lock, flags);
+
+ for (temp = 0; temp < 100; temp++)
+ {
+ i = isp1763_reg_read32(dev, HC_CHIP_ID_REG, 0);
+ if(i==0x176320)
+ break;
+ mdelay(2);
+ }
+ printk("temp=%d, chipid:0x%x \n",temp,i);
+ mdelay(10);
+ isp1763_reg_write16(dev, HC_UNLOCK_DEVICE, 0xAA37); /*unlock the device 0x7c*/
+ i = isp1763_reg_read32(dev, HC_POWER_DOWN_CONTROL_REG, 0);
+ printk("POWER DOWN CTRL REG value during suspend =0x%x\n", i);
+ for (temp = 0; temp < 100; temp++) {
+ mdelay(1);
+ isp1763_reg_write32(dev, HC_POWER_DOWN_CONTROL_REG, POWER_DOWN_CTRL_NORMAL_VALUE);
+ mdelay(1);
+ i = isp1763_reg_read32(dev, HC_POWER_DOWN_CONTROL_REG, 0);
+ if(i==POWER_DOWN_CTRL_NORMAL_VALUE)
+ break;
+ }
+ if (temp == 100) {
+ spin_unlock_irqrestore(&pehci_hcd->lock, flags);
+ pr_err("%s:isp1763a failed to resume\n", __func__);
+ return -1;
+ }
+ printk("%s: Powerdown Reg Val: 0x%08x -- %d\n", __func__, i, temp);
+
+ isp1763_reg_write32(dev, HC_USBSTS_REG,0x0); //0x90
+ isp1763_reg_write32(dev, HC_INTERRUPT_REG_EHCI, 0x0); //0x94
+ isp1763_reg_write16(dev, HC_INTENABLE_REG,0); //0xD6
+
+ portsc1 = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ printk("%s USBSTS: 0x%x, PORTSC1: 0x%x, INTSTATUS: 0x%x, INTMASK: 0x%x\n",
+ __func__, usbsts, portsc1, int_reg, irq_mask);
+
+ temp = isp1763_reg_read16(dev, HC_USBCMD_REG, 0);
+ temp |= 0x01; /* Start the controller */
+ isp1763_reg_write16(dev, HC_USBCMD_REG, temp);
+ mdelay(10);
+
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ if (temp & PORT_SUSPEND)
+ pr_err("%s: HC_PORTSC1_REG: 0x%08x\n", __func__, temp);
+ temp |= PORT_SUSPEND; //0x80;
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+ mdelay(50);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ temp |= PORT_RESUME; //0x40;
+ temp &= ~(PORT_SUSPEND); //0x80; /*suspend*/
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ temp &= ~(PORT_RESUME); //0x40;
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+
+ temp = INTR_ENABLE_MASK;
+ isp1763_reg_write16(dev, HC_INTENABLE_REG, temp); //0xD6
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ printk("%s resume port status: 0x%x\n", __func__, temp);
+ if(!(temp & 0x4)){ //port is disabled
+ isp1763_reg_write16(dev, HC_INTENABLE_REG, 0x1005); //0xD6
+ mdelay(10);
+ }
+// phci_resume_wakeup(dev);
+
+ hcdpowerdown = 0;
+ if(hubdev){
+ hubdev->hcd_priv = NULL;
+ hubdev->hcd_suspend = NULL;
+ }
+
+ spin_unlock_irqrestore(&pehci_hcd->lock, flags);
+ printk("%s Leave\n",__func__);
+
+ return 0;
+}
+
+void
+pehci_hcd_resume(struct isp1763_dev *dev)
+{
+ struct usb_hcd *usb_hcd;
+ u32 temp,i;
+ usb_hcd = (struct usb_hcd *) dev->driver_data;
+ if (!usb_hcd) {
+ return;
+ }
+
+ if(hcdpowerdown ==0){
+ return ;
+ }
+
+ printk("%s \n",__FUNCTION__);
+
+ for (temp = 0; temp < 10; temp++)
+ {
+ i = isp1763_reg_read32(dev, HC_CHIP_ID_REG, 0);
+ printk("temp=%d, chipid:0x%x \n",temp,i);
+ if(i==0x176320)
+ break;
+ mdelay(1);
+ }
+
+ /* Start the controller */
+ temp = 0x01;
+ isp1763_reg_write16(dev, HC_USBCMD_REG, temp);
+
+ /* update power down control reg value */
+ for (temp = 0; temp < 100; temp++) {
+ isp1763_reg_write32(dev, HC_POWER_DOWN_CONTROL_REG, POWER_DOWN_CTRL_NORMAL_VALUE);
+ i = isp1763_reg_read32(dev, HC_POWER_DOWN_CONTROL_REG, 0);
+ if(i==POWER_DOWN_CTRL_NORMAL_VALUE)
+ break;
+ }
+
+ if (temp == 100) {
+ pr_err("%s:isp1763a failed to resume\n", __func__);
+ return;
+ }
+
+ isp1763_reg_write16(dev, HC_INTENABLE_REG,0); //0xD6
+ isp1763_reg_write32(dev,HC_INTERRUPT_REG_EHCI,0x4); //0x94
+ isp1763_reg_write32(dev,HC_INTERRUPT_REG,0xFFFF); //0x94
+ /* clear suspend bit and resume bit */
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ temp &= ~(PORT_SUSPEND); //0x80; /*suspend*/
+ temp &= ~(PORT_RESUME); // 0x40;
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+
+ isp1763_reg_write16(dev, HC_INTENABLE_REG, INTR_ENABLE_MASK); //0xD6
+ /*this is just make sure port is resumed back */
+ mdelay(1);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ printk("after hcd resume :port status %x\n ", temp);
+
+ hcdpowerdown = 0;
+
+#ifndef NON_PCI
+ phci_resume_wakeup(dev);
+#endif
+
+ if(hubdev){
+ hubdev->hcd_priv=NULL;
+ hubdev->hcd_suspend=NULL;
+ }
+// usb_hcd->state = HC_STATE_RUNNING;
+
+}
+
+
+void
+pehci_hcd_suspend(struct isp1763_dev *dev)
+{
+ struct usb_hcd *usb_hcd;
+ u32 temp;
+ usb_hcd = (struct usb_hcd *) dev->driver_data;
+ if (!usb_hcd) {
+ return;
+ }
+ printk("%s \n",__FUNCTION__);
+ if(hcdpowerdown){
+ return ;
+ }
+
+ temp = isp1763_reg_read16(dev, HC_USBCMD_REG, 0);
+ temp &= ~0x01; /* stop the controller first */
+ isp1763_reg_write16(dev, HC_USBCMD_REG, temp);
+
+ isp1763_reg_write32(dev, HC_USBSTS_REG, 0x4); //0x90
+ isp1763_reg_write32(dev, HC_INTERRUPT_REG_EHCI, 0x4); //0x94
+ isp1763_reg_write16(dev, HC_INTERRUPT_REG, INTR_ENABLE_MASK); //0xd4
+
+ temp=isp1763_reg_read16(dev, HC_INTERRUPT_REG, 0); //0xd4
+
+ printk("suspend :Interrupt Status %x\n",temp);
+ isp1763_reg_write16(dev,HC_INTENABLE_REG,INTR_ENABLE_MASK);
+ temp=isp1763_reg_read16(dev,HC_INTENABLE_REG,0);
+ printk("suspend :Interrupt Enable %x\n",temp);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+
+ printk("suspend :port status %x\n ", temp);
+ temp &= ~0x2;
+ temp &= ~0x40; /*force port resume*/
+ temp |= 0x80; /*suspend*/
+// temp |= 0x700000; /*WKCNNT_E,WKDSCNNT_E,WKOC_E*/
+ isp1763_reg_write32(dev, HC_PORTSC1_REG, temp);
+ // mdelay(10);
+ temp = isp1763_reg_read32(dev, HC_PORTSC1_REG, 0);
+ printk("suspend :port status %x\n ", temp);
+ hcdpowerdown = 1;
+
+
+ temp = isp1763_reg_read16(dev,HC_HW_MODE_REG, 0); /*suspend the device first 0xc*/
+ temp&=0xff7b;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp); //0xc
+
+
+ temp = isp1763_reg_read16(dev, HC_HW_MODE_REG, 0); /*suspend the device first 0xc*/
+ temp |= 0x20;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp);//0xc
+ mdelay(2);
+ temp = isp1763_reg_read16(dev, HC_HW_MODE_REG, 0);//0xc
+ temp &= 0xffdf;
+ temp &= ~0x20;
+ isp1763_reg_write16(dev, HC_HW_MODE_REG, temp);//0xc
+
+ isp1763_reg_write32(dev, HC_POWER_DOWN_CONTROL_REG, 0xffff0830);
+
+
+}
+
+void
+pehci_hcd_remotewakeup(struct isp1763_dev *dev){
+ if(hubdev){
+ hubdev->hcd_priv=dev;
+ hubdev->hcd_suspend=(void *)pehci_hcd_suspend;
+ }
+ phci_remotewakeup(dev);
+}
+
+/*remove the host controller*/
+static void
+pehci_hcd_remove(struct isp1763_dev *isp1763_dev)
+{
+
+ struct usb_hcd *usb_hcd;
+
+#ifdef NON_PCI
+#else /* PCI */
+// struct pci_dev *dev = isp1763_dev->pcidev;
+#endif
+
+ phci_hcd *hcd = NULL;
+ u32 temp;
+ usb_hcd = (struct usb_hcd *) isp1763_dev->driver_data;
+ if (!usb_hcd) {
+ return;
+ }
+ hcd=usb_hcd_to_pehci_hcd(usb_hcd);
+ isp1763_reg_write32(hcd->dev,hcd->regs.hwmodecontrol,0);
+ isp1763_reg_write32(hcd->dev,hcd->regs.interruptenable,0);
+ hubdev=0;
+ huburb=0;
+ temp = isp1763_reg_read16(hcd->dev, HC_USBCMD_REG, 0);
+ temp &= ~0x01; /* stop the controller first */
+ isp1763_reg_write16(hcd->dev, HC_USBCMD_REG, temp);
+ isp1763_free_irq(isp1763_dev,usb_hcd);
+ usb_remove_hcd(usb_hcd);
+
+ return ;
+}
+
+
+static isp1763_id ids = {
+ .idVendor = 0x04CC, /*st ericsson isp1763 vendor_id */
+ .idProduct = 0x1A64, /*st ericsson isp1763 product_id */
+ .driver_info = (unsigned long) &pehci_driver,
+};
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct isp1763_driver pehci_hcd_pci_driver = {
+ .name = (char *) hcd_name,
+ .index = 0,
+ .id = &ids,
+ .probe = pehci_hcd_probe,
+ .remove = pehci_hcd_remove,
+ .suspend = pehci_hcd_suspend,
+ .resume = pehci_hcd_resume,
+ .remotewakeup=pehci_hcd_remotewakeup,
+ .powerup = pehci_hcd_powerup,
+ .powerdown = pehci_hcd_powerdown,
+};
+
+#ifdef HCD_PACKAGE
+int
+usb_hcddev_open(struct inode *inode, struct file *fp)
+{
+
+ return 0;
+}
+
+int
+usb_hcddev_close(struct inode *inode, struct file *fp)
+{
+
+ return 0;
+}
+
+int
+usb_hcddev_fasync(int fd, struct file *fp, int mode)
+{
+
+ return fasync_helper(fd, fp, mode, &fasync_q);
+}
+
+int
+usb_hcddev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+
+ switch (cmd) {
+ case HCD_IOC_POWERDOWN: /* SET HCD DEEP SUSPEND MODE */
+ printk("HCD IOC POWERDOWN MODE\n");
+ if(isp1763_hcd->driver->powerdown)
+ isp1763_hcd->driver->powerdown(isp1763_hcd);
+
+ break;
+
+ case HCD_IOC_POWERUP: /* Set HCD POWER UP */
+ printk("HCD IOC POWERUP MODE\n");
+ if(isp1763_hcd->driver->powerup)
+ isp1763_hcd->driver->powerup(isp1763_hcd);
+
+ break;
+ case HCD_IOC_TESTSE0_NACK:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_TEST_SE0_NAK;
+ break;
+ case HCD_IOC_TEST_J:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_TEST_J;
+ break;
+ case HCD_IOC_TEST_K:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_TEST_K;
+ break;
+
+ case HCD_IOC_TEST_TESTPACKET:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_TEST_PACKET;
+ break;
+ case HCD_IOC_TEST_FORCE_ENABLE:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_TEST_FORCE_ENABLE;
+ break;
+ case HCD_IOC_TEST_SUSPEND_RESUME:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_HS_HOST_PORT_SUSPEND_RESUME;
+ break;
+ case HCD_IOC_TEST_SINGLE_STEP_GET_DEV_DESC:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_SINGLE_STEP_GET_DEV_DESC;
+ break;
+ case HCD_IOC_TEST_SINGLE_STEP_SET_FEATURE:
+ HostComplianceTest = HOST_COMPILANCE_TEST_ENABLE;
+ HostTest = HOST_COMP_SINGLE_STEP_SET_FEATURE;
+ break;
+ case HCD_IOC_TEST_STOP:
+ HostComplianceTest = 0;
+ HostTest = 0;
+ break;
+ case HCD_IOC_SUSPEND_BUS:
+ printk("isp1763:SUSPEND bus\n");
+ if(isp1763_hcd->driver->suspend)
+ isp1763_hcd->driver->suspend(isp1763_hcd);
+ break;
+ case HCD_IOC_RESUME_BUS:
+ printk("isp1763:RESUME bus\n");
+ if(isp1763_hcd->driver->resume)
+ isp1763_hcd->driver->resume(isp1763_hcd);
+ break;
+ case HCD_IOC_REMOTEWAKEUP_BUS:
+ printk("isp1763:SUSPEND bus\n");
+ if(isp1763_hcd->driver->remotewakeup)
+ isp1763_hcd->driver->remotewakeup(isp1763_hcd);
+ break;
+ default:
+
+ break;
+
+ }
+ return 0;
+}
+
+/* HCD file operations */
+static struct file_operations usb_hcddev_fops = {
+ owner:THIS_MODULE,
+ read:NULL,
+ write:NULL,
+ poll:NULL,
+ unlocked_ioctl:usb_hcddev_ioctl,
+ open:usb_hcddev_open,
+ release:usb_hcddev_close,
+ fasync:usb_hcddev_fasync,
+};
+
+#endif
+
+
+static int __init
+pehci_module_init(void)
+{
+ int result = 0;
+ phci_hcd_mem_init();
+
+ /*register driver */
+ result = isp1763_register_driver(&pehci_hcd_pci_driver);
+ if (!result) {
+ info("Host Driver has been Registered");
+ } else {
+ err("Host Driver has not been Registered with errors : %x",
+ result);
+ }
+
+#ifdef THREAD_BASED
+ pehci_hcd_process_irq_in_thread(&(g_pehci_hcd->usb_hcd));
+ printk("kernel_thread() Enter\n");
+#endif
+
+#ifdef HCD_PACKAGE
+ printk("Register Char Driver for HCD\n");
+ result = register_chrdev(USB_HCD_MAJOR, USB_HCD_MODULE_NAME,
+ &usb_hcddev_fops);
+
+#endif
+ return result;
+
+}
+
+static void __exit
+pehci_module_cleanup(void)
+{
+#ifdef THREAD_BASED
+ printk("module exit: Sending signal to stop thread\n");
+ if (g_stUsbItThreadHandler.phThreadTask != NULL)
+ {
+ send_sig(SIGKILL, g_stUsbItThreadHandler.phThreadTask, 1);
+ mdelay(6);
+ }
+#endif
+
+#ifdef HCD_PACKAGE
+ unregister_chrdev(USB_HCD_MAJOR, USB_HCD_MODULE_NAME);
+#endif
+ isp1763_unregister_driver(&pehci_hcd_pci_driver);
+}
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+module_init(pehci_module_init);
+module_exit(pehci_module_cleanup);
diff --git a/drivers/usb/host/isp1763-hcd.h b/drivers/usb/host/isp1763-hcd.h
new file mode 100644
index 00000000000..2361952b0f5
--- /dev/null
+++ b/drivers/usb/host/isp1763-hcd.h
@@ -0,0 +1,755 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* Refer to file ~/drivers/usb/host/ehci-dbg.h for copyright owners (kernel version 2.6.9)
+* Code is modified for ST-Ericsson product
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#ifndef __PEHCI_H__
+#define __PEHCI_H__
+
+
+#define DRIVER_AUTHOR "ST-ERICSSON "
+#define DRIVER_DESC "ISP1763 'Enhanced' Host Controller (EHCI) Driver"
+
+/* bus related stuff */
+#define __ACTIVE 0x01
+#define __SLEEPY 0x02
+#define __SUSPEND 0x04
+#define __TRANSIENT 0x80
+
+#define USB_STATE_HALT 0
+#define USB_STATE_RUNNING (__ACTIVE)
+#define USB_STATE_READY (__ACTIVE|__SLEEPY)
+#define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
+#define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT)
+#define USB_STATE_SUSPENDED (__SUSPEND)
+
+/* System flags */
+#define HCD_MEMORY 0x0001
+#define HCD_USB2 0x0020
+#define HCD_USB11 0x0010
+
+#define HCD_IS_RUNNING(state) ((state) & __ACTIVE)
+#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+
+
+/*---------------------------------------------------
+ * Host controller related
+ -----------------------------------------------------*/
+/* IRQ line for the ISP1763 */
+#define HCD_IRQ IRQ_GPIO(25)
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+#define STS_PCD (1<<2) /* port change detect */
+/* NOTE: urb->transfer_flags expected to not use this bit !!! */
+#define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */
+
+/* Bits definations for qha*/
+/* Bits PID*/
+#define SETUP_PID (2)
+#define OUT_PID (0)
+#define IN_PID (1)
+
+/* Bits MULTI*/
+#define MULTI(x) ((x)<< 29)
+#define XFER_PER_UFRAME(x) (((x) >> 29) & 0x3)
+
+/*Active, EP type and speed bits */
+#define QHA_VALID (1<<0)
+#define QHA_ACTIVE (1<<31)
+
+/*1763 error bit maps*/
+#define HC_MSOF_INT (1<< 0)
+#define HC_MSEC_INT (1 << 1)
+#define HC_EOT_INT (1 << 3)
+#define HC_OPR_REG_INT (1<<4)
+#define HC_CLK_RDY_INT (1<<6)
+#define HC_INTL_INT (1 << 7)
+#define HC_ATL_INT (1 << 8)
+#define HC_ISO_INT (1 << 9)
+#define HC_OTG_INT (1 << 10)
+
+/*PTD error codes*/
+#define PTD_STATUS_HALTED (1 << 30)
+#define PTD_XACT_ERROR (1 << 28)
+#define PTD_BABBLE (1 << 29)
+#define PTD_ERROR (PTD_STATUS_HALTED | PTD_XACT_ERROR | PTD_BABBLE)
+/*ep types*/
+#define EPTYPE_BULK (2 << 12)
+#define EPTYPE_CONTROL (0 << 12)
+#define EPTYPE_INT (3 << 12)
+#define EPTYPE_ISO (1 << 12)
+
+#define PHCI_QHA_LENGTH 32
+
+#define usb_inc_dev_use usb_get_dev
+#define usb_dec_dev_use usb_put_dev
+#define usb_free_dev usb_put_dev
+/*1763 host controller periodic size*/
+#define PTD_PERIODIC_SIZE 16
+#define MAX_PERIODIC_SIZE 16
+#define PTD_FRAME_MASK 0x1f
+/*periodic list*/
+struct _periodic_list {
+ int framenumber;
+ struct list_head sitd_itd_head;
+ char high_speed; /*1 - HS ; 0 - FS*/
+ u16 ptdlocation;
+};
+typedef struct _periodic_list periodic_list;
+
+
+/*iso ptd*/
+struct _isp1763_isoptd {
+ u32 td_info1;
+ u32 td_info2;
+ u32 td_info3;
+ u32 td_info4;
+ u32 td_info5;
+ u32 td_info6;
+ u32 td_info7;
+ u32 td_info8;
+} __attribute__ ((aligned(32)));
+
+typedef struct _isp1763_isoptd isp1763_isoptd;
+
+struct _isp1763_qhint {
+ u32 td_info1;
+ u32 td_info2;
+ u32 td_info3;
+ u32 td_info4;
+ u32 td_info5;
+#define INT_UNDERRUN (1 << 2)
+#define INT_BABBLE (1 << 1)
+#define INT_EXACT (1 << 0)
+ u32 td_info6;
+ u32 td_info7;
+ u32 td_info8;
+} __attribute__ ((aligned(32)));
+
+typedef struct _isp1763_qhint isp1763_qhint;
+
+
+struct _isp1763_qha {
+ u32 td_info1; /* First 32 bit */
+ u32 td_info2; /* Second 32 bit */
+ u32 td_info3; /* third 32 bit */
+ u32 td_info4; /* fourth 32 bit */
+ u32 reserved[4];
+};
+typedef struct _isp1763_qha isp1763_qha, *pisp1763_qha;
+
+
+
+
+/*this does not cover all interrupts in 1763 chip*/
+typedef struct _ehci_regs {
+
+ /*standard ehci registers */
+ u32 command;
+ u32 usbinterrupt;
+ u32 usbstatus;
+ u32 hcsparams;
+ u32 frameindex;
+
+ /*isp1763 interrupt specific registers */
+ u16 hwmodecontrol;
+ u16 interrupt;
+ u16 interruptenable;
+ u32 interruptthreshold;
+ u16 iso_irq_mask_or;
+ u16 int_irq_mask_or;
+ u16 atl_irq_mask_or;
+ u16 iso_irq_mask_and;
+ u16 int_irq_mask_and;
+ u16 atl_irq_mask_and;
+ u16 buffer_status;
+
+ /*isp1763 initialization registers */
+ u32 reset;
+ u32 configflag;
+ u32 ports[4];
+ u32 pwrdwn_ctrl;
+
+ /*isp1763 transfer specific registers */
+ u16 isotddonemap;
+ u16 inttddonemap;
+ u16 atltddonemap;
+ u16 isotdskipmap;
+ u16 inttdskipmap;
+ u16 atltdskipmap;
+ u16 isotdlastmap;
+ u16 inttdlastmap;
+ u16 atltdlastmap;
+ u16 scratch;
+
+} ehci_regs, *pehci_regs;
+
+/*memory management structures*/
+#define MEM_KV
+#ifdef MEM_KV
+typedef struct isp1763_mem_addr {
+ u32 phy_addr; /* Physical address of the memory */
+ u32 virt_addr; /* after ioremap() function call */
+ u8 num_alloc; /* In case n*smaller size is allocated then for clearing purpose */
+ u32 blk_size; /*block size */
+ u8 blk_num; /* number of the block */
+ u8 used; /*used/free */
+} isp1763_mem_addr_t;
+#else
+typedef struct isp1763_mem_addr {
+ void *phy_addr; /* Physical address of the memory */
+ void *virt_addr; /* after ioremap() function call */
+ u8 usage;
+ u32 blk_size; /*block size */
+} isp1763_mem_addr_t;
+
+#endif
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
+
+/*next queuehead in execution*/
+#define QH_NEXT(dma) cpu_to_le32((u32)dma)
+
+struct ehci_qh {
+ /* first part defined by EHCI spec */
+ u32 hw_next; /* see EHCI 3.6.1 */
+ u32 hw_info1; /* see EHCI 3.6.2 */
+
+ u32 hw_info2; /* see EHCI 3.6.2 */
+ u32 hw_current; /* qtd list - see EHCI 3.6.4 */
+
+ /* qtd overlay (hardware parts of a struct ehci_qtd) */
+ u32 hw_qtd_next;
+ u32 hw_alt_next;
+ u32 hw_token;
+ u32 hw_buf[5];
+ u32 hw_buf_hi[5];
+
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ struct list_head qtd_list; /* sw qtd list */
+ struct ehci_qtd *dummy;
+ struct ehci_qh *reclaim; /* next to reclaim */
+
+ atomic_t refcount;
+ wait_queue_head_t waitforcomplete;
+ unsigned stamp;
+
+ u8 qh_state;
+
+ /* periodic schedule info */
+ u8 usecs; /* intr bandwidth */
+ u8 gap_uf; /* uframes split/csplit gap */
+ u8 c_usecs; /* ... split completion bw */
+ unsigned short period; /* polling interval */
+ unsigned short start; /* where polling starts */
+ u8 datatoggle; /*data toggle */
+
+ /*handling the ping stuffs */
+ u8 ping; /*ping bit */
+
+ /*qtd <-> ptd management */
+
+ u32 qtd_ptd_index; /* Td-PTD map index for this ptd */
+ u32 type; /* endpoint type */
+
+ /*iso stuffs */
+ struct usb_host_endpoint *ep;
+ int next_uframe; /*next uframe for this endpoint */
+ struct list_head itd_list; /*list of tds to this endpoint */
+ isp1763_mem_addr_t memory_addr;
+ struct _periodic_list periodic_list;
+ /*scheduling requirements for this endpoint */
+ u32 ssplit;
+ u32 csplit;
+ u8 totalptds; // total number of PTDs needed for current URB
+ u8 actualptds; // scheduled PTDs until now for current URB
+};
+
+/* urb private part for the driver. */
+typedef struct {
+ struct ehci_qh *qh;
+ u16 length; /* number of tds associated with this request */
+ u16 td_cnt; /* number of tds already serviced */
+ int state; /* State machine state when URB is deleted */
+ int timeout; /* timeout for bulk transfers */
+ wait_queue_head_t wait; /* wait State machine state when URB is deleted */
+ /*FIX solve the full speed dying */
+ struct timer_list urb_timer;
+ struct list_head qtd_list;
+ struct ehci_qtd *qtd[0]; /* list pointer to all corresponding TDs associated with this request */
+
+} urb_priv_t;
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+
+/*Defination required for the ehci Queuehead */
+#define QH_HEAD 0x00008000
+#define QH_STATE_LINKED 1 /* HC sees this */
+#define QH_STATE_UNLINK 2 /* HC may still see this */
+#define QH_STATE_IDLE 3 /* HC doesn't see this */
+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
+#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
+#define QH_STATE_TAKE_NEXT 8 /*take the new transfer from */
+#define NO_FRAME ((unsigned short)~0) /* pick new start */
+
+
+#define EHCI_ITD_TRANLENGTH 0x0fff0000 /*transaction length */
+#define EHCI_ITD_PG 0x00007000 /*page select */
+#define EHCI_ITD_TRANOFFSET 0x00000fff /*transaction offset */
+#define EHCI_ITD_BUFFPTR 0xfffff000 /*buffer pointer */
+
+struct ehci_sitd {
+ /* first part defined by EHCI spec */
+ u32 hw_next; /* see EHCI 3.3.1 */
+ u32 hw_transaction[8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
+#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
+#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
+
+#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
+
+ u32 hw_bufp[7]; /* see EHCI 3.3.3 */
+ u32 hw_bufp_hi[7]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t sitd_dma; /* for this itd */
+ struct urb *urb;
+ struct list_head sitd_list; /* list of urb frames' itds */
+ dma_addr_t buf_dma; /* frame's buffer address */
+
+ /* for now, only one hw_transaction per itd */
+ u32 transaction;
+ u16 index; /* in urb->iso_frame_desc */
+ u16 uframe; /* in periodic schedule */
+ u16 usecs;
+ /*memory address */
+ struct isp1763_mem_addr mem_addr;
+ int length;
+ u32 framenumber;
+ u32 ptdframe;
+ int sitd_index;
+ /*scheduling fields */
+ u32 ssplit;
+ u32 csplit;
+ u32 start_frame;
+};
+
+struct ehci_itd {
+ /* first part defined by EHCI spec */
+ u32 hw_next; /* see EHCI 3.3.1 */
+ u32 hw_transaction[8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
+#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
+#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
+
+#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
+
+ u32 hw_bufp[7]; /* see EHCI 3.3.3 */
+ u32 hw_bufp_hi[7]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t itd_dma; /* for this itd */
+ struct urb *urb;
+ struct list_head itd_list; /* list of urb frames' itds */
+ dma_addr_t buf_dma; /* frame's buffer address */
+ u8 num_of_pkts; /*number of packets for this ITD */
+ /* for now, only one hw_transaction per itd */
+ u32 transaction;
+ u16 index; /* in urb->iso_frame_desc */
+ u16 uframe; /* in periodic schedule */
+ u16 usecs;
+ /*memory address */
+ struct isp1763_mem_addr mem_addr;
+ int length;
+ u32 multi;
+ u32 framenumber;
+ u32 ptdframe;
+ int itd_index;
+ /*scheduling fields */
+ u32 ssplit;
+ u32 csplit;
+};
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+ /* first part defined by EHCI spec */
+ u32 hw_next; /* see EHCI 3.5.1 */
+ u32 hw_alt_next; /* see EHCI 3.5.2 */
+ u32 hw_token; /* see EHCI 3.5.3 */
+
+ u32 hw_buf[5]; /* see EHCI 3.5.4 */
+ u32 hw_buf_hi[5]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t qtd_dma; /* qtd address */
+ struct list_head qtd_list; /* sw qtd list */
+ struct urb *urb; /* qtd's urb */
+ size_t length; /* length of buffer */
+ u32 state; /*state of the qtd */
+#define QTD_STATE_NEW 0x100
+#define QTD_STATE_DONE 0x200
+#define QTD_STATE_SCHEDULED 0x400
+#define QTD_STATE_LAST 0x800
+ struct isp1763_mem_addr mem_addr;
+};
+
+#define QTD_TOGGLE (1 << 31) /* data toggle */
+#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define QTD_IOC (1 << 15) /* interrupt on complete */
+#define QTD_CERR(tok) (((tok)>>10) & 0x3)
+#define QTD_PID(tok) (((tok)>>8) & 0x3)
+#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
+#define QTD_STS_HALT (1 << 6) /* halted on error */
+#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
+#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
+#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
+#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
+#define QTD_STS_STS (1 << 1) /* split transaction state */
+#define QTD_STS_PING (1 << 0) /* issue PING? */
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
+#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
+
+struct _phci_driver;
+struct _isp1763_hcd;
+#define EHCI_MAX_ROOT_PORTS 1
+
+#include <linux/usb/hcd.h>
+
+#define USBNET
+#ifdef USBNET
+struct isp1763_async_cleanup_urb {
+ struct list_head urb_list;
+ struct urb *urb;
+};
+#endif
+
+
+/*host controller*/
+typedef struct _phci_hcd {
+
+ struct usb_hcd usb_hcd;
+ spinlock_t lock;
+
+ /* async schedule support */
+ struct ehci_qh *async;
+ struct ehci_qh *reclaim;
+ /* periodic schedule support */
+ unsigned periodic_size;
+ int next_uframe; /* scan periodic, start here */
+ int periodic_sched; /* periodic activity count */
+ int periodic_more_urb;
+ struct usb_device *otgdev; /*otg deice, with address 2 */
+ struct timer_list rh_timer; /* drives root hub */
+ struct list_head dev_list; /* devices on this bus */
+ struct list_head urb_list; /*iso testing */
+
+ /*msec break in interrupts */
+ atomic_t nuofsofs;
+ atomic_t missedsofs;
+
+ struct isp1763_dev *dev;
+ /*hw info */
+ u8 *iobase;
+ u32 iolength;
+ u8 *plxiobase;
+ u32 plxiolength;
+
+ int irq; /* irq allocated */
+ int state; /*state of the host controller */
+ unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
+ ehci_regs regs;
+
+ struct _isp1763_qha qha;
+ struct _isp1763_qhint qhint;
+ struct _isp1763_isoptd isotd;
+
+ struct tasklet_struct tasklet;
+ /*this timer is going to run every 20 msec */
+ struct timer_list watchdog;
+ void (*worker_function) (struct _phci_hcd * hcd);
+ struct _periodic_list periodic_list[PTD_PERIODIC_SIZE];
+#ifdef USBNET
+ struct isp1763_async_cleanup_urb cleanup_urb;
+#endif
+} phci_hcd, *pphci_hcd;
+
+/*usb_device->hcpriv, points to this structure*/
+typedef struct hcd_dev {
+ struct list_head dev_list;
+ struct list_head urb_list;
+} hcd_dev;
+
+#define usb_hcd_to_pehci_hcd(hcd) container_of(hcd, struct _phci_hcd, usb_hcd)
+
+/*td allocation*/
+#ifdef CONFIG_PHCI_MEM_SLAB
+
+#define qha_alloc(t,c) kmem_cache_alloc(c,ALLOC_FLAGS)
+#define qha_free(c,x) kmem_cache_free(c,x)
+static kmem_cache_t *qha_cache, *qh_cache, *qtd_cache;
+static int
+phci_hcd_mem_init(void)
+{
+ /* qha TDs accessed by controllers and host */
+ qha_cache = kmem_cache_create("phci_ptd", sizeof(isp1763_qha), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!qha_cache) {
+ printk("no TD cache?");
+ return -ENOMEM;
+ }
+
+ /* qh TDs accessed by controllers and host */
+ qh_cache = kmem_cache_create("phci_ptd", sizeof(isp1763_qha), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!qh_cache) {
+ printk("no TD cache?");
+ return -ENOMEM;
+ }
+
+ /* qtd accessed by controllers and host */
+ qtd_cache = kmem_cache_create("phci_ptd", sizeof(isp1763_qha), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!qtd_cache) {
+ printk("no TD cache?");
+ return -ENOMEM;
+ }
+ return 0;
+}
+static void
+phci_mem_cleanup(void)
+{
+ if (qha_cache && kmem_cache_destroy(qha_cache))
+ err("td_cache remained");
+ qha_cache = 0;
+}
+#else
+
+#define qha_alloc(t,c) kmalloc(t,ALLOC_FLAGS)
+#define qha_free(c,x) kfree(x)
+#define qha_cache 0
+
+
+#ifdef CONFIG_ISO_SUPPORT
+/*memory constants*/
+#define BLK_128_ 2
+#define BLK_256_ 3
+#define BLK_1024_ 1
+#define BLK_2048_ 3
+#define BLK_4096_ 3 //1
+#define BLK_8196_ 0 //1
+#define BLK_TOTAL (BLK_128_+BLK_256_ + BLK_1024_ +BLK_2048_+ BLK_4096_+BLK_8196_)
+
+#define BLK_SIZE_128 128
+#define BLK_SIZE_256 256
+#define BLK_SIZE_1024 1024
+#define BLK_SIZE_2048 2048
+#define BLK_SIZE_4096 4096
+#define BLK_SIZE_8192 8192
+
+#define COMMON_MEMORY 1
+
+#else
+#define BLK_256_ 8
+#define BLK_1024_ 6
+#define BLK_4096_ 3
+#define BLK_TOTAL (BLK_256_ + BLK_1024_ + BLK_4096_)
+#define BLK_SIZE_256 256
+#define BLK_SIZE_1024 1024
+#define BLK_SIZE_4096 4096
+#endif
+static void phci_hcd_mem_init(void);
+static inline void
+phci_mem_cleanup(void)
+{
+ return;
+}
+
+#endif
+
+#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+/* 19:16 for port testing */
+/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_OCC (1<<5) /* over current change */
+
+#define PORT_OC (1<<4) /* over current active */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+/*Legends,
+ * ATL control, bulk transfer
+ * INTL interrupt transfer
+ * ISTL iso transfer
+ * */
+
+/*buffer(transfer) bitmaps*/
+#define ATL_BUFFER 0x1
+#define INT_BUFFER 0x2
+#define ISO_BUFFER 0x4
+#define BUFFER_MAP 0x7
+
+/* buffer type for ST-ERICSSON HC */
+#define TD_PTD_BUFF_TYPE_ATL 0 /* ATL buffer */
+#define TD_PTD_BUFF_TYPE_INTL 1 /* INTL buffer */
+#define TD_PTD_BUFF_TYPE_ISTL 2 /* ISO buffer */
+#define TD_PTD_TOTAL_BUFF_TYPES (TD_PTD_BUFF_TYPE_ISTL +1)
+/*maximum number of tds per transfer type*/
+#define TD_PTD_MAX_BUFF_TDS 16
+
+/*invalid td index in the headers*/
+#define TD_PTD_INV_PTD_INDEX 0xFFFF
+/*Host controller buffer defination*/
+#define INVALID_FRAME_NUMBER 0xFFFFFFFF
+/*per td transfer size*/
+#define HC_ATL_PL_SIZE 4096
+#define HC_ISTL_PL_SIZE 1024
+#define HC_INTL_PL_SIZE 1024
+
+/*TD_PTD_MAP states*/
+#define TD_PTD_NEW 0x0000
+#define TD_PTD_ACTIVE 0x0001
+#define TD_PTD_IDLE 0x0002
+#define TD_PTD_REMOVE 0x0004
+#define TD_PTD_RELOAD 0x0008
+#define TD_PTD_IN_SCHEDULE 0x0010
+#define TD_PTD_DONE 0x0020
+
+#define PTD_RETRY(x) (((x) >> 23) & 0x3)
+#define PTD_PID(x) (((x) >> 10) & (0x3))
+#define PTD_NEXTTOGGLE(x) (((x) >> 25) & (0x1))
+#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
+#define PTD_XFERRED_NONHSLENGTH(x) ((x) & 0x7ff)
+#define PTD_PING_STATE(x) (((x) >> 26) & (0x1))
+
+/* urb state*/
+#define DELETE_URB 0x0008
+#define NO_TRANSFER_ACTIVE 0xFFFF
+#define NO_TRANSFER_DONE 0x0000
+#define MAX_PTD_BUFFER_SIZE 4096 /*max ptd size */
+
+/*information of the td in headers of host memory*/
+typedef struct td_ptd_map {
+ u32 state; /* ACTIVE, NEW, TO_BE_REMOVED */
+ u8 datatoggle; /*to preserve the data toggle for ATL/ISTL transfers */
+ u32 ptd_bitmap; /* Bitmap of this ptd in HC headers */
+ u32 ptd_header_addr; /* headers address of this td */
+ u32 ptd_data_addr; /*data address of this td to write in and read from */
+ /*this is address is actual RAM address not the CPU address
+ * RAM address = (CPU ADDRESS-0x400) >> 3
+ * */
+ u32 ptd_ram_data_addr;
+ u8 lasttd; /*last td , complete the transfer */
+ struct ehci_qh *qh; /* endpoint */
+ struct ehci_qtd *qtd; /* qtds for this endpoint */
+ struct ehci_itd *itd; /*itd pointer */
+ struct ehci_sitd *sitd; /*itd pointer */
+ /*iso specific only */
+ u32 grouptdmap; /*if td need to complete with error, then process all the tds
+ in the groupmap */
+} td_ptd_map_t;
+
+/*buffer(ATL/ISTL/INTL) managemnet*/
+typedef struct td_ptd_map_buff {
+ u8 buffer_type; /* Buffer type: BUFF_TYPE_ATL/INTL/ISTL0/ISTL1 */
+ u8 active_ptds; /* number of active td's in the buffer */
+ u8 total_ptds; /* Total number of td's present in the buffer (active + tobe removed + skip) */
+ u8 max_ptds; /* Maximum number of ptd's(32) this buffer can withstand */
+ u16 active_ptd_bitmap; /* Active PTD's bitmap */
+ u16 pending_ptd_bitmap; /* skip PTD's bitmap */
+ td_ptd_map_t map_list[TD_PTD_MAX_BUFF_TDS]; /* td_ptd_map list */
+} td_ptd_map_buff_t;
+
+
+#define USB_HCD_MAJOR 245
+#define USB_HCD_MODULE_NAME "isp1763hcd"
+
+#if 1
+static char devpath[] = "/dev/isp1763hcd";
+#endif
+
+#define HCD_IOC_MAGIC 'h'
+
+#define HCD_IOC_POWERDOWN _IO(HCD_IOC_MAGIC, 1)
+#define HCD_IOC_POWERUP _IO(HCD_IOC_MAGIC, 2)
+#define HCD_IOC_TESTSE0_NACK _IO(HCD_IOC_MAGIC, 3)
+#define HCD_IOC_TEST_J _IO(HCD_IOC_MAGIC,4)
+#define HCD_IOC_TEST_K _IO(HCD_IOC_MAGIC,5)
+#define HCD_IOC_TEST_TESTPACKET _IO(HCD_IOC_MAGIC,6)
+#define HCD_IOC_TEST_FORCE_ENABLE _IO(HCD_IOC_MAGIC,7)
+#define HCD_IOC_TEST_SUSPEND_RESUME _IO(HCD_IOC_MAGIC,8)
+#define HCD_IOC_TEST_SINGLE_STEP_GET_DEV_DESC _IO(HCD_IOC_MAGIC,9)
+#define HCD_IOC_TEST_SINGLE_STEP_SET_FEATURE _IO(HCD_IOC_MAGIC,10)
+#define HCD_IOC_TEST_STOP _IO(HCD_IOC_MAGIC,11)
+#define HCD_IOC_SUSPEND_BUS _IO(HCD_IOC_MAGIC,12)
+#define HCD_IOC_RESUME_BUS _IO(HCD_IOC_MAGIC,13)
+#define HCD_IOC_REMOTEWAKEUP_BUS _IO(HCD_IOC_MAGIC,14)
+
+#define HOST_COMPILANCE_TEST_ENABLE 1
+#define HOST_COMP_TEST_SE0_NAK 1
+#define HOST_COMP_TEST_J 2
+#define HOST_COMP_TEST_K 3
+#define HOST_COMP_TEST_PACKET 4
+#define HOST_COMP_TEST_FORCE_ENABLE 5
+#define HOST_COMP_HS_HOST_PORT_SUSPEND_RESUME 6
+#define HOST_COMP_SINGLE_STEP_GET_DEV_DESC 7
+#define HOST_COMP_SINGLE_STEP_SET_FEATURE 8
+
+#endif
diff --git a/drivers/usb/host/isp1763-itdptd.c b/drivers/usb/host/isp1763-itdptd.c
new file mode 100644
index 00000000000..8e0c16ee31f
--- /dev/null
+++ b/drivers/usb/host/isp1763-itdptd.c
@@ -0,0 +1,2156 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a host controller driver file. Isochronous event processing is handled here.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+#ifdef CONFIG_ISO_SUPPORT
+void phcd_clean_periodic_ep(void);
+#endif
+
+#ifdef CONFIG_ISO_SUPPORT
+
+#define MAX_URBS 8
+#define MAX_EPS 2/*maximum 2 endpoints supported in ISO transfers.*/
+/*number of microframe per frame which is scheduled, for high speed device
+* actually , NUMMICROFRAME should be 8 , but the micro frame #7 is fail , so
+* there's just 4 microframe is used (#0 -> #4)
+* Writer : LyNguyen - 25Nov09
+*/
+#define NUMMICROFRAME 8
+struct urb *gstUrb_pending[MAX_URBS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+struct usb_host_endpoint *periodic_ep[MAX_EPS];
+
+int giUrbCount = 0; /* count the pending urb*/
+int giUrbIndex = 0; /*the index of urb need to be scheduled next*/
+/*
+ * phcd_iso_sitd_to_ptd - convert an SITD into a PTD
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct ehci_sitd *sitd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more specific elements.
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * void * ptd
+ * - Points to the ISO ptd structure that needs to be initialized
+ *
+ * API Description
+ * This is mainly responsible for:
+ * -Initializing the PTD that will be used for the ISO transfer
+ */
+void *
+phcd_iso_sitd_to_ptd(phci_hcd * hcd,
+ struct ehci_sitd *sitd, struct urb *urb, void *ptd)
+{
+ struct _isp1763_isoptd *iso_ptd;
+ struct isp1763_mem_addr *mem_addr;
+
+ unsigned long max_packet, mult, length, td_info1, td_info3;
+ unsigned long token, port_num, hub_num, data_addr;
+ unsigned long frame_number;
+
+ iso_dbg(ISO_DBG_ENTRY, "phcd_iso_sitd_to_ptd entry\n");
+
+ /* Variable initialization */
+ iso_ptd = (struct _isp1763_isoptd *) ptd;
+ mem_addr = &sitd->mem_addr;
+
+ /*
+ * For both ISO and INT endpoints descriptors, new bit fields we added to
+ * specify whether or not the endpoint supports high bandwidth, and if so
+ * the number of additional packets that the endpoint can support during a
+ * single microframe.
+ * Bits 12:11 specify whether the endpoint supports high-bandwidth transfers
+ * Valid values:
+ * 00 None (1 transaction/uFrame)
+ * 01 1 additional transaction
+ * 10 2 additional transactions
+ * 11 reserved
+ */
+ max_packet = usb_maxpacket(urb->dev, urb->pipe,usb_pipeout(urb->pipe));
+
+ /*
+ * We need to add 1 since our Multi starts with 1 instead of the USB specs defined
+ * zero (0).
+ */
+ mult = 1 + ((max_packet >> 11) & 0x3);
+ max_packet &= 0x7ff;
+
+ /* This is the size of the request (bytes to write or bytes to read) */
+ length = sitd->length;
+
+ /*
+ * Set V bit to indicate that there is payload to be sent or received. And
+ * indicate that the current PTD is active.
+ */
+ td_info1 = QHA_VALID;
+
+ /*
+ * Set the number of bytes that can be transferred by this PTD. This indicates
+ * the depth of the data field.
+ */
+ td_info1 |= (length << 3);
+
+ /*
+ * Set the maximum packet length which indicates the maximum number of bytes that
+ * can be sent to or received from the endpoint in a single data packet.
+ */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /*
+ * According to the ISP1763 specs for sITDs, OUT token max packet should
+ * not be more than 188 bytes, while IN token max packet not more than
+ * 192 bytes (ISP1763 Rev 3.01, Table 72, page 79
+ */
+ if (usb_pipein(urb->pipe) && (max_packet > 192)) {
+ iso_dbg(ISO_DBG_INFO,
+ "IN Max packet over maximum\n");
+ max_packet = 192;
+ }
+
+ if ((!usb_pipein(urb->pipe)) && (max_packet > 188)) {
+ iso_dbg(ISO_DBG_INFO,
+ "OUT Max packet over maximum\n");
+ max_packet = 188;
+ }
+ }
+ td_info1 |= (max_packet << 18);
+
+ /*
+ * Place the FIRST BIT of the endpoint number here.
+ */
+ td_info1 |= (usb_pipeendpoint(urb->pipe) << 31);
+
+ /*
+ * Set the number of successive packets the HC can submit to the endpoint.
+ */
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ td_info1 |= MULTI(mult);
+ }
+
+ /* Set the first DWORD */
+ iso_ptd->td_info1 = td_info1;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD0 = 0x%08x\n",
+ iso_ptd->td_info1);
+
+ /*
+ * Since the first bit have already been added on the first DWORD of the PTD
+ * we only need to add the last 3-bits of the endpoint number.
+ */
+ token = (usb_pipeendpoint(urb->pipe) & 0xE) >> 1;
+
+ /*
+ * Get the device address and set it accordingly to its assigned bits of the 2nd
+ * DWORD.
+ */
+ token |= usb_pipedevice(urb->pipe) << 3;
+
+ /* See a split transaction is needed */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /*
+ * If we are performing a SPLIT transaction indicate that it is so by setting
+ * the S bit of the second DWORD.
+ */
+ token |= 1 << 14;
+
+ port_num = urb->dev->ttport;
+ hub_num = urb->dev->tt->hub->devnum;
+
+ /* Set the the port number of the hub or embedded TT */
+ token |= port_num << 18;
+
+ /*
+ * Set the hub address, this should be zero for the internal or
+ * embedded hub
+ */
+ token |= hub_num << 25;
+ }
+
+ /* if(urb->dev->speed != USB_SPEED_HIGH) */
+ /*
+ * Determine if the direction of this pipe is IN, if so set the Token bit of
+ * the second DWORD to indicate it as IN. Since it is initialized to zero and
+ * zero indicates an OUT token, then we do not need anything to the Token bit
+ * if it is an OUT token.
+ */
+ if (usb_pipein(urb->pipe)) {
+ token |= (IN_PID << 10);
+ }
+
+ /* Set endpoint type to Isochronous */
+ token |= EPTYPE_ISO;
+
+ /* Set the second DWORD */
+ iso_ptd->td_info2 = token;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD1 = 0x%08x\n",
+ iso_ptd->td_info2);
+
+ /*
+ * Get the physical address of the memory location that was allocated for this PTD
+ * in the PAYLOAD region, using the formula indicated in sectin 7.2.2 of the ISP1763 specs
+ * rev 3.01 page 17 to 18.
+ */
+ data_addr = ((unsigned long) (mem_addr->phy_addr) & 0xffff) - 0x400;
+ data_addr >>= 3;
+
+ /* Set it to its location in the third DWORD */
+ td_info3 =( 0xffff&data_addr) << 8;
+
+ /*
+ * Set the frame number when this PTD will be sent for ISO OUT or IN
+ * Bits 0 to 2 are don't care, only bits 3 to 7.
+ */
+ frame_number = sitd->framenumber;
+ frame_number = sitd->start_frame;
+ td_info3 |= (0xff& ((frame_number) << 3));
+
+ /* Set the third DWORD */
+ iso_ptd->td_info3 = td_info3;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD2 = 0x%08x\n",
+ iso_ptd->td_info3);
+
+ /*
+ * Set the A bit of the fourth DWORD to 1 to indicate that this PTD is active.
+ * This have the same functionality with the V bit of DWORD0
+ */
+ iso_ptd->td_info4 = QHA_ACTIVE;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD3 = 0x%08x\n",
+ iso_ptd->td_info4);
+
+ /* Set the fourth DWORD to specify which uSOFs the start split needs to be placed */
+ if (usb_pipein(urb->pipe)){
+ iso_ptd->td_info5 = (sitd->ssplit);
+ }else{
+ iso_ptd->td_info5 = (sitd->ssplit << 2);
+ }
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD4 = 0x%08x\n",
+ iso_ptd->td_info5);
+
+ /*
+ * Set the fifth DWORD to specify which uSOFs the complete split needs to be sent.
+ * This is VALID only for IN (since ISO transfers don't have handshake stages)
+ */
+ iso_ptd->td_info6 = sitd->csplit;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD5 = 0x%08x\n",
+ iso_ptd->td_info6);
+
+ /*printk(" [phcd_iso_itd_to_ptd]: DWORD0 = 0x%08x\n",iso_ptd->td_info1);
+ printk(" [phcd_iso_itd_to_ptd]: DWORD1 = 0x%08x\n",iso_ptd->td_info2);
+ printk(" [phcd_iso_itd_to_ptd]: DWORD2 = 0x%08x\n",iso_ptd->td_info3);
+ printk(" [phcd_iso_itd_to_ptd]: DWORD3 = 0x%08x\n",iso_ptd->td_info4);
+ printk(" [phcd_iso_itd_to_ptd]: DWORD4 = 0x%08x\n",iso_ptd->td_info5);
+ printk(" [phcd_iso_itd_to_ptd]: DWORD5 = 0x%08x\n",iso_ptd->td_info6);*/
+ iso_dbg(ISO_DBG_EXIT, "phcd_iso_itd_to_ptd exit\n");
+ return iso_ptd;
+}
+
+
+/*
+ * phcd_iso_itd_to_ptd - convert an ITD into a PTD
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct ehci_itd *itd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more ST-ERICSSON specific elements.
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * void * ptd
+ * - Points to the ISO ptd structure that needs to be initialized
+ *
+ * API Description
+ * This is mainly responsible for:
+ * -Initializing the PTD that will be used for the ISO transfer
+ */
+void *
+phcd_iso_itd_to_ptd(phci_hcd * hcd,
+ struct ehci_itd *itd, struct urb *urb, void *ptd)
+{
+ struct _isp1763_isoptd *iso_ptd;
+ struct isp1763_mem_addr *mem_addr;
+
+ unsigned long max_packet, mult, length, td_info1, td_info3;
+ unsigned long token, port_num, hub_num, data_addr;
+ unsigned long frame_number;
+ int maxpacket;
+ iso_dbg(ISO_DBG_ENTRY, "phcd_iso_itd_to_ptd entry\n");
+
+ /* Variable initialization */
+ iso_ptd = (struct _isp1763_isoptd *) ptd;
+ mem_addr = &itd->mem_addr;
+
+ /*
+ * For both ISO and INT endpoints descriptors, new bit fields we added to
+ * specify whether or not the endpoint supports high bandwidth, and if so
+ * the number of additional packets that the endpoint can support during a
+ * single microframe.
+ * Bits 12:11 specify whether the endpoint supports high-bandwidth transfers
+ * Valid values:
+ * 00 None (1 transaction/uFrame)
+ * 01 1 additional transaction
+ * 10 2 additional transactions
+ * 11 reserved
+ */
+ max_packet = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ /*
+ * We need to add 1 since our Multi starts with 1 instead of the USB specs defined
+ * zero (0).
+ */
+ maxpacket &= 0x7ff;
+ mult = 1 + ((max_packet >> 11) & 0x3);
+
+
+ max_packet &= 0x7ff;
+
+ /* This is the size of the request (bytes to write or bytes to read) */
+ length = itd->length;
+
+ /*
+ * Set V bit to indicate that there is payload to be sent or received. And
+ * indicate that the current PTD is active.
+ */
+ td_info1 = QHA_VALID;
+
+ /*
+ * Set the number of bytes that can be transferred by this PTD. This indicates
+ * the depth of the data field.
+ */
+ td_info1 |= (length << 3);
+
+ /*
+ * Set the maximum packet length which indicates the maximum number of bytes that
+ * can be sent to or received from the endpoint in a single data packet.
+ */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /*
+ * According to the ISP1763 specs for sITDs, OUT token max packet should
+ * not be more than 188 bytes, while IN token max packet not more than
+ * 192 bytes (ISP1763 Rev 3.01, Table 72, page 79
+ */
+ if (usb_pipein(urb->pipe) && (max_packet > 192)) {
+ iso_dbg(ISO_DBG_INFO,
+ "[phcd_iso_itd_to_ptd]: IN Max packet over maximum\n");
+ max_packet = 192;
+ }
+
+ if ((!usb_pipein(urb->pipe)) && (max_packet > 188)) {
+ iso_dbg(ISO_DBG_INFO,
+ "[phcd_iso_itd_to_ptd]: OUT Max packet over maximum\n");
+ max_packet = 188;
+ }
+ } else { /*HIGH SPEED */
+
+ if (max_packet > 1024){
+ max_packet = 1024;
+ }
+ }
+ td_info1 |= (max_packet << 18);
+
+ /*
+ * Place the FIRST BIT of the endpoint number here.
+ */
+ td_info1 |= (usb_pipeendpoint(urb->pipe) << 31);
+
+ /*
+ * Set the number of successive packets the HC can submit to the endpoint.
+ */
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ td_info1 |= MULTI(mult);
+ }
+
+ /* Set the first DWORD */
+ iso_ptd->td_info1 = td_info1;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD0 = 0x%08x\n",
+ iso_ptd->td_info1);
+
+ /*
+ * Since the first bit have already been added on the first DWORD of the PTD
+ * we only need to add the last 3-bits of the endpoint number.
+ */
+ token = (usb_pipeendpoint(urb->pipe) & 0xE) >> 1;
+
+ /*
+ * Get the device address and set it accordingly to its assigned bits of the 2nd
+ * DWORD.
+ */
+ token |= usb_pipedevice(urb->pipe) << 3;
+
+ /* See a split transaction is needed */
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /*
+ * If we are performing a SPLIT transaction indicate that it is so by setting
+ * the S bit of the second DWORD.
+ */
+ token |= 1 << 14;
+
+ port_num = urb->dev->ttport;
+ hub_num = urb->dev->tt->hub->devnum;
+
+ /* Set the the port number of the hub or embedded TT */
+ token |= port_num << 18;
+
+ /*
+ * Set the hub address, this should be zero for the internal or
+ * embedded hub
+ */
+ token |= hub_num << 25;
+ }
+
+ /* if(urb->dev->speed != USB_SPEED_HIGH) */
+ /*
+ * Determine if the direction of this pipe is IN, if so set the Token bit of
+ * the second DWORD to indicate it as IN. Since it is initialized to zero and
+ * zero indicates an OUT token, then we do not need anything to the Token bit
+ * if it is an OUT token.
+ */
+ if (usb_pipein(urb->pipe)){
+ token |= (IN_PID << 10);
+ }
+
+ /* Set endpoint type to Isochronous */
+ token |= EPTYPE_ISO;
+
+ /* Set the second DWORD */
+ iso_ptd->td_info2 = token;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD1 = 0x%08x\n",
+ iso_ptd->td_info2);
+
+ /*
+ * Get the physical address of the memory location that was allocated for this PTD
+ * in the PAYLOAD region, using the formula indicated in sectin 7.2.2 of the ISP1763 specs
+ * rev 3.01 page 17 to 18.
+ */
+ data_addr = ((unsigned long) (mem_addr->phy_addr) & 0xffff) - 0x400;
+ data_addr >>= 3;
+
+ /* Set it to its location in the third DWORD */
+ td_info3 = (data_addr&0xffff) << 8;
+
+ /*
+ * Set the frame number when this PTD will be sent for ISO OUT or IN
+ * Bits 0 to 2 are don't care, only bits 3 to 7.
+ */
+ frame_number = itd->framenumber;
+ td_info3 |= (0xff&(frame_number << 3));
+
+ /* Set the third DWORD */
+ iso_ptd->td_info3 = td_info3;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD2 = 0x%08x\n",
+ iso_ptd->td_info3);
+
+ /*
+ * Set the A bit of the fourth DWORD to 1 to indicate that this PTD is active.
+ * This have the same functionality with the V bit of DWORD0
+ */
+ iso_ptd->td_info4 = QHA_ACTIVE;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD3 = 0x%08x\n",
+ iso_ptd->td_info4);
+
+ /* Set the fourth DWORD to specify which uSOFs the start split needs to be placed */
+ iso_ptd->td_info5 = itd->ssplit;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD4 = 0x%08x\n",
+ iso_ptd->td_info5);
+
+ /*
+ * Set the fifth DWORD to specify which uSOFs the complete split needs to be sent.
+ * This is VALID only for IN (since ISO transfers don't have handshake stages)
+ */
+ iso_ptd->td_info6 = itd->csplit;
+ iso_dbg(ISO_DBG_DATA, "[phcd_iso_itd_to_ptd]: DWORD5 = 0x%08x\n",
+ iso_ptd->td_info6);
+
+ iso_dbg(ISO_DBG_EXIT, "phcd_iso_itd_to_ptd exit\n");
+ return iso_ptd;
+} /* phcd_iso_itd_to_ptd */
+
+/*
+ * phcd_iso_scheduling_info - Initializing the start split and complete split.
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct ehci_qh *qhead
+ * - Contains information about the endpoint.
+ * unsigned long max_pkt
+ * - Maximum packet size that the endpoint in capable of handling
+ * unsigned long high_speed
+ * - Indicates if the bus is a high speed bus
+ * unsigned long ep_in
+ * - Inidcates if the endpoint is an IN endpoint
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Determining the number of start split needed during an OUT transaction or
+ * the number of complete splits needed during an IN transaction.
+ */
+unsigned long
+phcd_iso_scheduling_info(phci_hcd * hcd,
+ struct ehci_qh *qhead,
+ unsigned long max_pkt,
+ unsigned long high_speed, unsigned long ep_in)
+{
+ unsigned long count, usof, temp;
+
+ /* Local variable initialization */
+ usof = 0x1;
+
+ if (high_speed) {
+ qhead->csplit = 0;
+
+ /* Always send high speed transfers in first uframes */
+ qhead->ssplit = 0x1;
+ return 0;
+ }
+
+ /* Determine how many 188 byte-transfers are needed to send all data */
+ count = max_pkt / 188;
+
+ /*
+ * Check is the data is not a factor of 188, if it is not then we need
+ * one more 188 transfer to move the last set of data less than 188.
+ */
+ if (max_pkt % 188){
+ count += 1;
+ }
+
+ /*
+ * Remember that usof was initialized to 0x1 so that means
+ * that usof is always guranteed a value of 0x1 and then
+ * depending on the maxp, other bits of usof will also be set.
+ */
+ for (temp = 0; temp < count; temp++){
+ usof |= (0x1 << temp);
+ }
+
+ if (ep_in) {
+ /*
+ * Send start split into first frame.
+ */
+ qhead->ssplit = 0x1;
+
+ /*
+ * Inidicate that we can send a complete split starting from
+ * the third uFrame to how much complete split is needed to
+ * retrieve all data.
+ *
+ * Of course, the first uFrame is reserved for the start split, the
+ * second is reserved for the TT to send the request and get some
+ * data.
+ */
+ qhead->csplit = (usof << 2);
+ } else {
+ /*
+ * For ISO OUT we don't need to send out a complete split
+ * since we do not require and data coming in to us (since ISO
+ * do not have integrity checking/handshake).
+ *
+ * For start split we indicate that we send a start split from the
+ * first uFrame up to the the last uFrame needed to retrieve all
+ * data
+ */
+ qhead->ssplit = usof;
+ qhead->csplit = 0;
+ } /* else for if(ep_in) */
+ return 0;
+} /* phcd_iso_scheduling_info */
+
+/*
+ * phcd_iso_sitd_fill - Allocate memory from the PAYLOAD memory region
+ *
+ * phci_hcd *pHcd_st
+ * - Main host controller driver structure
+ * struct ehci_sitd *sitd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more specific elements.
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long packets
+ * - Total number of packets to completely transfer this ISO transfer request.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Initialize the following elements of the ITS structure
+ * > sitd->length = length; -- the size of the request
+ * > sitd->multi = multi; -- the number of transactions for
+ * this EP per micro frame
+ * > sitd->hw_bufp[0] = buf_dma; -- The base address of the buffer where
+ * to put the data (this base address was
+ * the buffer provided plus the offset)
+ * - Allocating memory from the PAYLOAD memory area, where the data coming from
+ * the requesting party will be placed or data requested by the requesting party will
+ * be retrieved when it is available.
+ */
+unsigned long
+phcd_iso_sitd_fill(phci_hcd * hcd,
+ struct ehci_sitd *sitd,
+ struct urb *urb, unsigned long packets)
+{
+ unsigned long length, offset, pipe;
+ unsigned long max_pkt;
+ dma_addr_t buff_dma;
+ struct isp1763_mem_addr *mem_addr;
+
+#ifdef COMMON_MEMORY
+ struct ehci_qh *qhead = NULL;
+#endif
+
+ iso_dbg(ISO_DBG_ENTRY, "phcd_iso_itd_fill entry\n");
+ /*
+ * The value for both these variables are supplied by the one
+ * who submitted the URB.
+ */
+ length = urb->iso_frame_desc[packets].length;
+ offset = urb->iso_frame_desc[packets].offset;
+
+ /* Initialize the status and actual length of this packet */
+ urb->iso_frame_desc[packets].actual_length = 0;
+ urb->iso_frame_desc[packets].status = -EXDEV;
+
+ /* Buffer for this packet */
+ buff_dma = (u32) ((unsigned char *) urb->transfer_buffer + offset);
+
+ /* Memory for this packet */
+ mem_addr = &sitd->mem_addr;
+
+ pipe = urb->pipe;
+ max_pkt = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
+
+ max_pkt = max_pkt & 0x7FF;
+
+ if ((length < 0) || (max_pkt < length)) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No available memory.\n");
+ return -ENOSPC;
+ }
+ sitd->buf_dma = buff_dma;
+
+
+#ifndef COMMON_MEMORY
+ /*
+ * Allocate memory in the PAYLOAD memory region for the
+ * data buffer for this SITD
+ */
+ phci_hcd_mem_alloc(length, mem_addr, 0);
+ if (length && ((mem_addr->phy_addr == 0) || (mem_addr->virt_addr == 0))) {
+ mem_addr = 0;
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No payload memory available\n");
+ return -ENOMEM;
+ }
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+#else
+ qhead = urb->ep->hcpriv;
+#endif
+ if (qhead) {
+
+ mem_addr->phy_addr = qhead->memory_addr.phy_addr + offset;
+
+ mem_addr->virt_addr = qhead->memory_addr.phy_addr + offset;
+ } else {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No payload memory available\n");
+ return -ENOMEM;
+ }
+
+
+#endif
+ /* Length of this packet */
+ sitd->length = length;
+
+ /* Buffer address, one ptd per packet */
+ sitd->hw_bufp[0] = buff_dma;
+
+ iso_dbg(ISO_DBG_EXIT, "phcd_iso_sitd_fill exit\n");
+ return 0;
+}
+
+/*
+ * phcd_iso_itd_fill - Allocate memory from the PAYLOAD memory region
+ *
+ * phci_hcd *pHcd_st
+ * - Main host controller driver structure
+ * struct ehci_itd *itd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more IC specific elements.
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long packets
+ * - Total number of packets to completely transfer this ISO transfer request.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Initialize the following elements of the ITS structure
+ * > itd->length = length; -- the size of the request
+ * > itd->multi = multi; -- the number of transactions for
+ * this EP per micro frame
+ * > itd->hw_bufp[0] = buf_dma; -- The base address of the buffer where
+ * to put the data (this base address was
+ * the buffer provided plus the offset)
+ * - Allocating memory from the PAYLOAD memory area, where the data coming from
+ * the requesting party will be placed or data requested by the requesting party will
+ * be retrieved when it is available.
+ */
+unsigned long
+phcd_iso_itd_fill(phci_hcd * hcd,
+ struct ehci_itd *itd,
+ struct urb *urb,
+ unsigned long packets, unsigned char numofPkts)
+{
+ unsigned long length, offset, pipe;
+ unsigned long max_pkt, mult;
+ dma_addr_t buff_dma;
+ struct isp1763_mem_addr *mem_addr;
+#ifdef COMMON_MEMORY
+ struct ehci_qh *qhead = NULL;
+#endif
+ int i = 0;
+
+ iso_dbg(ISO_DBG_ENTRY, "phcd_iso_itd_fill entry\n");
+ for (i = 0; i < 8; i++){
+ itd->hw_transaction[i] = 0;
+ }
+ /*
+ * The value for both these variables are supplied by the one
+ * who submitted the URB.
+ */
+ length = urb->iso_frame_desc[packets].length;
+ offset = urb->iso_frame_desc[packets].offset;
+
+ /* Initialize the status and actual length of this packet */
+ urb->iso_frame_desc[packets].actual_length = 0;
+ urb->iso_frame_desc[packets].status = -EXDEV;
+
+ /* Buffer for this packet */
+ buff_dma = cpu_to_le32((unsigned char *) urb->transfer_buffer + offset);
+
+ /* Memory for this packet */
+ mem_addr = &itd->mem_addr;
+
+ pipe = urb->pipe;
+ max_pkt = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
+
+ mult = 1 + ((max_pkt >> 11) & 0x3);
+ max_pkt = max_pkt & 0x7FF;
+ max_pkt *= mult;
+
+ if ((length < 0) || (max_pkt < length)) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No available memory.\n");
+ return -ENOSPC;
+ }
+ itd->buf_dma = buff_dma;
+ for (i = packets + 1; i < numofPkts + packets; i++)
+ length += urb->iso_frame_desc[i].length;
+
+ /*
+ * Allocate memory in the PAYLOAD memory region for the
+ * data buffer for this ITD
+ */
+#ifndef COMMON_MEMORY
+
+ phci_hcd_mem_alloc(length, mem_addr, 0);
+ if (length && ((mem_addr->phy_addr == 0) || (mem_addr->virt_addr == 0))) {
+ mem_addr = 0;
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No payload memory available\n");
+ return -ENOMEM;
+ }
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ qhead = urb->ep->hcpriv;
+#else
+ qhead=urb->hcpriv;
+#endif
+ if (qhead) {
+
+ mem_addr->phy_addr = qhead->memory_addr.phy_addr + offset;
+
+ mem_addr->virt_addr = qhead->memory_addr.phy_addr + offset;
+ } else {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_fill Error]: No payload memory available\n");
+ return -ENOMEM;
+ }
+
+
+#endif
+ /* Length of this packet */
+ itd->length = length;
+
+ /* Number of transaction per uframe */
+ itd->multi = mult;
+
+ /* Buffer address, one ptd per packet */
+ itd->hw_bufp[0] = buff_dma;
+
+ iso_dbg(ISO_DBG_EXIT, "phcd_iso_itd_fill exit\n");
+ return 0;
+} /* phcd_iso_itd_fill */
+
+/*
+ * phcd_iso_get_sitd_ptd_index - Allocate an ISO PTD from the ISO PTD map list
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct ehci_sitd *sitd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more specific elements.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Allocating an ISO PTD from the ISO PTD map list
+ * - Set the equivalent bit of the allocated PTD to active
+ * in the bitmap so that this PTD will be included into
+ * the periodic schedule
+ */
+void
+phcd_iso_get_sitd_ptd_index(phci_hcd * hcd, struct ehci_sitd *sitd)
+{
+ td_ptd_map_buff_t *ptd_map_buff;
+ unsigned long buff_type, max_ptds;
+ unsigned char sitd_index, bitmap;
+
+ /* Local variable initialization */
+ bitmap = 0x1;
+ buff_type = td_ptd_pipe_x_buff_type[TD_PTD_BUFF_TYPE_ISTL];
+ ptd_map_buff = (td_ptd_map_buff_t *) & (td_ptd_map_buff[buff_type]);
+ max_ptds = ptd_map_buff->max_ptds;
+ sitd->sitd_index = TD_PTD_INV_PTD_INDEX;
+
+ for (sitd_index = 0; sitd_index < max_ptds; sitd_index++) {
+ /*
+ * ISO have 32 PTDs, the first thing to do is look for a free PTD.
+ */
+ if (ptd_map_buff->map_list[sitd_index].state == TD_PTD_NEW) {
+ iso_dbg(ISO_DBG_INFO,
+ "[phcd_iso_get_itd_ptd_index] There's a free PTD No. %d\n",
+ sitd_index);
+ /*
+ * Determine if this is a newly allocated SITD by checking the
+ * itd_index, since it was set to TD_PTD_INV_PTD_INDEX during
+ * initialization
+ */
+ if (sitd->sitd_index == TD_PTD_INV_PTD_INDEX) {
+ sitd->sitd_index = sitd_index;
+ }
+
+ /* Once there is a free slot, indicate that it is already taken */
+ ptd_map_buff->map_list[sitd_index].datatoggle = 0;
+ ptd_map_buff->map_list[sitd_index].state =
+ TD_PTD_ACTIVE;
+ ptd_map_buff->map_list[sitd_index].qtd = NULL;
+
+ /* Put a connection to the SITD with the PTD maplist */
+ ptd_map_buff->map_list[sitd_index].sitd = sitd;
+ ptd_map_buff->map_list[sitd_index].itd = NULL;
+ ptd_map_buff->map_list[sitd_index].qh = NULL;
+
+ /* ptd_bitmap just holds the bit assigned to this PTD. */
+ ptd_map_buff->map_list[sitd_index].ptd_bitmap =
+ bitmap << sitd_index;
+
+ phci_hcd_fill_ptd_addresses(&ptd_map_buff->
+ map_list[sitd_index], sitd->sitd_index,
+ buff_type);
+
+ /*
+ * Indicate that this SITD is the last in the list and update
+ * the number of active PTDs
+ */
+ ptd_map_buff->map_list[sitd_index].lasttd = 0;
+ ptd_map_buff->total_ptds++;
+
+
+ ptd_map_buff->active_ptd_bitmap |=
+ (bitmap << sitd_index);
+ ptd_map_buff->pending_ptd_bitmap |= (bitmap << sitd_index);
+ break;
+ } /* if(ptd_map_buff->map_list[sitd_index].state == TD_PTD_NEW) */
+ } /* for(itd_index = 0; itd_index < max_ptds; itd_index++) */
+ return;
+}
+
+/*
+ * phcd_iso_get_itd_ptd_index - Allocate an ISO PTD from the ISO PTD map list
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct ehci_itd *itd
+ * - Isochronous Transfer Descriptor, contains elements as defined by the
+ * EHCI standard plus a few more IC specific elements.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Allocating an ISO PTD from the ISO PTD map list
+ * - Set the equivalent bit of the allocated PTD to active
+ * in the bitmap so that this PTD will be included into
+ * the periodic schedule
+ */
+void
+phcd_iso_get_itd_ptd_index(phci_hcd * hcd, struct ehci_itd *itd)
+{
+ td_ptd_map_buff_t *ptd_map_buff;
+ unsigned long buff_type, max_ptds;
+ unsigned char itd_index, bitmap;
+
+ /* Local variable initialization */
+ bitmap = 0x1;
+ buff_type = td_ptd_pipe_x_buff_type[TD_PTD_BUFF_TYPE_ISTL];
+ ptd_map_buff = (td_ptd_map_buff_t *) & (td_ptd_map_buff[buff_type]);
+ max_ptds = ptd_map_buff->max_ptds;
+
+ itd->itd_index = TD_PTD_INV_PTD_INDEX;
+
+ for (itd_index = 0; itd_index < max_ptds; itd_index++) {
+ /*
+ * ISO have 32 PTDs, the first thing to do is look for a free PTD.
+ */
+ if (ptd_map_buff->map_list[itd_index].state == TD_PTD_NEW) {
+ /*
+ * Determine if this is a newly allocated ITD by checking the
+ * itd_index, since it was set to TD_PTD_INV_PTD_INDEX during
+ * initialization
+ */
+ if (itd->itd_index == TD_PTD_INV_PTD_INDEX) {
+ itd->itd_index = itd_index;
+ }
+
+ /* Once there is a free slot, indicate that it is already taken */
+ ptd_map_buff->map_list[itd_index].datatoggle = 0;
+ ptd_map_buff->map_list[itd_index].state = TD_PTD_ACTIVE;
+ ptd_map_buff->map_list[itd_index].qtd = NULL;
+
+ /* Put a connection to the ITD with the PTD maplist */
+ ptd_map_buff->map_list[itd_index].itd = itd;
+ ptd_map_buff->map_list[itd_index].qh = NULL;
+
+ /* ptd_bitmap just holds the bit assigned to this PTD. */
+ ptd_map_buff->map_list[itd_index].ptd_bitmap =
+ bitmap << itd_index;
+
+ phci_hcd_fill_ptd_addresses(&ptd_map_buff->
+ map_list[itd_index],
+ itd->itd_index, buff_type);
+
+ /*
+ * Indicate that this ITD is the last in the list and update
+ * the number of active PTDs
+ */
+ ptd_map_buff->map_list[itd_index].lasttd = 0;
+ ptd_map_buff->total_ptds++;
+
+ ptd_map_buff->active_ptd_bitmap |=
+ (bitmap << itd_index);
+ ptd_map_buff->pending_ptd_bitmap |= (bitmap << itd_index);
+ break;
+ } /* if(ptd_map_buff->map_list[itd_index].state == TD_PTD_NEW) */
+ } /* for(itd_index = 0; itd_index < max_ptds; itd_index++) */
+ return;
+} /* phcd_iso_get_itd_ptd_index */
+
+/*
+ * phcd_iso_sitd_free_list - Free memory used by SITDs in SITD list
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long status
+ * - Variable provided by the calling routine that contain the status of the
+ * SITD list.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Cleaning up memory used by each SITD in the SITD list
+ */
+void
+phcd_iso_sitd_free_list(phci_hcd * hcd, struct urb *urb, unsigned long status)
+{
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct ehci_sitd *first_sitd, *next_sitd, *sitd;
+ td_ptd_map_t *td_ptd_map;
+
+ /* Local variable initialization */
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
+ first_sitd = (struct ehci_sitd *) urb->hcpriv;
+ sitd = first_sitd;
+
+ /*
+ * Check if there is only one SITD, if so immediately
+ * go and clean it up.
+ */
+ if (sitd->hw_next == EHCI_LIST_END) {
+ if (sitd->sitd_index != TD_PTD_INV_PTD_INDEX) {
+ td_ptd_map = &ptd_map_buff->map_list[sitd->sitd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ if (status != -ENOMEM) {
+ phci_hcd_mem_free(&sitd->mem_addr);
+ }
+
+ list_del(&sitd->sitd_list);
+ qha_free(qha_cache, sitd);
+
+ urb->hcpriv = 0;
+ return;
+ }
+ /* if(sitd->hw_next == EHCI_LIST_END) */
+ while (1) {
+ /* Get the SITD following the head SITD */
+ next_sitd = (struct ehci_sitd *) (sitd->hw_next);
+ if (next_sitd->hw_next == EHCI_LIST_END) {
+ /*
+ * If the next SITD is the end of the list, check if space have
+ * already been allocated in the PTD array.
+ */
+ if (next_sitd->sitd_index != TD_PTD_INV_PTD_INDEX) {
+ /* Free up its allocation */
+ td_ptd_map =
+ &ptd_map_buff->map_list[next_sitd->
+ sitd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ /*
+ * If the error is not about memory allocation problems, then
+ * free up the memory used.
+ */
+ if (status != -ENOMEM) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_free_list Error]: Memory not available\n");
+ phci_hcd_mem_free(&next_sitd->mem_addr);
+ }
+
+ /* Remove from the SITD list and free up space allocated for SITD structure */
+ list_del(&next_sitd->sitd_list);
+ qha_free(qha_cache, next_sitd);
+ break;
+ }
+
+ /* if(next_itd->hw_next == EHCI_LIST_END) */
+ /*
+ * If SITD is not the end of the list, it only means that it already have everything allocated
+ * and there is no need to check which procedure failed. So just free all resourcs immediately
+ */
+ sitd->hw_next = next_sitd->hw_next;
+
+ td_ptd_map = &ptd_map_buff->map_list[next_sitd->sitd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ phci_hcd_mem_free(&next_sitd->mem_addr);
+ list_del(&next_sitd->sitd_list);
+ qha_free(qha_cache, next_sitd);
+ } /* while(1) */
+
+ /* Now work on the head SITD, it is the last one processed. */
+ if (first_sitd->sitd_index != TD_PTD_INV_PTD_INDEX) {
+ td_ptd_map = &ptd_map_buff->map_list[first_sitd->sitd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ if (status != -ENOMEM) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_free_list Error]: No memory\n");
+ phci_hcd_mem_free(&first_sitd->mem_addr);
+ }
+
+ list_del(&first_sitd->sitd_list);
+ qha_free(qha_cache, first_sitd);
+ urb->hcpriv = 0;
+ return;
+}
+
+/*
+ * phcd_iso_itd_free_list - Free memory used by ITDs in ITD list
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long status
+ * - Variable provided by the calling routine that contain the status of the
+ * ITD list.
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Cleaning up memory used by each ITD in the ITD list
+ */
+void
+phcd_iso_itd_free_list(phci_hcd * hcd, struct urb *urb, unsigned long status)
+{
+ td_ptd_map_buff_t *ptd_map_buff;
+ struct ehci_itd *first_itd, *next_itd, *itd;
+ td_ptd_map_t *td_ptd_map;
+
+ /* Local variable initialization */
+ ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL]);
+ first_itd = (struct ehci_itd *) urb->hcpriv;
+ itd = first_itd;
+
+ /*
+ * Check if there is only one ITD, if so immediately
+ * go and clean it up.
+ */
+ if (itd->hw_next == EHCI_LIST_END) {
+ if (itd->itd_index != TD_PTD_INV_PTD_INDEX) {
+ td_ptd_map = &ptd_map_buff->map_list[itd->itd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ if (status != -ENOMEM) {
+ phci_hcd_mem_free(&itd->mem_addr);
+ }
+
+ list_del(&itd->itd_list);
+ qha_free(qha_cache, itd);
+
+ urb->hcpriv = 0;
+ return;
+ }
+ /* if(itd->hw_next == EHCI_LIST_END) */
+ while (1) {
+ /* Get the ITD following the head ITD */
+ next_itd = (struct ehci_itd *) le32_to_cpu(itd->hw_next);
+ if (next_itd->hw_next == EHCI_LIST_END) {
+ /*
+ * If the next ITD is the end of the list, check if space have
+ * already been allocated in the PTD array.
+ */
+ if (next_itd->itd_index != TD_PTD_INV_PTD_INDEX) {
+ /* Free up its allocation */
+ td_ptd_map =
+ &ptd_map_buff->map_list[next_itd->
+ itd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ /*
+ * If the error is not about memory allocation problems, then
+ * free up the memory used.
+ */
+ if (status != -ENOMEM) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_free_list Error]: Memory not available\n");
+ phci_hcd_mem_free(&next_itd->mem_addr);
+ }
+
+ /* Remove from the ITD list and free up space allocated for ITD structure */
+ list_del(&next_itd->itd_list);
+ qha_free(qha_cache, next_itd);
+ break;
+ }
+
+ /* if(next_itd->hw_next == EHCI_LIST_END) */
+ /*
+ * If ITD is not the end of the list, it only means that it already have everything allocated
+ * and there is no need to check which procedure failed. So just free all resourcs immediately
+ */
+ itd->hw_next = next_itd->hw_next;
+
+ td_ptd_map = &ptd_map_buff->map_list[next_itd->itd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ phci_hcd_mem_free(&next_itd->mem_addr);
+ list_del(&next_itd->itd_list);
+ qha_free(qha_cache, next_itd);
+ } /* while(1) */
+
+ /* Now work on the head ITD, it is the last one processed. */
+ if (first_itd->itd_index != TD_PTD_INV_PTD_INDEX) {
+ td_ptd_map = &ptd_map_buff->map_list[first_itd->itd_index];
+ td_ptd_map->state = TD_PTD_NEW;
+ }
+
+ if (status != -ENOMEM) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_iso_itd_free_list Error]: No memory\n");
+ phci_hcd_mem_free(&first_itd->mem_addr);
+ }
+
+ list_del(&first_itd->itd_list);
+ qha_free(qha_cache, first_itd);
+ urb->hcpriv = 0;
+ return;
+} /* phcd_iso_itd_free_list */
+
+void
+phcd_clean_iso_qh(phci_hcd * hcd, struct ehci_qh *qh)
+{
+ unsigned int i = 0;
+ u16 skipmap=0;
+ struct ehci_sitd *sitd;
+ struct ehci_itd *itd;
+
+ iso_dbg(ISO_DBG_ERR, "phcd_clean_iso_qh \n");
+ if (!qh){
+ return;
+ }
+ skipmap = isp1763_reg_read16(hcd->dev, hcd->regs.isotdskipmap, skipmap);
+ skipmap |= qh->periodic_list.ptdlocation;
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap, skipmap);
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&qh->memory_addr);
+#endif
+ for (i = 0; i < 16 && qh->periodic_list.ptdlocation; i++) {
+ if (qh->periodic_list.ptdlocation & (0x1 << i)) {
+ printk("[phcd_clean_iso_qh] : %x \n",
+ qh->periodic_list.high_speed);
+
+ qh->periodic_list.ptdlocation &= ~(0x1 << i);
+
+ if (qh->periodic_list.high_speed == 0) {
+ if (td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd) {
+
+ printk("SITD found \n");
+ sitd = td_ptd_map_buff
+ [TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd;
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free(&sitd->mem_addr);
+#endif
+ /*
+ if(sitd->urb)
+ urb=sitd->urb;
+ */
+ sitd->urb = NULL;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].state = TD_PTD_NEW;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd = NULL;
+ qha_free(qha_cache, sitd);
+ }
+ } else {
+ if (td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd) {
+
+ printk("ITD found \n");
+ itd = td_ptd_map_buff
+ [TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd;
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&itd->mem_addr);
+#endif
+
+ /*
+ if(itd->urb)
+ urb=itd->urb;
+ */
+ itd->urb = NULL;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].state = TD_PTD_NEW;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd = NULL;
+ qha_free(qha_cache, itd);
+ }
+ }
+
+ }
+ }
+
+
+}
+
+
+/*
+ * phcd_store_urb_pending - store requested URB into a queue
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long *status
+ * - Variable provided by the calling routine that will contain the status of the
+ * phcd_submit_iso actions
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Store URB into a queue
+ * - If ther's enough free PTD slots , repairing the PTDs
+ */
+void phcd_clean_periodic_ep(void){
+ periodic_ep[0] = NULL;
+ periodic_ep[1] = NULL;
+}
+
+int
+phcd_clean_urb_pending(phci_hcd * hcd, struct urb *urb)
+{
+ unsigned int i = 0;
+ struct ehci_qh *qhead;
+ struct ehci_sitd *sitd;
+ struct ehci_itd *itd;
+ u16 skipmap=0;;
+
+ iso_dbg(ISO_DBG_ENTRY, "[phcd_clean_urb_pending] : Enter\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead=urb->hcpriv;
+ if (periodic_ep[0] == qhead->ep) {
+ periodic_ep[0] = NULL;
+
+ }
+
+ if (periodic_ep[1] == qhead->ep) {
+ periodic_ep[1] = NULL;
+ }
+#else
+ qhead = urb->ep->hcpriv;
+ if (periodic_ep[0] == urb->ep) {
+ periodic_ep[0] = NULL;
+
+ }
+
+ if (periodic_ep[1] == urb->ep) {
+ periodic_ep[1] = NULL;
+ }
+#endif
+ if (!qhead) {
+ return 0;
+ }
+ skipmap = isp1763_reg_read16(hcd->dev, hcd->regs.isotdskipmap, skipmap);
+ skipmap |= qhead->periodic_list.ptdlocation;
+ isp1763_reg_write16(hcd->dev, hcd->regs.isotdskipmap, skipmap);
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&qhead->memory_addr);
+#endif
+
+ for (i = 0; i < 16 && qhead->periodic_list.ptdlocation; i++) {
+
+ qhead->periodic_list.ptdlocation &= ~(0x1 << i);
+
+ if (qhead->periodic_list.ptdlocation & (0x1 << i)) {
+
+ printk("[phcd_clean_urb_pending] : %x \n",
+ qhead->periodic_list.high_speed);
+
+ if (qhead->periodic_list.high_speed == 0) {
+
+ if (td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd) {
+
+ sitd = td_ptd_map_buff
+ [TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd;
+#ifndef COMMON_MEMORY
+ phci_hcd_mem_free(&sitd->mem_addr);
+#endif
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].state = TD_PTD_NEW;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].sitd = NULL;
+ qha_free(qha_cache, sitd);
+ }
+ } else {
+
+ if (td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd) {
+
+ itd = td_ptd_map_buff
+ [TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd;
+#ifdef COMMON_MEMORY
+ phci_hcd_mem_free(&itd->mem_addr);
+#endif
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].state = TD_PTD_NEW;
+ td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL].
+ map_list[i].itd = NULL;
+ qha_free(qha_cache, itd);
+ }
+ }
+
+ }
+
+ }
+ INIT_LIST_HEAD(&qhead->periodic_list.sitd_itd_head);
+ iso_dbg(ISO_DBG_ENTRY, "[phcd_clean_urb_pending] : Exit\n");
+ return 0;
+}
+
+
+
+int
+phcd_store_urb_pending(phci_hcd * hcd, int index, struct urb *urb, int *status)
+{
+ unsigned int uiNumofPTDs = 0;
+ unsigned int uiNumofSlots = 0;
+ unsigned int uiMult = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ iso_dbg(ISO_DBG_ENTRY, "[phcd_store_urb_pending] : Enter\n");
+ if (urb != NULL) {
+ if (periodic_ep[0] != urb->ep && periodic_ep[1] != urb->ep) {
+ if (periodic_ep[0] == NULL) {
+ // printk("storing in 0 %x %x\n",urb,urb->pipe);
+ periodic_ep[0] = urb->ep;
+ } else if (periodic_ep[1] == NULL) {
+ printk("storing in 1\n");
+ periodic_ep[1] = urb->ep;
+ usb_hcd_link_urb_to_ep(&(hcd->usb_hcd), urb);
+ return -1;
+ } else {
+ iso_dbg(ISO_DBG_ERR,
+ "Support only 2 ISO endpoints simultaneously \n");
+ *status = -1;
+ return -1;
+ }
+ }
+ usb_hcd_link_urb_to_ep(&(hcd->usb_hcd), urb);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : Add an urb into gstUrb_pending array at index : %d\n",
+ giUrbCount);
+ giUrbCount++;
+ } else {
+
+ iso_dbg(ISO_DBG_ENTRY,
+ "[phcd_store_urb_pending] : getting urb from list \n");
+ if (index > 0 && index < 2) {
+ if (periodic_ep[index - 1]){
+ urb = container_of(periodic_ep[index - 1]->
+ urb_list.next, struct urb,
+ urb_list);
+ }
+ } else {
+ iso_dbg(ISO_DBG_ERR, " Unknown enpoints Error \n");
+ *status = -1;
+ return -1;
+ }
+
+ }
+
+
+ if ((urb != NULL && (urb->ep->urb_list.next == &urb->urb_list))){
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : periodic_sched : %d\n",
+ hcd->periodic_sched);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : number_of_packets : %d\n",
+ urb->number_of_packets);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : Maximum PacketSize : %d\n",
+ usb_maxpacket(urb->dev,urb->pipe, usb_pipeout(urb->pipe)));
+ /*if enough free slots */
+ if (urb->dev->speed == USB_SPEED_FULL) { /*for FULL SPEED */
+ // if (hcd->periodic_sched <
+ // MAX_PERIODIC_SIZE - urb->number_of_packets) {
+ if(1){
+ if (phcd_submit_iso(hcd,
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+ #endif
+ urb,
+ ( unsigned long *) &status) == 0) {
+ pehci_hcd_iso_schedule(hcd, urb);
+ } else{
+ //*status = 0;
+ }
+ }
+ } else if (urb->dev->speed == USB_SPEED_HIGH) { /*for HIGH SPEED */
+ /*number of slots for 1 PTD */
+ uiNumofSlots = NUMMICROFRAME / urb->interval;
+ /*max packets size */
+ uiMult = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ /*mult */
+ uiMult = 1 + ((uiMult >> 11) & 0x3);
+ /*number of PTDs need to schedule for this PTD */
+ uiNumofPTDs =
+ (urb->number_of_packets / uiMult) /
+ uiNumofSlots;
+ if ((urb->number_of_packets / uiMult) % uiNumofSlots != 0){
+ uiNumofPTDs += 1;
+ }
+
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : interval : %d\n",
+ urb->interval);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : uiMult : %d\n",
+ uiMult);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : uiNumofPTDs : %d\n",
+ uiNumofPTDs);
+
+ if (hcd->periodic_sched <=
+ MAX_PERIODIC_SIZE - uiNumofPTDs) {
+
+ if (phcd_submit_iso(hcd,
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+ #endif
+ urb, (unsigned long *) &status)== 0) {
+
+ pehci_hcd_iso_schedule(hcd, urb);
+ }
+ } else{
+ *status = 0;
+ }
+ }
+ } else{
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_store_urb_pending] : nextUrb is NULL\n");
+ }
+#endif
+ iso_dbg(ISO_DBG_ENTRY, "[phcd_store_urb_pending] : Exit\n");
+ return 0;
+}
+
+/*
+ * phcd_submit_iso - ISO transfer URB submit routine
+ *
+ * phci_hcd *hcd
+ * - Main host controller driver structure
+ * struct urb *urb
+ * - USB Request Block, contains information regarding the type and how much data
+ * is requested to be transferred.
+ * unsigned long *status
+ * - Variable provided by the calling routine that will contain the status of the
+ * phcd_submit_iso actions
+ *
+ * API Description
+ * This is mainly responsible for:
+ * - Allocating memory for the endpoint information structure (pQHead_st)
+ * - Requesting for bus bandwidth from the USB core
+ * - Allocating and initializing Payload and PTD memory
+ */
+unsigned long
+phcd_submit_iso(phci_hcd * hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+#else
+#endif
+ struct urb *urb, unsigned long *status)
+{
+ struct _periodic_list *periodic_list;
+ struct hcd_dev *dev;
+ struct ehci_qh *qhead;
+ struct ehci_itd *itd, *prev_itd;
+ struct ehci_sitd *sitd, *prev_sitd;
+ struct list_head *sitd_itd_list;
+ unsigned long ep_in, max_pkt, mult;
+ unsigned long bus_time, high_speed, start_frame;
+ unsigned long temp;
+ unsigned long packets;
+ /*for high speed device */
+ unsigned int iMicroIndex = 0;
+ unsigned int iNumofSlots = 0;
+ unsigned int iNumofPTDs = 0;
+ unsigned int iPTDIndex = 0;
+ unsigned int iNumofPks = 0;
+ int iPG = 0;
+ dma_addr_t buff_dma;
+ unsigned long length, offset;
+ int i = 0;
+
+ iso_dbg(ISO_DBG_ENTRY, "phcd_submit_iso Entry\n");
+
+ *status = 0;
+ /* Local variable initialization */
+ high_speed = 0;
+ periodic_list = &hcd->periodic_list[0];
+ dev = (struct hcd_dev *) urb->hcpriv;
+ urb->hcpriv = (void *) 0;
+ prev_itd = (struct ehci_itd *) 0;
+ itd = (struct ehci_itd *) 0;
+ prev_sitd = (struct ehci_sitd *) 0;
+ sitd = (struct ehci_sitd *) 0;
+ start_frame = 0;
+
+ ep_in = usb_pipein(urb->pipe);
+
+ /*
+ * Take the endpoint, if there is still no memory allocated
+ * for it allocate some and indicate this is for ISO.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead = ep->hcpriv;
+#else
+ qhead = urb->ep->hcpriv;
+#endif
+ if (!qhead) {
+
+ qhead = phci_hcd_qh_alloc(hcd);
+ if (qhead == 0) {
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: Not enough memory\n");
+ return -ENOMEM;
+ }
+
+ qhead->type = TD_PTD_BUFF_TYPE_ISTL;
+ INIT_LIST_HEAD(&qhead->periodic_list.sitd_itd_head);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qhead->ep=ep;
+ ep->hcpriv = qhead;
+ urb->hcpriv=qhead;
+#else
+ urb->ep->hcpriv = qhead;
+#endif
+ }
+
+ urb->hcpriv=qhead;
+
+ /* if(!qhead) */
+ /*
+ * Get the number of additional packets that the endpoint can support during a
+ * single microframe.
+ */
+ max_pkt = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ /*
+ * We need to add 1 since our Multi starts with 1 instead of the USB specs defined
+ * zero (0).
+ */
+ mult = 1 + ((max_pkt >> 11) & 0x3);
+
+ /* This is the actual length per for the whole transaction */
+ max_pkt *= mult;
+
+ /* Check bandwidth */
+ bus_time = 0;
+
+ if (urb->dev->speed == USB_SPEED_FULL) {
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ if (urb->bandwidth == 0) {
+ bus_time = usb_check_bandwidth(urb->dev, urb);
+ if (bus_time < 0) {
+ usb_dec_dev_use(urb->dev);
+ *status = bus_time;
+ return *status;
+ }
+ }
+#else
+#endif
+ } else { /*HIGH SPEED */
+
+ high_speed = 1;
+
+ /*
+ * Calculate bustime as dictated by the USB Specs Section 5.11.3
+ * for high speed ISO
+ */
+ bus_time = 633232L;
+ bus_time +=
+ (2083L * ((3167L + BitTime(max_pkt) * 1000L) / 1000L));
+ bus_time = bus_time / 1000L;
+ bus_time += BW_HOST_DELAY;
+ bus_time = NS_TO_US(bus_time);
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ usb_claim_bandwidth(urb->dev, urb, bus_time, 1);
+#else
+#endif
+
+ qhead->periodic_list.ptdlocation = 0;
+ /* Initialize the start split (ssplit) and complete split (csplit) variables of qhead */
+ if (phcd_iso_scheduling_info(hcd, qhead, max_pkt, high_speed, ep_in) <
+ 0) {
+
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: No space available\n");
+ return -ENOSPC;
+ }
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ iNumofSlots = NUMMICROFRAME / urb->interval;
+ /*number of PTDs need to schedule for this PTD */
+ iNumofPTDs = (urb->number_of_packets / mult) / iNumofSlots;
+ if ((urb->number_of_packets / mult) % iNumofSlots != 0){
+ /*get remainder */
+ iNumofPTDs += 1;
+ }
+ }
+ if (urb->iso_frame_desc[0].offset != 0) {
+ *status = -EINVAL;
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: Invalid value\n");
+ return *status;
+ }
+ if (1) {
+ /* Calculate the current frame number */
+ if (0){
+ if (urb->transfer_flags & URB_ISO_ASAP){
+ start_frame =
+ isp1763_reg_read16(hcd->dev,
+ hcd->regs.frameindex,
+ start_frame);
+ } else {
+ start_frame = urb->start_frame;
+ }
+ }
+
+ start_frame =
+ isp1763_reg_read16(hcd->dev, hcd->regs.frameindex,
+ start_frame);
+
+ /* The only valid bits of the frame index is the lower 14 bits. */
+
+ /*
+ * Remove the count for the micro frame (uSOF) and just leave the
+ * count for the frame (SOF). Since 1 SOF is equal to 8 uSOF then
+ * shift right by three is like dividing it by 8 (each shift is divide by two)
+ */
+ start_frame >>= 3;
+ if (urb->dev->speed != USB_SPEED_HIGH){
+ start_frame += 1;
+ }else{
+ start_frame += 2;
+ }
+ start_frame = start_frame & PTD_FRAME_MASK;
+ temp = start_frame;
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ qhead->next_uframe =
+ start_frame + urb->number_of_packets;
+ } else {
+ qhead->next_uframe = start_frame + iNumofPTDs;
+ }
+ qhead->next_uframe %= PTD_FRAME_MASK;
+ iso_dbg(ISO_DBG_DATA, "[phcd_submit_iso]: startframe = %ld\n",
+ start_frame);
+ } else {
+ /*
+ * The periodic frame list size is only 32 elements deep, so we need
+ * the frame index to be less than or equal to 32 (actually 31 if we
+ * start from 0)
+ */
+ start_frame = (qhead->next_uframe) % PTD_FRAME_MASK;
+ if (urb->dev->speed != USB_SPEED_HIGH){
+ qhead->next_uframe =
+ start_frame + urb->number_of_packets;
+ iNumofPTDs=urb->number_of_packets;
+ } else {
+ qhead->next_uframe = start_frame + iNumofPTDs;
+ }
+
+ qhead->next_uframe %= PTD_FRAME_MASK;
+ }
+
+
+ iso_dbg(ISO_DBG_DATA, "[phcd_submit_iso]: Start frame index: %ld\n",
+ start_frame);
+ iso_dbg(ISO_DBG_DATA, "[phcd_submit_iso]: Max packet: %d\n",
+ (int) max_pkt);
+
+#ifdef COMMON_MEMORY
+ if(urb->number_of_packets>8 && urb->dev->speed!=USB_SPEED_HIGH)
+ phci_hcd_mem_alloc(8*max_pkt, &qhead->memory_addr, 0);
+ else
+ phci_hcd_mem_alloc(urb->transfer_buffer_length, &qhead->memory_addr, 0);
+ if (urb->transfer_buffer_length && ((qhead->memory_addr.phy_addr == 0)
+ || (qhead->memory_addr.virt_addr ==0))) {
+ iso_dbg(ISO_DBG_ERR,
+ "[URB FILL MEMORY Error]: No payload memory available\n");
+ return -ENOMEM;
+ }
+#endif
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ iNumofPks = urb->number_of_packets;
+ qhead->totalptds=urb->number_of_packets;
+ qhead->actualptds=0;
+
+ /* Make as many tds as number of packets */
+ for (packets = 0; packets < urb->number_of_packets; packets++) {
+ /*
+ * Allocate memory for the SITD data structure and initialize it.
+ *
+ * This data structure follows the format of the SITD
+ * structure defined by the EHCI standard on the top part
+ * but also contains specific elements in the bottom
+ * part
+ */
+ sitd = kmalloc(sizeof(*sitd), GFP_ATOMIC);
+ if (!sitd) {
+ *status = -ENOMEM;
+ if (((int)(qhead->next_uframe -
+ urb->number_of_packets)) < 0){
+ /*plus max PTDs*/
+ qhead->next_uframe = qhead->next_uframe + PTD_PERIODIC_SIZE;
+
+ }
+ qhead->next_uframe -= urb->number_of_packets;
+
+ /* Handle SITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_sitd_free_list(hcd, urb,
+ *status);
+ }
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: No memory available\n");
+ return *status;
+ }
+
+ memset(sitd, 0, sizeof(struct ehci_sitd));
+
+ INIT_LIST_HEAD(&sitd->sitd_list);
+
+ sitd->sitd_dma = (u32) (sitd);
+ sitd->urb = urb;
+
+ /*
+ * Indicate that this SITD is the last in the list.
+ *
+ * Also set the itd_index to TD_PTD_INV_PTD_INDEX
+ * (0xFFFFFFFF). This would indicate when we allocate
+ * a PTD that this SITD did not have a PTD allocated
+ * before.
+ */
+
+ sitd->hw_next = EHCI_LIST_END;
+ sitd->sitd_index = TD_PTD_INV_PTD_INDEX;
+
+ /* This SITD will go into this frame */
+ sitd->framenumber = start_frame + packets;
+ sitd->start_frame = temp + packets;
+
+ /* Number of the packet */
+ sitd->index = packets;
+
+ sitd->framenumber = sitd->framenumber & PTD_FRAME_MASK;
+ sitd->ssplit = qhead->ssplit;
+ sitd->csplit = qhead->csplit;
+
+ /* Initialize the following elements of the ITS structure
+ * > sitd->length = length; -- the size of the request
+ * > sitd->multi = multi; -- the number of transactions for
+ * this EP per micro frame
+ * > sitd->hw_bufp[0] = buf_dma; -- The base address of the buffer where
+ * to put the data (this base address was
+ * the buffer provided plus the offset)
+ * And then, allocating memory from the PAYLOAD memory area, where the data
+ * coming from the requesting party will be placed or data requested by the
+ * requesting party will be retrieved when it is available.
+ */
+ *status = phcd_iso_sitd_fill(hcd, sitd, urb, packets);
+
+ if (*status != 0) {
+ if (((int)(qhead->next_uframe -
+ urb->number_of_packets)) < 0){
+ /*plus max PTDs*/
+ qhead->next_uframe = qhead->next_uframe +
+ PTD_PERIODIC_SIZE;
+ }
+ qhead->next_uframe -= urb->number_of_packets;
+
+ /* Handle SITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_sitd_free_list(hcd, urb,
+ *status);
+ }
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: Error in filling up SITD\n");
+ return *status;
+ }
+
+ /*
+ * If this SITD is not the head/root SITD, link this SITD to the SITD
+ * that came before it.
+ */
+ if (prev_sitd) {
+ prev_sitd->hw_next = (u32) (sitd);
+ }
+
+ prev_sitd = sitd;
+
+ if(packets<8){ //bcs of memory constraint , we use only first 8 PTDs if number_of_packets is more than 8.
+ /*
+ * Allocate an ISO PTD from the ISO PTD map list and
+ * set the equivalent bit of the allocated PTD to active
+ * in the bitmap so that this PTD will be included into
+ * the periodic schedule
+ */
+ phcd_iso_get_sitd_ptd_index(hcd, sitd);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_submit_iso]: SITD index %d\n",
+ sitd->sitd_index);
+
+ /*if we dont have any space left */
+ if (sitd->sitd_index == TD_PTD_INV_PTD_INDEX) {
+ *status = -ENOSPC;
+ if (((int) (qhead->next_uframe -
+ urb->number_of_packets)) < 0){
+ /*plus max PTDs*/
+ qhead->next_uframe = qhead->next_uframe + PTD_PERIODIC_SIZE;
+ }
+ qhead->next_uframe -= urb->number_of_packets;
+
+ /* Handle SITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_sitd_free_list(hcd, urb,
+ *status);
+ }
+ return *status;
+ }
+ qhead->actualptds++;
+ }
+ /* Insert this td into the periodic list */
+
+ sitd_itd_list = &qhead->periodic_list.sitd_itd_head;
+ list_add_tail(&sitd->sitd_list, sitd_itd_list);
+ qhead->periodic_list.high_speed = 0;
+ if(sitd->sitd_index!=TD_PTD_INV_PTD_INDEX)
+ qhead->periodic_list.ptdlocation |=
+ 0x1 << sitd->sitd_index;
+ /* Inidcate that a new SITD have been scheduled */
+ hcd->periodic_sched++;
+
+ /* Determine if there are any SITD scheduled before this one. */
+ if (urb->hcpriv == 0){
+ urb->hcpriv = sitd;
+ }
+ } /* for(packets = 0; packets... */
+ } else if (urb->dev->speed == USB_SPEED_HIGH) {
+ iNumofPks = iNumofPTDs;
+
+ packets = 0;
+ iPTDIndex = 0;
+ while (packets < urb->number_of_packets) {
+ iNumofSlots = NUMMICROFRAME / urb->interval;
+ /*
+ * Allocate memory for the ITD data structure and initialize it.
+ *
+ * This data structure follows the format of the ITD
+ * structure defined by the EHCI standard on the top part
+ * but also contains specific elements in the bottom
+ * part
+ */
+ itd = kmalloc(sizeof(*itd), GFP_ATOMIC);
+ if (!itd) {
+ *status = -ENOMEM;
+ if(((int) (qhead->next_uframe - iNumofPTDs))<0){
+ /*plus max PTDs*/
+ qhead->next_uframe = qhead->next_uframe +
+ PTD_PERIODIC_SIZE;
+ }
+ qhead->next_uframe -= iNumofPTDs;
+
+ /* Handle ITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_itd_free_list(hcd, urb,
+ *status);
+ }
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: No memory available\n");
+ return *status;
+ }
+ memset(itd, 0, sizeof(struct ehci_itd));
+
+ INIT_LIST_HEAD(&itd->itd_list);
+
+ itd->itd_dma = (u32) (itd);
+ itd->urb = urb;
+ /*
+ * Indicate that this ITD is the last in the list.
+ *
+ * Also set the itd_index to TD_PTD_INV_PTD_INDEX
+ * (0xFFFFFFFF). This would indicate when we allocate
+ * a PTD that this SITD did not have a PTD allocated
+ * before.
+ */
+
+ itd->hw_next = EHCI_LIST_END;
+ itd->itd_index = TD_PTD_INV_PTD_INDEX;
+ /* This ITD will go into this frame */
+ itd->framenumber = start_frame + iPTDIndex;
+ /* Number of the packet */
+ itd->index = packets;
+
+ itd->framenumber = itd->framenumber & 0x1F;
+
+ itd->ssplit = qhead->ssplit;
+ itd->csplit = qhead->csplit;
+
+ /*caculate the number of packets for this itd */
+ itd->num_of_pkts = iNumofSlots * mult;
+ /*for the case , urb number_of_packets is less than (number of slot*mult*x times) */
+ if (itd->num_of_pkts >= urb->number_of_packets)
+ {
+ itd->num_of_pkts = urb->number_of_packets;
+ }
+ else {
+ if (itd->num_of_pkts >
+ urb->number_of_packets - packets){
+ itd->num_of_pkts =
+ urb->number_of_packets -
+ packets;
+ }
+ }
+
+ /* Initialize the following elements of the ITS structure
+ * > itd->length = length; -- the size of the request
+ * > itd->multi = multi; -- the number of transactions for
+ * this EP per micro frame
+ * > itd->hw_bufp[0] = buf_dma; -- The base address of the buffer where
+ * to put the data (this base address was
+ * the buffer provided plus the offset)
+ * And then, allocating memory from the PAYLOAD memory area, where the data
+ * coming from the requesting party will be placed or data requested by the
+ * requesting party will be retrieved when it is available.
+ */
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_submit_iso] packets index = %ld itd->num_of_pkts = %d\n",
+ packets, itd->num_of_pkts);
+ *status =
+ phcd_iso_itd_fill(hcd, itd, urb, packets,
+ itd->num_of_pkts);
+ if (*status != 0) {
+ if (((int) (qhead->next_uframe - iNumofPTDs)) <
+ 0) {
+ qhead->next_uframe = qhead->next_uframe + PTD_PERIODIC_SIZE; /*plus max PTDs*/
+ }
+ qhead->next_uframe -= iNumofPTDs;
+
+ /* Handle SITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_itd_free_list(hcd, urb,
+ *status);
+ }
+ iso_dbg(ISO_DBG_ERR,
+ "[phcd_submit_iso Error]: Error in filling up ITD\n");
+ return *status;
+ }
+
+ iPG = 0;
+ iMicroIndex = 0;
+ while (iNumofSlots > 0) {
+ offset = urb->iso_frame_desc[packets].offset;
+ /* Buffer for this packet */
+ buff_dma =
+ (u32) ((unsigned char *) urb->
+ transfer_buffer + offset);
+
+ /*for the case mult is 2 or 3 */
+ length = 0;
+ for (i = packets; i < packets + mult; i++) {
+ length += urb->iso_frame_desc[i].length;
+ }
+ itd->hw_transaction[iMicroIndex] =
+ EHCI_ISOC_ACTIVE | (length &
+ EHCI_ITD_TRANLENGTH)
+ << 16 | iPG << 12 | buff_dma;
+
+ if (itd->hw_bufp[iPG] != buff_dma){
+ itd->hw_bufp[++iPG] = buff_dma;
+ }
+
+ iso_dbg(ISO_DBG_DATA,
+ "[%s] offset : %ld buff_dma : 0x%08x length : %ld\n",
+ __FUNCTION__, offset,
+ (unsigned int) buff_dma, length);
+
+ itd->ssplit |= 1 << iMicroIndex;
+ packets++;
+ iMicroIndex += urb->interval;
+ iNumofSlots--;
+
+ /*last packets or last slot */
+ if (packets == urb->number_of_packets
+ || iNumofSlots == 0) {
+
+ itd->hw_transaction[iMicroIndex] |=
+ EHCI_ITD_IOC;
+
+ break;
+
+ }
+ }
+
+ /*
+ * If this SITD is not the head/root SITD, link this SITD to the SITD
+ * that came before it.
+ */
+ if (prev_itd) {
+ prev_itd->hw_next = (u32) (itd);
+ }
+
+ prev_itd = itd;
+
+ /*
+ * Allocate an ISO PTD from the ISO PTD map list and
+ * set the equivalent bit of the allocated PTD to active
+ * in the bitmap so that this PTD will be included into
+ * the periodic schedule
+ */
+
+
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_submit_iso]: ITD index %d\n",
+ itd->framenumber);
+ phcd_iso_get_itd_ptd_index(hcd, itd);
+ iso_dbg(ISO_DBG_DATA,
+ "[phcd_submit_iso]: ITD index %d\n",
+ itd->itd_index);
+
+ /*if we dont have any space left */
+ if (itd->itd_index == TD_PTD_INV_PTD_INDEX) {
+ *status = -ENOSPC;
+ if (((int) (qhead->next_uframe - iNumofPTDs)) <
+ 0){
+ /*plus max PTDs*/
+ qhead->next_uframe = qhead->next_uframe + PTD_PERIODIC_SIZE;
+ }
+ qhead->next_uframe -= iNumofPTDs;
+
+ /* Handle SITD list cleanup */
+ if (urb->hcpriv) {
+ phcd_iso_itd_free_list(hcd, urb,
+ *status);
+ }
+ return *status;
+ }
+
+ sitd_itd_list = &qhead->periodic_list.sitd_itd_head;
+ list_add_tail(&itd->itd_list, sitd_itd_list);
+ qhead->periodic_list.high_speed = 1;
+ qhead->periodic_list.ptdlocation |=
+ 0x1 << itd->itd_index;
+
+ /* Inidcate that a new SITD have been scheduled */
+ hcd->periodic_sched++;
+
+ /* Determine if there are any ITD scheduled before this one. */
+ if (urb->hcpriv == 0){
+ urb->hcpriv = itd;
+ }
+ iPTDIndex++;
+
+ } /*end of while */
+ }
+
+ /*end of HIGH SPEED */
+ /* Last td of current transaction */
+ if (high_speed == 0){
+ sitd->hw_next = EHCI_LIST_END;
+ }
+ urb->error_count = 0;
+ return *status;
+} /* phcd_submit_iso */
+#endif /* CONFIG_ISO_SUPPORT */
diff --git a/drivers/usb/host/isp1763-mem.c b/drivers/usb/host/isp1763-mem.c
new file mode 100644
index 00000000000..dfcaef901ba
--- /dev/null
+++ b/drivers/usb/host/isp1763-mem.c
@@ -0,0 +1,355 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a host controller driver file. Memory initialization, allocation, and
+* deallocation are handled here.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#ifdef CONFIG_ISO_SUPPORT
+
+/*memory utilization fuctions*/
+void
+phci_hcd_mem_init(void)
+{
+ int i = 0;
+ u32 start_addr = 0x1000;
+ struct isp1763_mem_addr *memaddr;
+ for (i = 0; i < BLK_TOTAL; i++) {
+ memaddr = &memalloc[i];
+ memset(memaddr, 0, sizeof *memaddr);
+ }
+ /*initialize block of 128bytes */
+ for (i = 0; i < BLK_128_; i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_128;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_128;
+ }
+ /*initialize block of 256bytes */
+ for (i = BLK_128_; i < BLK_256_; i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_256;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_256;
+ }
+ /*initialize block of 1024bytes */
+ for (i = BLK_128_ + BLK_256_; i < (BLK_128_ + BLK_256_ + BLK_1024_);
+ i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_1024;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_1024;
+ }
+
+ /*initialize block of 2kbytes */
+ for (i = (BLK_128_ + BLK_256_ + BLK_1024_);
+ i < (BLK_128_ + BLK_256_ + BLK_1024_ + BLK_2048_); i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_2048;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_2048;
+ }
+ /* initialize block of 4kbytes */
+ for (i = (BLK_128_ + BLK_256_ + BLK_1024_ + BLK_2048_);
+ i < (BLK_128_ + BLK_256_ + BLK_1024_ + BLK_2048_ + BLK_4096_);
+ i++){
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_4096;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_4096;
+ }
+ /* initialize block of 8kbytes */
+ for (i = (BLK_128_ + BLK_256_ + BLK_1024_ + BLK_2048_); i <
+ (BLK_128_ + BLK_256_ + BLK_1024_ + BLK_2048_ + BLK_4096_ +
+ BLK_8196_); i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_8192;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_8192;
+ }
+
+}
+
+
+/*free memory*/
+static void
+phci_hcd_mem_free(struct isp1763_mem_addr *memptr)
+{
+ /*block number to be freed */
+ int block = memptr->blk_num;
+
+ if (block < BLK_TOTAL){
+ if ((memptr->blk_size) && (memalloc[block].used != 0)) {
+ memalloc[block].used = 0;
+ memptr->used = 0;
+ }
+ }
+}
+
+
+/*allocate memory*/
+static void
+phci_hcd_mem_alloc(u32 size, struct isp1763_mem_addr *memptr, u32 flag)
+{
+ u32 blk_size = size;
+ u16 i;
+ u32 nextblk1 = 0, nextblk4 = 0;
+ u32 start = 0, end = 0;
+ struct isp1763_mem_addr *memaddr = 0;
+
+ memset(memptr, 0, sizeof *memptr);
+
+ if (blk_size == 0) {
+ memptr->phy_addr = 0;
+ memptr->virt_addr = 0;
+ memptr->blk_size = 0;
+ memptr->num_alloc = 0;
+ memptr->blk_num = 0;
+ return;
+ }
+
+ for (i = 0; i < BLK_TOTAL; i++) {
+ memaddr = &memalloc[i];
+ if (!memaddr->used && size <= memaddr->blk_size) {
+ memaddr->used = 1;
+ memptr->used = 1;
+ memptr->blk_num = i;
+ memptr->blk_size = memaddr->blk_size;
+ memptr->phy_addr = memaddr->phy_addr;
+ memptr->virt_addr = memptr->phy_addr;
+ return;
+ }
+ }
+
+ printk("isp1763-mem: No suitable block found!");
+
+ return;
+ /*end of the 1k blocks */
+ nextblk1 = BLK_256_ + BLK_1024_;
+ /*end of the 4k blocks */
+ nextblk4 = nextblk1 + BLK_4096_;
+
+ if (blk_size <= BLK_SIZE_128) {
+ blk_size = BLK_SIZE_128;
+ start = 0;
+ end = BLK_256_;
+ }
+ if (blk_size <= BLK_SIZE_256) {
+ blk_size = BLK_SIZE_256;
+ start = 0;
+ end = BLK_256_;
+ } else if (blk_size <= BLK_SIZE_1024) {
+ blk_size = BLK_SIZE_1024;
+ start = BLK_256_;
+ end = start + BLK_1024_;
+ } else if (blk_size > BLK_SIZE_1024) {
+ blk_size = BLK_SIZE_4096;
+ start = BLK_256_ + BLK_1024_;
+ end = start + BLK_4096_;
+ }
+
+ for (i = start; i < end; i++) {
+ memaddr = &memalloc[i];
+ if (!memaddr->used) {
+ memaddr->used = 1;
+ memptr->blk_num = i;
+ memptr->used = 1;
+ memptr->blk_size = blk_size;
+ memptr->phy_addr = memaddr->phy_addr;
+ memptr->virt_addr = memptr->phy_addr;
+ return;
+ }
+ }
+
+ /*look for in the next block if memory is free */
+ /*start from the first place of the next block */
+ start = end;
+
+ /*for 1k and 256 size request only 4k can be returned */
+ end = nextblk4;
+
+ for (i = start; i < end; i++) {
+ memaddr = &memalloc[i];
+ if (!memaddr->used) {
+ memaddr->used = 1;
+ memptr->used = 1;
+ memptr->blk_num = i;
+ memptr->blk_size = blk_size;
+ memptr->phy_addr = memaddr->phy_addr;
+ memptr->virt_addr = memptr->phy_addr;
+ return;
+ }
+ }
+
+}
+
+#else
+
+void
+phci_hcd_mem_init(void)
+{
+ int i = 0;
+ u32 start_addr = 0x1000;
+ struct isp1763_mem_addr *memaddr;
+ for (i = 0; i < BLK_TOTAL; i++) {
+ memaddr = &memalloc[i];
+ memset(memaddr, 0, sizeof *memaddr);
+ }
+
+ /*initialize block of 256bytes */
+ for (i = 0; i < BLK_256_; i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_256;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_256;
+ }
+ /*initialize block of 1024bytes */
+ for (i = BLK_256_; i < (BLK_256_ + BLK_1024_); i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_1024;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_1024;
+ }
+
+ /*initialize block of 4kbytes */
+ for (i = (BLK_256_ + BLK_1024_); i < (BLK_256_ + BLK_1024_ + BLK_4096_);
+ i++) {
+ memaddr = &memalloc[i];
+ memaddr->blk_num = i;
+ memaddr->used = 0;
+ memaddr->blk_size = BLK_SIZE_4096;
+ memaddr->phy_addr = start_addr;
+ start_addr += BLK_SIZE_4096;
+ }
+
+}
+
+
+/*free memory*/
+static void
+phci_hcd_mem_free(struct isp1763_mem_addr *memptr)
+{
+ /*block number to be freed */
+ int block = memptr->blk_num;
+
+ if (block < BLK_TOTAL)
+ if ((memptr->blk_size) && (memalloc[block].used != 0)) {
+ memalloc[block].used = 0;
+ memptr->used = 0;
+ }
+}
+
+
+/*allocate memory*/
+static void
+phci_hcd_mem_alloc(u32 size, struct isp1763_mem_addr *memptr, u32 flag)
+{
+ u32 blk_size = size;
+ u16 i;
+ u32 nextblk1 = 0, nextblk4 = 0;
+ u32 start = 0, end = 0;
+ struct isp1763_mem_addr *memaddr = 0;
+
+ memset(memptr, 0, sizeof *memptr);
+
+ pehci_print("phci_hcd_mem_alloc(size = %d)\n", size);
+
+ if (blk_size == 0) {
+ memptr->phy_addr = 0;
+ memptr->virt_addr = 0;
+ memptr->blk_size = 0;
+ memptr->num_alloc = 0;
+ memptr->blk_num = 0;
+ return;
+ }
+
+ /*end of the 1k blocks */
+ nextblk1 = BLK_256_ + BLK_1024_;
+ /*end of the 4k blocks */
+ nextblk4 = nextblk1 + BLK_4096_;
+
+
+ if (blk_size <= BLK_SIZE_256) {
+ blk_size = BLK_SIZE_256;
+ start = 0;
+ end = BLK_256_;
+ } else if (blk_size <= BLK_SIZE_1024) {
+ blk_size = BLK_SIZE_1024;
+ start = BLK_256_;
+ end = start + BLK_1024_;
+ } else if (blk_size > BLK_SIZE_1024) {
+ blk_size = BLK_SIZE_4096;
+ start = BLK_256_ + BLK_1024_;
+ end = start + BLK_4096_;
+ }
+
+ for (i = start; i < end; i++) {
+ memaddr = &memalloc[i];
+ if (!memaddr->used) {
+ memaddr->used = 1;
+ memptr->blk_num = i;
+ memptr->used = 1;
+ memptr->blk_size = blk_size;
+ memptr->phy_addr = memaddr->phy_addr;
+ memptr->virt_addr = memptr->phy_addr;
+ return;
+ }
+ }
+
+ /*look for in the next block if memory is free */
+ /*start from the first place of the next block */
+ start = end;
+
+ /*for 1k and 256 size request only 4k can be returned */
+ end = nextblk4;
+
+ for (i = start; i < end; i++) {
+ memaddr = &memalloc[i];
+ if (!memaddr->used) {
+ memaddr->used = 1;
+ memptr->used = 1;
+ memptr->blk_num = i;
+ memptr->blk_size = blk_size;
+ memptr->phy_addr = memaddr->phy_addr;
+ memptr->virt_addr = memptr->phy_addr;
+ return;
+ }
+ }
+
+}
+
+#endif
diff --git a/drivers/usb/host/isp1763-otg.c b/drivers/usb/host/isp1763-otg.c
new file mode 100644
index 00000000000..a951c338124
--- /dev/null
+++ b/drivers/usb/host/isp1763-otg.c
@@ -0,0 +1,189 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a host controller driver file. OTG related events are handled here.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+
+/*hub device which connected with root port*/
+struct usb_device *hubdev = 0;
+/* hub interrupt urb*/
+struct urb *huburb;
+
+/*return otghub from here*/
+struct usb_device *
+phci_register_otg_device(struct isp1763_dev *dev)
+{
+ printk("OTG dev %x %d\n",(u32) hubdev, hubdev->devnum);
+ if (hubdev && hubdev->devnum >= 0x2) {
+ return hubdev;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(phci_register_otg_device);
+
+/*suspend the otg port(0)
+ * needed when port is switching
+ * from host to device
+ * */
+int
+phci_suspend_otg_port(struct isp1763_dev *dev, u32 command)
+{
+ int status = 0;
+ hubdev->otgstate = USB_OTG_SUSPEND;
+ if (huburb->status == -EINPROGRESS) {
+ huburb->status = 0;
+ }
+
+ huburb->status = 0;
+ huburb->complete(huburb);
+ return status;
+}
+EXPORT_SYMBOL(phci_suspend_otg_port);
+
+/*set the flag to enumerate the device*/
+int
+phci_enumerate_otg_port(struct isp1763_dev *dev, u32 command)
+{
+ /*set the flag to enumerate */
+ /*connect change interrupt will happen from
+ * phci_intl_worker only
+ * */
+ hubdev->otgstate = USB_OTG_ENUMERATE;
+ if (huburb->status == -EINPROGRESS) {
+ huburb->status = 0;
+ }
+ /*complete the urb */
+
+ huburb->complete(huburb);
+
+ /*reset the otghub urb status */
+ huburb->status = -EINPROGRESS;
+ return 0;
+}
+EXPORT_SYMBOL(phci_enumerate_otg_port);
+
+/*host controller resume sequence at otg port*/
+int
+phci_resume_otg_port(struct isp1763_dev *dev, u32 command)
+{
+ printk("Resume is called\n");
+ hubdev->otgstate = USB_OTG_RESUME;
+ if (huburb->status == -EINPROGRESS) {
+ huburb->status = 0;
+ }
+ /*complete the urb */
+
+ huburb->complete(huburb);
+
+ /*reset the otghub urb status */
+ huburb->status = -EINPROGRESS;
+ return 0;
+}
+EXPORT_SYMBOL(phci_resume_otg_port);
+/*host controller remote wakeup sequence at otg port*/
+int
+phci_remotewakeup(struct isp1763_dev *dev)
+{
+ printk("phci_remotewakeup_otg_port is called\n");
+ hubdev->otgstate = USB_OTG_REMOTEWAKEUP;
+ if(huburb->status == -EINPROGRESS)
+ huburb->status = 0;
+ /*complete the urb*/
+#if ((defined LINUX_269) || defined (LINUX_2611))
+ huburb->complete(huburb,NULL);
+#else
+ huburb->complete(huburb);
+#endif
+ /*reset the otghub urb status*/
+ huburb->status = -EINPROGRESS;
+ return 0;
+}
+EXPORT_SYMBOL(phci_remotewakeup);
+
+/*host controller wakeup sequence at otg port*/
+int
+phci_resume_wakeup(struct isp1763_dev *dev)
+{
+ printk("phci_wakeup_otg_port is called\n");
+#if 0
+ hubdev->otgstate = USB_OTG_WAKEUP_ALL;
+ if(huburb->status == -EINPROGRESS)
+#endif
+ huburb->status = 0;
+ /*complete the urb*/
+#if ((defined LINUX_269) || defined (LINUX_2611))
+ huburb->complete(huburb,NULL);
+#else
+ huburb->complete(huburb);
+#endif
+ /*reset the otghub urb status*/
+ huburb->status = -EINPROGRESS;
+ return 0;
+}
+EXPORT_SYMBOL(phci_resume_wakeup);
+
+struct isp1763_driver *host_driver;
+struct isp1763_driver *device_driver;
+
+void
+pehci_delrhtimer(struct isp1763_dev *dev)
+{
+
+ struct usb_hcd *usb_hcd =
+ container_of(huburb->dev->parent->bus, struct usb_hcd, self);
+ del_timer_sync(&usb_hcd->rh_timer);
+ del_timer(&usb_hcd->rh_timer);
+
+}
+EXPORT_SYMBOL(pehci_delrhtimer);
+
+int
+pehci_Deinitialize(struct isp1763_dev *dev)
+{
+ dev -= 2;
+ if (dev->index == 0) {
+ if (dev->driver) {
+ if (dev->driver->powerdown) {
+ dev->driver->powerdown(dev);
+ }
+ }
+ }
+return 0;
+}
+EXPORT_SYMBOL(pehci_Deinitialize);
+
+int
+pehci_Reinitialize(struct isp1763_dev *dev)
+{
+
+ dev -= 2;
+ if (dev->index == 0) {
+ if(dev->driver->powerup){
+ dev->driver->powerup(dev);
+ }
+ }
+return 0;
+}
+EXPORT_SYMBOL(pehci_Reinitialize);
+
+
diff --git a/drivers/usb/host/isp1763-qtdptd.c b/drivers/usb/host/isp1763-qtdptd.c
new file mode 100644
index 00000000000..34552fb22bc
--- /dev/null
+++ b/drivers/usb/host/isp1763-qtdptd.c
@@ -0,0 +1,1315 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : host
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a host controller driver file. QTD processing is handled here.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+
+/* Td managenment routines */
+
+#define QUEUE_HEAD_NOT_EMPTY 0x001
+
+
+/*free the location used by removed urb/endpoint*/
+static void
+phci_hcd_release_td_ptd_index(struct ehci_qh *qh)
+{
+ td_ptd_map_buff_t *td_ptd_buff = &td_ptd_map_buff[qh->type];
+ td_ptd_map_t *td_ptd_map = &td_ptd_buff->map_list[qh->qtd_ptd_index];
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+ /*hold the global lock here */
+ td_ptd_map->state = TD_PTD_NEW;
+ qh->qh_state = QH_STATE_IDLE;
+ /*
+ set these values to NULL as schedule
+ is based on these values,
+ rather td_ptd_map state
+ */
+ td_ptd_map->qh = NULL;
+ td_ptd_map->qtd = NULL;
+
+ td_ptd_buff->active_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+ /* Only pending transfers on current QH must be cleared */
+ td_ptd_buff->pending_ptd_bitmap &= ~td_ptd_map->ptd_bitmap;
+
+ pehci_entry("-- %s: Exit\n", __FUNCTION__);
+
+}
+
+/*print ehciqtd*/
+static void
+print_ehci_qtd(struct ehci_qtd *qtd)
+{
+ pehci_print("hwnext 0x%08x, altnext 0x%08x,token 0x%08x, length %d\n",
+ qtd->hw_next, qtd->hw_alt_next,
+ le32_to_cpu(qtd->hw_token), qtd->length);
+
+ pehci_print("buf[0] 0x%08x\n", qtd->hw_buf[0]);
+
+}
+
+/*delete all qtds linked with this urb*/
+static void
+phci_hcd_qtd_list_free(phci_hcd * ehci,
+ struct urb *urb, struct list_head *qtd_list)
+{
+ struct list_head *entry, *temp;
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct ehci_qtd *qtd;
+ qtd = list_entry(entry, struct ehci_qtd, qtd_list);
+ if(!list_empty(&qtd->qtd_list))
+ list_del_init(&qtd->qtd_list);
+ qha_free(qha_cache, qtd);
+ }
+
+ pehci_entry("-- %s: Exit \n", __FUNCTION__);
+}
+
+
+/*
+ * free all the qtds for this transfer, also
+ * free the Host memory to be reused
+ */
+static void
+phci_hcd_urb_free_priv(phci_hcd * hcd,
+ urb_priv_t * urb_priv_to_remove, struct ehci_qh *qh)
+{
+ int i = 0;
+ struct ehci_qtd *qtd;
+ for (i = 0; i < urb_priv_to_remove->length; i++) {
+ if (urb_priv_to_remove->qtd[i]) {
+ qtd = urb_priv_to_remove->qtd[i];
+
+ if(!list_empty(&qtd->qtd_list))
+ list_del_init(&qtd->qtd_list);
+
+ /* This is required when the device is abruptly disconnected and the
+ * PTDs are not completely processed
+ */
+ if (qtd->length)
+ phci_hcd_mem_free(&qtd->mem_addr);
+
+ qha_free(qha_cache, qtd);
+ urb_priv_to_remove->qtd[i] = 0;
+ qtd = 0;
+ }
+
+ }
+
+ return;
+}
+
+
+/*allocate the qtd*/
+struct ehci_qtd *
+phci_hcd_qtd_allocate(int mem_flags)
+{
+
+ struct ehci_qtd *qtd = 0;
+ qtd = kmalloc(sizeof *qtd, mem_flags);
+ if (!qtd)
+ {
+ return 0;
+ }
+
+ memset(qtd, 0, sizeof *qtd);
+ qtd->qtd_dma = cpu_to_le32(qtd);
+ qtd->hw_next = EHCI_LIST_END;
+ qtd->hw_alt_next = EHCI_LIST_END;
+ qtd->state = QTD_STATE_NEW;
+ INIT_LIST_HEAD(&qtd->qtd_list);
+ return qtd;
+}
+
+/*
+ * calculates host memory for current length transfer td,
+ * maximum td length is 4K(custom made)
+ * */
+static int
+phci_hcd_qtd_fill(struct urb *urb,
+ struct ehci_qtd *qtd,
+ dma_addr_t buf, size_t len, int token, int *status)
+{
+ int count = 0;
+
+ qtd->hw_buf[0] = (u32) buf;
+ /*max lenggth is HC_ATL_PL_SIZE */
+ if (len > HC_ATL_PL_SIZE) {
+ count = HC_ATL_PL_SIZE;
+ } else {
+ count = len;
+ }
+ qtd->hw_token = cpu_to_le32((count << 16) | token);
+ qtd->length = count;
+
+ pehci_print("%s:qtd %p, token %8x bytes %d dma %x\n",
+ __FUNCTION__, qtd, le32_to_cpu(qtd->hw_token), count,
+ qtd->hw_buf[0]);
+
+ return count;
+}
+
+
+/*
+ * makes number of qtds required for
+ * interrupt/bulk/control transfer length
+ * and initilize qtds
+ * */
+struct list_head *
+phci_hcd_make_qtd(phci_hcd * hcd,
+ struct list_head *head, struct urb *urb, int *status)
+{
+
+ struct ehci_qtd *qtd, *qtd_prev;
+ dma_addr_t buf, map_buf;
+ int len, maxpacket;
+ int is_input;
+ u32 token;
+ int cnt = 0;
+ urb_priv_t *urb_priv = (urb_priv_t *) urb->hcpriv;
+
+ pehci_entry("++ %s, Entered\n", __FUNCTION__);
+
+ /*take the qtd from already allocated
+ structure from hcd_submit_urb
+ */
+ qtd = urb_priv->qtd[cnt];
+ if (unlikely(!qtd)) {
+ *status = -ENOMEM;
+ return 0;
+ }
+
+ qtd_prev = 0;
+ list_add_tail(&qtd->qtd_list, head);
+
+ qtd->urb = urb;
+
+ token = QTD_STS_ACTIVE;
+ token |= (EHCI_TUNE_CERR << 10);
+
+ len = urb->transfer_buffer_length;
+
+ is_input = usb_pipein(urb->pipe);
+
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ if (phci_hcd_qtd_fill(urb, qtd, cpu_to_le32(urb->setup_packet),
+ sizeof(struct usb_ctrlrequest),
+ token | (2 /* "setup" */ << 8),
+ status) < 0) {
+ goto cleanup;
+ }
+
+ cnt++; /* increment the index */
+ print_ehci_qtd(qtd);
+ /* ... and always at least one more pid */
+ token ^= QTD_TOGGLE;
+ qtd_prev = qtd;
+ qtd = urb_priv->qtd[cnt];
+ if (unlikely(!qtd)) {
+ *status = -ENOMEM;
+ goto cleanup;
+ }
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * data transfer stage: buffer setup
+ */
+ len = urb->transfer_buffer_length;
+ if (likely(len > 0)) {
+ /*update the buffer address */
+ buf = cpu_to_le32(urb->transfer_buffer);
+ } else {
+ buf = map_buf = cpu_to_le32(0); /*set-up stage has no data. */
+ }
+
+ /* So are we waiting for the ack only or there is a data stage with out. */
+ if (!buf || usb_pipein(urb->pipe)) {
+ token |= (1 /* "in" */ << 8);
+ }
+ /* else it's already initted to "out" pid (0 << 8) */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe)) & 0x07ff;
+
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+
+ for (;;) {
+ int this_qtd_len;
+ this_qtd_len =
+ phci_hcd_qtd_fill(urb, qtd, buf, len, token, status);
+ if (this_qtd_len < 0)
+ goto cleanup;
+ print_ehci_qtd(qtd);
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+ cnt++;
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) {
+ token ^= QTD_TOGGLE;
+ }
+
+ if (likely(len <= 0)) {
+ break;
+ }
+ qtd_prev = qtd;
+ qtd = urb_priv->qtd[cnt];
+ if (unlikely(!qtd)) {
+ goto cleanup;
+ }
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (likely(buf != 0)) {
+ int one_more = 0;
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ token ^= 0x0100; /* "in" <--> "out" */
+ token |= QTD_TOGGLE; /* force DATA1 */
+
+ } else if (usb_pipebulk(urb->pipe) /* bulk data exactly terminated on zero lenth */
+ &&(urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = urb_priv->qtd[cnt];
+ if (unlikely(!qtd)) {
+ goto cleanup;
+ }
+
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+ phci_hcd_qtd_fill(urb, qtd, 0, 0, token, status);
+ print_ehci_qtd(qtd);
+ cnt++;
+ }
+ }
+
+ /*this is our last td for current transfer */
+ qtd->state |= QTD_STATE_LAST;
+
+ /*number of tds */
+ if (urb_priv->length != cnt) {
+ err("Never Error: number of tds allocated %d exceeding %d\n",
+ urb_priv->length, cnt);
+ }
+ /* by default, enable interrupt on urb completion */
+ if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT))) {
+ qtd->hw_token |= __constant_cpu_to_le32(QTD_IOC);
+ }
+
+ pehci_entry("-- %s, Exit\n", __FUNCTION__);
+ return head;
+
+ cleanup:
+ phci_hcd_qtd_list_free(hcd, urb, head);
+ return 0;
+}
+
+/*allocates a queue head(endpoint*/
+struct ehci_qh *
+phci_hcd_qh_alloc(phci_hcd * hcd)
+{
+
+ struct ehci_qh *qh = kmalloc(sizeof(struct ehci_qh), GFP_ATOMIC);
+ if (!qh)
+ {
+ return qh;
+ }
+
+ memset(qh, 0, sizeof *qh);
+ atomic_set(&qh->refcount, 1);
+ init_waitqueue_head(&qh->waitforcomplete);
+ qh->qh_dma = (u32) qh;
+ INIT_LIST_HEAD(&qh->qtd_list);
+ INIT_LIST_HEAD(&qh->itd_list);
+ qh->next_uframe = -1;
+ return qh;
+}
+
+/* calculates header address for the tds*/
+static int
+phci_hcd_fill_ptd_addresses(td_ptd_map_t * td_ptd_map, int index, int bufftype)
+{
+ int i = 0;
+ unsigned long tdlocation = 0;
+ /*
+ * the below payloadlocation and
+ * payloadsize are redundant
+ * */
+ unsigned long payloadlocation = 0;
+ unsigned long payloadsize = 0;
+ pehci_entry("++ %s: enter\n", __FUNCTION__);
+ switch (bufftype) {
+ /*atl header starts at 0xc00 */
+ case TD_PTD_BUFF_TYPE_ATL:
+ tdlocation = 0x0c00;
+ /*redundant */
+ payloadsize = 0x1000;
+ payloadlocation = 0x1000;
+ break;
+ case TD_PTD_BUFF_TYPE_INTL:
+ /*interrupt header
+ * starts at 0x800
+ * */
+ tdlocation = 0x0800;
+ /*redundant */
+ payloadlocation = 0x1000;
+ payloadsize = 0x1000;
+ break;
+
+ case TD_PTD_BUFF_TYPE_ISTL:
+ /*iso header starts
+ * at 0x400*/
+
+ tdlocation = 0x0400;
+ /*redunndant */
+ payloadlocation = 0x1000;
+ payloadsize = 0x1000;
+
+ break;
+ }
+
+
+ i = index;
+ payloadlocation += (i) * payloadsize; /*each payload is of 4096 bytes */
+ tdlocation += (i) * PHCI_QHA_LENGTH; /*each td is of 32 bytes */
+ td_ptd_map->ptd_header_addr = tdlocation;
+ td_ptd_map->ptd_data_addr = payloadlocation;
+ td_ptd_map->ptd_ram_data_addr = ((payloadlocation - 0x0400) >> 3);
+ pehci_print
+ ("Index: %d, Header: 0x%08x, Payload: 0x%08x,Data start address: 0x%08x\n",
+ index, td_ptd_map->ptd_header_addr, td_ptd_map->ptd_data_addr,
+ td_ptd_map->ptd_ram_data_addr);
+ pehci_entry("-- %s: Exit", __FUNCTION__);
+ return payloadlocation;
+}
+
+
+/*--------------------------------------------------------------*
+ * calculate the header location for the current
+ * endpoint, if found returns a valid index
+ * else invalid
+ -----------------------------------------------------------*/
+static void
+phci_hcd_get_qtd_ptd_index(struct ehci_qh *qh,
+ struct ehci_qtd *qtd, struct ehci_itd *itd)
+{
+ u8 buff_type = td_ptd_pipe_x_buff_type[qh->type];
+ u8 qtd_ptd_index; /*, index; */
+ /*this is the location of the ptd's skip map/done map, also
+ calculating the td header, payload, data start address
+ location */
+ u8 bitmap = 0x1;
+ u8 max_ptds;
+
+ td_ptd_map_buff_t *ptd_map_buff = &(td_ptd_map_buff[buff_type]);
+ pehci_entry("++ %s, Entered, buffer type %d\n", __FUNCTION__,
+ buff_type);
+
+ /* ATL PTDs can wait */
+ max_ptds = (buff_type == TD_PTD_BUFF_TYPE_ATL)
+ ? TD_PTD_MAX_BUFF_TDS : ptd_map_buff->max_ptds;
+
+ for (qtd_ptd_index = 0; qtd_ptd_index < max_ptds; qtd_ptd_index++) { /* Find the first free slot */
+ if (ptd_map_buff->map_list[qtd_ptd_index].state == TD_PTD_NEW) {
+ /* Found a free slot */
+ if (qh->qtd_ptd_index == TD_PTD_INV_PTD_INDEX) {
+ qh->qtd_ptd_index = qtd_ptd_index;
+ }
+ ptd_map_buff->map_list[qtd_ptd_index].datatoggle = 0;
+ /*put the ptd_index into operational state */
+ ptd_map_buff->map_list[qtd_ptd_index].state =
+ TD_PTD_ACTIVE;
+ ptd_map_buff->map_list[qtd_ptd_index].qtd = qtd;
+ /* No td transfer is in progress */
+ ptd_map_buff->map_list[qtd_ptd_index].itd = itd;
+ /*initialize endpoint(queuehead) */
+ ptd_map_buff->map_list[qtd_ptd_index].qh = qh;
+ ptd_map_buff->map_list[qtd_ptd_index].ptd_bitmap =
+ bitmap << qtd_ptd_index;
+ phci_hcd_fill_ptd_addresses(&ptd_map_buff->
+ map_list[qtd_ptd_index],
+ qh->qtd_ptd_index,
+ buff_type);
+ ptd_map_buff->map_list[qtd_ptd_index].lasttd = 0;
+ ptd_map_buff->total_ptds++; /* update # of total td's */
+ /*make the queuehead map, to process in the phci_schedule_ptds */
+ ptd_map_buff->active_ptd_bitmap |=
+ (bitmap << qtd_ptd_index);
+ break;
+ }
+ }
+ pehci_entry("-- %s, Exit\n", __FUNCTION__);
+ return;
+
+} /* phci_get_td_ptd_index */
+
+
+
+/*
+ * calculate the header location for the endpoint and
+ * all tds on this endpoint will use the same
+ * header location for all transfers on this endpoint.
+ * also puts the endpoint into the linked state
+ * */
+static void
+phci_hcd_qh_link_async(phci_hcd * hcd, struct ehci_qh *qh, int *status)
+{
+ struct ehci_qtd *qtd = 0;
+ struct list_head *qtd_list = &qh->qtd_list;
+
+#ifdef MSEC_INT_BASED
+ td_ptd_map_buff_t *ptd_map_buff;
+ td_ptd_map_t *td_ptd_map;
+#endif
+
+ /* take the first td, in case we are not able to schedule the new td
+ and this is going for remove
+ */
+ qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ /* Assign a td-ptd index for this ed so that we can put ptd's in the HC buffers */
+
+ qh->qtd_ptd_index = TD_PTD_INV_PTD_INDEX;
+ phci_hcd_get_qtd_ptd_index(qh, qtd, NULL); /* Get a td-ptd index */
+ if (qh->qtd_ptd_index == TD_PTD_INV_PTD_INDEX) {
+ err("can not find the location in our buffer\n");
+ *status = -ENOSPC;
+ return;
+ }
+#ifdef MSEC_INT_BASED
+ /*first transfers in sof interrupt goes into pending */
+ ptd_map_buff = &(td_ptd_map_buff[qh->type]);
+ td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];
+ ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;
+
+#endif
+ /* open the halt so that it acessed */
+ qh->hw_token &= ~__constant_cpu_to_le32(QTD_STS_HALT);
+ qh->qh_state = QH_STATE_LINKED;
+ qh->qh_state |= QH_STATE_TAKE_NEXT;
+ pehci_entry("-- %s: Exit , qh %p\n", __FUNCTION__, qh);
+
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * mainly used for setting up current td on current
+ * endpoint(queuehead), endpoint may be new or
+ * halted one
+ * */
+
+static inline void
+phci_hcd_qh_update(phci_hcd * ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+ /*make this current td */
+ qh->hw_current = QTD_NEXT(qtd->qtd_dma);
+ qh->hw_qtd_next = QTD_NEXT(qtd->qtd_dma);
+ qh->hw_alt_next = EHCI_LIST_END;
+ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+ wmb();
+ qh->hw_token &= __constant_cpu_to_le32(QTD_TOGGLE | QTD_STS_PING);
+}
+
+/*
+ * used for ATL, INT transfers
+ * function creates new endpoint,
+ * calculates bandwidth for interrupt transfers,
+ * and initialize the qh based on endpoint type/speed
+ * */
+struct ehci_qh *
+phci_hcd_make_qh(phci_hcd * hcd,
+ struct urb *urb, struct list_head *qtd_list, int *status)
+{
+ struct ehci_qh *qh = 0;
+ u32 info1 = 0, info2 = 0;
+ int is_input, type;
+ int maxp = 0;
+ int mult = 0;
+ int bustime = 0;
+ struct ehci_qtd *qtd =
+ list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ qh = phci_hcd_qh_alloc(hcd);
+ if (!qh) {
+ *status = -ENOMEM;
+ return 0;
+ }
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ info1 |= usb_pipeendpoint(urb->pipe) << 8;
+ info1 |= usb_pipedevice(urb->pipe) << 0;
+
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+ maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
+ mult = 1 + ((maxp >> 11) & 0x3);
+
+ /*set this queueheads index to invalid */
+ qh->qtd_ptd_index = TD_PTD_INV_PTD_INDEX;
+
+ switch (type) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ qh->type = TD_PTD_BUFF_TYPE_ATL;
+ break;
+
+ case PIPE_INTERRUPT:
+ qh->type = TD_PTD_BUFF_TYPE_INTL;
+ break;
+ case PIPE_ISOCHRONOUS:
+ qh->type = TD_PTD_BUFF_TYPE_ISTL;
+ break;
+
+ }
+
+
+
+ if (type == PIPE_INTERRUPT) {
+ /*for this interrupt transfer check how much bustime in usecs required */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ bustime = usb_check_bandwidth(urb->dev, urb);
+
+ if (bustime < 0) {
+ *status = -ENOSPC;
+ goto done;
+ }
+
+ usb_claim_bandwidth(urb->dev, urb, bustime,
+ usb_pipeisoc(urb->pipe));
+#else
+#endif
+ qh->usecs = bustime;
+
+ qh->start = NO_FRAME;
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ qh->c_usecs = 0;
+ qh->gap_uf = 0;
+ /*after how many uframes this interrupt is to be executed */
+ qh->period = urb->interval >> 3;
+ if (qh->period < 1) {
+ printk("intr period %d uframes,\n",
+ urb->interval);
+ }
+ /*restore the original urb->interval in qh->period */
+ qh->period = urb->interval;
+
+ } else {
+ /* gap is f(FS/LS transfer times) */
+ qh->gap_uf = 1 + 7; /*usb_calc_bus_time (urb->dev->speed,
+ is_input, 0, maxp) / (125 * 1000); */
+
+ if (is_input) { /* SPLIT, gap, CSPLIT+DATA */
+
+ qh->c_usecs = qh->usecs + 1; /*HS_USECS (0); */
+ qh->usecs = 10; /*HS_USECS (1); */
+ } else { /* SPLIT+DATA, gap, CSPLIT */
+ qh->usecs += 10; /*HS_USECS (1); */
+ qh->c_usecs = 1; /*HS_USECS (0); */
+ }
+
+
+ /*take the period ss/cs scheduling will be
+ handled by submit urb
+ */
+ qh->period = urb->interval;
+ }
+ }
+
+ /* using TT? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_LOW:
+ info1 |= (1 << 12); /* EPS "low" */
+ /* FALL THROUGH */
+
+ case USB_SPEED_FULL:
+ /* EPS 0 means "full" */
+ if (type != PIPE_INTERRUPT) {
+ info1 |= (EHCI_TUNE_RL_TT << 28);
+ }
+ if (type == PIPE_CONTROL) {
+ info1 |= (1 << 27); /* for TT */
+ info1 |= 1 << 14; /* toggle from qtd */
+ }
+ info1 |= maxp << 16;
+
+ info2 |= (EHCI_TUNE_MULT_TT << 30);
+ info2 |= urb->dev->ttport << 23;
+ info2 |= urb->dev->tt->hub->devnum << 16;
+ break;
+
+
+ case USB_SPEED_HIGH: /* no TT involved */
+ info1 |= (2 << 12); /* EPS "high" */
+ if (type == PIPE_CONTROL) {
+ info1 |= (EHCI_TUNE_RL_HS << 28);
+ info1 |= 64 << 16; /* usb2 fixed maxpacket */
+
+ info1 |= 1 << 14; /* toggle from qtd */
+ info2 |= (EHCI_TUNE_MULT_HS << 30);
+ } else if (type == PIPE_BULK) {
+ info1 |= (EHCI_TUNE_RL_HS << 28);
+ info1 |= 512 << 16; /* usb2 fixed maxpacket */
+ info2 |= (EHCI_TUNE_MULT_HS << 30);
+ } else { /* PIPE_INTERRUPT */
+ info1 |= (maxp & 0x7ff) /*max_packet (maxp) */ <<16;
+ info2 |= mult /*hb_mult (maxp) */ << 30;
+ }
+ break;
+
+ default:
+ pehci_print("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ done:
+#else
+#endif
+ qha_free(qha_cache, qh);
+ return 0;
+ } /*end of switch */
+
+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+ /* init as halted, toggle clear, advance to dummy */
+ qh->qh_state = QH_STATE_IDLE;
+ qh->hw_info1 = cpu_to_le32(info1);
+ qh->hw_info2 = cpu_to_le32(info2);
+ /*link the tds here */
+ list_splice(qtd_list, &qh->qtd_list);
+ phci_hcd_qh_update(hcd, qh, qtd);
+ qh->hw_token = cpu_to_le32(QTD_STS_HALT);
+ if (!usb_pipecontrol(urb->pipe)) {
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
+ 1);
+ }
+ pehci_entry("-- %s: Exit, qh %p\n", __FUNCTION__, qh);
+ return qh;
+}
+
+
+/*-----------------------------------------------------------*/
+/*
+ * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
+ * the hardware data toggle in the QH, and set the pseudo-toggle in udev
+ * so we can see if usb_clear_halt() was called. NOP for control, since
+ * we set up qh->hw_info1 to always use the QTD toggle bits.
+ */
+static inline void
+phci_hcd_clear_toggle(struct usb_device *udev, int ep, int is_out,
+ struct ehci_qh *qh)
+{
+ pehci_print("clear toggle, dev %d ep 0x%x-%s\n",
+ udev->devnum, ep, is_out ? "out" : "in");
+ qh->hw_token &= ~__constant_cpu_to_le32(QTD_TOGGLE);
+ usb_settoggle(udev, ep, is_out, 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+struct ehci_qh *
+phci_hcd_qh_append_tds(phci_hcd * hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+#else
+#endif
+ struct urb *urb, struct list_head *qtd_list,
+ void **ptr, int *status)
+{
+
+ int epnum;
+
+ struct ehci_qh *qh = 0;
+ struct ehci_qtd *qtd =
+ list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+ td_ptd_map_buff_t *ptd_map_buff;
+ td_ptd_map_t *td_ptd_map;
+
+
+
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ epnum = ep->desc.bEndpointAddress;
+#else
+ epnum = urb->ep->desc.bEndpointAddress;
+#endif
+
+ qh = (struct ehci_qh *) *ptr;
+ if (likely(qh != 0)) {
+ u32 hw_next = QTD_NEXT(qtd->qtd_dma);
+ pehci_print("%Queue head already %p\n", qh);
+
+ ptd_map_buff = &(td_ptd_map_buff[qh->type]);
+ td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];
+
+ /* maybe patch the qh used for set_address */
+ if (unlikely
+ (epnum == 0 && le32_to_cpu(qh->hw_info1 & 0x7f) == 0)) {
+ qh->hw_info1 |= cpu_to_le32(usb_pipedevice(urb->pipe));
+ }
+
+ /* is an URB is queued to this qh already? */
+ if (unlikely(!list_empty(&qh->qtd_list))) {
+ struct ehci_qtd *last_qtd;
+ /* update the last qtd's "next" pointer */
+ last_qtd = list_entry(qh->qtd_list.prev,
+ struct ehci_qtd, qtd_list);
+
+ /*queue head is not empty just add the
+ td at the end of it , and return from here
+ */
+ last_qtd->hw_next = hw_next;
+
+ /*set the status as positive */
+ *status = (u32) QUEUE_HEAD_NOT_EMPTY;
+
+ /* no URB queued */
+ } else {
+
+ // qh->qh_state = QH_STATE_IDLE;
+
+
+ /* usb_clear_halt() means qh data toggle gets reset */
+ if (usb_pipebulk(urb->pipe)
+ && unlikely(!usb_gettoggle(urb->dev, (epnum & 0x0f),
+ !(epnum & 0x80)))) {
+
+ phci_hcd_clear_toggle(urb->dev,
+ epnum & 0x0f,
+ !(epnum & 0x80), qh);
+
+ /*reset our data toggle */
+
+ qh->datatoggle = 0;
+ qh->ping = 0;
+
+ }
+ phci_hcd_qh_update(hcd, qh, qtd);
+ }
+ /*put everything in pedning, will be cleared during scheduling */
+ ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;
+ list_splice(qtd_list, qh->qtd_list.prev);
+ } else {
+ qh = phci_hcd_make_qh(hcd, urb, qtd_list, status);
+ *ptr = qh;
+ }
+ pehci_entry("-- %s: Exit qh %p\n", __FUNCTION__, qh);
+ return qh;
+}
+
+/*link qtds to endpoint(qh)*/
+struct ehci_qh *
+phci_hcd_submit_async(phci_hcd * hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+#else
+#endif
+ struct list_head *qtd_list, struct urb *urb, int *status)
+{
+ struct ehci_qtd *qtd;
+ struct hcd_dev *dev;
+ int epnum;
+
+#ifndef THREAD_BASED
+ unsigned long flags;
+#endif
+
+
+ struct ehci_qh *qh = 0;
+
+ urb_priv_t *urb_priv = urb->hcpriv;
+
+ qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+ dev = (struct hcd_dev *) urb->hcpriv;
+ epnum = usb_pipeendpoint(urb->pipe);
+ if (usb_pipein(urb->pipe) && !usb_pipecontrol(urb->pipe)) {
+ epnum |= 0x10;
+ }
+
+ pehci_entry("++ %s, enter\n", __FUNCTION__);
+
+ /* ehci_hcd->lock guards shared data against other CPUs:
+ * ehci_hcd: async, reclaim, periodic (and shadow), ...
+ * hcd_dev: ep[]
+
+ * ehci_qh: qh_next, qtd_list
+
+ * ehci_qtd: qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+#ifndef THREAD_BASED
+ spin_lock_irqsave(&hcd->lock, flags);
+#endif
+
+ spin_lock(&hcd_data_lock);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ usb_hcd_link_urb_to_ep(&hcd->usb_hcd, urb);
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ qh = phci_hcd_qh_append_tds(hcd, ep, urb, qtd_list, &ep->hcpriv,
+ status);
+#else
+ qh = phci_hcd_qh_append_tds(hcd, urb, qtd_list, &urb->ep->hcpriv,
+ status);
+#endif
+ if (!qh || *status < 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
+ usb_hcd_unlink_urb_from_ep(&hcd->usb_hcd, urb);
+#endif
+ goto cleanup;
+ }
+ /* Control/bulk operations through TTs don't need scheduling,
+ * the HC and TT handle it when the TT has a buffer ready.
+ */
+
+ /* now the quehead can not be in the unlink state */
+
+// printk("qh->qh_state:0x%x \n",qh->qh_state);
+ if (qh->qh_state == QH_STATE_UNLINK) {
+ pehci_info("%s: free the urb,qh->state %x\n", __FUNCTION__,
+ qh->qh_state);
+ phci_hcd_qtd_list_free(hcd, urb, &qh->qtd_list);
+ spin_unlock(&hcd_data_lock);
+
+#ifndef THREAD_BASED
+ spin_unlock_irqrestore(&hcd->lock, flags);
+#endif
+ *status = -ENODEV;
+ return 0;
+ }
+
+ if (likely(qh != 0)) {
+ urb_priv->qh = qh;
+ if (likely(qh->qh_state == QH_STATE_IDLE))
+ phci_hcd_qh_link_async(hcd, qh, status);
+ }
+
+ cleanup:
+ spin_unlock(&hcd_data_lock);
+
+#ifndef THREAD_BASED
+ /* free it from lock systme can sleep now */
+ spin_unlock_irqrestore(&hcd->lock, flags);
+#endif
+
+ /* could not get the QH terminate and clean. */
+ if (unlikely(qh == 0) || *status < 0) {
+ phci_hcd_qtd_list_free(hcd, urb, qtd_list);
+ return qh;
+ }
+ return qh;
+}
+
+/*
+ * initilaize the s-mask c-mask for
+ * interrupt transfers.
+ */
+static int
+phci_hcd_qhint_schedule(phci_hcd * hcd,
+ struct ehci_qh *qh,
+ struct ehci_qtd *qtd,
+ struct _isp1763_qhint *qha, struct urb *urb)
+{
+ int i = 0;
+ u32 td_info3 = 0;
+ u32 td_info5 = 0;
+ u32 period = 0;
+ u32 usofmask = 1;
+ u32 usof = 0;
+ u32 ssplit = 0, csplit = 0xFF;
+ int maxpacket;
+ u32 numberofusofs = 0;
+
+ /*and since whol msec frame is empty, i can schedule in any uframe */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, !usb_pipein(urb->pipe));
+ maxpacket &= 0x7ff;
+ /*length of the data per uframe */
+ maxpacket = XFER_PER_UFRAME(qha->td_info1) * maxpacket;
+
+ /*caculate the number of uframes are required */
+ numberofusofs = urb->transfer_buffer_length / maxpacket;
+ /*if something left */
+ if (urb->transfer_buffer_length % maxpacket) {
+ numberofusofs += 1;
+ }
+
+ for (i = 0; i < numberofusofs; i++) {
+ usofmask <<= i;
+ usof |= usofmask;
+
+ }
+
+ /*
+ for full/low speed devices, as we
+ have seperate location for all the endpoints
+ let the start split goto the first uframe, means 0 uframe
+ */
+ if (urb->dev->speed != USB_SPEED_HIGH && usb_pipeint(urb->pipe)) {
+ /*set the complete splits */
+ /*set all the bits and lets see whats happening */
+ /*but this will be set based on the maximum packet size */
+ ssplit = usof;
+ /* need to fix it */
+ csplit = 0x1C;
+ qha->td_info6 = csplit;
+ period = qh->period;
+ if (period >= 32) {
+ period = qh->period / 2;
+ }
+ td_info3 = period;
+ goto done;
+
+ } else {
+ if (qh->period >= 8) {
+ period = qh->period / 8;
+ } else {
+ period = qh->period;
+ }
+ }
+ /*our limitaion is maximum of 32 ie 31, 5 bits */
+ if (period >= 32) {
+ period = 32;
+ /*devide by 2 */
+ period >>= 1;
+ }
+ if (qh->period >= 8) {
+ /*millisecond period */
+ td_info3 = (period << 3);
+ } else {
+ /*usof based tranmsfers */
+ /*minimum 4 usofs */
+ td_info3 = period;
+ usof = 0x11;
+ }
+
+ done:
+ td_info5 = usof;
+ qha->td_info3 |= td_info3;
+ qha->td_info5 |= usof;
+ return numberofusofs;
+}
+
+/*link interrupts qtds to endpoint*/
+struct ehci_qh *
+phci_hcd_submit_interrupt(phci_hcd * hcd,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ struct usb_host_endpoint *ep,
+#else
+#endif
+ struct list_head *qtd_list,
+ struct urb *urb, int *status)
+{
+ struct ehci_qtd *qtd;
+ struct _hcd_dev *dev;
+ int epnum;
+ unsigned long flags;
+ struct ehci_qh *qh = 0;
+ urb_priv_t *urb_priv = (urb_priv_t *) urb->hcpriv;
+
+ qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ dev = (struct hcd_dev *) urb->hcpriv;
+ epnum = ep->desc.bEndpointAddress;
+
+ pehci_entry("++ %s, enter\n", __FUNCTION__);
+
+
+ /*check for more than one urb queued for this endpoint */
+ qh = ep->hcpriv;
+#else
+ dev = (struct _hcd_dev *) (urb->hcpriv);
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ pehci_entry("++ %s, enter\n", __FUNCTION__);
+
+
+ /*check for more than one urb queued for this endpoint */
+ qh = (struct ehci_qh *) urb->ep->hcpriv;
+#endif
+
+ spin_lock_irqsave(&hcd->lock, flags);
+ if (unlikely(qh != 0)) {
+ if (!list_empty(&qh->qtd_list)) {
+ *status = -EBUSY;
+ goto done;
+ } else {
+ td_ptd_map_buff_t *ptd_map_buff;
+ td_ptd_map_t *td_ptd_map;
+ ptd_map_buff = &(td_ptd_map_buff[qh->type]);
+ td_ptd_map = &ptd_map_buff->map_list[qh->qtd_ptd_index];
+ ptd_map_buff->pending_ptd_bitmap |=
+ td_ptd_map->ptd_bitmap;
+ /*NEW*/ td_ptd_map->qtd = qtd;
+ /* maybe reset hardware's data toggle in the qh */
+ if (unlikely(!usb_gettoggle(urb->dev, epnum & 0x0f,
+ !(epnum & 0x80)))) {
+
+ /*reset our data toggle */
+ td_ptd_map->datatoggle = 0;
+ usb_settoggle(urb->dev, epnum & 0x0f,
+ !(epnum & 0x80), 1);
+ qh->datatoggle = 0;
+ }
+ /* trust the QH was set up as interrupt ... */
+ list_splice(qtd_list, &qh->qtd_list);
+ }
+ }
+
+
+ if (!qh) {
+ qh = phci_hcd_make_qh(hcd, urb, qtd_list, status);
+ if (likely(qh == 0)) {
+ *status = -ENOMEM;
+ goto done;
+ }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
+ ep->hcpriv = qh;
+#else
+ urb->ep->hcpriv = qh;
+#endif
+ }
+
+ if (likely(qh != 0)) {
+ urb_priv->qh = qh;
+ if (likely(qh->qh_state == QH_STATE_IDLE)) {
+ phci_hcd_qh_link_async(hcd, qh, status);
+ }
+ }
+
+
+ done:
+ /* free it from lock systme can sleep now */
+ spin_unlock_irqrestore(&hcd->lock, flags);
+ /* could not get the QH terminate and clean. */
+ if (unlikely(qh == 0) || *status < 0) {
+ phci_hcd_qtd_list_free(hcd, urb, qtd_list);
+ return qh;
+ }
+ return qh;
+}
+
+
+
+
+/*
+ * converts original EHCI QTD into PTD(Proprietary transfer descriptor)
+ * we call PTD as qha also for atl transfers
+ * for ATL and INT transfers
+ */
+void *
+phci_hcd_qha_from_qtd(phci_hcd * hcd,
+ struct ehci_qtd *qtd,
+ struct urb *urb,
+ void *ptd, u32 ptd_data_addr, struct ehci_qh *qh)
+{
+ u8 toggle = qh->datatoggle;
+ u32 token = 0;
+ u32 td_info1 = 0;
+ u32 td_info3 = 0;
+ u32 td_info4 = 0;
+ int maxpacket = 0;
+ u32 length = 0, temp = 0;
+ /*for non high speed devices */
+ u32 portnum = 0;
+ u32 hubnum = 0;
+ u32 se = 0, rl = 0x0, nk = 0x0;
+ u8 datatoggle = 0;
+ struct isp1763_mem_addr *mem_addr = &qtd->mem_addr;
+ u32 data_addr = 0;
+ u32 multi = 0;
+ struct _isp1763_qha *qha = (isp1763_qha *) ptd;
+ pehci_entry("++ %s: Entered\n", __FUNCTION__);
+
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+
+ maxpacket &= 0x7ff;
+
+ /************************first word*********************************/
+ length = qtd->length;
+ td_info1 = QHA_VALID;
+ td_info1 |= (length << 3);
+ td_info1 |= (maxpacket << 18);
+ td_info1 |= (usb_pipeendpoint(urb->pipe) << 31);
+ td_info1 |= MULTI(multi);
+ /*set the first dword */
+ qha->td_info1 = td_info1;
+
+ pehci_print("%s: length %d, 1st word 0x%08x\n", __FUNCTION__, length,
+ qha->td_info1);
+
+ /*******************second word***************************************/
+ temp = qtd->hw_token;
+
+ /*take the pid, thats of only interest to me from qtd,
+ */
+
+ temp = temp & 0x0300;
+ temp = temp >> 8;
+ /*take the endpoint and its 3 bits */
+ token = (usb_pipeendpoint(urb->pipe) & 0xE) >> 1;
+ token |= usb_pipedevice(urb->pipe) << 3;
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ pehci_print("device is full/low speed, %d\n", urb->dev->speed);
+ token |= 1 << 14;
+ portnum = urb->dev->ttport;
+ /*IMMED*/ hubnum = urb->dev->tt->hub->devnum;
+ token |= portnum << 18;
+ token |= hubnum << 25;
+ /*for non-high speed transfer
+ reload and nak counts are zero
+ */
+ rl = 0x0;
+ nk = 0x0;
+
+ }
+
+ /*se should be 0x2 for only low speed devices */
+ if (urb->dev->speed == USB_SPEED_LOW) {
+ se = 0x2;
+ }
+
+ if (usb_pipeint(urb->pipe)) {
+ /* reload count and nakcount is
+ required for only async transfers
+ */
+ rl = 0x0;
+ }
+
+ /*set the se field, should be zero for all
+ but low speed devices
+ */
+ token |= se << 16;
+ /*take the pid */
+ token |= temp << 10;
+
+ if (usb_pipebulk(urb->pipe)) {
+ token |= EPTYPE_BULK;
+ } else if (usb_pipeint(urb->pipe)) {
+ token |= EPTYPE_INT;
+ } else if (usb_pipeisoc(urb->pipe)) {
+ token |= EPTYPE_ISO;
+ }
+
+
+ qha->td_info2 = token;
+
+ pehci_print("%s: second word 0x%08x, qtd token 0x%08x\n",
+ __FUNCTION__, qha->td_info2, temp);
+
+ /***********************Third word*************************************/
+
+ /*calculate the data start address from mem_addr for qha */
+
+ data_addr = ((u32) (mem_addr->phy_addr) & 0xffff) - 0x400;
+ data_addr >>= 3;
+ pehci_print("data start address %x\n", data_addr);
+ /*use this field only if there
+ * is something to transfer
+ * */
+ if (length) {
+ td_info3 = data_addr << 8;
+ }
+ /*RL Count, 16 */
+ td_info3 |= (rl << 25);
+ qha->td_info3 = td_info3;
+
+ pehci_print("%s: third word 0x%08x, tdinfo 0x%08x\n",
+ __FUNCTION__, qha->td_info3, td_info3);
+
+
+ /**************************fourt word*************************************/
+
+ if (usb_pipecontrol(urb->pipe)) {
+ datatoggle = qtd->hw_token >> 31;
+ } else {
+ /*take the data toggle from the previous completed transfer
+ or zero in case of fresh */
+ datatoggle = toggle;
+ }
+
+ td_info4 = QHA_ACTIVE;
+ /*dt */
+ td_info4 |= datatoggle << 25; /*QHA_DATA_TOGGLE; */
+ /*3 retry count for setup else forever */
+ if (PTD_PID(qha->td_info2) == SETUP_PID) {
+ td_info4 |= (3 << 23);
+ } else {
+ td_info4 |= (0 << 23);
+ }
+
+ /*nak count */
+ td_info4 |= (nk << 19);
+
+ td_info4 |= (qh->ping << 26);
+ qha->td_info4 = td_info4;
+#ifdef PTD_DUMP_SCHEDULE
+ printk("SCHEDULE PTD DUMPE\n") ;
+ printk("SDW0: 0x%08x\n",qha->td_info1);
+ printk("SDW1: 0x%08x\n",qha->td_info2);
+ printk("SDW2: 0x%08x\n",qha->td_info3);
+ printk("SDW3: 0x%08x\n",qha->td_info4);
+#endif
+ pehci_print("%s: fourt word 0x%08x\n", __FUNCTION__, qha->td_info4);
+ pehci_entry("-- %s: Exit, qha %p\n", __FUNCTION__, qha);
+ return qha;
+
+}
diff --git a/drivers/usb/host/isp1763.h b/drivers/usb/host/isp1763.h
new file mode 100644
index 00000000000..ae4a9908905
--- /dev/null
+++ b/drivers/usb/host/isp1763.h
@@ -0,0 +1,224 @@
+/*
+* Copyright (C) ST-Ericsson AP Pte Ltd 2010
+*
+* ISP1763 Linux OTG Controller driver : hal
+*
+* 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* This is a hardware abstraction layer header file.
+*
+* Author : wired support <wired.support@stericsson.com>
+*
+*/
+
+#ifndef ISP1763_H
+#define ISP1763_H
+
+
+
+/* For debugging option: ------------------- */
+#define PTD_DUMP_SCHEDULE
+#undef PTD_DUMP_SCHEDULE
+
+#define PTD_DUMP_COMPLETE
+#undef PTD_DUMP_COMPLETE
+/* ------------------------------------*/
+#define CONFIG_ISO_SUPPORT
+
+#ifdef CONFIG_ISO_SUPPORT
+
+#define ISO_DBG_ENTRY 1
+#define ISO_DBG_EXIT 1
+#define ISO_DBG_ADDR 1
+#define ISO_DBG_DATA 1
+#define ISO_DBG_ERR 1
+#define ISO_DBG_INFO 1
+
+#if 0 /* Set to 1 to enable isochronous debugging */
+#define iso_dbg(category, format, arg...) \
+do \
+{ \
+ if(category) \
+ { \
+ printk(format, ## arg); \
+ } \
+} while(0)
+#else
+#define iso_dbg(category, format, arg...) while(0)
+#endif
+
+#endif /* CONFIG_ISO_SUPPORT */
+
+/*Debug For Entry/Exit of the functions */
+//#define HCD_DEBUG_LEVEL1
+#ifdef HCD_DEBUG_LEVEL1
+#define pehci_entry(format, args... ) printk(format, ##args)
+#else
+#define pehci_entry(format, args...) do { } while(0)
+#endif
+
+/*Debug for Port Info and Errors */
+//#define HCD_DEBUG_LEVEL2
+#ifdef HCD_DEBUG_LEVEL2
+#define pehci_print(format, args... ) printk(format, ##args)
+#else
+#define pehci_print(format, args...) do { } while(0)
+#endif
+
+/*Debug For the Port changes and Enumeration */
+//#define HCD_DEBUG_LEVEL3
+#ifdef HCD_DEBUG_LEVEL3
+#define pehci_info(format,arg...) printk(format, ##arg)
+#else
+#define pehci_info(format,arg...) do {} while (0)
+#endif
+
+/*Debug For Transfer flow */
+//#define HCD_DEBUG_LEVEL4
+#ifdef HCD_DEBUG_LEVEL4
+#define pehci_check(format,args...) printk(format, ##args)
+#else
+#define pehci_check(format,args...)
+#endif
+/*******************END HOST CONTROLLER**********************************/
+
+
+
+/*******************START DEVICE CONTROLLER******************************/
+
+/* For MTP support */
+#undef MTP_ENABLE /* Enable to add MTP support; But requires MTP class driver to be present to work */
+/*For CHAPTER8 TEST */
+#undef CHAPTER8_TEST /* Enable to Pass Chapter 8 Test */
+
+/* Debug Entery/Exit of Function as well as some other Info */
+//#define DEV_DEBUG_LEVEL2
+#ifdef DEV_DEBUG_LEVEL2
+#define dev_print(format,arg...) printk(format, ##arg)
+#else
+#define dev_print(format,arg...) do {} while (0)
+#endif
+
+/*Debug for Interrupt , Registers , device Enable/Disable and some other info */
+//#define DEV_DEBUG_LEVEL3
+//#ifdef DEV_DEBUG_LEVEL3
+//#define dev_info(format,arg...) printk(format, ##arg)
+//#else
+//#define dev_info(format,arg...) do {} while (0)
+//#endif
+
+/*Debug for Tranffer flow , Enumeration and Packet info */
+//#define DEV_DEBUG_LEVEL4
+#ifdef DEV_DEBUG_LEVEL4
+#define dev_check(format,args...) printk(format, ##args)
+#else
+#define dev_check(format,args...) do{}while(0)
+#endif
+/*******************END DEVICE CONTROLLER********************************/
+
+
+/*******************START MSCD*******************************************/
+/*Debug Entery/Exit of Function as well as some other Information*/
+//#define MSCD_DEBUG_LEVEL2
+#ifdef MSCD_DEBUG_LEVEL2
+#define mscd_print(format,arg...) printk(format, ##arg)
+#else
+#define mscd_print(format,arg...) do {} while (0)
+#endif
+
+/*Debug for Info */
+//#define MSCD_DEBUG_LEVEL3
+#ifdef MSCD_DEBUG_LEVEL3
+#define mscd_info(format,arg...) printk(format, ##arg)
+#else
+#define mscd_info(format,arg...) do {} while (0)
+#endif
+/*******************END MSCD*********************************************/
+
+
+/*******************START OTG CONTROLLER*********************************/
+#define OTG /*undef for Device only and Host only */
+#define ALL_FSM_FLAGS
+/*Debug for Entry/Exit and Info */
+/* #define OTG_DEBUG_LEVEL1 */
+#ifdef OTG_DEBUG_LEVEL1
+#define otg_entry(format, args... ) printk(format, ##args)
+#else
+#define otg_entry(format, args...) do { } while(0)
+#endif
+
+/*Debug for State Machine Flow */
+/* #define OTG_DEBUG_LEVEL2 */
+#ifdef OTG_DEBUG_LEVEL2
+#define otg_print(format,arg...) printk(format, ##arg)
+#else
+#define otg_print(format,arg...) do {} while (0)
+#endif
+/*Debug for Info */
+/* #define OTG_DEBUG_LEVEL3 */
+#ifdef OTG_DEBUG_LEVEL3
+#define otg_info(format,arg...) printk(format, ##arg)
+#else
+#define otg_info(format,arg...) do {} while (0)
+#endif
+
+/* #define OTG_DEBUG_LEVEL4 */
+#ifdef OTG_DEBUG_LEVEL4
+#define otg_printB(format,arg...) printk(format, ##arg)
+#else
+#define otg_printB(format,arg...) do {} while (0)
+#endif
+/*******************END OTG CONTROLLER***********************************/
+
+
+
+/*******************START FOR HAL ***************************************/
+/*Debug For Entry and Exit of the functions */
+//#define HAL_DEBUG_LEVEL1
+#ifdef HAL_DEBUG_LEVEL1
+#define hal_entry(format, args... ) printk(format, ##args)
+#else
+#define hal_entry(format, args...) do { } while(0)
+#endif
+
+/*Debug For Interrupt information */
+//#define HAL_DEBUG_LEVEL2
+#ifdef HAL_DEBUG_LEVEL2
+#define hal_int(format, args... ) printk(format, ##args)
+#else
+#define hal_int(format, args...) do { } while(0)
+#endif
+
+/*Debug For HAL Initialisation and Mem Initialisation */
+//#define HAL_DEBUG_LEVEL3
+#ifdef HAL_DEBUG_LEVEL3
+#define hal_init(format, args... ) printk(format, ##args)
+#else
+#define hal_init(format, args...) do { } while(0)
+#endif
+/*******************END FOR HAL*******************************************/
+
+
+
+/*******************START FOR ALL CONTROLLERS*****************************/
+#undef CONFIG_USB_OTG /*undef for Device only and Host only */
+#define ISP1763_DEVICE
+
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+/*******************END FOR ALL CONTROLLERS*******************************/
+#endif