summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKalle Vahlman <kalle.vahlman@movial.com>2012-02-17 09:37:17 +0200
committerKalle Vahlman <kalle.vahlman@movial.com>2012-02-17 10:46:21 +0200
commit9259b71822e2c11d917c11924bd12b442d31e94c (patch)
treef6dc30f7ab427b3daee1f3ae87b4f986308b9679
parentcb0e1ea44ae3a166357265edaaee273a91331a1e (diff)
usb/host: Add ISP1763 host controller support
This is a driver for the ISP1763 USB host controller from ST-Ericsson, modified by Calao and imported to the kernel tree by Movial. Only hardware tested is the AVI daughterboard for Snowball from Calao, although the driver includes support for PCI evaluation version as well. Note that the driver depends on changes to the kernel USB interfaces from another patch, and needs a big hammer to iron out the warts in it.
-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