diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/Makefile linux-2.4.26/drivers/Makefile
--- linux-2.4.26.org/drivers/Makefile	2003-11-29 03:26:19.000000000 +0900
+++ linux-2.4.26/drivers/Makefile	2004-06-24 19:45:44.000000000 +0900
@@ -8,7 +8,7 @@
 
 mod-subdirs :=	dio hil mtd sbus video macintosh usb input telephony ide \
 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
-		fc4 net/hamradio i2c acpi bluetooth usb/gadget
+		fc4 net/hamradio i2c acpi bluetooth usb/gadget mmc
 
 subdir-y :=	parport char block net sound misc media cdrom hotplug
 subdir-m :=	$(subdir-y)
@@ -48,5 +48,6 @@
 subdir-$(CONFIG_ACPI_BOOT)	+= acpi
 
 subdir-$(CONFIG_BLUEZ)		+= bluetooth
+subdir-$(CONFIG_MMC)		+= mmc
 
 include $(TOPDIR)/Rules.make
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/char/Config.in linux-2.4.26/drivers/char/Config.in
--- linux-2.4.26.org/drivers/char/Config.in	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/char/Config.in	2004-03-22 10:56:06.000000000 +0900
@@ -12,7 +12,7 @@
    fi
 fi
 tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
-if [ "$CONFIG_SERIAL" = "y" ]; then
+if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_M32R_SERIAL" = "y" ]; then
    bool '  Support for console on serial port' CONFIG_SERIAL_CONSOLE
    if [ "$CONFIG_GSC_LASI" = "y" ]; then
       bool '   serial port on GSC support' CONFIG_SERIAL_GSC
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/char/serial.c linux-2.4.26/drivers/char/serial.c
--- linux-2.4.26.org/drivers/char/serial.c	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/char/serial.c	2004-03-22 10:56:06.000000000 +0900
@@ -297,7 +297,11 @@
 	{ "unknown", 1, 0 }, 
 	{ "8250", 1, 0 }, 
 	{ "16450", 1, 0 }, 
+#ifndef CONFIG_PLAT_USRV
 	{ "16550", 1, 0 }, 
+#else	/* CONFIG_PLAT_USRV */
+	{ "16552D", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+#endif	/* CONFIG_PLAT_USRV */
 	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
 	{ "cirrus", 1, 0 }, 	/* usurped by cyclades.c */
 	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, 
@@ -3742,6 +3746,7 @@
 			state->type = PORT_16550A;
 			break;
 	}
+#ifndef CONFIG_PLAT_USRV
 	if (state->type == PORT_16550A) {
 		/* Check for Startech UART's */
 		serial_outp(info, UART_LCR, UART_LCR_DLAB);
@@ -3760,6 +3765,9 @@
 				autoconfig_startech_uarts(info, state, flags);
 		}
 	}
+#else	/* CONFIG_PLAT_USRV */
+	state->type = PORT_16550;
+#endif	/* CONFIG_PLAT_USRV */
 	if (state->type == PORT_16550A) {
 		/* Check for TI 16750 */
 		serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/char/tty_io.c linux-2.4.26/drivers/char/tty_io.c
--- linux-2.4.26.org/drivers/char/tty_io.c	2004-04-14 22:05:29.000000000 +0900
+++ linux-2.4.26/drivers/char/tty_io.c	2004-04-28 19:34:38.000000000 +0900
@@ -2260,6 +2260,13 @@
  	mac_scc_console_init();
 #elif defined(CONFIG_PARISC)
 	pdc_console_init();
+#elif defined(CONFIG_M32R_USE_DBG_CONSOLE)
+	dbg_console_init();
+#if defined(CONFIG_PLAT_USRV) && !defined(CONFIG_SERIAL_MODULE)
+	serial_console_init();
+#endif
+#elif defined(CONFIG_M32R_PLD_SERIAL)
+	psio_console_init();
 #elif defined(CONFIG_SERIAL)
 	serial_console_init();
 #endif /* CONFIG_8xx */
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/input/keybdev.c linux-2.4.26/drivers/input/keybdev.c
--- linux-2.4.26.org/drivers/input/keybdev.c	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/input/keybdev.c	2004-03-22 10:56:13.000000000 +0900
@@ -40,7 +40,7 @@
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
     defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
     defined(CONFIG_PPC) || defined(__mc68000__) || defined(__hppa__) || \
-    defined(__arm__)
+    defined(__arm__) || defined(__m32r__)
 
 static int x86_sysrq_alt = 0;
 #ifdef CONFIG_SPARC64
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/Config.in linux-2.4.26/drivers/mmc/Config.in
--- linux-2.4.26.org/drivers/mmc/Config.in	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/Config.in	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,15 @@
+#
+# MMC subsystem configuration
+#
+mainmenu_option next_comment
+comment 'MMC/SD Card support'
+
+tristate 'MMC support' CONFIG_MMC
+if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then
+  bool '  MMC debugging' CONFIG_MMC_DEBUG
+  if [ "$CONFIG_MMC_DEBUG" = "y" ]; then
+    int '  MMC debugging verbosity (0=quiet, 3=noisy)' CONFIG_MMC_DEBUG_VERBOSE 0
+  fi
+fi
+
+endmenu
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/Makefile linux-2.4.26/drivers/mmc/Makefile
--- linux-2.4.26.org/drivers/mmc/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/Makefile	2004-06-24 20:08:12.000000000 +0900
@@ -0,0 +1,21 @@
+#
+# Makefile for the kernel mmc device drivers.
+#
+
+O_TARGET := mmc.o
+
+export-objs := mmc_core.o
+
+obj-$(CONFIG_MMC) += mmc_base.o
+
+# Declare multi-part drivers.
+list-multi := mmc_base.o
+# mmc_base-objs := mmc_protocol.o mmc_core.o mmc_media.o
+mmc_base-objs := mmc_protocol.o mmc_core.o mmc_media.o m32r_mmc.o
+
+include $(TOPDIR)/Rules.make
+
+# Link rules for multi-part drivers.
+
+mmc_base.o: $(mmc_base-objs)
+	$(LD) -r -o $@ $(mmc_base-objs)
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/h3600_asic_mmc.c linux-2.4.26/drivers/mmc/h3600_asic_mmc.c
--- linux-2.4.26.org/drivers/mmc/h3600_asic_mmc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/h3600_asic_mmc.c	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,861 @@
+/*
+ * Low-level MMC functions for the iPAQ H3800
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          6 May 2002
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>        /* H3800-specific interrupts */
+#include <asm/unaligned.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch-sa1100/h3600_asic.h>
+
+#include <linux/mmc/mmc_ll.h>
+
+#include "h3600_asic_mmc.h"
+#include "h3600_asic_core.h"
+
+struct response_info {
+	int length;
+	u16 cdc_flags;
+};
+
+static struct response_info rinfo[] = {
+	{ 0,  MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE                     }, /* R0 */
+	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1                              }, /* R1  */
+	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1 | MMC_CMD_DATA_CONT_BUSY_BIT }, /* R1b */
+	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CID */
+	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CSD */
* R3  */
+	{ 6,  0                                                        }, /* R4  */
+	{ 6,  0                                                        }, /* R5  */
+};
+
+enum h3800_request_type {
+	RT_NO_RESPONSE,
+	RT_RESPONSE_ONLY,
+	RT_READ,
+	RT_WRITE
+};
+
+struct h3800_mmc_data {
+	struct timer_list        sd_detect_timer;
+	struct timer_list        reset_timer;
+	struct timer_list        irq_timer;    /* Panic timer - make sure we get a response */
+	u32                      clock;        /* Current clock frequency */
+	struct mmc_request      *request;
+	enum h3800_request_type  type;
+};
+
+static struct h3800_mmc_data g_h3800_data;
+
+#define MMC_IRQ_TIMEOUT  (3 * HZ)
+#define H3800_MASTER_CLOCK 33868800
+
+static __inline__ void mmc_delay( void ) { udelay(1); }
+
+/**************************************************************************
+ * Utility routines for debuging
+ **************************************************************************/
+
+struct cmd_to_name {
+	int   id;
+	char *name;
+};
+
+static struct cmd_to_name cmd_names[] = {
+	{ MMC_CIM_RESET, "CIM_RESET" },
+	{ MMC_GO_IDLE_STATE, "GO_IDLE_STATE" },
+	{ MMC_SEND_OP_COND, "SEND_OP_COND" },
+	{ MMC_ALL_SEND_CID, "ALL_SEND_CID" },
+	{ MMC_SET_RELATIVE_ADDR, "SET_RELATIVE_ADDR" },
+	{ MMC_SET_DSR, "SET_DSR" },
+	{ MMC_SELECT_CARD, "SELECT_CARD" },
+	{ MMC_SEND_CSD, "SEND_CSD" },
+	{ MMC_SEND_CID, "SEND_CID" },
+	{ MMC_READ_DAT_UNTIL_STOP, "READ_DAT_UNTIL_STOP" },
+	{ MMC_STOP_TRANSMISSION, "STOP_TRANSMISSION" },
+	{ MMC_SEND_STATUS	, "SEND_STATUS	" },
+	{ MMC_GO_INACTIVE_STATE, "GO_INACTIVE_STATE" },
+	{ MMC_SET_BLOCKLEN, "SET_BLOCKLEN" },
+	{ MMC_READ_SINGLE_BLOCK, "READ_SINGLE_BLOCK" },
+	{ MMC_READ_MULTIPLE_BLOCK, "READ_MULTIPLE_BLOCK" },
+	{ MMC_WRITE_DAT_UNTIL_STOP, "WRITE_DAT_UNTIL_STOP" },
+	{ MMC_SET_BLOCK_COUNT, "SET_BLOCK_COUNT" },
+	{ MMC_WRITE_BLOCK, "WRITE_BLOCK" },
+	{ MMC_WRITE_MULTIPLE_BLOCK, "WRITE_MULTIPLE_BLOCK" },
+	{ MMC_PROGRAM_CID, "PROGRAM_CID" },
+	{ MMC_PROGRAM_CSD, "PROGRAM_CSD" },
+	{ MMC_SET_WRITE_PROT, "SET_WRITE_PROT" },
+	{ MMC_CLR_WRITE_PROT, "CLR_WRITE_PROT" },
+	{ MMC_SEND_WRITE_PROT, "SEND_WRITE_PROT" },
+	{ MMC_ERASE_GROUP_START, "ERASE_GROUP_START" },
+	{ MMC_ERASE_GROUP_END, "ERASE_GROUP_END" },
+	{ MMC_ERASE, "ERASE" },
+	{ MMC_FAST_IO, "FAST_IO" },
+	{ MMC_GO_IRQ_STATE, "GO_IRQ_STATE" },
+	{ MMC_LOCK_UNLOCK, "LOCK_UNLOCK" },
+	{ MMC_APP_CMD, "APP_CMD" },
+	{ MMC_GEN_CMD, "GEN_CMD" },
+};
+
+static char * get_cmd_name( int cmd )
+{
+	int i;
+	int len = sizeof(cmd_names) / sizeof(struct cmd_to_name);
+	for ( i = 0 ; i < len ; i++ )
+		if ( cmd == cmd_names[i].id )
+			return cmd_names[i].name;
+
+	return "UNKNOWN";
+}
+
+struct status_bit_to_name {
+	u16   mask;
+	int   shift;
+	char *name;
+};
+
+struct status_bit_to_name status_bit_names[] = {
+	{ MMC_STATUS_READ_TIMEOUT, -1, "READ_TIMEOUT" },
+	{ MMC_STATUS_RESPONSE_TIMEOUT, -1, "RESPONSE_TIMEOUT" },
+	{ MMC_STATUS_CRC_WRITE_ERROR, -1, "CRC_WRITE_ERROR" },
+	{ MMC_STATUS_CRC_READ_ERROR, -1, "CRC_READ_ERROR" },
+	{ MMC_STATUS_SPI_READ_ERROR, -1, "SPI_READ_ERROR" },
+	{ MMC_STATUS_CRC_RESPONSE_ERROR, -1, "CRC_RESPONSE_ERROR" },
+	{ MMC_STATUS_FIFO_EMPTY, -1, "FIFO_EMPTY" },
+	{ MMC_STATUS_FIFO_FULL, -1, "FIFO_FULL" },
+	{ MMC_STATUS_CLOCK_ENABLE, -1, "CLOCK_ENABLE" },
+	{ MMC_STATUS_WR_CRC_ERROR_CODE, 9, "WR_CRC_ERROR_CODE" },
+	{ MMC_STATUS_DATA_TRANSFER_DONE, -1, "DATA_TRANSFER_DONE" },
+	{ MMC_STATUS_END_PROGRAM, -1, "END_PROGRAM" },
+	{ MMC_STATUS_END_COMMAND_RESPONSE, -1, "END_COMMAND_RESPONSE" }
+};
+
+static void decode_status( u16 status )
+{
+	int i;
+	int len = sizeof(status_bit_names)/sizeof(struct status_bit_to_name);
+	struct status_bit_to_name *b = status_bit_names;
+	for ( i = 0 ; i < len ; i++, b++ ) {
+		if ( status & b->mask ) {
+			if ( b->shift >= 0 )
+				printk("%s[%d] ", b->name, ((status & b->mask) >> b->shift));
+			else
+				printk("%s ", b->name);
+		}
+	}
+}
+
+static void printk_request( struct mmc_request *request, char *header )
+{
+	printk("%sindex  %d\n", header, request->index );
+	printk("%scmd    %d\n", header, request->cmd );
+	printk("%sarg    0x%08x\n", header, request->arg );
+	printk("%srtype  %d\n", header, request->rtype );
+	printk("%snob    %d\n", header, request->nob );
+	printk("%sbl_len %d\n", header, request->block_len );
+	printk("%sbuffer %p\n", header, request->buffer );
+	printk("%sresult %d\n", header, request->result);
+}
+/*
+static void printk_asic_state( char *header )
+{
+	u16 status = H3800_ASIC1_MMC_Status;
+	printk("%sStartStopClock  0x%02x\n", header, H3800_ASIC1_MMC_StartStopClock );
+	printk("%sStatus          0x%04x  ", header, status );
+	decode_status(status);
+	printk("\n%sClockRate       0x%02x\n", header, H3800_ASIC1_MMC_ClockRate );
+	printk("%sRevision        0x%08x\n", header, H3800_ASIC1_MMC_Revision );
+	printk("%sCmdDataCont     0x%02x\n", header, H3800_ASIC1_MMC_CmdDataCont );
+	printk("%sResponseTimeout 0x%02x\n", header, H3800_ASIC1_MMC_ResponseTimeout );
+	printk("%sReadTimeout     0x%04x\n", header, H3800_ASIC1_MMC_ReadTimeout );
+	printk("%sBlock Length    0x%04x\n", header, H3800_ASIC1_MMC_BlockLength );
+	printk("%sNum of Blocks   0x%04x\n", header, H3800_ASIC1_MMC_NumOfBlocks );
+	printk("%sInterruptMask   0x%02x\n", header, H3800_ASIC1_MMC_InterruptMask );
+	printk("%sCommandNumber   0x%02x\n", header, H3800_ASIC1_MMC_CommandNumber );
+	printk("%sArgument H      0x%04x\n", header, H3800_ASIC1_MMC_ArgumentH );
+	printk("%sArgument L      0x%04x\n", header, H3800_ASIC1_MMC_ArgumentL );
+	printk("%sBufferPartFull  0x%02x\n", header, H3800_ASIC1_MMC_BufferPartFull );
+	printk("%sStatus          0x%04x\n", header, H3800_ASIC1_MMC_Status );
+}
+*/
+
+/**************************************************************************
+ *   Clock routines
+ *
+ * We have to poll the status register until we're sure that the clock has stopped.
+ * This may be called in interrupt context, so we can't go to sleep!
+ **************************************************************************/
+
+static int mmc_h3800_stop_clock( void )
+{
+	u16 status;
+
+	H3800_ASIC1_MMC_StartStopClock = MMC_STOP_CLOCK;
+	mmc_delay();
+	
+	status = H3800_ASIC1_MMC_Status;
+	if ( !(status & ~(MMC_STATUS_CLOCK_ENABLE | MMC_STATUS_FIFO_EMPTY | MMC_STATUS_FIFO_FULL)) )
+		return MMC_NO_ERROR;
+
+	DEBUG(0,": Warning!  Clock not stopping correctly (%04x)\n", status);
+	H3800_ASIC1_MMC_StartStopClock = MMC_START_CLOCK;
+	mmc_delay();
+
+	H3800_ASIC1_MMC_StartStopClock = MMC_STOP_CLOCK;
+	mmc_delay();
+	
+	status = H3800_ASIC1_MMC_Status;
+	if ( !(status & ~(MMC_STATUS_CLOCK_ENABLE | MMC_STATUS_FIFO_EMPTY | MMC_STATUS_FIFO_FULL)) )
+		return MMC_NO_ERROR;
+
+	DEBUG(0,": Error!  Clock not stopping correctly (%04x)\n", status);
+
+	return MMC_ERROR_DRIVER_FAILURE;
+}
+
+static void mmc_h3800_start_clock( void )
+{
+	H3800_ASIC1_MMC_StartStopClock = MMC_START_CLOCK;
+	mmc_delay();
+}
+
+static int mmc_h3800_set_clock( u32 rate )
+{
+	int retval;
+
+	u32 master = H3800_MASTER_CLOCK;   /* Default master clock */
+	u8  divisor = 0;         /* No divisor */
+	while ( master > rate ) {
+		divisor++;
+		master /= 2;
+	}
+	if ( rate > 6 ) rate = 6;
+	DEBUG(2,": setting divisor to %d (request=%d result=%d)\n", 
+	      divisor, rate, master );
+
+	retval = mmc_h3800_stop_clock();
+	if ( retval )
+		return retval;
+
+	H3800_ASIC1_MMC_ClockRate = divisor;
+	mmc_delay();
+
+	H3800_ASIC1_MMC_ResponseTimeout = 0x0040;
+	mmc_delay();
+	
+	H3800_ASIC1_MMC_ReadTimeout = 0xffff;
+	mmc_delay();
+
+	mmc_h3800_start_clock();
+	g_h3800_data.clock = master;
+	
+	return MMC_NO_ERROR;
+}
+
+static int mmc_h3800_reset_asic( u32 clock_rate )
+{
+	int retval;
+	u16 version = H3800_ASIC1_MMC_Revision;
+
+	DEBUG(2," version=%04x\n", version);
+	mmc_delay();
+	H3800_ASIC1_MMC_Revision = version;
+	mmc_delay();
+
+	udelay(5);
+
+	retval = mmc_h3800_set_clock( clock_rate );
+	mmc_h3800_start_clock();
+	return retval;
+}
+
+/* 
+   The reset function clears _everything_ in the ASIC,
+   so it needs be completely reset
+*/
+
+static void mmc_h3800_reset_timeout( unsigned long nr )
+{
+//	struct h3800_mmc_data *sd = (struct h3800_mmc_data *) nr;
+
+	/* Send 80 clocks to get things started */
+	H3800_ASIC1_MMC_CmdDataCont = MMC_CMD_DATA_CONT_BC_MODE;
+	mmc_delay();
+	H3800_ASIC1_MMC_InterruptMask = MMC_INT_MASK_ALL & ~MMC_INT_MASK_END_COMMAND_RESPONSE;
+	mmc_delay();
+
+	START_DEBUG(2) { 
+		u16 status = H3800_ASIC1_MMC_Status;
+		printk("%s: enabling irq mask=%04x status=0x%04x (", __FUNCTION__, 
+		       H3800_ASIC1_MMC_InterruptMask, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_DEBUG;
+
+	mod_timer( &g_h3800_data.irq_timer, jiffies + MMC_IRQ_TIMEOUT); 
+	enable_irq( IRQ_GPIO_H3800_MMC_INT );
+}
+
+static int mmc_h3800_reset( struct h3800_mmc_data *sd )
+{
+	int retval = mmc_h3800_reset_asic( MMC_CLOCK_SLOW );
+	g_h3800_data.type = RT_NO_RESPONSE;
+	mod_timer( &sd->reset_timer, jiffies + (100 * HZ) / 1000 );
+	g_h3600_asic_statistics.mmc_reset++;
+
+	return retval;
+}
+
+
+static void mmc_h3800_set_command( u16 cmd, u32 arg )
+{
+	DEBUG(2,": cmd=%d arg=0x%08x\n", cmd, arg);
+
+	H3800_ASIC1_MMC_ArgumentH = arg >> 16;
+	mmc_delay();
+
+	H3800_ASIC1_MMC_ArgumentL = arg & 0xffff;
+	mmc_delay();
+
+	H3800_ASIC1_MMC_CommandNumber = cmd;
+	mmc_delay();
+}
+
+static void mmc_h3800_set_transfer( u16 block_len, u16 nob )
+{
+	DEBUG(2,": block_len=%d nob=%d\n", block_len, nob);
+
+	H3800_ASIC1_MMC_BlockLength = block_len;
+	mmc_delay();
+
+	H3800_ASIC1_MMC_NumOfBlocks = nob;
+	mmc_delay();
+}
+
+static void mmc_h3800_transmit_data( struct mmc_request *request )
+{
+	u8 *buf = request->buffer;
+	u16 data;
+	int i;
+
+	DEBUG(2,": nob=%d block_len=%d\n", request->nob, request->block_len);
+	if ( request->nob <= 0 ) {
+		DEBUG(1,": *** nob already at 0 ***\n");
+		return;
+	}
+
+	for ( i = 0 ; i < request->block_len ; i+=2, buf+=2 ) {
+		data = *(buf+1) | (((u16) *buf) << 8);
+		H3800_ASIC1_MMC_DataBuffer = data;
+		mmc_delay();
+	}
+
+	START_DEBUG(2) { 
+		u16 status = H3800_ASIC1_MMC_Status;
+		printk("%s: irq_mask=%04x status=0x%04x (", __FUNCTION__, 
+		       H3800_ASIC1_MMC_InterruptMask, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_DEBUG;
+
+	START_DEBUG(3) {
+		u8 *b = request->buffer;
+		for ( i = 0 ; i < request->block_len ; i++ ) {
+			printk(" %02x", *b++);
+			if ( ((i + 1) % 16) == 0 )
+				printk("\n");
+		}
+	} END_DEBUG;
+
+	/* Updated the request buffer to reflect the current state */
+	request->buffer = (u8 *) buf;
+	request->nob--;
+	g_h3600_asic_statistics.mmc_written++;
+}
+
+static void mmc_h3800_receive_data( struct mmc_request *request )
+{
+	u8 *buf = request->buffer;
+	u16 data;
+	int i;
+
+	DEBUG(2,": nob=%d block_len=%d buf=%p\n", request->nob, request->block_len, buf);
+	if ( request->nob <= 0 ) {
+		DEBUG(1,": *** nob already at 0 ***\n");
+		return;
+	}
+
+	for ( i = 0 ; i < request->block_len ; i+=2 ) {
+		data = H3800_ASIC1_MMC_DataBuffer;
+		mmc_delay();
+		*buf++ = data >> 8;
+		*buf++ = data & 0xff;
+	}
+
+	START_DEBUG(3) {
+		u8 *b = request->buffer;
+		for ( i = 0 ; i < request->block_len ; i++ ) {
+			printk(" %02x", *b++);
+			if ( ((i + 1) % 16) == 0 )
+				printk("\n");
+		}
+	} END_DEBUG;
+
+	/* Updated the request buffer to reflect the current state */
+	request->buffer = (u8 *) buf;
+	request->nob--;
+	g_h3600_asic_statistics.mmc_read++;
+}
+
+#define STATBUG(_x) \
+	{ u16 status = H3800_ASIC1_MMC_Status; \
+          if ( status & ~(MMC_STATUS_FIFO_EMPTY | MMC_STATUS_CLOCK_ENABLE)) \
+		printk("..." _x " status=0x%04x\n", status); }
+
+static int mmc_h3800_exec_command( struct mmc_request *request )
+{
+	int retval;
+	int cdc = 0;
+	int irq = 0;
+
+	DEBUG(2,": request=%p status=%04x\n", request, H3800_ASIC1_MMC_Status );
+
+	/* Start the actual transfer */
+	retval = mmc_h3800_stop_clock();
+	if ( retval )
+		return retval;
+
+	STATBUG("stop_clock");
+
+	mmc_h3800_set_command( request->cmd, request->arg );
+
+	STATBUG("set_command");
+
+	switch (request->cmd) {
+	case MMC_READ_SINGLE_BLOCK:
+	case MMC_READ_MULTIPLE_BLOCK:
+		mmc_h3800_set_transfer( request->block_len, request->nob );
+		cdc = MMC_CMD_DATA_CONT_READ | MMC_CMD_DATA_CONT_DATA_ENABLE;
+		irq = MMC_INT_MASK_ALL;
+		g_h3800_data.type = RT_READ;
+		break;
+	case MMC_WRITE_BLOCK:
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		mmc_h3800_set_transfer( request->block_len, request->nob );
+		cdc = MMC_CMD_DATA_CONT_WRITE | MMC_CMD_DATA_CONT_DATA_ENABLE;
+		irq = MMC_INT_MASK_ALL;
+		g_h3800_data.type = RT_WRITE;
+		break;
+	default:
+		irq = MMC_INT_MASK_END_COMMAND_RESPONSE;
+		g_h3800_data.type = RT_RESPONSE_ONLY;
+		break;
+	}
+	
+	cdc |= rinfo[request->rtype].cdc_flags;
+
+	H3800_ASIC1_MMC_CmdDataCont = cdc;
+	mmc_delay();
+
+	STATBUG("cmd_data_cont");
+
+	H3800_ASIC1_MMC_InterruptMask = MMC_INT_MASK_ALL & ~irq;
+	mmc_delay();
+
+	STATBUG("irq_mask");
+
+	mmc_h3800_start_clock();
+
+	START_DEBUG(2) { 
+		u16 status = H3800_ASIC1_MMC_Status;
+		printk("%s: enabling irq mask=%04x status=0x%04x (", __FUNCTION__, 
+		       H3800_ASIC1_MMC_InterruptMask, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_DEBUG;
+
+	mod_timer( &g_h3800_data.irq_timer, jiffies + MMC_IRQ_TIMEOUT); 
+	enable_irq( IRQ_GPIO_H3800_MMC_INT );
+	g_h3600_asic_statistics.mmc_command++;
+	return MMC_NO_ERROR;
+}
+
+static void mmc_h3800_send_command( struct mmc_request *request )
+{
+	int retval;
+
+	DEBUG(1,": request=%p cmd=%d (%s) arg=%08x status=%04x\n", request, 
+	      request->cmd, get_cmd_name(request->cmd), request->arg,
+	      H3800_ASIC1_MMC_Status);
+
+	/* TODO: Grab a lock???? */
+	g_h3800_data.request = request;
+	request->result = MMC_NO_RESPONSE;   /* Flag to indicate don't have a result yet */
+
+	if ( request->cmd == MMC_CIM_RESET ) {
+		retval = mmc_h3800_reset( &g_h3800_data );
+	}
+	else {
+		retval = mmc_h3800_exec_command( request );
+		if ( retval ) {
+			g_h3600_asic_statistics.mmc_error++;
+			DEBUG(0,": ASIC not responding!  Trying to reset\n");
+			mmc_h3800_start_clock();
+
+			retval = mmc_h3800_reset_asic( g_h3800_data.clock );
+			if ( retval ) {
+				DEBUG(0,": ASIC doesn't reset!  Panic now!\n");
+			}
+			else {
+				retval = mmc_h3800_exec_command( request );
+				if ( retval ) {
+					DEBUG(0,": ASIC unable to exec!\n");
+				}
+			}
+		}
+	}
+
+	if ( retval ) {
+		request->result = retval;
+		mmc_cmd_complete( request );
+	}
+}
+
+/**************************************************************************/
+/* TODO: Need to mask interrupts?? */
+
+static void mmc_h3800_get_response( struct mmc_request *request )
+{
+	int i;
+	int len = rinfo[request->rtype].length;
+	u8 *buf = request->response;
+	
+	request->result = MMC_NO_ERROR;    /* Mark this as having a request result of some kind */
+
+	if ( len <= 0 )
+		return;
+
+	for ( i = 0 ; i < len ; ) {
+		u16 data = H3800_ASIC1_MMC_ResFifo;
+		buf[i++] = data >> 8;
+		buf[i++] = data & 0xff;
+	}
+
+	START_DEBUG(2) {
+		printk("%s:  Raw byte stream: ", __FUNCTION__);
+		for ( i = 0 ; i < len; i++ )
+			printk("%02x ", buf[i]);
+		printk("\n");
+	} END_DEBUG;
+}
+
+static void mmc_h3800_handle_int( struct h3800_mmc_data *sd, u16 status, int timeout )
+{
+	int retval = MMC_NO_ERROR;
+
+	disable_irq( IRQ_GPIO_H3800_MMC_INT );
+
+	if ( status & (MMC_STATUS_READ_TIMEOUT 
+		       | MMC_STATUS_RESPONSE_TIMEOUT )) {
+		retval = MMC_ERROR_TIMEOUT;
+		goto terminate_int;
+	}
+	
+	if ( status & ( MMC_STATUS_CRC_WRITE_ERROR 
+			| MMC_STATUS_CRC_READ_ERROR 
+			| MMC_STATUS_SPI_READ_ERROR 
+			| MMC_STATUS_CRC_RESPONSE_ERROR
+			| MMC_STATUS_WR_CRC_ERROR_CODE )) {
+		retval = MMC_ERROR_CRC;
+		goto terminate_int;
+	}
+
+	if ( status & MMC_STATUS_END_COMMAND_RESPONSE && sd->request->result == MMC_NO_RESPONSE ) 
+		mmc_h3800_get_response( sd->request );
+
+	if ( g_h3800_data.type == RT_READ && 
+	     (status & (MMC_STATUS_FIFO_FULL | MMC_STATUS_DATA_TRANSFER_DONE)) != 0)
+		mmc_h3800_receive_data( sd->request );
+
+	if ( g_h3800_data.type == RT_WRITE && (status & MMC_STATUS_FIFO_EMPTY ) != 0
+	     && sd->request->nob > 0 )
+		mmc_h3800_transmit_data( sd->request );
+
+	switch (g_h3800_data.type) {
+	case RT_NO_RESPONSE:
+		break;
+
+	case RT_RESPONSE_ONLY:
+		if ( sd->request->result < 0 ) {
+			printk(KERN_INFO "%s: illegal interrupt - command hasn't finished\n", __FUNCTION__);
+			retval = MMC_ERROR_TIMEOUT;
+		}
+		break;
+	case RT_READ:
+		if ( sd->request->nob ) {
+			DEBUG(2,": read re-enabling IRQ mask=0x%04x\n", H3800_ASIC1_MMC_InterruptMask);
+			mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); 
+			mmc_h3800_start_clock();
+			enable_irq( IRQ_GPIO_H3800_MMC_INT );
+			return;
+		}
+		break;
+	case RT_WRITE:
+		if ( sd->request->nob || !(status & MMC_STATUS_END_PROGRAM)  ) {
+			DEBUG(2,": write re-enabling IRQ mask=0x%04x\n", H3800_ASIC1_MMC_InterruptMask);
+			mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); 
+			mmc_h3800_start_clock();
+			enable_irq( IRQ_GPIO_H3800_MMC_INT );
+			return;
+		}
+		break;
+	}
+	
+	DEBUG(2,": terminating status=0x%04x\n", H3800_ASIC1_MMC_Status );
+terminate_int:
+	H3800_ASIC1_MMC_InterruptMask = MMC_INT_MASK_ALL & ~MMC_INT_MASK_END_COMMAND_RESPONSE;
+	del_timer_sync( &sd->irq_timer );
+	sd->request->result = retval;
+	mmc_cmd_complete( sd->request );
+}
+
+static void mmc_h3800_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct h3800_mmc_data *sd = (struct h3800_mmc_data *) dev_id;
+	u16 status = H3800_ASIC1_MMC_Status;
+	
+	START_DEBUG(2) { 
+		printk("%s: sd=%p status=0x%04x (", __FUNCTION__, sd, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_DEBUG;
+
+	mmc_h3800_handle_int( sd, status, 0 );
+}
+
+static void mmc_h3800_irq_timeout( unsigned long nr )
+{
+	struct h3800_mmc_data *sd = (struct h3800_mmc_data *) nr;
+	u16 status = H3800_ASIC1_MMC_Status;
+
+	START_DEBUG(0) { 
+		printk("%s: irq_mask=%04x status=0x%04x (", __FUNCTION__, 
+		       H3800_ASIC1_MMC_InterruptMask, status);
+		decode_status(status); 
+		printk(")\nRequest info:\n"); 
+		printk_request( sd->request, "  " );
+	} END_DEBUG;
+
+	g_h3600_asic_statistics.mmc_timeout++;
+	mmc_h3800_handle_int( sd, status, 1 );
+}
+
+
+/**************************************************************************/
+
+static void mmc_h3800_fix_sd_detect( unsigned long nr )
+{
+	/* カード有無の判定*/
+	int sd_card = (H3800_ASIC2_GPIOPIOD & GPIO2_SD_DETECT ? 1 : 0);
+	int sd_con_slot = (H3800_ASIC2_GPIOPIOD & GPIO2_SD_CON_SLT ? 1 : 0);
+
+	DEBUG(2,": card=%d con_slot=%d\n", sd_card, sd_con_slot);
+
+	/* 次の変化の割り込みを立ち上がりエッジにするか立下りエッジにするか設定*/
+	if ( sd_card )
+		H3800_ASIC2_GPIINTESEL &= ~GPIO2_SD_DETECT; /* Falling */
+	else
+		H3800_ASIC2_GPIINTESEL |= GPIO2_SD_DETECT; /* Rising */
+
+	/* 状態変化に合わせて、上位関数insert/ejectを呼び出す*/
+	if ( sd_card != sd_con_slot ) {
+		mmc_insert(0);
+		g_h3600_asic_statistics.mmc_insert++;
+	}
+	else {
+		mmc_eject(0);
+		g_h3600_asic_statistics.mmc_eject++;
+	}
+}
+
+
+/* 挿抜割り込みハンドラ：割り込み発生後0.25秒後に
+   タイマー関数経由で上位モジュールに挿抜を通知 */
+static void mmc_h3800_sd_detect_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct h3800_mmc_data *sd = (struct h3800_mmc_data *) dev_id;
+	mod_timer( &sd->sd_detect_timer, jiffies + (250 * HZ) / 1000 );
+}
+
+static int mmc_h3800_slot_is_empty( int slot )
+{
+	int sd_card = (H3800_ASIC2_GPIOPIOD & GPIO2_SD_DETECT ? 1 : 0);
+	int sd_con_slot = (H3800_ASIC2_GPIOPIOD & GPIO2_SD_CON_SLT ? 1 : 0);
+
+	return sd_card == sd_con_slot;
+}
+
+
+/**************************************************************************/
+
+static unsigned long mmc_shared;
+
+/* mmc slotを使用可能にする?　*/
+static void mmc_h3800_slot_up( void )
+{
+	H3800_ASIC2_GPIINTTYPE |= GPIO2_SD_DETECT;          /* Edge-type interrupt */
+
+/* 挿抜割り込み用レベル指定をする */
+	if ( H3800_ASIC2_GPIOPIOD & GPIO2_SD_DETECT )
+		H3800_ASIC2_GPIINTESEL &= ~GPIO2_SD_DETECT; /* Falling */
+	else
+		H3800_ASIC2_GPIINTESEL |= GPIO2_SD_DETECT;  /* Rising */
+
+	/* Let's turn on everything. In the future, we should 
+	   only do this when we know there is a card (???) */
+
+	H3800_ASIC1_GPIO_OUT     |= GPIO1_SD_PWR_ON;
+	h3600_asic_shared_add( &mmc_shared, ASIC_SHARED_CLOCK_EX2 );
+	H3800_ASIC2_CLOCK_Enable |= ASIC2_CLOCK_SD_3;
+
+/* MMC用各種割り込み許可 */
+	enable_irq( IRQ_H3800_SD_DETECT );
+}
+
+static void mmc_h3800_slot_down( void )
+{
+	disable_irq( IRQ_H3800_SD_DETECT );
+	disable_irq( IRQ_GPIO_H3800_MMC_INT );
+
+	H3800_ASIC2_CLOCK_Enable &= ~ASIC2_CLOCK_SD_MASK;
+	h3600_asic_shared_release( &mmc_shared, ASIC_SHARED_CLOCK_EX2 );
+	H3800_ASIC1_GPIO_OUT     &= ~GPIO1_SD_PWR_ON;
+
+	del_timer_sync(&g_h3800_data.sd_detect_timer);
+	del_timer_sync(&g_h3800_data.reset_timer);
+	del_timer_sync(&g_h3800_data.irq_timer);
+}
+
+/* iPAQ asic ハンドラに登録する関数(APM用?) */
+int h3600_asic_mmc_suspend(void)
+{
+	mmc_h3800_slot_down();
+	return 0;
+}
+
+void h3600_asic_mmc_resume(void)
+{
+	mmc_h3800_slot_up();
+}
+
+static int mmc_h3800_slot_init( void )
+{
+	int retval;
+	DEBUG(1,"\n");
+
+	/* Set up timers */
+	g_h3800_data.sd_detect_timer.function = mmc_h3800_fix_sd_detect;
+	g_h3800_data.sd_detect_timer.data     = (unsigned long) &g_h3800_data;
+	init_timer(&g_h3800_data.sd_detect_timer);
+	
+	g_h3800_data.reset_timer.function = mmc_h3800_reset_timeout;
+	g_h3800_data.reset_timer.data     = (unsigned long) &g_h3800_data;
+	init_timer(&g_h3800_data.reset_timer);
+	
+	g_h3800_data.irq_timer.function = mmc_h3800_irq_timeout;
+	g_h3800_data.irq_timer.data     = (unsigned long) &g_h3800_data;
+	init_timer(&g_h3800_data.irq_timer);
+	
+	/* Basic service interrupt */
+	H3800_ASIC1_MMC_InterruptMask = MMC_INT_MASK_ALL;
+	set_GPIO_IRQ_edge( GPIO_H3800_MMC_INT, GPIO_RISING_EDGE );
+	retval = request_irq( IRQ_GPIO_H3800_MMC_INT, mmc_h3800_int,
+			      SA_INTERRUPT, "mmc_h3800_int", &g_h3800_data );
+	if ( retval ) {
+		printk(KERN_CRIT "%s: unable to grab MMC IRQ\n", __FUNCTION__);
+		return retval;
+	}
+	disable_irq( IRQ_GPIO_H3800_MMC_INT );
+
+	mmc_h3800_slot_up(); /* Fixes the sd_detect interrupt direction */
+
+	/* 割り込みによるカード状態変化検出用ハンドラの登録 */
+	retval = request_irq( IRQ_H3800_SD_DETECT, mmc_h3800_sd_detect_int, 
+			      SA_INTERRUPT, "mmc_h3800_sd_detect", &g_h3800_data );
+
+	if ( retval ) {
+		printk(KERN_CRIT "%s: unable to grab SD_DETECT IRQ\n", __FUNCTION__);
+		mmc_h3800_slot_down();
+		free_irq(IRQ_GPIO_H3800_MMC_INT, &g_h3800_data);
+	}
+	return retval;
+}
+
+static void mmc_h3800_slot_cleanup( void )
+{
+	DEBUG(1,"\n");
+
+	mmc_h3800_slot_down();
+
+	free_irq(IRQ_H3800_SD_DETECT, &g_h3800_data);
+	free_irq(IRQ_GPIO_H3800_MMC_INT, &g_h3800_data);
+}
+
+
+/***********************************************************/
+
+static struct mmc_slot_driver dops = {
+	owner:     THIS_MODULE,
+	name:      "H3800 MMC",
+	ocr:       0x00ffc000,
+	flags:     MMC_SDFLAG_MMC_MODE,
+
+	init:      mmc_h3800_slot_init,
+	cleanup:   mmc_h3800_slot_cleanup,
+	is_empty:  mmc_h3800_slot_is_empty,
+	send_cmd:  mmc_h3800_send_command,
+	set_clock: mmc_h3800_set_clock,
+};
+
+int __init h3600_asic_mmc_init(void)
+{
+	int retval;
+
+	DEBUG(0,"\n");
+	retval = mmc_register_slot_driver(&dops, 1);
+	if ( retval < 0 )
+		printk(KERN_INFO "%s: unable to register slot\n", __FUNCTION__);
+
+	return retval;
+}
+
+void __exit h3600_asic_mmc_cleanup(void)
+{
+	DEBUG(0,"\n");
+	mmc_unregister_slot_driver(&dops);
+}
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/h3600_asic_mmc.h linux-2.4.26/drivers/mmc/h3600_asic_mmc.h
--- linux-2.4.26.org/drivers/mmc/h3600_asic_mmc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/h3600_asic_mmc.h	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,29 @@
+/*
+* Driver interface to the ASIC Complasion chip on the iPAQ H3800
+*
+* Copyright 2001 Compaq Computer Corporation.
+*
+* Use consistent with the GNU GPL is permitted,
+* provided that this copyright notice is
+* preserved in its entirety in all copies and derived works.
+*
+* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+* FITNESS FOR ANY PARTICULAR PURPOSE.
+*
+* Author:  Andrew Christian
+*          <Andrew.Christian@compaq.com>
+*          October 2001
+*
+* Restrutured June 2002
+*/
+
+#ifndef H3600_ASIC_MMC_H
+#define H3600_ASIC_MMC_H
+
+int  h3600_asic_mmc_init(void);
+void h3600_asic_mmc_cleanup(void);
+int  h3600_asic_mmc_suspend(void);
+void h3600_asic_mmc_resume(void);
+
+#endif /* H3600_ASIC_MMC_H */
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/m32r_mmc.c linux-2.4.26/drivers/mmc/m32r_mmc.c
--- linux-2.4.26.org/drivers/mmc/m32r_mmc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/m32r_mmc.c	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,1084 @@
+/*
+ * Low-level MMC functions for the M32R mappi2/uT-Engine
+ *
+ * based on h3600_asic_mmc.c 
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/mmc/mmc_ll.h>
+
+#if defined( CONFIG_PLAT_M32700UT)
+#include <asm/m32700ut/m32700ut_pld.h>
+#elif defined( CONFIG_PLAT_MAPPI2)
+#include <asm/mappi2/mappi2_pld.h>
+#endif
+
+#include "m32r_mmc.h"
+
+struct response_info {
+	int length;
+	u16 cdc_flags;
+};
+
+static struct response_info rinfo[] = {
+	{ 0,  MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE                     }, /* R0 */
+	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1                              }, /* R1  */
+	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R1 | MMC_CMD_DATA_CONT_BUSY_BIT }, /* R1b */
+	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CID */
+	{ 17, MMC_CMD_DATA_CONT_FORMAT_R2                              }, /* R2 CSD */
+	{ 6,  MMC_CMD_DATA_CONT_FORMAT_R3                              }, /* R3  */
+	{ 6,  0                                                        }, /* R4  */
+	{ 6,  0                                                        }, /* R5  */
+};
+
+enum m32r_request_type {
+	RT_NO_RESPONSE,
+	RT_RESPONSE_ONLY,
+	RT_READ,
+	RT_WRITE
+};
+
+enum cmd_poll_state {
+	STS_IDLE,
+	STS_STA_CMD,
+	STS_STA_RES,
+	STS_END_CMD,
+	STS_STA_READ,
+	STS_END_READ,
+	STS_STA_WRITE,
+	STS_END_WRITE,
+	STS_END_CMD_ERR
+};
+
+struct m32r_mmc_data {
+	struct timer_list        sd_detect_timer;
+	struct timer_list        reset_timer;
+#if 0
+	struct timer_list        irq_timer;    /* Panic timer - make sure we get a response */
+#endif	
+	struct timer_list        poll_timer;
+	u32                      clock;        /* Current clock frequency */
+	struct mmc_request      *request;
+	enum m32r_request_type  type;
+	enum cmd_poll_state state;	/* for M32R: command polling state */
+	unsigned short MMC_Status;	/* for M32R: status flag (replace ARM ASIC register) */
+	int state_timeout_tick;		/* for M32R: polling timeout counter */
+	int nob; 		/* for M32R: current nob  (replace ARM ASIC register)*/
+	int block_len;	/* for M32R: current length  (replace ARM ASIC register)*/
+};
+
+static struct m32r_mmc_data g_m32r_mmc_data;
+
+//#define MMC_CMD_POLL  ((2 * HZ)/1000) /*command polling interval */
+#define MMC_CMD_POLL  ((5 * HZ)/1000) /*command polling interval */
+#define MMC_CMD_POLL_TIMES  50		 /*command polling timeout wait*/
+
+#define MMC_WRITE_TIME  ((100 * HZ)/1000)		 /*command polling timeout wait*/
+
+#define MMC_IRQ_TIMEOUT  (3 * HZ)
+
+#define DUMMY_CLOCK	(160/16)	// dummy clock = 160clock(ｻﾃﾄ)
+
+static __inline__ void mmc_delay( void ) { udelay(1); }
+static void mmc_m32r_handle_int( struct m32r_mmc_data *sd, u16 status, int timeout );
+
+/****************** local finctions ***************************************/
+/****************** based on M3A-2139 mmc driver for ITRON ****************/
+/**************************************************************************/
+
+/* generate CRC(7) for command     */
+/* in: unsigned short *cmd; cmd buffer */
+
+static void MMCSetCmd( u16 cmd, u32 arg )
+{
+	int i;
+	volatile unsigned short reg;
+	unsigned short cmd_data[3];
+	unsigned char *ptr;
+	unsigned short tmp;
+
+	MMC_DEBUG(1, "cmd[%x] arg[%lx]\n", cmd, (unsigned long)arg);
+
+	/* check transfer done */
+	do{
+		reg = inw((unsigned long)PLD_MMCCMDBCUT);
+	}while(reg != 0);
+
+	cmd_data[0] = ((cmd << 8) & 0xff00) | 0x4000 | ((arg >> 24) & 0xff);
+	cmd_data[1] = (((arg >> 16) << 8) & 0xff00) | ((arg >> 8) & 0xff);
+	cmd_data[2] = ((arg << 8) & 0xff00);
+
+	/* command CRC set */
+	outw(0, (unsigned long)PLD_CRC7DATA);
+	ptr = (unsigned char *)&cmd_data[0];
+	for ( i = 0; i < 5; i++ ) {
+		outw( *ptr++, (unsigned long)PLD_CRC7INDATA);
+	}
+
+	tmp = inw((unsigned long)PLD_CRC7DATA) << 1;
+	cmd_data[2] = cmd_data[2] | tmp;
+
+	MMC_DEBUG(3, "cmd1[%x] cmd2[%x] cmd3[%x]\n", cmd_data[0], cmd_data[1], cmd_data[2]);
+
+	/* write command to buffer */
+	for ( i = 0; i < 3; i++ ) {
+		outw(cmd_data[i], (unsigned long)(PLD_MMCCMDDATA+i));
+	}
+
+}
+
+static void MMCSendCmd(int resp_bytes)
+{
+	MMC_DEBUG(1, "resp_bytes %d\n", resp_bytes);
+
+	outw(resp_bytes+6, (unsigned long)PLD_MMCCMDBCUT);
+	outw(0x0002, (unsigned long)PLD_MMCCR);      /* transfer enable */
+}
+
+static int MMCRecvDummy(int num)
+{
+        int i;
+        volatile unsigned short reg;
+
+	MMC_DEBUG(1, "num %d\n", num);
+
+        //･ﾀ･ﾟ｡ｼ･ﾇ｡ｼ･ｿｼｿｮ･筍ｼ･ﾉ､ﾋ･ｻ･ﾃ･ﾈ
+        outw( 0x0100, (unsigned long)PLD_MMCMOD);                //･ﾇ｡ｼ･ｿ･ﾀ･ﾟ｡ｼｼｿｮ･筍ｼ･ﾉ
+
+        outw( num*2, (unsigned long)PLD_MMCCDTBCUT );        //･ﾇ｡ｼ･ｿｼｿｮｿ･ｻ･ﾃ･ﾈ
+
+        outw( 0x0001, (unsigned long)PLD_MMCCR );      //･ﾇ｡ｼ･ｿｼｿｮｳｫｻﾏ､ｷ､ﾆ･ﾀ･ﾟ｡ｼ･ｯ･･ﾃ･ｯ､ｽﾐﾎﾏ
+
+        for(i=0; i< 0xffffff; i++){
+                reg = inw((unsigned long)PLD_MMCCDTBCUT);
+                if(reg == 0){
+                        while(inw((unsigned long)PLD_MMCCR) != 0){
+                                // ｺﾇｸ螟ﾎ･ﾀ･ﾟ｡ｼ･ｯ･･ﾃ･ｯﾁｽﾐｴｰﾎｻﾂﾔ､ﾁ
+                        }
+                        outw( 0x0000, (unsigned long)PLD_MMCMOD );                //･ﾇ｡ｼ･ｿ･ﾀ･ﾟ｡ｼｼｿｮ･筍ｼ･ﾉｲｽ
+                        return 0;
+		}
+        }
+
+        outw( 0x0100, (unsigned long)PLD_MMCCR ); //MMCｲﾏｩ･･ｻ･ﾃ･ﾈ
+	MMC_DEBUG(2, "end error [%x]\n", i);
+
+        return -1;      //･ｨ･鬘ｼ(PLDｰﾛｾ｡ｩ)
+}
+
+static int MMCRecvResp(unsigned short *resp,int num,int dummy)
+{
+	
+	int i;
+	unsigned short reg;
+
+	num = (num+1)/2;
+	
+	i= 0x1000;
+	
+	/* ｼｿｮｴｰﾎｻﾂﾔ､ﾁ */
+	do{
+		reg = inw((unsigned long)PLD_MMCCR);
+		i--;
+		if(i<0){
+			outw(0x0100, (unsigned long)PLD_MMCCR);		//MMCｲﾏｩ･･ｻ･ﾃ･ﾈ
+			return -1;			//ｼｿｮ･ｿ･､･爭｢･ｦ･ﾈ
+		}
+	}while(reg != 0);
+
+	for ( i = 0; i < num; i++ ) {
+		*resp++ = inw((unsigned long)(PLD_MMCRSPDATA + i));
+	}
+
+	if(dummy != 0){
+		MMCRecvDummy(dummy);
+	}
+	
+	return 0;
+}
+
+#if 0
+#define RESP_R1 6
+#define RESP_R2 17
+static int mmc_comp_crc7(unsigned short *buff, int length)
+{
+	int i;
+	unsigned char *ptr;
+	unsigned short ret, result;
+
+	ptr = (unsigned char *)buff;
+	ret = ptr[length -1] & 0xff; /* CRCﾌ皃ﾃﾍ*/
+	ret >>= 1;
+
+	if (length == RESP_R1) { //R1
+		length--;
+	} else if (length == RESP_R2) {
+		ptr++;
+		length -= 2;
+	}
+	outw(0, (unsigned long)CRC7DATA); // ｽ魘ｲｽ
+	for (i = 0; i < length; i++) {
+		outw(*ptr++, (unsigned long)PLD_CRC7INDATA);
+	}
+	result = inw((unsigned long)PLD_CRC7DATA);
+
+	if (result != ret) {
+		return -1;
+	}
+	return 0;
+}
+#endif
+
+static void dev_init_mmc( void )
+{
+	unsigned short status;
+
+	MMC_DEBUG(1, "\n");
+
+	status = inw((unsigned long)PLD_CPCR);
+	outw(status | 2, (unsigned long)PLD_CPCR);
+
+	outw(0x0100, (unsigned long)PLD_MMCCR);
+}
+
+/* close buffer and power down */
+static void dev_close_mmc(int side)
+{
+	unsigned short status;
+
+	MMC_DEBUG(1, "\n");
+
+	outw(0x0100, (unsigned long)PLD_MMCCR);
+
+	status = inw((unsigned long)PLD_CPCR);
+	outw(status ^ 0xFFFD, (unsigned long)PLD_CPCR);
+
+}
+
+/****************END  M32R LOCAL FUNCTIONS ************/
+
+static int MMCSendData(unsigned char *data)
+{
+	int i;
+	volatile unsigned short reg;
+	unsigned short regbackup;
+	unsigned short crc16;
+	
+	regbackup = inw((unsigned long)PLD_MMCBAUR);
+	outw(0, (unsigned long)PLD_MMCCR);      //ｶﾘｻﾟ
+	/* check CLOCK */
+
+	MMC_DEBUG(3, "PLD_MMCBAUR %d\n", regbackup);
+
+	outw(0, (unsigned long)PLD_CRC16DATA);
+
+	outw(1, (unsigned long)PLD_MMCMOD);				//･ﾇ｡ｼ･ｿﾁｿｮ
+	outw(0, (unsigned long)PLD_MMCSTS);				//CRCﾁｿｮ･ｹ･ﾆ｡ｼ･ｿ･ｹ､･ｯ･･｢
+	outw(514, (unsigned long)PLD_MMCCDTBCUT);		//ﾁｿｮ･ﾐ･､･ﾈｿ､･ｻ･ﾃ･ﾈ
+
+	/* ﾁｿｮ･ﾇ｡ｼ･ｿ､ﾎｽ､ｭｹ､ﾟ */
+	for( i=0; i < 512/2; i++ ){
+		outw(*data, (unsigned long)PLD_CRC16INDATA);
+		reg = *data++ << 8;
+		outw(*data, (unsigned long)PLD_CRC16INDATA);
+		reg |= *data++ ;
+
+		outw(reg, (unsigned long)(PLD_MMCWDATA+i));
+	}
+
+	crc16 = inw((unsigned long)PLD_CRC16DATA);
+	outw(crc16, (unsigned long)(PLD_MMCWDATA+i));
+
+	return 0;
+}
+
+static int MMCSendDataChk( void ) 
+{
+	int i;
+	volatile unsigned short reg;
+	unsigned short status;
+
+	/* wait recive data ack */
+	i = 0xffffff;
+	do{
+		reg = inw((unsigned long)PLD_MMCCR);
+		i--;
+		if(i<0){
+			outw(0x0100, (unsigned long)PLD_MMCCR);			//MMCｲﾏｩ･･ｻ･ﾃ･ﾈ
+			MMC_DEBUG(1,": timeout\n");
+			return MMC_ERROR_TIMEOUT;				//ｼｿｮ･ｿ･､･爭｢･ｦ･ﾈ
+		}
+	}while(reg != 0);
+	
+	/* CRC･ｹ･ﾆ｡ｼ･ｿ･ｹ･ﾁ･ｧ･ﾃ･ｯ */
+	status = inw((unsigned long)PLD_MMCSTS);
+	if( status != 0x0002){
+		/* 0x0005､ﾏCRC･ｨ･鬘ｼ */
+		MMC_DEBUG(1, "CRC ERROR status[%x]\n", status);
+		return MMC_ERROR_CRC;
+	}
+	return 0;
+}
+
+
+static	unsigned short regbackup;
+static int MMCRecvData( int block_len )
+{
+	
+	regbackup = inw((unsigned long)PLD_MMCBAUR);
+
+	outw(0, (unsigned long)PLD_CRC16DATA);
+	outw(0, (unsigned long)PLD_MMCMOD);				//･ﾇ｡ｼ･ｿｼｿｮ
+	outw(block_len+2, (unsigned long)PLD_MMCCDTBCUT);		//ｼｿｮ･ﾐ･､･ﾈｿ､･ｻ･ﾃ･ﾈ
+	outw(1, (unsigned long)PLD_MMCCR);				//･ﾇ｡ｼ･ｿｼｿｮｳｫｻﾏ
+
+	return 0;
+}
+
+static int MMCRecvDataChk( unsigned char *data, int block_len )
+{	
+	int i,num;
+	volatile unsigned short reg;
+	volatile unsigned short count;
+	unsigned short crc16;
+	unsigned short recv;
+	unsigned char tmp;
+
+	/* ----- ･ﾇ｡ｼ･ｿ､ﾎﾆﾉ､ﾟｽﾐ､ｷ 512byteｼｿｮ ----- */
+	num = block_len;
+	i = 0xffffff;
+	recv = 0;
+	while(num){
+		i= num ;
+		
+		/* ｼｿｮ､ﾇ､ｭ､ﾆ､､､･ﾏ｡ｼ･ﾕ･｡ｼ･ﾉ､ｼ隍ｹ､ */
+		count = inw((unsigned long)PLD_MMCCDTBCUT);
+		if((i - count) > 0){
+			reg = inw((unsigned long)(PLD_MMCRDATA + recv++));
+
+			tmp = reg >> 8;
+			outw(tmp, (unsigned long)PLD_CRC16INDATA);
+			*data++ = tmp;
+
+			tmp = reg & 0xff;
+			outw(tmp, (unsigned long)PLD_CRC16INDATA);
+			*data++ = tmp;
+
+			num-=2;
+			i= 0xffffff;
+		}
+		else{
+			i--;
+			if(i<0){
+				outw(0x0100, (unsigned long)PLD_MMCCR);			//MMCｲﾏｩ･･ｻ･ﾃ･ﾈ
+				MMC_DEBUG(1,": timeout\n");
+				return MMC_ERROR_TIMEOUT;				//ｼｿｮ･ｿ･､･爭｢･ｦ･ﾈ
+			}
+		}
+		
+	}
+	
+	/* ---- CRCｼｿｮ 2byteｼｿｮ ---- */ 
+	i= 0xffffff;
+	do{
+		reg = inw((unsigned long)PLD_MMCCR);
+		i--;
+		if(i<0){
+			outw(0x0100, (unsigned long)PLD_MMCCR);			//MMCｲﾏｩ･･ｻ･ﾃ･ﾈ
+			MMC_DEBUG(1,": timeout\n");
+			return MMC_ERROR_TIMEOUT;				//ｼｿｮ･ｿ･､･爭｢･ｦ･ﾈ
+		}
+	}while(reg != 0);
+	
+	crc16 = inw((unsigned long)(PLD_MMCRDATA + recv));
+	
+	outw(regbackup, (unsigned long)PLD_MMCBAUR);
+	
+	MMCRecvDummy(10);
+
+	if(inw((unsigned long)PLD_CRC16DATA) != crc16){
+		MMC_DEBUG(1,": CRC Error\n");
+		return MMC_ERROR_CRC;		// CRC16･ｨ･鬘ｼ
+	}
+	return MMC_NO_ERROR;
+}
+
+/************************* ARM src *******************************/
+/**************************************************************************
+ * Utility routines for debuging
+ **************************************************************************/
+
+struct cmd_to_name {
+	int   id;
+	char *name;
+};
+
+static struct cmd_to_name cmd_names[] = {
+	{ MMC_CIM_RESET, "CIM_RESET" },
+	{ MMC_GO_IDLE_STATE, "GO_IDLE_STATE" },
+	{ MMC_SEND_OP_COND, "SEND_OP_COND" },
+	{ MMC_ALL_SEND_CID, "ALL_SEND_CID" },
+	{ MMC_SET_RELATIVE_ADDR, "SET_RELATIVE_ADDR" },
+	{ MMC_SET_DSR, "SET_DSR" },
+	{ MMC_SELECT_CARD, "SELECT_CARD" },
+	{ MMC_SEND_CSD, "SEND_CSD" },
+	{ MMC_SEND_CID, "SEND_CID" },
+	{ MMC_READ_DAT_UNTIL_STOP, "READ_DAT_UNTIL_STOP" },
+	{ MMC_STOP_TRANSMISSION, "STOP_TRANSMISSION" },
+	{ MMC_SEND_STATUS	, "SEND_STATUS	" },
+	{ MMC_GO_INACTIVE_STATE, "GO_INACTIVE_STATE" },
+	{ MMC_SET_BLOCKLEN, "SET_BLOCKLEN" },
+	{ MMC_READ_SINGLE_BLOCK, "READ_SINGLE_BLOCK" },
+	{ MMC_READ_MULTIPLE_BLOCK, "READ_MULTIPLE_BLOCK" },
+	{ MMC_WRITE_DAT_UNTIL_STOP, "WRITE_DAT_UNTIL_STOP" },
+	{ MMC_SET_BLOCK_COUNT, "SET_BLOCK_COUNT" },
+	{ MMC_WRITE_BLOCK, "WRITE_BLOCK" },
+	{ MMC_WRITE_MULTIPLE_BLOCK, "WRITE_MULTIPLE_BLOCK" },
+	{ MMC_PROGRAM_CID, "PROGRAM_CID" },
+	{ MMC_PROGRAM_CSD, "PROGRAM_CSD" },
+	{ MMC_SET_WRITE_PROT, "SET_WRITE_PROT" },
+	{ MMC_CLR_WRITE_PROT, "CLR_WRITE_PROT" },
+	{ MMC_SEND_WRITE_PROT, "SEND_WRITE_PROT" },
+	{ MMC_ERASE_GROUP_START, "ERASE_GROUP_START" },
+	{ MMC_ERASE_GROUP_END, "ERASE_GROUP_END" },
+	{ MMC_ERASE, "ERASE" },
+	{ MMC_FAST_IO, "FAST_IO" },
+	{ MMC_GO_IRQ_STATE, "GO_IRQ_STATE" },
+	{ MMC_LOCK_UNLOCK, "LOCK_UNLOCK" },
+	{ MMC_APP_CMD, "APP_CMD" },
+	{ MMC_GEN_CMD, "GEN_CMD" },
+};
+
+static char * get_cmd_name( int cmd )
+{
+	int i;
+	int len = sizeof(cmd_names) / sizeof(struct cmd_to_name);
+	for ( i = 0 ; i < len ; i++ )
+		if ( cmd == cmd_names[i].id )
+			return cmd_names[i].name;
+
+	return "UNKNOWN";
+}
+
+struct status_bit_to_name {
+	u16   mask;
+	int   shift;
+	char *name;
+};
+
+static void decode_status( u16 status )
+{
+    return;
+}
+
+static void printk_request( struct mmc_request *request, char *header )
+{
+	printk("%sindex  %d\n", header, request->index );
+	printk("%scmd    %d\n", header, request->cmd );
+	printk("%sarg    0x%08x\n", header, request->arg );
+	printk("%srtype  %d\n", header, request->rtype );
+	printk("%snob    %d\n", header, request->nob );
+	printk("%sbl_len %d\n", header, request->block_len );
+	printk("%sbuffer %p\n", header, request->buffer );
+	printk("%sresult %d\n", header, request->result);
+}
+
+/**************************************************************************
+ *   Clock routines
+ *
+ * We have to poll the status register until we're sure that the clock has stopped.
+ * This may be called in interrupt context, so we can't go to sleep!
+ **************************************************************************/
+
+/* mmc_h3800_start_clock ､ﾏ
+  ･ｳ･ﾞ･･ﾉﾅｾﾁ/･ﾇ｡ｼ･ｿﾅｾﾁｳｫｻﾏ､ﾎ･ｭ･蝪ｼ､ﾈ､ｷ､ﾆ､
+  ｻﾈﾍﾑ､ｷ､ﾆ､､､ -> ｳﾆﾅｾﾁﾍﾑｴﾘｿ､ﾋﾃﾖ､ｭｴｹ､ｨ､ */
+static void mmc_m32r_start_clock( void )
+{	
+	outw(0x0001, (unsigned long)PLD_MMCCR);				//･ﾇ｡ｼ･ｿﾁｿｮｳｫｻﾏ
+}
+
+static int mmc_m32r_stop_clock( void )
+{
+	outw(0x0100, (unsigned long)PLD_MMCCR); 
+	mmc_delay();
+	if (inw((unsigned long)PLD_MMCCR) != 0)
+		return MMC_ERROR_DRIVER_FAILURE;
+	return MMC_NO_ERROR;
+}
+
+static int mmc_m32r_set_clock( u32 rate )
+{
+	int retval;
+
+	retval = mmc_m32r_stop_clock();
+	if ( retval )
+		return retval;
+
+	MMC_DEBUG(1,": set clock rate in %d, set %d\n", rate, MMC_BAUR(rate));
+	outw(MMC_BAUR(rate), (unsigned long)PLD_MMCBAUR);
+	return MMC_NO_ERROR;
+}
+
+static int mmc_m32r_reset_asic( u32 clock_rate )
+{
+	int retval;
+	unsigned short status;
+
+	MMC_DEBUG(1,"clock_rate[%ld]\n", (unsigned long)clock_rate);
+
+	status = inw((unsigned long)PLD_CPCR);
+	outw(status | 2, (unsigned long)PLD_CPCR);
+
+	/* set clock rate */
+	retval = mmc_m32r_set_clock( clock_rate );
+
+	/* dummy clock 160clock */
+	retval = MMCRecvDummy( DUMMY_CLOCK );
+
+	return retval;
+}
+
+/* 
+   The reset function clears _everything_ in the ASIC,
+   so it needs be completely reset
+*/
+/* ･･ｻ･ﾃ･ﾈｸ蝪｢MMC､ｬｻﾈﾍﾑｲﾄﾇｽ､ﾋ､ﾊ､ﾃ､ｿ､｢､ﾈ､ﾇｵｯﾆｰ､ｹ､･ｿ･､･ﾞ･ﾏ･･ﾉ･ */
+static void mmc_m32r_reset_timeout( unsigned long nr )
+{
+	struct m32r_mmc_data *sd = (struct m32r_mmc_data *) nr;
+  
+	sd->request->result = MMC_NO_ERROR;
+	mmc_cmd_complete( sd->request );
+}
+
+static int mmc_m32r_reset( struct m32r_mmc_data *sd )
+{
+	int retval = mmc_m32r_reset_asic( MMC_CLOCK_SLOW );
+
+	g_m32r_mmc_data.type = RT_NO_RESPONSE;
+	g_m32r_mmc_data.state = STS_IDLE;
+
+	/* ･･ｻ･ﾃ･ﾈｸ蝪｢MMC､ｬｰﾂﾄﾆｰｺ､ｹ､､ﾞ､ﾇ､･ｿ･､･ﾞ､ﾇｷﾗﾂｬ*/
+	mod_timer( &sd->reset_timer, jiffies + (100 * HZ) / 1000 );
+	return retval;
+}
+
+
+static void mmc_m32r_set_command( u16 cmd, u32 arg )
+{
+	MMCSetCmd(cmd, arg);
+}
+
+static void mmc_m32r_set_transfer( u16 block_len, u16 nob )
+{
+	MMC_DEBUG(2,": block_len=%d nob=%d\n", block_len, nob);
+	g_m32r_mmc_data.nob = nob;
+	g_m32r_mmc_data.block_len = block_len;
+}
+
+static int mmc_m32r_transmit_data( struct mmc_request *request )
+{
+	int retval = MMC_NO_ERROR;
+	u8 *buf = request->buffer;
+	int i;
+
+	MMC_DEBUG(2,": nob=%d block_len=%d\n", request->nob, request->block_len);
+	if ( request->nob <= 0 ) {
+		MMC_DEBUG(1,": *** nob already at 0 ***\n");
+		return retval;
+	}
+
+	MMCSendData(buf);
+
+	mmc_m32r_start_clock();
+	
+	retval = MMCSendDataChk();
+
+	START_MMC_DEBUG(2) { 
+		u16 status = g_m32r_mmc_data.MMC_Status;
+		printk("%s: status=0x%04x (", __FUNCTION__, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_MMC_DEBUG;
+
+	START_MMC_DEBUG(3) {
+		u8 *b = request->buffer;
+		for ( i = 0 ; i < request->block_len ; i++ ) {
+			printk(" %02x", *b++);
+			if ( ((i + 1) % 16) == 0 )
+				printk("\n");
+		}
+	} END_MMC_DEBUG;
+
+	/* Updated the request buffer to reflect the current state */
+	request->buffer = (u8 *) buf;
+	request->nob--;
+	
+	return retval;
+}
+
+static int mmc_m32r_receive_data( struct mmc_request *request )
+{
+	int retval = MMC_NO_ERROR;
+	u8 *buf = request->buffer;
+	int i;
+
+	MMC_DEBUG(2,": nob=%d block_len=%d buf=%p\n", request->nob, request->block_len, buf);
+	if ( request->nob <= 0 ) {
+		MMC_DEBUG(1,": *** nob already at 0 ***\n");
+		return retval;
+	}
+
+	MMCRecvData( request->block_len );
+
+	retval = MMCRecvDataChk( buf, request->block_len );
+
+	START_MMC_DEBUG(3) {
+		u8 *b = request->buffer;
+		for ( i = 0 ; i < request->block_len ; i++ ) {
+			printk(" %02x", *b++);
+			if ( ((i + 1) % 16) == 0 )
+				printk("\n");
+		}
+	} END_MMC_DEBUG;
+
+	/* Updated the request buffer to reflect the current state */
+	request->buffer = (u8 *) buf;
+	request->nob--;
+	
+	return retval;
+}
+
+static int mmc_m32r_exec_command( struct mmc_request *request )
+{
+	int retval;
+
+	MMC_DEBUG(1,": request=%p status=%04x\n", request, g_m32r_mmc_data.MMC_Status );
+
+	/* Start the actual transfer */
+	retval = mmc_m32r_stop_clock();
+	if ( retval )
+		return retval;
+
+	/* set command to transfer register */
+	mmc_m32r_set_command( request->cmd, request->arg );
+
+	switch (request->cmd) {
+	case MMC_READ_SINGLE_BLOCK:
+	case MMC_READ_MULTIPLE_BLOCK:
+		mmc_m32r_set_transfer( request->block_len, request->nob );
+		g_m32r_mmc_data.type = RT_READ;
+		break;
+	case MMC_WRITE_BLOCK:
+	case MMC_WRITE_MULTIPLE_BLOCK:
+		mmc_m32r_set_transfer( request->block_len, request->nob );
+		g_m32r_mmc_data.type = RT_WRITE;
+		break;
+	default:
+		g_m32r_mmc_data.type = RT_RESPONSE_ONLY;
+		break;
+	}
+	
+	MMCSendCmd( rinfo[request->rtype].length );
+
+	g_m32r_mmc_data.state = STS_STA_CMD;
+	g_m32r_mmc_data.state_timeout_tick = MMC_CMD_POLL_TIMES;
+	mod_timer( &g_m32r_mmc_data.poll_timer, jiffies + MMC_CMD_POLL); 
+	return MMC_NO_ERROR;
+}
+
+static void mmc_m32r_send_command( struct mmc_request *request )
+{
+	int retval;
+
+	MMC_DEBUG(1,": request=%p cmd=%d (%s) arg=%08x status=%04x\n", request, 
+	      request->cmd, get_cmd_name(request->cmd), request->arg,
+	      g_m32r_mmc_data.MMC_Status);
+
+	/* TODO: Grab a lock???? */
+	g_m32r_mmc_data.request = request;
+	request->result = MMC_NO_RESPONSE;   /* Flag to indicate don't have a result yet */
+
+	if ( request->cmd == MMC_CIM_RESET ) {
+		retval = mmc_m32r_reset( &g_m32r_mmc_data );
+	}
+	else {
+		retval = mmc_m32r_exec_command( request );
+		if ( retval ) {
+			MMC_DEBUG(0,": ASIC not responding!  Trying to reset\n");
+
+			retval = mmc_m32r_reset_asic( g_m32r_mmc_data.clock );
+			if ( retval ) {
+				MMC_DEBUG(0,": ASIC doesn't reset!  Panic now!\n");
+			}
+			else {
+				retval = mmc_m32r_exec_command( request );
+				if ( retval ) {
+					MMC_DEBUG(0,": ASIC unable to exec!\n");
+				}
+			}
+		}
+	}
+
+	if ( retval ) {
+		request->result = retval;
+		mmc_cmd_complete( request );
+	}
+}
+
+/**************************************************************************/
+/* TODO: Need to mask interrupts?? */
+
+static void mmc_m32r_get_response( struct mmc_request *request )
+{
+	int i;
+	int dummy=0;
+	int len = rinfo[request->rtype].length;
+	u8 *buf = request->response;
+	
+	MMC_DEBUG(1,"\n");
+
+	request->result = MMC_NO_ERROR;    /* Mark this as having a request result of some kind */
+
+        if ( len == 0 ) { /* NO DATA, dummy read */
+                MMCRecvDummy(1);
+        } else {
+
+                switch (g_m32r_mmc_data.type) {
+                case RT_READ:
+                        /* ･ﾀ･ﾟ｡ｼ･ｵ･､･ｯ･､ﾊ､ｷ(Read) */
+                        dummy = 0;
+                        break;
+                case RT_WRITE:
+                        /* ･ﾀ･ﾟ｡ｼ･ｵ･､･ｯ･､｢､(Write) */
+                        dummy = DUMMY_CLOCK;
+                        break;
+                default:
+                        dummy = DUMMY_CLOCK;
+                        break;
+                }
+                MMCRecvResp( (unsigned short *)buf, len, dummy );
+        }
+
+	START_MMC_DEBUG(2) {
+		printk("%s:  Raw byte stream: ", __FUNCTION__);
+		for ( i = 0 ; i < len; i++ )
+			printk("%02x ", buf[i]);
+		printk("\n");
+	} END_MMC_DEBUG;
+}
+
+/* ｳ荀ｹ､ﾟ･ﾏ･･ﾉ･ */
+/* M32Rﾈﾇ､ﾇ､ﾏ｡｢
+ * ｡ｦｽ靉･ｳ･ﾞ･･ﾉ､ｬｴｰﾎｻ､ｷ､ﾆ､､､ﾊ､､ｾｹ遉ﾋｷﾐｲ盻ｴﾖ､ﾄﾉｲﾃ､ｷ､ﾆｺﾆﾅﾙ･ｹ･遙ｼ･ﾗ
+ * ｡ｦｷﾐｲ盻ｴﾖ､ｬ･ｿ･､･爭｢･ｦ･ﾈｻｴﾖ､ｱﾛ､ｨ､ｿｾｹ逾ｿ･､･爭｢･ｦ･ﾈｽ靉
+ * ｡ｦ･ﾀ･ﾟ｡ｼ･ｯ･･ﾃ･ｯ､ﾎﾁｿｮ｡ｧ･ﾝ｡ｼ･･･ｰ､ﾇｹﾔ､ｦ､ｫ･ｿ･､･ﾞ､ﾋ､ｹ､､ｫ｡ｩ｡ｩ
+ * ､ﾄﾉｲﾃ､ｹ､
+ * */
+static void mmc_m32r_handle_int( struct m32r_mmc_data *sd, u16 status, int timeout )
+{
+
+	int retval = MMC_NO_ERROR;
+
+	MMC_DEBUG(1,"status[%x]\n", status);
+
+	if ( status & (MMC_STATUS_READ_TIMEOUT) ) {
+		retval = MMC_ERROR_TIMEOUT;
+		goto terminate_int;
+	}
+
+	if ( status & MMC_STATUS_END_COMMAND_RESPONSE && sd->request->result == MMC_NO_RESPONSE ) 
+		mmc_m32r_get_response( sd->request );
+
+	if ( g_m32r_mmc_data.type == RT_READ && 
+	     (status & (MMC_STATUS_FIFO_FULL | MMC_STATUS_DATA_TRANSFER_DONE)) != 0)
+		retval = mmc_m32r_receive_data( sd->request );
+
+	if ( g_m32r_mmc_data.type == RT_WRITE && (status & MMC_STATUS_FIFO_EMPTY ) != 0
+	     && sd->request->nob > 0 )
+		retval = mmc_m32r_transmit_data( sd->request );
+
+	switch (g_m32r_mmc_data.type) {
+	case RT_NO_RESPONSE:
+		break;
+
+	case RT_RESPONSE_ONLY:
+		if ( sd->request->result < 0 ) {
+			printk(KERN_INFO "%s: illegal interrupt - command hasn't finished\n", __FUNCTION__);
+			retval = MMC_ERROR_TIMEOUT;
+		}
+		break;
+	case RT_READ:
+		if ( sd->request->nob ) {
+			MMC_DEBUG(2,": read re-enabling \n");
+			mod_timer( &sd->poll_timer, jiffies + MMC_CMD_POLL); 
+			return;
+		}
+		break;
+	case RT_WRITE:
+		if ( sd->request->nob || !(status & MMC_STATUS_END_PROGRAM)  ) {
+			MMC_DEBUG(2,": write re-enabling \n");
+			mod_timer( &sd->poll_timer, jiffies + MMC_CMD_POLL); 
+			return;
+		}
+		break;
+	}
+	
+	MMC_DEBUG(2,": terminating status=0x%04x\n", g_m32r_mmc_data.MMC_Status );
+
+terminate_int:
+	del_timer_sync( &sd->poll_timer );
+	sd->request->result = retval;
+	mmc_cmd_complete( sd->request );
+}
+
+#define TM_GO_HANDLER 0
+#define TM_RESTART_TIMER 1
+
+static int mmc_make_status(struct m32r_mmc_data *sd, u16 *status)
+{
+	
+	unsigned short bytes;
+	unsigned short cr;
+
+	*status = 0;
+
+	cr     = inw((unsigned long)PLD_MMCCR);
+
+	switch ( g_m32r_mmc_data.state ) {
+
+	/* ･ｳ･ﾞ･･ﾉﾁｿｮ */
+	case STS_STA_CMD:
+		bytes = inw((unsigned long)PLD_MMCCMDBCUT); 
+		if ((bytes != 0) || (cr != 0)) {  /* still busy */
+			if (sd->state_timeout_tick-- <= 0) { /* timeout count down */
+				*status = MMC_STATUS_READ_TIMEOUT;
+				g_m32r_mmc_data.state = STS_END_CMD_ERR;
+				return TM_GO_HANDLER;
+			} else {
+				return TM_RESTART_TIMER;
+			}
+		} else {
+		   	/* ﾁｿｮ･ｹ･ﾆ｡ｼ･ｿ･ｹ OK */
+			switch (g_m32r_mmc_data.type) {
+			case RT_READ:
+				g_m32r_mmc_data.state = STS_STA_READ;
+				break;
+			case RT_WRITE:
+				g_m32r_mmc_data.state = STS_STA_WRITE;
+				break;
+			default:
+				*status = MMC_STATUS_END_COMMAND_RESPONSE;
+				g_m32r_mmc_data.state = STS_END_CMD;
+				return TM_GO_HANDLER;
+				break;
+			}
+		}
+		break;
+	case STS_STA_READ:
+		/* CRC｡ｿ･ｿ･､･爭｢･ｦ･ﾈ､ﾎｳﾎﾇｧ､ﾏmmc_m32r_receive_data()､ﾇｹﾔ､ｦ */
+		*status = MMC_STATUS_DATA_TRANSFER_DONE;
+		g_m32r_mmc_data.state = STS_END_CMD;
+		return TM_GO_HANDLER;
+		break;
+	case STS_STA_WRITE:
+		/* CRC｡ｿ･ｿ･､･爭｢･ｦ･ﾈ､ﾎｳﾎﾇｧ､ﾏmmc_m32r_transmit_data()､ﾇｹﾔ､ｦ */
+		*status = MMC_STATUS_FIFO_EMPTY | MMC_STATUS_END_PROGRAM;
+		g_m32r_mmc_data.state = STS_END_CMD;
+		return TM_GO_HANDLER;
+	default:
+		break;
+	}
+	
+	return 0;
+}
+
+static void mmc_m32r_polling( unsigned long nr )
+{
+	struct m32r_mmc_data *sd = (struct m32r_mmc_data *) nr;
+	u16 status;
+	int result;
+
+	if ((result = mmc_make_status(sd, &status)) == TM_RESTART_TIMER) {
+		START_MMC_DEBUG(1) {
+			printk("%s: keep timer sd->status =%d\n", __FUNCTION__,  sd->state);
+		} END_MMC_DEBUG;
+		mod_timer( &g_m32r_mmc_data.poll_timer, jiffies + MMC_CMD_POLL); 
+		return;
+	}
+	START_MMC_DEBUG(2) { 
+		printk("%s: sd=%p status=0x%04x (", __FUNCTION__, sd, status);
+		decode_status(status); 
+		printk(")\n"); 
+	} END_MMC_DEBUG;
+
+	mmc_m32r_handle_int( sd, status, 0 );
+}
+
+/**************************************************************************/
+
+static int _is_mmc_empty = 1;
+/* ･ｿ･､･ﾞ｡ｼ */
+/* ARM､ﾇ､ﾏｳ荀ｹ､ﾟ･ﾏ･･ﾉ･魴ｯﾆｰ､ﾀ､ﾃ､ｿ､ｬM32R/PLD､ﾇ､ﾏｼｴｵｯｾｲ､ﾋﾊﾑｹｹ｡｡*/
+static void mmc_m32r_sd_detect( unsigned long nr )
+{
+	struct m32r_mmc_data *sd = (struct m32r_mmc_data *) nr;
+	int sd_card;
+	sd_card = inw((unsigned long)PLD_MMCDET);
+	if (sd_card != _is_mmc_empty) { /* change state */
+
+		/* MMC initialize */
+		outw(0x0100, (unsigned long)PLD_MMCCR);
+
+		if (sd_card == 0) {
+			mmc_insert(0);
+		} else {
+			mmc_eject(0);
+		}	
+		_is_mmc_empty = sd_card;
+	}
+	mod_timer( &sd->sd_detect_timer, jiffies + (3000 * HZ) / 1000 );
+}
+
+/* ･ｹ･･ﾃ･ﾈｾﾂﾖ･ﾁ･ｧ･ﾃ･ｯｴﾘｿ */
+static int mmc_m32r_slot_is_empty( int slot )
+{
+	return  !(inw((unsigned long)PLD_MMCDET) == 0);
+}
+
+/**************************************************************************/
+
+static void mmc_m32r_slot_up( void )
+{
+	MMC_DEBUG(1,"\n");
+
+	/* enable MMC */
+	dev_init_mmc();
+}
+
+static void mmc_m32r_slot_down( void )
+{
+	MMC_DEBUG(1,"\n");
+
+	del_timer_sync(&g_m32r_mmc_data.sd_detect_timer);
+	del_timer_sync(&g_m32r_mmc_data.reset_timer);
+	del_timer_sync(&g_m32r_mmc_data.poll_timer);
+
+	/* disable MMC */
+	dev_close_mmc(0);
+}
+
+#if 0
+int m32r_asic_mmc_suspend(void)
+{
+	mmc_m32r_slot_down();
+	return 0;
+}
+
+void m32r_asic_mmc_resume(void)
+{
+	mmc_m32r_slot_up();
+}
+#endif
+
+/* 
+  initial timers
+          sd_detect_timer .... for insert eject detect
+          reset_timer     .... for mmc reset timeout
+          irq_timer(NOT USE).... for command responce timeout
+          poll_timer      .... for command polling
+                               h3800 use irq
+
+ */
+
+/* mmc･ｹ･･ﾃ･ﾈ､ﾎｽ魘ｲｽｴﾘｿ */
+/* ｾ蟆ﾌ･筵ｸ･蝪ｼ･mmc_core､ｫ､鮑ﾆ､ﾐ､､ﾍｽﾄ */
+static int mmc_m32r_slot_init( void )
+{
+	int retval=0;
+
+	MMC_DEBUG(1,"MMCDET[%x]\n", inw((unsigned long)PLD_MMCDET));
+
+	/* Set up timers */
+	g_m32r_mmc_data.sd_detect_timer.function = mmc_m32r_sd_detect;
+	g_m32r_mmc_data.sd_detect_timer.data     = (unsigned long) &g_m32r_mmc_data;
+	_is_mmc_empty = inw((unsigned long)PLD_MMCDET);
+	init_timer(&g_m32r_mmc_data.sd_detect_timer);
+
+	/* reset timeout */	
+	g_m32r_mmc_data.reset_timer.function = mmc_m32r_reset_timeout;
+	g_m32r_mmc_data.reset_timer.data     = (unsigned long) &g_m32r_mmc_data;
+	init_timer(&g_m32r_mmc_data.reset_timer);
+	
+	/* timer for comannd polling check */
+	g_m32r_mmc_data.poll_timer.function = mmc_m32r_polling;
+	g_m32r_mmc_data.poll_timer.data     = (unsigned long) &g_m32r_mmc_data;
+	init_timer(&g_m32r_mmc_data.poll_timer);
+
+	mmc_m32r_slot_up(); /* Fixes the sd_detect interrupt direction */
+
+	/* start slot detection timer */
+	mod_timer( &g_m32r_mmc_data.sd_detect_timer, jiffies + (3000 * HZ) / 1000 );
+
+	return retval;
+}
+
+static void mmc_m32r_slot_cleanup( void )
+{
+	MMC_DEBUG(1,"\n");
+
+	mmc_m32r_slot_down();
+}
+
+
+/***********************************************************/
+static struct mmc_slot_driver dops = {
+	owner:     THIS_MODULE,
+	name:      "M32R MMC",
+	ocr:       0x00ff0000,
+	flags:     MMC_SDFLAG_MMC_MODE, 
+
+	init:      mmc_m32r_slot_init,
+	cleanup:   mmc_m32r_slot_cleanup,
+	is_empty:  mmc_m32r_slot_is_empty,
+	send_cmd:  mmc_m32r_send_command,
+	set_clock: mmc_m32r_set_clock, /* set MMC transfer CLOCK */
+};
+
+static int __init m32r_mmc_init(void)
+{
+	int retval;
+
+	MMC_DEBUG(0,"m32r_mmc_init\n");
+
+	retval = mmc_register_slot_driver(&dops, 1); // mmc_core
+	if ( retval < 0 )
+		printk(KERN_INFO "%s: unable to register slot\n", __FUNCTION__);
+
+	return retval;
+}
+
+static void __exit m32r_mmc_cleanup(void)
+{
+	MMC_DEBUG(0,"\n");
+
+	mmc_unregister_slot_driver(&dops);
+}
+
+struct mmc_slot_module slot_module = {
+	init:    m32r_mmc_init,
+	cleanup: m32r_mmc_cleanup
+};
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/m32r_mmc.h linux-2.4.26/drivers/mmc/m32r_mmc.h
--- linux-2.4.26.org/drivers/mmc/m32r_mmc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/m32r_mmc.h	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,84 @@
+/*
+*/
+
+#ifndef M32700UT_MMC_H
+#define M32700UT_MMC_H
+
+/* MMC */
+/* PLD_MMCCR bit */
+#define MMC_CLR 0x0100 /* 1: init mmc */
+#define MMC_CMDEN 0x02 /* write: 0: N/A
+                                     1: start command transfer 
+                              read:  0: idle
+							         1: command transfer busy */
+#define MMC_DTEN 0x01 /* write: 0: N/A
+                                    1: start data transfer 
+                              read: 0: idle
+							        1: data transfer busy */
+
+
+/* PLD_MMCMOD bit */
+#define MMC_DMY 0x0100 /* 1: send dummy clock  */
+#define MMC_DSEL 0x01  /* 0: send data */
+                       /* 1: receve data */
+
+/* PLD_MMCSTS */
+/* PLD_MMCBAUR */
+#if defined( CONFIG_PLAT_M32700UT)
+#define _BCLK_ 50000000
+#elif defined( CONFIG_PLAT_MAPPI2)
+#define _BCLK_ 20000000
+#endif
+#define MMC_BAUR(mmc_baur)  ((_BCLK_/((mmc_baur) * 2)) - 1)
+
+
+/* PLD_MMCCMDBCUT */
+
+/* PLD_MMCDET */
+/*  0:card exist 1:no card */
+
+/* PLD_MMCWP */
+/*  0:write protect 1:no write protect */
+/* define PLD_MMCWDATA */
+/* define PLD_MMCRDATA */
+/* define PLD_MMCCMDDATA */
+/* define PLD_MMCRSPDATA */
+
+/* CRC */
+/* PLD_CRC7DATA */
+/* PLD_CRC7INDATA */
+/* PLD_CRC16DATA */
+/* PLD_CRC16INDATA */
+/* PLD_CRC16ADATA */
+/* PLD_CRC16AINDATA */
+
+#define MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE  0x00
+#define MMC_CMD_DATA_CONT_FORMAT_R1           0x01
+#define MMC_CMD_DATA_CONT_FORMAT_R2           0x02
+#define MMC_CMD_DATA_CONT_FORMAT_R3           0x03
+#define MMC_CMD_DATA_CONT_DATA_ENABLE         (1 << 2)  /* This command contains a data transfer */
+#define MMC_CMD_DATA_CONT_WRITE               (1 << 3)  /* This data transfer is a write */
+#define MMC_CMD_DATA_CONT_STREAM_MODE         (1 << 4)  /* This data transfer is in stream mode */
+#define MMC_CMD_DATA_CONT_BUSY_BIT            (1 << 5)  /* Busy signal expected after current cmd */
+#define MMC_CMD_DATA_CONT_INITIALIZE          (1 << 6)  /* Enables the 80 bits for initializing card */
+
+#define MMC_STATUS_READ_TIMEOUT          (1 << 0)
+#define MMC_STATUS_RESPONSE_TIMEOUT      (1 << 1)
+#define MMC_STATUS_CRC_WRITE_ERROR       (1 << 2)
+#define MMC_STATUS_CRC_READ_ERROR        (1 << 3)
+#define MMC_STATUS_SPI_READ_ERROR        (1 << 4)  /* SPI data token error received */
+#define MMC_STATUS_CRC_RESPONSE_ERROR    (1 << 5)
+#define MMC_STATUS_FIFO_EMPTY            (1 << 6)
+#define MMC_STATUS_FIFO_FULL             (1 << 7)
+#define MMC_STATUS_CLOCK_ENABLE          (1 << 8)  /* MultiMediaCard clock stopped */
+#define MMC_STATUS_DATA_TRANSFER_DONE    (1 << 11) /* Write operation, indicates transfer finished */
+#define MMC_STATUS_END_PROGRAM           (1 << 12) /* End write and read operations */
+#define MMC_STATUS_END_COMMAND_RESPONSE  (1 << 13) /* End command response */
+
+#if 0
+int  m32r_mmc_init(void);
+void m32r_mmc_cleanup(void);
+int  m32r_mmc_suspend(void);
+void m32r_mmc_resume(void);
+#endif
+#endif /* M32700UT_MMC_H */
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_core.c linux-2.4.26/drivers/mmc/mmc_core.c
--- linux-2.4.26.org/drivers/mmc/mmc_core.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_core.c	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,839 @@
+/*
+ * Core MMC driver functions
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          6 May 2002
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/sysctl.h>
+#include <linux/pm.h>
+
+#include "mmc_core.h"
+
+#define STATE_CMD_ACTIVE   (1<<0)
+#define STATE_CMD_DONE     (1<<1)
+#define STATE_INSERT       (1<<2)
+#define STATE_EJECT        (1<<3)
+
+static struct mmc_dev          g_mmc_dev;
+static struct proc_dir_entry  *proc_mmc_dir;
+
+#ifdef CONFIG_MMC_DEBUG
+int g_mmc_debug = CONFIG_MMC_DEBUG_VERBOSE;
+EXPORT_SYMBOL(g_mmc_debug);
+#endif
+
+/**************************************************************************
+ * Debugging functions
+ **************************************************************************/
+
+static char * mmc_result_strings[] = {
+	"NO_RESPONSE",
+	"NO_ERROR",
+	"ERROR_OUT_OF_RANGE",
+	"ERROR_ADDRESS",
+	"ERROR_BLOCK_LEN",
+	"ERROR_ERASE_SEQ",
+	"ERROR_ERASE_PARAM",
+	"ERROR_WP_VIOLATION",
+	"ERROR_CARD_IS_LOCKED",
+	"ERROR_LOCK_UNLOCK_FAILED",
+	"ERROR_COM_CRC",
+	"ERROR_ILLEGAL_COMMAND",
+	"ERROR_CARD_ECC_FAILED",
+	"ERROR_CC",
+	"ERROR_GENERAL",
+	"ERROR_UNDERRUN",
+	"ERROR_OVERRUN",
+	"ERROR_CID_CSD_OVERWRITE",
+	"ERROR_STATE_MISMATCH",
+	"ERROR_HEADER_MISMATCH",
+	"ERROR_TIMEOUT",
+	"ERROR_CRC",
+	"ERROR_DRIVER_FAILURE",
+};
+
+char * mmc_result_to_string( int i )
+{
+	return mmc_result_strings[i+1];
+}
+
+static char * card_state_strings[] = {
+	"empty",
+	"idle",
+	"ready",
+	"ident",
+	"stby",
+	"tran",
+	"data",
+	"rcv",
+	"prg",
+	"dis",
+};
+
+static inline char * card_state_to_string( int i )
+{
+	return card_state_strings[i+1];
+}
+
+/**************************************************************************
+ * Utility functions
+ **************************************************************************/
+
+#define PARSE_U32(_buf,_index) \
+	(((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \
+        (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]);
+
+#define PARSE_U16(_buf,_index) \
+	(((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]);
+
+int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd )
+{
+	u8 *buf = request->response;
+	
+	if ( request->result ) return request->result;
+
+	csd->csd_structure      = (buf[1] & 0xc0) >> 6;
+	csd->spec_vers          = (buf[1] & 0x3c) >> 2;
+	csd->taac               = buf[2];
+	csd->nsac               = buf[3];
+	csd->tran_speed         = buf[4];
+	csd->ccc                = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
+	csd->read_bl_len        = buf[6] & 0x0f;
+	csd->read_bl_partial    = (buf[7] & 0x80) ? 1 : 0;
+	csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0;
+	csd->read_blk_misalign  = (buf[7] & 0x20) ? 1 : 0;
+	csd->dsr_imp            = (buf[7] & 0x10) ? 1 : 0;
+	csd->c_size             = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6;
+	csd->vdd_r_curr_min     = (buf[9] & 0x38) >> 3;
+	csd->vdd_r_curr_max     = buf[9] & 0x07;
+	csd->vdd_w_curr_min     = (buf[10] & 0xe0) >> 5;
+	csd->vdd_w_curr_max     = (buf[10] & 0x1c) >> 2;
+	csd->c_size_mult        = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7);
+	switch ( csd->csd_structure ) {
+	case CSD_STRUCT_VER_1_0:
+	case CSD_STRUCT_VER_1_1:
+		csd->erase.v22.sector_size    = (buf[11] & 0x7c) >> 2;
+		csd->erase.v22.erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
+		break;
+	case CSD_STRUCT_VER_1_2:
+	default:
+		csd->erase.v31.erase_grp_size = (buf[11] & 0x7c) >> 2;
+		csd->erase.v31.erase_grp_mult = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
+		break;
+	}
+	csd->wp_grp_size        = buf[12] & 0x1f;
+	csd->wp_grp_enable      = (buf[13] & 0x80) ? 1 : 0;
+	csd->default_ecc        = (buf[13] & 0x60) >> 5;
+	csd->r2w_factor         = (buf[13] & 0x1c) >> 2;
+	csd->write_bl_len       = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6);
+	csd->write_bl_partial   = (buf[14] & 0x20) ? 1 : 0;
+	csd->file_format_grp    = (buf[15] & 0x80) ? 1 : 0;
+	csd->copy               = (buf[15] & 0x40) ? 1 : 0;
+	csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
+	csd->tmp_write_protect  = (buf[15] & 0x10) ? 1 : 0;
+	csd->file_format        = (buf[15] & 0x0c) >> 2;
+	csd->ecc                = buf[15] & 0x03;
+
+	MMC_DEBUG(2,"  csd_structure=%d  spec_vers=%d  taac=%02x  nsac=%02x  tran_speed=%02x\n"
+	      "  ccc=%04x  read_bl_len=%d  read_bl_partial=%d  write_blk_misalign=%d\n"
+	      "  read_blk_misalign=%d  dsr_imp=%d  c_size=%d  vdd_r_curr_min=%d\n"
+	      "  vdd_r_curr_max=%d  vdd_w_curr_min=%d  vdd_w_curr_max=%d  c_size_mult=%d\n"
+	      "  wp_grp_size=%d  wp_grp_enable=%d  default_ecc=%d  r2w_factor=%d\n"
+	      "  write_bl_len=%d  write_bl_partial=%d  file_format_grp=%d  copy=%d\n"
+	      "  perm_write_protect=%d  tmp_write_protect=%d  file_format=%d  ecc=%d\n",
+	      csd->csd_structure, csd->spec_vers, 
+	      csd->taac, csd->nsac, csd->tran_speed,
+	      csd->ccc, csd->read_bl_len, 
+	      csd->read_bl_partial, csd->write_blk_misalign,
+	      csd->read_blk_misalign, csd->dsr_imp, 
+	      csd->c_size, csd->vdd_r_curr_min,
+	      csd->vdd_r_curr_max, csd->vdd_w_curr_min, 
+	      csd->vdd_w_curr_max, csd->c_size_mult,
+	      csd->wp_grp_size, csd->wp_grp_enable,
+	      csd->default_ecc, csd->r2w_factor, 
+	      csd->write_bl_len, csd->write_bl_partial,
+	      csd->file_format_grp, csd->copy, 
+	      csd->perm_write_protect, csd->tmp_write_protect,
+	      csd->file_format, csd->ecc);
+	switch (csd->csd_structure) {
+	case CSD_STRUCT_VER_1_0:
+	case CSD_STRUCT_VER_1_1:
+		MMC_DEBUG(2," V22 sector_size=%d erase_grp_size=%d\n", 
+		      csd->erase.v22.sector_size, 
+		      csd->erase.v22.erase_grp_size);
+		break;
+	case CSD_STRUCT_VER_1_2:
+	default:
+		MMC_DEBUG(2," V31 erase_grp_size=%d erase_grp_mult=%d\n", 
+		      csd->erase.v31.erase_grp_size,
+		      csd->erase.v31.erase_grp_mult);
+		break;
+		
+	}
+
+	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;
+
+	return 0;
+}
+
+int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state )
+{
+	u8 *buf = request->response;
+
+	if ( request->result )        return request->result;
+
+	r1->cmd    = buf[0];
+	r1->status = PARSE_U32(buf,1);
+
+	MMC_DEBUG(2," cmd=%d status=%08x\n", r1->cmd, r1->status);
+
+	if (R1_STATUS(r1->status)) {
+		if ( r1->status & R1_OUT_OF_RANGE )       return MMC_ERROR_OUT_OF_RANGE;
+		if ( r1->status & R1_ADDRESS_ERROR )      return MMC_ERROR_ADDRESS;
+		if ( r1->status & R1_BLOCK_LEN_ERROR )    return MMC_ERROR_BLOCK_LEN;
+		if ( r1->status & R1_ERASE_SEQ_ERROR )    return MMC_ERROR_ERASE_SEQ;
+		if ( r1->status & R1_ERASE_PARAM )        return MMC_ERROR_ERASE_PARAM;
+		if ( r1->status & R1_WP_VIOLATION )       return MMC_ERROR_WP_VIOLATION;
+		if ( r1->status & R1_CARD_IS_LOCKED )     return MMC_ERROR_CARD_IS_LOCKED;
+		if ( r1->status & R1_LOCK_UNLOCK_FAILED ) return MMC_ERROR_LOCK_UNLOCK_FAILED;
+		if ( r1->status & R1_COM_CRC_ERROR )      return MMC_ERROR_COM_CRC;
+		if ( r1->status & R1_ILLEGAL_COMMAND )    return MMC_ERROR_ILLEGAL_COMMAND;
+		if ( r1->status & R1_CARD_ECC_FAILED )    return MMC_ERROR_CARD_ECC_FAILED;
+		if ( r1->status & R1_CC_ERROR )           return MMC_ERROR_CC;
+		if ( r1->status & R1_ERROR )              return MMC_ERROR_GENERAL;
+		if ( r1->status & R1_UNDERRUN )           return MMC_ERROR_UNDERRUN;
+		if ( r1->status & R1_OVERRUN )            return MMC_ERROR_OVERRUN;
+		if ( r1->status & R1_CID_CSD_OVERWRITE )  return MMC_ERROR_CID_CSD_OVERWRITE;
+	}
+
+	if ( buf[0] != request->cmd ) return MMC_ERROR_HEADER_MISMATCH;
+
+	/* This should be last - it's the least dangerous error */
+	if ( R1_CURRENT_STATE(r1->status) != state ) return MMC_ERROR_STATE_MISMATCH;
+
+	return 0;
+}
+
+int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid )
+{
+	u8 *buf = request->response;
+	int i;
+
+	if ( request->result ) return request->result;
+
+	cid->mid = buf[1];
+	cid->oid = PARSE_U16(buf,2);
+	for ( i = 0 ; i < 6 ; i++ )
+		cid->pnm[i] = buf[4+i];
+	cid->pnm[6] = 0;
+	cid->prv = buf[10];
+	cid->psn = PARSE_U32(buf,11);
+	cid->mdt = buf[15];
+	
+	MMC_DEBUG(2," mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n",
+	      cid->mid, cid->oid, cid->pnm, 
+	      (cid->prv>>4), (cid->prv&0xf), 
+	      cid->psn, (cid->mdt>>4), (cid->mdt&0xf)+1997);
+
+	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;
+      	return 0;
+}
+
+int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 )
+{
+	u8 *buf = request->response;
+
+	if ( request->result ) return request->result;
+
+	r3->ocr = PARSE_U32(buf,1);
+	MMC_DEBUG(2," ocr=%08x\n", r3->ocr);
+
+	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;
+	return 0;
+}
+
+/**************************************************************************/
+
+#define KBPS 1
+#define MBPS 1000
+
+static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };
+static u32 ts_mul[] = { 0,    1000, 1200, 1300, 1500, 2000, 2500, 3000, 
+			3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };
+
+u32 mmc_tran_speed( u8 ts )
+{
+	u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];
+
+	if ( rate <= 0 ) {
+		MMC_DEBUG(0, ": error - unrecognized speed 0x%02x\n", ts);
+		return 1;
+	}
+
+	return rate;
+}
+
+/**************************************************************************/
+
+void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg, 
+		   u16 nob, u16 block_len, enum mmc_rsp_t rtype )
+{
+	dev->request.cmd       = cmd;
+	dev->request.arg       = arg;
+	dev->request.rtype     = rtype;
+	dev->request.nob       = nob;
+	dev->request.block_len = block_len;
+	dev->request.buffer    = NULL;
+	if ( nob && dev->io_request )
+		dev->request.buffer = dev->io_request->buffer;
+
+	dev->state  |= STATE_CMD_ACTIVE;
+	dev->sdrive->send_cmd(&dev->request);
+}
+
+void mmc_finish_io_request( struct mmc_dev *dev, int result )
+{
+	struct mmc_io_request *t = dev->io_request;
+	struct mmc_slot *slot = dev->slot + t->id;
+
+	dev->io_request = NULL;     // Remove the old request (the media driver may requeue)
+	if ( slot->media_driver )
+		slot->media_driver->io_request_done( t, result );
+}
+
+
+/* Only call this when there is no pending request - it unloads the media driver */
+int mmc_check_eject( struct mmc_dev *dev )
+{
+	unsigned long   flags;
+	int             state;
+	int             i;
+
+	MMC_DEBUG(2," dev state=%x\n", dev->state);
+
+	local_irq_save(flags);
+	state = dev->state;
+	dev->state = state & ~STATE_EJECT;
+	local_irq_restore(flags);
+
+	if ( !(state & STATE_EJECT) )
+		return 0;
+
+	for ( i = 0 ; i < dev->num_slots ; i++ ) {
+		struct mmc_slot *slot = dev->slot + i;
+
+		if ( slot->flags & MMC_SLOT_FLAG_EJECT ) {
+			slot->state = CARD_STATE_EMPTY;
+			if ( slot->media_driver ) {
+				slot->media_driver->unload( slot );
+				slot->media_driver = NULL;
+			}
+			slot->flags &= ~MMC_SLOT_FLAG_EJECT;
+			run_sbin_mmc_hotplug(dev,i,0);
+		}
+	}
+	return 1;
+}
+
+int mmc_check_insert( struct mmc_dev *dev )
+{
+	unsigned long   flags;
+	int             state;
+	int             i;
+	int             card_count = 0;
+
+	MMC_DEBUG(2," dev state=%x\n", dev->state);
+
+	local_irq_save(flags);
+	state = dev->state;
+	dev->state = state & ~STATE_INSERT;
+	local_irq_restore(flags);
+
+	if ( !(state & STATE_INSERT) ) 
+		return 0;
+
+	for ( i = 0 ; i < dev->num_slots ; i++ ) {
+		struct mmc_slot *slot = dev->slot + i;
+
+		if ( slot->flags & MMC_SLOT_FLAG_INSERT ) {
+			if  (!dev->sdrive->is_empty(i)) {
+				slot->state = CARD_STATE_IDLE;
+				card_count++;
+			}
+			slot->flags &= ~MMC_SLOT_FLAG_INSERT;
+		}
+	}
+	return card_count;
+}
+
+/******************************************************************
+ *
+ * Hotplug callback card insertion/removal
+ *
+ ******************************************************************/
+
+#ifdef CONFIG_HOTPLUG
+
+extern char hotplug_path[];
+extern int call_usermodehelper(char *path, char **argv, char **envp);
+
+static void run_sbin_hotplug(struct mmc_dev *dev, int id, int insert)
+{
+	int i;
+	char *argv[3], *envp[8];
+	char media[64], slotnum[16];
+
+	if (!hotplug_path[0])
+		return;
+
+	MMC_DEBUG(0,": hotplug_path=%s id=%d insert=%d\n", hotplug_path, id, insert);
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "mmc";
+	argv[i] = 0;
+
+	/* minimal command environment */
+	i = 0;
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	
+	/* other stuff we want to pass to /sbin/hotplug */
+	sprintf(slotnum, "SLOT=%d", id );
+	if ( dev->slot[id].media_driver && dev->slot[id].media_driver->name )
+		sprintf(media, "MEDIA=%s", dev->slot[id].media_driver->name );
+	else
+		sprintf(media, "MEDIA=unknown");
+
+	envp[i++] = slotnum;
+	envp[i++] = media;
+
+	if (insert)
+		envp[i++] = "ACTION=add";
+	else
+		envp[i++] = "ACTION=remove";
+	envp[i] = 0;
+
+	call_usermodehelper (argv [0], argv, envp);
+}
+
+static void mmc_hotplug_task_handler( void *nr )
+{
+	int insert = ((int) nr) & 0x01;
+	int id     = ((int) nr) >> 1;
+	MMC_DEBUG(2," id=%d insert=%d\n", id, insert );
+	run_sbin_hotplug(&g_mmc_dev, id, insert );
+}
+
+static struct tq_struct mmc_hotplug_task = {
+	routine:  mmc_hotplug_task_handler
+};
+
+void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert )
+{
+	mmc_hotplug_task.data = (void *) ((id << 1) | insert);
+	schedule_task( &mmc_hotplug_task );
+}
+
+#else
+void run_sbin_mmc_hotplug(struct sleeve_dev *sdev, int insert) { }
+#endif /* CONFIG_HOTPLUG */
+
+
+/******************************************************************
+ * Common processing tasklet
+ * Everything gets serialized through this
+ ******************************************************************/
+
+static void mmc_tasklet_action(unsigned long data)
+{
+	struct mmc_dev *dev = (struct mmc_dev *)data;
+	unsigned long   flags;
+	int             state;
+
+	MMC_DEBUG(2,": dev=%p flags=%02x\n", dev, dev->state);
+
+	/* Grab the current working state */
+	local_irq_save(flags);
+	state = dev->state;
+	if ( state & STATE_CMD_DONE )
+		dev->state = state & ~(STATE_CMD_DONE | STATE_CMD_ACTIVE);
+	local_irq_restore(flags);
+
+	/* If there is an active command, don't do anything */
+	if ( (state & STATE_CMD_ACTIVE) && !(state & STATE_CMD_DONE) )
+		return;
+
+	if ( dev->protocol )
+		dev->protocol(dev,state);
+}
+
+/******************************************************************
+ * Callbacks from low-level driver
+ * These run at interrupt time
+ ******************************************************************/
+
+void mmc_cmd_complete(struct mmc_request *request)
+{
+	MMC_DEBUG(2,": request=%p retval=%d\n", request, request->result);
+	g_mmc_dev.state |= STATE_CMD_DONE;
+	if ( !g_mmc_dev.suspended )
+		tasklet_schedule(&g_mmc_dev.task);
+}
+
+void mmc_insert(int slot)
+{
+	MMC_DEBUG(2,": %d\n", slot);
+	g_mmc_dev.state |= STATE_INSERT;
+	g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_INSERT;
+	if ( !g_mmc_dev.suspended )
+		tasklet_schedule(&g_mmc_dev.task);
+}
+
+void mmc_eject(int slot)
+{
+	MMC_DEBUG(2,": %d\n", slot);
+	g_mmc_dev.state |= STATE_EJECT;
+	g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_EJECT;
+	if ( !g_mmc_dev.suspended )
+		tasklet_schedule(&g_mmc_dev.task);
+}
+
+EXPORT_SYMBOL(mmc_cmd_complete);
+EXPORT_SYMBOL(mmc_insert);
+EXPORT_SYMBOL(mmc_eject);
+
+/******************************************************************
+ * Called from the media handler
+ ******************************************************************/
+
+void mmc_handle_io_request( struct mmc_io_request *t )
+{
+	MMC_DEBUG(2," id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+	      t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer);
+	
+	if ( g_mmc_dev.io_request ) {
+		MMC_DEBUG(0,": error! io_request in progress\n");
+		return;
+	}
+	
+	g_mmc_dev.io_request = t;
+	tasklet_schedule(&g_mmc_dev.task);
+}
+
+EXPORT_SYMBOL(mmc_handle_io_request);
+
+/******************************************************************
+ *  Media handlers
+ *  Allow different drivers to register a media handler
+ ******************************************************************/
+
+static LIST_HEAD(mmc_media_drivers);
+
+int mmc_match_media_driver( struct mmc_slot *slot )
+{
+	struct list_head *item;
+
+	MMC_DEBUG(2,": slot=%p\n", slot);
+
+	for ( item = mmc_media_drivers.next ; item != &mmc_media_drivers ; item = item->next ) {
+		struct mmc_media_driver *drv = list_entry(item, struct mmc_media_driver, node );
+		if ( drv->probe(slot) ) {
+			slot->media_driver = drv;
+			drv->load(slot);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int mmc_register_media_driver( struct mmc_media_driver *drv )
+{
+	list_add_tail( &drv->node, &mmc_media_drivers );
+	return 0;
+}
+
+void mmc_unregister_media_driver( struct mmc_media_driver *drv )
+{
+	list_del(&drv->node);
+}
+
+EXPORT_SYMBOL(mmc_register_media_driver);
+EXPORT_SYMBOL(mmc_unregister_media_driver);
+
+/******************************************************************/
+
+int mmc_register_slot_driver( struct mmc_slot_driver *sdrive, int num_slots )
+{
+	int i;
+	int retval;
+
+	MMC_DEBUG(2," max=%d ocr=0x%08x\n", num_slots, sdrive->ocr);
+
+	if ( num_slots > MMC_MAX_SLOTS ) {
+		printk(KERN_CRIT "%s: illegal num of slots %d\n", __FUNCTION__, num_slots );
+		return -ENOMEM;
+	}
+
+	if ( g_mmc_dev.sdrive ) {
+		printk(KERN_ALERT "%s: slot in use\n", __FUNCTION__);
+		return -EBUSY;
+	}
+
+	g_mmc_dev.sdrive    = sdrive;
+	g_mmc_dev.num_slots = num_slots;
+
+	for ( i = 0 ; i < num_slots ; i++ ) {
+		struct mmc_slot *slot = &g_mmc_dev.slot[i];
+		memset(slot,0,sizeof(struct mmc_slot));
+		slot->id = i;
+		slot->state = CARD_STATE_EMPTY;
+	}
+	retval = sdrive->init();
+	if ( retval )
+		return retval;
+
+	/* Generate insert events for cards */
+	for ( i = 0 ; i < num_slots ; i++ )
+		if ( !sdrive->is_empty(i) )
+			mmc_insert(i);
+	return 0;
+}
+
+void mmc_unregister_slot_driver( struct mmc_slot_driver *sdrive )
+{
+	MMC_DEBUG(2,"\n");
+
+#if 0
+	int i;
+	for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ )
+		mmc_eject(i);
+#endif
+	if ( sdrive == g_mmc_dev.sdrive ) {
+		g_mmc_dev.sdrive->cleanup();
+		g_mmc_dev.sdrive = NULL;
+	}
+}
+
+EXPORT_SYMBOL(mmc_register_slot_driver);
+EXPORT_SYMBOL(mmc_unregister_slot_driver);
+
+/******************************************************************/
+
+static struct pm_dev *mmc_pm_dev;
+
+static int mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
+{
+	int i;
+	MMC_DEBUG(0,": pm callback %d\n", req );
+
+	switch (req) {
+	case PM_SUSPEND: /* Enter D1-D3 */
+		g_mmc_dev.suspended = 1;
+                break;
+	case PM_RESUME:  /* Enter D0 */
+		if ( g_mmc_dev.suspended ) {
+			g_mmc_dev.suspended = 0;
+			g_mmc_dev.state = 0;     // Clear the old state
+			for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) {
+				mmc_eject(i);
+				if ( !g_mmc_dev.sdrive->is_empty(i) )
+					mmc_insert(i);
+			}
+		}
+		break;
+        }
+        return 0;
+}
+
+/******************************************************************
+ * TODO: These would be better handled by driverfs
+ * For the moment, we'll just eject and insert everything
+ ******************************************************************/
+
+int mmc_do_eject(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp)
+{
+	mmc_eject(0);
+	return 0;
+}
+
+int mmc_do_insert(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp)
+{
+	mmc_insert(0);
+	return 0;
+}
+
+
+static struct ctl_table mmc_sysctl_table[] =
+{
+#ifdef CONFIG_MMC_DEBUG
+	{ 1, "debug", &g_mmc_debug, sizeof(int), 0666, NULL, &proc_dointvec },
+#endif
+	{ 2, "eject", NULL, 0, 0600, NULL, &mmc_do_eject },
+	{ 3, "insert", NULL, 0, 0600, NULL, &mmc_do_insert },
+	{0}
+};
+
+static struct ctl_table mmc_dir_table[] =
+{
+	{CTL_BUS_MMC, "mmc", NULL, 0, 0555, mmc_sysctl_table},
+	{0}
+};
+
+static struct ctl_table bus_dir_table[] = 
+{
+	{CTL_BUS, "bus", NULL, 0, 0555, mmc_dir_table},
+        {0}
+};
+
+static struct ctl_table_header *mmc_sysctl_header;
+
+static int mmc_proc_read_device(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct mmc_dev *dev = (struct mmc_dev *)data;
+        char *p = page;
+        int len = 0;
+	int i;
+
+	if (!dev || !dev->sdrive)
+		return 0;
+
+	for ( i = 0 ; i < dev->num_slots ; i++ ) {
+		struct mmc_slot *slot = &dev->slot[i];
+
+		p += sprintf(p, "Slot #%d\n", i);
+		p += sprintf(p, "  State %s (%d)\n", card_state_to_string(slot->state), slot->state);
+
+		if ( slot->state != CARD_STATE_EMPTY ) {
+			p += sprintf(p, "  Media %s\n", (slot->media_driver ? slot->media_driver->name : "unknown"));
+			p += sprintf(p, "  CID mid=%d\n", slot->cid.mid);
+			p += sprintf(p, "      oid=%d\n", slot->cid.oid);
+			p += sprintf(p, "      pnm=%s\n", slot->cid.pnm);
+			p += sprintf(p, "      prv=%d.%d\n", slot->cid.prv>>4, slot->cid.prv&0xf);
+			p += sprintf(p, "      psn=0x%08x\n", slot->cid.psn);
+			p += sprintf(p, "      mdt=%d/%d\n", slot->cid.mdt>>4, (slot->cid.mdt&0xf)+1997);
+
+			p += sprintf(p, "  CSD csd_structure=%d\n", slot->csd.csd_structure);
+			p += sprintf(p, "      spec_vers=%d\n", slot->csd.spec_vers);
+			p += sprintf(p, "      taac=0x%02x\n", slot->csd.taac);
+			p += sprintf(p, "      nsac=0x%02x\n", slot->csd.nsac);
+			p += sprintf(p, "      tran_speed=0x%02x\n", slot->csd.tran_speed);
+			p += sprintf(p, "      ccc=0x%04x\n", slot->csd.ccc);
+			p += sprintf(p, "      read_bl_len=%d\n", slot->csd.read_bl_len);
+			p += sprintf(p, "      read_bl_partial=%d\n", slot->csd.read_bl_partial);
+			p += sprintf(p, "      write_blk_misalign=%d\n", slot->csd.write_blk_misalign);
+			p += sprintf(p, "      read_blk_misalign=%d\n", slot->csd.read_blk_misalign);
+			p += sprintf(p, "      dsr_imp=%d\n", slot->csd.dsr_imp);
+			p += sprintf(p, "      c_size=%d\n", slot->csd.c_size);
+			p += sprintf(p, "      vdd_r_curr_min=%d\n", slot->csd.vdd_r_curr_min);
+			p += sprintf(p, "      vdd_r_curr_max=%d\n", slot->csd.vdd_r_curr_max);
+			p += sprintf(p, "      vdd_w_curr_min=%d\n", slot->csd.vdd_w_curr_min);
+			p += sprintf(p, "      vdd_w_curr_max=%d\n", slot->csd.vdd_w_curr_max);
+			p += sprintf(p, "      c_size_mult=%d\n", slot->csd.c_size_mult);
+			p += sprintf(p, "      wp_grp_size=%d\n", slot->csd.wp_grp_size);
+			p += sprintf(p, "      wp_grp_enable=%d\n", slot->csd.wp_grp_enable);
+			p += sprintf(p, "      default_ecc=%d\n", slot->csd.default_ecc);
+			p += sprintf(p, "      r2w_factor=%d\n", slot->csd.r2w_factor);
+			p += sprintf(p, "      write_bl_len=%d\n", slot->csd.write_bl_len);
+			p += sprintf(p, "      write_bl_partial=%d\n", slot->csd.write_bl_partial);
+			p += sprintf(p, "      file_format_grp=%d\n", slot->csd.file_format_grp);
+			p += sprintf(p, "      copy=%d\n", slot->csd.copy);
+			p += sprintf(p, "      perm_write_protect=%d\n", slot->csd.perm_write_protect);
+			p += sprintf(p, "      tmp_write_protect=%d\n", slot->csd.tmp_write_protect);
+			p += sprintf(p, "      file_format=%d\n", slot->csd.file_format);
+			p += sprintf(p, "      ecc=%d\n", slot->csd.ecc);
+			switch (slot->csd.csd_structure) {
+			case CSD_STRUCT_VER_1_0:
+			case CSD_STRUCT_VER_1_1:
+				p += sprintf(p, "      sector_size=%d\n", slot->csd.erase.v22.sector_size);
+				p += sprintf(p, "      erase_grp_size=%d\n", slot->csd.erase.v22.erase_grp_size);
+				break;
+			case CSD_STRUCT_VER_1_2:
+			default:
+				p += sprintf(p, "      erase_grp_size=%d\n", slot->csd.erase.v31.erase_grp_size);
+				p += sprintf(p, "      erase_grp_mult=%d\n", slot->csd.erase.v31.erase_grp_mult);
+				break;
+			}
+		}
+	}
+
+        len = (p - page) - off;
+	*start = page + off;
+        return len;
+}
+
+/******************************************************************/
+
+void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags );
+extern struct mmc_media_module media_module;
+extern struct mmc_slot_module slot_module;
+static int __init mmc_init(void) 
+{
+	MMC_DEBUG(1,"\n");
+	
+	mmc_sysctl_header = register_sysctl_table(bus_dir_table, 0 );
+
+	tasklet_init(&g_mmc_dev.task,mmc_tasklet_action,(unsigned long)&g_mmc_dev);
+	g_mmc_dev.protocol = mmc_protocol_single_card;
+
+#ifdef CONFIG_PROC_FS
+	proc_mmc_dir = proc_mkdir("mmc", proc_bus);
+	if ( proc_mmc_dir )
+		create_proc_read_entry("device", 0, proc_mmc_dir, mmc_proc_read_device, &g_mmc_dev);
+#endif
+
+	mmc_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, mmc_pm_callback);
+
+	media_module.init();
+	slot_module.init();
+	return 0;
+}
+
+static void __exit mmc_exit(void)
+{
+	MMC_DEBUG(1,"\n");
+
+	media_module.cleanup();
+	slot_module.cleanup();
+
+	unregister_sysctl_table(mmc_sysctl_header);
+
+	tasklet_kill(&g_mmc_dev.task);
+
+#ifdef CONFIG_PROC_FS
+	if ( proc_mmc_dir ) {
+		remove_proc_entry("device", proc_mmc_dir);
+		remove_proc_entry("mmc", proc_bus);
+	}
+#endif
+
+	pm_unregister(mmc_pm_dev);
+}
+
+module_init(mmc_init);
+module_exit(mmc_exit);
+
+
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_core.h linux-2.4.26/drivers/mmc/mmc_core.h
--- linux-2.4.26.org/drivers/mmc/mmc_core.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_core.h	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,68 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2004/06/24 10:45:44 $ 
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_CORE_H
+#define MMC_MMC_CORE_H
+
+#include <linux/mmc/mmc_ll.h>
+#include "mmc_media.h"
+
+#define ID_TO_RCA(x) ((x)+1)
+
+struct mmc_dev {
+	struct mmc_slot_driver   *sdrive;
+	struct mmc_slot           slot[MMC_MAX_SLOTS];
+	struct mmc_request        request;               // Active request to the low-level driver
+	struct mmc_io_request    *io_request;            // Active transfer request from the high-level media io
+	struct tasklet_struct     task;
+	int    num_slots;                 // Copied from the slot driver; used when slot driver shuts down
+
+	/* State maintenance */
+	int    state;  
+	int    suspended;
+	void (*protocol)(struct mmc_dev *, int);
+};
+
+char * mmc_result_to_string( int );
+int    mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd );
+int    mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state );
+int    mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid );
+int    mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 );
+
+void   mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg, 
+		     u16 nob, u16 block_len, enum mmc_rsp_t rtype );
+void   mmc_finish_io_request( struct mmc_dev *dev, int result );
+int    mmc_check_eject( struct mmc_dev *dev );
+int    mmc_check_insert( struct mmc_dev *dev );
+u32    mmc_tran_speed( u8 ts );
+int    mmc_match_media_driver( struct mmc_slot *slot );
+void   run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert);
+
+static inline void mmc_simple_cmd( struct mmc_dev *dev, int cmd, u32 arg, enum mmc_rsp_t rtype )
+{
+	mmc_send_cmd( dev, cmd, arg, 0, 0, rtype );
+}
+
+#endif  /* MMC_MMC_CORE_H */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_media.c linux-2.4.26/drivers/mmc/mmc_media.c
--- linux-2.4.26.org/drivers/mmc/mmc_media.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_media.c	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,502 @@
+/*
+ * Block driver for media (i.e., flash cards)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Author:  Andrew Christian
+ *          28 May 2002
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/fs.h>     /* everything... */
+#include <linux/errno.h>  /* error codes */
+#include <linux/types.h>  /* size_t */
+#include <linux/fcntl.h>  /* O_ACCMODE */
+#include <linux/hdreg.h>  /* HDIO_GETGEO */
+#include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "mmc_media.h"
+
+#define MAJOR_NR mmc_major /* force definitions on in blk.h */
+static int mmc_major; /* must be declared before including blk.h */
+
+#define MMC_SHIFT           3             /* max 8 partitions per card */
+
+#define DEVICE_NR(device)   (MINOR(device)>>MMC_SHIFT)
+#define DEVICE_NAME         "mmc"         /* name for messaging */
+#define DEVICE_INTR         mmc_intrptr   /* pointer to the bottom half */
+#define DEVICE_NO_RANDOM                  /* no entropy to contribute */
+#define DEVICE_REQUEST      mmc_media_request
+#define DEVICE_OFF(d) /* do-nothing */
+
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+
+static int rahead     = 8;
+static int maxsectors = 4;
+
+MODULE_PARM(maxsectors,"i");
+MODULE_PARM_DESC(maxsectors,"Maximum number of sectors for a single request");
+MODULE_PARM(rahead,"i");
+MODULE_PARM_DESC(rahead,"Default sector read ahead");
+
+#define MMC_NDISK	(MMC_MAX_SLOTS << MMC_SHIFT)
+
+/* 
+   Don't bother messing with blksize_size....it gets changed by various filesystems.
+   You're better off dealing with arbitrary blksize's
+*/ 
+static int              mmc_blk[MMC_NDISK];  /* Used for hardsect_size - should be 512 bytes */
+static int              mmc_max[MMC_NDISK];  /* Used for max_sectors[] - limit size of individual request */
+
+static int              mmc_sizes[MMC_NDISK];        /* Used in gendisk - gives whole size of partition */
+static struct hd_struct mmc_partitions[MMC_NDISK];   /* Used in gendisk - gives particular partition information */
+
+static char             mmc_gendisk_flags;
+static devfs_handle_t   mmc_devfs_handle;
+
+// There is one mmc_media_dev per inserted card
+struct mmc_media_dev {
+	int              usage;
+	struct mmc_slot *slot;
+	spinlock_t       lock;
+	int              changed;
+	long             nr_sects;   // In total number of sectors
+
+	int              read_block_len;      // Valid read block length
+	int              write_block_len;     // Valid write block length
+};
+
+static struct mmc_media_dev   g_media_dev[MMC_MAX_SLOTS];
+static struct mmc_io_request  g_io_request;
+static int                    g_busy;
+
+static struct gendisk mmc_gendisk = {
+        major:	        0,               /* major number dynamically assigned */
+	major_name:	DEVICE_NAME,
+	minor_shift:	MMC_SHIFT,	 /* shift to get device number */
+	max_p:	        1 << MMC_SHIFT,	 /* Number of partiions */
+	/* The remainder will be filled in dynamically */
+};
+
+/*************************************************************************/
+/* TODO: O_EXCL, O_NDELAY, invalidate_buffers */
+static int mmc_media_open( struct inode *inode, struct file *filp )
+{
+	struct mmc_media_dev *dev;
+	int num = DEVICE_NR(inode->i_rdev);
+
+	MMC_DEBUG(1,": num=%d\n", num);
+
+	if ( num >= MMC_MAX_SLOTS) 
+		return -ENODEV;
+
+	dev = &g_media_dev[num];
+	if ( !dev->slot ) 
+		return -ENODEV;
+
+	spin_lock(&dev->lock);
+	if (!dev->usage)
+		check_disk_change(inode->i_rdev);
+	dev->usage++;
+	MOD_INC_USE_COUNT;
+	spin_unlock(&dev->lock);
+	return 0;
+}
+
+static int mmc_media_release( struct inode *inode, struct file *filep )
+{
+	struct mmc_media_dev *dev = &g_media_dev[DEVICE_NR(inode->i_rdev)];
+
+	MMC_DEBUG(1,": num=%d\n", DEVICE_NR(inode->i_rdev));
+
+	spin_lock(&dev->lock);
+	dev->usage--;
+	/* Is this worth doing? */
+	if (!dev->usage) {	
+		fsync_dev(inode->i_rdev);
+		invalidate_buffers(inode->i_rdev);
+	}
+	MOD_DEC_USE_COUNT;
+	spin_unlock(&dev->lock);
+	return 0;
+}
+
+static int mmc_media_revalidate(kdev_t i_rdev)
+{
+	int index, max_p, start, i;
+	struct mmc_media_dev *dev;
+
+	index = DEVICE_NR(i_rdev);
+	MMC_DEBUG(2,": index=%d\n", index);
+
+	max_p = mmc_gendisk.max_p;
+	start = index << MMC_SHIFT;
+	dev   = &g_media_dev[index];
+
+	for ( i = max_p - 1 ; i >= 0 ; i-- ) {
+		int item = start + i;
+		invalidate_device(MKDEV(mmc_major,item),1);
+		mmc_gendisk.part[item].start_sect = 0;
+		mmc_gendisk.part[item].nr_sects   = 0;
+		/* TODO: Fix the blocksize? */
+	}
+
+	register_disk(&mmc_gendisk, i_rdev, 1 << MMC_SHIFT, mmc_gendisk.fops, dev->nr_sects);
+	return 0;
+}
+
+static int mmc_media_ioctl (struct inode *inode, struct file *filp,
+			    unsigned int cmd, unsigned long arg)
+{
+	int num = DEVICE_NR(inode->i_rdev);
+	int size;
+	struct hd_geometry geo;
+
+	MMC_DEBUG(1," ioctl 0x%x 0x%lx\n", cmd, arg);
+
+	switch(cmd) {
+	case BLKGETSIZE:
+		/* Return the device size, expressed in sectors */
+		/* Not really necessary, but this is faster than walking the gendisk list */
+		if (!access_ok(VERIFY_WRITE, arg, sizeof(long)))
+			return -EFAULT;
+		return put_user(mmc_partitions[MINOR(inode->i_rdev)].nr_sects, (long *)arg);
+
+	case BLKRRPART: /* re-read partition table */
+		if (!capable(CAP_SYS_ADMIN)) 
+			return -EACCES;
+		return mmc_media_revalidate(inode->i_rdev);
+
+	case HDIO_GETGEO:
+		if (!access_ok(VERIFY_WRITE, arg, sizeof(geo)))
+			return -EFAULT;
+		/* Grab the size from the 0 partition for this minor */
+		/* TODO: is this the right thing?  Or should we do it by partition??? */
+		size = mmc_sizes[num << MMC_SHIFT] / mmc_blk[num << MMC_SHIFT];
+		geo.cylinders = (size & ~0x3f) >> 6;
+		geo.heads     = 4;
+		geo.sectors   = 16;
+		geo.start     = mmc_partitions[MINOR(inode->i_rdev)].start_sect;
+		if (copy_to_user((void *) arg, &geo, sizeof(geo)))
+			return -EFAULT;
+		return 0;
+
+	default:
+		return blk_ioctl(inode->i_rdev, cmd, arg);
+	}
+
+	return -ENOTTY; /* should never get here */
+}
+
+static int mmc_media_check_change(kdev_t i_rdev) 
+{
+	int                   index, retval;
+	struct mmc_media_dev *dev;
+	unsigned long         flags;
+
+	index = DEVICE_NR(i_rdev);
+	MMC_DEBUG(2," device=%d\n", index);
+	if (index >= MMC_MAX_SLOTS) 
+		return 0;
+
+	dev = &g_media_dev[index];
+
+	spin_lock_irqsave(&dev->lock, flags);
+	retval = (dev->changed ? 1 : 0);
+	dev->changed = 0;
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return retval;
+}
+
+static struct mmc_media_dev * mmc_media_locate_device(const struct request *req)
+{
+	int num = DEVICE_NR(req->rq_dev);
+	if ( num >= MMC_MAX_SLOTS) {
+		static int count = 0;
+		if (count++ < 5) /* print the message at most five times */
+			printk(KERN_WARNING "mmc: request for unknown device\n");
+		return NULL;
+	}
+	return &g_media_dev[num];
+}
+
+static int mmc_media_transfer( struct mmc_media_dev *dev, const struct request *req )
+{
+	int minor = MINOR(req->rq_dev);
+	unsigned long flags;
+
+	MMC_DEBUG(2,": minor=%d\n", minor);
+
+	if ( req->sector + req->current_nr_sectors > mmc_partitions[minor].nr_sects ) {
+		static int count = 0;
+		if (count++ < 5)
+			printk(KERN_WARNING "%s: request past end of partition\n", __FUNCTION__);
+		return 0;
+	}
+	
+	spin_lock_irqsave(&dev->lock, flags);
+
+	g_io_request.id         = DEVICE_NR(req->rq_dev);
+	g_io_request.cmd        = req->cmd;
+	g_io_request.sector     = mmc_partitions[minor].start_sect + req->sector;
+	g_io_request.nr_sectors = req->current_nr_sectors;
+	g_io_request.block_len  = mmc_blk[minor];
+	g_io_request.buffer     = req->buffer;
+
+	MMC_DEBUG(2,": id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+	      g_io_request.id, g_io_request.cmd, g_io_request.sector, g_io_request.nr_sectors,
+	      g_io_request.block_len, g_io_request.buffer );
+
+	mmc_handle_io_request(&g_io_request);
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 1;
+}
+
+static void mmc_media_request( request_queue_t *q )
+{
+	struct mmc_media_dev *dev;
+
+	if ( g_busy )
+		return;
+
+	while(1) {
+		INIT_REQUEST;  /* returns when queue is empty */
+		dev = mmc_media_locate_device(CURRENT);
+		if ( !dev ) {
+			end_request(0);
+			continue;
+		}
+
+		MMC_DEBUG(2," (%p): cmd %i sec %li (nr. %li)\n", CURRENT,
+		      CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors);
+
+		if ( mmc_media_transfer(dev,CURRENT) ) {
+			g_busy = 1;
+			return;
+		}
+		end_request(0);  /* There was a problem with the request */
+	}
+}
+
+static void mmc_media_transfer_done( struct mmc_io_request *trans, int result )
+{
+	unsigned long flags;
+	MMC_DEBUG(3,": result=%d\n", result);
+	spin_lock_irqsave(&io_request_lock, flags);
+	end_request(result);
+	g_busy = 0;
+	if (!QUEUE_EMPTY)
+		mmc_media_request(NULL);  // Start the next transfer
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+
+static struct block_device_operations mmc_bdops = {
+	open:               mmc_media_open,
+	release:            mmc_media_release,
+	ioctl:              mmc_media_ioctl,
+	check_media_change: mmc_media_check_change,
+	revalidate:         mmc_media_revalidate
+};
+
+/******************************************************************/
+/* TODO:
+   We have a race condition if two slots need to be revalidated at the same
+   time.  Perhaps we should walk the list of devices and look for change
+   flags?
+*/
+
+static void mmc_media_load_task_handler( void *nr )
+{
+	int slot_id = (int) nr;
+	MMC_DEBUG(2," slot_id=%d\n", slot_id );
+	mmc_media_revalidate(MKDEV(mmc_major,(slot_id<<MMC_SHIFT)));
+}
+
+static struct tq_struct mmc_media_load_task = {
+	routine:  mmc_media_load_task_handler
+};
+
+static void mmc_media_load( struct mmc_slot *slot )
+{
+	unsigned long flags;
+	struct mmc_media_dev *dev  = &g_media_dev[slot->id];
+	int i;
+
+	long nr_sects;
+	int  write_block_len;
+	int  read_block_len;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	nr_sects        = (1 + slot->csd.c_size) * (1 << (slot->csd.c_size_mult + 2));
+	write_block_len = 1 << slot->csd.write_bl_len;
+	read_block_len  = 1 << slot->csd.read_bl_len;
+
+	MOD_INC_USE_COUNT;
+	MMC_DEBUG(1, " slot=%p nr_sect=%ld write_block_length=%d read_block_len=%d\n", 
+	      slot, nr_sects, write_block_len, read_block_len );
+
+	dev->slot            = slot;
+	dev->nr_sects        = nr_sects;
+	dev->read_block_len  = read_block_len;
+	dev->write_block_len = write_block_len;
+	dev->changed         = 1;
+	mmc_gendisk.nr_real++;
+
+	/* Fix up the block size to match read_block_len */
+	/* TODO: can we really do this?  Right now we're affecting blksize_size and hardsect_size */
+	for ( i = 0 ; i < (1 << MMC_SHIFT) ; i++ )
+		mmc_blk[(slot->id << MMC_SHIFT) + i] = read_block_len;
+
+	mmc_media_load_task.data = (void *) slot->id;
+	schedule_task( &mmc_media_load_task );
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* TODO: This is a problem area.  We've lost our card, so we'd like
+   to flush all outstanding buffers and requests, remove the partitions from
+   the file system, and generally shut everything down.
+*/
+
+static void mmc_media_unload( struct mmc_slot *slot )
+{
+	unsigned long flags;
+	struct mmc_media_dev *dev = &g_media_dev[slot->id];
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+//	for ( i = 0 ; i < MMC_SHIFT ; i++ )
+//		fsync_dev(MKDEV(mmc_major,slot->id,i));
+
+	MOD_DEC_USE_COUNT;
+	MMC_DEBUG(1," slot=%p id=%d\n", slot, slot->id);
+
+	dev->slot            = NULL;
+	dev->nr_sects        = 0;
+	dev->changed         = 1;
+	mmc_gendisk.nr_real--;
+
+	mmc_media_load_task.data = (void *) slot->id;
+	schedule_task( &mmc_media_load_task );
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/* 
+   Called once the device has a valid CSD structure
+   In the future this should determine what type of card we have
+   For the moment, everything is a memory card 
+*/
+
+static int mmc_media_probe( struct mmc_slot *slot )
+{
+	return 1;
+}
+
+static struct mmc_media_driver mmc_driver = {
+	name:            "flash",
+	load:            mmc_media_load,
+	unload:          mmc_media_unload,
+	probe:           mmc_media_probe,
+	io_request_done: mmc_media_transfer_done,
+};
+
+/******************************************************************/
+
+static int __init mmc_media_init( void )
+{
+	int i, result;
+	MMC_DEBUG(0,"\n");
+
+	mmc_devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
+	if (!mmc_devfs_handle) return -EBUSY;
+
+	result = devfs_register_blkdev(mmc_major, DEVICE_NAME, &mmc_bdops);
+	if (result < 0) {
+		printk(KERN_WARNING "Unable to get major %d for MMC media\n", mmc_major);
+		return result;
+	}
+
+	if ( !mmc_major ) mmc_major = result;
+
+	MMC_DEBUG(1,"mmc_major[%x]\n", mmc_major);
+
+	/* Set up global block arrays */
+	read_ahead[mmc_major]    = rahead;
+	for(i=0 ; i < MMC_NDISK; i++)
+		mmc_blk[i] = 512;
+	hardsect_size[mmc_major] = mmc_blk;
+	for(i=0; i < MMC_NDISK; i++)
+		mmc_max[i] = maxsectors;
+	max_sectors[mmc_major]   = mmc_max;
+
+	/* Start with zero-sized partitions : we'll fix this later */
+	memset(mmc_sizes, 0, sizeof(int) * MMC_NDISK);
+	blk_size[mmc_major] = mmc_sizes;
+
+	/* Fix up the gendisk structure */
+	mmc_gendisk.part    = mmc_partitions;
+	mmc_gendisk.sizes   = mmc_sizes;
+	mmc_gendisk.nr_real = 0;
+	mmc_gendisk.de_arr  = &mmc_devfs_handle;
+	mmc_gendisk.flags   = &mmc_gendisk_flags;
+	mmc_gendisk.fops    = &mmc_bdops;
+
+	/* Add ourselves to the global list */
+	mmc_gendisk.major = mmc_major;
+	add_gendisk(&mmc_gendisk);
+	
+	blk_init_queue(BLK_DEFAULT_QUEUE(mmc_major), DEVICE_REQUEST);
+	return mmc_register_media_driver(&mmc_driver);
+}
+
+static void __exit mmc_media_cleanup( void )
+{
+	int i;
+	MMC_DEBUG(0,"\n");
+
+	flush_scheduled_tasks();
+	unregister_blkdev(mmc_major, DEVICE_NAME);
+
+	for ( i = 0 ; i < MMC_NDISK; i++ )
+		fsync_dev(MKDEV(mmc_major,i));
+
+	mmc_unregister_media_driver(&mmc_driver);
+
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(mmc_major));
+
+	blk_size[mmc_major]      = NULL;
+	hardsect_size[mmc_major] = NULL;
+	max_sectors[mmc_major]   = NULL;
+
+	del_gendisk(&mmc_gendisk);
+
+	devfs_unregister(mmc_devfs_handle);
+}
+
+struct mmc_media_module media_module = {
+	init:    mmc_media_init,
+	cleanup: mmc_media_cleanup
+};
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_media.h linux-2.4.26/drivers/mmc/mmc_media.h
--- linux-2.4.26.org/drivers/mmc/mmc_media.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_media.h	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,85 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2004/06/24 10:45:44 $ 
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_MEDIA_H
+#define MMC_MMC_MEDIA_H
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+
+#include <linux/mmc/mmc_protocol.h>
+
+/* Set an upper bound for how many cards we'll support */
+/* This is used only for static array initialization */
+#define MMC_MAX_SLOTS   2
+
+#define MMC_SLOT_FLAG_INSERT  (1<<0)
+#define MMC_SLOT_FLAG_EJECT   (1<<1)
+
+struct mmc_media_driver;
+
+struct mmc_slot {
+	int             id;     /* Card index */
+	/* Card specific information */
+	struct mmc_cid  cid;
+	struct mmc_csd  csd;
+
+	enum card_state state;  /* empty, ident, ready, whatever */
+	int             flags;  /* Ejected, inserted */
+
+	/* Assigned media driver */
+	struct mmc_media_driver *media_driver;
+};
+
+struct mmc_io_request {
+	int            id;         /* Card index     */
+	int            cmd;        /* READ or WRITE  */
+	unsigned long  sector;     /* Start address  */
+	unsigned long  nr_sectors; /* Length of read */
+	unsigned long  block_len;  /* Size of sector (sanity check) */
+	char          *buffer;     /* Data buffer    */
+};
+
+/* Media driver (e.g., Flash card, I/O card...) */
+struct mmc_media_driver {
+	struct list_head   node;
+	char              *name;
+	void (*load)(struct mmc_slot *);
+	void (*unload)(struct mmc_slot *);
+	int  (*probe)(struct mmc_slot *);
+	void (*io_request_done)(struct mmc_io_request *, int result);
+};
+
+struct mmc_media_module {
+	int (*init)(void);
+	void (*cleanup)(void);
+};
+
+/* Calls made by the media driver */
+extern int  mmc_register_media_driver( struct mmc_media_driver * );
+extern void mmc_unregister_media_driver( struct mmc_media_driver * );
+extern void mmc_handle_io_request( struct mmc_io_request * );
+
+#endif  /* MMC_MMC_MEDIA_H */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_protocol.c linux-2.4.26/drivers/mmc/mmc_protocol.c
--- linux-2.4.26.org/drivers/mmc/mmc_protocol.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_protocol.c	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,427 @@
+/*
+ * MMC State machine functions
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * This part of the code is separated from mmc_core.o so we can
+ * plug in different state machines (e.g., SPI, SD)
+ *
+ * This code assumes that you have exactly one card slot, no more.
+ *
+ * Author:  Andrew Christian
+ *          6 May 2002
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+
+#include "mmc_core.h"
+
+static void * mmc_cim_default_state( struct mmc_dev *dev, int first );
+
+/******************************************************************
+ *
+ * Useful utility functions
+ *
+ ******************************************************************/
+
+static int mmc_has_valid_request( struct mmc_dev *dev )
+{
+	struct mmc_io_request *request = dev->io_request;
+	struct mmc_slot *slot;
+
+	MMC_DEBUG(2," (%p)\n", request);
+
+	if ( !request ) return 0;
+
+	slot = dev->slot + request->id;
+
+	if ( !slot->media_driver ) {
+		MMC_DEBUG(0,": card doesn't have media driver\n");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void mmc_configure_card( struct mmc_dev *dev, int slot )
+{
+	u32 rate;
+	MMC_DEBUG(2,": slot=%d\n", slot);
+
+	/* Fix the clock rate */
+	rate = mmc_tran_speed(dev->slot[slot].csd.tran_speed);
+	if ( rate < MMC_CLOCK_SLOW )
+		rate = MMC_CLOCK_SLOW;
+	if ( rate > MMC_CLOCK_FAST )
+		rate = MMC_CLOCK_FAST;
+
+	dev->sdrive->set_clock(rate);
+	
+	/* Match the drive media */
+	mmc_match_media_driver(&dev->slot[slot]);
+	run_sbin_mmc_hotplug(dev, slot, 1);
+}
+
+/* The blocks requested by the kernel may or may not
+   match what we can do.  Unfortunately, filesystems play
+   fast and loose with block sizes, so we're stuck with this */
+
+static void mmc_fix_request_block_size( struct mmc_dev *dev )
+{
+	struct mmc_io_request *t = dev->io_request;
+	struct mmc_slot *slot = dev->slot + t->id;
+	u16 block_len;
+
+	MMC_DEBUG(1, ": io_request id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",
+	      t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer);
+
+	switch( t->cmd ) {
+	case READ:
+		block_len = 1 << slot->csd.read_bl_len;
+		break;
+	case WRITE:
+		block_len = 1 << slot->csd.write_bl_len;
+		break;
+	default:
+		MMC_DEBUG(0,": unrecognized command %d\n", t->cmd);
+		return;
+	}
+
+	if ( block_len < t->block_len ) {
+		int scale = t->block_len / block_len;
+		MMC_DEBUG(1,": scaling by %d from block_len=%d to %ld\n", 
+		      scale, block_len, t->block_len);
+		t->block_len   = block_len;
+		t->sector     *= scale;
+		t->nr_sectors *= scale;
+	}
+}
+
+
+/******************************************************************
+ * State machine routines to read and write data
+ *
+ *  SET_BLOCKLEN only needs to be done once for each card.
+ *  SET_BLOCK_COUNT is only valid in MMC 3.1; most cards don't support this,
+ *  so we don't use it.
+ * 
+ *  In the 2.x cards we have a choice between STREAMING mode and
+ *  SINGLE mode.  There's an obvious performance possibility in 
+ *  using streaming mode, but at this time we're just using the SINGLE
+ *  mode.
+ ******************************************************************/
+
+static void * mmc_cim_read_write_block( struct mmc_dev *dev, int first )
+{
+	struct mmc_io_request *t = dev->io_request;
+	struct mmc_response_r1 r1;
+	struct mmc_slot *slot = dev->slot + t->id;
+	int    retval = 0;
+	int    i;
+
+	MMC_DEBUG(2," first=%d\n",first);
+
+	if ( first ) {
+		mmc_fix_request_block_size( dev );
+
+		switch ( slot->state ) {
+		case CARD_STATE_STBY:
+			mmc_simple_cmd(dev, MMC_SELECT_CARD, ID_TO_RCA(slot->id) << 16, RESPONSE_R1B );
+			break;
+		case CARD_STATE_TRAN:
+			mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 );
+			break;
+		default:
+			MMC_DEBUG(0,": invalid card state %d\n", slot->state);
+			goto read_block_error;
+			break;
+		}
+		return NULL;
+	}
+
+	switch (dev->request.cmd) {
+	case MMC_SELECT_CARD:
+		mmc_unpack_r1( &dev->request, &r1, slot->state );
+		for ( i = 0 ; i < dev->num_slots ; i++ )
+			dev->slot[i].state = ( i == t->id ? CARD_STATE_TRAN : CARD_STATE_STBY );
+
+		mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 );
+		break;
+
+	case MMC_SET_BLOCKLEN:
+		mmc_unpack_r1( &dev->request, &r1, slot->state );
+		mmc_send_cmd(dev, (t->cmd == READ ? MMC_READ_SINGLE_BLOCK : MMC_WRITE_BLOCK), 
+			     t->sector * t->block_len, 1, t->block_len, RESPONSE_R1 );
+		break;
+
+	case MMC_READ_SINGLE_BLOCK:
+	case MMC_WRITE_BLOCK:
+		mmc_unpack_r1( &dev->request, &r1, slot->state );
+
+		t->nr_sectors--;
+		t->sector++;
+		t->buffer += t->block_len;
+
+		if ( t->nr_sectors ) {
+			mmc_send_cmd(dev, (t->cmd == READ ? MMC_READ_SINGLE_BLOCK : MMC_WRITE_BLOCK), 
+				     t->sector * t->block_len, 1, t->block_len, RESPONSE_R1 );
+		}
+		else {
+			mmc_finish_io_request( dev, 1 );
+			if ( mmc_has_valid_request(dev) )
+				return mmc_cim_read_write_block;
+			return mmc_cim_default_state;
+		}
+		break;
+
+	default:
+		goto read_block_error;
+		break;
+	}
+	return NULL;
+
+read_block_error:
+	MMC_DEBUG(0,": failure during cmd %d, error %d (%s)\n", 
+	      dev->request.cmd, retval, mmc_result_to_string(retval));
+	mmc_finish_io_request( dev, 0 );   // Failure
+	return mmc_cim_default_state;
+}
+
+/* Update the card's status information in preparation to running a read/write cycle */
+
+static void * mmc_cim_get_status( struct mmc_dev *dev, int first )
+{
+	struct mmc_slot *slot = dev->slot + dev->io_request->id;
+	struct mmc_response_r1 r1;
+	int retval = MMC_NO_ERROR;
+
+	MMC_DEBUG(2," first=%d\n",first);
+
+	if ( first ) {
+		mmc_simple_cmd(dev, MMC_SEND_STATUS, ID_TO_RCA(slot->id) << 16, RESPONSE_R1 );
+		return NULL;
+	}
+
+	switch (dev->request.cmd) {
+	case MMC_SEND_STATUS:
+		retval = mmc_unpack_r1(&dev->request,&r1,slot->state);
+		slot->state = CARD_STATE_STBY;
+//		slot->state = CARD_STATE_TRAN;
+MMC_DEBUG(2," state=%d\n",slot->state);
+		return mmc_cim_read_write_block;
+
+		break;
+
+	default:
+		break;
+	}
+
+	MMC_DEBUG(0, ": failure during cmd %d, error=%d (%s)\n", dev->request.cmd,
+	      retval, mmc_result_to_string(retval));
+	mmc_finish_io_request(dev,0);
+	return mmc_cim_default_state;
+}
+
+static void * mmc_cim_handle_request( struct mmc_dev *dev, int first )
+{
+	MMC_DEBUG(2," first=%d\n",first);
+
+	if ( !first && !mmc_has_valid_request(dev)) {
+		MMC_DEBUG(0, ": invalid request\n");
+		mmc_finish_io_request(dev,0);
+		return mmc_cim_default_state;
+	}
+
+	if ( first )
+		return mmc_cim_get_status;
+
+	return mmc_cim_read_write_block;
+}
+
+/******************************************************************
+ *
+ * State machine routines to initialize card(s)
+ *
+ ******************************************************************/
+
+/*
+  CIM_SINGLE_CARD_ACQ  (frequency at 400 kHz)
+  --- Must enter from GO_IDLE_STATE ---
+
+  1. SEND_OP_COND (Full Range) [CMD1]   {optional}
+  2. SEND_OP_COND (Set Range ) [CMD1]
+     If busy, delay and repeat step 2
+  3. ALL_SEND_CID              [CMD2]
+     If timeout, set an error (no cards found)
+  4. SET_RELATIVE_ADDR         [CMD3]
+  5. SEND_CSD                  [CMD9]
+  6. SET_DSR                   [CMD4]    Only call this if (csd.dsr_imp).
+  7. Set clock frequency (check available in csd.tran_speed)
+ */
+
+static void * mmc_cim_single_card_acq( struct mmc_dev *dev, int first )
+{
+	struct mmc_response_r3 r3;
+	struct mmc_response_r1 r1;
+	struct mmc_slot *slot = dev->slot;     /* Must be slot 0 */
+	int retval;
+
+	MMC_DEBUG(2,"\n");
+
+	if ( first ) {
+		mmc_simple_cmd(dev, MMC_GO_IDLE_STATE, 0, RESPONSE_NONE);
+		return NULL;
+	}
+
+	switch (dev->request.cmd) {
+	case MMC_GO_IDLE_STATE: /* No response to parse */
+		if ( (dev->sdrive->flags & MMC_SDFLAG_VOLTAGE ))
+			MMC_DEBUG(0,": error - current driver doesn't do OCR\n");
+		mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3);
+		break;
+
+	case MMC_SEND_OP_COND:
+		retval = mmc_unpack_r3(&dev->request, &r3);
+		if ( retval ) {
+			MMC_DEBUG(0,": failed SEND_OP_COND error=%d (%s) - could be SD card\n", 
+			      retval, mmc_result_to_string(retval));
+			return mmc_cim_default_state;
+		}
+
+		MMC_DEBUG(2,": read ocr value = 0x%08x\n", r3.ocr);
+		if (!(r3.ocr & MMC_CARD_BUSY)) {
+			mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3);
+		}
+		else {
+			slot->state = CARD_STATE_READY;
+			mmc_simple_cmd(dev, MMC_ALL_SEND_CID, 0, RESPONSE_R2_CID);
+		}
+		break;
+		
+	case MMC_ALL_SEND_CID: 
+		retval = mmc_unpack_cid( &dev->request, &slot->cid );
+		if ( retval ) {
+			MMC_DEBUG(0,": unable to ALL_SEND_CID error=%d (%s)\n", 
+			      retval, mmc_result_to_string(retval));
+			return mmc_cim_default_state;
+		}
+		slot->state = CARD_STATE_IDENT;
+		mmc_simple_cmd(dev, MMC_SET_RELATIVE_ADDR, ID_TO_RCA(slot->id) << 16, RESPONSE_R1);
+		break;
+
+        case MMC_SET_RELATIVE_ADDR:
+		retval = mmc_unpack_r1(&dev->request,&r1,slot->state);
+		if ( retval ) {
+			MMC_DEBUG(0, ": unable to SET_RELATIVE_ADDR error=%d (%s)\n", 
+			      retval, mmc_result_to_string(retval));
+			return mmc_cim_default_state;
+		}
+		slot->state = CARD_STATE_STBY;
+		mmc_simple_cmd(dev, MMC_SEND_CSD, ID_TO_RCA(slot->id) << 16, RESPONSE_R2_CSD);
+		break;
+
+	case MMC_SEND_CSD:
+		retval = mmc_unpack_csd(&dev->request, &slot->csd);
+		if ( retval ) {
+			MMC_DEBUG(0, ": unable to SEND_CSD error=%d (%s)\n", 
+			      retval, mmc_result_to_string(retval));
+			return mmc_cim_default_state;
+		}
+		if ( slot->csd.dsr_imp ) {
+			MMC_DEBUG(0, ": driver doesn't support setting DSR\n");
+				// mmc_simple_cmd(dev, MMC_SET_DSR, 0, RESPONSE_NONE);
+		}
+		mmc_configure_card( dev, 0 );
+		return mmc_cim_default_state;
+
+	default:
+		MMC_DEBUG(0, ": error!  Illegal last cmd %d\n", dev->request.cmd);
+		return mmc_cim_default_state;
+	}
+	return NULL;
+}
+
+/*
+  CIM_INIT_STACK       (frequency at 400 kHz)
+
+  1. GO_IDLE_STATE (CMD0)
+  2. Do CIM_SINGLE_CARD_ACQ
+*/
+
+static void * mmc_cim_init_stack( struct mmc_dev *dev, int first )
+{
+	MMC_DEBUG(2,"\n");
+
+	if ( first ) {
+		mmc_simple_cmd(dev, MMC_CIM_RESET, 0, RESPONSE_NONE);
+		return NULL;
+	}
+
+	switch (dev->request.cmd) {
+	case MMC_CIM_RESET:
+		if ( dev->slot[0].state == CARD_STATE_EMPTY )
+			return mmc_cim_default_state;
+
+		dev->slot[0].state = CARD_STATE_IDLE;
+		return mmc_cim_single_card_acq;
+
+	default:
+		MMC_DEBUG(0,": invalid state %d\n", dev->request.cmd);
+		break;
+	}
+
+	return NULL;
+}
+
+/******************************************************************
+ *  Default state - start here
+ ******************************************************************/
+
+static void * mmc_cim_default_state( struct mmc_dev *dev, int first )
+{
+	MMC_DEBUG(2,"\n");
+
+	mmc_check_eject(dev);
+
+	if (mmc_check_insert(dev))
+		return mmc_cim_init_stack;
+	else if (mmc_has_valid_request(dev))
+		return mmc_cim_handle_request;
+
+	return NULL;
+}
+
+
+/******************************************************************
+ *  State function handler
+ ******************************************************************/
+
+typedef void *(*state_func_t)(struct mmc_dev *, int);
+static state_func_t g_single_card = &mmc_cim_default_state;
+
+void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags )
+{
+	state_func_t    sf;
+
+	MMC_DEBUG(2,"\n");
+
+	sf = g_single_card(dev,0);
+	while ( sf ) {
+		g_single_card = sf;
+		sf = g_single_card(dev,1);
+	}
+}
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mmc/mmc_protocol.h linux-2.4.26/drivers/mmc/mmc_protocol.h
--- linux-2.4.26.org/drivers/mmc/mmc_protocol.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mmc/mmc_protocol.h	2004-06-24 19:45:44.000000000 +0900
@@ -0,0 +1,261 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2004/06/24 10:45:44 $ 
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_PROTOCOL_H
+#define MMC_MMC_PROTOCOL_H
+
+#include <linux/types.h>
+
+/* Standard MMC clock speeds */
+#if 0 /* NSS */
+#define MMC_CLOCK_SLOW    400000      /* 400 kHz for initial setup */
+#else
+#define MMC_CLOCK_SLOW    370000      /* 370 kHz for initial setup */
+#endif
+#define MMC_CLOCK_FAST  20000000      /* 20 MHz for maximum for normal operation */
+
+/* Extra MMC commands for state control */
+/* Use negative numbers to disambiguate */
+#define MMC_CIM_RESET            -1
+
+/* Standard MMC commands (3.1)           type  argument     response */
+   /* class 1 */
+#define	MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
+#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
+#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
+#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
+#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
+#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+
+  /* class 2 */
+#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
+#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+
+  /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+
+  /* class 4 */
+#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
+
+  /* class 6 */
+#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
+#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
+#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
+
+  /* class 5 */
+#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE                37   /* ac                      R1b */
+
+  /* class 9 */
+#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
+
+  /* class 7 */
+#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
+
+  /* class 8 */
+#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
+
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+
+/* Don't change the order of these; they are used in dispatch tables */
+enum mmc_rsp_t {
+	RESPONSE_NONE   = 0,
+	RESPONSE_R1     = 1,
+	RESPONSE_R1B    = 2,
+	RESPONSE_R2_CID = 3,
+	RESPONSE_R2_CSD  = 4,
+	RESPONSE_R3      = 5,
+	RESPONSE_R4      = 6,
+	RESPONSE_R5      = 7
+};
+
+
+/*
+  MMC status in R1
+  Type
+  	e : error bit
+	s : status bit
+	r : detected and set for the actual command response
+	x : detected and set during command execution. the host must poll
+            the card by sending status command in order to read these bits.
+  Clear condition
+  	a : according to the card state
+	b : always related to the previous command. Reception of
+            a valid command will clear it (with a delay of one command)
+	c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
+#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
+#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
+#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
+#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
+#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
+#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
+#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
+#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
+#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
+#define R1_CC_ERROR		(1 << 20)	/* erx, c */
+#define R1_ERROR		(1 << 19)	/* erx, c */
+#define R1_UNDERRUN		(1 << 18)	/* ex, c */
+#define R1_OVERRUN		(1 << 17)	/* ex, c */
+#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
+#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
+#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
+#define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
+#define R1_APP_CMD		(1 << 7)	/* sr, c */
+
+enum card_state {
+	CARD_STATE_EMPTY = -1,
+	CARD_STATE_IDLE	 = 0,
+	CARD_STATE_READY = 1,
+	CARD_STATE_IDENT = 2,
+	CARD_STATE_STBY	 = 3,
+	CARD_STATE_TRAN	 = 4,
+	CARD_STATE_DATA	 = 5,
+	CARD_STATE_RCV	 = 6,
+	CARD_STATE_PRG	 = 7,
+	CARD_STATE_DIS	 = 8,
+};
+
+/* These are unpacked versions of the actual responses */
+
+struct mmc_response_r1 {
+	u8  cmd;
+	u32 status;
+};
+
+struct mmc_cid {
+	u8  mid;
+	u16 oid;
+	u8  pnm[7];   // Product name (we null-terminate)
+	u8  prv;
+	u32 psn;
+	u16 mdt;
+};
+
+struct mmc_csd {
+	u8  csd_structure;
+	u8  spec_vers;
+	u8  taac;
+	u8  nsac;
+	u8  tran_speed;
+	u16 ccc;
+	u8  read_bl_len;
+	u8  read_bl_partial;
+	u8  write_blk_misalign;
+	u8  read_blk_misalign;
+	u8  dsr_imp;
+	u16 c_size;
+	u8  vdd_r_curr_min;
+	u8  vdd_r_curr_max;
+	u8  vdd_w_curr_min;
+	u8  vdd_w_curr_max;
+	u8  c_size_mult;
+	union {
+		struct { /* MMC system specification version 3.1 */
+			u8  erase_grp_size;  
+			u8  erase_grp_mult; 
+		} v31;
+		struct { /* MMC system specification version 2.2 */
+			u8  sector_size;
+			u8  erase_grp_size;
+		} v22;
+	} erase;
+	u8  wp_grp_size;
+	u8  wp_grp_enable;
+	u8  default_ecc;
+	u8  r2w_factor;
+	u8  write_bl_len;
+	u8  write_bl_partial;
+	u8  file_format_grp;
+	u8  copy;
+	u8  perm_write_protect;
+	u8  tmp_write_protect;
+	u8  file_format;
+	u8  ecc;
+};
+
+struct mmc_response_r3 {  
+	u32 ocr;
+}; 
+
+#define MMC_VDD_145_150	0x00000001	/* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155	0x00000002	/* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160	0x00000004	/* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165	0x00000008	/* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170	0x00000010	/* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18	0x00000020	/* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19	0x00000040	/* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20	0x00000080	/* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21	0x00000100	/* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22	0x00000200	/* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23	0x00000400	/* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24	0x00000800	/* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25	0x00001000	/* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26	0x00002000	/* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27	0x00004000	/* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28	0x00008000	/* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29	0x00010000	/* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30	0x00020000	/* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31	0x00040000	/* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32	0x00080000	/* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33	0x00100000	/* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34	0x00200000	/* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35	0x00400000	/* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36	0x00800000	/* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
+
+
+/* CSD field definitions */
+ 
+#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1       */
+
+#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
+
+#endif  /* MMC_MMC_PROTOCOL_H */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/mtd/bootldr.c linux-2.4.26/drivers/mtd/bootldr.c
--- linux-2.4.26.org/drivers/mtd/bootldr.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/mtd/bootldr.c	2004-01-09 18:22:15.000000000 +0900
@@ -0,0 +1,214 @@
+/*
+ * Read flash partition table from Compaq Bootloader
+ *
+ * Copyright 2001 Compaq Computer Corporation.
+ *
+ * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+#define FLASH_PARTITION_NAMELEN 32
+enum LFR_FLAGS {
+   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
+   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
+   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
+   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
+};
+
+// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
+// for now
+#define MAX_NUM_PARTITIONS 8
+typedef struct FlashRegion {
+   char name[FLASH_PARTITION_NAMELEN];
+   unsigned long base;
+   unsigned long size;
+   enum LFR_FLAGS flags;
+} FlashRegion;
+
+typedef struct BootldrFlashPartitionTable {
+  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
+  int npartitions;
+  struct FlashRegion partition[8];
+} BootldrFlashPartitionTable;
+
+#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
+#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
+
+#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
+#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
+
+#define BOOTCAP_WAKEUP	(1<<0)
+#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
+#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
+
+static struct BootldrFlashPartitionTable Table;
+static struct BootldrFlashPartitionTable *partition_table = NULL;
+
+
+int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+	struct mtd_partition *parts;
+	int ret, retlen, i;
+	int npartitions = 0;
+	long partition_table_offset;
+	long bootmagic = 0;
+	long bootcap = 0;
+	int namelen = 0;
+
+	char *names; 
+
+#if 0
+	/* verify bootldr magic */
+	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
+	if (ret) 
+		goto out;
+        if (bootmagic != BOOTLDR_MAGIC)
+                goto out;
+	/* see if bootldr supports partition tables and where to find the partition table */
+	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
+	if (ret) 
+		goto out;
+
+	if (!(bootcap & BOOTCAP_PARTITIONS))
+		goto out;
+	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
+		partition_table_offset = master->erasesize;
+	else
+		partition_table_offset = master->size - master->erasesize;
+
+	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
+	printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
+
+
+	/* Read the partition table */
+	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!partition_table)
+		return -ENOMEM;
+
+	ret = master->read(master, partition_table_offset,
+			   PAGE_SIZE, &retlen, (void *)partition_table);
+	if (ret)
+	    goto out;
+
+#endif
+	if (!partition_table)
+	    return -ENOMEM;
+
+	
+	printk("%s: magic=%#x\n", __FUNCTION__, partition_table->magic);
+	printk("%s: numPartitions=%#x\n", __FUNCTION__, partition_table->npartitions);
+
+
+	/* check for partition table magic number */
+	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
+		goto out;
+	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
+	    MAX_NUM_PARTITIONS:partition_table->npartitions;	
+
+	printk("%s: npartitions=%#x\n", __FUNCTION__, npartitions);
+
+	for (i = 0; i < npartitions; i++) {
+		namelen += strlen(partition_table->partition[i].name) + 1;
+	}
+
+	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	names = (char *)&parts[npartitions];
+	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
+
+
+
+	// from here we use the partition table
+	for (i = 0; i < npartitions; i++) {
+                struct FlashRegion *partition = &partition_table->partition[i];
+		const char *name = partition->name;
+		parts[i].name = names;
+		names += strlen(name) + 1;
+		strcpy(parts[i].name, name);
+
+                if (partition->flags & LFR_EXPAND)
+                        parts[i].size = MTDPART_SIZ_FULL;
+                else
+                        parts[i].size = partition->size;
+		parts[i].offset = partition->base;
+		parts[i].mask_flags = 0;
+		
+		printk("        partition %s o=%x s=%x\n", 
+		       parts[i].name, parts[i].offset, parts[i].size);
+
+	}
+
+	ret = npartitions;
+	*pparts = parts;
+
+ out:
+#if 0
+	if (partition_table)
+		kfree(partition_table);
+#endif
+	
+	return ret;
+}
+
+
+static int __init parse_tag_ptable(const struct tag *tag)
+{
+    char buf[128];
+    int i;
+    int j;
+    
+    partition_table = &Table;
+
+#ifdef CONFIG_DEBUG_LL    
+    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
+	    tag->u.ptable.magic,tag->u.ptable.npartitions);
+    printascii(buf);
+    
+    for (i=0; i<tag->u.ptable.npartitions; i++){
+	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
+	    (char *) (&tag->u.ptable.partition[i].name[0]),
+		tag->u.ptable.partition[i].base,
+		tag->u.ptable.partition[i].size,
+		tag->u.ptable.partition[i].flags);
+	printascii(buf);
+    }
+#endif
+
+    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
+	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
+
+    
+    return 0;
+}
+
+__tagtable(ATAG_PTABLE, parse_tag_ptable);
+
+EXPORT_SYMBOL(parse_bootldr_partitions);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Compaq Computer Corporation");
+MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/net/8390.c linux-2.4.26/drivers/net/8390.c
--- linux-2.4.26.org/drivers/net/8390.c	2003-11-29 03:26:20.000000000 +0900
+++ linux-2.4.26/drivers/net/8390.c	2004-03-22 10:56:15.000000000 +0900
@@ -221,6 +221,16 @@
 
 void ei_tx_timeout(struct net_device *dev)
 {
+#if defined(CONFIG_CHIP_M32700) && defined(CONFIG_SMP)
+	unsigned long flags, icucr;
+
+	printk(KERN_DEBUG "eth0 : timeout\n");
+	local_irq_save(flags);
+	icucr = inl(0x00eff200);
+	icucr |= 0x00000030;
+	outl(icucr, 0x00eff200);
+	local_irq_restore(flags);
+#else	/* not CONFIG_CHIP_M32700 || not CONFIG_SMP */
 	long e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int txsr, isr, tickssofar = jiffies - dev->trans_start;
@@ -255,6 +265,7 @@
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
 	netif_wake_queue(dev);
+#endif	/* not CONFIG_CHIP_M32700 || not CONFIG_SMP */
 }
     
 /**
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/net/Makefile linux-2.4.26/drivers/net/Makefile
--- linux-2.4.26.org/drivers/net/Makefile	2004-04-14 22:05:30.000000000 +0900
+++ linux-2.4.26/drivers/net/Makefile	2004-04-28 10:36:54.000000000 +0900
@@ -142,6 +142,7 @@
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_EL2) += 3c503.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390.o
+obj-$(CONFIG_MAPPI_NE2000) += 8390.o
 obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
 obj-$(CONFIG_HPLAN) += hp.o 8390.o
 obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/net/Space.c linux-2.4.26/drivers/net/Space.c
--- linux-2.4.26.org/drivers/net/Space.c	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/net/Space.c	2004-03-22 10:56:15.000000000 +0900
@@ -101,6 +101,12 @@
 extern int mac8390_probe(struct net_device *dev);
 extern int mac89x0_probe(struct net_device *dev);
 extern int mc32_probe(struct net_device *dev);
+#ifdef CONFIG_M32R_NE2000
+extern int mappi_ne_probe(struct net_device *dev);
+#endif /* CONFIG_MAPPI_NE2000 */
+#ifdef CONFIG_M32R_SMC91111
+extern int m32r_smc_init( struct net_device * );
+#endif /* CONFIG_M32R_SMC91111 */
   
 /* Detachable devices ("pocket adaptors") */
 extern int de600_probe(struct net_device *);
@@ -243,12 +249,18 @@
 #ifdef CONFIG_NE2000		/* ISA (use ne2k-pci for PCI cards) */
 	{ne_probe, 0},
 #endif
+#ifdef CONFIG_M32R_NE2000	/* ne2k for Mappi */
+	{mappi_ne_probe, 0},
+#endif
 #ifdef CONFIG_LANCE		/* ISA/VLB (use pcnet32 for PCI cards) */
 	{lance_probe, 0},
 #endif
 #ifdef CONFIG_SMC9194
 	{smc_init, 0},
 #endif
+#ifdef CONFIG_M32R_SMC91111	/* SMC91111 for M32R */
+	{m32r_smc_init, 0},
+#endif
 #ifdef CONFIG_SEEQ8005 
 	{seeq8005_probe, 0},
 #endif
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/net/wireless/hermes.h linux-2.4.26/drivers/net/wireless/hermes.h
--- linux-2.4.26.org/drivers/net/wireless/hermes.h	2003-08-25 20:44:42.000000000 +0900
+++ linux-2.4.26/drivers/net/wireless/hermes.h	2004-03-22 10:56:21.000000000 +0900
@@ -299,12 +299,21 @@
 } hermes_response_t;
 
 /* Register access convenience macros */
+#if defined(__m32r__)
+#define hermes_read_reg(hw, off) ((hw)->io_space ? \
+	le16_to_cpu(inw((hw)->iobase + ( (off) << (hw)->reg_spacing ))) : \
+	readw((hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#define hermes_write_reg(hw, off, val) ((hw)->io_space ? \
+	outw_p(cpu_to_le16((val)), (hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
+	writew((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#else
 #define hermes_read_reg(hw, off) ((hw)->io_space ? \
 	inw((hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
 	readw((hw)->iobase + ( (off) << (hw)->reg_spacing )))
 #define hermes_write_reg(hw, off, val) ((hw)->io_space ? \
 	outw_p((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )) : \
 	writew((val), (hw)->iobase + ( (off) << (hw)->reg_spacing )))
+#endif
 
 #define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
 #define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/pcmcia/Config.in linux-2.4.26/drivers/pcmcia/Config.in
--- linux-2.4.26.org/drivers/pcmcia/Config.in	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/pcmcia/Config.in	2004-03-22 10:56:21.000000000 +0900
@@ -29,6 +29,12 @@
    if [ "$CONFIG_8xx" = "y" ]; then
       dep_tristate '  M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
    fi
+   if [ "$CONFIG_PLAT_MAPPI" = "y" ]; then
+      dep_bool '  M32R pc card controller support' CONFIG_M32RPCC $CONFIG_PCMCIA
+      if [ "$CONFIG_M32RPCC" = "y" ]; then
+	bool '   Enable M32R PCC slot2' CONFIG_M32RPCC_SLOT2
+      fi
+   fi
    if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
       dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA 
       if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/pcmcia/Makefile linux-2.4.26/drivers/pcmcia/Makefile
--- linux-2.4.26.org/drivers/pcmcia/Makefile	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/pcmcia/Makefile	2004-03-22 10:56:21.000000000 +0900
@@ -38,6 +38,9 @@
   ifeq ($(CONFIG_HD64465_PCMCIA),y)
     obj-y += hd64465_ss.o
   endif
+  ifeq ($(CONFIG_M32RPCC),y)
+    obj-y += m32r_pcc.o
+  endif
 else
   ifeq ($(CONFIG_PCMCIA),m)
     obj-m   := pcmcia_core.o ds.o
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/pcmcia/cistpl.c linux-2.4.26/drivers/pcmcia/cistpl.c
--- linux-2.4.26.org/drivers/pcmcia/cistpl.c	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/pcmcia/cistpl.c	2004-03-22 10:56:21.000000000 +0900
@@ -1027,6 +1027,11 @@
 			       cistpl_cftable_entry_t *entry)
 {
     u_char *p, *q, features;
+#define MUST_ALIGNED
+#ifdef MUST_ALIGNED
+      u_short t;
+      u_char *tp = (u_char *)&t;
+#endif	
 
     p = tuple->TupleData;
     q = p + tuple->TupleDataLen;
@@ -1099,7 +1104,13 @@
 	break;
     case 0x20:
 	entry->mem.nwin = 1;
+#ifdef MUST_ALIGNED
+	tp[0]=*p;
+	tp[1]=*(p+1);
+	entry->mem.win[0].len = le16_to_cpu(t) << 8;
+#else
 	entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+#endif
 	entry->mem.win[0].card_addr = 0;
 	entry->mem.win[0].host_addr = 0;
 	p += 2;
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/pcmcia/m32r_pcc.c linux-2.4.26/drivers/pcmcia/m32r_pcc.c
--- linux-2.4.26.org/drivers/pcmcia/m32r_pcc.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/pcmcia/m32r_pcc.c	2002-12-25 18:15:56.000000000 +0900
@@ -0,0 +1,978 @@
+/*======================================================================
+
+	Device driver for the PCMCIA functionality of M32R.
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+
+#include "cs_internal.h"
+#include "m32r_pcc.h"
+
+/* XXX: should be moved into asm/irq.h */
+#define PCC0_IRQ 24
+#define PCC1_IRQ 25
+
+#define CHAOS_PCC_DEBUG
+#ifdef CHAOS_PCC_DEBUG
+	static volatile u_short dummy_readbuf;
+#endif
+
+#define PCC_DEBUG_DBEX
+
+#define PCMCIA_DEBUG   3
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(args)
+
+static const char *version =
+"m32r_pcc.c 0.001 2002/02/12 18:36:21 (Hiroyuki Kondo)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+static unsigned long pcc_access_timing = 0x51755175;
+
+typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;
+
+typedef struct pcc_socket_info_t {
+	u_short			type, flags;
+	socket_cap_t	cap;
+ 	ioaddr_t		ioaddr;
+	u_long			mapaddr;
+	u_long			base;	/* PCC register base */
+	u_char			cs_irq, intr;
+	void			(*handler)(void *info, u_int events);
+	void			*info;
+	pccard_io_map	io_map[MAX_IO_WIN];
+	pccard_mem_map	mem_map[MAX_WIN];
+	u_char			io_win;
+	u_char			mem_win;
+	pcc_as_t		current_space;
+	u_char			last_iodbex;
+#ifdef CHAOS_PCC_DEBUG
+	u_char			last_iosize;
+#endif
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc;
+#endif
+} pcc_socket_info_t;
+
+static int pcc_sockets = 0;
+static pcc_socket_info_t socket[M32R_MAX_PCC] = {
+	{ 0, }, /* ... */
+};
+
+#define ISA_LOCK(n, f) do { } while (0)
+#define ISA_UNLOCK(n, f) do { } while (0)
+
+/*====================================================================*/
+
+static unsigned int pcc_get(u_short, unsigned int);
+static void pcc_set(u_short, unsigned int , unsigned int );
+
+static spinlock_t pcc_lock = SPIN_LOCK_UNLOCKED;
+
+void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag)
+{
+	u_long addr;
+	u_long flags;
+	int need_ex;
+#ifdef PCC_DEBUG_DBEX
+	int _dbex;
+#endif
+	pcc_socket_info_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+	int map_changed = 0;
+#endif
+
+	/* Need lock ? */
+	spin_lock_irqsave(&pcc_lock, flags);
+
+	/*
+	 * Check if need dbex
+	 */
+	need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0;
+#ifdef PCC_DEBUG_DBEX
+	_dbex = need_ex;
+	need_ex = 0;
+#endif
+
+	/*
+	 * calculate access address
+	 */
+	addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */
+
+	/*
+	 * Check current mapping
+	 */
+	if (t->current_space != as_io || t->last_iodbex != need_ex) {
+
+		u_long cbsz;
+
+		/*
+		 * Disable first
+		 */
+		pcc_set(sock, PCCR, 0);
+
+		/*
+		 * Set mode and io address
+		 */
+		cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ;
+		pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex);
+		pcc_set(sock, PCADR, addr & 0x1ff00000);
+
+		pcc_set(sock, PCATCR, pcc_access_timing);
+
+		/*
+		 * Enable and read it
+		 */
+		pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+		map_changed = (t->current_space == as_attr && size == 2); /* XXX */
+#else
+		map_changed = 1;
+#endif
+#endif
+		t->current_space = as_io;
+	}
+
+	/*
+	 * access to IO space
+	 */
+	if (size == 1) {
+		/* Byte */
+		unsigned char *bp = (unsigned char *)buf;
+
+#ifdef CHAOS_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readb(addr);
+		}
+#endif
+		if (wr) {
+			/* write Byte */
+			while (nmemb--) {
+				writeb(*bp++, addr);
+			}
+		} else {
+			/* read Byte */
+			while (nmemb--) {
+	    		*bp++ = readb(addr);
+			}
+		}
+	} else {
+		/* Word */
+		unsigned short *bp = (unsigned short *)buf;
+
+#ifdef CHAOS_PCC_DEBUG
+		if (map_changed) {
+			dummy_readbuf = readw(addr);
+		}
+#endif
+		if (wr) {
+			/* write Word */
+			while (nmemb--) {
+#ifdef PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = cp[1] << 8 | cp[0];
+					writew(tmp, addr);
+					bp++;
+				} else 
+#endif
+				writew(*bp++, addr);
+	    	}
+	    } else {
+	    	/* read Word */
+	    	while (nmemb--) {
+#ifdef  PCC_DEBUG_DBEX
+				if (_dbex) {
+					unsigned char *cp = (unsigned char *)bp;
+					unsigned short tmp;
+					tmp = readw(addr);
+					cp[0] = tmp & 0xff;
+					cp[1] = (tmp >> 8) & 0xff;
+					bp++;
+				} else 
+#endif
+				*bp++ = readw(addr);
+	    	}
+	    }
+	}
+
+#if 1
+	/* addr is no longer used */
+	if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) {
+	  printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n",
+			 port, size * 8);
+	  pcc_set(sock, PCIRC, addr);
+	}
+#endif
+	/*
+	 * save state
+	 */
+	t->last_iosize = size;
+	t->last_iodbex = need_ex;
+
+	/* Need lock ? */
+	spin_unlock_irqrestore(&pcc_lock,flags);
+
+	return;
+}
+
+void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+	pcc_iorw(sock, port, buf, size, nmemb, 0, flag);
+}
+
+void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) {
+    pcc_iorw(sock, port, buf, size, nmemb, 1, flag);
+}
+
+/*====================================================================*/
+
+#define IS_ALIVE		0x8000
+
+typedef struct pcc_t {
+	char				*name;
+	u_short				flags;
+} pcc_t;
+
+static pcc_t pcc[] = {
+	{ "xnux2", 0 }, { "xnux2", 0 },
+};
+
+static void pcc_interrupt(int, void *, struct pt_regs *regs);
+
+/*====================================================================*/
+
+static struct timer_list poll_timer;
+
+static unsigned int pcc_get(u_short sock, unsigned int reg)
+{
+	return inl(socket[sock].base + reg);
+}
+
+
+static void pcc_set(u_short sock, unsigned int reg, unsigned int data)
+{
+  	outl(data, socket[sock].base + reg);
+}
+
+/*======================================================================
+
+	See if a card is present, powered up, in IO mode, and already
+	bound to a (non PC Card) Linux driver.  We leave these alone.
+
+	We make an exception for cards that seem to be serial devices.
+	
+======================================================================*/
+
+static int __init is_alive(u_short sock)
+{
+	unsigned int stat;
+	unsigned int f;
+	
+	stat = pcc_get(sock, PCIRC);
+	f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16;
+	if(!f){
+		printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock);
+		return 0;
+	}
+	if(f!=3)
+		printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock);
+	else
+		printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,stat);
+	return 0;
+}
+
+static void add_pcc_socket(ulong base, int irq, ulong mapaddr, ioaddr_t ioaddr)
+{
+  	pcc_socket_info_t *t = &socket[pcc_sockets];
+
+	/* add sockets */
+	t->ioaddr = ioaddr;
+	t->mapaddr = mapaddr;
+	t->base = base;
+#ifdef CHAOS_PCC_DEBUG
+	t->flags = MAP_16BIT;
+#else
+	t->flags = 0;
+#endif
+	if (is_alive(pcc_sockets))
+		t->flags |= IS_ALIVE;
+
+	/* pcc_set(sockets,PCCR,1); */
+	/* pcc_set(sockets,PCIRC,3); */
+
+	/* add pcc */
+	if (t->base > 0) {
+		request_region(t->base, 0x20, "m32r-pcc");
+	}
+
+	printk(KERN_INFO "  %s ", pcc[pcc_sockets].name);
+	printk("pcc at 0x%08lx\n", t->base);
+
+	/* Update socket interrupt information, capabilities */
+	t->cap.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP);
+	t->cap.map_size = M32R_PCC_MAPSIZE;
+	t->cap.io_offset = ioaddr; /*  */
+	t->cap.irq_mask = 0;
+	t->cap.pci_irq = 2 + pcc_sockets; /* XXX */
+
+	request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt);
+
+	pcc_sockets++;
+
+	return;
+}
+
+
+/*====================================================================*/
+
+static u_int pending_events[8];
+static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+
+static void pcc_bh(void *dummy)
+{
+	u_int events;
+	int i;
+	DEBUG(4, "m32r: pcc_bh\n");
+
+	for (i=0; i < pcc_sockets; i++) {
+		spin_lock_irq(&pending_event_lock);
+		events = pending_events[i];
+		pending_events[i] = 0;
+		spin_unlock_irq(&pending_event_lock);
+	/* 
+	 * SS_DETECT events need a small delay here. The reason for this is that 
+	 * the "is there a card" electronics need time to see the card after the
+	 * "we have a card coming in" electronics have seen it. 
+	 */
+		if (events & SS_DETECT) 
+			mdelay(4);
+		if (socket[i].handler)
+			socket[i].handler(socket[i].info, events);
+	}
+}
+
+static struct tq_struct pcc_task = {
+		routine:		pcc_bh
+};
+
+static unsigned long last_detect_jiffies;
+
+static void pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	int i, j, irc;
+	u_int events, active;
+#ifdef CONFIG_ISA
+	u_long flags = 0;
+#endif
+	
+	DEBUG(4, "m32r: pcc_interrupt(%d)\n", irq);
+
+	for (j = 0; j < 20; j++) {
+		active = 0;
+		for (i = 0; i < pcc_sockets; i++) {
+			if ((socket[i].cs_irq != irq) &&
+				(socket[i].cap.pci_irq != irq))
+				continue;
+			irc = pcc_get(i, PCIRC);
+			irc >>=16;
+			DEBUG(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc);
+			if ((irc == 0) || (!socket[i].handler) ) {
+				continue;
+			}
+			events = (irc ) ? SS_DETECT : 0;
+			
+			
+			/* Several sockets will send multiple "new card detected"
+			   events in rapid succession. However, the rest of the pcmcia expects 
+			   only one such event. We just ignore these events by having a
+			   timeout */
+
+			if (events) {
+				if ((jiffies - last_detect_jiffies)<(HZ/20)) 
+					events = 0;
+				last_detect_jiffies = jiffies;
+			}
+			events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0;
+#if 0
+			if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+				events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+			else {
+				events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+				events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+				events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+			}
+			DEBUG(2, "m32r-pcc:interrput: socket %d event 0x%02x\n", i, events);
+#endif
+			DEBUG(2, " event 0x%02x\n", events);
+
+			if (events) {
+				spin_lock(&pending_event_lock);
+				pending_events[i] |= events;
+				spin_unlock(&pending_event_lock);
+				schedule_task(&pcc_task);
+			}
+			active |= events;
+			active = 0;
+		}
+		if (!active) break;
+	}
+	if (j == 20)
+		printk(KERN_NOTICE "m32r-pcc: infinite loop in interrupt handler\n");
+
+	DEBUG(4, "m32r-pcc: interrupt done\n");
+} /* pcc_interrupt */
+
+static void pcc_interrupt_wrapper(u_long data)
+{
+	pcc_interrupt(0, NULL, NULL);
+#if 1
+	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+#endif
+}
+
+/*====================================================================*/
+
+static int _pcc_get_status(u_short sock, u_int *value)
+{
+	u_int status;
+	
+	status = pcc_get(sock,PCIRC);
+	*value = ((status & PCIRC_CDIN1) && (status & PCIRC_CDIN2))
+		? SS_DETECT : 0;
+		
+#if 0
+	if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+		*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+	else {
+		*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+		*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+	}
+	*value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+#endif
+	status = pcc_get(sock,PCCR);
+
+#if 0
+	*value |= (status & PCCR_PCEN) ? SS_READY : 0;
+#else
+	*value |= SS_READY; /* XXX: always */
+#endif
+
+	status = pcc_get(sock,PCCSIGCR);
+	*value |= (status & PCCSIGCR_VEN) ? SS_POWERON : 0;
+
+	DEBUG(3, "m32r-pcc: GetStatus(%d) = %#4.4x\n", sock, *value);
+	return 0;
+} /* _get_status */
+
+/*====================================================================*/
+
+static int _pcc_get_socket(u_short sock, socket_state_t *state)
+{
+#if 0
+	pcc_socket_info_t *t = &socket[sock];
+	u_char reg, vcc, vpp;
+	
+	reg = i365_get(sock, I365_POWER);
+	state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+	state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+
+	vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+	state->Vcc = state->Vpp = 0;
+	if (reg & I365_VCC_5V) {
+		state->Vcc = 50;
+		if (vpp == I365_VPP1_5V) state->Vpp = 50;
+		if (vpp == I365_VPP1_12V) state->Vpp = 120;
+	}
+
+	/* IO card, RESET flags, IO interrupt */
+	reg = i365_get(sock, I365_INTCTL);
+	state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+	if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+	state->io_irq = reg & I365_IRQ_MASK;
+	
+	/* Card status change mask */
+	reg = i365_get(sock, I365_CSCINT);
+	state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+	if (state->flags & SS_IOCARD)
+		state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+	else {
+		state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+		state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+		state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+	}
+#endif
+	
+	DEBUG(3, "m32r-pcc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+	return 0;
+} /* _get_socket */
+
+/*====================================================================*/
+
+static int _pcc_set_socket(u_short sock, socket_state_t *state)
+{
+	u_long reg = 0;
+	
+	DEBUG(3, "m32r-pcc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+		  "io_irq %d, csc_mask %#2.2x)", sock, state->flags,
+		  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+
+	if (state->Vcc) {
+		/*
+		 * 5V only
+		 */
+		if (state->Vcc == 50) {
+			reg |= PCCSIGCR_VEN;
+		} else {
+			return -EINVAL;
+		}
+	}
+
+	if (state->flags & SS_RESET) {
+		DEBUG(3, ":RESET");
+		reg |= PCCSIGCR_CRST;
+	}
+	if (state->flags & SS_OUTPUT_ENA){
+		DEBUG(3, ":OUTPUT_ENA");
+		/* bit clear */
+	} else {
+		reg |= PCCSIGCR_SEN;
+	}
+
+	pcc_set(sock,PCCSIGCR,reg);
+
+#ifdef PCMCIA_DEBUG
+	if(state->flags & SS_IOCARD){
+		DEBUG(3, ":IOCARD");
+	}
+	if (state->flags & SS_PWR_AUTO) {
+		DEBUG(3, ":PWR_AUTO");
+	}
+	if (state->csc_mask & SS_DETECT)
+		DEBUG(3, ":csc-SS_DETECT");
+	if (state->flags & SS_IOCARD) {
+		if (state->csc_mask & SS_STSCHG) 
+			DEBUG(3, ":STSCHG");
+	} else {
+		if (state->csc_mask & SS_BATDEAD)
+			DEBUG(3, ":BATDEAD");
+		if (state->csc_mask & SS_BATWARN)
+			DEBUG(3, ":BATWARN");
+		if (state->csc_mask & SS_READY)
+			DEBUG(3, ":READY");
+	}
+	DEBUG(3, "\n");
+#endif
+	return 0;
+} /* _set_socket */
+
+/*====================================================================*/
+
+static int _pcc_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+	
+	map = io->map;
+
+	DEBUG(3, "m32r-pcc: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+		  "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+		  io->start, io->stop);
+	return 0;
+} /* _get_io_map */
+
+/*====================================================================*/
+
+static int _pcc_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+	u_char map;
+	
+	DEBUG(3, "m32r-pcc: SetIOMap(%d, %d, %#2.2x, %d ns, "
+		  "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+		  io->speed, io->start, io->stop);
+	map = io->map;
+
+	return 0;
+} /* _set_io_map */
+
+/*====================================================================*/
+
+static int _pcc_get_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+	int mode;
+	u_char map;
+	
+	map = mem->map;
+	mode = pcc_get(sock, PCMOD);
+
+	DEBUG(3, "m32r-pcc: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+		  "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+		  mem->sys_start, mem->sys_stop, mem->card_start);
+	return 0;
+} /* _get_mem_map */
+
+/*====================================================================*/
+
+  
+static int _pcc_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+
+	u_char map = mem->map;
+	u_long mode;
+	u_long addr;
+	pcc_socket_info_t *t = &socket[sock];
+#ifdef CHAOS_PCC_DEBUG
+	pcc_as_t last = t->current_space;
+#endif
+
+	DEBUG(3, "m32r-pcc: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+		  "lx, %#5.5x)\n", sock, map, mem->flags, mem->speed,
+		  mem->sys_start, mem->sys_stop, mem->card_start);
+
+	/*
+	 * sanity check
+	 */
+	if ((map > MAX_WIN) || (mem->card_start > 0x3ffffff) ||	 
+		(mem->sys_start > mem->sys_stop)) {
+		return -EINVAL;
+	}
+
+	/*
+	 * de-activate
+	 */
+	if ((mem->flags & MAP_ACTIVE) == 0) {
+		t->current_space = as_none;
+		return 0;
+	}
+
+	/*
+	 * Disable first
+	 */
+	pcc_set(sock, PCCR, 0);
+
+	/*
+	 * Set mode
+	 */
+	if (mem->flags & MAP_ATTRIB) {
+		mode = PCMOD_AS_ATTRIB | PCMOD_CBSZ;
+		t->current_space = as_attr;
+	} else {
+		mode = 0; /* common memory */
+		t->current_space = as_comm;
+	}
+	pcc_set(sock, PCMOD, mode);
+
+	/*
+	 * Set address
+	 */
+	addr = t->mapaddr + (mem->card_start & M32R_PCC_MAPMASK);
+	pcc_set(sock, PCADR, addr);
+
+	mem->sys_start = addr + mem->card_start;
+	mem->sys_stop = mem->sys_start + (M32R_PCC_MAPSIZE - 1);
+
+	/*
+	 * Set timing
+	 */
+	pcc_set(sock, PCATCR, pcc_access_timing);
+
+	/*
+	 * Enable again
+	 */
+	pcc_set(sock, PCCR, 1);
+
+#ifdef CHAOS_PCC_DEBUG
+#if 0
+	if (last != as_attr) {
+#else
+	if (1) {
+#endif
+
+		dummy_readbuf = *(u_char *)(addr + KSEG1);
+	}
+#endif
+
+	return 0;
+
+} /* _set_mem_map */
+
+/*======================================================================
+
+	Routines for accessing socket information and register dumps via
+	/proc/bus/pccard/...
+	
+======================================================================*/
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_read_info(char *buf, char **start, off_t pos,
+				  int count, int *eof, void *data)
+{
+	pcc_socket_info_t *s = data;
+	char *p = buf;
+	p += sprintf(p, "type:	 %s\nbase addr:	0x%08lx\n",
+				 pcc[s->type].name, s->base);
+	return (p - buf);
+}
+
+static int proc_read_exca(char *buf, char **start, off_t pos,
+				  int count, int *eof, void *data)
+{
+#if 0
+	u_short sock = (pcc_socket_info_t *)data - socket;
+#endif
+	char *p = buf;
+	int i, top;
+	
+	ISA_LOCK(sock, flags);
+	top = 0x40;
+	for (i = 0; i < top; i += 4) {
+		if (i == 0x50) {
+			p += sprintf(p, "\n");
+			i = 0x100;
+		}
+#if 0
+		p += sprintf(p, "%02x %02x %02x %02x%s",
+			 i365_get(sock,i), i365_get(sock,i+1),
+			 i365_get(sock,i+2), i365_get(sock,i+3),
+			 ((i % 16) == 12) ? "\n" : " ");
+#endif
+	}
+	ISA_UNLOCK(sock, flags);
+	return (p - buf);
+}
+
+static void pcc_proc_setup(unsigned int sock, struct proc_dir_entry *base)
+{
+	pcc_socket_info_t *s = &socket[sock];
+
+	if (s->flags & IS_ALIVE)
+			return;
+
+	create_proc_read_entry("info", 0, base, proc_read_info, s);
+	create_proc_read_entry("exca", 0, base, proc_read_exca, s);
+	s->proc = base;
+}
+
+static void pcc_proc_remove(u_short sock)
+{
+	struct proc_dir_entry *base = socket[sock].proc;
+	if (base == NULL) return;
+	remove_proc_entry("info", base);
+	remove_proc_entry("exca", base);
+}
+
+#else
+
+#define pcc_proc_setup NULL
+
+#endif /* CONFIG_PROC_FS */
+
+/*====================================================================*/
+
+#define LOCKED(x) return x
+
+static int pcc_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void * info)
+{
+	DEBUG(4, "m32r-pcc: reg call\n");
+	socket[sock].handler = handler;
+	socket[sock].info = info;
+	if (handler == NULL) {
+		MOD_DEC_USE_COUNT;
+	} else {
+		MOD_INC_USE_COUNT;
+	}
+	return 0;
+} /* pcc_register_callback */
+
+static int pcc_inquire_socket(unsigned int sock, socket_cap_t *cap)
+{
+	*cap = socket[sock].cap;
+	return 0;
+} /* pcc_inquire_socket */
+
+static int pcc_get_status(unsigned int sock, u_int *value)
+{
+	if (socket[sock].flags & IS_ALIVE) {
+		*value = 0;
+		return -EINVAL;
+	}
+	LOCKED(_pcc_get_status(sock, value));
+}
+
+static int pcc_get_socket(unsigned int sock, socket_state_t *state)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_get_socket(sock, state));
+}
+
+static int pcc_set_socket(unsigned int sock, socket_state_t *state)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+
+	LOCKED(_pcc_set_socket(sock, state));
+}
+
+static int pcc_get_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_get_io_map(sock, io));
+}
+
+static int pcc_set_io_map(unsigned int sock, struct pccard_io_map *io)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_io_map(sock, io));
+}
+
+static int pcc_get_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_get_mem_map(sock, mem));
+}
+
+static int pcc_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
+{
+	if (socket[sock].flags & IS_ALIVE)
+		return -EINVAL;
+	LOCKED(_pcc_set_mem_map(sock, mem));
+}
+
+static int pcc_init(unsigned int s)
+{
+	DEBUG(4, "m32r-pcc: init call\n");
+	return 0;
+}
+
+static int pcc_suspend(unsigned int sock)
+{
+	return pcc_set_socket(sock, &dead_socket);
+}
+
+
+static struct pccard_operations pcc_operations = {
+	pcc_init,
+	pcc_suspend,
+	pcc_register_callback,
+	pcc_inquire_socket,
+	pcc_get_status,
+	pcc_get_socket,
+	pcc_set_socket,
+	pcc_get_io_map,
+	pcc_set_io_map,
+	pcc_get_mem_map,
+	pcc_set_mem_map,
+	pcc_proc_setup
+};
+
+/*====================================================================*/
+
+static int __init init_m32r_pcc(void)
+{
+	servinfo_t serv;
+	pcmcia_get_card_services_info(&serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "m32r-pcc: Card Services release "
+			   "does not match!\n");
+		return -1;
+	}
+
+	DEBUG(0, "%s\n", version);
+	printk(KERN_INFO "m32r PCC probe:\n");
+	pcc_sockets = 0;
+
+	add_pcc_socket(M32R_PCC0_BASE, PCC0_IRQ, M32R_PCC0_MAPBASE, 0x1000);
+
+#ifdef CONFIG_M32RPCC_SLOT2
+	add_pcc_socket(M32R_PCC1_BASE, PCC1_IRQ, M32R_PCC1_MAPBASE, 0x2000);
+#endif
+
+	if (pcc_sockets == 0) {
+		printk("not found.\n");
+		return -ENODEV;
+	}
+	/* Set up interrupt handler(s) */
+
+	if (register_ss_entry(pcc_sockets, &pcc_operations) != 0)
+		printk(KERN_NOTICE "m32r_pcc: register_ss_entry() failed\n");
+
+	/* Finally, schedule a polling interrupt */
+#if 0
+	poll_interval = HZ;
+#endif
+	if (poll_interval != 0) {
+		poll_timer.function = pcc_interrupt_wrapper;
+		poll_timer.data = 0;
+		init_timer(&poll_timer);
+		poll_timer.expires = jiffies + poll_interval;
+		add_timer(&poll_timer);
+	}
+
+	return 0;
+} /* init_m32r_pcc */
+
+static void __exit exit_m32r_pcc(void)
+{
+#ifdef CONFIG_PROC_FS
+	int i;
+	for (i = 0; i < pcc_sockets; i++) pcc_proc_remove(i);
+#endif
+	unregister_ss_entry(&pcc_operations);
+
+} /* exit_m32r_pcc */
+
+module_init(init_m32r_pcc);
+module_exit(exit_m32r_pcc);
+
+/*
+ ***  Emacs  Setting ***
+ * Local Variables:
+ * c-basic-offset:4
+ * tab-width:4
+ * End:
+ */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/pcmcia/m32r_pcc.h linux-2.4.26/drivers/pcmcia/m32r_pcc.h
--- linux-2.4.26.org/drivers/pcmcia/m32r_pcc.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/pcmcia/m32r_pcc.h	2002-07-16 21:23:34.000000000 +0900
@@ -0,0 +1,70 @@
+/*
+ *  $Id: m32r_pcc.h,v 1.1 2002/07/16 12:23:34 sakugawa Exp $
+ *
+ * Copyright (C) 2001 by Hiroyuki Kondo
+ */
+
+
+
+#define M32R_MAX_PCC	2
+
+/*
+ * M32R PC Card Controler
+ */
+#define M32R_PCC0_BASE        0x00ef7000
+#define M32R_PCC1_BASE        0x00ef7020
+
+/*
+ * Register offsets
+ */
+#define PCCR            0x00
+#define PCADR           0x04
+#define PCMOD           0x08
+#define PCIRC           0x0c
+#define PCCSIGCR        0x10
+#define PCATCR          0x14
+
+/*
+ * PCCR
+ */
+#define PCCR_PCEN       (1UL<<(31-31))
+
+/*
+ * PCIRC
+ */
+#define PCIRC_BWERR     (1UL<<(31-7))
+#define PCIRC_CDIN1     (1UL<<(31-14))
+#define PCIRC_CDIN2     (1UL<<(31-15))
+#define PCIRC_BEIEN     (1UL<<(31-23))
+#define PCIRC_CIIEN     (1UL<<(31-30))
+#define PCIRC_COIEN     (1UL<<(31-31))
+
+/*
+ * PCCSIGCR
+ */
+#define PCCSIGCR_SEN    (1UL<<(31-3))
+#define PCCSIGCR_VEN    (1UL<<(31-7))
+#define PCCSIGCR_CRST   (1UL<<(31-15))
+#define PCCSIGCR_COCR   (1UL<<(31-31))
+
+/*
+ *
+ */
+#define PCMOD_AS_ATTRIB	(1UL<<(31-19))
+#define PCMOD_AS_IO	(1UL<<(31-18))
+
+#define PCMOD_CBSZ	(1UL<<(31-23)) /* set for 8bit */
+
+#define PCMOD_DBEX	(1UL<<(31-31)) /* set for excahnge */
+
+/*
+ * M32R PCC Map addr
+ */
+#define M32R_PCC0_MAPBASE        0x14000000
+#define M32R_PCC1_MAPBASE        0x16000000
+
+#define M32R_PCC_MAPMAX		 0x02000000
+
+#define M32R_PCC_MAPSIZE	 0x00001000 /* XXX */
+#define M32R_PCC_MAPMASK     	(~(M32R_PCC_MAPMAX-1))
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/Config.in linux-2.4.26/drivers/usb/Config.in
--- linux-2.4.26.org/drivers/usb/Config.in	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/usb/Config.in	2004-03-22 10:56:30.000000000 +0900
@@ -4,7 +4,14 @@
 mainmenu_option next_comment
 comment 'USB support'
 
-dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI
+if [ "$CONFIG_PLAT_MAPPI2" = "y" -o "$CONFIG_PLAT_M32700UT" = "y" ];
+then
+  define_bool CONFIG_M32R_USB y
+fi
+
+  dep_tristate 'Support for USB' CONFIG_USB $CONFIG_M32R_USB
+
+
 if [ "$CONFIG_USB" = "y" -o  "$CONFIG_USB" = "m" ]; then
    bool '  USB verbose debug messages' CONFIG_USB_DEBUG
 
@@ -21,6 +28,7 @@
    comment 'USB Device Class drivers'
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '    EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO
+
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       if [ "$CONFIG_BLUEZ" = "n" ]; then
          dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/Makefile linux-2.4.26/drivers/usb/Makefile
--- linux-2.4.26.org/drivers/usb/Makefile	2004-02-18 22:36:31.000000000 +0900
+++ linux-2.4.26/drivers/usb/Makefile	2004-04-12 13:06:03.000000000 +0900
@@ -77,6 +77,16 @@
 	obj-y += host/usb-ohci.o
 endif
 
+subdir-$(CONFIG_USB_PHCI)	+= host
+ifeq ($(CONFIG_USB_PHCI),y)
+	obj-y += host/usb_phci.o
+endif
+
+subdir-$(CONFIG_USB_HAL_MAPPI2)	+= host
+ifeq ($(CONFIG_USB_HAL_MAPPI2),y)
+	obj-y += host/hal_mappi2.o
+endif
+
 subdir-$(CONFIG_USB_SL811HS_ALT)	+= host
 subdir-$(CONFIG_USB_SL811HS)	+= host
 
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/hcd.c linux-2.4.26/drivers/usb/hcd.c
--- linux-2.4.26.org/drivers/usb/hcd.c	2004-04-14 22:05:32.000000000 +0900
+++ linux-2.4.26/drivers/usb/hcd.c	2004-04-28 11:27:03.000000000 +0900
@@ -1206,6 +1206,7 @@
 	if (urb->dev == hcd->bus->root_hub) {
 		status = rh_urb_enqueue (hcd, urb);
 	} else {
+#ifdef CONFIG_PCI
 		if (usb_pipecontrol (urb->pipe))
 			urb->setup_dma = pci_map_single (
 					hcd->pdev,
@@ -1220,6 +1221,7 @@
 					usb_pipein (urb->pipe)
 					    ? PCI_DMA_FROMDEVICE
 					    : PCI_DMA_TODEVICE);
+#endif
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
 	}
 	return status;
@@ -1489,6 +1491,7 @@
 	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
 	
 	/* For 2.4, don't unmap bounce buffer if it's a root hub operation. */
+#ifdef CONFIG_PCI
 	if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation)
 		pci_unmap_single (hcd->pdev, urb->setup_dma,
 				sizeof (struct usb_ctrlrequest),
@@ -1500,7 +1503,7 @@
 				usb_pipein (urb->pipe)
 				    ? PCI_DMA_FROMDEVICE
 				    : PCI_DMA_TODEVICE);
-
+#endif
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
 }
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/host/Config.in linux-2.4.26/drivers/usb/host/Config.in
--- linux-2.4.26.org/drivers/usb/host/Config.in	2003-11-29 03:26:20.000000000 +0900
+++ linux-2.4.26/drivers/usb/host/Config.in	2004-03-22 10:56:31.000000000 +0900
@@ -17,3 +17,6 @@
    dep_tristate '  SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  SL811HS (x86, StrongARM) support, old driver' CONFIG_USB_SL811HS $CONFIG_USB $CONFIG_EXPERIMENTAL
 fi
+dep_tristate '  ISP1362(Philips) support' CONFIG_USB_PHCI $CONFIG_USB
+dep_tristate '    M32R HAL support' CONFIG_USB_HAL_MAPPI2 $CONFIG_USB $CONFIG_USB_PHCI
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/host/Makefile linux-2.4.26/drivers/usb/host/Makefile
--- linux-2.4.26.org/drivers/usb/host/Makefile	2003-11-29 03:26:20.000000000 +0900
+++ linux-2.4.26/drivers/usb/host/Makefile	2004-03-22 10:56:31.000000000 +0900
@@ -9,8 +9,10 @@
 obj-$(CONFIG_USB_UHCI_ALT)			+= uhci.o
 obj-$(CONFIG_USB_UHCI)				+= usb-uhci.o
 obj-$(CONFIG_USB_OHCI)				+= usb-ohci.o
-obj-$(CONFIG_USB_SL811HS_ALT)  			+= sl811.o
-obj-$(CONFIG_USB_SL811HS)  			+= hc_sl811.o
+obj-$(CONFIG_USB_SL811HS_ALT)			+= sl811.o
+obj-$(CONFIG_USB_SL811HS)			+= hc_sl811.o
+obj-$(CONFIG_USB_PHCI)				+= usb_phci.o
+obj-$(CONFIG_USB_HAL_MAPPI2)			+= hal_mappi2.o
 
 # Extract lists of the multi-part drivers.
 # The 'int-*' lists are the intermediate files used to build the multi's.
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/host/usb_phci.c linux-2.4.26/drivers/usb/host/usb_phci.c
--- linux-2.4.26.org/drivers/usb/host/usb_phci.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/usb/host/usb_phci.c	2004-04-28 11:27:11.000000000 +0900
@@ -0,0 +1,5723 @@
+/*************************************************************
+ * Philips HCD (Host Controller Driver) for USB.
+ *
+ *	Original Host Controller driver code from Linux OS 2.4.5 Kernel and 
+ *  modified for Philips ISP1362 HCD
+ * 
+ * File Name:	usb_phci.c
+ *
+ * History:	
+ *
+ *	Version	Date		Author		Comments
+ * -------------------------------------------------
+ * 	1.0		09/23/02	SYARRA		Initial Release
+ *  1.1		11/22/02	SYARRA		Waiting in while loop for IsoTx
+ *									start of frame is changed (ISO_WAIT_FIX)
+ * 
+ *************************************************************/
+ 
+#include <linux/config.h>
+//#define MODULE
+#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>  /* for in_interrupt() */
+#undef DEBUG
+#include <linux/usb.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+
+#include "usb_phci.h"
+
+#include "../hcd.h"
+
+struct isp1362_dev	*isp1362_device = NULL;
+
+static int cc_to_error[16] = { 
+
+/* mapping of the OHCI CC status to error codes */ 
+	/* No  Error  */               USB_ST_NOERROR,
+	/* CRC Error  */               USB_ST_CRC,
+	/* Bit Stuff  */               USB_ST_BITSTUFF,
+	/* Data Togg  */               USB_ST_CRC,
+	/* Stall      */               USB_ST_STALL,
+	/* DevNotResp */               USB_ST_NORESPONSE,
+	/* PIDCheck   */               USB_ST_BITSTUFF,
+	/* UnExpPID   */               USB_ST_BITSTUFF,
+	/* DataOver   */               USB_ST_DATAOVERRUN,
+	/* DataUnder  */               USB_ST_DATAUNDERRUN,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* reservd    */               USB_ST_NORESPONSE,
+	/* BufferOver */               USB_ST_BUFFEROVERRUN,
+	/* BuffUnder  */               USB_ST_BUFFERUNDERRUN,
+	/* Not Access */               USB_ST_NORESPONSE,
+	/* Not Access */               USB_ST_NORESPONSE 
+};
+
+#define		phc_name					"PHCI-HC"	
+#if 1
+#define		PHCI_UNLINK_TIMEOUT			(HZ / 10)
+#else
+#define		PHCI_UNLINK_TIMEOUT			(HZ)
+#endif
+#define		DRIVER_AUTHOR	"Linux kernel 2.4.5 usb-ohci.c modified for Philips Semiconductors"
+#define		DRIVER_DESC	"USB Philips ISP1362 Host Controller Driver"
+
+/* Trace functions */
+#ifdef DEBUG
+void 	print_int_ed_list(phci_t	*phci);
+#endif
+
+#ifdef __PHCI_DEBUG_DETAIL__
+static	void 	phci_print_map_buffers(__u8	index);
+static	void 	phci_print_ptd_header(__u8	*header, __u32	pipe);
+static	void 	phci_print_hex_data(__u8	*data, __u32	length);
+static	void 	phci_print_hc_regs(phci_t	*phci, __u8	buff_type);
+static 	void 	phci_urb_print (struct urb * urb, char * str, int small);
+#endif /* __detail_debug__ */
+
+/* HC Register accessing functions decleration */
+void 	fnvPhciHcorWrite	(phci_t 	*phci,__u32 	uReg, __u32 	uRegData);
+void 	fnvPhciHcorRead	(phci_t 	*phci,__u32 	uReg, __u32 	*puRegData);
+void 	phci_reg_read16	(__u32	uReg, __u32 	*puRegData);
+void 	phci_reg_write16	(__u32 	uReg, __u32 	uRegData);
+
+/* HC RAM accessing functions decleration */
+void	fnvPhciRamRead(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data);
+void	fnvPhciRamWrite(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data);
+
+/* HC Initialization functions decleration */
+static	__u32 	fnvPhciHostReset	(phci_t 	*phci);
+static	void 	fnvHcIntEnable	(phci_t 	*phci);
+static	void 	fnvHcControlInit	(phci_t 	*phci);
+static	void 	fnvHcInterruptInit	(phci_t 	*phci);
+static	void 	fnvHcFmIntervalInit	(phci_t 	*phci);
+static	void 	fnvHcRhPower	(phci_t 	*phci);
+static	int	 	fnuPhciHostInit	(phci_t 	*phci);
+static	void	fnvHcRamBufferInit( phci_t	*phci) ;
+static	phci_t * __devinit 	hc_alloc_phci (struct isp1362_dev *dev);
+int __devinit 		hc_found_phci (struct isp1362_dev *dev) ;
+void 	hc_release_phci (phci_t * phci);
+
+/* HC Interrupt Functions */
+void 	phci_isr(struct isp1362_dev *dev, void *isr_data);
+
+static void 	fnvProcessAtlInt(phci_t	*phci);
+static void 	fnvProcessIntlInt(phci_t	*phci);
+static void 	fnvProcessIstlInt(phci_t	*phci);
+
+/* TD-PTD map function declerations */
+static	void 	phci_init_map_buffers(phci_t	*phci) ;
+static	void 	phci_get_td_ptd_index(ed_t	*ed);
+static	void 	phci_release_td_ptd_index(ed_t		*ed);
+static	void phci_move_pending_td_ptds(td_ptd_map_buff_t   *ptd_map_buff);
+static	void 	phci_fill_send_ptd(phci_t	*phci, __u32	send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff);
+static	void 	phci_fill_send_isoc_ptd(phci_t	*phci, __u32	send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff);
+static	void 	phci_submit_ed(phci_t	*phci,	ed_t	*ed) ;
+
+
+
+/* TD functions decleration */
+static 	void 	td_fill (unsigned int info, void * data, int len, struct urb * urb, int index);
+static 	void 	td_submit_urb (struct urb * urb);
+
+/* EP handling functions */
+static int 		ep_int_ballance (phci_t * phci, int interval, int load);
+static int 		ep_2_n_interval (int inter);
+static int 		ep_rev (int num_bits, int word);
+static int 		ep_link (phci_t * phci, ed_t * edi);
+static int 		ep_unlink (phci_t * phci, ed_t * ed);
+static void	 	ep_rm_ed (struct usb_device * usb_dev, ed_t * ed);
+static ed_t*	ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load);
+
+/* Done List handling functions */
+static void 	dl_transfer_length(td_t * td);
+static void 	dl_del_urb (phci_t * phci, struct urb * urb);
+static void 	dl_del_list (phci_t  * phci, unsigned int frame);
+static td_t * 	dl_reverse_done_list (phci_t * phci, td_t *td_list);
+static void 	dl_done_list (phci_t * phci, td_t * td_list);
+
+/* Root Hub function declerations */
+int 			rh_send_irq (phci_t * phci, void * rh_data, int rh_len);
+static void 	rh_int_timer_do (unsigned long ptr);
+static int 		rh_init_int_timer (struct urb * urb);
+static int 		rh_submit_urb (struct urb * urb);
+static int 		rh_unlink_urb (struct urb * urb);
+
+/* URB support functions */
+
+static void phci_complete_add(struct phci *phci, struct urb *urb);
+static struct urb *phci_complete_get(struct phci *phci);
+static void phci_complete(struct phci *phci);
+
+static void 	urb_free_priv( struct phci	*hc, urb_priv_t	*urb_priv);
+static void 	urb_rm_priv_locked (struct urb	*urb);
+
+/* USB core (usb.c) interface functions */
+static int 		sphci_alloc_dev (struct usb_device *usb_dev);
+static int 		sphci_free_dev (struct usb_device *usb_dev);
+static int 		sphci_get_current_frame_number (struct usb_device *usb_dev);
+static int 		sphci_return_urb (struct phci *hc, struct urb * urb);
+static int 		sphci_submit_urb (struct urb	*urb);
+static int 		sphci_unlink_urb (struct urb	*urb);
+
+#ifdef CONFIG_USB_HCDC_OTG
+/* otg function declerations for OTG driver interface */
+int		phci_register_otg(phci_otg_data_t	*otg_data);
+void	phci_unregister_otg(phci_otg_data_t	*otg_data);
+void	phci_otg_port_control(void *priv, __u8	cmd, __u32 *data);
+#endif /* CONFIG_USB_HCDC_OTG */
+
+/* Global Variable decleration */
+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[PIPE_BULK+1] = {	/* Pipe vs buffer type data structure */
+								TD_PTD_BUFF_TYPE_ISTL0, 					/* ISOC for ISTL0 */
+								TD_PTD_BUFF_TYPE_INTL,					/* INT	for INTL */
+								TD_PTD_BUFF_TYPE_ATL,					/* CONTROL for ATL */
+								TD_PTD_BUFF_TYPE_ATL					/* BULK for ATL */
+};
+static	__u8				atl_active_ptd_X_threshold_ptd[17] = {0,1,2,2,3,3,4,5,6,6,7,8,9,9,10,11,12};
+
+
+/*--------------------------------------------------------------*
+ * Host Controller operational registers write
+ *--------------------------------------------------------------*/
+void fnvPhciHcorWrite(phci_t *phci,__u32 uReg, __u32 uRegData) {
+
+	__u32	uData;
+
+	detail_debug(("fnvPhciHcorWrite(phci = 0x%p, uReg = 0x%x, uRegData = 0x%x)\n",phci, uReg, uRegData))
+
+	/* Check if the registers are controlled by software */
+	if ((uReg == uHcHcdControl ) || (uReg == (uHcHcdControl | 0x80))) {
+		phci->uHcHcdControl_hcd = uRegData;
+		return;
+	}
+
+	if ((uReg == uHcHcdCommandStatus) || (uReg == (uHcHcdCommandStatus | 0x80))) {
+		phci->uHcHcdCommandStatus_hcd = uRegData;
+		return;
+	}
+
+#ifdef CONFIG_USB_HCDC_OTG
+
+	/* In OTG mode, clear the internal connect status change bit */
+	if((uReg == (uHcRhPort1Status+OTG_HC_PORT_NO)) || (uReg == ((uHcRhPort1Status+OTG_HC_PORT_NO)|0x80))) {
+		if(uRegData & RH_PS_CSC) phci->otg_port_status &= ~(RH_PS_CSC);
+	}
+
+#endif /* CONFIG_USB_HCDC_OTG */
+
+
+	isp1362_command((uReg|0x80), isp1362_device);
+	uData = uRegData & 0x0000FFFF;
+	isp1362_write16(uData,isp1362_device);
+	uData = (uRegData & 0xFFFF0000) >> 16;
+	isp1362_write16(uData,isp1362_device);
+
+} /* fnvPhciHcorWrite() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller operational registers read
+ *--------------------------------------------------------------*/
+void fnvPhciHcorRead(phci_t *phci,__u32 uReg, __u32 *puRegData) {
+
+	__u32	uData;
+
+	detail_debug(("fnvPhciHcorRead(phci = 0x%p, uReg = 0x%x, puRegData = 0x%p)\n",phci, uReg, puRegData))
+
+	/* Service the HCD HC transfer control registers first */
+	if (uReg == uHcHcdControl ) {
+		*puRegData = phci->uHcHcdControl_hcd;
+		return;
+	}
+
+	if (uReg == uHcHcdCommandStatus) {
+		*puRegData = phci->uHcHcdCommandStatus_hcd;
+		return;
+	}
+
+	isp1362_command(uReg, isp1362_device);
+	uData = isp1362_read16(isp1362_device);
+	*puRegData = uData & 0x0000FFFF;
+	uData = isp1362_read16(isp1362_device);
+	*puRegData |= (uData & 0x0000FFFF) << 16;
+
+#ifdef CONFIG_USB_HCDC_OTG
+
+	/* In OTG mode mask the Connect status, connect status change bits from HC and give
+	 * internal values which are controlled by OTG module */
+
+	if(uReg == (uHcRhPort1Status+OTG_HC_PORT_NO)) {
+		*puRegData &= ~(RH_PS_CSC|RH_PS_CCS);
+		*puRegData |= (phci->otg_port_status & (RH_PS_CSC|RH_PS_CCS));
+	}
+
+#endif /* CONFIG_USB_HCDC_OTG */
+
+} /* fnvPhciHcorRead() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller registers read
+ *--------------------------------------------------------------*/
+void phci_reg_read16(__u32 uReg, __u32 *puRegData) {
+
+	__u32	uData;
+
+	detail_debug(("phci_reg_read16(uReg = 0x%x, puRegData = 0x%p)\n",uReg, puRegData))
+
+	isp1362_command(uReg,isp1362_device);
+	uData = isp1362_read16(isp1362_device);
+	*puRegData = uData;
+
+} /* phci_reg_read16() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller registers write
+ *--------------------------------------------------------------*/
+void phci_reg_write16(__u32 uReg, __u32 uRegData) {
+
+	detail_debug(("phci_reg_write16(uReg = 0x%x, uRegData = 0x%x)\n",uReg, uRegData))
+
+	isp1362_command((uReg|0x80), isp1362_device);
+	isp1362_write16(uRegData, isp1362_device);
+
+} /* phci_reg_write16() */
+
+
+
+/*--------------------------------------------------------------*
+ * Host Controller registers read 32 bit 
+ *--------------------------------------------------------------*/
+void phci_reg_read32(__u32 uReg, __u32 *puRegData) {
+
+	__u32	uData;
+
+	detail_debug(("phci_reg_read32(uReg = 0x%x, puRegData = 0x%p)\n",uReg, puRegData))
+
+	isp1362_command(uReg, isp1362_device);
+	uData = isp1362_read16(isp1362_device);
+	*puRegData = uData & 0x0000FFFF;
+	uData = isp1362_read16(isp1362_device);
+	*puRegData |= (uData & 0x0000FFFF) << 16;
+
+} /* phci_reg_read32() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller registers write 32 bit 
+ *--------------------------------------------------------------*/
+void phci_reg_write32(__u32 uReg, __u32 uRegData) {
+
+    __u32 	uData;
+
+	detail_debug(("phci_reg_write32(uReg = 0x%x, uRegData = 0x%x)\n",uReg, uRegData))
+    
+	isp1362_command((uReg|0x80), isp1362_device);
+	uData = uRegData & 0x0000FFFF;
+	isp1362_write16(uData,isp1362_device);
+	uData = (uRegData & 0xFFFF0000) >> 16;
+	isp1362_write16(uData,isp1362_device);
+	
+} /* phci_reg_write32() */
+
+#ifdef CONFIG_USB_PHCD_DMA
+void	fnvPhciRamWrite(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data) {
+
+	__u32		direct_addr_len;
+	__u16		dma_cnfg = 0;
+	__u32		int_reg;
+	unsigned int	flags;
+	__u32		original_length;
+
+	detail_debug(("fnvPhciRamWrite(length = %d, direction = %d, addr = 0x%x, byte_data = 0x%p)\n",length, direction, addr, byte_data))
+
+	if(!length || !byte_data) return;				/* If there is nothing to write , return back */
+
+	original_length = length;
+
+	if(length & 0x01)	length++;			/* Align length to even number */
+
+	/* fill the direct address length register with len+dir+addr */
+	direct_addr_len = addr & 0x7FFF;
+	direct_addr_len |= direction;
+	direct_addr_len |= (length << 16);
+
+	phci_reg_write32(REG_DIRECT_ADDR_LEN  ,direct_addr_len);  // writing the direct address length 
+
+	memcpy(phci->dma_buff, byte_data, original_length);
+
+	dma_cnfg = (DMA_BUFF_TYPE_DIR_ADDR | DMA_1CYCLE_BURST_LEN | DMA_COUNTER_ENABLE);	/* Disable DMA */
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+
+	/* Clear EOT bit inthe interrupt register */
+	phci_reg_write16(REG_IRQ, EOT_INT);
+
+	save_flags(flags);
+	disable_dma(DMA4HC_CHNNL);
+	clear_dma_ff(DMA4HC_CHNNL);
+	set_dma_mode(DMA4HC_CHNNL,DMA_MODE_WRITE);
+	set_dma_addr(DMA4HC_CHNNL,virt_to_bus(phci->dma_buff));
+	set_dma_count(DMA4HC_CHNNL, length);
+
+	/* Enable PC DMA */
+	enable_dma(DMA4HC_CHNNL);
+	restore_flags(flags);
+
+	dma_cnfg |= (DMA_ENABLE | DMA_WRITE_SELECT) ;
+
+	/* Enable HC DMA */
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+	
+	/* wait for End of transfer */
+	do {
+		isp1362_udelay(1);
+		phci_reg_read16(REG_IRQ, &int_reg);
+	} while(!(int_reg&EOT_INT));
+
+	/* Disable HC dma */
+	dma_cnfg &= ~(DMA_ENABLE | DMA_WRITE_SELECT) ;
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+
+	return;
+}
+
+void	fnvPhciRamRead(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data) {
+
+	__u32		direct_addr_len;
+	__u16		dma_cnfg = 0;
+	__u32		int_reg;
+	unsigned int	flags;
+	__u32		original_length;
+
+	detail_debug(("fnvPhciRamRead(length = %d, direction = %d, addr = 0x%x, byte_data = 0x%p)\n",length, direction, addr, byte_data))
+
+	if(!length || !byte_data) return;				/* If there is nothing to write , return back */
+
+	original_length = length;
+
+	if(length & 0x01)	length++;			/* Align length to even number */
+
+	/* fill the direct address length register with len+dir+addr */
+	direct_addr_len = addr & 0x7FFF;
+	direct_addr_len |= direction;
+	direct_addr_len |= (length << 16);
+
+	phci_reg_write32(REG_DIRECT_ADDR_LEN  ,direct_addr_len);  // writing the direct address length 
+
+
+	dma_cnfg = (DMA_BUFF_TYPE_DIR_ADDR | DMA_1CYCLE_BURST_LEN | DMA_COUNTER_ENABLE);	/* Disable DMA */
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+
+	/* Clear EOT bit inthe interrupt register */
+	phci_reg_write16(REG_IRQ, EOT_INT);
+
+	save_flags(flags);
+	disable_dma(DMA4HC_CHNNL);
+	clear_dma_ff(DMA4HC_CHNNL);
+	set_dma_mode(DMA4HC_CHNNL,DMA_MODE_READ);
+	set_dma_addr(DMA4HC_CHNNL,virt_to_bus(phci->dma_buff));
+	set_dma_count(DMA4HC_CHNNL, length);
+
+	/* Enable PC DMA */
+	enable_dma(DMA4HC_CHNNL);
+	restore_flags(flags);
+
+	dma_cnfg |= (DMA_ENABLE) ;
+
+	/* Enable HC DMA */
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+
+	/* wait for End of transfer */
+	do {
+		isp1362_udelay(1);
+		phci_reg_read16(REG_IRQ, &int_reg);
+	} while(!(int_reg&EOT_INT));
+
+	/* Disable HC dma */
+	dma_cnfg &= ~(DMA_ENABLE) ;
+	phci_reg_write16(REG_DMA_CNFG, dma_cnfg);
+
+	memcpy(byte_data, phci->dma_buff, original_length);
+
+	return;
+}
+
+
+#else /* CONFIG_USB_PHCD_DMA */
+
+/*--------------------------------------------------------------*
+ * Host Controller ATL/INTL/ISTL buffer Write
+ *--------------------------------------------------------------*/
+void	fnvPhciRamWrite(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data) {
+
+	__u32		direct_addr_len, cnt;
+	__u16		lower_dword, higher_dword = 0;
+	__u32		*dword_buff = (__u32*)byte_data;
+	__u32		original_length, rem_length;
+
+	detail_debug(("fnvPhciRamWrite(length = %d, direction = %d, addr = 0x%x, byte_data = 0x%p)\n",length, direction, addr, byte_data))
+
+	if(!length || !byte_data) return;				/* If there is nothing to write , return back */
+
+	original_length = length;
+
+	rem_length = (length & (RAM_BUFF_ALIGNMENT-1));		/* 0, 1, 2, 3 */
+
+	/* Make length to RAM_BUFF_ALIGNMENT byte boundary */
+	while(length & (RAM_BUFF_ALIGNMENT-1)){
+		length++;
+	}
+
+	/* fill the direct address length register with len+dir+addr */
+	direct_addr_len = addr & 0x7FFF;
+	direct_addr_len |= direction;
+	direct_addr_len |= (length << 16);
+
+	phci_reg_write32(REG_DIRECT_ADDR_LEN  ,direct_addr_len);  // writing the direct address length 
+
+
+   	/* Receive data from direct address register on the data IO */
+	isp1362_command((REG_DIRECT_ADDR_DATA|0x80), isp1362_device);
+
+	length = original_length;
+
+	if(direction == HC_DIR_ADDR_INCREMENT) {
+		length >>= 2;								/* total number of double words = length/4 */
+		cnt = 0;
+		while( cnt < length) {
+#if 0 /* debug sakugawa */
+			lower_dword = dword_buff[cnt];			/* convert dword to 2 words */
+			higher_dword = (dword_buff[cnt++] >> 16);
+			isp1362_write16(lower_dword,isp1362_device);
+			isp1362_write16(higher_dword,isp1362_device);
+#else
+			lower_dword = dword_buff[cnt];			/* convert dword to 2 words */
+			higher_dword = (dword_buff[cnt++] >> 16);
+			isp1362_write16(cpu_to_le16(higher_dword),isp1362_device);
+			isp1362_write16(cpu_to_le16(lower_dword),isp1362_device);
+#endif
+
+		}
+		
+#if 0 /* NSS Debug */
+		if(rem_length) {
+			length <<= 2;
+			lower_dword = byte_data[length];
+
+#if 0 /* debug sakugawa */
+			if(rem_length > 1) lower_dword |= (byte_data[length+1] << 8);
+			if(rem_length > 2) higher_dword = byte_data[length+2];
+			isp1362_write16(lower_dword,isp1362_device);
+			isp1362_write16(higher_dword,isp1362_device);
+#else
+			/* atomawasi */
+			if(rem_length > 1) higher_dword |= (byte_data[length+1] << 8);
+			if(rem_length > 2) lower_dword = byte_data[length+2];
+			isp1362_write16(le16_to_cpu(lower_dword),isp1362_device);
+			isp1362_write16(le16_to_cpu(higher_dword),isp1362_device);
+#endif
+		}
+#else
+		if(rem_length) {
+			higher_dword = 0;
+			lower_dword = 0;
+
+			length <<= 2;
+			lower_dword = byte_data[length];
+
+			if(rem_length > 1) lower_dword |= (byte_data[length+1] << 8);
+			if(rem_length > 2) higher_dword = byte_data[length+2];
+			isp1362_write16(lower_dword,isp1362_device);
+			isp1362_write16(higher_dword,isp1362_device);
+		}
+#endif
+	}
+	return;
+} /* End of fnvPhciRamWrite */
+
+/*--------------------------------------------------------------*
+ * Host Controller ATL/INTL/ISTL buffer Read
+ *--------------------------------------------------------------*/
+void	fnvPhciRamRead(phci_t	*phci, __u32	length, __u32	direction, __u32	addr, __u8	*byte_data) {
+
+	__u32		direct_addr_len, cnt;
+	__u16		lower_dword, higher_dword;
+	__u32		*dword_buff = (__u32*)byte_data;
+	__u32		original_length, rem_length, dword;
+
+
+
+	if(!length || !byte_data) return;				/* If there is nothing to read, return back */
+
+	original_length = length;
+
+	rem_length = (length & (RAM_BUFF_ALIGNMENT-1));		/* 0, 1, 2, 3 */
+
+	/* Make length to RAM_BUFF_ALIGNMENT byte boundary */
+	while(length & (RAM_BUFF_ALIGNMENT-1)){
+		length++;
+	}
+//	ALIGN_RAM_BUFF_LENGTH(length);
+
+	/* fill the direct address length register with len+dir+addr */
+	direct_addr_len = addr & 0x7FFF;
+	direct_addr_len |= direction;
+	direct_addr_len |= (length << 16);
+
+	phci_reg_write32(REG_DIRECT_ADDR_LEN  ,direct_addr_len);  // writing the direct address length 
+
+
+   	/* Receive data from direct address register on the data IO */
+	isp1362_command(REG_DIRECT_ADDR_DATA, isp1362_device);
+
+	length = original_length;
+
+	if(direction == HC_DIR_ADDR_INCREMENT) {
+		length >>= 2;								/* total number of double words = length/4 */
+		cnt = 0;
+		while( cnt < length) {
+#if 0 /* debug sakugawa */
+
+			lower_dword = isp1362_read16(isp1362_device);
+			higher_dword = isp1362_read16(isp1362_device);
+
+		    dword_buff[cnt++] = lower_dword | (higher_dword << 16) ;	/* Combine lower and higher 16 bits and fill buffer */
+#else
+			lower_dword = isp1362_read16(isp1362_device);
+			higher_dword = isp1362_read16(isp1362_device);
+			dword_buff[cnt++] = le16_to_cpu(higher_dword) | (le16_to_cpu(lower_dword) <<16);
+#endif
+
+		}
+		
+		if(rem_length) {
+			length <<= 2;
+#if 0 /* debug sakugawa */	
+
+			lower_dword = isp1362_read16(isp1362_device);
+			higher_dword = isp1362_read16(isp1362_device);
+			
+			dword = lower_dword | (higher_dword << 16) ;	/* make the 32 bit double word */
+#else
+
+			lower_dword = isp1362_read16(isp1362_device);
+			higher_dword = isp1362_read16(isp1362_device);
+			dword = le16_to_cpu(higher_dword) | (le16_to_cpu(lower_dword) <<16);	
+#endif
+
+#if 0
+			byte_data[length] = (dword & 0xFF);		/* Copy the first remaining byte */
+#else
+			byte_data[length] = (dword & 0xFF000000) >> 24;		/* Copy the first remaining byte */
+#endif
+			cnt = 1;
+
+#if 0 
+			while(cnt < rem_length) {			/* Based on reming bytes copy the 2nd, 3rd bytes */
+				dword >>= 8;
+				byte_data[length+cnt] = (dword & 0xFF);
+				cnt++;
+			}
+#else
+			while(cnt < rem_length) {			/* Based on reming bytes copy the 2nd, 3rd bytes */
+				dword <<= 8;
+				byte_data[length+cnt] = (dword & 0xFF000000) >> 24;
+				cnt++;
+			}
+#endif
+		}
+	}
+	return;
+} /* End of fnvPhciRamRead */
+
+#endif /* CONFIG_USB_PHCD_DMA */
+
+/*--------------------------------------------------------------*
+ * Host Controller Ram buffer parameter initialization
+ *--------------------------------------------------------------*/
+void	fnvHcRamBufferInit( phci_t	*phci) {
+
+	__u8		ram_data[1024];
+	int		i;
+	__u32	data = 0;
+
+
+	/* Configure ISTL buffer */
+	phci_reg_write16(REG_ISTL_BUFF_LEN, HC_ISTL_BUFFER_LENGTH);			/* Istl buffer length */
+	phci_reg_write16(REG_ISTL_TOGGLE_RATE, HC_ISTL_DEF_TOGGLE_RATE);	/* Istl toggle rate */
+
+	/* Configure INTL buffer */
+	phci_reg_write16(REG_INTL_BUFF_LEN, HC_INTL_BUFFER_LENGTH);			/* Intl buffer length */
+	phci_reg_write16(REG_INTL_BLK_PL_SIZE, HC_INTL_BLK_PL_SIZE);		/* Intl payload block size */
+
+	/* Configure ATL buffer */
+	phci_reg_write16(REG_ATL_BUFF_LEN, HC_ATL_BUFFER_LENGTH);			/* Atl buffer length */
+	phci_reg_write16(REG_ATL_BLK_PL_SIZE, HC_ATL_BLK_PL_SIZE);			/* Atl payload block size */
+
+	data = 0x0001 << (TD_PTD_MAX_ATL_TDS);
+	phci_reg_write32(REG_ATL_PTD_LAST_PTD,data);						/* Set the last ATL ptd in HC */
+
+	data = (0x0001 << (TD_PTD_MAX_INTL_TDS));
+	phci_reg_write32(REG_INTL_PTD_LAST_PTD,data);						/* Update the last INTL ptd in HC */
+
+	phci_reg_write16(REG_ATL_THRESHOLD_TIMEOUT,HC_DEF_ATL_THRESHOLD_TIMEOUT);	/* set the atl threshold ptd timeout HC */
+
+
+	phci_reg_write32(REG_ATL_PTD_SKIP_MAP,0xFFFFFFFF);					/* Set all ptds to skip */
+	phci_reg_write32(REG_INTL_PTD_SKIP_MAP,0xFFFFFFFF);					/* Set all ptds to skip */
+	
+	
+	/* Initialize the RAM buffer with zeros */
+	for(i=0;i<1024;i++) { ram_data[i] = 0; }
+	for(i=0; i<(HC_RAM_SIZE/1024);i++) {
+		fnvPhciRamWrite( phci, 1024, HC_DIR_ADDR_INCREMENT, i*1024, ram_data);
+	}
+
+	return;
+} /* End of fnvHcRamBufferInit */
+
+/*--------------------------------------------------------------*
+ * Host Controller Initialization functions 
+ *--------------------------------------------------------------*/
+/*--------------------------------------------------------------*
+ * Host Controller Reset
+ *--------------------------------------------------------------*/
+__u32 fnvPhciHostReset(phci_t *phci) {
+
+	__u32 uData;
+	__u32 uI;
+	__u32 uRetVal;
+
+	func_debug(("fnuHostReset(phci = 0x%p)\n",phci))
+
+	/* Set the HostController Reset bit in command status register */
+ 	fnvPhciHcorRead(phci,uHcCommandStatus,&uData);
+
+ 	uData = HC_COMMAND_STATUS_HCR;
+
+ 	fnvPhciHcorWrite(phci,uHcCommandStatus, uData);
+
+	/* wait some time for HC to be reset */
+ 	for(uI=0;uI<5000;uI++) {
+  		fnvPhciHcorRead(phci,uHcCommandStatus,&uData);
+  		if((uData & HC_COMMAND_STATUS_HCR) == 0) break;
+ 	}
+
+ 	uRetVal = uData & HC_COMMAND_STATUS_HCR;
+
+ return uRetVal;
+
+} /* End of fnvPhciHostReset */
+
+/*--------------------------------------------------------------*
+ * Host Controller hardware Interrupt Initialization
+ *--------------------------------------------------------------*/
+void fnvHcIntEnable(phci_t *phci) {
+
+	__u32		uData;
+
+	func_debug(("fnvHcIntEnable(phci = 0x%p)\n",phci))
+
+	/* Clear all pending int. source */
+	uData = 0xFFFFFFFF;
+	phci_reg_write16(REG_IRQ, uData);
+
+	/* Enable int. according settings in host_conf.h */
+	uData = 0;			/* All int. are initially disabled */
+
+	uData |= ATL_INT;	/* Enable ATL interrupt */
+
+//	uData |= SOF_INT;	/* Enable ATL interrupt */
+
+	uData |= INTL_INT;	/* Enable INTL interrupt */
+
+	uData |= ISTL_0_INT;	/* Enable ITL interrupt */
+
+	uData |= ISTL_1_INT;	/* Enable ITL interrupt */
+
+	phci_reg_write16(REG_IRQ_MASK, uData);
+
+} /* End of fnvHcIntEnable() */
+
+/*--------------------------------------------------------------*
+ * Host Controller Control Register Initialization
+ *--------------------------------------------------------------*/
+void fnvHcControlInit(phci_t *phci) {
+
+	__u32 uData;
+	__u32 uHostConfigData;
+
+	func_debug(("fnvHcControlInit(phci = 0x%p)\n",phci))
+
+	uHostConfigData = 0;
+
+	/* Fill the control register of HC */
+	/* (1) Set the sate to operational */
+	uData = HC_STATE;
+	uHostConfigData &= (~HC_CONTROL_HCFS);
+	uHostConfigData |= (uData << 6);
+
+	/* (2)  Enable remote wakeup connection if opted */
+	uData = REMOTE_WAKEUP_CONN;
+	uHostConfigData &= (~HC_CONTROL_RWC);
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_RWC;
+
+	/* (3)  Enable remote wakeup if opted */
+	uData = REMOTE_WAKEUP_ENABLE;
+	uHostConfigData &= (~HC_CONTROL_RWE);
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_RWE;
+
+	fnvPhciHcorWrite(phci,uHcControl, uHostConfigData);
+
+
+	/* Configure the HCD transfer control registers uHcHcdControl and uHcHcdCommandStatus */
+	uHostConfigData = 0;			
+	uData = PERIODIC_LIST_ENABLE;				/* Periodic list Enable ? */
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_PLE;
+
+	uData = ISO_ENABLE;							/* Isochronous transfer enabled  ? */
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_IE;
+
+	uData = CONTROL_LIST_ENABLE;				/* Control trasnfer enabled ? */
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_CLE;
+
+	uData = BULK_LIST_ENABLE;					/* Bulk Transfer Enabled ? */
+	if (uData == YES)
+		uHostConfigData |= HC_CONTROL_BLE;
+
+	/* Note: HC_CONTROL_TIP (Transfer In Progress) is alreday set to 0 */
+	phci->hc_control = (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_PLE | OHCI_USB_OPER ;
+
+	fnvPhciHcorWrite(phci,uHcHcdControl, uHostConfigData);
+
+} /* End of fnvHcControlInit() */
+
+/*--------------------------------------------------------------*
+ * Host Controller Interrupt Register Initialization
+ *--------------------------------------------------------------*/
+void fnvHcInterruptInit(phci_t *phci) {
+
+	__u32 uHostConfigData;
+
+	func_debug(("fnvHcInterruptInit(phci = 0x%p)\n",phci))
+
+	/* First of all, disable all interrupts */
+	uHostConfigData = HC_INTERRUPT_ALL;
+	fnvPhciHcorWrite(phci,uHcInterruptDisable, uHostConfigData);
+
+	uHostConfigData = 0;
+
+	/* Master Interrupt Enable */
+	uHostConfigData |= HC_INTERRUPT_MIE;
+
+	/* Write the configuration to uHcInterruptEnable register */
+	fnvPhciHcorWrite(phci,uHcInterruptEnable, uHostConfigData);
+
+
+} /* End of fnvHcInterruptInit() */
+
+/*--------------------------------------------------------------*
+ * Host Controller Frame Number interval Initialization
+ *--------------------------------------------------------------*/
+void fnvHcFmIntervalInit(phci_t *phci) {
+
+	__u32 uHostConfigData;
+
+	func_debug(("fnvHcFmIntervalInit(phci = 0x%p)\n",phci))
+
+	/* Determine the fram interval and the largest data size */
+	uHostConfigData = FRAME_INTERVAL | (FS_LARGEST_DATA << 16);
+
+	/* Write the configuration to uHcFmInterval register */
+	fnvPhciHcorWrite(phci,uHcFmInterval, uHostConfigData);
+
+} /* End of fnvHcFmIntervalInit() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller Roothub registers Initialization
+ *--------------------------------------------------------------*/
+void fnvHcRhPower(phci_t *phci) {
+
+	__u32 uData;
+	__u32 uHostConfigData;
+
+	func_debug(("fnvHcRhPower(phci = 0x%p)\n",phci))
+
+	/* Initialize the configuration data */
+	uHostConfigData = 0;
+
+	/* Enable or disable power switching */
+	uData = PORT_POWER_SWITCHING;
+
+	if (uData == NO)	/* No power switching; ports are always powered on when the HC is powered on */
+		uHostConfigData |= HC_RH_DESCRIPTORA_NPS;
+
+	else {
+
+		/********************************************************/
+		/* Power switching is enabled                           */
+		/* Program root hub in per-port switching mode          */
+		/********************************************************/
+		uHostConfigData |= HC_RH_DESCRIPTORA_PSM;
+
+	} /* else */
+
+
+	/* Port over current protection */
+	uData = OVER_CURRENT_PROTECTION;
+	if (uData == NO)					/* No over current protection */
+		uHostConfigData |= HC_RH_DESCRIPTORA_NOCP;
+
+	else
+		uData = PER_PORT_OVER_CURRENT_REPORT;
+		if (uData == YES)
+			uHostConfigData |= HC_RH_DESCRIPTORA_OCPM;
+
+	/* Set the power on to power good time */
+	uHostConfigData |= ((POWER_ON_TO_POWER_GOOD_TIME / 2) << 24);			/* Divided by 2, then move it into position */
+
+	fnvPhciHcorWrite(phci,uHcRhDescriptorA, uHostConfigData);
+
+	/* Set the global power to all the ports */
+        uHostConfigData = RH_HS_LPSC;
+        fnvPhciHcorWrite(phci,uHcRhStatus, uHostConfigData);
+
+	/* Wait till the POWER ON TO POWER GOOD time */
+        isp1362_mdelay(POWER_ON_TO_POWER_GOOD_TIME);
+
+
+	/* Set the HcRhDescriptorB register (13h) */
+	uHostConfigData = DEVICE_REMOVABLE;
+
+	if (PORT_POWER_SWITCHING == YES)
+		uHostConfigData |= 0xFFFF0000;		/* Set PPCM bits 31..16 to disable gang-mode power switching */
+
+	fnvPhciHcorWrite(phci,uHcRhDescriptorB, uHostConfigData);
+
+} /* End of fnvHcRhPower() */
+
+
+/*--------------------------------------------------------------*
+ * Host Controller Initialization
+ *--------------------------------------------------------------*/
+int	 fnuPhciHostInit(phci_t	*phci) {
+
+	struct usb_device 	*usb_dev;
+
+	func_debug(("fnuPhciHostInit(phci = 0x%p)\n",phci))
+
+	/* 1. Host Controller Extended Registers Initialization */
+	isp1362_set_hw_config(phci->phci_dev);
+
+	fnvHcIntEnable(phci);
+
+	fnvHcRamBufferInit(phci);
+
+	phci_init_map_buffers(phci);
+
+	fnvHcControlInit(phci);			 	/* Initialize HcControl register */
+	
+	phci->disabled = 0;
+
+	fnvHcInterruptInit(phci);			/* Initialize HcInterruptEnable/Disable registers */
+
+	fnvHcFmIntervalInit(phci);			/* Initialize HcFmInterval Register */
+
+	fnvHcRhPower(phci);					/* Root hub port power switching mode */
+
+	phci->rh.devnum = 0;				/* No root hub yet */
+
+	phci->p_ed_controlhead = NULL;		/* Initialize control & bulk list heads */
+	phci->p_ed_bulkhead = NULL;
+
+#ifndef CONFIG_USB_HCDC_OTG
+	/* Select the port 1 to HC by writing the OTG Control register
+	 * HC_DC_SEL to HC */
+	phci_reg_write16(0x62,0x0601);	
+#endif /* CONFIG_USB_HCDC_OTG */
+
+	/* Allocate data structure for root hub */
+	usb_dev = usb_alloc_dev ( NULL, phci->bus) ;
+	
+	if( !usb_dev ) {
+		phci->disabled = 1;
+		return -ENOMEM;
+	}
+
+	phci->bus->root_hub = usb_dev;
+
+	/* Connect the virtual hub to the usb bus, host stack will do all the enumeration,
+	   configuration etc.. */
+	usb_connect (usb_dev); 
+
+	if(usb_new_device(usb_dev) != 0) {
+		usb_free_dev(usb_dev);
+		phci->disabled = 1;
+		return -ENODEV;
+	}
+
+	return 0;
+} /* End of fnuPhciHostInit() */
+
+
+
+/*--------------------------------------------------------------*
+ * HC  TD-PTD functions 										* 
+ *--------------------------------------------------------------*/
+
+static __u8		td_ptd_buff_type_max_ptds[TD_PTD_TOTAL_BUFF_TYPES] = {
+	TD_PTD_MAX_ATL_TDS,
+	TD_PTD_MAX_INTL_TDS,
+	TD_PTD_MAX_ISTL_TDS,
+	TD_PTD_MAX_ISTL_TDS
+};
+
+static __u8		hc_ram_buff_port_reg[TD_PTD_TOTAL_BUFF_TYPES] = {
+	REG_ATL_BUFF_PORT,
+	REG_INTL_BUFF_PORT,
+	REG_ISTL0_BUFF_PORT,
+	REG_ISTL1_BUFF_PORT
+};
+
+static __u16	hc_ram_buff_lengths[TD_PTD_TOTAL_BUFF_TYPES] = {
+	HC_ATL_BUFFER_LENGTH,
+	HC_INTL_BUFFER_LENGTH,
+	HC_ISTL_BUFFER_LENGTH,
+	HC_ISTL_BUFFER_LENGTH
+};
+
+static __u16	hc_ram_buff_block_pl_size[TD_PTD_TOTAL_BUFF_TYPES] = {
+	HC_ATL_BLK_PL_SIZE,
+	HC_INTL_BLK_PL_SIZE,
+	HC_ISTL_BLK_PL_SIZE,
+	HC_ISTL_BLK_PL_SIZE
+};
+
+static __u16	hc_ram_buff_address[TD_PTD_TOTAL_BUFF_TYPES] = {
+	HC_ATL_ADDRESS,
+	HC_INTL_ADDRESS,
+	HC_ISTL_0_ADDRESS,
+	HC_ISTL_1_ADDRESS
+};
+
+#ifdef __PHCI_DEBUG_DETAIL__
+
+/*--------------------------------------------------------------*
+ * HC TD-PTD map buffers print functions 						* 
+ *--------------------------------------------------------------*/
+void phci_print_map_buffers(__u8	index) {
+	__u8	index1;
+	td_ptd_map_buff_t	*ptd_map_buff;
+
+	ptd_map_buff = &(td_ptd_map_buff[index]);
+	printk("buffer:: %p, buffer type:: %d\n",ptd_map_buff, ptd_map_buff->buffer_type);
+	printk("\tbuffer active_ptds:: %d \n\tbuffer total_ptds:: %d\n",ptd_map_buff->active_ptds, ptd_map_buff->total_ptds);
+	printk("\tbuffer max_ptds:: %d \n\tbuffer active_ptd_bitmap:: %x\n",ptd_map_buff->max_ptds, ptd_map_buff->active_ptd_bitmap);
+	printk("\tbuffer skip_ptd_bitmap:: %x \n\tbuffer ram_buff_addr:: %x \n",ptd_map_buff->skip_ptd_bitmap, ptd_map_buff->ram_buff_addr);
+
+	printk("\tbuffer buffer_length:: %d \n\tbuffer buffer_port:: %d\n",ptd_map_buff->regs.buffer_length, ptd_map_buff->regs.buffer_port);
+	printk("\tbuffer block_pl_size:: %d \n\tbuffer toggle_rate:: %d\n",ptd_map_buff->regs.block_pl_size, ptd_map_buff->regs.toggle_rate);
+	printk("\tbuffer last_ptd:: %d \n\tbuffer ptd_done_map:: %x\n",ptd_map_buff->regs.last_ptd, ptd_map_buff->regs.ptd_done_map);
+	printk("\tbuffer ptd_skip_map:: %x \n\tbuffer curr_active_ptd:: %d\n",ptd_map_buff->regs.ptd_skip_map, ptd_map_buff->regs.curr_active_ptd);
+	printk("\tbuffer threshold_count:: %d \n\tbuffer threshold_timeout:: %d\n",ptd_map_buff->regs.threshold_count, ptd_map_buff->regs.threshold_timeout);
+
+	for(index1=0; index1<ptd_map_buff->max_ptds;index1++){
+		printk("td_ptd_map = %p\n", &(ptd_map_buff->map_list[index1]));
+		printk("\t\tbuffer state:: %d \n\t\tbuffer total_bytes:: %d\n",ptd_map_buff->map_list[index1].state, ptd_map_buff->map_list[index1].total_bytes);
+		printk("\t\tbuffer ptd_bitmap:: %x \n\t\tbuffer td:: %p\n",ptd_map_buff->map_list[index1].ptd_bitmap, ptd_map_buff->map_list[index1].td);
+	}
+
+} /* phci_print_map_buffers */
+
+/*--------------------------------------------------------------*
+ * print buffer data in hex format functions 					* 
+ *--------------------------------------------------------------*/
+void phci_print_hex_data(__u8	*data, __u32	length) {
+	__u32	index;
+
+	for(index = 0; index < length; index++) {
+		if(index%8 == 0) printk("\n");
+		printk(" 0x%2x  ", data[index]);
+	}
+	printk("\n");
+	
+	return;
+}
+
+/*--------------------------------------------------------------*
+ * HC TD-PTD map buffers print functions 						* 
+ *--------------------------------------------------------------*/
+void phci_print_ptd_header(__u8	*header, __u32	pipe) {
+	
+	__u16	data;
+	
+#ifdef CONFIG_USB_PHCD_EVEN_SCH
+	__u8	poll_int;
+#endif /* CONFIG_USB_PHCD_EVEN_SCH */
+
+	printk("  0x%x  0x%x  0x%x  0x%x  0x%x  0x%x  0x%x  0x%x\n",header[0],header[1],header[2],header[3],header[4],header[5],header[6],header[7]);
+
+	printk("PTD_HEADER for pipe :: %s\n", ((pipe==PIPE_CONTROL) ? "CONTROL" : ((pipe == PIPE_INTERRUPT) ? "INTERRUPT" : ((pipe == PIPE_BULK) ? "BULK" : "ISOCHRONOUS"))));
+	data = ((header[1] & 0x03) << 8);
+	data |= header[0];
+	printk("     Actual Bytes: %d\n", data);
+	data = header[1];
+	printk("     CC: 0x%x     %s     toggle: %d\n", ((data & 0xF0)>>4), (data&0x8) ? "ACTIVE" : "NOT ACTIVE", (data&0x4)>>2);
+	data = ((header[3] & 0x03) << 8);
+	data |= header[2];
+	printk("     Max Packet Size: %d\n", data);
+	data = header[3];
+	if(pipe == PIPE_ISOCHRONOUS) {
+		printk("     EN: %x     %s    %s\n", ((data & 0xF0)>>4), (data&0x8) ? "LAST PTD" : "", (data&0x4) ? "LOW SPEED" : "FULL SPEED");
+	} else {
+		printk("     EN: %x     %s\n", ((data & 0xF0)>>4), (data&0x4) ? "LOW SPEED" : "FULL SPEED");
+	}
+	data = ((header[5] & 0x03) << 8);
+	data |= header[4];
+	printk("     Total Bytes: %d\n", data);
+	data = header[5];
+	if(pipe == PIPE_INTERRUPT) {
+		printk("     Dir:: %s\n", ( ((data & 0xC) == 0) ? "SETUP" : (((data & 0xC) == 0x4) ? "OUT" : "IN")));
+		data = header[6];
+#ifdef CONFIG_USB_PHCD_EVEN_SCH
+		poll_int = ((header[6] & 0xE0) >> 5) ;
+		printk("     Addr: %d     poll interval = %d milli seconds, start fn# = %d\n", data & 0x7F, ((poll_int == 0) ? 1 : ( (poll_int == 2) ? 2 : ((poll_int == 4) ? 4 : ((poll_int == 6) ? 8 : ((poll_int == 8) ? 16 : 32))))), (header[7] & 0x1F));
+#else
+		printk("     Addr: %d     poll interval = %d milli seconds\n", data & 0x7F, ((header[7] == 0) ? 1 : ( (header[7] == 2) ? 2 : ((header[7] == 4) ? 4 : ((header[7] == 6) ? 8 : ((header[7] == 8) ? 16 : 32))))));
+#endif /* CONFIG_USB_PHCD_EVEN_SCH */
+	} else if( pipe == PIPE_ISOCHRONOUS) {
+		printk("     Dir:: %s\n", ( ((data & 0xC) == 0) ? "SETUP" : (((data & 0xC) == 0x4) ? "OUT" : "IN")));
+		data = header[6];
+		printk("     Addr: %d     fn = 0x%x\n", data & 0x7F, header[7]);
+	} else {
+		if(data & 0x80) {
+			printk("     PAIRED  %s  Dir:: %s\n", (data & 0x40) ? "PONG" : "PING", ( ((data & 0xC) == 0) ? "SETUP" : (((data & 0xC) == 0x4) ? "OUT" : "IN")));
+		} else {
+			printk("     NOT PAIRED     Dir:: %s\n", ( ((data & 0xC) == 0) ? "SETUP" : (((data & 0xC) == 0x4) ? "OUT" : "IN")));
+		}
+		data = header[6];
+		printk("     Addr: %d\n", data & 0x7F);
+	}
+
+} /* phci_print_ptd_header */
+
+void phci_print_hc_regs(phci_t	*phci, __u8	buff_type) {
+	__u32	data_read = 0;
+
+	if(buff_type ==  TD_PTD_BUFF_TYPE_ATL) {
+		phci_reg_read16(REG_BUFF_STS,&data_read);
+		printk("Buffer Status = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_IRQ_MASK, &data_read);
+		printk("  Irq_mask = %x\n", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ISTL_BUFF_LEN, &data_read);
+		printk("  Istl Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_INTL_BUFF_LEN, &data_read);
+		printk("  INTL Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_BUFF_LEN, &data_read);
+		printk(" Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_BLK_PL_SIZE, &data_read);
+		printk("  Block_pl_size = %x\n", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_THRESHOLD_COUNT,&data_read);
+		printk("threshold_count = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_THRESHOLD_TIMEOUT,&data_read);
+		printk("  threshold_timeout = %x\n", data_read);
+		data_read = 0;
+		phci_reg_read32(REG_ATL_PTD_DONE_MAP, &data_read);
+		printk("done_map = %x", data_read);
+		data_read = 0;
+		phci_reg_read32(REG_ATL_PTD_SKIP_MAP, &data_read);
+		printk("  skip_map %x\n", data_read); 
+		data_read = 0;
+		phci_reg_read32(REG_ATL_PTD_LAST_PTD,&data_read);		
+		printk("last_ptd_map %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_CURR_ACTIVE_PTD,&data_read);		
+		printk("  curr_act_ptd %x\n", data_read);
+	} else if(buff_type ==  TD_PTD_BUFF_TYPE_INTL) {
+		phci_reg_read16(REG_BUFF_STS,&data_read);
+		printk("Buffer Status = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_IRQ_MASK, &data_read);
+		printk("  Irq_mask = %x\n", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ISTL_BUFF_LEN, &data_read);
+		printk("  Istl Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_INTL_BUFF_LEN, &data_read);
+		printk("  INTL Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_ATL_BUFF_LEN, &data_read);
+		printk(" Buffer_len = %x", data_read);
+		data_read = 0;
+		phci_reg_read16(REG_INTL_BLK_PL_SIZE, &data_read);
+		printk("  Block_pl_size = %x\n", data_read);
+		data_read = 0;
+		phci_reg_read32(REG_INTL_PTD_DONE_MAP, &data_read);
+		printk("done_map = %x", data_read);
+		data_read = 0;
+		phci_reg_read32(REG_INTL_PTD_SKIP_MAP, &data_read);
+		printk("  skip_map %x\n", data_read);
+		data_read = 0;
+		phci_reg_read32(REG_INTL_PTD_LAST_PTD,&data_read);		
+		printk("last_ptd_map %x", data_read);
+	}
+}
+
+void phci_urb_print (struct urb * urb, char * str, int small) {
+	unsigned int pipe= urb->pipe;
+	
+	if (!urb->dev || !urb->dev->bus) {
+		printk("%s URB: no dev", str);
+		return;
+	}
+	
+	if (urb->status != 0)
+	printk("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)", 
+			str,
+		 	sphci_get_current_frame_number (urb->dev), 
+		 	usb_pipedevice (pipe),
+		 	usb_pipeendpoint (pipe), 
+		 	usb_pipeout (pipe)? 'O': 'I',
+		 	usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+		 		(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+		 	urb->transfer_flags, 
+		 	urb->actual_length, 
+		 	urb->transfer_buffer_length,
+		 	urb->status, urb->status);
+
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printk (KERN_DEBUG __FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++) 
+				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
+			printk ("\n");
+		}
+		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
+			printk (KERN_DEBUG __FILE__ ": data(%d/%d):", 
+				urb->actual_length, 
+				urb->transfer_buffer_length);
+			len = usb_pipeout (pipe)? 
+						urb->transfer_buffer_length: urb->actual_length;
+			for (i = 0; i < 16 && i < len; i++) 
+				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
+			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+		}
+	} 
+}
+#endif /* __PHCI_DEBUG_DETAIL__ */
+
+
+/*--------------------------------------------------------------*
+ * HC TD-PTD map buffers initialization functions 			* 
+ *--------------------------------------------------------------*/
+void phci_init_map_buffers(phci_t	*phci) {
+
+	td_ptd_map_buff_t	*ptd_map_buff;
+	__u8				buff_type, ptd_index;
+	__u32				bitmap;
+
+	func_debug(("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;					/* Set buffer type */
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+		ptd_map_buff->ping_pong_status = 0;							/* Set ping pong status to not in use */
+		ptd_map_buff->ping_ptd_index = TD_PTD_INV_PTD_INDEX;		/* ping ptd index is invalid index */
+		ptd_map_buff->pong_ptd_index = TD_PTD_INV_PTD_INDEX;		/* pong ptd index is invalid index */
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+		ptd_map_buff->active_ptds = 0;								/* active td's = 0 */
+		ptd_map_buff->total_ptds = 0;								/* total td's = 0 */
+		ptd_map_buff->max_ptds = td_ptd_buff_type_max_ptds[buff_type];	/* set maximum ptds for this buffer type */
+		ptd_map_buff->active_ptd_bitmap = 0;						/* no active ptds */
+		ptd_map_buff->skip_ptd_bitmap = 0xFFFFFFFF;					/* Skip all ptds */
+		ptd_map_buff->pending_ptd_bitmap = 0x00000000;				/* Initially no pending ptds */
+
+		bitmap = 0x00000001;
+
+		for(ptd_index = 0; ptd_index < ptd_map_buff->max_ptds; ptd_index++) {
+			ptd_map_buff->active_ptd_bitmask |= bitmap;
+			bitmap <<= 1;
+		}
+		
+		ptd_map_buff->ram_buff_addr = hc_ram_buff_address[buff_type];		/* Buffer lengths for each buffer */
+		ptd_map_buff->done_head = NULL;										/* No done ptd's */
+		ptd_map_buff->frame_number = INVALID_FRAME_NUMBER;					/* Invalid frame number */
+		
+		ptd_map_buff->regs.buffer_length = hc_ram_buff_lengths[buff_type];			/* Buffer lengths for each buffer */
+		ptd_map_buff->regs.buffer_port = hc_ram_buff_port_reg[buff_type];			/* Buffer accessing port register */
+		ptd_map_buff->regs.block_pl_size = hc_ram_buff_block_pl_size[buff_type];	/* Block pay load size */
+		ptd_map_buff->regs.toggle_rate = HC_ISTL_DEF_TOGGLE_RATE;					/* toggle rate for ISTL buffer */
+		ptd_map_buff->regs.last_ptd = 0;								/* Last PTD for ATL & INTL is zero */
+		ptd_map_buff->regs.ptd_done_map = 0;							/* No PTD is done */
+		ptd_map_buff->regs.ptd_skip_map = 0;							/* Skip all PTD */
+		ptd_map_buff->regs.curr_active_ptd = 0;							/* current active ptd is zero */
+		ptd_map_buff->regs.threshold_count = HC_DEF_ATL_THRESHOLD_COUNT;		/* Default ptd thereshold for ATL */
+		ptd_map_buff->regs.threshold_timeout = HC_DEF_ATL_THRESHOLD_TIMEOUT;	/* Default thereshold timeout for ATL */
+
+		/* For each ptd index of this buffer, set the fiedls */
+		bitmap = 0x00000001;
+//		for(ptd_index = 0; ptd_index < ptd_map_buff->max_ptds; ptd_index++)
+		for(ptd_index = 0; ptd_index < TD_PTD_MAX_BUFF_TDS; ptd_index++){
+			ptd_map_buff->map_list[ptd_index].state = TD_PTD_NEW;	/* Set the td_ptd as new */
+			ptd_map_buff->map_list[ptd_index].total_bytes = 0;		/* total bytes to 0 */
+			ptd_map_buff->map_list[ptd_index].ptd_bitmap = bitmap;	/* set the bitmap for this buffer */
+			ptd_map_buff->map_list[ptd_index].td = NULL;
+			ptd_map_buff->map_list[ptd_index].ed = NULL;
+			ptd_map_buff->map_list[ptd_index].ping_pong = TD_PTD_NO_PING_PONG;
+			ptd_map_buff->map_list[ptd_index].ram_addr = 0xFFFF;
+			bitmap <<= 1;
+
+		}/* for( ptd_index */
+
+	}	/* for(buff_type */
+
+} /* phci_init_map_buffers */
+
+
+/* This function is called when ep is linked to the oprational ep list.
+	It searches for the free td_ptd_index.
+	If the ping pong ptd is not set, sets the next free td_ptd_index to
+	pong ptd index */
+/*--------------------------------------------------------------*
+ * HC get td ptd index from TD-PTD map buffer					* 
+ *--------------------------------------------------------------*/
+void	phci_get_td_ptd_index(ed_t	*ed) {
+
+	__u8	buff_type = td_ptd_pipe_x_buff_type[ed->type];
+	__u8	td_ptd_index, index;
+	__u8	max_ptds;
+
+	td_ptd_map_buff_t	*ptd_map_buff = &(td_ptd_map_buff[buff_type]);
+
+	func_debug(("phci_get_td_ptd_index(ed = 0x%p)\n",ed))
+
+	/* ATL PTDs can wait */
+	max_ptds = (buff_type == TD_PTD_BUFF_TYPE_ATL) ? TD_PTD_MAX_BUFF_TDS : ptd_map_buff->max_ptds;
+
+
+	for(td_ptd_index = 0; td_ptd_index < max_ptds; td_ptd_index++) {	/* Find the first free slot */
+
+		if(ptd_map_buff->map_list[td_ptd_index].state == TD_PTD_NEW) {
+				/* Found a free slot */
+			if( ed->td_ptd_index == TD_PTD_INV_PTD_INDEX ) {
+				ed->td_ptd_index = td_ptd_index;
+			}
+#ifdef CONFIG_USB_PHCD_PING_PONG
+			else {
+				/* Might be a bulk pong ptd index (bulk, not already 
+				 * ping is running and not a pending one) */
+				if( (ed->type != PIPE_BULK) || 
+					(td_ptd_index >= ptd_map_buff->max_ptds) ||
+					(ptd_map_buff->ping_ptd_index != TD_PTD_INV_PTD_INDEX) )  {
+						break;
+				}
+
+				ptd_map_buff->ping_ptd_index =  ed->td_ptd_index;
+				ptd_map_buff->pong_ptd_index =  td_ptd_index;
+			}
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+			
+			ptd_map_buff->map_list[td_ptd_index].state = TD_PTD_OPER;	/* put ptd_index to operational state */
+			ptd_map_buff->map_list[td_ptd_index].td = NULL;				/* No td transfer is in progress */
+			ptd_map_buff->map_list[td_ptd_index].ed = ed;				/* initialize the ed pointer */
+			ptd_map_buff->map_list[td_ptd_index].ping_pong = 0;			/* initialize the ping pong flag */
+			ptd_map_buff->total_ptds ++;								/* update # of total td's */
+		
+			if( ed->type == PIPE_ISOCHRONOUS) {				/* reserve additional indexes for ISTL buffer */
+				for(index=0; index < ptd_map_buff->regs.toggle_rate;index++) {   /* for serving till the toggle rate */
+					ptd_map_buff->map_list[td_ptd_index+index].state = TD_PTD_OPER;
+					ptd_map_buff->map_list[td_ptd_index+index].ed = ed;			/* initialize the ed pointer */
+				}
+				ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1]);
+				for(index=0; index < ptd_map_buff->regs.toggle_rate;index++) {   /* for serving till the toggle rate */
+					ptd_map_buff->map_list[td_ptd_index+index].state = TD_PTD_OPER;
+					ptd_map_buff->map_list[td_ptd_index+index].ed = ed;			/* initialize the ed pointer */
+				}
+			}
+
+			break;
+		}
+	}
+	
+	return;
+} /* phci_get_td_ptd_index */
+
+
+/*--------------------------------------------------------------*
+ * HC release td ptd index from TD-PTD map buffer				* 
+ *--------------------------------------------------------------*/
+void phci_release_td_ptd_index(ed_t		*ed) {
+
+	__u8				td_ptd_index = ed->td_ptd_index;
+	__u8				buff_type = td_ptd_pipe_x_buff_type[ed->type];
+	td_ptd_map_buff_t   *ptd_map_buff;
+	td_ptd_map_buff_t   *ptd_map_buff1;
+	td_ptd_map_t		*ptd_map;
+	__u8				index;
+	__u32				ptd_bitmap = 0, skip_map;
+
+	func_debug(("phci_release_td_ptd_index(ed = 0x%p)\n",ed))
+
+
+	if( td_ptd_index != TD_PTD_INV_PTD_INDEX) {
+		ptd_map_buff = &(td_ptd_map_buff[buff_type]);
+	
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+		/* Check if this is ping pong ptd ed or not, if yes clear the pong ptd index also */
+		if( ed->type == PIPE_BULK && ptd_map_buff->ping_ptd_index == td_ptd_index){
+			ptd_map = &(ptd_map_buff->map_list[ptd_map_buff->pong_ptd_index]);
+
+			ptd_map_buff->total_ptds --;
+			if(ptd_map->td)	ptd_map_buff->active_ptds--;
+			ptd_map_buff->active_ptd_bitmap &= (~(ptd_map->ptd_bitmap));
+			ptd_map->state = TD_PTD_NEW;
+			ptd_map->td = NULL;
+			ptd_map->ed = NULL;
+			ptd_bitmap |= ptd_map->ptd_bitmap;
+
+			ptd_map_buff->ping_ptd_index = TD_PTD_INV_PTD_INDEX;
+			ptd_map_buff->pong_ptd_index = TD_PTD_INV_PTD_INDEX;
+			ptd_map_buff->ping_pong_status = 0;
+		}
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+		ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+
+		ptd_map_buff->total_ptds --;
+		if(ed->type == PIPE_ISOCHRONOUS) {
+
+			/* For isochronous pipe, clear all the td_ptd_index of toggle rate */
+			for(index = 0; index < ptd_map_buff->regs.toggle_rate; index++) {
+
+				ptd_map = &(ptd_map_buff->map_list[td_ptd_index+index]);
+				ptd_map_buff->active_ptd_bitmap &= (~(ptd_map->ptd_bitmap));
+				ptd_map->state = TD_PTD_NEW;
+				ptd_map->td = NULL;
+				ptd_map->ed = NULL;
+
+			}
+
+			ptd_map_buff1 = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1]);
+
+			for(index = 0; index < ptd_map_buff->regs.toggle_rate; index++) {
+
+				ptd_map = &(ptd_map_buff1->map_list[td_ptd_index+index]);
+				ptd_map_buff1->active_ptd_bitmap &= (~(ptd_map->ptd_bitmap));
+				ptd_map->state = TD_PTD_NEW;
+				ptd_map->td = NULL;
+				ptd_map->ed = NULL;
+			}
+
+		} else {
+
+			if(ptd_map->td)	ptd_map_buff->active_ptds--;		/* this ed is deleted in between */
+
+			ptd_map_buff->active_ptd_bitmap &= (~(ptd_map->ptd_bitmap));
+			ptd_map->state = TD_PTD_NEW;
+			ptd_map->td = NULL;
+			ptd_map->ed = NULL;
+			ptd_bitmap |= ptd_map->ptd_bitmap;
+
+		}
+		ed->td_ptd_index = TD_PTD_INV_PTD_INDEX;
+
+		if(buff_type == TD_PTD_BUFF_TYPE_ATL) {
+			phci_reg_read32(REG_ATL_PTD_SKIP_MAP, &skip_map);	/* Read the ATL skip map */
+			skip_map |= ptd_map->ptd_bitmap;
+			phci_reg_write32(REG_ATL_PTD_SKIP_MAP,skip_map);	/* Skip all ptds */
+		}
+	}
+
+	return;
+
+} /* end of phci_release_td_ptd_index */
+
+/* Applicable only for ATL buffer */
+void phci_move_pending_td_ptds(td_ptd_map_buff_t   *ptd_map_buff) {
+	   
+	ed_t				*ed;
+	td_t				*td;
+	td_ptd_map_t		*ptd_map;
+	__u8				td_ptd_index;
+	
+
+	if(ptd_map_buff->pending_ptd_bitmap) {
+
+		/* There are some pending ptd maps that need to be moved to Active ptd map */
+
+		for(td_ptd_index = 0; td_ptd_index < TD_PTD_MAX_BUFF_TDS; td_ptd_index++) {
+			
+			ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+
+			if(ptd_map->ptd_bitmap & ptd_map_buff->pending_ptd_bitmap) {
+				/* This PTD is pending */
+				if(td_ptd_index < ptd_map_buff->max_ptds) {
+					/* Just update the Active map */
+					ptd_map_buff->active_ptd_bitmap |= ptd_map->ptd_bitmap;
+					ptd_map_buff->pending_ptd_bitmap &= (~ptd_map->ptd_bitmap);
+				} else {
+					/* Check if there is room to accomodate this */
+					if((ptd_map_buff->active_ptd_bitmap & ptd_map_buff->active_ptd_bitmask) != 
+						ptd_map_buff->active_ptd_bitmask){
+
+						ed = ptd_map->ed;			/* Store ED and TD */
+						td = ptd_map->td;
+
+						phci_release_td_ptd_index(ed);
+						phci_get_td_ptd_index(ed);
+						ptd_map_buff->active_ptd_bitmap |= ptd_map_buff->map_list[ed->td_ptd_index].ptd_bitmap;
+						ptd_map_buff->pending_ptd_bitmap &= (~ptd_map->ptd_bitmap);
+
+					}
+					/* Otherwise wait for some one to come to get free */
+				}
+			}
+		}
+	}
+
+}
+
+/*--------------------------------------------------------------*
+ *--------------------------------------------------------------*
+ phci_fill_send_ptd::
+	
+	send_ptd_bitmap:		32bit map for the ptds to be sent
+	ptd_map_buff:	map buffer pointer of buffer to be written
+
+	Skip all the PTDs that are going to be filled by this function.
+
+	fill the ptd buffer and send it to HC
+
+	Fill into the HC buffer all the ptd's indicated by the bitmap
+	into their corresponding locations in the buffer.
+
+	Check and update the Last Ptd, thereshold level.
+
+	remove the skip map so that PTD's processing starts
+ *--------------------------------------------------------------*
+ *--------------------------------------------------------------*/
+void phci_fill_send_ptd(phci_t	*phci,__u32	send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff) {
+
+	td_ptd_map_t		*td_ptd_map;
+	__u8				*ptd_payload = NULL;
+	__u8				ram_data[TD_PTD_MAX_BUFF_TDS];
+	__u8				byte_data = 0;
+	__u16				payload_bytes = 0;					/* ptd payload bytes */
+	__u16				total_bytes = HC_PTD_HEADER_SIZE;	/* ptd total bytes to be written to HC buffer */
+	__u32				active_ptd_bitmap = 0x0;
+	td_t				*td;
+	ed_t				*ed;
+	__u8				index = 0;
+
+	__u32				finished_map = send_ptd_bitmap;	
+	__u32				ram_addr;
+
+	__u32				data_read;
+
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+	__u8				ping_pong_flag = 0;
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+#if 0
+	printk("phci_fill_send_ptd(phci = 0x%p, send_ptd_map = 0x%x, ptd_map_buff = 0x%p)\n",phci,send_ptd_bitmap, ptd_map_buff);
+#endif
+
+
+	if(!send_ptd_bitmap)	{
+
+		if(ptd_map_buff->buffer_type == TD_PTD_BUFF_TYPE_ATL) {
+			if(!ptd_map_buff->active_ptds){
+
+
+				/* No ptds are active */
+				ptd_map_buff->regs.threshold_count = 0;	/* Set the thereshol count from logic */
+				/* Update the same in HC */
+				phci_reg_write16(REG_ATL_THRESHOLD_COUNT,ptd_map_buff->regs.threshold_count);			
+				phci_reg_write32(REG_ATL_PTD_SKIP_MAP,0xFFFFFFFF);	/* Skip all ptds */
+				
+				phci_reg_read16(REG_BUFF_STS,&data_read);				/* Read the buffer status register */
+				data_read &= (~ATL_ACTIVE);							/* Deactivate ATL */
+				phci->hcd_operational_flags &= (~ATL_ACTIVE);
+				phci_reg_write16(REG_BUFF_STS,data_read);				/* Deactivate ATL buffers */
+
+			}
+		}
+
+		if(ptd_map_buff->buffer_type == TD_PTD_BUFF_TYPE_INTL) {
+
+			if(!ptd_map_buff->active_ptds){
+
+				phci_reg_write32(REG_INTL_PTD_SKIP_MAP,0xFFFFFFFF);/* Skip all ptds */
+				
+				phci_reg_read16(REG_BUFF_STS,&data_read);				/* Read the buffer status register */
+				data_read &= (~INTL_ACTIVE);						/* Deactivate ATL */
+				phci->hcd_operational_flags &= (~INTL_ACTIVE);
+				phci_reg_write16(REG_BUFF_STS,data_read);				/* Deactivate ATL/INTL buffers */
+			}
+		}
+		return;							/* If there is nothing to do, just return it */
+	}
+
+	/* Take care of pending ATL ptds */
+
+	if(ptd_map_buff->buffer_type == TD_PTD_BUFF_TYPE_ATL) {
+
+		ptd_map_buff->pending_ptd_bitmap |= (send_ptd_bitmap & (~ptd_map_buff->active_ptd_bitmask));
+		send_ptd_bitmap &= ptd_map_buff->active_ptd_bitmask;
+
+		if(!send_ptd_bitmap)	return;
+	}
+
+	switch(ptd_map_buff->buffer_type) {
+
+		case TD_PTD_BUFF_TYPE_INTL:
+
+
+			/* Skip the PTD's in ATL & INTL so that we can write the PTD's into the buffer */
+			phci_reg_read32(REG_INTL_PTD_SKIP_MAP, &(ptd_map_buff->regs.ptd_skip_map));	/* Read the ATL skip map */
+			ptd_map_buff->regs.ptd_skip_map |= send_ptd_bitmap;							/* Add the new ptds to be skipped */
+			phci_reg_write32(REG_INTL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);	/* The HC don;t touch the ptds */
+			break;
+
+		case TD_PTD_BUFF_TYPE_ATL:
+
+			/* Skip the PTD's in ATL & INTL so that we can write the PTD's into the buffer */
+			phci_reg_read32(REG_ATL_PTD_SKIP_MAP, &(ptd_map_buff->regs.ptd_skip_map));		/* Read the ATL skip map */
+			ptd_map_buff->regs.ptd_skip_map |= send_ptd_bitmap;										/* Add the new ptds to be skipped */
+			phci_reg_write32(REG_ATL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);			/* The HC don;t touch the ptds */
+			break;
+	}
+
+	for( index = 0; (index < ptd_map_buff->max_ptds) || (finished_map != 0); index++) {
+
+		td_ptd_map = &(ptd_map_buff->map_list[index]);
+		if(td_ptd_map->ptd_bitmap & finished_map) {				/* This ptd needs to be filled */
+	
+			/* Start filling the ram_data to send it to HC */
+
+			td = td_ptd_map->td;
+			ed = td->ed;
+
+			/* start filling the ptd header */
+			
+			total_bytes = HC_PTD_HEADER_SIZE;	/* ptd total bytes to be written to HC buffer, initialize to ptd header */
+
+			/**********************************************************************/
+			/* ptd_header[0]: 7..0		actual bytes(7...0)				0(always) */
+			/**********************************************************************/
+			ram_data[0] = 0;
+
+			/************************************************************************/
+			/* ptd_header[1]: 7..4		completion code(3...0)		1111 (always) 	*/
+			/* ptd_header[1]: 3		 	active(0)					1 (always) 		*/
+			/* ptd_header[1]: 2		 	toggle(0)					from ed&td 		*/
+			/* ptd_header[1]: 1..0		actual bytes(9..8)			0 (always)		*/
+			/************************************************************************/
+
+			ram_data[1] = (PTD_CC_MASK | PTD_ACTIVE);
+			if( td->hwINFO & HC_GTD_MLSB) {						/* fill toggle bit from td hw info */
+				ram_data[1] |= (((__u8)((td->hwINFO & HC_GTD_TLSB) >> 24)) << 2);
+			} else {												/* fill toggle bit from ed hw info */
+				ram_data[1] |= (((__u8)((ed->hwHeadP & HC_ED_TOGGLE) >> 1)) << 2);
+			}
+	
+			/**********************************************************************/
+			/* ptd_header[2]: 7..0		Max.PacketSize(7...0)		from ed MPS	  */
+			/**********************************************************************/
+
+			ram_data[2] = ((__u8)((ed->hwINFO & HC_ED_MPS) >> 16));
+
+
+			/************************************************************************/
+			/* ptd_header[3]: 7..4		End point number(3...0)		from ED EN		*/
+			/* ptd_header[3]: 3		 	reserved(0)					0 (always) 		*/
+			/* ptd_header[3]: 2		 	speed(0)					from ED			*/
+			/* ptd_header[3]: 1..0		Max.PacketSize(9..8)		from ED MPS		*/
+			/************************************************************************/
+
+			ram_data[3] = (((__u8)((ed->hwINFO & HC_ED_EN) >> 7)) << 4);
+
+			if(ed->hwINFO & HC_ED_SPD) {				/* Check if speed device or not */
+				ram_data[3] |= PTD_SPEED;
+			}
+
+			ram_data[3] |= (((__u8)((ed->hwINFO & HC_ED_MPS) >> 24)) & 0x03);
+	
+
+			/********************************************************************************/
+			/* ptd_header[4]: 7..0		Total Bytes(7...0)		from td cbp & be			*/
+			/* ptd_header[5]: 1..0 		total bytes(9..8)			from td cbp & be		*/
+			/********************************************************************************/
+
+			if(td->hwCBP) {
+				payload_bytes = td->hwBE - td->hwCBP + 1;				/* get the total bytes from td cbp & be */
+				ram_data[4] = (__u8)payload_bytes;
+				ram_data[5] = (__u8)(payload_bytes >> 8);
+			} else {			/* Null data packet */
+				payload_bytes = 0;
+				ram_data[4] = 0;
+				ram_data[5] = 0;
+			}
+	
+			/********************************************************************************/
+			/* ptd_header[5]: 7			paired(0)					from ping_pong input 	*/
+			/* ptd_header[5]: 6		 	ping_pong(0)				from ping_pong input 	*/
+			/* ptd_header[5]: 5..4	 	reserved(1..0)				00 always 				*/
+			/* ptd_header[5]: 3..2 		token direction(1..0)		from ed DIR 			*/
+			/* ptd_header[5]: 1..0 		total bytes(9..8)			already filled before 	*/
+			/********************************************************************************/
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+
+			if(td_ptd_map->ping_pong) ping_pong_flag = 1;
+
+			ram_data[5] |= td_ptd_map->ping_pong;
+
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+			byte_data = (__u8)((ed->hwINFO & HC_ED_DIR) >> 11);
+			if(byte_data != OHCI_OUT && byte_data != OHCI_IN) {
+				byte_data = (__u8)((td->hwINFO & HC_GTD_DP) >> 19);
+			}
+
+			ram_data[5] |= (byte_data << 2);
+
+			/********************************************************************************/
+			/* ptd_header[6]: 7			format(0)					0	always 				*/
+			/* ptd_header[6]: 6..0	 	function address(6..0)		from ED FA				*/
+			/********************************************************************************/
+
+			ram_data[6] = ((__u8)(ed->hwINFO & HC_ED_FA));
+
+			/*************************************************************************************/
+			/* ptd_header[7]: 7..0	 	Frame Number/Int polling Interval(7..0)	poll_frame# input*/
+			/*************************************************************************************/
+			ram_data[7] = 0;
+
+			if(ed->type == PIPE_INTERRUPT) {
+				__u8	int_interval, byte;
+
+				int_interval = (ed->int_interval >> 1);
+				byte = 0;
+				while(int_interval) {int_interval >>= 1; byte++;}
+
+#ifdef CONFIG_USB_PHCD_EVEN_SCH
+				ram_data[7] = (byte << 5);				/* Check the last 5 bits of Interrupt polling interval */
+				ram_data[7] |= ed->int_branch ;
+#else
+				ram_data[7] = (byte << 1);				/* Always schedule on even frame */
+#endif /* CONFIG_USB_PHCD_EVEN_SCH */
+
+			}
+
+			/* start sendig the data for this ptd */
+
+			ram_addr = ptd_map_buff->ram_buff_addr+index*(ptd_map_buff->regs.block_pl_size + HC_PTD_HEADER_SIZE);
+			ptd_payload = (__u8*)(td->hwCBP);
+			
+			if( (byte_data != OHCI_IN ) && payload_bytes && ptd_payload ) {			/* Don's send data in case of IN token */
+				total_bytes += payload_bytes;
+				fnvPhciRamWrite(phci,payload_bytes, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), ptd_payload);
+
+			}
+
+			if(ram_addr < 2*HC_ISTL_BUFFER_LENGTH) 
+				printk("Something bad is going to happen, trying to write at %x for A/INTL ptd's", ram_addr);
+
+			fnvPhciRamWrite(phci,HC_PTD_HEADER_SIZE, HC_DIR_ADDR_INCREMENT, ram_addr, ram_data);		/* Send the ptd header */
+
+
+			td_ptd_map->total_bytes = payload_bytes+HC_PTD_HEADER_SIZE;			/* Set the total bytes size for this td-ptd map */
+			ptd_map_buff->active_ptd_bitmap |= td_ptd_map->ptd_bitmap;			/* Set this ptd is active in active ptd map */
+			ptd_map_buff->active_ptds++;
+				
+			finished_map &= (~(td_ptd_map->ptd_bitmap));						/* Set this ptd as finished one */
+
+		}
+	}
+
+	switch(ptd_map_buff->buffer_type) {
+		case TD_PTD_BUFF_TYPE_ATL:
+			ptd_map_buff->regs.threshold_count = atl_active_ptd_X_threshold_ptd[ptd_map_buff->active_ptds] ;	/* Set the thereshol count from logic */
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+			/* PING PONG pair of PTDs will be treated as one PTD */
+			if(ptd_map_buff->regs.threshold_count) ptd_map_buff->regs.threshold_count -= ping_pong_flag;
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+
+			phci_reg_write16(REG_ATL_THRESHOLD_COUNT,ptd_map_buff->regs.threshold_count);			/* Update the same in HC */
+
+			phci_reg_read16(REG_ATL_THRESHOLD_COUNT,&data_read);			/* Update the same in HC */
+
+			/* Set the Last PTD in ATL */
+			/* Calculate the last ptd in ATL */
+
+			active_ptd_bitmap = ptd_map_buff->active_ptd_bitmap;
+			ptd_map_buff->regs.last_ptd = 0x1;
+			active_ptd_bitmap >>= 1;
+
+			/*
+			 * Last PTD is already set at the time of initialization to the maximum TDs
+			 * So no need of dynamic update
+			 */
+#if 0
+			while(active_ptd_bitmap) {					/* right shift till active ptd bitmap becomes zero */
+				ptd_map_buff->regs.last_ptd <<= 1;
+				active_ptd_bitmap >>= 1;
+			}
+			phci_reg_write32(REG_ATL_PTD_LAST_PTD,ptd_map_buff->regs.last_ptd);		/* Update the last ATL ptd in HC */
+#endif
+
+
+
+
+		
+			/* Activate the PTD's in ATL so that we can start the PTD's in the buffer */
+			ptd_map_buff->regs.ptd_skip_map &= (~send_ptd_bitmap);									/* remove the skip on new ptd's */
+			phci_reg_write32(REG_ATL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);			/* write into the skip map buffer */
+
+
+			phci_reg_read16(REG_BUFF_STS,&data_read);		/* Activate ATL buffer processing */
+
+			if(!(data_read & ATL_ACTIVE)) {
+				data_read |= ATL_ACTIVE;
+				phci->hcd_operational_flags |= ATL_ACTIVE;
+				phci_reg_write16(REG_BUFF_STS,data_read);		/* Activate ATL buffer processing */
+			}
+			break;
+
+	 	case TD_PTD_BUFF_TYPE_INTL:
+
+			active_ptd_bitmap = ptd_map_buff->active_ptd_bitmap;
+			ptd_map_buff->regs.last_ptd = 0x1;
+			active_ptd_bitmap >>= 1;
+
+			/* Activate the PTD's in INTL so that we can start the PTD's in the buffer */
+			ptd_map_buff->regs.ptd_skip_map &= (~send_ptd_bitmap);			/* remove the skip on new ptd's */
+			phci_reg_write32(REG_INTL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);	/* write into the skip map buffer */
+	
+			phci_reg_read16(REG_BUFF_STS,&data_read);		/* Activate INTL buffer processing */
+
+			if(!(data_read & INTL_ACTIVE)) {
+				phci->hcd_operational_flags |= INTL_ACTIVE;
+				data_read |= INTL_ACTIVE;
+				phci_reg_write16(REG_BUFF_STS,data_read);		/* Activate INTL buffer processing */
+			}
+			phci_reg_read32(REG_INTL_PTD_SKIP_MAP,&ptd_map_buff->regs.ptd_skip_map);	/* write into the skip map buffer */
+
+			break;
+	}
+} /* phci_fill_send_ptd */
+
+/*--------------------------------------------------------------*
+ *--------------------------------------------------------------*
+ phci_fill_send_isoc_ptd::
+	
+	send_ptd_bitmap:		32bit map for the ptds to be sent
+	ptd_map_buff:	map buffer pointer of buffer to be written
+
+	fill the ptd buffer and send it to HC
+
+	Fill into the HC buffer all the ptd's indicated by the bitmap
+	into their corresponding locations in the buffer.
+
+	activate the corresponding istl buffer
+ *--------------------------------------------------------------*
+ *--------------------------------------------------------------*/
+void phci_fill_send_isoc_ptd(phci_t	*phci,__u32	send_ptd_bitmap,td_ptd_map_buff_t *ptd_map_buff) {
+
+	td_ptd_map_t		*td_ptd_map;
+	__u8				*ptd_payload = NULL;
+	__u8				ram_data[TD_PTD_MAX_BUFF_TDS];
+	__u8				byte_data = 0;
+	__u16				payload_bytes = 0;					/* ptd payload bytes */
+	__u16				total_bytes = HC_PTD_HEADER_SIZE;	/* ptd total bytes to be written to HC buffer */
+	td_t				*td;
+	ed_t				*ed;
+	__u8				index = 0;
+
+	__u32				finished_map = send_ptd_bitmap;	
+	__u32				ram_addr = ptd_map_buff->ram_buff_addr;
+	__u32				ram_buff_sts;
+
+	detail_debug(("phci_fill_send_isoc_ptd(phci = 0x%p, send_ptd_map = 0x%x, ptd_map_buff = 0x%p)\n",phci,send_ptd_bitmap, ptd_map_buff))
+
+
+	ptd_map_buff->active_ptd_bitmap = 0;			/* Set this ptd is active in active ptd map */
+
+	if(!send_ptd_bitmap)	return;							/* If there is nothing to do, just return it */
+
+
+	phci_reg_read16(REG_BUFF_STS, &ram_buff_sts);		/* Activate ITL buffer processing */
+
+	if(ptd_map_buff->buffer_type == TD_PTD_BUFF_TYPE_ISTL0) {
+		ram_buff_sts |= ISTL_0_BUFF_FULL;
+	} else {
+		ram_buff_sts |= ISTL_1_BUFF_FULL;
+	}
+
+	phci_reg_write16(REG_BUFF_STS,ram_buff_sts);		/* Activate ITL buffer processing */
+
+
+	for( index = 0; (index < ptd_map_buff->max_ptds) || (finished_map != 0); index++) {
+
+		td_ptd_map = &(ptd_map_buff->map_list[index]);
+		if(td_ptd_map->ptd_bitmap & finished_map) {				/* This ptd needs to be filled */
+	
+			/* Start filling the ram_data to send it to HC */
+
+			td = td_ptd_map->td;
+			ed = td->ed;
+
+	
+			/* start filling the ptd header */
+
+			total_bytes = HC_PTD_HEADER_SIZE;	/* ptd total bytes to be written to HC buffer, initialize to ptd header */
+			
+			/**********************************************************************/
+			/* ptd_header[0]: 7..0		actual bytes(7...0)				0(always) */
+			/**********************************************************************/
+			ram_data[0] = 0;
+
+			/************************************************************************/
+			/* ptd_header[1]: 7..4		completion code(3...0)		1111 (always) 	*/
+			/* ptd_header[1]: 3		 	active(0)					1 (always) 		*/
+			/* ptd_header[1]: 2		 	toggle(0)					always data0	*/
+			/* ptd_header[1]: 1..0		actual bytes(9..8)			0 (always)		*/
+			/************************************************************************/
+
+			/* for toggle bit of OUT its always DATA0, for IN it should accept either 
+			DATA0 & DATA1, we set now DATA0 and if the device gives DATA1 the HC should 
+			not crib such situation as error case. If HC gives data toggle error, sw
+			ignores the error */
+
+			ram_data[1] = (PTD_CC_MASK | PTD_ACTIVE);			
+	
+			/**********************************************************************/
+			/* ptd_header[2]: 7..0		Max.PacketSize(7...0)		from ed MPS   */
+			/**********************************************************************/
+
+			ram_data[2] = ((__u8)((ed->hwINFO & HC_ED_MPS) >> 16));
+
+
+			/************************************************************************/
+			/* ptd_header[3]: 7..4		End point number(3...0)		from ED EN		*/
+			/* ptd_header[3]: 3		 	last(0)						from finish map	*/
+			/* ptd_header[3]: 2		 	speed(0)					from ED			*/
+			/* ptd_header[3]: 1..0		Max.PacketSize(9..8)		from ED MPS		*/
+			/************************************************************************/
+
+			ram_data[3] = (((__u8)((ed->hwINFO & HC_ED_EN) >> 7)) << 4);
+
+			if(ed->hwINFO & HC_ED_SPD) {				/* Check if speed device or not */
+				ram_data[3] |= PTD_SPEED;
+			}
+
+			ram_data[3] |= (((__u8)((ed->hwINFO & HC_ED_MPS) >> 24)) & 0x03);
+
+		
+			/* As ptd's are finished, the finished map bits will go and finally for the last
+			ptd, finished map is the ptd_bitmap */
+			if( finished_map == td_ptd_map->ptd_bitmap) {
+				ram_data[3] |= PTD_LAST;
+			}
+	
+
+			/********************************************************************************/
+			/* ptd_header[4]: 7..0		Total Bytes(7...0)		from td cbp & be			*/
+			/* ptd_header[5]: 1..0 		total bytes(9..8)			from td cbp & be		*/
+			/********************************************************************************/
+
+			if(td->hwCBP) {
+				payload_bytes = td->hwBE - (td->hwCBP+(td->hwPSW[0] & 0x0FFF)) + 1; /* get the total bytes from td cbp & be & psw */
+				ram_data[4] = (__u8)payload_bytes;
+				ram_data[5] = (__u8)(payload_bytes >> 8);
+			} else {			/* Null data packet */
+				payload_bytes = 0;
+				ram_data[4] = 0;
+				ram_data[5] = 0;
+			}
+	
+			/********************************************************************************/
+			/* ptd_header[5]: 7			(0)							always 0				*/
+			/* ptd_header[5]: 6		 	(0)							always 0				*/
+			/* ptd_header[5]: 5..4	 	reserved(1..0)				00 always 				*/
+			/* ptd_header[5]: 3..2 		token direction(1..0)		from ed DIR 			*/
+			/* ptd_header[5]: 1..0 		total bytes(9..8)			already filled before 	*/
+			/********************************************************************************/
+
+			byte_data = (__u8)((ed->hwINFO & HC_ED_DIR) >> 11);
+
+			ram_data[5] |= (byte_data << 2);
+
+			/********************************************************************************/
+			/* ptd_header[6]: 7			format(1)					1	always for ISOC		*/
+			/* ptd_header[6]: 6..0	 	function address(6..0)		from ED FA				*/
+			/********************************************************************************/
+
+			ram_data[6] = ((__u8)(ed->hwINFO & HC_ED_FA));
+			ram_data[6] |= PTD_FORMAT;
+
+			/*************************************************************************************/
+			/* ptd_header[7]: 7..0	 	Frame Number/Int polling Interval(7..0)	poll_frame# input*/
+			/*************************************************************************************/
+			ram_data[7] = (td->hwINFO & 0xFF);
+
+			/* start sendig the data for this ptd */
+
+			ptd_payload = (__u8*)((td->hwCBP) + (td->hwPSW[0] & 0x0FFF));
+
+			if( (byte_data != OHCI_IN ) && payload_bytes && ptd_payload ) {				/* Don's send data in case of IN token */
+				total_bytes += payload_bytes;
+				fnvPhciRamWrite(phci,payload_bytes, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), ptd_payload);
+			}
+
+
+			fnvPhciRamWrite(phci, HC_PTD_HEADER_SIZE, HC_DIR_ADDR_INCREMENT, ram_addr, ram_data);		/* Send the ptd header */
+
+			td_ptd_map->ram_addr = ram_addr;
+	
+			ALIGN_RAM_BUFF_LENGTH(payload_bytes);
+
+			td_ptd_map->total_bytes = payload_bytes+HC_PTD_HEADER_SIZE;			/* Set the total bytes size for this td-ptd map */
+			
+			if(ram_addr > 2*HC_ISTL_BUFFER_LENGTH) {
+				printk("Something bad is going to happen, Writing at %x for ISTL ptd's\n", ram_addr);
+			}
+
+			ram_addr += td_ptd_map->total_bytes;
+
+			ptd_map_buff->active_ptd_bitmap |= td_ptd_map->ptd_bitmap;			/* Set this ptd is active in active ptd map */
+			ptd_map_buff->active_ptds++;
+				
+			finished_map &= (~(td_ptd_map->ptd_bitmap));							/* Set this ptd as finished one */
+		}
+	}
+
+
+} /* phci_fill_send_isoc_ptd */
+
+/*--------------------------------------------------------------*
+ *--------------------------------------------------------------*
+ phci_submit_ed
+	phci:	phci data structure
+	ed:		endpoint descriptor data strucrure for which data transfer is initiated
+
+	control/bulk::
+	Check if there are any transfers are active for this ed
+	If no transfers, fill the first td into HC buffer
+	If ping-pong is enabled and if this is ping pong ed, send the pong buffer also
+	Set the ATL interrupt if not enabled
+	Set the atl last ptd, atl thereshold level and remove the skip bit for the ptds filled
+ *--------------------------------------------------------------*
+ *--------------------------------------------------------------*/
+void phci_submit_ed(phci_t	*phci,	ed_t	*ed) {
+
+	td_ptd_map_buff_t   *ptd_map_buff;
+	td_ptd_map_t		*td_ptd_map;
+	__u32				ptd_bitmap = 0;
+	__u8				td_ptd_index = ed->td_ptd_index;
+	td_t				*td;
+	__u32				irq_mask;
+	urb_priv_t			*urb_priv;
+
+	__u32				buff_sts;
+
+	/* Check if td_ptd_index is free */
+	/* If free fill it with setup stage td */
+	/* If this is ping pong ptd pair, fill data stage as ping pong */
+	/* if ATL interrupt is not set yet set it */
+	/* Check number of ptd's in the atl buffer, set last ptd, threshold ptd ...etc */
+			
+
+	switch(ed->type) {
+			
+		case PIPE_BULK:
+
+ 			ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL]);
+
+ 			td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+			
+			phci_reg_read16(REG_BUFF_STS, &buff_sts);
+			
+			if( td_ptd_map->state == TD_PTD_OPER && !(td_ptd_map->td) )	{
+				/* No td ptds are in progress for this ed */
+			
+				td = (td_t*)(ed->hwHeadP & 0xfffffff0);
+				ptd_bitmap |= td_ptd_map->ptd_bitmap;
+				td_ptd_map->ping_pong = TD_PTD_NO_PING_PONG;
+
+				if(!(buff_sts&ATL_ACTIVE)) td_ptd_map->td = td;
+				urb_priv = (urb_priv_t*)(td->urb->hcpriv);
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+
+				// Conditions to start ping pong ptd
+				// 1) This ed is reserved for ping pong mechanism
+				// 2) There are more than 1 PTD's to be serverd for this URB
+				// 3) ATL IS NOT Active or PING PONG is not PONG
+				//  	0					0			start
+				//		0					1			start (clear pingpong)
+				//		1					0			start
+				//		1					1			don't start (can not clear)
+				//		!(ATL_ACTIVE) || !(PING_PONG)
+				
+				
+				if((urb_priv->length > 1) && (!(buff_sts & ATL_ACTIVE) || 
+					!(buff_sts &  ACTIVE_PING_PONG_PAIR))) {
+
+					phci_get_td_ptd_index(ed); 	/* Get a pong-ptd index */
+					if(ptd_map_buff->pong_ptd_index == TD_PTD_INV_PTD_INDEX) printk("ha ha ha\n");
+					if(ptd_map_buff->ping_ptd_index ==  ed->td_ptd_index) {
+						if(buff_sts &  ACTIVE_PING_PONG_PAIR) 
+						{
+							/* Reset Hardware Ping Pong */
+							buff_sts |= RESET_PING_PONG;
+							phci_reg_write16(REG_BUFF_STS, buff_sts);		/* Clear the Reset bit so that we can 
+																	   able to clear in future */
+							buff_sts &= (~RESET_PING_PONG);
+							phci_reg_write16(REG_BUFF_STS, buff_sts);
+						}
+						ptd_map_buff->ping_pong_status = 0;	
+						/* Set PING to fill for ping ptd index */
+						td_ptd_map->ping_pong = TD_PTD_PING;
+						if(!(buff_sts&ATL_ACTIVE)) ptd_map_buff->ping_pong_status = TD_PTD_PING_FILLED;
+
+						/* Fill PONG ptd to the ATL buffer */
+						td_ptd_index = ptd_map_buff->pong_ptd_index;
+						td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+						td = (td_t*)(td->hwNextTD & HC_GTD_NEXTTD);
+						if(!(buff_sts&ATL_ACTIVE)) td_ptd_map->td = td;
+						ptd_bitmap |= td_ptd_map->ptd_bitmap;
+						td_ptd_map->ping_pong = TD_PTD_PONG;
+						if(!(buff_sts&ATL_ACTIVE)) ptd_map_buff->ping_pong_status = TD_PTD_PONG_FILLED;
+					}
+				}
+
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+				/* Fill PTD to the ATL buffer (No ping-pong) */
+				if(buff_sts & ATL_ACTIVE) {
+					ptd_map_buff->pending_ptd_bitmap |= ptd_bitmap;
+				} else {
+					phci_fill_send_ptd(phci, ptd_bitmap, ptd_map_buff);
+				}
+
+			} /* else {
+				some td's of this ed are already in progress, processing will be done later 
+			} */
+
+			phci->uHcHcdControl_hcd |= OHCI_BLF;
+			
+			break;
+		case PIPE_CONTROL:
+
+ 			ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL]);
+
+ 			td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+			
+			phci_reg_read16(REG_BUFF_STS, &buff_sts);
+			
+
+			if(td_ptd_map->state == TD_PTD_OPER && !(td_ptd_map->td) )	{		
+				/* No td ptds are in progress for this ed */
+			
+				/* Fill PTD to the ATL buffer (No ping-pong) */
+				if(buff_sts & ATL_ACTIVE) {
+					ptd_map_buff->pending_ptd_bitmap |= td_ptd_map->ptd_bitmap;
+				} else 
+				{
+				td_ptd_map->td = (td_t*)(ed->hwHeadP & 0xfffffff0);
+				phci_fill_send_ptd(phci, td_ptd_map->ptd_bitmap, ptd_map_buff);
+				}
+
+			} /* else {
+				some td's of this ed are already in progress, processing will be done later 
+			} */
+
+			phci->uHcHcdControl_hcd |= OHCI_CLF;
+			
+			break;
+
+		case PIPE_INTERRUPT:
+ 			ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL]);
+
+ 			td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+			
+			if(td_ptd_map->state == TD_PTD_OPER && !(td_ptd_map->td) )	{		
+				/* No td ptds are in progress for this ed */
+			
+				td_ptd_map->td = (td_t*)(ed->hwHeadP & 0xfffffff0);
+				phci_fill_send_ptd(phci,td_ptd_map->ptd_bitmap, ptd_map_buff);
+			}
+
+			break;
+
+		case PIPE_ISOCHRONOUS:
+				
+				if(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1].frame_number == INVALID_FRAME_NUMBER) {
+					/* This is the first ed to start ISOC transfer, Sof is not switched on, start SOF */
+
+					phci_reg_read16(REG_IRQ_MASK, &irq_mask);
+					irq_mask |= SOF_INT;							/* Enable SOF processing */
+					phci_reg_write16(REG_IRQ_MASK, irq_mask);
+				}
+
+			break;
+	}
+
+} /* phci_submit_ed */
+
+
+/*--------------------------------------------------------------*
+ * ATL Interrupt Processing										* 
+ *--------------------------------------------------------------*/
+void fnvProcessAtlInt(phci_t	*phci) {
+
+	__u8				td_ptd_index = 0;
+	__u8				completion_code,byte_data;
+	__u32				ptd_bitmap;			/* HC 	done atl ptd map */
+	td_ptd_map_buff_t   *ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ATL]);
+	td_ptd_map_t		*td_ptd_map;
+	td_t				*td;
+	ed_t				*ed;
+	__u8				ram_data[HC_ATL_BLK_SIZE];
+	__u32				ram_addr;
+	__u16				bytes;
+	__u32				uData1, uTotal;
+	__u8*				td_payload;
+	__u32				active_ptd_bitmap = 0;
+	__u32				active_ptdmap = 0;
+	__u32				hc_buff_sts = 0;
+	__u32				fn, fn_rem;
+
+	__u32				ping_pong_bitmap = 0x00;
+
+	__u32				td_head, td_tail;
+
+	/* Read the Atl Done PTD's map from the HC atl buffer */
+	phci_reg_read32(REG_ATL_PTD_DONE_MAP, &ptd_bitmap);
+
+	fnvPhciHcorRead(phci,uHcFmNumber, &fn);
+	fnvPhciHcorRead(phci,uHcFmRemaining, &fn_rem);
+
+	ptd_map_buff->regs.ptd_done_map = ptd_bitmap;
+	phci_reg_read32(REG_ATL_PTD_SKIP_MAP, &(ptd_map_buff->regs.ptd_skip_map));	/* Read the ATL skip map */
+	ptd_map_buff->regs.ptd_skip_map |= ptd_bitmap;			/* Add the done ptds to be skipped */
+	phci_reg_write32(REG_ATL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);	/* The HC don;t touch the ptds */
+
+	ptd_bitmap = 0x00000001;
+
+	active_ptdmap = ptd_map_buff->regs.ptd_done_map;
+
+	phci_reg_read16(REG_BUFF_STS, &hc_buff_sts);
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+	/* Find if both ping and pong ptds are done, and the scanning sequesnce is pong-ping 
+     * if so we need to reverse the scanning sequence */
+
+	if(ptd_map_buff->ping_ptd_index != TD_PTD_INV_PTD_INDEX) {
+		/* Paired PTD sequence is ON, check if both are done */
+		ping_pong_bitmap = ptd_map_buff->map_list[ptd_map_buff->ping_ptd_index].ptd_bitmap;
+		ping_pong_bitmap |= ptd_map_buff->map_list[ptd_map_buff->pong_ptd_index].ptd_bitmap;
+
+		if( ((ping_pong_bitmap & ptd_map_buff->regs.ptd_done_map) == ping_pong_bitmap) &&
+			(ptd_map_buff->ping_pong_status & TD_PTD_PING_FILLED) )  {
+
+			/* Reverse the scan sequence */
+			ptd_bitmap <<= (TD_PTD_MAX_BUFF_TDS - 1);
+			td_ptd_index = TD_PTD_MAX_BUFF_TDS - 1;
+		} else {
+			/* normal scan sequence */
+			ping_pong_bitmap = 0x00;
+		}
+	}
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+
+
+	while(ptd_map_buff->regs.ptd_done_map) {				/* If there are any done ptd's present */
+
+		if(ptd_map_buff->regs.ptd_done_map & ptd_bitmap) {	/* At this bitmap there is a done ptd */
+			td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+				
+			ram_addr = ptd_map_buff->ram_buff_addr+td_ptd_index*(ptd_map_buff->regs.block_pl_size + HC_PTD_HEADER_SIZE);
+
+			/* Read the PTD header from the HC */
+			fnvPhciRamRead(phci, HC_PTD_HEADER_SIZE , HC_DIR_ADDR_INCREMENT, ram_addr, ram_data);
+
+			td = td_ptd_map->td;
+
+			if(td_ptd_map->state == TD_PTD_OPER && td) {				/* This PTD is done, do the necessary processing */
+			ptd_map_buff->active_ptds--;
+
+				ed = td->ed;											/* Get the ed of this td */
+				
+				/* Process completion code, and toggle bit */
+				byte_data = ram_data[1];
+				if ((byte_data & PTD_ACTIVE) == 0) {       /* Test if the PTD is still active */
+					/* Copy completion code to GTD */
+					completion_code = ((byte_data & PTD_COMPLETION_CODE) >> 4);
+
+					bytes = (ram_data[0]+((ram_data[1] & 0x3) << 8));	/* Get the actual bytes */
+
+
+					/* MOCK OHCI IN SOFTWARE */
+						
+					/* Check if there is any transmission error (pid check fail, data toggle mismatch, crc fail, bitstuffing or dev not responding)
+					and number of retries is not zero then process the PTD else go to transmission error processing */
+					if(!(--(td->retry_count)) || (completion_code != TD_PIDCHECKFAIL && 
+						completion_code != TD_CC_DATATOGGLEM && completion_code  != TD_CC_CRC && 
+						completion_code != TD_CC_BITSTUFFING && completion_code != TD_DEVNOTRESP)) 
+					{
+
+
+						td->hwINFO &= ~HC_GTD_CC; /* Clear the original CC */
+						td->hwINFO |= completion_code << 28; /* Move CC into position */
+
+						/* Data Toggle */
+						/* Copy the data toggle from PTD to ED and TD if there is no error or if under run or over run (for IN transfers),
+						for others it is treated as error and some error handling mechanism should be done */
+						if (completion_code == TD_CC_NOERROR || 
+						((completion_code == TD_DATAOVERRUN || completion_code == TD_DATAUNDERRUN) && (((ram_data[5] & PTD_DIR) >> 2) == OHCI_IN))) {
+							/* Get the data toggle bit from PTD in ATL */
+							uData1 = 0;
+							uData1 = (__u32) ((ram_data[1] & PTD_TOGGLE) >> 2);
+
+							/* Set the toggle bit same as the PTD in ATL */
+							td->hwINFO &= ~HC_GTD_TLSB;    /* Clear the toggle bit */
+							td->hwINFO |= (uData1 << 24);  /* Move it into position */
+	
+							ed->hwHeadP &= ~HC_ED_TOGGLE;		/* clear the toggle bit in ED */
+							ed->hwHeadP |= (uData1 << 1);		/* copy the ptd toggle bit here */
+
+						}
+
+
+						/*******************************/
+						/* Move TDs to done-queue list */
+						/*******************************/
+
+						/* Dequeue the current TD (the first TD in the TD queue from ED */
+						ed->hwHeadP &= ~HC_ED_HEADP; 							/* Clear the head pointer */
+						ed->hwHeadP |= (td->hwNextTD & HC_GTD_NEXTTD);
+
+						/* Move the TD to the head of done queue */
+						td->hwNextTD = (__u32)ptd_map_buff->done_head;
+						ptd_map_buff->done_head = td;
+
+						/* Take out the PID token from PTD byte 5 */
+						byte_data = (ram_data[5] & PTD_DIR) >> 2;
+
+						/* Move data returned from device to the buffer for IN transfer */
+						/* The data in case of under run as well as over run is valid and we have to copy the data to td buffer */
+						if ((byte_data == OHCI_IN) && ((completion_code == TD_CC_NOERROR) ||
+						(completion_code == TD_DATAUNDERRUN ) || (completion_code == TD_DATAOVERRUN))) {
+
+							td_payload = (__u8*) td->hwCBP; 						/* Starting address */
+
+							/* Get the actual number of transferred bytes */
+							uTotal = ((__u32) (ram_data[1] & PTD_ACTUAL_BYTES98)) << 8; 		/* Bit 9..8 */
+							uTotal |= (__u32) (ram_data[0]); 								/* Bit 7..0 */
+
+							if(uTotal && td_payload) {
+								fnvPhciRamRead(phci, uTotal, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), td_payload);
+							}
+
+						} /* if (byData == OHCI_IN) */
+
+						/* Update the Current Buffer pointer.
+						if success:: make CBP = 0 to signal that complete TD is success.
+						if underrun/overrun, update it to the received bytes so that the application knows how many bytes are transfered */
+						if( completion_code == TD_CC_NOERROR) td->hwCBP = 0;    /* To signal that last byte has been transferred */
+						else if(byte_data == OHCI_IN && (completion_code == TD_DATAUNDERRUN || completion_code == TD_DATAOVERRUN) ) {
+							td->hwCBP += bytes;
+						}
+
+						/* If the buffer rounding bit is set, and its an under run case, we treat that as success */
+						if(completion_code == TD_DATAUNDERRUN && (td->hwINFO & TD_R))
+							completion_code = TD_CC_NOERROR;
+
+						/* For any error other than success we have to halt the End Point */
+						if(completion_code != TD_CC_NOERROR)
+							td->ed->hwHeadP |= 0x00000001;
+
+						if(completion_code) {
+							printk("ATL CC = 0x%d, bytes = %d, OUT:%d retry_count = %d at fn = %x, fn_rem =%x\n",completion_code,bytes,(((ram_data[5] & PTD_DIR) >> 2) == OHCI_OUT), td->retry_count, fn, fn_rem);
+						}
+
+					} else {
+						/* ERROR_HANDLING_FIX:: */
+						/* Allt the transmission error cases are handled here.  Inverse and copy the toggle bit, 
+						copy any data if present, update current buffer pointer and don't put this in done queue so that 
+						this td is scheduled for transfer again */
+						printk("ATL retry CC = 0x%d, bytes = %d, OUT:%d retry_count = %d at fn = %x, fn_rem =%x\n",completion_code,bytes,(((ram_data[5] & PTD_DIR) >> 2) == OHCI_OUT), td->retry_count, fn, fn_rem);
+
+						byte_data = (ram_data[5] & PTD_DIR) >> 2;
+						if(byte_data == OHCI_OUT|| (byte_data == OHCI_IN )) {			/* Assuming SETUP tokens does not have this problem */
+
+							/* Get the data toggle bit from PTD in ATL */
+							uData1 = 0;
+							uData1 = (__u32) ((ram_data[1] & PTD_TOGGLE) >> 2);
+
+							/* Set the toggle bit same as the PTD in ATL */
+							td->hwINFO &= ~HC_GTD_TLSB;    /* Clear the toggle bit */
+							td->hwINFO |= (uData1 << 24);  /* Move it into position */
+	
+							ed->hwHeadP &= ~HC_ED_TOGGLE;		/* Clear the ED toggle bit */
+							ed->hwHeadP |= (uData1 << 1);		/* Move the toggle bit to ED */
+
+							/* Copy the received bytes in case of IN Transfer */
+							if(byte_data == OHCI_IN) {
+								td_payload = (__u8*) td->hwCBP; 			/* Starting address */
+									
+								if(bytes && td_payload) {
+									fnvPhciRamRead(phci, bytes, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), td_payload);
+								}
+							}
+							td->hwCBP += bytes;						/* Update the current buffer pointer */
+						}
+								
+					}
+					td_ptd_map->td = NULL;
+				} /* if ((byData & PTD_ACTIVE) == 0) */
+
+				byte_data = ram_data[1];    /* Byte 1 of PTD contains the PTD active bit */
+				if ((byte_data & PTD_ACTIVE)) {    /* Test if the PTD is still active */
+					/* Get the actual number of transferred bytes */
+					uTotal = 0;
+					uTotal = ((__u32) (ram_data[1] & PTD_ACTUAL_BYTES98)) << 8; /* Bit 9..8 */
+					uTotal |= (__u32) (ram_data[0]); /* Bit 7..0 */
+
+				} /* if ((byData & PTD_ACTIVE) == 1) */
+
+				
+#ifdef CONFIG_USB_PHCD_PING_PONG
+				if(td_ptd_map->ping_pong == TD_PTD_PONG) {
+					ptd_map_buff->ping_pong_status &= (~TD_PTD_PONG_FILLED);
+				}
+				if(td_ptd_map->ping_pong == TD_PTD_PING) {
+					ptd_map_buff->ping_pong_status &= (~TD_PTD_PING_FILLED);
+				}
+
+				td_ptd_map->ping_pong = TD_PTD_NO_PING_PONG;
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+			} else {		/* the ed is deleted in between */
+							/* Do nothing for this ptd */
+			}
+
+			ptd_map_buff->regs.ptd_done_map &= (~(ptd_bitmap));
+		}
+		
+		if(ping_pong_bitmap) {
+			/* higner to lower ptd scanning */
+			td_ptd_index--;
+			ptd_bitmap >>= 1;
+		} else {	
+			/* lower to higner ptd scanning */
+			td_ptd_index++;
+			ptd_bitmap <<= 1;
+		}
+
+	} /* while( ptd_map_buff->regs.ptd_done_map ) */
+
+	/* Process the done-queue list */
+	dl_done_list( phci, dl_reverse_done_list(phci,ptd_map_buff->done_head));
+	ptd_map_buff->done_head = NULL;
+
+	
+	phci_move_pending_td_ptds(ptd_map_buff);
+
+	active_ptd_bitmap = ptd_map_buff->active_ptd_bitmap;
+
+	active_ptdmap = 0;
+
+	ptd_bitmap = 0x00000001;
+	td_ptd_index = 0;
+
+
+	if(ping_pong_bitmap) {
+		ptd_bitmap <<= (TD_PTD_MAX_BUFF_TDS - 1);
+		td_ptd_index = TD_PTD_MAX_BUFF_TDS - 1;
+	}
+	
+
+
+
+	/* Update the td's in the td-ptd list for scheduling */
+	while(active_ptd_bitmap) {
+	
+		td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+
+
+		if((active_ptd_bitmap & ptd_bitmap) && !(td_ptd_map->td)) {			
+			/* This ptd needs to be scheduled */
+
+			ed = td_ptd_map->ed;			
+
+			td = (td_t*)(ed->hwHeadP & 0xfffffff0);
+		
+
+
+			td_head = (ed->hwHeadP & HC_ED_HEADP);
+			td_tail = (ed->hwTailP & HC_ED_TAILP);
+
+			if(td_head != td_tail)  {
+
+#ifdef CONFIG_USB_PHCD_PING_PONG
+	
+				if( (((urb_priv_t*)(td->urb->hcpriv))->length > 1) &&
+				   ( ((td_ptd_index == ptd_map_buff->ping_ptd_index) || 
+				 	(td_ptd_index == ptd_map_buff->pong_ptd_index))) ) {
+
+					if(td->retry_count == PTD_MAX_RETRY_COUNT) 
+					{
+						/* Fresh ptd's */
+
+						if( (td_ptd_index == ptd_map_buff->ping_ptd_index) && 
+							(!(ptd_map_buff->ping_pong_status & TD_PTD_PING_FILLED) )) {
+							/* If Ping is empty , so fill ping */
+								if(ptd_map_buff->ping_pong_status & TD_PTD_PONG_FILLED) {
+								/* Already Pong PTD is in progress, so skip this PTD */
+	
+									td = (td_t*)(td->hwNextTD & HC_GTD_NEXTTD);
+								}
+
+							if((__u32)td != td_tail) {
+
+								if((td->hwNextTD & HC_GTD_NEXTTD) != td_tail){
+									td_ptd_map->td = td;
+									td_ptd_map->ping_pong = TD_PTD_PING;
+									ptd_map_buff->ping_pong_status = TD_PTD_PING_FILLED;
+									active_ptdmap |= td_ptd_map->ptd_bitmap;
+								} else if(!(ptd_map_buff->ping_pong_status & TD_PTD_PONG_FILLED)){
+									td_ptd_map->td = td;
+									active_ptdmap |= td_ptd_map->ptd_bitmap;
+								}
+
+							} else {
+
+								/* No TD needs to be scheduled as one td is already in progress */
+								/* Might be the last ptd which is PONG ptd and next there are no more 
+						 		* PTDs to schedule but wait till td ptd is cleared */
+							}
+						} else if( (td_ptd_index == ptd_map_buff->pong_ptd_index) && 
+									(!(ptd_map_buff->ping_pong_status & TD_PTD_PONG_FILLED)) ) {
+
+							/* If Pong is empty , so fill pong */
+							if((ptd_map_buff->ping_pong_status & TD_PTD_PING_FILLED)||(ping_pong_bitmap)) {
+
+								if(ptd_map_buff->ping_pong_status & TD_PTD_PING_FILLED) {
+									/* Already Pong PTD is in progress, so skip this PTD */
+	
+									td = (td_t*)(td->hwNextTD & HC_GTD_NEXTTD);
+								}
+	
+								td_ptd_map->td = td;
+								td_ptd_map->ping_pong = TD_PTD_PONG;
+								ptd_map_buff->ping_pong_status = TD_PTD_PONG_FILLED;
+					
+								active_ptdmap |= td_ptd_map->ptd_bitmap;
+							}
+						}
+					} else {
+						if( td_ptd_index == ptd_map_buff->ping_ptd_index ) {
+							td_ptd_map->ping_pong = TD_PTD_PING;
+						} else  {
+							td_ptd_map->ping_pong = TD_PTD_PONG;
+						}
+						td_ptd_map->td = td;
+						active_ptdmap |= td_ptd_map->ptd_bitmap;
+					}
+				} else if(td_ptd_index != ptd_map_buff->pong_ptd_index)
+					/* This will take care of the case, when PING pong index is allocated
+					 * but there is only one PTD (previous) */
+
+#endif /* CONFIG_USB_PHCD_PING_PONG */
+
+				{
+					td_ptd_map->td = td;
+					active_ptdmap |= td_ptd_map->ptd_bitmap;
+				}
+
+			}
+
+
+		} /* if(active_ptd_bitmap & ptd_bitmap)  */
+	
+		active_ptd_bitmap &= (~ptd_bitmap);
+		if(ping_pong_bitmap) {
+			/* higner to lower ptd scanning */
+			td_ptd_index--;
+			ptd_bitmap >>= 1;
+		} else {	
+			/* lower to higner ptd scanning */
+			td_ptd_index++;
+			ptd_bitmap <<= 1;
+		}
+
+	} /* while(active_ptd_bitmap) */
+
+	/* Send the td's for scheduling */
+	phci_fill_send_ptd(phci,active_ptdmap, ptd_map_buff);
+	
+} /* End of fnvProcessAtlInt */
+
+
+/*--------------------------------------------------------------*
+ * INTL Interrupt Processing										* 
+ *--------------------------------------------------------------*/
+void fnvProcessIntlInt(phci_t	*phci) {
+
+	__u8				td_ptd_index = 0;
+	__u8				completion_code,byte_data;
+	__u32				ptd_bitmap;			/* HC 	done atl ptd map */
+	td_ptd_map_buff_t   *ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_INTL]);
+	td_ptd_map_t		*td_ptd_map;
+	td_t				*td;
+	ed_t				*ed;
+	__u8				ram_data[HC_INTL_BLK_SIZE];
+	__u32				ram_addr;
+	__u16				bytes;
+	__u32				uData1, uTotal;
+	__u8*				td_payload;
+	__u32				active_ptd_bitmap = 0;
+	__u32				active_ptdmap = 0;
+
+	__u32				fn, fn_rem;
+
+	detail_debug(("fnvProcessIntlInt(phci = 0x%p)\n",phci))
+
+	/* Read the Atl Done PTD's map from the HC atl buffer */
+	phci_reg_read32(REG_INTL_PTD_DONE_MAP, &ptd_bitmap);
+
+	ptd_map_buff->regs.ptd_done_map = ptd_bitmap;
+
+	phci_reg_read32(REG_INTL_PTD_SKIP_MAP, &(ptd_map_buff->regs.ptd_skip_map));/* Read the istl skip map */
+	ptd_map_buff->regs.ptd_skip_map |= ptd_bitmap;						/* Add the done ptds to be skipped */
+	phci_reg_write32(REG_INTL_PTD_SKIP_MAP,ptd_map_buff->regs.ptd_skip_map);	/* Skip all done ptds */
+
+	ptd_bitmap = 0x00000001;
+
+	active_ptdmap = ptd_map_buff->regs.ptd_done_map;
+
+	fnvPhciHcorRead(phci,uHcFmNumber, &fn);
+	fnvPhciHcorRead(phci,uHcFmRemaining, &fn_rem);
+
+	while(ptd_map_buff->regs.ptd_done_map) {						/* If there are any done ptd's present */
+
+		if(ptd_map_buff->regs.ptd_done_map & ptd_bitmap) {	/* At this bitmap there is a done ptd */
+			td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+				
+			ram_addr = ptd_map_buff->ram_buff_addr+td_ptd_index*(ptd_map_buff->regs.block_pl_size + HC_PTD_HEADER_SIZE);
+
+			/* Read the PTD header from the HC */
+			fnvPhciRamRead(phci, HC_PTD_HEADER_SIZE , HC_DIR_ADDR_INCREMENT, ram_addr, ram_data);
+
+			td = td_ptd_map->td;
+
+			if(td_ptd_map->state == TD_PTD_OPER && td ) {				/* This PTD is done, do the necessary processing */
+
+				ed = td->ed;											/* Get the ed of this td */
+
+				ptd_map_buff->active_ptds--;	
+
+				/* Process completion code, and toggle bit */
+				byte_data = ram_data[1];
+
+				if ((byte_data & PTD_ACTIVE) == 0) {       /* Test if the PTD is still active */
+
+					/* Copy completion code to GTD */
+					completion_code = ((byte_data & PTD_COMPLETION_CODE) >> 4);
+
+					bytes = (ram_data[0]+((ram_data[1] & 0x3) << 8));	/* Get the actual bytes */
+
+
+					/* MOCK OHCI IN SOFTWARE */
+						
+					/* Check if there is any transmission error (pid check fail, data toggle mismatch, crc fail, bitstuffing or dev not responding)
+					and number of retries is not zero then process the PTD else go to transmission error processing */
+					if(!(--(td->retry_count)) || (completion_code != TD_PIDCHECKFAIL && 
+						completion_code != TD_CC_DATATOGGLEM && completion_code  != TD_CC_CRC && 
+						completion_code != TD_CC_BITSTUFFING && completion_code != TD_DEVNOTRESP)) 
+					{
+
+
+						td->hwINFO &= ~HC_GTD_CC; /* Clear the original CC */
+						td->hwINFO |= completion_code << 28; /*a Toggle */
+						/* Copy the data toggle from PTD to ED and TD if there is no error or if under run or over run (for IN transfers),
+						for others it is treated as error and some error handling mechanism should be done */
+						if (completion_code == TD_CC_NOERROR || 
+						((completion_code == TD_DATAOVERRUN || completion_code == TD_DATAUNDERRUN) && (((ram_data[5] & PTD_DIR) >> 2) == OHCI_IN))) {
+							/* Get the data toggle bit from PTD in ATL */
+							uData1 = 0;
+							uData1 = (__u32) ((ram_data[1] & PTD_TOGGLE) >> 2);
+
+							/* Set the toggle bit same as the PTD in ATL */
+							td->hwINFO &= ~HC_GTD_TLSB;    /* Clear the toggle bit */
+							td->hwINFO |= (uData1 << 24);  /* Move it into position */
+	
+							ed->hwHeadP &= ~HC_ED_TOGGLE;		/* clear the toggle bit in ED */
+							ed->hwHeadP |= (uData1 << 1);		/* copy the ptd toggle bit here */
+
+						}
+
+
+						/*******************************/
+						/* Move TDs to done-queue list */
+						/*******************************/
+
+						/* Dequeue the current TD (the first TD in the TD queue from ED */
+						ed->hwHeadP &= ~HC_ED_HEADP; 							/* Clear the head pointer */
+						ed->hwHeadP |= (td->hwNextTD & HC_GTD_NEXTTD);
+
+						/* Move the TD to the head of done queue */
+						td->hwNextTD = (__u32)ptd_map_buff->done_head;
+						ptd_map_buff->done_head = td;
+
+						/* Take out the PID token from PTD byte 5 */
+						byte_data = (ram_data[5] & PTD_DIR) >> 2;
+
+						/* Move data returned from device to the buffer for IN transfer */
+						/* The data in case of under run as well as over run is valid and we have to copy the data to td buffer */
+						if ((byte_data == OHCI_IN) && ((completion_code == TD_CC_NOERROR) ||
+						(completion_code == TD_DATAUNDERRUN ) || (completion_code == TD_DATAOVERRUN))) {
+
+							td_payload = (__u8*) td->hwCBP; 						/* Starting address */
+
+							/* Get the actual number of transferred bytes */
+							uTotal = ((__u32) (ram_data[1] & PTD_ACTUAL_BYTES98)) << 8; 		/* Bit 9..8 */
+							uTotal |= (__u32) (ram_data[0]); 								/* Bit 7..0 */
+
+							if(uTotal && td_payload) {
+								fnvPhciRamRead(phci, uTotal, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), td_payload);
+							}
+
+						} /* if (byData == OHCI_IN) */
+
+						/* Update the Current Buffer pointer.
+						if success:: make CBP = 0 to signal that complete TD is success.
+						if underrun/overrun, update it to the received bytes so that the application knows how many bytes are transfered */
+						if( completion_code == TD_CC_NOERROR) td->hwCBP = 0;    /* To signal that last byte has been transferred */
+						else if(byte_data == OHCI_IN && (completion_code == TD_DATAUNDERRUN || completion_code == TD_DATAOVERRUN) ) {
+							td->hwCBP += bytes;
+						}
+
+						/* If the buffer rounding bit is set, and its an under run case, we treat that as success */
+						if(completion_code == TD_DATAUNDERRUN && (td->hwINFO & TD_R))
+							completion_code = TD_CC_NOERROR;
+
+						/* For any error other than success we have to halt the End Point */
+						if(completion_code != TD_CC_NOERROR)
+							td->ed->hwHeadP |= 0x00000001;
+
+						if(completion_code) printk("INTL CC = 0x%d, bytes = %d, OUT:%d bitmap = %x at fn = %x, fn_rem =%x\n",completion_code,bytes,(((ram_data[5] & PTD_DIR) >> 2) == OHCI_OUT), ptd_bitmap, fn, fn_rem);
+//						else isp1362_udelay(500);
+
+					} else {
+						/* ERROR_HANDLING_FIX:: */
+						/* Allt the transmission error cases are handled here.  Inverse and copy the toggle bit, 
+						copy any data if present, update current buffer pointer and don't put this in done queue so that 
+						this td is scheduled for transfer again */
+
+						byte_data = (ram_data[5] & PTD_DIR) >> 2;
+						if(byte_data == OHCI_OUT|| (byte_data == OHCI_IN )) {			/* Assuming SETUP tokens does not have this problem */
+
+							/* Get the data toggle bit from PTD in ATL */
+							uData1 = 0;
+							uData1 = (__u32) ((ram_data[1] & PTD_TOGGLE) >> 2);
+
+							/* Set the toggle bit same as the PTD in ATL */
+							td->hwINFO &= ~HC_GTD_TLSB;    /* Clear the toggle bit */
+							td->hwINFO |= (uData1 << 24);  /* Move it into position */
+	
+							ed->hwHeadP &= ~HC_ED_TOGGLE;		/* Clear the ED toggle bit */
+							ed->hwHeadP |= (uData1 << 1);		/* Move the toggle bit to ED */
+
+							/* Copy the received bytes in case of IN Transfer */
+							if(byte_data == OHCI_IN) {
+								td_payload = (__u8*) td->hwCBP; 			/* Starting address */
+									
+								if(bytes && td_payload) {
+									fnvPhciRamRead(phci, bytes, HC_DIR_ADDR_INCREMENT, (ram_addr+HC_PTD_HEADER_SIZE), td_payload);
+								}
+							}
+							td->hwCBP += bytes;						/* Update the current buffer pointer */
+						}
+								
+					}
+				
+					td_ptd_map->td = NULL;
+
+				} /* if ((byData & PTD_ACTIVE) == 0) */
+
+				byte_data = ram_data[1];    /* Byte 1 of PTD contains the PTD active bit */
+				if ((byte_data & PTD_ACTIVE)) {    /* Test if the PTD is still active */
+					/* Get the actual number of transferred bytes */
+					uTotal = 0;
+					uTotal = ((__u32) (ram_data[1] & PTD_ACTUAL_BYTES98)) << 8; /* Bit 9..8 */
+					uTotal |= (__u32) (ram_data[0]); /* Bit 7..0 */
+
+					printk("Active PTD is received as done PTD with %d bytes at fn:%x with rem_bits:%x, future success is unexpected",uTotal, fn, fn_rem);
+				} /* if ((byData & PTD_ACTIVE) == 1) */
+
+			} else {		/* the ed is deleted in between */
+							/* Do nothing for this ptd */
+			}
+
+			ptd_map_buff->regs.ptd_done_map &= (~(ptd_bitmap));
+		}
+		td_ptd_index++;
+		ptd_bitmap <<= 1;
+
+	} /* while( ptd_map_buff->regs.ptd_done_map ) */
+
+	/* Process the done-queue list */
+	dl_done_list( phci, dl_reverse_done_list(phci,ptd_map_buff->done_head));
+	ptd_map_buff->done_head = 0;
+
+	
+	active_ptd_bitmap = ptd_map_buff->active_ptd_bitmap;
+	
+	active_ptdmap = 0;
+
+	ptd_bitmap = 0x00000001;
+	td_ptd_index = 0;
+
+	/* Update the td's in the td-ptd list for scheduling */
+	while(active_ptd_bitmap) {
+	
+		td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+
+		if((active_ptd_bitmap & ptd_bitmap) && !(td_ptd_map->td)) {			/* This ptd needs to be scheduled */
+
+			ed = td_ptd_map->ed;			
+			
+			td_ptd_map->td = (td_t*)(ed->hwHeadP & 0xfffffff0);
+			active_ptdmap |= td_ptd_map->ptd_bitmap;
+
+		} /* if(active_ptd_bitmap & ptd_bitmap)  */
+	
+		td_ptd_index++;
+		active_ptd_bitmap &= (~ptd_bitmap);
+		ptd_bitmap <<= 1;
+
+	} /* while(active_ptd_bitmap) */
+
+
+	/* Send the td's for scheduling */
+	phci_fill_send_ptd(phci,active_ptdmap, ptd_map_buff);
+
+} /* End of fnvProcessIntlInt */
+
+
+void fnvProcessIstlInt(phci_t	*phci) {
+
+	__u8				td_ptd_index = 0;
+	__u8				completion_code;
+	__u32				td_head, td_tail;
+	td_ptd_map_buff_t   *ptd_map_buff = NULL;
+	td_ptd_map_t		*td_ptd_map;
+	td_t				*td;
+	ed_t				*ed;
+#if 0 /* NSS Debug */
+	__u8				ram_data[HC_INTL_BLK_SIZE];
+#else
+	__u8				ram_data[HC_ISTL_BLK_SIZE];
+#endif
+	__u16				bytes;
+	__u8*				td_payload;
+	__u32				active_ptd_bitmap = 0;
+	__u32				ptdmap = 0;
+
+	__u32				frame_number= 0, fn_rem;
+	__u32				hc_buff_sts, istl_irq = 0;	
+	__u32				istl_full_flag = 0;
+
+	__u8				fn_offset;
+	__u32				td_frame_number;
+	__u32				irq_mask;
+	__u8				missed_toggle = 0;
+	__u32				fn_diff = 0;
+	__u8				toggle_rate;
+
+	
+
+	td_ptd_map_buff_t   *istl0_ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0]);
+	td_ptd_map_buff_t   *istl1_ptd_map_buff = &(td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1]);
+
+
+	toggle_rate = istl0_ptd_map_buff->regs.toggle_rate;
+
+	fnvPhciHcorRead(phci,uHcFmNumber, &frame_number);
+
+
+	irq_mask = phci->phci_regs.int_reg;
+	
+	phci_reg_read16(REG_BUFF_STS, &hc_buff_sts);
+
+	if( ((irq_mask & ISTL_0_INT) && (irq_mask & ISTL_1_INT)) || (phci->hcd_operational_flags & ISOC_SCHED_MISSED) ) {
+
+		missed_toggle = 1;
+		fn_diff = (istl1_ptd_map_buff->frame_number - istl0_ptd_map_buff->frame_number) %0x10000;
+		phci->hcd_operational_flags |= ISOC_SCHED_MISSED;
+
+		if(fn_diff < 0xF000) {
+
+			/* Time to Process ISTL 0 Buffer */
+			ptd_map_buff = istl0_ptd_map_buff;
+			istl_full_flag = ISTL_0_BUFF_FULL;
+			istl_irq = ISTL_0_INT;
+
+		} else {
+
+			ptd_map_buff = istl1_ptd_map_buff;
+			istl_full_flag = ISTL_1_BUFF_FULL;
+			istl_irq = ISTL_1_INT;
+
+		}
+
+		fn_diff = (ptd_map_buff->frame_number - frame_number) %0x10000;
+		if(fn_diff < toggle_rate) {
+			phci->hcd_operational_flags &= (~ISOC_SCHED_MISSED);
+		}
+
+	} else {
+
+		if( irq_mask & ISTL_0_INT ) {
+
+			fn_diff = (istl0_ptd_map_buff->frame_number - frame_number) % 0x10000;	
+			/* Time to Process ISTL 0 Buffer */
+			ptd_map_buff = istl0_ptd_map_buff;
+			istl_full_flag = ISTL_0_BUFF_FULL;
+			istl_irq = ISTL_0_INT;
+
+
+		} else if( irq_mask & ISTL_1_INT ) {
+
+			/* Time to process ISTL 1 Buffer */
+			fn_diff = (istl1_ptd_map_buff->frame_number - frame_number) % 0x10000;	
+			ptd_map_buff = istl1_ptd_map_buff;
+			istl_full_flag = ISTL_1_BUFF_FULL;
+			istl_irq = ISTL_1_INT;
+		}
+	}
+	
+
+	if(ptd_map_buff) {
+
+
+		td_ptd_index = 0;
+		active_ptd_bitmap = ptd_map_buff->active_ptd_bitmap;
+		ptdmap = 0x00000001;
+
+		while(active_ptd_bitmap) {
+
+			if(ptdmap & active_ptd_bitmap) {
+
+				td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index]);
+				td = td_ptd_map->td;
+				ed = td_ptd_map->ed;
+
+				if( td && ed) {
+					fnvPhciRamRead(phci,HC_PTD_HEADER_SIZE , HC_DIR_ADDR_INCREMENT, td_ptd_map->ram_addr, ram_data);
+
+				
+					completion_code = ((ram_data[1] & PTD_COMPLETION_CODE) >> 4);
+
+					td->hwINFO &= (~HC_GTD_CC);
+					td->hwINFO |= (completion_code << 28);
+
+					td_payload = (__u8*)(td->hwCBP + (td->hwPSW[0] & 0x0FFF));
+
+					td->hwPSW[0] = 0;
+
+					if((((ram_data[5] & PTD_DIR) >> 2) == OHCI_IN)) {
+						bytes = ((__u16) (ram_data[1] & PTD_ACTUAL_BYTES98)) << 8;
+						bytes |= (__u16)(ram_data[0]);
+
+
+						if((completion_code == TD_CC_NOERROR) || (completion_code == TD_DATAUNDERRUN) || (completion_code == TD_DATAOVERRUN)){
+	                         fnvPhciRamRead(phci, bytes , HC_DIR_ADDR_INCREMENT, (td_ptd_map->ram_addr+HC_PTD_HEADER_SIZE), td_payload);
+							td->hwPSW[0] |= bytes & 0x7FFF;
+							td->hwCBP = 0;
+						}
+					}
+
+					td->hwPSW[0] |= (completion_code << 12);
+				}
+				td_ptd_map->td = NULL;
+			}
+
+			td_ptd_index++;
+			active_ptd_bitmap &= (~ptdmap);
+			ptdmap <<= 1;
+		}
+		dl_done_list(phci, dl_reverse_done_list(phci, ptd_map_buff->done_head));
+		ptd_map_buff->done_head = NULL;
+		phci->hcd_operational_flags &= (~istl_full_flag);
+	}
+
+	if(phci->ed_rm_list[!(frame_number&0x1)] != NULL) {
+		dl_del_list(phci, !(frame_number&0x1));
+	}
+
+isoc_refill:
+
+	if(phci->hcd_operational_flags & ISOC_SCHED_TO_START) {
+
+		/* ISOC_WAIT_FIX */
+		if( ((frame_number+1)%0x10000) != istl0_ptd_map_buff->frame_number) {			
+			/* if you are still waiting for the first frame to come do nothing */
+			return;
+		}
+	
+		ptd_map_buff = istl0_ptd_map_buff;
+		istl_full_flag = ISTL_0_BUFF_FULL;
+
+		phci_reg_write16(REG_ISTL_TOGGLE_RATE, istl0_ptd_map_buff->regs.toggle_rate);	/* Istl toggle rate */
+
+		istl1_ptd_map_buff->frame_number = (istl0_ptd_map_buff->frame_number + toggle_rate) % 0x10000;
+
+		phci->hcd_operational_flags &= (~ISOC_SCHED_TO_START);
+		phci->hcd_operational_flags &= (~ISOC_ISTL0_SCHED_TO_START);
+
+	} else if(phci->hcd_operational_flags & ISOC_ISTL1_SCHED_TO_START){
+		ptd_map_buff = istl1_ptd_map_buff;
+		istl_full_flag = ISTL_1_BUFF_FULL;
+		phci->hcd_operational_flags &= (~ISOC_ISTL1_SCHED_TO_START);
+	} 
+
+	else if(!missed_toggle) {
+	
+		if( (phci->hcd_operational_flags & ISTL_0_BUFF_FULL) == 0 ) {
+			ptd_map_buff = istl0_ptd_map_buff;
+			istl_full_flag = ISTL_0_BUFF_FULL;
+		} else if( (phci->hcd_operational_flags & ISTL_1_BUFF_FULL) == 0 ) {
+			ptd_map_buff = istl1_ptd_map_buff;
+			istl_full_flag = ISTL_1_BUFF_FULL;
+		}
+	} else {
+	
+		/* You need to write special software to take care of frame missing */
+	}
+
+
+	ed = phci->ed_isohead;
+
+	if( ed && ptd_map_buff) {
+
+		active_ptd_bitmap = 0;
+
+		while(ed) {
+
+			td_head = (ed->hwHeadP & HC_ED_HEADP);
+			td_tail = (ed->hwTailP & HC_ED_TAILP);
+
+			td_ptd_index = ed->td_ptd_index;
+
+			if(td_head != td_tail) {
+
+				td = (td_t*)td_head;
+				
+				do{
+
+					td_frame_number = (td->hwINFO & 0xFFFF);
+
+					fn_diff = ((td_frame_number - ptd_map_buff->frame_number) % 0x10000);
+
+					if(fn_diff == 0 ) {
+
+						for(fn_offset=0; ((fn_offset < toggle_rate) && (td_head != td_tail)); fn_offset++) {
+
+							td_ptd_map = &(ptd_map_buff->map_list[td_ptd_index + fn_offset]);
+
+							td_ptd_map->td = td;
+
+							if((phci->hcd_operational_flags & ISOC_SCHED_MISSED)==0) 
+							{
+								active_ptd_bitmap |= td_ptd_map->ptd_bitmap;
+							}
+
+							td->hwINFO &= (~HC_GTD_CC);
+							td->hwINFO |= ( (TD_NOTACCESSED << 28));
+
+							ed->hwHeadP &= (~HC_ED_HEADP);
+							ed->hwHeadP |= (td->hwNextTD & HC_GTD_NEXTTD);
+
+							td->hwNextTD = (__u32)(ptd_map_buff->done_head);
+							ptd_map_buff->done_head = td;
+
+							td_head = (ed->hwHeadP & HC_ED_HEADP);
+							td = (td_t*)td_head;
+						}
+						break;
+					} else if( fn_diff > 2*toggle_rate) {
+						td->hwINFO &= (~HC_GTD_CC);
+						td->hwINFO |= ( (TD_CC_NOERROR << 28));
+
+						ed->hwHeadP &= (~HC_ED_HEADP);
+						ed->hwHeadP |= (td->hwNextTD & HC_GTD_NEXTTD);
+
+						td->hwNextTD = (__u32)(ptd_map_buff->done_head);
+						ptd_map_buff->done_head = td;
+
+						td_head = (ed->hwHeadP & HC_ED_HEADP);
+						td = (td_t*)td_head;
+					} else {
+						/* wait till td's toggle rate comes, should not touch this point */
+					}
+				} while( td_head != td_tail);
+
+			}
+
+			ed  = (ed_t*)ed->hwNextED;
+		}
+
+		if(active_ptd_bitmap) {
+			phci_fill_send_isoc_ptd(phci, active_ptd_bitmap, ptd_map_buff);
+			phci->hcd_operational_flags |= istl_full_flag;
+		} else if((phci->hcd_operational_flags & ISOC_SCHED_MISSED)){
+			phci->hcd_operational_flags |= istl_full_flag;
+		}
+		ptd_map_buff->frame_number = (ptd_map_buff->frame_number + 2*toggle_rate) % 0x10000;
+	}
+
+	if (!(phci->ed_isohead)) {
+
+		phci_reg_read16(REG_BUFF_STS, &hc_buff_sts);
+//		phci_reg_read16(REG_IRQ, &irq_mask);
+		irq_mask = phci->phci_regs.int_reg;
+		while(hc_buff_sts & 0x60) {
+			phci_reg_read16(REG_BUFF_STS, &hc_buff_sts);
+		}
+		phci_reg_write16(REG_ISTL_TOGGLE_RATE, HC_ISTL_DEF_TOGGLE_RATE);		/* Istl toggle rate */
+																						/* No more ed's, Better to turn off SOF & ISOC processing */
+		istl0_ptd_map_buff->frame_number = INVALID_FRAME_NUMBER;
+		istl1_ptd_map_buff->frame_number = INVALID_FRAME_NUMBER;
+
+		istl0_ptd_map_buff->done_head = NULL;
+		istl1_ptd_map_buff->done_head = NULL;
+
+		phci->hcd_operational_flags &= (~ISOC_TRANSFER_ON);
+		phci->hcd_operational_flags = 0;
+	}
+
+	if(phci->hcd_operational_flags & ISOC_ISTL0_ISTL1_TO_START) {
+		phci->hcd_operational_flags &= (~ISOC_ISTL0_ISTL1_TO_START);
+		goto isoc_refill;
+	}
+
+} /* End of fnvProcessIstlInt */
+
+
+/*--------------------------------------------------------------*
+ * HC Interrupt Functions									* 
+ *--------------------------------------------------------------*/
+/*--------------------------------------------------------------*
+ * Host Controller Interrupt function						*
+ *--------------------------------------------------------------*/
+void 	phci_isr(struct isp1362_dev *dev, void *isr_data) 
+{
+
+	__u32	 int_reg;		/* Int. status of the HC ext. int register */
+	phci_t	*phci = (phci_t*)isr_data;
+
+	__u32	fn,fn_rem;
+	__u32	data_read;
+
+	int_reg = dev->int_reg;
+	phci->phci_regs.int_reg = int_reg;
+
+	/*********************************************/
+	/* Process ISTL_0_INT                         */
+	/* ISTL0 Done                                 */
+	/*********************************************/
+
+	if ((int_reg & ISTL_0_INT) || (int_reg & ISTL_1_INT)) {
+
+
+		fnvProcessIstlInt(phci);			/* Proess the ISTL interrupt */
+
+		if( phci->hcd_operational_flags & ISOC_SCHED_MISSED) {
+			phci_reg_read16(REG_IRQ_MASK, &data_read);
+			data_read |= (SOF_INT);							/* Enable SOF processing */
+			phci_reg_write16(REG_IRQ_MASK, data_read);
+		}
+
+	} /* if ISTL_1_INT */
+
+	/*********************************************/
+	/* Process ATL_INT                           */
+	/* ALT Done                                  */
+	/*********************************************/
+
+	if (int_reg & ATL_INT) {
+
+		fnvProcessAtlInt(phci);			/* Proess the ATL interrupt */
+
+	} /* if ATL_INT */
+
+	/*********************************************/
+	/* Process INTL_INT                           */
+	/* ILT Done                                  */
+	/*********************************************/
+
+	if (int_reg & INTL_INT) {
+
+		fnvProcessIntlInt(phci);		/* Proess the INTL interrupt */
+
+	} /* if ITL_INT */
+
+
+
+	/*******************************/
+	/* Process SOFInt IRQ       */
+	/* SOF interrupts      */
+	/*******************************/
+	if (int_reg & SOF_INT) {
+
+		if(phci->hcd_operational_flags & (ISOC_ISTL0_SCHED_TO_START | ISOC_ISTL1_SCHED_TO_START | ISOC_SCHED_MISSED))
+		{
+
+		 	fnvProcessIstlInt(phci);		/* Proess the ISTL interrupt */
+
+		} else {
+
+			fnvPhciHcorRead(phci,uHcFmNumber, &fn);
+
+			if(phci->ed_rm_list[!(fn&0x1)] != NULL) {
+				dl_del_list(phci, !(fn&0x1));
+			}
+		}
+
+
+		if( (phci->ed_rm_list[(fn&0x1)] != NULL) || 
+			(phci->hcd_operational_flags & (ISOC_ISTL0_SCHED_TO_START | ISOC_ISTL1_SCHED_TO_START | ISOC_SCHED_MISSED)) 
+		) {
+		} else {
+			phci_reg_read16(REG_IRQ_MASK, &data_read);
+			data_read &= (~SOF_INT);							/* Disable SOF processing */
+			phci_reg_write16(REG_IRQ_MASK, data_read);
+		}
+
+	} /* if SOF_INT */
+
+
+} /* End of phci_isr() */
+
+
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*
+ * fill the td with the information
+ *-------------------------------------------------------------------------*/
+static void td_fill (unsigned int info, void * data, int len, struct urb * urb, int index) {
+	td_t  * td, * td_pt;
+	urb_priv_t * urb_priv = urb->hcpriv;
+
+	dbg();
+
+	detail_debug(("td_fill(info = 0x%x, data = 0x%p, len = %d, urb = 0x%p, index = %d)\n",info, data, len, urb, index))
+
+	/* Check if TD Index is > maximum number of td's for this urb */
+	if (index >= urb_priv->length) {
+		err("internal OHCI error: TD index > length");
+		return;
+	}
+
+	td_pt = urb_priv->td [index];
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = (td_t *) ((urb_priv->ed->hwTailP) & 0xfffffff0);
+
+	/* Fill the non-phci elements of td data structure */
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->urb = urb; 
+
+	/* Fill the phci elements of td data structure */
+	td->hwINFO = (info);
+
+	/* Fill the current buffer pointer ,based on length */
+	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
+		td->ed->total_isoc_tds++;
+		td->hwCBP = ((!data || !len) ? 0 : ((__u32)data)) & 0xFFFFF000;
+		td->ed->last_iso = info & 0xffff;
+	} else {
+		td->hwCBP = (!data || !len) ? 0 : ((__u32)data); 
+	}			
+	td->hwBE = (!data || !len ) ? 0 : ((__u32)data + len - 1);
+	td->hwNextTD = (__u32)td_pt;
+	td_pt->hwNextTD = 0;
+	td->ed->hwTailP = td->hwNextTD;
+
+	
+	/* Only one buffer per Iso TD */
+	td->hwPSW [0] = (((__u32)data) & 0x0FFF) | 0xE000;
+
+	/* Using of unused field for retry count for errors like
+	crc check, bit stuffing, dev not responding pid check etc */
+	td->retry_count = PTD_MAX_RETRY_COUNT;
+
+	if(data && len && (info & TD_DP_IN)){
+		memset(data,0,(td->hwBE - td->hwCBP +1));
+	}	
+
+} /* End of td_fill */
+
+/*-------------------------------------------------------------------------*
+ * prepare all TDs of a transfer
+ *-------------------------------------------------------------------------*/
+static void td_submit_urb (struct urb * urb) { 
+
+	urb_priv_t * urb_priv = urb->hcpriv;
+	phci_t * phci = (phci_t *) urb->dev->bus->hcpriv;
+	void * ctrl = urb->setup_packet;
+	void * data = urb->transfer_buffer;
+	int data_len = urb->transfer_buffer_length;
+	int cnt = 0; 
+  	unsigned int toggle = 0;
+	__u32 info = 0;
+	__u32	data_read;
+        int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+  	if(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe))) {
+  		toggle = TD_T_TOGGLE;
+	} else {
+  		toggle = TD_T_DATA0;
+		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 1);
+	}
+	
+	urb_priv->td_cnt = 0;
+	
+	switch (usb_pipetype (urb->pipe)) {
+		case PIPE_BULK:
+			info = usb_pipeout (urb->pipe)?  TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+			/* Fill the transfer descriptors of size MAX_BULK_TD_BUFF_SIZE.
+			data toggle bit for first is set to 0 and rest depends on the
+			toggle bit of previous td */
+			while(data_len > MAX_BULK_TD_BUFF_SIZE) {		
+				td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, MAX_BULK_TD_BUFF_SIZE, urb, cnt);
+				data += MAX_BULK_TD_BUFF_SIZE; data_len -= MAX_BULK_TD_BUFF_SIZE; cnt++;
+			}
+
+			/* Fill the last TD of bulk transfer */
+			info = usb_pipeout (urb->pipe)?
+				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+			td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
+			cnt++;
+
+                        /* If the transfer size is multiple of the pipe mtu,
+                         * we may need an extra TD to create a empty frame */
+                        if ((urb->transfer_flags & USB_ZERO_PACKET) && usb_pipeout (urb->pipe) &&
+                            (urb->transfer_buffer_length != 0) && ((urb->transfer_buffer_length % maxps) == 0)) {
+                                td_fill (info | (cnt? TD_T_TOGGLE:toggle), 0, 0, urb, cnt);
+                                cnt++;
+                        }
+
+			/* Set yje bulk list filled status on command status register */
+			fnvPhciHcorRead(phci,uHcHcdCommandStatus, &data_read);
+			data_read |= OHCI_BLF;
+			fnvPhciHcorWrite(phci,uHcHcdCommandStatus, data_read);
+			break;
+
+		case PIPE_INTERRUPT:
+			/* For interrupt transfer there is only one td and fill it */
+			info = usb_pipeout (urb->pipe)? 
+				TD_CC | TD_DP_OUT | toggle: TD_CC | TD_R | TD_DP_IN | toggle;
+			td_fill (info, data, data_len, urb, cnt++);
+			break;
+
+		case PIPE_CONTROL:
+			/* set up stage, one td */
+			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+			td_fill (info, ctrl, 8, urb, cnt++); 
+#if 0
+			info = usb_pipeout (urb->pipe)?  TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+
+			while(data_len > MAX_CNTL_TD_BUFF_SIZE) {		
+				td_fill (info | ((cnt-1) ? TD_T_TOGGLE:TD_T_DATA1), data, MAX_CNTL_TD_BUFF_SIZE, urb, cnt);
+				data += MAX_BULK_TD_BUFF_SIZE; data_len -= MAX_CNTL_TD_BUFF_SIZE; cnt++;
+			}
+#endif
+
+			/* Fill the last data TD of control transfer */
+			if(data_len > 0) {
+				info = usb_pipeout (urb->pipe)?
+					TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+				td_fill (info | ((cnt-1)? TD_T_TOGGLE:TD_T_DATA1), data, data_len, urb, cnt);
+				cnt++;
+			}
+			
+			/* Status stage, one td */
+			info = usb_pipeout (urb->pipe)? 
+ 				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+			td_fill (info, NULL, 0, urb, cnt++);
+			fnvPhciHcorRead(phci,uHcHcdCommandStatus, &data_read);
+			data_read |= OHCI_CLF;
+			fnvPhciHcorWrite(phci,uHcHcdCommandStatus, data_read);
+			break;
+
+		case PIPE_ISOCHRONOUS:
+			/* Td's based on number of packets to be sent */
+			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
+				td_fill (TD_CC|TD_ISO | ((urb->start_frame + cnt) & 0xffff), 
+ 					(__u8 *) data + urb->iso_frame_desc[cnt].offset, 
+					urb->iso_frame_desc[cnt].length, urb, cnt); 
+			}
+			break;
+	} 
+	if (urb_priv->length != cnt) 
+		dbg("TD LENGTH %d != CNT %d", urb_priv->length, cnt);
+	
+} /* End of td_submit_urb */
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/  
+		
+/* search for the right branch to insert an interrupt ed into the int tree 
+ * do some load ballancing;
+ * returns the branch and 
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (phci_t * phci, int interval, int load) {
+
+	int i, branch = 0;
+
+	detail_debug(("ep_int_ballance(phci = 0x%p, interval = %d, load = %d)\n",phci, interval, load))
+   
+	/* search for the least loaded interrupt endpoint branch of all 32 branches */
+	for (i = 0; i < 32; i++) 
+		if (phci->phci_int_load [branch] > phci->phci_int_load [i]) branch = i; 
+  
+	branch = branch % interval;
+	for (i = branch; i < 32; i += interval) phci->phci_int_load [i] += load;
+
+	return branch;
+} /* End of ep_int_ballance */
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+/* Finding the nearest 2^n interval (1,2,4,8,16,32) for a given inter of any value */
+static int ep_2_n_interval (int inter) {	
+	int i;
+
+	detail_debug(("ep_2_n_interval(inter = %d)\n",inter))
+
+	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); 
+	return 1 << i;
+} /* End of ep_2_n_interval */
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree 
+ * in order to process it sequentially the indexes of the branches have to be mapped 
+ * the mapping reverses the bits of a word of num_bits length */
+ 
+static int ep_rev (int num_bits, int word) {
+	int i, wout = 0;
+
+	detail_debug(("ep_rev(num_bits = %d, word = %d)\n",num_bits, word))
+
+	for (i = 0; i < num_bits; i++) wout |= (((word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+} /* End of ep_rev */
+
+/*-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (phci_t * phci, ed_t * edi) {	 
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	int load;
+	ed_t	**ed_p;
+	volatile ed_t * ed = edi;
+	__u32	data_read;
+	
+
+	func_debug(("ep_link(phci = 0x%p, edi = 0x%p)\n",phci, edi))
+	
+	/* Assign a td-ptd index for this ed so that we can put ptd's in the HC buffers */
+	ed->td_ptd_index = TD_PTD_INV_PTD_INDEX;
+	phci_get_td_ptd_index(edi);		/* Get a td-ptd index */
+	if(ed->td_ptd_index == TD_PTD_INV_PTD_INDEX) {
+		detail_debug(("unable to get a slot for the data tranfer\n"))
+		return -ENOMEM;
+	}
+
+	ed->state = ED_OPER;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+
+		/* Check if the control list is empty */
+		if (phci->ed_controltail == NULL) {
+			phci->p_ed_controlhead = edi;
+		} else {
+			phci->ed_controltail->hwNextED = (__u32)edi;
+		}
+		ed->ed_prev = phci->ed_controltail;
+
+		/* Fill control list enable bit in control register 
+		if no to be remved ed list and ed is correct */
+		if (!phci->ed_controltail && !phci->ed_rm_list[0] &&
+			!phci->ed_rm_list[1]) {
+			phci->hc_control |= OHCI_CTRL_CLE;
+			fnvPhciHcorRead(phci,uHcHcdControl,&data_read);
+			data_read |= OHCI_CTRL_CLE;
+			fnvPhciHcorWrite(phci,uHcHcdControl, data_read);
+		}
+
+		/* set the ed control list tail to the current ed to be linked */
+		phci->ed_controltail = edi;	  
+		break;
+		
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+
+		/* Check if the bulk ed list is empty */
+		if (phci->ed_bulktail == NULL) {
+			phci->p_ed_bulkhead = edi;	
+		} else {
+			phci->ed_bulktail->hwNextED = (__u32)edi;
+		}
+		ed->ed_prev = phci->ed_bulktail;
+
+		/* Fill bulk list enable bit in control register 
+		if no to be remved ed list and ed is correct */
+
+		if (!phci->ed_bulktail && !phci->ed_rm_list[0] &&
+			!phci->ed_rm_list[1]) {
+			phci->hc_control |= OHCI_CTRL_BLE;
+			fnvPhciHcorRead(phci,uHcHcdControl,&data_read);
+			data_read |= OHCI_CTRL_BLE;
+			fnvPhciHcorWrite(phci,uHcHcdControl, data_read);
+		}
+		/* set the ed control list tail to the current ed to be linked */
+		phci->ed_bulktail = edi;	  
+		break;
+		
+	case PIPE_INTERRUPT:
+		load = edi->int_load;
+
+		/* find the nearest 2^n interval */
+		interval = ep_2_n_interval (ed->int_period);
+		ed->int_interval = interval;
+
+		/* find the interrupt brach where we can start linking this ed,
+		for optimum load balancing */
+		int_branch = ep_int_ballance (phci, interval, load);
+		ed->int_branch = int_branch;
+		
+		/* link the ed to all the lists in the interrupt table for
+		the set interval */
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = &(phci->p_int_table[ep_rev (5, i) + int_branch]); 
+				(*ed_p != 0) && ((*ed_p)->int_interval >= interval); 
+				ed_p = (ed_t**)(&((*ed_p)->hwNextED))) 
+					inter = ep_rev (6, (*ed_p)->int_interval);
+			ed->hwNextED = (__u32)(*ed_p); 
+			*ed_p = edi;
+		}  
+#ifdef DEBUG
+		print_int_ed_list(phci);
+#endif
+		break;
+		
+	case PIPE_ISOCHRONOUS:
+		ed->hwNextED = 0;
+		ed->int_interval = 1;
+
+		/* XXXX */
+		if(phci->ed_isotail != NULL) {
+			phci->ed_isotail->hwNextED = (__u32)edi;
+		} else {
+			phci->ed_isohead = edi;
+		}
+		ed->ed_prev = phci->ed_isotail;
+		phci->ed_isotail = edi;  
+		ed->total_isoc_tds = 0;
+		
+		
+		break;
+	}	 	
+	return 0;
+} /* End of ep_link */
+
+/*-------------------------------------------------------------------------*/
+
+/* unlink an ed from one of the HC chains. 
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (phci_t * phci, ed_t * ed) {
+	int 	int_branch;
+	int 	i;
+	int 	inter;
+	int 	interval;
+	ed_t	**ed_p;
+	__u32	data_read;
+
+	func_debug(("ep_unlink(phci = 0x%p, ed = 0x%p)\n",phci, ed))
+
+	ed->hwINFO |= (OHCI_ED_SKIP);
+
+	/* Release the td-ptd index so that we can grab that later when it  is needed */
+	phci_release_td_ptd_index(ed);			/* Release td-ptd index */
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				/* THis is the only ed in the list */
+				phci->hc_control &= ~OHCI_CTRL_CLE;
+				fnvPhciHcorRead(phci,uHcHcdControl,&data_read);
+				data_read &= ~OHCI_CTRL_CLE;
+				fnvPhciHcorWrite(phci, uHcHcdControl, data_read);
+
+			}
+			phci->p_ed_controlhead = (ed_t*)(ed->hwNextED);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+
+		/* set control list tail  if this is the last ed in the list */
+		if (phci->ed_controltail == ed) {
+			phci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *)(ed->hwNextED))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				/* THis is the only ed in the list */
+
+				phci->hc_control &= ~OHCI_CTRL_BLE;
+				fnvPhciHcorRead(phci,uHcHcdControl,&data_read);
+				data_read &= ~OHCI_CTRL_BLE;
+				fnvPhciHcorWrite(phci, uHcHcdControl, data_read);
+			}
+			phci->p_ed_bulkhead = (ed_t*)(ed->hwNextED);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+
+		/* set control list tail  if this is the last ed in the list */
+		if (phci->ed_bulktail == ed) {
+			phci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *)(ed->hwNextED))->ed_prev = ed->ed_prev;
+		}
+		break;
+      
+	case PIPE_INTERRUPT:
+		int_branch = ed->int_branch;
+		interval = ed->int_interval;
+
+		/* remove ed from all the lists in the interrupt table */
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			for (ed_p = &(phci->p_int_table[ep_rev (5, i) + int_branch]), inter = 1; 
+				(*ed_p != 0) && ((__u32)(*ed_p) != ed->hwNextED); 
+				ed_p = (ed_t**)(&((*ed_p)->hwNextED)), 
+				inter = ep_rev (6, (*ed_p)->int_interval)) {				
+					if((*ed_p) == ed) {
+			  			*ed_p = (ed_t*)(ed->hwNextED);		
+			  			break;
+			  		}
+			  }
+		}
+
+		/* remove the load of this ed from the interrupt table lists */
+		for (i = int_branch; i < 32; i += interval)
+		    phci->phci_int_load[i] -= ed->int_load;
+
+#ifdef DEBUG
+		print_int_ed_list(phci);
+#endif
+		break;
+		
+	case PIPE_ISOCHRONOUS:
+
+		/* XXXX */
+		if(phci->ed_isotail == ed)
+			phci->ed_isotail = ed->ed_prev;
+
+		if(phci->ed_isohead == ed)
+			phci->ed_isohead = (ed_t*)(ed->hwNextED);
+
+		if(ed->hwNextED != 0) 
+		    ((ed_t *)(ed->hwNextED))->ed_prev = ed->ed_prev;
+
+		if (ed->ed_prev != NULL) 
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+} /* End of ep_unlink */
+
+
+/*-------------------------------------------------------------------------*/
+ 
+/* request the removal of an endpoint
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start frame (SF) hardware interrupt */
+ 
+static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed) {    
+	unsigned int frame;
+	phci_t * phci = usb_dev->bus->hcpriv;
+	__u32			data_read;
+
+	func_debug(("ep_rm_ed(usb_dev = 0x%p, ed = 0x%p)\n",usb_dev, ed))
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL))
+		return;
+	
+	ed->hwINFO |= (OHCI_ED_SKIP);
+
+	if (!phci->disabled) {
+		/* Stop control and bulk list processing till ed's are removed */
+		switch (ed->type) {
+			case PIPE_CONTROL: /* stop control list */
+				phci->hc_control &= ~OHCI_CTRL_CLE;
+				fnvPhciHcorRead(phci,uHcHcdControl, &data_read);
+				data_read &= ~OHCI_CTRL_CLE;
+				fnvPhciHcorWrite(phci,uHcHcdControl,data_read);
+			case PIPE_BULK: /* stop bulk list */
+				phci->hc_control &= ~OHCI_CTRL_BLE;
+				fnvPhciHcorRead(phci,uHcHcdControl, &data_read);
+				data_read &= ~OHCI_CTRL_BLE;
+				fnvPhciHcorWrite(phci,uHcHcdControl,data_read);
+				break;
+		}
+	}
+
+	/* the concept of removing an ed from the list is to 
+	put it in rm list and on the next SOF interrupt these will be
+	cleared one done list is processed */
+
+	fnvPhciHcorRead(phci,uHcFmNumber,&data_read);
+	frame = data_read & 0x1;
+	ed->ed_rm_list = phci->ed_rm_list[frame];
+	phci->ed_rm_list[frame] = ed;
+
+	phci_reg_read16(REG_IRQ_MASK, &data_read);
+	data_read |= SOF_INT;							/* Enable SOF processing */
+	phci_reg_write16(REG_IRQ_MASK, data_read);
+
+	return;
+} /* End of ep_rm_ed */
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
+ * but the USB stack is a little bit stateless  so we do it at every transaction
+ * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
+ * in all other cases the state is left unchanged
+ * the ed info fields are setted anyway even though most of them should not change */
+ 
+static ed_t * ep_add_ed (struct usb_device * usb_dev, unsigned int pipe, int interval, int load)
+{
+   	phci_t * phci = usb_dev->bus->hcpriv;
+	td_t * td;
+	ed_t * ed_ret;
+	volatile ed_t * ed; 
+ 	
+	func_debug(("ep_add_ed(usb_dev = 0x%p, pipe = 0x%x, interval = %d, load = %d)\n",usb_dev, pipe, interval, load))
+ 	
+	ed = ed_ret = &(usb_to_phci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | 
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]);
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		/* pending delete request */
+		return NULL;
+	}
+	
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = (OHCI_ED_SKIP); /* skip ed */
+  		/* dummy td; end of td list for ed */
+		td = td_alloc (phci);
+  		if (!td) {
+			/* out of memory */
+			return NULL;
+		}
+		ed->hwTailP = (__u32)td;
+		ed->hwHeadP = ed->hwTailP;	
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		usb_to_phci (usb_dev)->ed_cnt++;
+	}
+
+	phci->dev[usb_pipedevice (pipe)] = usb_dev;
+	
+	/* Fill the ed hardware information based on the given information */
+	ed->hwINFO = (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16);
+  
+  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+  		ed->int_period = interval;
+  		ed->int_load = load;
+  	}
+  	
+	return ed_ret; 
+} /* End of ep_add_ed */
+
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*
+ * calculate the transfer length and update the urb
+ *-------------------------------------------------------------------------*/
+static void dl_transfer_length(td_t * td) {
+	__u32 		tdINFO, tdBE, tdCBP;
+ 	__u16 		tdPSW;
+ 	struct urb 		* urb = td->urb;
+ 	urb_priv_t 	* urb_priv = urb->hcpriv;
+	int 		dlen = 0;
+	int 		cc = 0;
+
+	func_debug(("dl_transfer_length(td = 0x%p)\n",td))
+	
+	tdINFO = td->hwINFO;
+  	tdBE   = td->hwBE;
+  	tdCBP  = td->hwCBP;
+
+
+	/* Check if it is general td or ISOchronous td */
+  	if (tdINFO & TD_ISO) {
+ 		tdPSW = td->hwPSW[0];
+ 		cc = (tdPSW >> 12) & 0xF;
+		if (cc < 0xE)  {
+			if (usb_pipeout(urb->pipe)) {
+				dlen = urb->iso_frame_desc[td->index].length;
+			} else {
+				dlen = tdPSW & 0x3ff;
+			}
+			urb->actual_length += dlen;
+			urb->iso_frame_desc[td->index].actual_length = dlen;
+			if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN))
+				cc = TD_CC_NOERROR;
+					 
+			urb->iso_frame_desc[td->index].status = cc_to_error[cc];
+		}
+	} else { /* BULK, INT, CONTROL DATA */
+		/* if the transfer is for control and there exists a data stage for this get 
+		the actual legth frp, the current buffer pointer, transfer bnuffer in urb
+		and buffer end pointer */
+		if (!(usb_pipetype (urb->pipe) == PIPE_CONTROL && 
+				((td->index == 0) || (td->index == urb_priv->length - 1)))) {
+ 			if (tdBE != 0) {
+ 				if (td->hwCBP == 0)
+					urb->actual_length = tdBE - (__u32)urb->transfer_buffer + 1;
+  				else
+					urb->actual_length = tdCBP - (__u32)urb->transfer_buffer;
+			}
+  		}
+  	}
+} /* End of dl_transfer_length */
+
+/*-------------------------------------------------------------------------*
+ * handle an urb that is being unlinked 
+ *-------------------------------------------------------------------------*/
+static void dl_del_urb (phci_t *phci, struct urb * urb) {
+	wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait;
+
+	func_debug(("dl_del_urb(urb = 0x%p)\n",urb))
+
+	urb_rm_priv_locked (urb);
+
+	if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+		urb->status = -ECONNRESET;
+		phci_complete_add(phci, urb);
+	} else {
+		urb->status = -ENOENT;
+
+		/* unblock sphci_unlink_urb */
+		if (wait_head)
+			wake_up (wait_head);
+	}
+} /* End of dl_del_urb */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+void print_int_ed_list(phci_t	*phci) {
+ed_t	*ed;
+int	i;
+	
+	func_debug(("print_int_ed_list(phci = 0x%p)\n",phci))
+
+	for(i=0; i<32; i++) {
+
+		ed = phci->p_int_table[i];
+		if(ed) printk("\n %d:::",i);
+		while(ed!=NULL) {
+			printk(":%p ::%d ",ed, ed->type);
+			ed = (ed_t*)(ed->hwNextED);
+		}
+	}
+}
+#endif
+
+/* there are some pending requests to remove 
+ * - some of the eds (if ed->state & ED_DEL (set by sphci_free_dev)
+ * - some URBs/TDs if urb_priv->state == URB_DEL */
+ 
+static void dl_del_list (phci_t  * phci, unsigned int frame) {
+	ed_t 			* ed;
+	__u32 			edINFO;
+	__u32 			tdINFO;
+	td_t 			* td = NULL, * td_next = NULL, * tdHeadP = NULL, * tdTailP;
+	__u32 			* td_p;
+	struct urb			*del_urb[10];
+	__u8			del_urb_cnt;
+
+	func_debug(("dl_del_list(phci = 0x%p,fn#&0x01 = 0x%x)\n",phci,frame))
+
+	/* go through all the to be removed list of this frame */
+	for (ed = phci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) {
+
+   	 	tdTailP = (td_t*)((ed->hwTailP) & 0xfffffff0);
+		tdHeadP = (td_t*)((ed->hwHeadP) & 0xfffffff0);
+		edINFO = ed->hwINFO;
+		td_p = &(ed->hwHeadP);
+
+		del_urb_cnt = 0;
+		/* process all the td's of the ed */
+		for (td = (td_t*)tdHeadP; td != (td_t*)tdTailP; td = td_next) { 
+			struct urb * urb = td->urb;
+			urb_priv_t * urb_priv = td->urb->hcpriv;
+			
+			td_next = (td_t*)((td->hwNextTD) & 0xfffffff0);
+			if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) {
+				/* If the delete is for urb delete request or ed delete request,
+				update the processed td's count */
+				tdINFO = td->hwINFO;
+				if (TD_CC_GET (tdINFO) < 0xE)
+					dl_transfer_length (td);
+				*td_p = td->hwNextTD | (*td_p & (0x3));
+
+				/* URB is done; clean up */
+				if (++(urb_priv->td_cnt) == urb_priv->length) {
+				if (ed->state & ED_DEL) { /* set by sphci_free_dev */
+					dl_del_urb (phci, urb);
+				} else {
+					del_urb[del_urb_cnt++] = urb;
+				}
+				}
+			} else {
+				td_p = &td->hwNextTD;
+			}
+		}
+
+		if (ed->state & ED_DEL) { /* set by sphci_free_dev */
+			struct phci_device * dev = usb_to_phci (phci->dev[edINFO & 0x7F]);
+			td_free (phci, tdTailP); /* free dummy td */
+   	 		ed->hwINFO = OHCI_ED_SKIP; 
+   	 		ed->state = ED_NEW; 
+   	 		/* if all eds are removed wake up sphci_free_dev */
+			if (!--dev->ed_cnt) {
+				wait_queue_head_t *wait_head = dev->wait;
+
+				dev->wait = 0;
+				if (wait_head)
+					wake_up (wait_head);
+			}
+   	 	} else {
+			/* URB delete */
+   	 		ed->state &= ~ED_URB_DEL;
+			tdHeadP = (td_t*)((ed->hwHeadP) & 0xfffffff0);
+
+			/* If ed's td list is free un link it from the ed list */
+			if (tdHeadP == tdTailP) {
+				if (ed->state == ED_OPER)
+					ep_unlink(phci, ed);
+			} else
+   	 			ed->hwINFO &= ~(OHCI_ED_SKIP);
+			while(del_urb_cnt--){
+					dl_del_urb(phci,del_urb[del_urb_cnt]);
+			}
+   	 	}
+   	}
+   	
+	/* make the remove list to null */
+   	phci->ed_rm_list[frame] = NULL;
+} /* End of dl_del_list */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static td_t * dl_reverse_done_list (phci_t * phci, td_t *td_list)
+{
+	td_t * td_rev = NULL;
+  	urb_priv_t * urb_priv = NULL;
+  	
+	func_debug(("dl_reverse_done_list(phci = 0p%p,td_list = 0x%p)\n",phci,td_list))
+
+	/* Go through all the td list in the done queue */
+	while (td_list) {		
+
+		if(td_list->ed->type == PIPE_ISOCHRONOUS) {
+			td_list->ed->total_isoc_tds--;
+		}
+
+		if (TD_CC_GET (td_list->hwINFO)) {
+			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
+
+#ifdef __TRACE_LOW_LEVEL__
+			printk(" USB-error/status: %x : %p\n", TD_CC_GET (td_list->hwINFO), td_list);
+#endif /* __TRACE_LOW_LEVEL__ */
+
+			/* IF the ed halt bit is set, delete all the tds for that urb */
+			if (td_list->ed->hwHeadP & (0x1)) {
+
+				if((td_list->ed->type == PIPE_CONTROL) && ((TD_CC_GET (td_list->hwINFO)) == TD_DATAUNDERRUN) && 
+					((td_list->index > 0) && (td_list->index != (urb_priv->length-1)))) {
+					if (urb_priv) {
+#if 0 /* NSS Debug */
+						td_list->ed->hwHeadP = 
+							(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+										(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+#else
+						td_list->ed->hwHeadP =
+							(urb_priv->td[urb_priv->length - 1]->hwNextTD & 0xfffffff0) |
+										(td_list->ed->hwHeadP & 0x2);
+
+#endif
+						urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+					}
+				} else
+				if (urb_priv && ((td_list->index + 1) < urb_priv->length)) {
+#if 0 /* NSS Debug */
+					td_list->ed->hwHeadP = 
+						(urb_priv->td[urb_priv->length - 1]->hwNextTD & cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & cpu_to_le32 (0x2));
+#else
+					td_list->ed->hwHeadP =
+						(urb_priv->td[urb_priv->length - 1]->hwNextTD & 0xfffffff0) |
+									(td_list->ed->hwHeadP & 0x2);
+
+#endif
+					urb_priv->td_cnt += urb_priv->length - td_list->index - 1;
+				} else 
+#if 0 /* NSS Debug */
+					td_list->ed->hwHeadP &= cpu_to_le32 (0xfffffff2);
+#else
+					td_list->ed->hwHeadP &= 0xfffffff2;
+#endif
+			}
+
+		}
+
+		/* attach td to the reverse list */
+		td_list->next_dl_td = td_rev;	
+		td_rev = td_list;
+		td_list = (td_t*)((td_list->hwNextTD) & 0xfffffff0);	
+	}	
+	return td_rev;
+} /* End of dl_reverse_done_list */
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+
+static void dl_done_list (phci_t * phci, td_t * td_list) {
+  	td_t * td_list_next = NULL;
+	ed_t * ed;
+	int cc = 0;
+	struct urb * urb;
+	urb_priv_t * urb_priv;
+ 	__u32 tdINFO, edHeadP, edTailP;
+ 	
+	func_debug(("dl_done_list(phci = 0x%p,td_list = 0x%p)\n",phci,td_list))
+
+	/* Go through all the td's in the done queue */
+  	while (td_list) {
+   		td_list_next = td_list->next_dl_td;
+   		
+  		urb = td_list->urb;
+  		urb_priv = urb->hcpriv;
+  		tdINFO = td_list->hwINFO;
+  		
+   		ed = td_list->ed;
+
+		/* Get the trasnsfered length to the urb length field */
+   		dl_transfer_length(td_list);
+ 			
+  		/* error code of transfer */
+  		cc = TD_CC_GET (tdINFO);
+		/* If the error code is stall call endpoint stall for that device */
+  		if (cc == TD_CC_STALL)
+			usb_endpoint_halt(urb->dev,
+				usb_pipeendpoint(urb->pipe),
+				usb_pipeout(urb->pipe));
+  		
+		/* If it is data underrun case and disable spd that is not an error case */
+  		if (!(urb->transfer_flags & USB_DISABLE_SPD)
+				&& (cc == TD_DATAUNDERRUN))
+			cc = TD_CC_NOERROR;
+
+  		if (++(urb_priv->td_cnt) == urb_priv->length) {
+			/* IF all the td's of this urb are finished, 
+			call the corresponding call back function */
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (urb_priv->state != URB_DEL)) {
+  				urb->status = cc_to_error[cc];			/* Convert the cc to USB stack status */
+				sphci_return_urb(phci, urb);
+  			} else {
+				/* If the opetation state of ed is deleted or unlinked meanwhile, delete the urb */
+  				dl_del_urb (phci, urb);
+			}
+  		}
+  		
+  		if (ed->state != ED_NEW) { 
+  			edHeadP = (ed->hwHeadP) & 0xfffffff0;
+  			edTailP = ed->hwTailP;
+
+			/* unlink eds if they are not busy */
+   			if ((edHeadP == edTailP) && (ed->state == ED_OPER) && 
+				(ed->total_isoc_tds == 0)) ep_unlink (phci, ed);
+     	}	
+     	
+    	td_list = td_list_next;
+  	}  
+} /* End of dl_done_list */
+
+
+/* ROOT Hub Functions */
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub 
+ *-------------------------------------------------------------------------*/
+ 
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x10,	    /*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x00,       /*  __u8  bDeviceProtocol; */
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,       /*  __u16 idVendor; */
+	0x00,
+	0x00,       /*  __u16 idProduct; */
+ 	0x00,
+	0x00,       /*  __u16 bcdDevice; */
+ 	0x00,
+	0x00,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19,       /*  __u16 wTotalLength; */
+	0x00,
+	0x01,       /*  __u8  bNumInterfaces; */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* interface */	  
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* endpoint */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02,       /*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 	0x00,
+	0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare Interrupt pipe data; HUB INTERRUPT ENDPOINT */ 
+ 
+int rh_send_irq (phci_t * phci, void * rh_data, int rh_len) {
+	int num_ports;
+	int i;
+	int ret;
+	int len;
+	__u8 data[8];
+
+	__u32 data_read;
+
+	detail_debug(("rh_send_irq(phci = 0x%p,rh_data = 0x%p, rh_len = %d)\n",phci,rh_data, rh_len))
+
+	/* Get the number of root hub ports */
+	fnvPhciHcorRead(phci,uHcRhDescriptorA,&data_read);
+	num_ports = data_read & RH_A_NDP;
+
+	if (num_ports > MAX_ROOT_PORTS) {
+		printk("rereads as NDP=%d\n", data_read & RH_A_NDP);
+		/* retry later; "should not happen" */
+		return 0;
+	}
+
+	/* Read the root hub status */
+	fnvPhciHcorRead(phci,uHcRhStatus,&data_read);
+
+	*(__u8 *) data = (data_read & (RH_HS_LPSC | RH_HS_OCIC))
+		? 1: 0;
+	ret = *(__u8 *) data;
+
+	for ( i = 0; i < num_ports; i++) {
+		/* Read status of each port of the root hub and set 
+		the status bit accordingly */
+
+		fnvPhciHcorRead(phci,(uHcRhPort1Status+i),&data_read);
+#ifndef __FPGA__
+		data_read &= (~RH_PS_OCIC);
+#endif
+		*(__u8 *) (data + (i + 1) / 8) |= 
+			((data_read & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC))
+			    ? 1: 0) << ((i + 1) % 8);
+		ret += *(__u8 *) (data + (i + 1) / 8);
+	}
+	len = i/8 + 1;
+  
+	if (ret > 0) { 
+		/* If there is some change in the root hub status,
+		copy the status data to root hub data */
+		memcpy (rh_data, data, min_hcd (len, min_hcd (rh_len, sizeof(data))));
+		return len;
+	}
+	return 0;
+} /* End of rh_send_irq */
+
+/*-------------------------------------------------------------------------*/
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+ 
+static void rh_int_timer_do (unsigned long ptr) {
+	int len; 
+
+	struct urb * urb = (struct urb *) ptr;
+	phci_t * phci = urb->dev->bus->hcpriv;
+
+	detail_debug(("rh_int_timer_do(phci = 0x%p)\n",phci))
+
+	if (phci->disabled)
+		return;
+
+	/* ignore timers firing during PM suspend, etc */
+	if ((phci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER)
+		goto out;
+
+	if(phci->rh.send) { 
+		/* Check the root hub status change */
+		len = rh_send_irq (phci, urb->transfer_buffer, urb->transfer_buffer_length);
+		if (len > 0) {
+
+			/* If there is a status change, call the call back function */
+			urb->actual_length = len;
+
+#ifdef __PHCI_DEBUG_DETAIL__
+			phci_urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
+#endif /* __PHCI_DEBUG_DETAIL__ */
+
+			if (urb->complete)
+				urb->complete (urb);
+		}
+	}
+
+	/* restart the periodic timer for accessing the 
+	status next time */
+ out:
+	rh_init_int_timer (urb);
+} /* End of rh_int_timer_do */
+
+/*-------------------------------------------------------------------------*/
+
+/* Root Hub INTs are polled by this timer */
+
+static int rh_init_int_timer (struct urb * urb) {
+	phci_t * phci = urb->dev->bus->hcpriv;
+
+	detail_debug(("rh_init_int_timer(urb = 0x%p)\n",urb))
+
+	/* fill and start the root hub status change interrupt timer */
+	phci->rh.interval = urb->interval;
+	init_timer (&phci->rh.rh_int_timer);
+	phci->rh.rh_int_timer.function = rh_int_timer_do;
+	phci->rh.rh_int_timer.data = (unsigned long) urb;
+	phci->rh.rh_int_timer.expires = 
+			jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
+	add_timer (&phci->rh.rh_int_timer);
+	
+	return 0;
+} /* End of rh_init_int_timer */
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x) 				len = (x); break
+#define WR_RH_STAT(x) 		fnvPhciHcorWrite(phci,uHcRhStatus,x)
+#define WR_RH_PORTSTAT(x) 	fnvPhciHcorWrite(phci,(uHcRhPort1Status+wIndex-1),x)
+#define RD_RH_STAT			read_data
+#define RD_RH_PORTSTAT		read_data
+
+/* request to virtual root hub */
+
+static int rh_submit_urb (struct urb * urb) {
+	struct usb_device * usb_dev = urb->dev;
+	phci_t * phci = usb_dev->bus->hcpriv;
+	unsigned int pipe = urb->pipe;
+	struct usb_ctrlrequest * cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+	void * data = urb->transfer_buffer;
+	int leni = urb->transfer_buffer_length;
+	int len = 0;
+	int status = TD_CC_NOERROR;
+
+	 unsigned long flags;
+	
+	__u32 datab[4];
+	__u8  * data_buf = (__u8 *) datab;
+	
+ 	__u16 bmRType_bReq;
+	__u16 wValue; 
+	__u16 wIndex;
+	__u16 wLength;
+
+	__u32	read_data;
+
+	spin_lock_irqsave(&phci->phci_lock, flags);
+
+	if (usb_pipeint(pipe)) {
+		phci->rh.urb =  urb;
+		phci->rh.send = 1;
+		phci->rh.interval = urb->interval;
+		rh_init_int_timer(urb);
+		urb->status = cc_to_error [TD_CC_NOERROR];
+		
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->bRequestType | (cmd->bRequest << 8);
+	wValue        = le16_to_cpu (cmd->wValue);
+	wIndex        = le16_to_cpu (cmd->wIndex);
+	wLength       = le16_to_cpu (cmd->wLength);
+
+	dbg ("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq,
+		bmRType_bReq, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device, 
+	   RH_INTERFACE: interface, 
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here, 
+	   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+	*/
+  
+		case RH_GET_STATUS: 				 		/* Get root hub status */
+				*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+		case RH_GET_STATUS | RH_INTERFACE: 	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+		case RH_GET_STATUS | RH_ENDPOINT:	 		
+				*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);   
+		case RH_GET_STATUS | RH_CLASS: 				
+				fnvPhciHcorRead(phci,uHcRhStatus,&read_data);
+				*(__u32 *) data_buf = cpu_to_le32 (
+					RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+				OK (4);
+		case RH_GET_STATUS | RH_OTHER | RH_CLASS: 	
+				fnvPhciHcorRead(phci,(uHcRhPort1Status+wIndex-1),&read_data);
+				*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+
+		case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+			switch (wValue) {
+				case (RH_ENDPOINT_STALL): OK (0);
+			}
+			break;
+
+		case RH_CLEAR_FEATURE | RH_CLASS:
+			switch (wValue) {
+				case RH_C_HUB_LOCAL_POWER:
+					OK(0);
+				case (RH_C_HUB_OVER_CURRENT): 
+						WR_RH_STAT(RH_HS_OCIC); OK (0);
+			}
+			break;
+		
+		case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_ENABLE): 			
+						WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+				case (RH_C_PORT_CONNECTION):	
+						WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+				case (RH_C_PORT_ENABLE):		
+						WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+				case (RH_C_PORT_SUSPEND):		
+						WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+				case (RH_C_PORT_OVER_CURRENT):	
+						WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+				case (RH_C_PORT_RESET):			
+						WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); 
+			}
+			break;
+ 
+		case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+			switch (wValue) {
+				case (RH_PORT_SUSPEND):			
+						WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); 
+				case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+						fnvPhciHcorRead(phci,(uHcRhPort1Status+wIndex-1),&read_data);
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PRS);
+						OK (0);
+				case (RH_PORT_POWER):			
+						WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); 
+				case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+						fnvPhciHcorRead(phci,(uHcRhPort1Status+wIndex-1),&read_data);
+						if (RD_RH_PORTSTAT & RH_PS_CCS)
+						    WR_RH_PORTSTAT (RH_PS_PES );
+						OK (0);
+			}
+			break;
+
+		case RH_SET_ADDRESS: phci->rh.devnum = wValue; OK(0);
+
+		case RH_GET_DESCRIPTOR:						/* Get root hub descriptors */
+			switch ((wValue & 0xff00) >> 8) {
+				case (0x01): 						/* device descriptor */
+					len = min_hcd (leni, min_hcd (sizeof (root_hub_dev_des), wLength));
+					data_buf = root_hub_dev_des; OK(len);
+				case (0x02): 						/* configuration descriptor */
+					len = min_hcd (leni, min_hcd (sizeof (root_hub_config_des), wLength));
+					data_buf = root_hub_config_des; OK(len);
+				case (0x03): 						/* string descriptors */
+					len = usb_root_hub_string (wValue & 0xff,
+						(int)(long) phci, "PHCI",
+						data, wLength);
+					if (len > 0) {
+						data_buf = data;
+						OK (min_hcd (leni, len));
+					}
+					// else fallthrough
+				default: 
+					status = TD_CC_STALL;
+			}
+			break;
+		
+		case RH_GET_DESCRIPTOR | RH_CLASS:
+		    {
+			    __u32 temp;
+				
+				fnvPhciHcorRead(phci,uHcRhDescriptorA, &temp);
+#if 0 /* for Mapii2 (AE by paced data access) */
+			    data_buf [0] = 9;		// min length;
+			    data_buf [1] = 0x29;
+			    data_buf [2] = temp & RH_A_NDP;
+			    data_buf [3] = 0;
+			    if (temp & RH_A_PSM) 	/* per-port power switching? */
+				data_buf [3] |= 0x1;
+			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+				data_buf [3] |= 0x10;
+			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+				data_buf [3] |= 0x8;
+
+			    datab [1] = 0;
+			    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+				fnvPhciHcorRead(phci,uHcRhDescriptorB, &temp);
+			    data_buf [7] = temp & RH_B_DR;
+			    if (data_buf [2] < 7) {
+				data_buf [8] = 0xff;
+			    } else {
+				data_buf [0] += 2;
+				data_buf [8] = (temp & RH_B_DR) >> 8;
+				data_buf [10] = data_buf [9] = 0xff;
+			    }
+#else
+			    data_buf [0] = 9;		// min length;
+			    data_buf [1] = 0x29;
+			    data_buf [2] = temp & RH_A_NDP;
+			    data_buf [3] = 0;
+			    data_buf [4] = 0;
+			    if (temp & RH_A_PSM) 	/* per-port power switching? */
+				data_buf [4] |= 0x1;
+			    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+				data_buf [4] |= 0x10;
+			    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+				data_buf [4] |= 0x8;
+
+			    data_buf [6] = (temp & RH_A_POTPGT) >> 24;
+
+			    fnvPhciHcorRead(phci,uHcRhDescriptorB, &temp);
+
+			    data_buf [8] = temp & RH_B_DR;
+			    if (data_buf [2] < 7) {
+				data_buf [9] = 0xff;
+			    } else {
+				data_buf [0] += 2;
+				data_buf [9] = (temp & RH_B_DR) >> 8;
+				data_buf [11] = data_buf [10] = 0xff;
+			    }
+#endif				
+			    len = min_hcd (leni, min_hcd (data_buf [0], wLength));
+			    OK (len);
+			}
+ 
+		case RH_GET_CONFIGURATION: 	*(__u8 *) data_buf = 0x01; OK (1);
+
+		case RH_SET_CONFIGURATION: 	WR_RH_STAT (0x10000); OK (0);
+
+		default: 
+			dbg ("unsupported root hub command");
+			status = TD_CC_STALL;
+	}
+	
+	//	phci_dump_roothub (phci, 0);
+
+	len = min_hcd(len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+  	urb->actual_length = len;
+	urb->status = cc_to_error [status];
+	
+#ifdef __PHCI_DEBUG_DETAIL__
+	phci_urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+#endif /* __PHCI_DEBUG_DETAIL__ */
+
+	urb->hcpriv = NULL;
+	spin_unlock_irqrestore(&phci->phci_lock, flags);
+	usb_dec_dev_use (usb_dev);
+	urb->dev = NULL;
+	if (urb->complete)
+	    	urb->complete (urb);
+	return 0;
+} /* End of rh_submit_urb */
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_unlink_urb (struct urb * urb) {
+	phci_t * phci = urb->dev->bus->hcpriv;
+	unsigned int flags;
+ 
+	detail_debug(("rh_unlink_urb(urb = 0x%p)\n",urb))
+
+	/* If urb is root hub urb, delete periodic timer,
+	decrement device use, clear rest of the fields 
+	and call the callback function if present */
+	spin_lock_irqsave(&phci->phci_lock, flags);
+	if (phci->rh.urb == urb) {
+		phci->rh.send = 0;
+		del_timer (&phci->rh.rh_int_timer);
+		phci->rh.urb = NULL;
+
+		urb->hcpriv = NULL;
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		usb_dec_dev_use(urb->dev);
+		urb->dev = NULL;
+		if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+			urb->status = -ECONNRESET;
+			if (urb->complete)
+				urb->complete (urb);
+		} else
+			urb->status = -ENOENT;
+	} else {
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+	}
+	return 0;
+} /* End of rh_unlink_urb */
+ 
+
+/*------------------------------------------------------------------------*
+ * URB support functions
+ *------------------------------------------------------------------------*/
+
+static void phci_complete_add(struct phci *phci, struct urb *urb)
+{
+
+	if (urb->hcpriv != NULL) {
+		printk("completing with non-null priv!\n");
+		return;
+	}
+
+	if (phci->complete_tail == NULL) {
+		phci->complete_head = urb;
+		phci->complete_tail = urb;
+	} else {
+		phci->complete_head->hcpriv = urb;
+		phci->complete_tail = urb;
+	}
+}
+
+static inline struct urb *phci_complete_get(struct phci *phci)
+{
+	struct urb *urb;
+
+	if ((urb = phci->complete_head) == NULL)
+		return NULL;
+	if (urb == phci->complete_tail) {
+		phci->complete_tail = NULL;
+		phci->complete_head = NULL;
+	} else {
+		phci->complete_head = urb->hcpriv;
+	}
+	urb->hcpriv = NULL;
+	return urb;
+}
+
+static inline void phci_complete(struct phci *phci)
+{
+	struct urb *urb;
+
+	spin_lock(&phci->phci_lock);
+	while ((urb = phci_complete_get(phci)) != NULL) {
+		spin_unlock(&phci->phci_lock);
+		if (urb->dev) {
+			usb_dec_dev_use (urb->dev);
+			urb->dev = NULL;
+		}
+		if (urb->complete)
+			(*urb->complete)(urb);
+		spin_lock(&phci->phci_lock);
+	}
+	spin_unlock(&phci->phci_lock);
+}
+
+/* free HCD-private data asoociated with this URB */
+
+static void urb_free_priv( struct phci	*hc, urb_priv_t	*urb_priv) {
+	int i;
+	
+	func_debug(("urb_free_priv(hc = 0x%p,urb_priv = 0x%p)\n",hc, urb_priv))
+
+	/* Free all the transfer descriptors of the urb */
+	for(i=0; i< urb_priv->length; i++){
+		if(urb_priv->td[i]){
+			td_free(hc,urb_priv->td[i]);
+		}
+	}
+
+	kfree(urb_priv);
+} /* End of urb_free_priv */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static void urb_rm_priv_locked (struct urb	*urb) {
+	urb_priv_t	*urb_priv = urb->hcpriv;
+
+	func_debug(("urb_rm_priv_locked(urb = 0x%p)\n",urb))
+
+	if(urb_priv) {
+		urb->hcpriv = NULL;
+		/* Release int/iso bandwidth */
+		if(urb->bandwidth) {
+			switch(usb_pipetype(urb->pipe)) {
+				case PIPE_INTERRUPT:
+					usb_release_bandwidth(urb->dev, urb, 0 );
+					break;
+				case PIPE_ISOCHRONOUS:
+					usb_release_bandwidth(urb->dev, urb, 1);
+					break;
+				default:
+					break;
+			}
+		}
+			
+		/* free urb, hc data strucure elements */
+		urb_free_priv( (phci_t*)(urb->dev->bus), urb_priv);
+	} else {
+		if (urb->dev != NULL) {
+			err ("Non-null dev at rm_priv time");
+			// urb->dev = NULL;
+		}
+	}
+} /* End of urb_rm_priv_locked */
+
+/*-------------------------------------------------------------------------*/
+/* SOHCI functions */
+/*-------------------------------------------------------------------------*/
+static int sphci_alloc_dev (struct usb_device *usb_dev) {
+	struct phci_device * dev;
+	
+	func_debug(("sphci_alloc_dev(usb_dev = 0x%p)\n",usb_dev))
+
+	/* Allocate and initialize and set the 
+	device HC device data structure elements */
+	dev = dev_alloc (NULL);
+	
+	if(!dev)	return -ENOMEM;
+	
+	memset(dev, 0, sizeof *dev);
+
+	usb_dev->hcpriv = dev;
+
+	detail_debug(("allocated phci dev[0x%p]\n",dev))
+
+	return 0;
+} /* End of sphci_alloc_dev */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static int sphci_free_dev (struct usb_device *usb_dev) {
+	struct phci_device 	*dev = usb_to_phci (usb_dev);
+	unsigned long 	flags = 0;
+	ed_t			*ed;
+	int				i, cnt = 0;	
+	phci_t			*phci = usb_dev->bus->hcpriv;
+
+	func_debug(("sphci_free_dev(usb_dev = 0x%p)\n",usb_dev))
+
+	if(!dev)	return 0;
+	if(usb_dev->devnum >=0) {
+		/* driver disconnects should have unlinked all urbs
+		 * (freeing all the TDs, unlinking EDs) but we need
+		 * to defend against bugs that prevent that.
+		 */
+		spin_lock_irqsave(&phci->phci_lock, flags);
+		for(i=0; i< NUM_EDS; i++) {					/* Go through all the ed's */
+			ed = &(dev->ed[i]);
+
+			if(ed->state != ED_NEW) {
+				if(ed->state == ED_OPER) {
+					/* driver on that interface didn't unlink an ed */
+					printk("un freed urb: 0x%p\n", ed);
+					ep_unlink( phci, ed);			/* Unlink the ed if it is operational */
+				}
+				ep_rm_ed (usb_dev, ed);				/* delete the ed */
+				ed->state = ED_DEL;
+				cnt++;
+			}	
+		}
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+
+		/* if the controller is running, tds for those unlinked
+         * urbs get freed by dl_del_list at the next SF interrupt
+         */
+
+		if(cnt > 0) {
+			
+			if(phci->disabled) {
+				/* FIXME: Something like this should kick in,
+                 * though it's currently an exotic case ...
+                 * the controller won't ever be touching
+                 * these lists again!!
+                dl_del_list (phci,
+                    le16_to_cpu (phci->hcca.frame_no) & 1);
+                 */
+				printk("TD Leak, %d\n", cnt);
+			} else if( !in_interrupt()) {
+				DECLARE_WAIT_QUEUE_HEAD(freedev_wakeup);
+				DECLARE_WAITQUEUE(wait, current);
+				int timeout = PHCI_UNLINK_TIMEOUT ;
+		
+				/* SF interrupt handler calls dl_del_list */
+				add_wait_queue(&freedev_wakeup, &wait);
+				dev->wait = &freedev_wakeup;
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				while(timeout && dev->ed_cnt)
+					timeout = schedule_timeout(timeout);
+				current->state = TASK_RUNNING;
+				remove_wait_queue(&freedev_wakeup, &wait);
+				if(dev->ed_cnt) {
+					printk("free device %d timeout\n", usb_dev->devnum);
+					return -ETIMEDOUT;
+				}
+			} else {
+				/* likely some interface's driver has a refcount bug */
+				printk("dev num %d deletion in interrupt\n", usb_dev->devnum);
+				BUG();
+			}
+		}
+	}
+
+	/* free device, and associated EDs */
+
+	dev_free(dev);
+	
+	return 0;
+} /* End of sphci_free_dev */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static int sphci_get_current_frame_number (struct usb_device *usb_dev) {
+	__u32 		frame_number;
+	phci_t		*phci = (phci_t*)(usb_dev->bus->hcpriv);
+
+	func_debug(("sphci_get_current_frame_number(usb_dev = 0x%p)\n",usb_dev))
+
+	/* Get the current frame number from the HC register */
+	fnvPhciHcorRead(phci,uHcFmNumber,&frame_number);
+
+
+	detail_debug(("current frame number[0x%x]\n",frame_number))
+	
+	return frame_number;
+} /* End of sphci_get_current_frame_number */
+
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* return a request to the completion handler */
+ 
+static int sphci_return_urb (struct phci *hc, struct urb * urb) {
+	urb_priv_t * urb_priv = urb->hcpriv;
+	struct urb * urbt;
+	int i;
+
+	func_debug(("sphci_return_urb(urb = 0x%p)\n",urb))
+	
+	if (!urb_priv)
+		return -1; /* urb already unlinked */
+
+	/* just to be sure */
+	if (!urb->complete) {
+		urb_rm_priv_locked (urb);
+		phci_complete_add(hc, urb);     /* Just usb_dec_dev_use */
+		return -1;
+	}
+	
+#ifdef __PHCI_DEBUG_DETAIL__
+	phci_urb_print (urb, "RET", usb_pipeout (urb->pipe));
+#endif /* __PHCI_DEBUG_DETAIL__ */
+
+	switch (usb_pipetype (urb->pipe)) {
+  		case PIPE_INTERRUPT:
+
+			urb->complete (urb); /* call complete and requeue URB */	
+			if (urb->interval) {
+				urb->complete (urb);
+ 
+				/* implicitly requeued */
+				urb->actual_length = 0;
+				urb->status = -EINPROGRESS;
+				td_submit_urb (urb);
+			} else {
+				urb_rm_priv_locked (urb);
+				phci_complete_add(hc, urb);
+			}
+			break;
+  			
+		case PIPE_ISOCHRONOUS:
+#if 1
+			for (urbt = urb->next; urbt && (urbt != urb); urbt = urbt->next);
+			if (urbt) { /* send the reply and requeue URB */	
+				urb->complete (urb);
+				
+				urb->actual_length = 0;
+  				urb->status = USB_ST_URB_PENDING;
+  				urb->start_frame = urb_priv->ed->last_iso + 1;
+  				if (urb_priv->state != URB_DEL) {
+  					for (i = 0; i < urb->number_of_packets; i++) {
+  						urb->iso_frame_desc[i].actual_length = 0;
+  						urb->iso_frame_desc[i].status = -EXDEV;
+  					}
+  					td_submit_urb (urb);
+  				}
+  				
+  			} else { /* unlink URB, call complete */
+				urb_rm_priv_locked (urb);
+				phci_complete_add(hc, urb);
+			}		
+#endif
+			break;
+  				
+		case PIPE_BULK:
+		case PIPE_CONTROL: /* unlink URB, call complete */
+			urb_rm_priv_locked (urb);
+			phci_complete_add(hc, urb);
+			break;
+	}
+	return 0;
+} /* End of sphci_return_urb */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static int sphci_submit_urb (struct urb	*urb) {
+	phci_t			*phci;
+	unsigned int	pipe = urb->pipe;
+	ed_t			*ed;
+	int				i, size = 0,actual_length;
+	urb_priv_t		*urb_priv;
+	__u32			data_read = 0;
+	int				bustime = 0;
+	unsigned long	flags = 0;
+    int maxps = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	int	result = 0;
+
+	
+	if(!urb->dev || !urb->dev->bus) return -ENODEV;	
+
+	if(urb->hcpriv)		return -EINVAL;
+
+	usb_inc_dev_use(urb->dev);
+	
+	phci = (phci_t *)(urb->dev->bus->hcpriv);
+
+	if(usb_pipedevice(pipe) == phci->rh.devnum)
+		return rh_submit_urb(urb);
+
+	spin_lock_irqsave(&phci->phci_lock, flags);
+
+	/* when controller's hung, permit only roothub cleanup attempts
+     * such as powering down ports */
+	if(phci->disabled) {
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		usb_dec_dev_use (urb->dev);
+		return -ESHUTDOWN;
+	}
+
+
+	/* every endpoint has a ed, locate and fill it */
+	if(!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		usb_dec_dev_use(urb->dev);
+		return -ENOMEM;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch(usb_pipetype(pipe)) {
+		case PIPE_BULK:
+
+			/* one TD for every MAX_BULK_TD_BUFF_SIZE Byte */
+
+			size = (urb->transfer_buffer_length -1)/MAX_BULK_TD_BUFF_SIZE +1;
+                        /* If the transfer size is multiple of the pipe mtu,
+                         * we may need an extra TD to create a empty frame */
+			if ((urb->transfer_flags & USB_ZERO_PACKET) && usb_pipeout (pipe) && 
+				(urb->transfer_buffer_length != 0) && ((urb->transfer_buffer_length % maxps) == 0))
+                                size++;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = urb->number_of_packets;
+			if(size <= 0) {
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+				usb_dec_dev_use(urb->dev);
+				return -EINVAL;
+			}
+			for(i=0; i< urb->number_of_packets; i++) {
+				urb->iso_frame_desc[i].actual_length = 0;
+				urb->iso_frame_desc[i].status = -EXDEV;
+			}
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every MAX_CNTL_TD_BUFF_SIZE B */
+			size = (urb->transfer_buffer_length == 0) ? 2 :
+						((urb->transfer_buffer_length -1)/MAX_CNTL_TD_BUFF_SIZE + 3) ;
+			break;
+		case PIPE_INTERRUPT: /* one TD */
+			size = 1;
+			break;
+	}
+
+	/* allocate the private part of the URB */
+	urb_priv = kmalloc((sizeof(urb_priv_t) + size * sizeof(td_t*)),GFP_ATOMIC);
+	if(!urb_priv) {
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		usb_dec_dev_use(urb->dev);
+		return -ENOMEM;
+	}
+	memset(urb_priv, 0, (sizeof(urb_priv_t) + size * sizeof(td_t*)));
+
+	/* fill the private part of the URB */
+	urb_priv->length = size;
+	urb_priv->ed = ed;
+
+	/* allocate the TDs */
+	for(i=0; i < size; i++) {
+		urb_priv->td[i] = td_alloc(phci);
+		if(!urb_priv->td[i]) {
+			urb_free_priv(phci, urb_priv);
+			spin_unlock_irqrestore(&phci->phci_lock, flags);
+			usb_dec_dev_use( urb->dev);
+			return -ENOMEM;
+		}	
+	}
+
+	if(ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv(phci, urb_priv);
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+		usb_dec_dev_use(urb->dev);
+		return -EINVAL;
+	}
+
+	/* allocate and claim bandwidth if needed; ISO
+	 * needs start frame index if it was't provided.
+     */
+	switch(usb_pipetype(pipe)) {
+		case PIPE_ISOCHRONOUS:
+			if(urb->transfer_flags & USB_ISO_ASAP) {
+
+			/*-----------------------------------------------------------------
+			Assuming::	If transfer started ed will be operational state, 
+						else if is ISOC transfer is going on::
+								this is a second or third ..... ISOC ed. So schedule it as early as possible
+								in the next toggle rate.
+							else this is starting of an ISOC transfer for first ed
+								schedule it as early as possible
+						*						*						*
+						|						|						|
+						|						|						|
+						|		|				|	|					|	...........
+						SOF		request			SOF	isoc				SOF	isoc transfer on bus
+								sof(on)				scheduling
+											
+						start_fn = 			fn +			1 			+	1
+			-----------------------------------------------------------------*/	
+															 
+				fnvPhciHcorRead(phci, uHcFmNumber, &data_read);
+				if(ed->state == ED_OPER) {								/* Already ISO pipe is running */
+					urb->start_frame = ed->last_iso + 1;
+				} else if(phci->hcd_operational_flags & ISOC_TRANSFER_ON) {
+					if( td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].frame_number > td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1].frame_number) {
+																		/* Schedule for ISTL0 buffer */
+						urb->start_frame = td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1].frame_number;
+					} else {
+																		/* Schedule for ISTL1 buffer */
+						urb->start_frame = td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].frame_number;
+					}
+				} else {												/* start ISOC transfer */
+					phci->hcd_operational_flags |= (ISOC_TRANSFER_ON | ISOC_SCHED_TO_START);
+					phci->hcd_operational_flags |= (ISOC_ISTL0_SCHED_TO_START |ISOC_ISTL1_SCHED_TO_START);
+#if 0 /* NSS Debug */
+					urb->start_frame = (data_read + 3) & 0xFFFF;		/* at Next sof scheduling will start for Next to Next frame */
+#else
+					urb->start_frame = (data_read + 20) & 0xFFFF;		/* at Next sof scheduling will start for Next to Next frame */
+#endif
+					td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].frame_number = urb->start_frame;
+
+					actual_length = 0;
+					for(i=0;i<urb->number_of_packets;i++) actual_length += urb->iso_frame_desc[i].length + HC_PTD_HEADER_SIZE;
+
+					if(actual_length < HC_ISTL_BUFFER_LENGTH) {
+						td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].regs.toggle_rate = HC_ISTL_DEF_TOGGLE_RATE;
+					}else {
+#if 0 /* NSS Debug */
+						td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].regs.toggle_rate = 1;
+#else
+						td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].regs.toggle_rate = HC_ISTL_DEF_TOGGLE_RATE;
+#endif
+						phci->hcd_operational_flags |= ISOC_ISTL0_ISTL1_TO_START;
+					}
+//					printk("toggle rate = %x %x start_frame 0= %x start_frame1 = %x\n",td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].regs.toggle_rate, data_read, td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL0].frame_number, td_ptd_map_buff[TD_PTD_BUFF_TYPE_ISTL1].frame_number);
+				}
+
+			}
+			/* FALL THROUGH */
+		case PIPE_INTERRUPT:
+			if(urb->bandwidth == 0) {
+				bustime = usb_check_bandwidth(urb->dev,urb);
+			}
+			if(bustime < 0 ) {
+				urb_free_priv(phci,urb_priv);
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+				usb_dec_dev_use(urb->dev);
+				return bustime;
+			}
+			usb_claim_bandwidth(urb->dev, urb, bustime,usb_pipeisoc(urb->pipe));
+		break;
+	}
+
+	urb->actual_length = 0;
+	urb->hcpriv = urb_priv;
+	urb->status = USB_ST_URB_PENDING;
+
+	/* link the ed into a chain if is not already */
+
+	if( ed->state != ED_OPER)
+		result = ep_link (phci, ed);
+
+	if(result == 0 ) {
+		/* fill the TDs and link it to the ed */
+		td_submit_urb(urb);
+
+		phci_submit_ed( phci, urb_priv->ed ) ;		/* Submit the ed for ptd scheduling to HC */
+	} else {
+		urb_free_priv(phci, urb_priv);
+		usb_dec_dev_use(urb->dev);
+		urb->status = result;
+	}
+
+	spin_unlock_irqrestore(&phci->phci_lock, flags);
+
+	return result;
+} /* End of sphci_submit_urb */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static int sphci_unlink_urb (struct urb	*urb) {
+
+	phci_t	*phci;
+	unsigned long flags = 0;
+
+	func_debug(("sphci_unlink_urb(urb = 0x%p)\n",urb))
+
+	if(!urb)	return -EINVAL;
+
+	if(!urb->dev || !urb->dev->bus)	return -ENODEV;
+
+	phci = (phci_t *)(urb->dev->bus->hcpriv);
+
+	if(usb_pipedevice(urb->pipe) == phci->rh.devnum)
+		return rh_unlink_urb (urb);
+
+	spin_lock_irqsave(&phci->phci_lock, flags);
+	if(urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) {
+		if(!phci->disabled) {
+			urb_priv_t	*urb_priv;
+			
+			/* interrupt code may not sleep; it must use
+             * async status return to unlink pending urbs.
+             */
+			if(!(urb->transfer_flags & USB_ASYNC_UNLINK) 
+				&& in_interrupt()) {
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+				printk("bug in call to sphci_unlink_urb(); use async\n");
+				
+				return -EWOULDBLOCK;
+			}
+			/* flag the urb and its TDs for deletion in some
+             * upcoming SF interrupt delete list processing
+             */
+			urb_priv = urb->hcpriv;
+			
+			if(!urb_priv || (urb_priv->state == URB_DEL)) {
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+				return 0;
+			}
+			urb_priv->state = URB_DEL;
+			ep_rm_ed(urb->dev, urb_priv->ed);
+			urb_priv->ed->state |= ED_URB_DEL;
+			
+			if(!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+				DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup);
+				DECLARE_WAITQUEUE(wait, current);
+				int timeout = PHCI_UNLINK_TIMEOUT;
+	
+				add_wait_queue(&unlink_wakeup, &wait);
+				urb_priv->wait = &unlink_wakeup;
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+			
+				/* wait until all TDs are deleted */
+				set_current_state(TASK_UNINTERRUPTIBLE);
+//				while( timeout && (urb->status == USB_ST_URB_PENDING))
+				while( timeout ) {
+					timeout = schedule_timeout(timeout);
+					set_current_state(TASK_UNINTERRUPTIBLE);
+				}
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&unlink_wakeup, &wait);
+				if(urb->status == USB_ST_URB_PENDING) {
+					printk("unlink URB timeout\n");
+					return -ETIMEDOUT;
+				}
+
+				usb_dec_dev_use (urb->dev);
+				urb->dev = NULL;
+				if (urb->complete)
+					urb->complete (urb); 
+			} else {
+				/* usb_dec_dev_use done in dl_del_list() */
+				urb->status = -EINPROGRESS;
+				spin_unlock_irqrestore(&phci->phci_lock, flags);
+			}
+		} else {	
+			urb_rm_priv_locked (urb);
+			spin_unlock_irqrestore(&phci->phci_lock, flags);
+			usb_dec_dev_use (urb->dev);
+			urb->dev = NULL;
+			if(urb->transfer_flags & USB_ASYNC_UNLINK) {
+				urb->status = -ECONNRESET;
+				if(urb->complete)	
+					urb->complete(urb);
+			} else 
+				urb->status = -ENOENT;		
+		}
+	} else {
+		spin_unlock_irqrestore(&phci->phci_lock, flags);
+	}
+	return 0;
+} /* End of sphci_unlink_urb */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+void hc_release_phci (phci_t * phci) {
+
+	if( phci->bus->root_hub)	usb_disconnect(&phci->bus->root_hub);
+	
+	func_debug(("hc_release_phci(phci = 0x%p)\n",phci))
+	
+	phci_reg_write16(REG_BUFF_STS,0);		/* Do not process any buffers (ATL/INTL/ISTL) */
+
+	if(phci->disabled)
+		fnvPhciHostReset(phci);
+
+	((struct isp1362_dev*)phci->phci_dev)->driver_data = 0;
+
+	if(phci->bus) {
+		if(phci->bus->busnum != 1) usb_deregister_bus(phci->bus);		/* Deregister hc from bus stack */ 
+		usb_free_bus (phci->bus);			/* Free the data structure */
+	}
+
+#ifdef CONFIG_USB_PHCD_DMA
+	if(phci->dma_buff)		kfree(phci->dma_buff);
+#endif /* CONFIG_USB_PHCD_DMA */
+
+	kfree(phci);						/* Free phci data structure */
+
+	detail_debug(("freed phci[0x%p] data structure\n",phci))
+
+} /* End of hc_release_phci */
+
+struct usb_operations sphci_device_operations = {
+		sphci_alloc_dev,
+		sphci_free_dev,
+		sphci_get_current_frame_number,
+		sphci_submit_urb,
+		sphci_unlink_urb
+};
+
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+static phci_t * __devinit hc_alloc_phci (struct isp1362_dev *dev) {
+
+	phci_t			*phci;
+	struct usb_bus	*bus;
+
+	func_debug(("hc_alloc_phci(dev = 0x%p)\n",dev))
+
+	phci = (phci_t *) kmalloc( sizeof *phci, GFP_KERNEL );
+
+	if(!phci)	return NULL;
+
+	memset(phci,0,sizeof(phci_t));
+
+	phci->disabled = 1;				/* Set phci to disabled */
+	
+	phci->irq = dev->irq;		/* set the irq number */
+
+	dev->driver_data = phci;
+	phci->phci_dev = (void*)dev;
+
+	spin_lock_init(&phci->phci_lock);
+	
+	bus = usb_alloc_bus(&sphci_device_operations);	/* Allocate usb bus (PHC) in the bus stack */
+	if(!bus) {
+		kfree(phci);
+		return NULL;
+	}
+	
+#ifdef CONFIG_USB_HCDC_OTG
+	bus->otg.otg_capable = 1;
+	bus->otg.otg_port = OTG_HC_PORT_NO;
+#endif /* CONFIG_USB_HCDC_OTG */
+
+	phci->bus = bus;
+	//	bus->bus_name = dev->slot_name;
+	bus->hcpriv = (void *)phci;
+
+	detail_debug(("usb bus[0x%p] allocated\n",bus))
+
+	return phci;
+} /* End of hc_alloc_phci */
+
+/*-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+int __devinit hc_found_phci (struct isp1362_dev *dev) {
+	phci_t	*phci;
+	__u32	data_read;
+
+	func_debug(("hc_found_phci(void)\n"))
+
+	phci = hc_alloc_phci(dev);		/* allocate hc data */
+
+	if(!phci) {
+		return -ENOMEM;
+	}
+
+#ifdef CONFIG_USB_PHCD_DMA 
+	phci->dma_buff = kmalloc(TD_PTD_MAX_BUFF_SIZE, (GFP_ATOMIC|GFP_DMA));
+
+	if(!phci->dma_buff) {
+			hc_release_phci(phci);
+			return -ENOMEM;
+	}
+#endif /* CONFIG_USB_PHCD_DMA */
+		
+	/* Reset Philips host controller */
+   	if(fnvPhciHostReset(phci) != 0 ){
+		hc_release_phci(phci);
+		return -EBUSY;
+	}
+
+	usb_register_bus(phci->bus);		/* Register Philips HC to the bus stack */
+
+
+	/* set phci state to reset */
+	phci->hc_control = OHCI_USB_RESET;
+
+   	phci->irq = dev->irq;
+   	if(fnuPhciHostInit(phci) != 0) {		/* Initialize Philips hc */
+		hc_release_phci(phci);
+		return -ENOMEM;
+	}
+
+	phci_reg_read16(REG_IRQ, &data_read);
+	phci_reg_write16(REG_IRQ, data_read);
+
+	return 0;
+} /* End of hc_found_phci */
+
+
+#ifdef CONFIG_USB_HCDC_OTG
+
+int		phci_register_otg(phci_otg_data_t	*otg_data){
+	phci_t	*phci = (phci_t*)(isp1362_device->driver_data);
+	__u32	data_read;
+
+	func_debug(("phci_register_otg(otg_data = 0x%p)\n",otg_data))
+
+	if(phci && otg_data && otg_data->priv_data) {
+		phci->otg = otg_data;
+		otg_data->hc_priv_data = (void*)phci;
+
+		/* Enable OTG interrupt */
+		if(otg_data->otg_notif) {
+			phci->bus->otg.otg_notif = otg_data->otg_notif;
+			phci->bus->otg.otg_priv = otg_data->priv_data;
+		}
+
+		phci_reg_read16(REG_IRQ_MASK, &data_read);
+		data_read |= OTG_INT;			/* Enable OTG  Interrupt */
+		phci_reg_write16(REG_IRQ_MASK, data_read);
+	
+		detail_debug(("otg registration success REG_IRQ_MASK[0x%x]\n",data_read))
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+void	phci_unregister_otg(phci_otg_data_t	*otg_data){
+	phci_t	*phci = (phci_t*)(otg_data->hc_priv_data);
+	__u32	data_read;
+
+	func_debug(("phci_unregister_otg(otg_data = 0x%p)\n",otg_data))
+
+	if(phci && phci->otg == otg_data) {
+		otg_data->hc_priv_data = NULL;
+
+		/* Disable OTG_Interrupt */
+
+		phci_reg_read16(REG_IRQ_MASK, &data_read);
+		data_read &= (~OTG_INT);							
+		phci_reg_write16(REG_IRQ_MASK, data_read);
+		
+		detail_debug(("Cleared OTG Interrupt: REG_IRQ_MASK(0x%x)\n",data_read))
+
+		phci->otg = NULL;
+	}
+
+}
+
+/*----------------------------------------------*/
+/* Control the OTG port operations				*/
+/* ---------------------------------------------*/
+void	phci_otg_port_control(void *priv, __u8	cmd, __u32 *data){
+
+	phci_t	*phci = (phci_t*)priv;
+	__u32	data_read;
+	struct urb	*urb;
+	int		len;
+
+	func_debug(("phci_otg_port_control(priv = 0x%p, cmd = %d, data = 0x%p)\n",priv, cmd, data))
+
+	switch(cmd) {
+		case OTG_PORT_OPEN_PORT:		/* Open OTG port for hub */
+			// This will be called when the OTG fsm goes to A_IDLE
+			// and B_IDLE states, this opens the port for status changes
+			// and starts enumeration process.
+			
+			fnvPhciHcorRead(phci,(uHcRhPort1Status+OTG_HC_PORT_NO),&data_read);
+			detail_debug(("OTG Port status before  = %x opened\n",data_read))
+
+			phci->otg_port_status = (RH_PS_CCS|RH_PS_CSC);
+
+			phci->bus->otg.otg_flags &= ~(0x3);
+			phci->bus->otg.otg_flags |= (*data& 0x03);
+
+			fnvPhciHcorRead(phci,(uHcRhPort1Status+OTG_HC_PORT_NO),&data_read);
+			
+			detail_debug(("OTG Port status = %x opened\n",data_read))
+
+			break;
+
+		case OTG_PORT_OPEN_PORT_IMM:	/* Open OTG port for hub */
+			// This will be called when the OTG fsm goes to A_IDLE
+			// and B_IDLE states, this opens the port for status changes
+			// and starts enumeration process.
+			
+			fnvPhciHcorRead(phci,(uHcRhPort1Status+OTG_HC_PORT_NO),&data_read);
+			
+			phci->otg_port_status = (RH_PS_CCS|RH_PS_CSC);
+
+			phci->bus->otg.otg_flags &= ~(0x3);
+			phci->bus->otg.otg_flags |= (*data& 0x03);
+
+			urb = phci->rh.urb;
+			if (phci->disabled || 
+				((phci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER))
+				return;
+
+			if(phci->rh.send) { 
+				/* Check the root hub status change */
+				len = rh_send_irq (phci, urb->transfer_buffer, urb->transfer_buffer_length);
+				if (len > 0) {
+
+					/* If there is a status change, call the call back function */
+					urb->actual_length = len;
+
+					if (urb->complete)
+						urb->complete (urb);
+				}
+			}
+
+			break;
+
+		case OTG_PORT_DISCONNECT_PORT:
+			phci->otg_port_status = (RH_PS_CSC & (~RH_PS_CCS));
+
+			break;
+
+
+		case OTG_PORT_GET_ENUM:
+			// This will be called when OTG module gets notificaion from 
+			// USB, and PHCI gives the results of enumeration
+			
+			*data = phci->bus->otg.otg_flags & 0x3F;
+
+			break;
+
+		case OTG_PORT_SUSPEND:
+			
+
+			fnvPhciHcorRead(phci,uHcFmNumber, &data_read);
+			detail_debug(("Suspending at fn = %x\n",data_read))
+
+			fnvPhciHcorWrite(phci,(uHcRhPort1Status+OTG_HC_PORT_NO),RH_PS_PSS);
+			
+			fnvPhciHcorRead(phci,(uHcRhPort1Status+OTG_HC_PORT_NO),&data_read);
+
+			detail_debug(("OTG PORT STATUS = %x\n",data_read))
+
+			break;
+	}
+}
+
+#endif /* CONFIG_USB_HCDC_OTG */
+
+static int phci_probe (struct isp1362_dev	*dev) 
+{
+	int ret;
+	phci_t	*phci;
+
+	if(!dev) return -1;
+
+	isp1362_device = dev;
+
+	isp1362_request_io_region(dev);		/* request IO space */
+
+	ret = hc_found_phci (dev);
+	if(ret < 0) {
+		isp1362_release_io_region(dev);	/* release IO space */
+		return ret;
+	}
+	
+	phci = (phci_t*)(dev->driver_data);
+
+   	ret = isp1362_request_irq(phci_isr,dev,phci);
+
+	if(ret!=0) {
+		detail_debug(("isp1362_request_irq(%p,%p,%p) call failed\n",phci_isr, dev, phci))
+		hc_release_phci(phci);
+		isp1362_release_io_region(dev);	/* release IO space */
+		return ret;
+	}
+
+
+#ifdef CONFIG_USB_PHCD_DMA
+	phci->dma = DMA4HC_CHNNL;
+	ret = request_dma(phci->dma,phci_driver_name);
+	if(ret != 0) {
+		detail_debug(("request_dma(%d, %s) call failed\n",phci->dma, dev.name));
+		isp1362_free_irq(dev,phci);
+		hc_release_phci(phci);
+		isp1362_release_io_region(dev);	/* release IO space */
+		return ret;
+	}
+#endif /* CONFIG_USB_PHCD_DMA */
+
+	return ret;
+}
+
+static void phci_remove (struct isp1362_dev	*dev) 
+{
+	__u32		reg_data;
+	phci_t		*phci = (phci_t *)dev->driver_data;
+
+	func_debug(("phci_pci_remove(%p)\n",dev))
+
+	fnvPhciHcorRead(phci,uHcControl, &reg_data);
+#if 0
+	dbg ("remove %d controller usb-%d%s%s",
+		(reg_data & OHCI_CTRL_HCFS),
+		dev->index,
+		phci->disabled ? " (disabled)" : "",
+		in_interrupt () ? " in interrupt" : ""
+		);
+#endif
+
+	
+
+	/* don't wake up sleeping controllers, or block in interrupt context */
+	if ((reg_data & OHCI_CTRL_HCFS) != OHCI_USB_OPER || in_interrupt ()) {
+		dbg ("controller being disabled");
+		phci->disabled = 1;
+	}
+
+	/* on return, USB will always be reset (if present) */
+	if (phci->disabled)
+		fnvPhciHcorWrite(phci, uHcControl, OHCI_USB_RESET);
+
+	hc_release_phci (phci);
+
+#ifdef CONFIG_USB_PHCD_DMA
+	free_dma(DMA4HC_CHNNL);
+#endif /* CONFIG_USB_PHCD_DMA */
+
+	isp1362_free_irq(dev,phci);	/* Free interrupt line */
+	isp1362_release_io_region(dev);
+}
+
+#ifdef CONFIG_PM
+static void phci_suspend (struct isp1362_dev	*dev) 
+{
+	__u32		reg_data;
+	phci_t		*phci = (phci_t*)dev->driver_data;
+
+
+	fnvPhciHcorRead(phci,uHcControl, &reg_data);
+
+	if ((reg_data & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+		dbg ("can't suspend usb-%d (state is %d)", dev->index,
+			(reg_data & OHCI_CTRL_HCFS));
+		return;
+	}
+
+	/* act as if usb suspend can always be used */
+	detail_debug(("USB suspend: usb-%d", dev->index))
+#ifdef CONFIG_PMAC_PBOOK
+	disable_irq (phci->irq);
+	/* else, 2.4 assumes shared irqs -- don't disable */
+#endif
+	fnvPhciHcorWrite(phci,uHcControl, OHCI_USB_SUSPEND);
+	mdelay (10);
+}
+
+static void phci_resume (struct isp1362_dev	*dev) 
+{
+	phci_t		*phci = (phci_t *)dev->driver_data;
+	int		temp;
+	__u32		reg_data;
+
+	func_debug(("isp1362_pci_resume(%p)\n",dev))
+
+	/* guard against multiple resumes */
+	atomic_inc (&phci->resume_count);
+	if (atomic_read (&phci->resume_count) != 1) {
+		detail_debug(("concurrent PCI resumes for usb-%d", dev->index))
+		atomic_dec (&phci->resume_count);
+		return;
+	}
+
+	/* did we suspend, or were we powered off? */
+	fnvPhciHcorRead(phci,uHcControl, &reg_data);
+	temp = reg_data & OHCI_CTRL_HCFS;
+
+
+	switch (temp) {
+
+	case OHCI_USB_RESET:	// lost power
+		detail_debug(("USB restart: usb-%d", dev->index))
+		/* TODO
+		hc_restart (phci); */
+		break;
+
+	case OHCI_USB_SUSPEND:	// host wakeup
+	case OHCI_USB_RESUME:	// remote wakeup
+		detail_debug(("USB continue: usb-%d from %s wakeup", dev->index,
+			(temp == OHCI_USB_SUSPEND)
+				? "host" : "remote"))
+		fnvPhciHcorWrite(phci,uHcControl, OHCI_USB_RESUME);
+		mdelay (20);
+
+		fnvPhciHcorRead(phci,uHcControl, &reg_data);
+		temp = reg_data & OHCI_CTRL_HCFS;
+		if (temp != OHCI_USB_RESUME) {
+			detail_debug(("controller usb-%d won't resume", dev->index))
+			phci->disabled = 1;
+			return;
+		}
+
+		phci->disabled = 0;
+#if 0
+		if (!phci->ed_rm_list[0] & !phci->ed_rm_list[1]) {
+			if (phci->ed_controltail)
+				phci->hc_control |= OHCI_CTRL_CLE;
+			if (phci->ed_bulktail)
+				phci->hc_control |= OHCI_CTRL_BLE;
+		}
+		writel (phci->hc_control, &phci->regs->control);
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+		enable_irq (phci->irq);
+#endif
+		break;
+
+	default:
+		detail_debug(("odd PCI resume for usb-%d", dev->index))
+	}
+
+	/* controller is operational, extra resumes are harmless */
+	atomic_dec (&phci->resume_count);
+}
+#endif /* CONFIG_PM */
+
+struct isp1362_driver	phci_driver = {
+	name:		"usb-phci",
+	index:		ISP1362_HC,
+	probe:		phci_probe,
+	remove:		phci_remove,
+#ifdef CONFIG_PM
+	suspend:	phci_suspend,
+	resume:		phci_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init phci_module_init (void) 
+{
+	int	result;
+
+	result = ohci_1161_mem_init();
+
+	if(result == 0) {
+		result = isp1362_register_driver(&phci_driver);
+	}
+
+	return result;
+}
+
+static void __exit phci_module_cleanup (void) 
+{
+	
+	isp1362_unregister_driver(&phci_driver);
+
+	return ohci_1161_mem_cleanup();
+}
+
+module_init (phci_module_init);
+module_exit (phci_module_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/drivers/usb/host/usb_phci.h linux-2.4.26/drivers/usb/host/usb_phci.h
--- linux-2.4.26.org/drivers/usb/host/usb_phci.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/drivers/usb/host/usb_phci.h	2004-04-28 11:27:11.000000000 +0900
@@ -0,0 +1,1013 @@
+/************************************************************************
+ * Philips ISP1362 Host Controller Driver
+ *
+ * Copyright  2002	Philips Semiconductors,
+ *	All rights are reserved.  Reproduction in whole or
+ *	part is prohibited without the prior written consent of
+ *	the copyright owner.
+ *
+ * File Name:	usb_phci.h
+ *
+ * History:	
+ *
+ *	Version	Date		Author		Comments
+ * -------------------------------------------------
+ * 	1.0		09/23/02	SYARRA		Initial Creation
+ *
+ ************************************************************************/
+
+#ifndef __USB_PHCI_H__
+#define	__USB_PHCI_H__
+
+#include "hal_intf.h"
+
+#define CONFIG_USB_PHCD_EVEN_SCH
+#define CONFIG_USB_PHCD_PING_PONG
+#define CONFIG_PHCI_MEM_SLAB
+
+/*--------------------------*/
+/* ED States 				*/
+/*--------------------------*/
+#define 	ED_NEW 					0x00
+#define 	ED_UNLINK 				0x01
+#define 	ED_OPER					0x02
+#define 	ED_DEL					0x04
+#define 	ED_URB_DEL  			0x08
+
+/*--------------------------*/
+/* usb_phci_ed 				*/
+/*--------------------------*/
+typedef struct ed {
+	__u32 		hwINFO;       	/* hw information */
+	__u32 		hwTailP;		/* td Tail Pointer */
+	__u32 		hwHeadP;		/* td Head poinetr */
+	__u32 		hwNextED;		/* Next ED pointer */
+
+	struct ed 	* ed_prev;  	/* Previous ed pointer */
+	__u8 		int_period;		/* Interrupt period (Int,ISO) */
+	__u8 		int_branch;		/* Interrupt table index (Int,ISO) */
+	__u8 		int_load; 		/* load for this ed */
+	__u8 		int_interval;
+	__u8 		state;			/* ED State */
+	__u8 		type; 			/* Type of transfer */
+	__u16 		last_iso;		/* Last ISochronous? (ISO) */
+
+	__u8		td_ptd_index;	/* Td-PTD map index for this ptd */
+	__u8		total_isoc_tds;
+	__u16		reserved_word;
+
+	void		*empty1;		/* Make the structure length to 32 byte boundary */
+	void		*empty2;
+	void		*empty3;
+
+    struct ed 	* ed_rm_list;	/* Rm list pointer */
+   
+} ed_t;
+
+ 
+/*------------------------------*/
+/* TD info field 				*/
+/*------------------------------*/
+#define 	TD_CC							0xf0000000			/* Condifion code mask */
+#define 	TD_CC_GET(td_p) 				((td_p >>28) & 0x0f)		/* Condition code get */
+#define 	TD_CC_SET(td_p, cc) 			(td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) /* Condition code set */
+#define 	TD_EC       					0x0C000000			/* Error count mask */
+#define 	TD_T        					0x03000000			/* Toggle mask */
+#define 	TD_T_DATA0  					0x02000000			/* Data0 toggle */
+#define 	TD_T_DATA1  					0x03000000			/* DATA1 toggle */
+#define 	TD_T_TOGGLE 					0x00000000			/* Toggle is carried from ED */
+#define 	TD_R        					0x00040000			/* Buffer rounding */
+#define 	TD_DI       					0x00E00000			/* Delay Interrupt mask */
+#define 	TD_DI_SET(X) 					(((X) & 0x07)<< 21)	/* set delay Interrupt */
+#define 	TD_DP       					0x00180000			/* Direction of PID mask */
+#define 	TD_DP_SETUP 					0x00000000			/* Direction Set up */
+#define 	TD_DP_IN    					0x00100000			/* Direction IN */
+#define 	TD_DP_OUT   					0x00080000			/* Direction OUT */
+
+#define 	TD_ISO							0x00010000
+#define 	TD_DEL      					0x00020000
+
+/* CC Codes */
+#define 	TD_CC_NOERROR      				0x00		/* NO error */
+#define 	TD_CC_CRC          				0x01		/* CRC Error */
+#define 	TD_CC_BITSTUFFING  				0x02		/* Bit stuffing Error */
+#define 	TD_CC_DATATOGGLEM  				0x03		/* Data toggle mismatch error */
+#define 	TD_CC_STALL        				0x04		/* received stall */
+#define 	TD_DEVNOTRESP      				0x05		/* Device not responding */
+#define 	TD_PIDCHECKFAIL    				0x06		/* PID Check failure */
+#define 	TD_UNEXPECTEDPID   				0x07		/* Unexpected error */
+#define 	TD_DATAOVERRUN     				0x08		/* Data over run */
+#define 	TD_DATAUNDERRUN    				0x09		/* Data under run */
+#define 	TD_BUFFEROVERRUN   				0x0C		/* Buffer over run */
+#define 	TD_BUFFERUNDERRUN  				0x0D		/* Buffer under run */
+#define 	TD_NOTACCESSED     				0x0E		/* Not accessed */
+
+
+#define 	MAXPSW 							1
+
+typedef struct td { 
+	__u32 		hwINFO;
+  	__u32 		hwCBP;						/* Current Buffer Pointer */
+  	__u32 		hwNextTD;					/* Next TD Pointer */
+  	__u32 		hwBE;						/* Memory Buffer End Pointer */
+  	__u16 		hwPSW[MAXPSW];
+
+  	__u8 		retry_count;				/* Retry count */
+  	__u8 		index;						/* Index in urb */
+  	struct ed 	* ed;						/* pointer to ed attached to */
+  	struct td 	* next_dl_td;				/* next td */
+  	struct urb 		* urb;						/* Urb request it belongs to */
+} td_t;
+
+
+#define 	OHCI_ED_SKIP			(1 << 14)
+
+#define		PTD_MAX_RETRY_COUNT		9
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+ 
+#define 	NUM_INTS 					32	/* part of the OHCI standard */
+
+/*
+ * Maximum number of root hub ports.  
+ */
+#define 	MAX_ROOT_PORTS				2	/* maximum OHCI root hub ports */
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define 	OHCI_CTRL_CBSR				(3 << 0)			/* control/bulk service ratio */
+#define 	OHCI_CTRL_PLE				(1 << 2)			/* periodic list enable */
+#define 	OHCI_CTRL_IE				(1 << 3)			/* isochronous enable */
+#define 	OHCI_CTRL_CLE				(1 << 4)			/* control list enable */
+#define 	OHCI_CTRL_BLE				(1 << 5)			/* bulk list enable */
+#define 	OHCI_CTRL_HCFS				(3 << 6)			/* host controller functional state */
+#define 	OHCI_CTRL_IR				(1 << 8)			/* interrupt routing */
+#define 	OHCI_CTRL_RWC				(1 << 9)			/* remote wakeup connected */
+#define 	OHCI_CTRL_RWE				(1 << 10)			/* remote wakeup enable */
+/* Added for Philips HC Used i.o Interrupt routing as IR is not supported
+by Philips HC */
+#define		OHCI_CTRL_TIP				(1 << 8)			/* Transfer in progress */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET				(0 << 6)
+#	define OHCI_USB_RESUME				(1 << 6)
+#	define OHCI_USB_OPER				(2 << 6)
+#	define OHCI_USB_SUSPEND				(3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define 	OHCI_HCR					(1 << 0)			/* host controller reset */
+#define 	OHCI_CLF  					(1 << 1)			/* control list filled */
+#define 	OHCI_BLF  					(1 << 2)			/* bulk list filled */
+#define 	OHCI_OCR  					(1 << 3)			/* ownership change request */
+#define 	OHCI_SOC  					(3 << 16)			/* scheduling overrun count */
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int 				devnum; 			/* Address of Root Hub endpoint */ 
+	void 				* urb;				/* Root hub urb pointer */
+	void 				* int_addr;
+	int 				send;
+	int 				interval;
+	struct timer_list 	rh_int_timer;		/* root hub interval timer */
+};
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+ 
+/* destination of request */
+#define 	RH_INTERFACE               	0x01			/* Root hub interface related request */
+#define 	RH_ENDPOINT                	0x02			/* Root hub end point  related request */
+#define 	RH_OTHER                   	0x03			/* Root hub other request */
+
+#define 	RH_CLASS                   	0x20			/* Root hub class specific */
+#define 	RH_VENDOR                  	0x40			/* Root hub vender specific */
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define 	RH_GET_STATUS           	0x0080			/* Root hub get status */
+#define 	RH_CLEAR_FEATURE        	0x0100			/* Root hub clear feature */
+#define 	RH_SET_FEATURE          	0x0300			/* Root hub clear feature */
+#define 	RH_SET_ADDRESS				0x0500			/* Root hub set address */
+#define 	RH_GET_DESCRIPTOR			0x0680			/* Root hub get descriptor */
+#define 	RH_SET_DESCRIPTOR       	0x0700			/* Root hub set descriptor */
+#define 	RH_GET_CONFIGURATION		0x0880			/* Root hub get configuration */
+#define 	RH_SET_CONFIGURATION		0x0900			/* Root hub set configuration */
+#define 	RH_GET_STATE            	0x0280			/* Root hub get state */
+#define 	RH_GET_INTERFACE        	0x0A80			/* root hub get inferface */
+#define 	RH_SET_INTERFACE        	0x0B00			/* Root hub set Interface */
+#define 	RH_SYNC_FRAME          	 	0x0C80
+/* Our Vendor Specific Request */
+#define 	RH_SET_EP               	0x2000
+
+
+/* Hub port features */
+#define 	RH_PORT_CONNECTION         0x00
+#define 	RH_PORT_ENABLE             0x01
+#define 	RH_PORT_SUSPEND            0x02
+#define 	RH_PORT_OVER_CURRENT       0x03
+#define 	RH_PORT_RESET              0x04
+#define 	RH_PORT_POWER              0x08
+#define 	RH_PORT_LOW_SPEED          0x09
+
+#define 	RH_C_PORT_CONNECTION       0x10
+#define 	RH_C_PORT_ENABLE           0x11
+#define 	RH_C_PORT_SUSPEND          0x12
+#define 	RH_C_PORT_OVER_CURRENT     0x13
+#define 	RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define 	RH_C_HUB_LOCAL_POWER       0x00				/* Hub local powered */
+#define 	RH_C_HUB_OVER_CURRENT      0x01				/* Hub over current */
+
+#define 	RH_DEVICE_REMOTE_WAKEUP    0x00				
+#define 	RH_ENDPOINT_STALL          0x01
+
+#define 	RH_ACK                     0x01
+#define 	RH_REQ_ERR                 -1
+#define 	RH_NACK                    0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+ 
+/* roothub.portstatus [i] bits */
+#define 	RH_PS_CCS            		0x00000001   			/* current connect status */
+#define 	RH_PS_PES            		0x00000002   			/* port enable status*/
+#define 	RH_PS_PSS            		0x00000004   			/* port suspend status */
+#define 	RH_PS_POCI           		0x00000008   			/* port over current indicator */
+#define 	RH_PS_PRS            		0x00000010  			/* port reset status */
+#define 	RH_PS_PPS            		0x00000100   			/* port power status */
+#define 	RH_PS_LSDA           		0x00000200    			/* low speed device attached */
+#define 	RH_PS_CSC            		0x00010000 				/* connect status change */
+#define 	RH_PS_PESC           		0x00020000   			/* port enable status change */
+#define 	RH_PS_PSSC           		0x00040000    			/* port suspend status change */
+#define 	RH_PS_OCIC           		0x00080000    			/* over current indicator change */
+#define 	RH_PS_PRSC           		0x00100000   			/* port reset status change */
+	
+/* roothub.status bits */
+#define 	RH_HS_LPS	     			0x00000001				/* local power status */
+#define 	RH_HS_OCI	     			0x00000002				/* over current indicator */
+#define 	RH_HS_DRWE	     			0x00008000				/* device remote wakeup enable */
+#define 	RH_HS_LPSC	     			0x00010000				/* local power status change */
+#define 	RH_HS_OCIC	     			0x00020000				/* over current indicator change */
+#define 	RH_HS_CRWE	     			0x80000000				/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define 	RH_B_DR						0x0000ffff				/* device removable flags */
+#define 	RH_B_PPCM					0xffff0000				/* port power control mask */
+	
+/* roothub.a masks */
+#define		RH_A_NDP					(0xff << 0)				/* number of downstream ports */
+#define		RH_A_PSM					(1 << 8)				/* power switching mode */
+#define		RH_A_NPS					(1 << 9)				/* no power switching */
+#define		RH_A_DT						(1 << 10)				/* device type (mbz) */
+#define		RH_A_OCPM					(1 << 11)				/* over current protection mode */
+#define		RH_A_NOCP					(1 << 12)				/* no over current protection */
+#define		RH_A_POTPGT					(0xff << 24)			/* power on to power good time */
+
+#define 	min_hcd(a,b) 				(((a)<(b))?(a):(b))  
+#define 	max_hcd(a,b) 				(((a)>(b))?(a):(b))  
+ 
+
+/* urb */
+typedef struct {
+	ed_t 				* ed;
+	__u16 				length;			// number of tds associated with this request
+	__u16 				td_cnt;			// number of tds already serviced
+	int   				state;
+	wait_queue_head_t 	* wait;
+	td_t 				* td[0];		// list pointer to all corresponding TDs associated with this request
+
+} urb_priv_t;
+
+#define 	URB_DEL 					1
+
+
+#ifdef CONFIG_USB_HCDC_OTG
+
+#define		OTG_PORT_OPEN_PORT			0x0
+#define		OTG_PORT_GET_ENUM			0x1
+#define		OTG_PORT_SUSPEND			0x2
+#define		OTG_PORT_DISCONNECT_PORT	0x3
+#define		OTG_PORT_OPEN_PORT_IMM		0x4
+
+#define 	OTG_HC_PORT_NO			0	//select roothub port 0 as OTG port
+
+typedef struct {
+	void	*priv_data;
+	void	(*otg_notif)(void *otg_priv);
+	void	*hc_priv_data;
+} phci_otg_data_t;
+
+extern	int		phci_register_otg(phci_otg_data_t	*otg_data);
+extern	void	phci_unregister_otg(phci_otg_data_t	*otg_data);
+#endif /* CONFIG_USB_HCDC_OTG */
+
+
+
+/* This is not the complete ISP1362 register set, but some ISP1362 specific 
+*  registers stored at the begining of ISR processing 
+*/
+typedef struct phci_regs {
+	__u16	chip_id;
+	__u32	int_reg;	/* ISP1362 specific */
+	__u32	intrstatus;	/* OHCI compatible */
+	__u32	intrenable;	/* OHCI compatible */
+} phci_regs_t;
+
+/*
+ * This is the full phci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+typedef struct phci {
+
+	int 				disabled;			// e.g. got a UE, we're hung 
+	atomic_t 			resume_count;		// defending against multiple resumes
+
+	int 				phci_int_load[32];	/* load of the 32 Interrupt Chains (for load balancing)*/
+	ed_t 				* ed_rm_list[2];    /* lists of all endpoints to be removed */
+	ed_t 				* ed_bulktail;      /* last endpoint of bulk list */
+	ed_t 				* ed_controltail;   /* last endpoint of control list */
+ 	ed_t 				* ed_isohead;       /* first endpoint of iso list */
+ 	ed_t 				* ed_isotail;       /* last endpoint of iso list */
+	int 				intrstatus;
+	__u32 				hc_control;			/* copy of the hc control reg */
+	struct usb_bus 		* bus;    
+	struct usb_device 	* dev[128];			/* Usb devices attached to this HCD */
+	struct virt_root_hub rh;				/* Virtual Root Hub information */
+
+	unsigned int		irq;				/* Interrupt line for Philips HC */
+	unsigned int		dma;				/* Interrupt line for Philips HC */
+	__u8				*dma_buff;
+	
+	__u32				uHcHcdControl_hcd;	/* Software Control Register of Philips HC */
+												/* Bit 5: Bulk List Enable (BLE) */
+													/* Bit 4: Control List Enable (CLE) */
+													/* Bit 3: Isochronous Enable (IE) */
+													/* Bit 2: Periodic List Enable (PLE) */
+													/* Bit 1..0: Control/Bulk Service Ratio */
+
+	__u32				uHcHcdCommandStatus_hcd;	/* Software Command Status Register of Philips HC */
+													/* Bit 1: Control List Filled (CLF) */
+													/* Bit 2: Bulk List Filled (BLF) */
+
+	__u32				hcd_operational_flags;		/* Host Controller Driver flags */
+													/* Bit 0-12: bits of REG_BUFF_STS bits */
+													/* Bit 16: ISOC scheduling needs to be started */
+	ed_t				* p_int_table[NUM_INTS];	/* Interrupt EndPoint Table (supposdly part of HCCA) */
+	ed_t				* p_ed_bulkhead;			/* Bulk ED Head (supposdly part of OHCI register) */
+	ed_t				* p_ed_controlhead;			/* Control ED Head (supposdly part of OHCI register) */
+
+#ifdef CONFIG_USB_HCDC_OTG
+	 phci_otg_data_t	*otg;						/* OTG module private data */
+	 __u32				otg_port_status;			// OTG Port status
+	struct urb				*rh_urb;					// Root Hub urb
+#endif /* CONFIG_USB_HCDC_OTG */
+	
+	/* PCI device handle and settings */
+	void				*phci_dev;					/* Keep name info here */
+	struct phci_regs	phci_regs;
+
+	spinlock_t phci_lock;           /* Covers all fields up & down */
+
+	struct urb *complete_head, *complete_tail;
+
+} phci_t;
+
+
+#define		ISOC_TRANSFER_ON			0x00010000	/* Bit 16: ISOC transfer for HCD is started */
+#define		ISOC_SCHED_TO_START			0x00020000	/* Bit 17: ISOC scheduling needs to be started */
+#define		ISOC_SCHED_MISSED			0x00040000	/* Bit 18: ISOC scheduling missed needs to be corrected */
+#define		ISOC_ISTL0_SCHED_TO_START	0x00080000	/* Bit 19: ISOC ISTL0 scheduling needs to be started */
+#define		ISOC_ISTL1_SCHED_TO_START	0x00100000	/* Bit 20: ISOC ISTL1 scheduling needs to be started */
+#define		ISOC_ISTL0_ISTL1_TO_START	0x00200000	/* Bit 21: ISO1&ISOC2 both started together */
+
+#define 	NUM_TDS						0			/* num of preallocated transfer descriptors */
+#define 	NUM_EDS 					32			/* num of preallocated endpoint descriptors */
+
+
+/* Structure for phci related device data structure
+ * dev->hc_priv
+ */
+struct phci_device {
+	ed_t 				ed[NUM_EDS];				/* Static Ed's */
+	int 				ed_cnt;						/* total ed's */
+	wait_queue_head_t 	* wait;						/* Wait queue head */
+};
+
+#define 	phci_to_usb(phci)			((phci)->usb)
+#define 	usb_to_phci(usb)			((struct phci_device *)(usb)->hcpriv)
+
+/*-------------------------------------------------------------------------*/
+
+#define 	ALLOC_FLAGS 					(in_interrupt () ? GFP_ATOMIC : GFP_NOIO)
+ 
+#ifdef CONFIG_PHCI_MEM_SLAB
+#define		__alloc(t,c) 					kmem_cache_alloc(c,ALLOC_FLAGS)
+#define		__free(c,x) 					kmem_cache_free(c,x)
+static 		kmem_cache_t 					*td_cache, *ed_cache;
+
+/*
+ * WARNING:  do NOT use this with "forced slab debug"; it won't respect
+ * our hardware alignment requirement.
+ */
+#ifndef 	PHCI_MEM_FLAGS
+#define		PHCI_MEM_FLAGS 					0
+#endif
+
+static int ohci_1161_mem_init (void)
+{
+	/* redzoning (or forced debug!) breaks alignment */
+	int	flags = (PHCI_MEM_FLAGS) & ~SLAB_RED_ZONE;
+
+	/* TDs accessed by controllers and host */
+	td_cache = kmem_cache_create ("ohci_td", sizeof (struct td), 0,
+		flags | SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!td_cache) {
+		dbg ("no TD cache?");
+		return -ENOMEM;
+	}
+
+	printk("td_cache = %p\n", td_cache);
+
+	/* EDs are accessed by controllers and host;  dev part is host-only */
+	ed_cache = kmem_cache_create ("ohci_ed", sizeof (struct phci_device), 0,
+		flags | SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!ed_cache) {
+		dbg ("no ED cache?");
+		kmem_cache_destroy (td_cache);
+		td_cache = 0;
+		return -ENOMEM;
+	}
+	printk("ed_cache = %p\n", ed_cache);
+	dbg ("slab flags 0x%x", flags);
+	return 0;
+}
+
+static void ohci_1161_mem_cleanup (void)
+{
+	if (ed_cache && kmem_cache_destroy (ed_cache))
+		err ("ed_cache remained");
+	ed_cache = 0;
+
+	if (td_cache && kmem_cache_destroy (td_cache))
+		err ("td_cache remained");
+	td_cache = 0;
+}
+
+#else
+#define		__alloc(t,c) 					kmalloc(sizeof(t),ALLOC_FLAGS)
+#define		__free(dev,x) 					kfree(x)
+#define 	td_cache 						0
+#define 	ed_cache 						0
+
+static inline int ohci_1161_mem_init (void) { return 0; }
+static inline void ohci_1161_mem_cleanup (void) { return; }
+
+/* FIXME: pci_consistent version */
+
+#endif
+
+static inline struct td *
+td_alloc (struct phci *hc) {
+
+	struct td *td = (struct td *) __alloc (struct td, td_cache);
+	if(((__u32)td)&0xF) {	
+		/* 
+		 * The Td and ED structure are 16 byte aligned
+		 * Make sure that cache allocation is 16 byte aligned
+		 */
+
+		printk("td_aloc: is not 16 byte aligned %p\n", td);
+		__free (td_cache, td);
+		td = NULL;
+	}
+	return td;
+}
+
+static inline void
+td_free (struct phci *hc, struct td *td) {
+
+	__free (td_cache, td);
+}
+
+
+/* DEV + EDs ... only the EDs need to be consistent */
+static inline struct phci_device *
+dev_alloc (struct phci *hc) {
+
+	struct phci_device *dev = (struct phci_device *)
+		__alloc (struct phci_device, ed_cache);
+	if(((__u32)dev)&0xF)	{
+		/* 
+		 * The Td and ED structure are 16 byte aligned
+		 * Make sure that cache allocation is 16 byte aligned
+		 */
+		printk("dev_aloc: is not 16 byte aligned %p\n", dev);
+		__free (ed_cache, dev);
+		dev = NULL;
+	}
+	return dev;
+}
+
+static inline void
+dev_free (struct phci_device *dev) {
+
+	__free (ed_cache, dev);
+}
+
+
+/* Added Philips HC related Constants */
+
+#define 	YES						1
+#define 	NO						0
+#define 	ON						1
+#define 	OFF						0
+#define		MAX_GTD					64
+
+#define		INVALID_FRAME_NUMBER			0xFFFFFFFF				/* valid frame # is 0 - FFFF only */
+
+
+/* Bit field definition for hwINFO of the td_t  */
+#define 	HC_GTD_R						0x00040000UL			/* Buffer Rounding */
+#define 	HC_GTD_DP						0x00180000UL			/* Direction/PID   */
+#define 	HC_GTD_DI						0x00E00000UL			/* Delay Interrupt */
+#define 	HC_GTD_T						0x03000000UL			/* Data Toggle     */
+#define 	HC_GTD_MLSB						0x02000000UL			/* Data Toggle MSB */
+#define 	HC_GTD_TLSB						0x01000000UL			/* Data Toggle LSB */
+#define 	HC_GTD_EC						0x0C000000UL			/* Error Count     */
+#define 	HC_GTD_CC						0xF0000000UL			/* Condition Code  */
+
+/* Bit field definition for hwINFO of the ed_t */
+#define 	HC_ED_FA						0x0000007FUL			/* Function Address */
+#define 	HC_ED_EN						0x00000780UL			/* Endpoint Number */
+#define 	HC_ED_DIR						0x00001800UL			/* Direction of data flow */
+#define 	HC_ED_SPD						0x00002000UL			/* Device Speed */
+#define 	HC_ED_SKIP						0x00004000UL			/* Skip this ED */
+#define 	HC_ED_F							0x00008000UL			/* Format of this ED */
+#define 	HC_ED_MPS						0x07FF0000UL			/* Maximum Packet Size */
+
+/* Bit field definitions for hwNextP of the td_t */
+#define 	HC_GTD_NEXTTD					0xFFFFFFF0UL			/* Next TD */
+
+/* Bit field definition for hwHeadP of the ed_t */
+#define 	HC_ED_HEADP						0xFFFFFFF0UL			/* Bit 31 .. 4 */
+#define 	HC_ED_TOGGLE					0x00000002UL			/* Bit 1, toggle carry */
+#define 	HC_ED_HALTED					0x00000001UL			/* Bit 0, halted */
+
+/* Bit field definition for hwTailP of the ed_t */
+#define 	HC_ED_TAILP						HC_ED_HEADP				/* Bit 31 .. 4 */
+
+#define 	OHCI_SETUP						0X00000000UL
+#define 	OHCI_OUT						0x00000001UL
+#define 	OHCI_IN							0x00000002UL
+
+
+
+/*-----------------------------------------------------------*/
+/* Philips HC control and data port numbers */
+/*-----------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------*/
+/* host controller operational registers */
+/*-----------------------------------------------------------*/
+
+#define 	uHcRevision                     0x00UL			/* Revision Register */
+#define 	uHcControl                      0x01UL			/* Control Register */
+#define 	uHcCommandStatus                0x02UL			/* Command Status Register */
+#define 	uHcInterruptStatus              0x03UL			/* Interrupt Status Register */
+#define 	uHcInterruptEnable              0x04UL			/* Interrupt Enable Register */
+#define 	uHcInterruptDisable             0x05UL			/* Interrupt Disable Register */
+#define 	uHcFmInterval                   0x0dUL			/* Frame Interval Register */
+#define 	uHcFmRemaining                  0x0eUL			/* Frame Remaining Register */
+#define 	uHcFmNumber                     0x0fUL			/* Frame Number Register */
+#define 	uHcLsThreshold                  0x11UL			/* Threshold register */
+#define 	uHcRhDescriptorA                0x12UL			/* Root Hub Descriptor A Register */
+#define 	uHcRhDescriptorB                0x13UL			/* Root Hub Descriptor B Register */
+#define 	uHcRhStatus                     0x14UL			/* Root Hub Status Register */
+#define 	uHcRhPort1Status                0x15UL          /* Root Hub Port 1 status */  /* Philips HC has only two root hub ports */
+#define 	uHcRhPort2Status                0x16UL			/* Root Hub Port 2 status */ 
+
+/* These two registers are used internally by software. They are not HC hardware 
+	registers.*/
+#define 	uHcHcdControl                   0x17UL			/* HCD Software Control Register */
+#define 	uHcHcdCommandStatus             0x18UL			/* HCD Software Command Status Register */
+
+
+/* Bit field definition for register HcCommandStatus */
+#define 	HC_COMMAND_STATUS_HCR			0x00000001UL		/* Host Controller Reset */
+#define 	HC_COMMAND_STATUS_CLF			0x00000002UL		/* Control List Filled   */
+#define 	HC_COMMAND_STATUS_BLF			0x00000004UL		/* Bulk List Filled      */
+
+
+
+/**********************/
+/* HcControl Register */
+/**********************/
+#define 	CB_RATIO						3	/* Control/Bulk transfer ratio */
+												/* 0 = 1:1                     */
+												/* 1 = 2:1                     */
+												/* 2 = 3:1                     */
+												/* 3 = 4:1                     */
+
+#define 	PERIODIC_LIST_ENABLE			YES	/* Periodic transfer enable    */
+#define 	ISO_ENABLE						YES	/* Isochronous transfer enable */
+#define 	CONTROL_LIST_ENABLE				YES	/* Control transfer enable     */
+#define 	BULK_LIST_ENABLE				YES	/* Bulk transfer enable        */
+#define 	HC_STATE						2	/* Host functional state */
+												/* 0 = Reset             */
+												/* 1 = Resume            */
+												/* 2 = Operational       */
+												/* 3 = Suspend           */
+
+#define 	REMOTE_WAKEUP_CONN				NO	/* Remote wakeup connected */
+
+#define 	REMOTE_WAKEUP_ENABLE			NO	/* Remote wakeup enable    */
+
+
+#define 	INT_NUM_IRQ0					0x20
+
+
+/* Bit field definition for register HcControl */
+#define 	HC_CONTROL_HCFS					0x000000C0UL	/* Host Controller Functional State, bit 7..6 */
+#define 	HC_CONTROL_RWC					0x00000200UL	/* Remote Wakeup Connected, bit 9 */
+#define 	HC_CONTROL_RWE					0x00000400UL	/* Remote Wakeup Enable, bit 10 */
+
+/* Bit field definition for HCD register HcHcdControl */
+/* PHC does not have this HC register as OHCI     */
+/* It is added as a global variable to emulate the    */
+/* OHCI transfer control functionality defined in the */
+/* following bit field                                */
+#define 	HC_CONTROL_CBSR					0x00000003UL		/* Control/Bulk ratio */
+#define 	HC_CONTROL_PLE					0X00000004UL		/* Periodic List Enable */
+#define 	HC_CONTROL_IE					0x00000008UL		/* Isochronous Enable */
+#define 	HC_CONTROL_CLE					0x00000010UL		/* Control List Enable */
+#define 	HC_CONTROL_BLE					0x00000020UL		/* Bulk List Enable */
+#define 	HC_CONTROL_TIP					0x00000100UL		/* Transfer In Progress */
+
+/* Bit field definition for register HcInterruptStatus */
+/* HcInterruptEnable/HcInterruptDisable registers      */
+#define 	HC_INTERRUPT_SO					0x00000001UL		/* Scheduling Overrun      */
+#define 	HC_INTERRUPT_SF					0x00000004UL		/* Start of Frame          */
+#define 	HC_INTERRUPT_RD					0x00000008UL		/* Resume Detect           */
+#define 	HC_INTERRUPT_UE					0x00000010UL		/* Unrecoverable error     */
+#define 	HC_INTERRUPT_FNO				0x00000020UL		/* Frame Number Overflow   */
+#define 	HC_INTERRUPT_RHSC				0x00000040UL		/* Root Hub Status Change  */
+#define 	HC_INTERRUPT_ATD				0X00000080UL		/* ATL List Done           */
+#define 	HC_INTERRUPT_MIE				0x80000000UL		/* Master Interrupt Enable */
+#define 	HC_INTERRUPT_ALL				0x8000007FUL		/* All interrupts          */
+
+/****************************/
+/* HcRhDescriptorA Register */
+/****************************/
+#define 	PORT_POWER_SWITCHING			NO					/* Must be NO for Philips HC */
+#define 	OVER_CURRENT_PROTECTION			YES
+#define 	PER_PORT_OVER_CURRENT_REPORT	NO
+#define 	POWER_ON_TO_POWER_GOOD_TIME		50UL				/* Max. = 512 Msec. Use even number */
+
+/* Bit field definition for register HcRhDescriptorA */
+#define 	HC_RH_DESCRIPTORA_NDP			0x000000FFUL		/* Number of downstream ports  */
+#define 	HC_RH_DESCRIPTORA_PSM			0x00000100UL		/* Power Switching Mode        */
+#define 	HC_RH_DESCRIPTORA_NPS			0x00000200UL		/* No Power Switching          */
+#define 	HC_RH_DESCRIPTORA_OCPM			0x00000800UL		/* OverCurrent Protection Mode */
+#define 	HC_RH_DESCRIPTORA_NOCP			0x00001000UL		/* No OverCurrent Protection   */
+#define 	HC_RH_DESCRIPTORA_POTPGT		0xFF000000UL		/* Power On To Power Good Time */
+
+/****************************/
+/* HcRhDescriptorB Register */
+/****************************/
+#define 	DEVICE_REMOVABLE				0x00000000UL
+#define 	PORT_POWER_MASK					0x00000000UL
+
+/* Bit field definition for register HcRhDescriptorB */
+#define 	HC_RH_DESCRIPTORB_PPCM			0xFFFF0000UL		/* Port Power Control Mask     */
+#define 	HC_RH_DESCRIPTORB_DR			0x0000FFFFUL		/* Device Removable            */
+
+
+/* Bit field definition for register HcRhStatus */
+#define HC_RH_STATUS_LPS					0x00000001UL		/* R: Local Power Status       */
+
+
+/*---------------------------------------------------*/
+/* Index of the HC extended 16-bit registers */
+/*---------------------------------------------------*/
+#define 	REG_HW_MODE						0x20			/* Hardware configuration register */
+#define 	REG_DMA_CNFG					0x21			/* DMA configuration register      */
+#define 	REG_XFER_CNTR					0x22			/* Transfer counter register       */
+#define 	REG_IRQ							0x24			/* Interrupt register              */
+#define 	REG_IRQ_MASK					0x25			/* Interrupt enable register       */
+#define 	REG_CHIP_ID						0x27			/* Chip ID register                */
+#define 	REG_SCRATCH						0x28			/* Scratch register                */
+#define 	REG_RESET_DEV					0xA9			/* Reset register                  */
+#define 	REG_BUFF_STS					0x2C			/* Buffer status register          */
+
+
+#define		REG_DIRECT_ADDR_LEN			0x32			/* Direct Addressing length+dir+addr */
+#define		REG_DIRECT_ADDR_DATA		0x45			/* Direct Addressing data (port) */
+
+#define		REG_ISTL_BUFF_LEN			0x30			/* ISTL buffer length register */
+#define		REG_ISTL0_BUFF_PORT			0x40			/* ISTL0 buffer port register */
+#define		REG_ISTL1_BUFF_PORT			0x42			/* ISTL1 buffer port register */
+#define		REG_ISTL_TOGGLE_RATE		0x47			/* ISTL1 buffer toggle rate */
+
+#define		REG_ATL_BUFF_LEN			0x34			/* ATL buffer length register */
+#define		REG_ATL_BUFF_PORT			0x44			/* ATL buffer port register */
+#define		REG_ATL_BLK_PL_SIZE			0x54			/* ATL buffer  payload block size */
+#define		REG_ATL_THRESHOLD_COUNT		0x51			/* ATL buffer PTD done threshold counter register */
+#define		REG_ATL_THRESHOLD_TIMEOUT	0x52			/* ATL buffer PTD done threshold timeout register */
+
+#define		REG_ATL_PTD_DONE_MAP		0x1B			/* ATL Done map register (Read Only) */
+#define		REG_ATL_PTD_SKIP_MAP		0x1C			/* ATL Skip map register */
+#define		REG_ATL_PTD_LAST_PTD		0x1D			/* ATL buffer last PTD */
+#define		REG_ATL_CURR_ACTIVE_PTD		0x1E			/* ATL buffer Current active PTD (Read Only) */
+
+
+#define		REG_INTL_BUFF_LEN			0x33			/* INTL buffer length register */
+#define		REG_INTL_BUFF_PORT			0x43			/* INTL buffer port register */
+#define		REG_INTL_BLK_PL_SIZE		0x53			/* INTL buffer  payload block size */
+
+#define		REG_INTL_PTD_DONE_MAP		0x17			/* INTL Done map register (Read Only) */
+#define		REG_INTL_PTD_SKIP_MAP		0x18			/* INTL Skip map register */
+#define		REG_INTL_PTD_LAST_PTD		0x19			/* INTL buffer last PTD */
+#define		REG_INTL_CURR_ACTIVE_PTD	0x1A			/* INTL buffer Current active PTD (Read Only) */
+
+#define 	PIC1_OCW1               	0x21
+#define 	PIC1_CASCADE    			0xFB
+#define 	PIC2_OCW1               	0xA1
+
+
+
+/*------------------------------------------------------------------*/
+/* Philips HC external Interrupts configuration						*/
+/*------------------------------------------------------------------*/
+
+/**********************************/
+/* HardwareConfiguration Register */
+/**********************************/
+#define 	GLOBAL_INT_PIN_ENABLE      	YES
+#define 	INT_EDGE_TRIGGERED         	NO
+#define 	INT_ACTIVE_HIGH            	YES
+
+/****************************/
+/* InterruptEnable Register */
+/****************************/
+#define 	SOF_INT_ENABLED            	YES
+#define 	ATL_INT_ENABLED            	NO
+#define 	EOT_INT_ENABLED            	NO
+#define 	OPR_INT_ENABLED            	YES
+#define 	HC_SUSPEND_INT_ENABLED     	NO
+#define 	HC_RESUME_INT_ENABLED      	NO
+
+/****************************/
+/* HcFmInterval Register    */
+/****************************/
+#define		FRAME_INTERVAL				0x00002EDFUL
+#define		FS_LARGEST_DATA				(((FRAME_INTERVAL - 210) * 6) / 7)
+
+/*-----------------------------------------------*/
+/* Bit field definition for REG_HW_MODE register */
+/*-----------------------------------------------*/
+#define 	INT_PIN_ENABLE				0X0001			/* Bit 0    */
+#define 	INT_PIN_TRIGGER				0X0002			/* Bit 1    */
+#define 	INT_OUTPUT_POLARITY			0X0004			/* Bit 2    */
+#define 	DATA_BUS_WIDTH				0X0018			/* Bit 4..3 */
+#define		DREQ_OUT_POLARITY			0x0020			/* Bit 5	*/
+#define		DACK_IN_POLARITY			0x0040			/* Bit 6	*/
+#define		ONE_DMA					0x0080			/* Bit 7	*/
+#define		DACK_MODE				0x0100			/* Bit 8	*/
+#define		ONE_INT					0x0200			/* Bit 9	*/
+#define		ANALOG_OC_ENABLE			0x0400			/* Bit 10 	*/
+#define		SUSPEND_CLK_NOT_STOP			0x0800			/* Bit 11 	*/
+#define		CONNECT_PLDN_15K_DS1			0x1000			/* Bit 12   */
+#define		CONNECT_PLDN_15K_DS2			0x2000			/* Bit 13   */
+
+#define		DATA_BUS_16BIT_WIDTH			0x0008
+
+/*-----------------------------------------------*/
+/* Bit field definition for REG_DMA_CNFG register */
+/*-----------------------------------------------*/
+#define 	DMA_WRITE_SELECT			0X0001			/* Bit 0    */
+#define 	DMA_BUFF_TYPE				0X000E			/* Bit 1..3 */
+#define 	DMA_ENABLE				0X0010			/* Bit 4   	*/
+#define 	DMA_BURST_LENGTH			0X0060			/* Bit 5..6	*/
+#define 	DMA_COUNTER_ENABLE			0X0080			/* Bit 7	*/
+
+#define		DMA_BUFF_TYPE_ISTL0			0x0000			/* ISTL0	*/
+#define		DMA_BUFF_TYPE_ISTL1			0x0002			/* ISTL1	*/
+#define		DMA_BUFF_TYPE_INTL			0x0004			/* INTL		*/
+#define		DMA_BUFF_TYPE_ATL			0x0006			/* ATL		*/
+#define		DMA_BUFF_TYPE_DIR_ADDR			0x0008			/* DIR ADDR	*/
+
+#define		DMA_1CYCLE_BURST_LEN			0x0000			/* Single Cycle 	*/
+#define		DMA_4CYCLE_BURST_LEN			0x0020			/* 4 Cycle	burst	*/
+#define		DMA_8CYCLE_BURST_LEN			0x0040			/* * Cycle burst 	*/
+
+/*-------------------------------------------------------------*/
+/* Bit field definition for REG_IRQ and REG_IRQ_MASK registers */
+/*-------------------------------------------------------------*/
+#define		SOF_INT					0X0001			/* Bit 0: SOF interrupts */
+#define		ISTL_0_INT				0X0002			/* Bit 1: ISTL 0 interrupt */
+#define		ISTL_1_INT				0X0004			/* Bit 2: ISTL 1 interrupt */
+#define		EOT_INT					0X0008			/* Bit 3: End of transfer interrupt */
+#define		OPR_INT					0X0010			/* Bit 4: HCOR int. */
+#define		HC_SUSPEND_INT				0X0020			/* Bit 5 */
+#define		HC_RESUME_INT				0X0040			/* Bit 6 */
+#define		INTL_INT				0X0080			/* Bit 7: INTL interrupt */
+#define		ATL_INT					0X0100			/* Bit 8: ALT interrupt */
+#define		OTG_INT					0X0200			/* Bit 9: OTG interrupt */
+
+/*-------------------------------------------------*/
+/* Bit field definition for REG_BUFF_STS registers */
+/*-------------------------------------------------*/
+#define		ISTL_0_BUFF_FULL			0X0001			/* Bit 0: ISOA buffer full */
+#define		ISTL_1_BUFF_FULL			0X0002			/* Bit 1: ISOB buffer full */
+#define		INTL_ACTIVE				0X0004			/* Bit 2: INTL buffer full */
+#define		ATL_ACTIVE				0X0008			/* Bit 3: ATL buffer full */
+#define		RESET_PING_PONG				0x0010			/* Bit 4: Reset H/W ping Pong bit (bit10) */
+#define		ISTL_0_ACTIVE_STATUS			0X0020			/* Bit 5: ISOA buffer done */
+#define		ISTL_1_ACTIVE_STATUS			0X0040			/* Bit 6: ISOB buffer done */
+#define		ISTL_0_BUFF_DONE			0X0100			/* Bit 8: ISOA buffer done */
+#define		ISTL_1_BUFF_DONE			0X0200			/* Bit 9: ISOB buffer done */
+#define		ACTIVE_PING_PONG_PAIR			0X0400			/* Bit 10: ATL ping-pong active */
+
+/*-----------------------------------------------------------*/
+/* Definitions related to Philips Transfer Descriptors (PTD) */
+/*-----------------------------------------------------------*/
+
+/* Bit field definition for PTD byte 0 */
+#define 	PTD_ACTUAL_BYTES70  			0XFF			/* Bit 7..0 */
+
+/* Bit field definition for PTD byte 1 */
+#define 	PTD_COMPLETION_CODE 			0XF0			/* Bit 7..4 */
+#define 	PTD_ACTIVE      			0X08			/* Bit 3 */
+#define 	PTD_TOGGLE      			0X04			/* Bit 2 */
+#define 	PTD_ACTUAL_BYTES98  			0X03			/* Bit 1..0 */
+
+/* Bit field definition for PTD byte 2 */
+#define 	PTD_MAXPACKET70 			0XFF			/* Bit 7..0 */
+
+/* Bit field definition for PTD byte 3 */
+#define 	PTD_ED          			0XF0			/* Bit 7..4 */
+#define 	PTD_LAST        			0X08			/* Bit 3 */
+#define 	PTD_SPEED       			0X04			/* Bit 2 */
+#define 	PTD_MAXPACKET98 			0X03 			/* Bit 1..0 */
+
+/* Bit field definition for PTD byte 4 */
+#define 	PTD_TOTAL70     			0XFF			/* Bit 7..0 */
+
+/* Bit field definition for PTD byte 5 */
+#define 	PTD_DIR         			0X0C			/* Bit 3..2 */
+#define 	PTD_TOTAL98     			0X03			/* Bit 1..0 */
+
+/* Bit field definition for PTD byte 6 */
+#define 	PTD_FORMAT      			0X80			/* Bit 7 */
+#define 	PTD_FUNCTION    			0X7F			/* Bit 6..0 */
+
+#define		HC_PTD_HEADER_SIZE			8
+#define		HC_RAM_SIZE					4096		/* (ATL + INTL + 2*ISTL < 4096) */
+#define		HC_ATL_BUFFER_LENGTH		1536
+#if 0 /* NSS Debug */
+#define		HC_ATL_BLK_PL_SIZE			256 
+#else
+#define		HC_ATL_BLK_PL_SIZE			512 
+#endif
+#define		HC_ISTL_BUFFER_LENGTH		1024
+#if 0 /* NSS Debug */
+#define		HC_ISTL_BLK_PL_SIZE			128
+#else
+#define		HC_ISTL_BLK_PL_SIZE			256
+#endif
+
+#define		HC_INTL_BUFFER_LENGTH		512
+#define		HC_INTL_BLK_PL_SIZE			64
+
+#define		HC_ISTL_DEF_TOGGLE_RATE		5			/* based on num of isoc pipes supported and max pl size we can change this number */
+#define		HC_ISTL_0_ADDRESS			0
+#define		HC_ISTL_1_ADDRESS			(HC_ISTL_0_ADDRESS + HC_ISTL_BUFFER_LENGTH)
+#define		HC_INTL_ADDRESS				(HC_ISTL_1_ADDRESS + HC_ISTL_BUFFER_LENGTH)
+#define		HC_ATL_ADDRESS				(HC_INTL_ADDRESS+HC_INTL_BUFFER_LENGTH)
+
+#define		HC_DIR_ADDR_INCREMENT		0x00000000
+#define		HC_DIR_ADDR_DECREMENT		0x00008000
+
+#define		HC_DEF_ATL_THRESHOLD_COUNT	1		/* 1 interrupt per 1 ptd done */
+#define		HC_DEF_ATL_THRESHOLD_TIMEOUT	5	/* timeout after 5 milli second */
+
+#define		HC_ATL_BLK_SIZE				(HC_ATL_BLK_PL_SIZE+HC_PTD_HEADER_SIZE)
+#define		HC_INTL_BLK_SIZE			(HC_INTL_BLK_PL_SIZE+HC_PTD_HEADER_SIZE)
+#define		HC_ISTL_BLK_SIZE			(HC_ISTL_BLK_PL_SIZE+HC_PTD_HEADER_SIZE)
+
+#define		TD_PTD_MAX_ATL_TDS			(HC_ATL_BUFFER_LENGTH/HC_ATL_BLK_SIZE)
+#define		TD_PTD_MAX_INTL_TDS			(HC_INTL_BUFFER_LENGTH/HC_INTL_BLK_SIZE)
+#define		TD_PTD_MAX_ISTL_TDS			(HC_ISTL_BUFFER_LENGTH/HC_ISTL_BLK_SIZE)
+
+/* assuming ISTL buffer size is greater than HC_ATL_BLK_PL_SIZE  (or) use
+ * max_hcd(HC_ATL_BLK_PL_SIZE, max_hcd(HC_INTL_BLK_PL_SIZE,HC_ISTL_BUFFER_LENGTH))
+ */
+#define		TD_PTD_MAX_BUFF_SIZE		HC_ISTL_BUFFER_LENGTH
+
+#define		TD_PTD_MAX_BUFF_TDS			32		/* Maximum atl & ITl td's served by PHC
+													are 32 only, assuming istl does not go more
+													than 32 ptd's */
+
+#define		TD_PTD_INV_PTD_INDEX		0xFF	/* Invalid td-ptd index */
+
+#define		TD_PTD_PING					0x80			/* Ping PTD */
+#define		TD_PTD_PONG					0xC0			/* Pong PTD */
+#define		TD_PTD_NO_PING_PONG			0x00			/* ordinary ptd */
+
+#define		TD_PTD_PING_FILLED			0x01	/* PING PTD FILLED IN RAM BUFFER */
+#define		TD_PTD_PONG_FILLED			0x02	/* PING PTD FILLED IN RAM BUFFER */
+
+/* td ptd status */
+#define		TD_PTD_NEW					0	/* PTD is not active */
+#define		TD_PTD_OPER					1	/* PTD is active */
+#define		TD_PTD_SKIP					2	/* PTD is to be skipped */
+#define		TD_PTD_DEL					3	/* PTD is to be removed */
+
+typedef struct td_ptd_map {
+__u8		state;			/* ACTIVE, SKIP, NOT_ACTIVE, TO_BE_REMOVED */
+//__u8		ptd_cnt;		/* Number of ISOC ptds in the ram buffer in the starting td-ptd map only  */
+__u8		ping_pong;		/* ping pong filling status (PING or PONG or NO_PING_PONG */
+__u16		total_bytes;	/* Total Number of bytes for this PTD (including header) */
+__u32		ptd_bitmap;		/* Bitmap of this ptd in HC */
+__u32		ram_addr;		/* ram_addr of this ptd */
+ed_t		*ed;			/* ed pointer */
+td_t		*td;			/* td pointer */
+} td_ptd_map_t;
+
+/* buffer type for Philips HC */
+#define		TD_PTD_BUFF_TYPE_ATL		0	/* ATL buffer */
+#define		TD_PTD_BUFF_TYPE_INTL		1	/* INTL buffer */
+#define		TD_PTD_BUFF_TYPE_ISTL0		2	/* ISTL2 buffer */
+#define		TD_PTD_BUFF_TYPE_ISTL1		3	/* ISTL1 buffer */
+
+#define		TD_PTD_TOTAL_BUFF_TYPES			(TD_PTD_BUFF_TYPE_ISTL1+1)
+
+
+
+typedef struct hc_ram_buff_regs {
+	__u16				buffer_length;			/* Buffer length of RAM buffer */
+	__u16				buffer_port;			/* RAM buffer port number (for accessing) */
+	__u16				block_pl_size;			/* block payload size (for INTL & ATL only ) */
+	__u16				toggle_rate;			/* ISOC buffer toggle rate (ISTL only) */
+	__u32				last_ptd;				/* Last ptd in the hc RAM buffer */
+	__u32				ptd_done_map;			/* Done ptd map in the hc RAM buffer */
+	__u32				ptd_skip_map;			/* skip ptd map in the hc RAM buffer */
+	__u32				curr_active_ptd;		/* Current active ptd in hc RAM buffer */
+	__u8				threshold_count;		/* Thereshold ptd count for ATL buffer */
+	__u8				threshold_timeout;		/* Thereshold timeout units for ATL buffer */
+} hc_ram_buff_regs_t;
+
+typedef struct td_ptd_map_buff {
+	__u8				buffer_type;			/* Buffer type: BUFF_TYPE_ATL/INTL/ISTL0/ISTL1 */
+	__u8				ping_pong_status;		/* Ping_Pong mechanism is being used or not */		
+	__u8				ping_ptd_index;			/* index of the ping PTD */
+	__u8				pong_ptd_index;			/* index of the pong PTD */
+	__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 this buffer can withstand */
+	__u32				active_ptd_bitmap;		/* Active PTD's bitmap */
+	__u32				skip_ptd_bitmap;		/* skip PTD's bitmap */
+	__u32				pending_ptd_bitmap;		/* skip PTD's bitmap */
+	__u32				active_ptd_bitmask;		/* active ptd bitmask */
+	__u16				ram_buff_addr;			/* Ram Buffer Address */	
+	__u32				frame_number;			/* Isoc frame Number */
+	td_t				*done_head;				/* Done td's head pointer */
+	hc_ram_buff_regs_t	regs;					/* HC ram buffer registers (copy of hc registers maintained at HCD */
+	td_ptd_map_t		map_list[TD_PTD_MAX_BUFF_TDS];	/* td_ptd_map list */
+} td_ptd_map_buff_t;
+
+
+#define		PTD_CC_MASK					0xF0			/* PTD completion code mask */
+#define		ATL_PTD_HEADER_BYTE7		0x00			/* Atl buffer ptd header 7th byte */
+#define		RAM_BUFF_ALIGNMENT			0x4
+
+#define		ALIGN_RAM_BUFF_LENGTH(x)	while( (x) & (RAM_BUFF_ALIGNMENT-1)) {(x)++;}
+
+
+#define		PHCI_DRIVER_VERSION			"v1.0"
+#define		HC_NUMBER					"1362"
+
+#define		MAX_BULK_TD_BUFF_SIZE		HC_ATL_BLK_PL_SIZE
+#define		MAX_CNTL_TD_BUFF_SIZE		HC_ATL_BLK_PL_SIZE
+
+#ifdef CONFIG_USB_HCDC_OTG
+extern 	void	phci_otg_port_control(void *priv, __u8	cmd, __u32 *data);
+extern	int	phci_register_otg(phci_otg_data_t	*otg_data);
+extern	void	phci_unregister_otg(phci_otg_data_t	*otg_data);
+extern	void	phci_otg_port_control(void *priv, __u8	cmd, __u32 *data);
+#endif /* CONFIG_USB_HCDC_OTG */
+
+#endif	/* __USB_PHCI_H__ */
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/fs/proc/proc_misc.c linux-2.4.26/fs/proc/proc_misc.c
--- linux-2.4.26.org/fs/proc/proc_misc.c	2003-11-29 03:26:21.000000000 +0900
+++ linux-2.4.26/fs/proc/proc_misc.c	2004-03-22 10:56:40.000000000 +0900
@@ -58,7 +58,7 @@
 extern int get_device_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
-#ifndef CONFIG_X86
+#if !(defined(CONFIG_X86) || defined(CONFIG_M32R))
 extern int get_irq_list(char *);
 #endif
 extern int get_dma_list(char *);
@@ -391,7 +391,7 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-#ifndef CONFIG_X86
+#if !(defined(CONFIG_X86) || defined(CONFIG_M32R))
 #if !defined(CONFIG_ARCH_S390)
 static int interrupts_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -609,7 +609,7 @@
 #endif
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
-#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86)
+#if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_X86) && !defined(CONFIG_M32R)
 		{"interrupts",	interrupts_read_proc},
 #endif
 		{"filesystems",	filesystems_read_proc},
@@ -633,7 +633,7 @@
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
-#if defined(CONFIG_X86)
+#if defined(CONFIG_X86) || defined(CONFIG_M32R)
 	create_seq_entry("interrupts", 0, &proc_interrupts_operations);
 #endif
 	create_seq_entry("ioports", 0, &proc_ioports_operations);
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/brlock.h linux-2.4.26/include/linux/brlock.h
--- linux-2.4.26.org/include/linux/brlock.h	2002-11-29 08:53:15.000000000 +0900
+++ linux-2.4.26/include/linux/brlock.h	2004-03-18 19:10:23.000000000 +0900
@@ -73,7 +73,12 @@
 extern struct br_wrlock __br_write_locks[__BR_IDX_MAX];
 #endif
 
+/* FIXME : Workaround for fix compile error */
+#if defined(CONFIG_M32R) && defined(CONFIG_SMP)
+#define __br_lock_usage_bug()	do { } while (0)
+#else
 extern void __br_lock_usage_bug (void);
+#endif
 
 #ifdef __BRLOCK_USE_ATOMICS
 
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/elf.h linux-2.4.26/include/linux/elf.h
--- linux-2.4.26.org/include/linux/elf.h	2004-02-18 22:36:32.000000000 +0900
+++ linux-2.4.26/include/linux/elf.h	2004-03-22 10:57:00.000000000 +0900
@@ -85,12 +85,14 @@
 #define EM_S390		22	/* IBM S/390 */
 
 #define EM_CRIS         76      /* Axis Communications 32-bit embedded processor */
+#define EM_M32R		88	/* M32R */
 
 /*
  * This is an interim value that we will use until the committee comes
  * up with a final number.
  */
 #define EM_ALPHA	0x9026
+#define EM_CYGNUS_M32R	0x9041
 
 /*
  * This is the old interim value for S/390 architecture
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/gdb.h linux-2.4.26/include/linux/gdb.h
--- linux-2.4.26.org/include/linux/gdb.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/include/linux/gdb.h	2001-10-05 22:54:13.000000000 +0900
@@ -0,0 +1,67 @@
+#ifndef _GDB_H_
+#define _GDB_H_
+
+/*
+ * Copyright (C) 2001 Amit S. Kale
+ */
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+extern int gdb_enter;	/* 1 = enter debugger on boot */
+extern int gdb_ttyS;
+extern int gdb_baud;
+extern int gdb_initialized;
+
+extern int gdb_hook(void);
+extern void breakpoint(void);
+
+typedef int     gdb_debug_hook(int trapno,
+                               int signo,
+                               int err_code,
+                               struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+extern spinlock_t kgdb_nmispinlock;
+#else
+extern unsigned kgdb_spinlock;
+extern unsigned kgdb_nmispinlock;
+#endif
+
+extern volatile int kgdb_memerr_expected;
+
+struct console;
+void gdb_console_write(struct console *co, const char *s,
+				unsigned count);
+void gdb_console_init(void);
+
+extern volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#define KGDB_ASSERT(message, condition)	do {			\
+	if (!(condition)) {					\
+		printk("kgdb assertion failed: %s\n", message); \
+		asm ("int $0x3");				\
+	}							\
+} while (0)
+
+#ifdef CONFIG_KERNEL_ASSERTS
+#define KERNEL_ASSERT(message, condition) KGDB_ASSERT(message, condition)
+#else
+#define KERNEL_ASSERT(message, condition)
+#endif
+
+#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
+
+#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
+
+#define KA_VALID_KPTR(ptr)  (!(ptr) ||	\
+	       ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
+	       (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
+
+#define KA_VALID_PTRORERR(errptr) (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
+
+#define KA_HELD_GKL()	(current->lock_depth >= 0)
+
+#endif /* _GDB_H_ */
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/linkage.h linux-2.4.26/include/linux/linkage.h
--- linux-2.4.26.org/include/linux/linkage.h	2000-12-12 05:49:54.000000000 +0900
+++ linux-2.4.26/include/linux/linkage.h	2001-11-13 21:23:49.000000000 +0900
@@ -25,6 +25,10 @@
 #define SYMBOL_NAME_LABEL(X) X/**/:
 #endif
 
+#ifdef __M32R__
+#define __ALIGN	.balign 4
+#define __ALIGN_STR ".balign 4"
+#else  /* __M32R__ */
 #ifdef __arm__
 #define __ALIGN .align 0
 #define __ALIGN_STR ".align 0"
@@ -47,16 +51,25 @@
 #endif /* __sh__ */
 #endif /* __mc68000__ */
 #endif /* __arm__ */
+#endif /* __M32R__ */
 
 #ifdef __ASSEMBLY__
 
 #define ALIGN __ALIGN
 #define ALIGN_STR __ALIGN_STR
-
+#ifdef __M32R__ 
+#define ENTRY(name) ENTRY_M name
+  .macro ENTRY_M name
+  .global SYMBOL_NAME(\name)
+  ALIGN
+SYMBOL_NAME_LABEL(\name)
+  .endm
+#else  /* !__M32R__ */
 #define ENTRY(name) \
   .globl SYMBOL_NAME(name); \
   ALIGN; \
   SYMBOL_NAME_LABEL(name)
+#endif  /* __M32R__ */
 
 #endif
 
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/mmc/mmc_ll.h linux-2.4.26/include/linux/mmc/mmc_ll.h
--- linux-2.4.26.org/include/linux/mmc/mmc_ll.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/include/linux/mmc/mmc_ll.h	2004-06-25 16:17:06.000000000 +0900
@@ -0,0 +1,112 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2004/06/25 07:17:06 $ 
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_LL_H
+#define MMC_MMC_LL_H
+
+#include <linux/types.h>
+#include <linux/mmc/mmc_protocol.h>
+
+#ifdef __KERNEL__
+
+/* Error codes */
+enum mmc_result_t {
+	MMC_NO_RESPONSE        = -1,
+	MMC_NO_ERROR           = 0,
+	MMC_ERROR_OUT_OF_RANGE,
+	MMC_ERROR_ADDRESS,
+	MMC_ERROR_BLOCK_LEN,
+	MMC_ERROR_ERASE_SEQ,
+	MMC_ERROR_ERASE_PARAM,
+	MMC_ERROR_WP_VIOLATION,
+	MMC_ERROR_CARD_IS_LOCKED,
+	MMC_ERROR_LOCK_UNLOCK_FAILED,
+	MMC_ERROR_COM_CRC,
+	MMC_ERROR_ILLEGAL_COMMAND,
+	MMC_ERROR_CARD_ECC_FAILED,
+	MMC_ERROR_CC,
+	MMC_ERROR_GENERAL,
+	MMC_ERROR_UNDERRUN,
+	MMC_ERROR_OVERRUN,
+	MMC_ERROR_CID_CSD_OVERWRITE,
+	MMC_ERROR_STATE_MISMATCH,
+	MMC_ERROR_HEADER_MISMATCH,
+	MMC_ERROR_TIMEOUT,
+	MMC_ERROR_CRC,
+	MMC_ERROR_DRIVER_FAILURE,
+};
+
+struct mmc_request {
+	int               index;      /* Slot index - used for CS lines */
+	int               cmd;        /* Command to send */
+	u32               arg;        /* Argument to send */
+	enum mmc_rsp_t    rtype;      /* Response type expected */
+
+	/* Data transfer (these may be modified at the low level) */
+	u16               nob;        /* Number of blocks to transfer*/
+	u16               block_len;  /* Block length */
+	u8               *buffer;     /* Data buffer */
+
+	/* Results */
+	u8                response[18]; /* Buffer to store response - CRC is optional */
+	enum mmc_result_t result;
+};
+
+#define MMC_SDFLAG_SPI_MODE   (1<<0)    /* Can use SPI mode */
+#define MMC_SDFLAG_MMC_MODE   (1<<1)    /* Can use MMC mode */
+#define MMC_SDFLAG_SD_MODE    (1<<2)    /* Can use SD mode */
+#define MMC_SDFLAG_VOLTAGE    (1<<3)    /* Can change voltage range */
+
+struct module;
+
+struct mmc_slot_driver {
+	struct module  *owner;
+	char           *name;
+	u32             ocr;         /* Valid voltage ranges */
+	u32             flags;       /* Slot driver flags */
+
+	int  (*init)(void);   
+	void (*cleanup)(void);
+	int  (*is_empty)(int);
+	int  (*set_clock)(u32 rate);
+	void (*send_cmd)(struct mmc_request *);
+};
+
+/* add NSS */
+struct mmc_slot_module {
+	int (*init)(void);
+	void (*cleanup)(void);
+};
+
+/* Calls made by the hardware-specific slot driver code */
+extern int  mmc_register_slot_driver( struct mmc_slot_driver *, int );
+extern void mmc_unregister_slot_driver( struct mmc_slot_driver * );
+extern void mmc_cmd_complete( struct mmc_request * );
+extern void mmc_insert( int );
+extern void mmc_eject( int );
+
+#endif /* #ifdef __KERNEL__ */
+
+#endif /* MMC_MMC_LL_H */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/mmc/mmc_protocol.h linux-2.4.26/include/linux/mmc/mmc_protocol.h
--- linux-2.4.26.org/include/linux/mmc/mmc_protocol.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.4.26/include/linux/mmc/mmc_protocol.h	2004-06-25 16:17:06.000000000 +0900
@@ -0,0 +1,285 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date  : $Date: 2004/06/25 07:17:06 $ 
+ *
+ * Author:  Andrew Christian
+ *          15 May 2002
+ */
+
+#ifndef MMC_MMC_PROTOCOL_H
+#define MMC_MMC_PROTOCOL_H
+
+#include <linux/types.h>
+
+/* Standard MMC clock speeds */
+#if 0 /* NSS */
+#define MMC_CLOCK_SLOW    400000      /* 400 kHz for initial setup */
+#else
+#define MMC_CLOCK_SLOW    370000      /* 370 kHz for initial setup */
+#endif
+#define MMC_CLOCK_FAST  20000000      /* 20 MHz for maximum for normal operation */
+
+/* Extra MMC commands for state control */
+/* Use negative numbers to disambiguate */
+#define MMC_CIM_RESET            -1
+
+/* Standard MMC commands (3.1)           type  argument     response */
+   /* class 1 */
+#define	MMC_GO_IDLE_STATE         0   /* bc                          */
+#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
+#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
+#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
+#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
+#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
+#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
+
+  /* class 2 */
+#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
+#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+
+  /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
+
+  /* class 4 */
+#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
+
+  /* class 6 */
+#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
+#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
+#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
+
+  /* class 5 */
+#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
+#define MMC_ERASE                37   /* ac                      R1b */
+
+  /* class 9 */
+#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
+
+  /* class 7 */
+#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
+
+  /* class 8 */
+#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
+
+  /* Advanced Command (used by sd card) */
+#define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
+
+
+/* Don't change the order of these; they are used in dispatch tables */
+enum mmc_rsp_t {
+	RESPONSE_NONE   = 0,
+	RESPONSE_R1     = 1,
+	RESPONSE_R1B    = 2,
+	RESPONSE_R2_CID = 3,
+	RESPONSE_R2_CSD  = 4,
+	RESPONSE_R3      = 5,
+	RESPONSE_R4      = 6,
+	RESPONSE_R5      = 7
+};
+
+
+/*
+  MMC status in R1
+  Type
+  	e : error bit
+	s : status bit
+	r : detected and set for the actual command response
+	x : detected and set during command execution. the host must poll
+            the card by sending status command in order to read these bits.
+  Clear condition
+  	a : according to the card state
+	b : always related to the previous command. Reception of
+            a valid command will clear it (with a delay of one command)
+	c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
+#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
+#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
+#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
+#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
+#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
+#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
+#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
+#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
+#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
+#define R1_CC_ERROR		(1 << 20)	/* erx, c */
+#define R1_ERROR		(1 << 19)	/* erx, c */
+#define R1_UNDERRUN		(1 << 18)	/* ex, c */
+#define R1_OVERRUN		(1 << 17)	/* ex, c */
+#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
+#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
+#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
+#define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
+#define R1_APP_CMD		(1 << 7)	/* sr, c */
+
+enum card_state {
+	CARD_STATE_EMPTY = -1,
+	CARD_STATE_IDLE	 = 0,
+	CARD_STATE_READY = 1,
+	CARD_STATE_IDENT = 2,
+	CARD_STATE_STBY	 = 3,
+	CARD_STATE_TRAN	 = 4,
+	CARD_STATE_DATA	 = 5,
+	CARD_STATE_RCV	 = 6,
+	CARD_STATE_PRG	 = 7,
+	CARD_STATE_DIS	 = 8,
+};
+
+/* These are unpacked versions of the actual responses */
+
+struct mmc_response_r1 {
+	u8  cmd;
+	u32 status;
+};
+
+struct mmc_cid {
+	u8  mid;
+	u16 oid;
+	u8  pnm[7];   // Product name (we null-terminate)
+	u8  prv;
+	u32 psn;
+	u8  mdt;
+};
+
+struct mmc_csd {
+	u8  csd_structure;
+	u8  spec_vers;
+	u8  taac;
+	u8  nsac;
+	u8  tran_speed;
+	u16 ccc;
+	u8  read_bl_len;
+	u8  read_bl_partial;
+	u8  write_blk_misalign;
+	u8  read_blk_misalign;
+	u8  dsr_imp;
+	u16 c_size;
+	u8  vdd_r_curr_min;
+	u8  vdd_r_curr_max;
+	u8  vdd_w_curr_min;
+	u8  vdd_w_curr_max;
+	u8  c_size_mult;
+	union {
+		struct { /* MMC system specification version 3.1 */
+			u8  erase_grp_size;  
+			u8  erase_grp_mult; 
+		} v31;
+		struct { /* MMC system specification version 2.2 */
+			u8  sector_size;
+			u8  erase_grp_size;
+		} v22;
+	} erase;
+	u8  wp_grp_size;
+	u8  wp_grp_enable;
+	u8  default_ecc;
+	u8  r2w_factor;
+	u8  write_bl_len;
+	u8  write_bl_partial;
+	u8  file_format_grp;
+	u8  copy;
+	u8  perm_write_protect;
+	u8  tmp_write_protect;
+	u8  file_format;
+	u8  ecc;
+};
+
+struct mmc_response_r3 {  
+	u32 ocr;
+}; 
+
+#define MMC_VDD_145_150	0x00000001	/* VDD voltage 1.45 - 1.50 */
+#define MMC_VDD_150_155	0x00000002	/* VDD voltage 1.50 - 1.55 */
+#define MMC_VDD_155_160	0x00000004	/* VDD voltage 1.55 - 1.60 */
+#define MMC_VDD_160_165	0x00000008	/* VDD voltage 1.60 - 1.65 */
+#define MMC_VDD_165_170	0x00000010	/* VDD voltage 1.65 - 1.70 */
+#define MMC_VDD_17_18	0x00000020	/* VDD voltage 1.7 - 1.8 */
+#define MMC_VDD_18_19	0x00000040	/* VDD voltage 1.8 - 1.9 */
+#define MMC_VDD_19_20	0x00000080	/* VDD voltage 1.9 - 2.0 */
+#define MMC_VDD_20_21	0x00000100	/* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22	0x00000200	/* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23	0x00000400	/* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24	0x00000800	/* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25	0x00001000	/* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26	0x00002000	/* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27	0x00004000	/* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28	0x00008000	/* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29	0x00010000	/* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30	0x00020000	/* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31	0x00040000	/* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32	0x00080000	/* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33	0x00100000	/* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34	0x00200000	/* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35	0x00400000	/* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36	0x00800000	/* VDD voltage 3.5 ~ 3.6 */
+#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
+
+
+/* CSD field definitions */
+ 
+#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1       */
+
+#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
+
+
+#define PERROR(format,arg...) printk(KERN_ERR __FILE__ ":%s - " format "\n", __FUNCTION__ , ## arg)
+#define PALERT(format,arg...) printk(KERN_ALERT __FILE__ ":%s - " format "\n", __FUNCTION__ , ## arg)
+
+#ifdef CONFIG_MMC_DEBUG
+#ifndef CONFIG_MMC_DEBUG_VERBOSE
+#define CONFIG_MMC_DEBUG_VERBOSE 3
+#endif
+extern int g_mmc_debug;
+#define MMC_DEBUG(n, format, args...)	\
+	if (n <=  g_mmc_debug) {	\
+                printk("[%s:%d] %s ", __FILE__, __LINE__, __FUNCTION__); \
+		printk(format "\n" , ## args);	\
+	}
+#define START_MMC_DEBUG(n) do { if (n <= g_mmc_debug)
+#define END_MMC_DEBUG      } while (0)
+#else
+#define MMC_DEBUG(n, args...)
+#define START_MMC_DEBUG(n)
+#define END_MMC_DEBUG
+#endif /* CONFIG_MMC_DEBUG */
+
+#endif  /* MMC_MMC_PROTOCOL_H */
+
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/mtd/cfi.h linux-2.4.26/include/linux/mtd/cfi.h
--- linux-2.4.26.org/include/linux/mtd/cfi.h	2003-06-13 23:51:38.000000000 +0900
+++ linux-2.4.26/include/linux/mtd/cfi.h	2004-03-22 10:57:01.000000000 +0900
@@ -465,7 +465,8 @@
 		return;
 	}
 #endif
-	udelay(us);
+// XXXXXXXXXXXXXX bad_udelay?
+	__udelay(us);
 	cond_resched();
 }
 
diff -ruN -xasm-m32r -xm32r linux-2.4.26.org/include/linux/sysctl.h linux-2.4.26/include/linux/sysctl.h
--- linux-2.4.26.org/include/linux/sysctl.h	2004-04-14 22:05:40.000000000 +0900
+++ linux-2.4.26/include/linux/sysctl.h	2004-06-24 19:45:44.000000000 +0900
@@ -69,7 +69,8 @@
 /* CTL_BUS names: */
 enum
 {
-	CTL_BUS_ISA=1		/* ISA */
+	CTL_BUS_ISA=1,		/* ISA */
+	CTL_BUS_MMC=2           /* MultiMedia Card */
 };
 
 /* CTL_KERN names: */

