diff -Naru linux-2.4.20.orig/arch/ppc/boot/simple/misc-embedded.c linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c
--- linux-2.4.20.orig/arch/ppc/boot/simple/misc-embedded.c	2002-12-11 02:40:29.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c	2003-04-01 15:14:18.000000000 +0000
@@ -62,6 +62,51 @@
 char ramroot_string[] = "root=/dev/ram";
 char netroot_string[] = "root=/dev/nfs rw ip=on";
 
+#ifdef CONFIG_OPENBLOCKS266
+char eeprom_root_string[30] = { 0 };
+static int get_root_parameter(bd_t *b, char *str)
+{
+	int i;
+	char *p = str;
+
+	if (b == NULL) return 1;	/* something error */
+
+#if 0	/* for debug */
+	puts("\n[");
+	for (i = 0; i < sizeof(b->bi_r_version); i++) {
+		puts(" ");
+		puthex(b->bi_r_version[i]);
+	}
+	puts("]\n");
+#endif
+
+	for (i = 0; i < sizeof(b->bi_r_version); i++) {
+		if (b->bi_r_version[i] == '\0') goto found;
+	}
+	return 2;	/* no null termination */
+found:
+	*p = '\0';
+	for (i += 1; i < sizeof(b->bi_r_version); i++) {
+		*p++ = b->bi_r_version[i];
+		if (b->bi_r_version[i] == '\0') {
+			if (p == str) return 3;	/* Maybe old ROM Monitor... */
+			return 0;	/* OK */
+		}
+	}
+	return 4;	/* too long */
+}
+
+static int is_pushsw(bd_t *b)
+{
+#define PUSHSW_INT	26
+	if (mfdcr(DCRN_UIC_SR(UIC0)) & (1 << (31 - PUSHSW_INT))) {
+		b->bi_s_version[0] = '\0';
+		return 1;
+	}
+	return 0;
+}
+#endif
+
 /* Serial port to use. */
 unsigned long com_port;
 
@@ -171,6 +216,13 @@
 	else
 		memcpy (cmd_line, netroot_string, sizeof(netroot_string));
 #endif
+#ifdef CONFIG_OPENBLOCKS266
+	if (!is_pushsw(hold_residual) && get_root_parameter(bp, eeprom_root_string) == 0) {
+		int len = strlen(eeprom_root_string);
+		memcpy (cmd_line, "root=/dev/", 10);
+		memcpy (cmd_line + 10, eeprom_root_string, len + 1);
+	}
+#endif
 	while ( *cp )
 		putc(*cp++);
 #if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
@@ -178,7 +230,12 @@
 	 * If they have a console, allow them to edit the command line.
 	 * Otherwise, don't bother wasting the five seconds.
 	 */
-	while (timer++ < 5*1000) {
+#ifdef CONFIG_OPENBLOCKS266
+#define BOOT_WAIT_TIME (400)	/* real 2sec */
+#else
+#define BOOT_WAIT_TIME (5*1000)
+#endif
+	while (timer++ < BOOT_WAIT_TIME) {
 		if (tstc()) {
 			while ((ch = getc()) != '\n' && ch != '\r') {
 				if (ch == '\b' || ch == '\177') {
diff -Naru linux-2.4.20.orig/arch/ppc/boot/simple/misc-embedded.c-dbg linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c-dbg
--- linux-2.4.20.orig/arch/ppc/boot/simple/misc-embedded.c-dbg	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/boot/simple/misc-embedded.c-dbg	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,317 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ *
+ * Originally adapted by Gary Thomas.  Much additional work by
+ * Cort Dougan <cort@fsmlabs.com>.  On top of that still more work by
+ * Dan Malek <dmalek@jlc.net>.
+ *
+ * Currently maintained by: Tom Rini <trini@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/elf.h>
+#include <asm/bootinfo.h>
+#include <asm/ibm4xx.h>
+#include <asm/mmu.h>
+#include <asm/mpc8xx.h>
+#include <asm/mpc8260.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+
+#include "nonstdio.h"
+#include "zlib.h"
+
+/* The linker tells us where the image is. */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin, __ramdisk_end;
+extern char _end[];
+
+/* Because of the limited amount of memory on embedded, it presents
+ * loading problems.  The biggest is that we load this boot program
+ * into a relatively low memory address, and the Linux kernel Bss often
+ * extends into this space when it get loaded.  When the kernel starts
+ * and zeros the BSS space, it also writes over the information we
+ * save here and pass to the kernel (usually board info).
+ * On these boards, we grab some known memory holes to hold this information.
+ */
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
+char *avail_ram;
+char *end_avail;
+char *zimage_start;
+
+/* This is for 4xx treeboot.  It provides a place for the bootrom
+ * give us a pointer to a rom environment command line.
+ */
+char *bootrom_cmdline = "";
+
+/* This is the default cmdline that will be given to the user at boot time..
+ * If none was specified at compile time, we'll give it one that should work.
+ * -- Tom */
+#ifdef CONFIG_CMDLINE_BOOL
+char compiled_string[] = CONFIG_CMDLINE;
+#endif
+char ramroot_string[] = "root=/dev/ram";
+char netroot_string[] = "root=/dev/nfs rw ip=on";
+
+/* Serial port to use. */
+unsigned long com_port;
+
+/* We need to make sure that this is before the images to ensure
+ * that it's in a mapped location. - Tom */
+bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
+bd_t *hold_residual = &hold_resid_buf;
+
+extern unsigned long serial_init(int chan, bd_t *bp);
+extern void serial_close(unsigned long com_port);
+extern unsigned long start;
+extern void flush_instruction_cache(void);
+extern void gunzip(void *, int, unsigned char *, int *);
+extern void embed_config(bd_t **bp);
+
+unsigned long
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
+{
+	char *cp, ch;
+	int timer = 0, zimage_size;
+	unsigned long initrd_size;
+    	volatile unsigned char *Mode = (char *)0x00100006;	
+    	volatile unsigned char *Ram = (char *)0x00100007;	
+
+
+	/* First, capture the embedded board information.  Then
+	 * initialize the serial console port.
+	 */
+#ifdef CONFIG_SERIAL_CONSOLE
+	com_port = serial_init(0, bp);
+#endif
+	embed_config(&bp);
+#if 0
+        if (*Ram == 4)
+	{
+		puts("[decompress_kernel] Ramsize 4MB\n");
+		bp->bi_memsize = 0x00400000;
+	}
+        else if (*Ram == 8)
+	{
+		puts("[decompress_kernel] Ramsize 8MB\n");
+		bp->bi_memsize = 0x00800000;
+	}
+        else if (*Ram == 16)
+	{
+		puts("[decompress_kernel] Ramsize 16MB\n");
+		bp->bi_memsize = 0x01000000;
+	}
+        else if (*Ram == 32)
+	{
+		puts("[decompress_kernel] Ramsize 32MB\n");
+		bp->bi_memsize = 0x02000000;
+	}
+        else if (*Ram == 64)
+	{
+		puts("[decompress_kernel] Ramsize 64MB\n");
+		bp->bi_memsize = 0x04000000;
+	}
+        else if (*Ram == 128)
+	{
+		puts("[decompress_kernel] Ramsize 128MB\n");
+		bp->bi_memsize = 0x08000000;
+	}
+        else if (*Ram == 256)
+	{
+		puts("[decompress_kernel] Ramsize 256MB\n");
+		bp->bi_memsize = 0x10000000;
+	}
+	else
+	{
+		puts("[decompress_kernel] Do not know Ramsize setting 64MB\n");
+		bp->bi_memsize = 0x02000000;
+	}
+#else
+#endif
+	puts("MEMSIZE:");
+	puthex(bp->bi_memsize);
+	/* copy board data */
+	if (bp)
+		memcpy(hold_residual,bp,sizeof(bd_t));
+
+#if 0
+	if (*Mode == 0)
+	{
+		puts("[decompress_kernel] Entering initrd mode. Root FS: ram disk\n");
+		/* Load data from flash */
+   		bp->bi_r_version[0] = 0x01;
+	}
+        else if (*Mode == 1)
+	{
+		puts("[decompress_kernel] Entering hard disk mode. Root FS: hard disk\n");
+   		bp->bi_r_version[0] = 0x00;
+	}
+	else if (*Mode == 2)
+	{
+		puts("[decompress_kernel] Entering recover mode. Root FS: ram disk\n");
+   		bp->bi_r_version[0] = 0x00;
+	}
+	else
+	{
+		puts("[decompress_kernel] Entering recover mode. Root FS: ram disk\n");
+   		bp->bi_r_version[0] = 0x00;
+	}
+#endif
+
+	/* Set end of memory available to us.  It is always the highest
+	 * memory address provided by the board information.
+	 */
+	end_avail = (char *)(bp->bi_memsize);
+
+	puts("\nloaded at:     "); puthex(load_addr);
+	puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
+	if ( (unsigned long)load_addr != (unsigned long)&start ) {
+		puts("relocated to:  "); puthex((unsigned long)&start);
+		puts(" ");
+		puthex((unsigned long)((unsigned long)&start + (4*num_words)));
+		puts("\n");
+	}
+
+	if ( bp ) {
+		puts("board data at: "); puthex((unsigned long)bp);
+		puts(" ");
+		puthex((unsigned long)((unsigned long)bp + sizeof(bd_t)));
+		puts("\nrelocated to:  ");
+		puthex((unsigned long)hold_residual);
+		puts(" ");
+		puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
+		puts("\n");
+	}
+
+	/*
+	 * We link ourself to an arbitrary low address.  When we run, we
+	 * relocate outself to that address.  __image_being points to
+	 * the part of the image where the zImage is. -- Tom
+	 */
+	zimage_start = (char *)(unsigned long)(&__image_begin);
+	zimage_size = (unsigned long)(&__image_end) -
+			(unsigned long)(&__image_begin);
+
+	initrd_size = (unsigned long)(&__ramdisk_end) -
+		(unsigned long)(&__ramdisk_begin);
+
+	/*
+	 * The zImage and initrd will be between start and _end, so they've
+	 * already been moved once.  We're good to go now. -- Tom
+	 */
+	puts("zimage at:     "); puthex((unsigned long)zimage_start);
+	puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+	puts("\n");
+
+	if ( initrd_size ) {
+		puts("initrd at:     ");
+		puthex((unsigned long)(&__ramdisk_begin));
+		puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
+	}
+
+	/*
+	 * setup avail_ram - this is the first part of ram usable
+	 * by the uncompress code.  Anything after this program in RAM
+	 * is now fair game. -- Tom
+	 */
+	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
+
+	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
+	puthex((unsigned long)end_avail); puts("\n");
+	puts("\nLinux/PPC load: ");
+	cp = cmd_line;
+	/* This is where we try and pick the right command line for booting.
+	 * If we were given one at compile time, use it.  It Is Right.
+	 * If we weren't, see if we have a ramdisk.  If so, thats root.
+	 * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom
+	 */
+#ifdef CONFIG_CMDLINE_BOOL
+	memcpy (cmd_line, compiled_string, sizeof(compiled_string));
+#else
+	if ( initrd_size )
+		memcpy (cmd_line, ramroot_string, sizeof(ramroot_string));
+	else
+		memcpy (cmd_line, netroot_string, sizeof(netroot_string));
+#endif
+	while ( *cp )
+		putc(*cp++);
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_VGA_CONSOLE)
+	/*
+	 * If they have a console, allow them to edit the command line.
+	 * Otherwise, don't bother wasting the five seconds.
+	 */
+	while (timer++ < 5*1000) {
+		if (tstc()) {
+			while ((ch = getc()) != '\n' && ch != '\r') {
+				if (ch == '\b' || ch == '\177') {
+					if (cp != cmd_line) {
+						cp--;
+						puts("\b \b");
+					}
+				} else if (ch == '\030'		/* ^x */
+					   || ch == '\025') {	/* ^u */
+					while (cp != cmd_line) {
+						cp--;
+						puts("\b \b");
+					}
+				} else {
+					*cp++ = ch;
+					putc(ch);
+				}
+			}
+			break;  /* Exit 'timer' loop */
+		}
+		udelay(1000);  /* 1 msec */
+	}
+#endif
+	*cp = 0;
+	puts("\nUncompressing Linux...");
+
+	gunzip(0, 0x400000, zimage_start, &zimage_size);
+	flush_instruction_cache();
+	puts("done.\n");
+	{
+		struct bi_record *rec;
+
+		rec = (struct bi_record *)_ALIGN((unsigned long)zimage_size +
+				(1 << 20) - 1,(1 << 20));
+
+		rec->tag = BI_FIRST;
+		rec->size = sizeof(struct bi_record);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+		rec->tag = BI_CMD_LINE;
+		memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
+		rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+		if ( initrd_size ) {
+			rec->tag = BI_INITRD;
+			rec->data[0] = (unsigned long)(&__ramdisk_begin);
+			rec->data[1] = initrd_size;
+			rec->size = sizeof(struct bi_record) + 2 *
+				sizeof(unsigned long);
+			rec = (struct bi_record *)((unsigned long)rec +
+					rec->size);
+		}
+
+		rec->tag = BI_LAST;
+		rec->size = sizeof(struct bi_record);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+	puts("Now booting the kernel\n");
+#ifdef CONFIG_SERIAL_CONSOLE
+	serial_close(com_port);
+#endif
+
+	return (unsigned long)hold_residual;
+}
diff -Naru linux-2.4.20.orig/arch/ppc/config.in linux-2.4.20/arch/ppc/config.in
--- linux-2.4.20.orig/arch/ppc/config.in	2003-04-01 15:11:21.000000000 +0000
+++ linux-2.4.20/arch/ppc/config.in	2003-04-01 15:14:18.000000000 +0000
@@ -86,6 +86,8 @@
 	 Sycamore	CONFIG_SYCAMORE		\
 	 Tivo		CONFIG_TIVO 		\
 	 Walnut		CONFIG_WALNUT		\
+	 EBK405GPr	CONFIG_EBK405GPR	\
+	 OpenBlockS266	CONFIG_OPENBLOCKS266	\
 	 Xilinx-ML300	CONFIG_XILINX_ML300"	Walnut
 
    if [ "$CONFIG_EP405" = "y" ]; then
@@ -303,6 +305,20 @@
     define_bool CONFIG_IBM405_ERR77 y
     define_bool CONFIG_IBM_OCP y
   fi
+  if [ "$CONFIG_EBK405GPR" = "y" ]; then
+    define_bool CONFIG_405GP y
+    define_bool CONFIG_BIOS_FIXUP y
+    define_bool CONFIG_IBM_OPENBIOS y
+    define_bool CONFIG_IBM405_ERR77 y
+    define_bool CONFIG_IBM_OCP y
+  fi
+  if [ "$CONFIG_OPENBLOCKS266" = "y" ]; then
+    define_bool CONFIG_405GP y
+    define_bool CONFIG_BIOS_FIXUP y
+    define_bool CONFIG_IBM_OPENBIOS y
+    define_bool CONFIG_IBM405_ERR77 y
+    define_bool CONFIG_IBM_OCP y
+  fi
   if [ "$CONFIG_BEECH" = "y" ]; then
     define_bool CONFIG_405LP y
     define_bool CONFIG_IBM_OPENBIOS y
diff -Naru linux-2.4.20.orig/arch/ppc/configs/ebk405gpr_defconfig linux-2.4.20/arch/ppc/configs/ebk405gpr_defconfig
--- linux-2.4.20.orig/arch/ppc/configs/ebk405gpr_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/ebk405gpr_defconfig	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,538 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_440 is not set
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_PPC_ISERIES is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+CONFIG_EBK405GPR=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+# CONFIG_MATH_EMULATION is not set
+CONFIG_405GP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_IBM_OPENBIOS=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM_OCP=y
+# CONFIG_PM is not set
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_GEN550_KGDB=y
+CONFIG_IBM405_ERR51=y
+CONFIG_NOT_COHERENT_CACHE=y
+# CONFIG_PPC4xx_DMA is not set
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+CONFIG_PPC_RTC=y
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_IBM_OCP is not set
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_PROC is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+CONFIG_IBM_OCP_GPIO=y
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_SERIAL_TEXT_DEBUG=y
diff -Naru linux-2.4.20.orig/arch/ppc/configs/openblocks266_defconfig linux-2.4.20/arch/ppc/configs/openblocks266_defconfig
--- linux-2.4.20.orig/arch/ppc/configs/openblocks266_defconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/configs/openblocks266_defconfig	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,724 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_UID16 is not set
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Platform support
+#
+CONFIG_PPC=y
+CONFIG_PPC32=y
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_440 is not set
+# CONFIG_POWER3 is not set
+# CONFIG_8xx is not set
+# CONFIG_PPC_ISERIES is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_EBK405GPR is not set
+CONFIG_OPENBLOCKS266=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
+# CONFIG_SMP is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_405GP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_IBM_OPENBIOS=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM_OCP=y
+# CONFIG_PM is not set
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_GEN550_KGDB=y
+CONFIG_IBM405_ERR51=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
+
+#
+# General setup
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_PCI=y
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PPC_RTC is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_B1=y
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_REDWOOD=y
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_IDEDISK_STROKE=y
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
+# CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_AEC62XX_TUNING is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_CMD680 is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+CONFIG_BLK_DEV_HPT366=y
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_IBM_OCP_IDE is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Console drivers
+#
+
+#
+# Frame-buffer support
+#
+# CONFIG_FB is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Macintosh device drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_IBM_OCP=y
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_PROC is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_X1226_RTC=y
+CONFIG_I2C_EEPROM=y
+CONFIG_OBS_PUSHSW=y
+CONFIG_OBS_LED=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# IBM 4xx options
+#
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_HIGHMEM=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_IOVIRT=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Naru linux-2.4.20.orig/arch/ppc/defconfig linux-2.4.20/arch/ppc/defconfig
--- linux-2.4.20.orig/arch/ppc/defconfig	2002-12-11 02:37:23.000000000 +0000
+++ linux-2.4.20/arch/ppc/defconfig	2003-04-01 15:14:18.000000000 +0000
@@ -1,5 +1,5 @@
 #
-# Automatically generated make config: don't edit
+# Automatically generated by make menuconfig: don't edit
 #
 # CONFIG_UID16 is not set
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
@@ -10,48 +10,59 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
 
 #
 # Loadable module support
 #
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
 
 #
 # Platform support
 #
 CONFIG_PPC=y
 CONFIG_PPC32=y
-CONFIG_6xx=y
-# CONFIG_40x is not set
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_440 is not set
 # CONFIG_POWER3 is not set
 # CONFIG_8xx is not set
 # CONFIG_PPC_ISERIES is not set
-# CONFIG_8260 is not set
-CONFIG_PPC_STD_MMU=y
-CONFIG_ALL_PPC=y
-# CONFIG_APUS is not set
-# CONFIG_SPRUCE is not set
-# CONFIG_PCORE is not set
-# CONFIG_POWERPMC250 is not set
-# CONFIG_MENF1 is not set
-# CONFIG_LOPEC is not set
-# CONFIG_MCPN765 is not set
-# CONFIG_MVME5100 is not set
-# CONFIG_PRPMC750 is not set
-# CONFIG_PRPMC800 is not set
-# CONFIG_SANDPOINT is not set
-# CONFIG_ADIR is not set
-# CONFIG_K2 is not set
-# CONFIG_GEMINI is not set
-# CONFIG_WILLOW is not set
-# CONFIG_ZX4500 is not set
+CONFIG_4xx=y
+# CONFIG_PPC_STD_MMU is not set
+# CONFIG_ASH is not set
+# CONFIG_CEDER is not set
+# CONFIG_BEECH is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_OAK is not set
+# CONFIG_RAINIER is not set
+# CONFIG_REDWOOD_4 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_TIVO is not set
+# CONFIG_WALNUT is not set
+# CONFIG_EBK405GPR is not set
+CONFIG_OPENBLOCKS266=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_405GP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_IBM_OPENBIOS=y
+CONFIG_IBM405_ERR77=y
+CONFIG_IBM_OCP=y
+# CONFIG_PM is not set
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_GEN550_KGDB=y
+CONFIG_IBM405_ERR51=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_OCP_PROC=y
 
 #
 # General setup
@@ -62,6 +73,7 @@
 # CONFIG_SBUS is not set
 # CONFIG_MCA is not set
 CONFIG_PCI=y
+# CONFIG_PC_KEYBOARD is not set
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
@@ -69,32 +81,83 @@
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=m
-CONFIG_PCI_NAMES=y
-CONFIG_HOTPLUG=y
-
-#
-# PCMCIA/CardBus support
-#
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 
 #
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
-CONFIG_PPC_RTC=y
-CONFIG_PPC601_SYNC_FIX=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_PPC_RTAS=y
-CONFIG_PREP_RESIDUAL=y
-CONFIG_PROC_PREPRESIDUAL=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,9600 console=tty0 root=/dev/sda2"
+# CONFIG_PPC_RTC is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Memory Technology Devices (MTD)
 #
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_CFI_B1=y
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_REDWOOD=y
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
 
 #
 # Plug and Play configuration
@@ -105,7 +168,7 @@
 #
 # Block devices
 #
-CONFIG_BLK_DEV_FD=m
+# CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
@@ -116,8 +179,9 @@
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=32768
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -134,74 +198,30 @@
 #
 # Networking options
 #
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+# CONFIG_PACKET is not set
 # CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
-
-#
-#   IP: Netfilter Configuration
-#
-CONFIG_IP_NF_CONNTRACK=m
-CONFIG_IP_NF_FTP=m
-CONFIG_IP_NF_IRC=m
-# CONFIG_IP_NF_QUEUE is not set
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_LIMIT=m
-CONFIG_IP_NF_MATCH_MAC=m
-CONFIG_IP_NF_MATCH_MARK=m
-CONFIG_IP_NF_MATCH_MULTIPORT=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_AH_ESP=m
-CONFIG_IP_NF_MATCH_LENGTH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_TCPMSS=m
-CONFIG_IP_NF_MATCH_STATE=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
-CONFIG_IP_NF_NAT=m
-CONFIG_IP_NF_NAT_NEEDED=y
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-# CONFIG_IP_NF_NAT_LOCAL is not set
-CONFIG_IP_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_NAT_IRC=m
-CONFIG_IP_NF_NAT_FTP=m
-# CONFIG_IP_NF_MANGLE is not set
-# CONFIG_IP_NF_TARGET_LOG is not set
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_TARGET_TCPMSS=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_COMPAT_IPCHAINS=m
-CONFIG_IP_NF_NAT_NEEDED=y
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
-
-#
-#  
-#
 # CONFIG_IPX is not set
-CONFIG_ATALK=m
+# CONFIG_ATALK is not set
 
 #
 # Appletalk devices
@@ -237,15 +257,11 @@
 # IDE, ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
 # CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_IDEDISK_STROKE is not set
+CONFIG_IDEDISK_MULTI_MODE=y
+CONFIG_IDEDISK_STROKE=y
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -256,26 +272,22 @@
 # CONFIG_BLK_DEV_COMMERIAL is not set
 # CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
-CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
-CONFIG_BLK_DEV_IDEFLOPPY=y
-CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
 # CONFIG_BLK_DEV_CMD640 is not set
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
-# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
 # CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
@@ -287,13 +299,13 @@
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
-CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_CMD680 is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
-# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_HPT366=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
@@ -304,12 +316,8 @@
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_SL82C105=y
-CONFIG_BLK_DEV_IDE_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC=y
-CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_SL82C105 is not set
+# CONFIG_IBM_OCP_IDE is not set
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
@@ -322,89 +330,16 @@
 #
 # SCSI support
 #
-CONFIG_SCSI=y
+# CONFIG_SCSI is not set
 
 #
-# SCSI support type (disk, tape, CD-ROM)
+# Fusion MPT device support
 #
-CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=y
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=y
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_DEBUG_QUEUES is not set
-# CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AACRAID is not set
-CONFIG_SCSI_AIC7XXX=m
-CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY_MS=15000
-# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
-# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
-CONFIG_SCSI_AIC7XXX_OLD=m
-# CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT is not set
-CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
-CONFIG_AIC7XXX_OLD_PROC_STATS=y
-# CONFIG_SCSI_DPT_I2O is not set
-CONFIG_SCSI_ADVANSYS=m
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-CONFIG_SCSI_SYM53C8XX_2=y
-CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
-CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_DEBUG is not set
-CONFIG_SCSI_MESH=y
-CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
-CONFIG_SCSI_MAC53C94=y
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -412,6 +347,16 @@
 # CONFIG_IEEE1394 is not set
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -430,10 +375,9 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-CONFIG_MACE=y
-# CONFIG_MACE_AAUI_PORT is not set
-CONFIG_BMAC=y
-CONFIG_GMAC=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_GMAC is not set
 # CONFIG_SUNLANCE is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
@@ -446,18 +390,18 @@
 # CONFIG_HP100 is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 CONFIG_TULIP=y
-# CONFIG_TC35815 is not set
 # CONFIG_TULIP_MWI is not set
-CONFIG_TULIP_MMIO=y
-CONFIG_DE4X5=m
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 # CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -469,11 +413,13 @@
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_NEW_RX_RESET is not set
+# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -484,41 +430,39 @@
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
+
+#
+# Backplane Networking
+#
+# CONFIG_NPNET is not set
+
+#
+# On-chip net devices
+#
+CONFIG_IBM_OCP_ENET=y
+# CONFIG_IBM_OCP_ENET_ERROR_MSG is not set
+CONFIG_IBM_OCP_ENET_RX_BUFF=64
+CONFIG_IBM_OCP_ENET_TX_BUFF=8
+CONFIG_IBM_OCP_ENET_GAP=8
+CONFIG_IBM_OCP_ENET_SKB_RES=0
+CONFIG_OCP_NET=y
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
-CONFIG_PPP=y
-CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=y
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=y
-# CONFIG_PPP_BSDCOMP is not set
-# CONFIG_PPPOE is not set
+# CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
 #
 # Wireless LAN (non-hamradio)
 #
-CONFIG_NET_RADIO=y
-# CONFIG_STRIP is not set
-# CONFIG_WAVELAN is not set
-# CONFIG_ARLAN is not set
-# CONFIG_AIRONET4500 is not set
-# CONFIG_AIRONET4500_NONCS is not set
-# CONFIG_AIRONET4500_PROC is not set
-# CONFIG_AIRO is not set
-CONFIG_HERMES=m
-CONFIG_APPLE_AIRPORT=m
-# CONFIG_PLX_HERMES is not set
-# CONFIG_PCI_HERMES is not set
-CONFIG_NET_WIRELESS=y
+# CONFIG_NET_RADIO is not set
 
 #
 # Token Ring devices
@@ -556,170 +500,73 @@
 #
 # Console drivers
 #
-CONFIG_VGA_CONSOLE=y
 
 #
 # Frame-buffer support
 #
-CONFIG_FB=y
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_CLGEN is not set
-# CONFIG_FB_PM2 is not set
-# CONFIG_FB_PM3 is not set
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-CONFIG_FB_CONTROL=y
-CONFIG_FB_PLATINUM=y
-CONFIG_FB_VALKYRIE=y
-CONFIG_FB_CT65550=y
-CONFIG_FB_IMSTT=y
-# CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_VGA16 is not set
-CONFIG_FB_MATROX=y
-CONFIG_FB_MATROX_MILLENIUM=y
-CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
-# CONFIG_FB_MATROX_I2C is not set
-# CONFIG_FB_MATROX_G450 is not set
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-CONFIG_FB_ATY=y
-CONFIG_FB_ATY_GX=y
-CONFIG_FB_ATY_CT=y
-CONFIG_FB_RADEON=y
-CONFIG_FB_ATY128=y
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-CONFIG_FB_3DFX=y
-# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
-CONFIG_FBCON_CFB8=y
-CONFIG_FBCON_CFB16=y
-CONFIG_FBCON_CFB24=y
-CONFIG_FBCON_CFB32=y
-# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
-CONFIG_FBCON_FONTS=y
-# CONFIG_FONT_8x8 is not set
-CONFIG_FONT_8x16=y
-CONFIG_FONT_SUN8x16=y
-CONFIG_FONT_SUN12x22=y
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FB_COMPAT_XPMAC is not set
+# CONFIG_FB is not set
 
 #
 # Input core support
 #
-CONFIG_INPUT=y
-CONFIG_INPUT_KEYBDEV=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
-CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Macintosh device drivers
 #
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_PMU=y
-CONFIG_PMAC_PBOOK=y
-CONFIG_PM=y
-CONFIG_PMAC_APM_EMU=y
-CONFIG_PMAC_BACKLIGHT=y
-# CONFIG_MAC_FLOPPY is not set
-CONFIG_MAC_SERIAL=m
-CONFIG_ADB=y
-CONFIG_ADB_MACIO=y
-CONFIG_INPUT_ADBHID=y
-CONFIG_MAC_ADBKEYCODES=y
-CONFIG_MAC_EMUMOUSEBTN=y
-CONFIG_MAC_HID=y
-# CONFIG_ANSLCD is not set
 
 #
 # Character devices
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=m
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_BRIQ_PANEL is not set
 
 #
 # I2C support
 #
-CONFIG_I2C=m
+CONFIG_I2C=y
 # CONFIG_I2C_ALGOBIT is not set
 # CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_KEYWEST=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_PROC=m
+CONFIG_I2C_IBM_OCP=y
+# CONFIG_I2C_CHARDEV is not set
+# CONFIG_I2C_PROC is not set
 
 #
 # Mice
 #
-CONFIG_BUSMOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_LOGIBUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_MOUSE=y
-CONFIG_PSMOUSE=y
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
-# CONFIG_MK712_MOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
 
 #
 # Joysticks
 #
 # CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_INPUT_NS558 is not set
-# CONFIG_INPUT_LIGHTNING is not set
-# CONFIG_INPUT_PCIGAME is not set
-# CONFIG_INPUT_CS461X is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_INPUT_SERIO is not set
-# CONFIG_INPUT_SERPORT is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_ANALOG is not set
-# CONFIG_INPUT_A3D is not set
-# CONFIG_INPUT_ADI is not set
-# CONFIG_INPUT_COBRA is not set
-# CONFIG_INPUT_GF2K is not set
-# CONFIG_INPUT_GRIP is not set
-# CONFIG_INPUT_INTERACT is not set
-# CONFIG_INPUT_TMDC is not set
-# CONFIG_INPUT_SIDEWINDER is not set
-# CONFIG_INPUT_IFORCE_USB is not set
-# CONFIG_INPUT_IFORCE_232 is not set
-# CONFIG_INPUT_WARRIOR is not set
-# CONFIG_INPUT_MAGELLAN is not set
-# CONFIG_INPUT_SPACEORB is not set
-# CONFIG_INPUT_SPACEBALL is not set
-# CONFIG_INPUT_STINGER is not set
-# CONFIG_INPUT_DB9 is not set
-# CONFIG_INPUT_GAMECON is not set
-# CONFIG_INPUT_TURBOGRAFX is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-CONFIG_NVRAM=y
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+CONFIG_X1226_RTC=y
+CONFIG_I2C_EEPROM=y
+CONFIG_OBS_PUSHSW=y
+CONFIG_OBS_LED=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
+# CONFIG_IBM_OCP_GPIO is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -745,31 +592,36 @@
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=m
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+CONFIG_JBD_DEBUG=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
 CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=y
+# CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
+# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
@@ -790,9 +642,10 @@
 # CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
@@ -807,7 +660,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -817,7 +669,7 @@
 # CONFIG_OSF_PARTITION is not set
 # CONFIG_AMIGA_PARTITION is not set
 # CONFIG_ATARI_PARTITION is not set
-CONFIG_MAC_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
 CONFIG_MSDOS_PARTITION=y
 # CONFIG_BSD_DISKLABEL is not set
 # CONFIG_MINIX_SUBPARTITION is not set
@@ -827,207 +679,46 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-CONFIG_NLS_ISO8859_1=m
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
+# CONFIG_NLS is not set
 
 #
 # Sound
 #
-CONFIG_SOUND=m
-CONFIG_DMASOUND_PMAC=m
-CONFIG_DMASOUND=m
-CONFIG_I2C=m
-CONFIG_I2C_KEYWEST=m
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_MIDI_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_SONICVIBES is not set
-# CONFIG_SOUND_TRIDENT is not set
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_MIDI_VIA82CXXX is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_TVMIXER is not set
-
-#
-# USB support
-#
-CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
-# CONFIG_USB_LONG_TIMEOUT is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_UHCI is not set
-# CONFIG_USB_UHCI_ALT is not set
-CONFIG_USB_OHCI=y
-
-#
-# USB Device Class drivers
-#
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_EMI26 is not set
-# CONFIG_USB_BLUETOOTH is not set
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-CONFIG_USB_STORAGE_FREECOM=y
-# CONFIG_USB_STORAGE_ISD200 is not set
-CONFIG_USB_STORAGE_DPCM=y
-# CONFIG_USB_STORAGE_HP8200e is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-
-#
-# USB Human Interface Devices (HID)
-#
-CONFIG_USB_HID=y
-CONFIG_USB_HIDINPUT=y
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_WACOM is not set
+# CONFIG_SOUND is not set
 
 #
-# USB Imaging devices
+# IBM 4xx options
 #
-# CONFIG_USB_DC2XX is not set
-# CONFIG_USB_MDC800 is not set
-CONFIG_USB_SCANNER=m
-# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
 
 #
-# USB Multimedia devices
-#
-
-#
-#   Video4Linux support is needed for USB Multimedia device support
-#
-
-#
-# USB Network adaptors
-#
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_CDCETHER is not set
-# CONFIG_USB_USBNET is not set
-
-#
-# USB port drivers
-#
-# CONFIG_USB_USS720 is not set
-
-#
-# USB Serial Converter support
+# USB support
 #
-CONFIG_USB_SERIAL=m
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-CONFIG_USB_SERIAL_VISOR=m
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-CONFIG_USB_SERIAL_KEYSPAN=m
-CONFIG_USB_SERIAL_KEYSPAN_USA28=y
-CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-CONFIG_USB_SERIAL_KEYSPAN_USA19=y
-CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
-CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
-CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB is not set
 
 #
-# USB Miscellaneous drivers
+# Bluetooth support
 #
-# CONFIG_USB_RIO500 is not set
-# CONFIG_USB_AUERSWALD is not set
+# CONFIG_BLUEZ is not set
 
 #
-# Bluetooth support
+# Library routines
 #
-# CONFIG_BLUEZ is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
 
 #
 # Kernel hacking
 #
-CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_HIGHMEM=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_IOVIRT=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
 # CONFIG_KGDB is not set
-CONFIG_XMON=y
+# CONFIG_XMON is not set
 # CONFIG_BDI_SWITCH is not set
-CONFIG_BOOTX_TEXT=y
-# CONFIG_MORE_COMPILE_OPTIONS is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
diff -Naru linux-2.4.20.orig/arch/ppc/kernel/ppc405_pci.c linux-2.4.20/arch/ppc/kernel/ppc405_pci.c
--- linux-2.4.20.orig/arch/ppc/kernel/ppc405_pci.c	2002-12-11 02:39:15.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc405_pci.c	2003-04-01 15:14:18.000000000 +0000
@@ -147,7 +147,6 @@
 
 	pcip = ioremap((unsigned long) ocp_get_paddr(PCI, 0), PAGE_SIZE);
 	if (pcip != NULL) {
-
 #if defined(CONFIG_BIOS_FIXUP)
 		bios_fixup(hose_a, pcip);
 #endif
diff -Naru linux-2.4.20.orig/arch/ppc/kernel/ppc4xx_pic.c linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c
--- linux-2.4.20.orig/arch/ppc/kernel/ppc4xx_pic.c	2002-12-11 02:39:05.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc4xx_pic.c	2003-04-01 15:14:18.000000000 +0000
@@ -161,6 +161,16 @@
 #ifdef UIC_DEBUG
 	printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n", irq, word, bit);
 #endif
+
+#ifdef CONFIG_OPENBLOCKS266
+#define PUSHSW_INT	26
+	if (irq == PUSHSW_INT) {
+		/* printk(__FUNCTION__ ": TR=0x%08x\n", mfdcr(DCRN_UIC_TR(UIC0))); */
+		mtdcr(DCRN_UIC_TR(UIC0), 1 << (31 - PUSHSW_INT));
+		mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - PUSHSW_INT));
+	}
+#endif
+
 	ppc_cached_irq_mask[word] |= 1 << (31 - bit);
 	switch (word) {
 	case 0:
diff -Naru linux-2.4.20.orig/arch/ppc/kernel/ppc4xx_setup.c linux-2.4.20/arch/ppc/kernel/ppc4xx_setup.c
--- linux-2.4.20.orig/arch/ppc/kernel/ppc4xx_setup.c	2002-12-11 02:40:51.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/ppc4xx_setup.c	2003-04-01 15:14:18.000000000 +0000
@@ -89,6 +89,12 @@
 extern void board_setup_irq(void);
 extern void board_init(void);
 
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+#include <linux/delay.h>
+extern int obsled_out(int);
+#define BLINK_MSEC	(1000)
+#endif
+
 /* Global Variables */
 unsigned char __res[sizeof (bd_t)];
 
@@ -204,7 +210,16 @@
 {
 	printk("System Halted\n");
 	__cli();
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	while (1) {
+		obsled_out(7);
+		mdelay(BLINK_MSEC);
+		obsled_out(0);
+		mdelay(BLINK_MSEC);
+	}
+#else
 	while (1) ;
+#endif
 }
 
 static void
@@ -212,7 +227,16 @@
 {
 	printk("System Halted\n");
 	__cli();
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	while (1) {
+		obsled_out(7);
+		mdelay(BLINK_MSEC);
+		obsled_out(0);
+		mdelay(BLINK_MSEC);
+	}
+#else
 	while (1) ;
+#endif
 }
 
 static void __init
@@ -241,7 +265,8 @@
 	bd_t *bip = (bd_t *) __res;
 
 #if defined(CONFIG_WALNUT) || defined(CONFIG_CEDER) 	\
-	|| defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
+	|| defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE) \
+	|| defined(CONFIG_EBK405GPR) || defined(CONFIG_OPENBLOCKS266)
 	/* Openbios sets cpu  timers to CPU clk
 	 * we want to use the external clk 
 	 * DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
diff -Naru linux-2.4.20.orig/arch/ppc/kernel/todc_time.c linux-2.4.20/arch/ppc/kernel/todc_time.c
--- linux-2.4.20.orig/arch/ppc/kernel/todc_time.c	2002-12-11 02:39:06.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/todc_time.c	2003-04-01 15:14:18.000000000 +0000
@@ -194,14 +194,21 @@
 todc_time_init(void)
 {
 	static u_char	not_initialized = 1;
+	static char tmpbuf[10];
+	ppc_md.progress("todc_time_init:start\n", 0x332);
+	if(todc_info){
+	  sprintf(tmpbuf, "%x\n", (u32)todc_info->nvram_data);
+	  ppc_md.progress(tmpbuf , 0x332);
+	}
 
 	/* Make sure clocks are running */
 	if (not_initialized) {
 		u_char	cntl_b;
 
 		cntl_b = todc_read_val(todc_info->control_b);
-
+		ppc_md.progress("todc_time_init:read_val\n", 0x332);
 		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		ppc_md.progress("todc_time_init:MC146818\n", 0x332);
 			if ((cntl_b & 0x70) != 0x20) {
 				printk(KERN_INFO "TODC %s %s\n",
 					"real-time-clock was stopped.",
@@ -214,7 +221,7 @@
 		}
 		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
 			u_char	month;
-
+		ppc_md.progress("todc_time_init:DS1501\n", 0x332);
 			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
 			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
 
@@ -233,7 +240,7 @@
 		}
 		else { /* must be a m48txx type */
 			u_char	cntl_a;
-
+		ppc_md.progress("todc_time_init:M48TXX\n", 0x332);
 			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
 			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
 
@@ -261,7 +268,7 @@
 		not_initialized = 0;
 	}
 
-
+	ppc_md.progress("todc_time_init:end\n", 0x332);
 	return 0;
 }
 
diff -Naru linux-2.4.20.orig/arch/ppc/kernel/traps.c linux-2.4.20/arch/ppc/kernel/traps.c
--- linux-2.4.20.orig/arch/ppc/kernel/traps.c	2002-12-11 02:39:18.000000000 +0000
+++ linux-2.4.20/arch/ppc/kernel/traps.c	2003-04-01 15:14:18.000000000 +0000
@@ -13,6 +13,9 @@
  *
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
  *  and Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *     PlatHome <openlab.plathome.co.jp>
+ *             - Added dump_stack() as dummy.
  */
 
 /*
@@ -467,3 +470,9 @@
 void __init trap_init(void)
 {
 }
+
+void dump_stack(void)
+{
+       printk(KERN_NOTICE
+               "This architecture does not implement dump_stack()\n");
+}
diff -Naru linux-2.4.20.orig/arch/ppc/platforms/Makefile linux-2.4.20/arch/ppc/platforms/Makefile
--- linux-2.4.20.orig/arch/ppc/platforms/Makefile	2002-12-11 02:36:58.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/Makefile	2003-04-01 15:14:18.000000000 +0000
@@ -36,6 +36,8 @@
 obj-$(CONFIG_REDWOOD_5)		+= redwood5.o ibmstb4.o
 obj-$(CONFIG_REDWOOD_6)		+= redwood6.o ibmstbx25.o
 obj-$(CONFIG_WALNUT)		+= walnut.o ibm405gp.o
+obj-$(CONFIG_EBK405GPR)		+= ebk405gpr.o ibm405gpr.o
+obj-$(CONFIG_OPENBLOCKS266)	+= openblocks266.o ibm405gpr.o
 obj-$(CONFIG_ASH)		+= ash.o ibmnp405h.o
 obj-$(CONFIG_RAINIER)		+= rainier.o ibmnp4gs.o
 obj-$(CONFIG_APUS)		+= apus_setup.o
diff -Naru linux-2.4.20.orig/arch/ppc/platforms/ebk405gpr.c linux-2.4.20/arch/ppc/platforms/ebk405gpr.c
--- linux-2.4.20.orig/arch/ppc/platforms/ebk405gpr.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/ebk405gpr.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,258 @@
+/*
+ *
+ *    Copyright (c) 2003 AXE,Inc.
+ *    ebk405gpr.c: Based on walnut.c
+ *
+ *    Copyrigh t(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000-2002 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: MontaVista Software, Inc.  <source@mvista.com>
+ *
+ *    Module name: walnut.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      IBM PowerPC 4xx based boards. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ *      History: 11/09/2001 - armin
+ *      added board_init to add in additional instuctions needed during platfrom_init
+ *
+ *      01/22/2002 - Armin
+ *      converted pci to ocp
+ *
+ *
+ * Please read the COPYING file for all license details.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <platforms/ibm_ocp.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *kb_cs;
+void *kb_data;
+void *ebk405gpr_rtc_base;
+
+/* Some IRQs unique to EBK405GPr.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *      A       B       C       D
+	     */
+	{
+		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
+		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
+		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
+		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+board_setup_arch(void)
+{
+#define EBK405GPR_PS2_BASE		0xF0100000
+#define EBK405GPR_FPGA_BASE	0xF0300000
+
+	void *fpga_brdc;
+	unsigned char fpga_brdc_data;
+	void *fpga_enable;
+	void *fpga_polarity;
+	void *fpga_status;
+	void *fpga_trigger;
+	
+	kb_data = ioremap(EBK405GPR_PS2_BASE, 8);
+	if (!kb_data) {
+		printk(KERN_CRIT
+		       "ebk405gpr_setup_arch() kb_data ioremap failed\n");
+		return;
+	}
+
+	kb_cs = kb_data + 1;
+
+	fpga_status = ioremap(EBK405GPR_FPGA_BASE, 8);
+	if (!fpga_status) {
+		printk(KERN_CRIT
+		       "ebk405gpr_setup_arch() fpga_status ioremap failed\n");
+		return;
+	}
+
+
+	fpga_enable = fpga_status + 1;
+	fpga_polarity = fpga_status + 2;
+	fpga_trigger = fpga_status + 3;
+	fpga_brdc = fpga_status + 4;
+
+	/* split the keyboard and mouse interrupts */
+	fpga_brdc_data = readb(fpga_brdc);
+	fpga_brdc_data |= 0x80;
+	writeb(fpga_brdc_data, fpga_brdc);
+	writeb(0x3, fpga_enable);
+
+	writeb(0x3, fpga_polarity);
+
+	writeb(0x3, fpga_trigger);
+
+	/* RTC step for the EBK405GPr */
+	ebk405gpr_rtc_base = (void *) EBK405GPR_RTC_VADDR;
+	TODC_INIT(TODC_TYPE_DS1743, ebk405gpr_rtc_base, ebk405gpr_rtc_base,
+		  ebk405gpr_rtc_base, 8);
+
+	/* Identify the system */
+	printk("IBM EBK405GPr port\n");
+	/* printk("IBM Walnut port (C) 2000-2002 MontaVista Software, Inc. (source@mvista.com)\n"); */
+}
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+
+	unsigned int bar_response, bar;
+	/*
+	 * Expected PCI mapping:
+	 *
+	 *  PLB addr             PCI memory addr
+	 *  ---------------------       ---------------------
+	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
+	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
+	 *
+	 *  PLB addr             PCI io addr
+	 *  ---------------------       ---------------------
+	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
+	 *
+	 * The following code is simplified by assuming that the bootrom
+	 * has been well behaved in following this mapping.
+	 */
+
+#ifdef DEBUG
+	int i;
+
+	printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+	printk("PCI bridge regs before fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+	/* added for IBM boot rom version 1.15 bios bar changes  -AK */
+
+	/* Disable region first */
+	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+	/* PLB starting addr, PCI: 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+	/* PCI start addr, 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+	/* 512MB range of PLB to PCI */
+	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+	/* Enable no pre-fetch, enable region */
+	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+						(PPC405_PCI_UPPER_MEM -
+						 PPC405_PCI_MEM_BASE)) | 0x01));
+
+	/* Disable region one */
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+	/* Disable region two */
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+	/* Zero config bars */
+	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+		early_write_config_dword(hose, hose->first_busno,
+					 PCI_FUNC(hose->first_busno), bar,
+					 0x00000000);
+		early_read_config_dword(hose, hose->first_busno,
+					PCI_FUNC(hose->first_busno), bar,
+					&bar_response);
+		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+		    hose->first_busno, PCI_SLOT(hose->first_busno),
+		    PCI_FUNC(hose->first_busno), bar, bar_response);
+	}
+	/* end work arround */
+
+#ifdef DEBUG
+	printk("PCI bridge regs after fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+}
+
+void __init
+board_io_mapping(void)
+{
+	io_block_mapping(EBK405GPR_RTC_VADDR,
+			 EBK405GPR_RTC_PADDR, EBK405GPR_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+}
diff -Naru linux-2.4.20.orig/arch/ppc/platforms/ebk405gpr.h linux-2.4.20/arch/ppc/platforms/ebk405gpr.h
--- linux-2.4.20.orig/arch/ppc/platforms/ebk405gpr.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/ebk405gpr.h	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,92 @@
+/*
+ *
+ *    Copyright (c) 2003 AXE,Inc.
+ *    ebk405gpr.h: Based on walnut.h
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *
+ *    Module name: ppc405.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      based boards.
+ *
+ *      This includes:
+ *
+ *         405GP "Walnut" evaluation board
+ *
+ * Please read the COPYING file for all license details.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_EBK405GPR_H__
+#define __ASM_EBK405GPR_H__
+
+/* We have a 405GPr core */
+#include <platforms/ibm405gpr.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "EBK405GPr" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
+	unsigned char	 bi_pci_enetaddr[6];	/* PCI Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the IBM "EBK405GPr" 405GPr evaluation board.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *ebk405gpr_rtc_base;
+#define EBK405GPR_RTC_PADDR	((uint)0xf0000000)
+#define EBK405GPR_RTC_VADDR	EBK405GPR_RTC_PADDR
+#define EBK405GPR_RTC_SIZE	((uint)8*1024)
+
+/* ps2 keyboard and mouse */
+#define KEYBOARD_IRQ		25
+#define AUX_IRQ			26
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD		691200
+#endif
+
+#define EBK405GPR_PS2_BASE	0xF0100000
+#define EBK405GPR_FPGA_BASE	0xF0300000
+
+
+extern void *kb_cs;
+extern void *kb_data;
+#define kbd_read_input()	readb(kb_data)
+#define kbd_read_status()	readb(kb_cs)
+#define kbd_write_output(val)	writeb(val, kb_data)
+#define kbd_write_command(val)	writeb(val, kb_cs)
+
+#define PPC4xx_MACHINE_NAME	"IBM EBK405GPr"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_EBK405GPR_H__ */
+#endif /* __KERNEL__ */
diff -Naru linux-2.4.20.orig/arch/ppc/platforms/openblocks266.c linux-2.4.20/arch/ppc/platforms/openblocks266.c
--- linux-2.4.20.orig/arch/ppc/platforms/openblocks266.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/openblocks266.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,345 @@
+/*
+ *
+ *    Copyright (c) 2003 AXE,Inc.
+ *    openblocks266.c: Based on walnut.c
+ *
+ *    Copyrigh t(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000-2002 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: MontaVista Software, Inc.  <source@mvista.com>
+ *
+ *    Module name: walnut.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      IBM PowerPC 4xx based boards. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ *      History: 11/09/2001 - armin
+ *      added board_init to add in additional instuctions needed during platfrom_init
+ *
+ *      01/22/2002 - Armin
+ *      converted pci to ocp
+ *
+ *
+ * Please read the COPYING file for all license details.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <platforms/ibm_ocp.h>
+#include <asm/delay.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+void *kb_cs;
+void *kb_data;
+void *openblocks266_rtc_base;
+
+/* Some IRQs unique to OpenBlockS266.
+ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
+ */
+int __init
+ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *      A       B       C       D
+	     */
+	{
+		{28, 28, 28, 28},	/* IDSEL 1 - PCI slot 1 */
+		{29, 29, 29, 29},	/* IDSEL 2 - PCI slot 2 */
+		{30, 30, 30, 30},	/* IDSEL 3 - PCI slot 3 */
+		{31, 31, 31, 31},	/* IDSEL 4 - PCI slot 4 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+};
+
+void __init
+board_setup_arch(void)
+{
+#define OPENBLOCKS266_PS2_BASE		0xF0100000
+#define OPENBLOCKS266_FPGA_BASE	0xF0300000
+
+	void *fpga_brdc;
+	void *fpga_enable;
+	void *fpga_polarity;
+	void *fpga_status;
+	void *fpga_trigger;
+	
+	kb_data = ioremap(OPENBLOCKS266_PS2_BASE, 8);
+	if (!kb_data) {
+		printk(KERN_CRIT
+		       "openblocks266_setup_arch() kb_data ioremap failed\n");
+		return;
+	}
+
+	kb_cs = kb_data + 1;
+
+	fpga_status = ioremap(OPENBLOCKS266_FPGA_BASE, 8);
+	if (!fpga_status) {
+		printk(KERN_CRIT
+		       "openblocks266_setup_arch() fpga_status ioremap failed\n");
+		return;
+	}
+
+
+	fpga_enable = fpga_status + 1;
+	fpga_polarity = fpga_status + 2;
+	fpga_trigger = fpga_status + 3;
+	fpga_brdc = fpga_status + 4;
+
+	/* Identify the system */
+	printk("OpenBlockS port\n");
+	/* printk("IBM Walnut port (C) 2000-2002 MontaVista Software, Inc. (source@mvista.com)\n"); */
+}
+
+#ifdef NEVER
+static void obs_dump_pci_conf(struct pci_controller *hose, int bus, int devfn)
+{
+	u8 addr;
+	u32 buf;
+	printk("OpenBlockS: PCI configuration register dump (bus:%d,dev:%d,fn:%d)\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	for( addr=0; addr<0x80; addr+=4 ){
+		if( early_read_config_dword(hose, bus, devfn, addr, &buf) ){
+			printk("OpenBlockS: read error PCI:(bus:%d,dev:%d,fn:%d,addr:0x%02x)\n", bus, PCI_SLOT(devfn), PCI_FUNC(devfn), addr);
+		}
+		if( addr % 16 == 0 )
+			printk("%02x:", addr);
+		printk(" %08x", buf);
+		if( addr % 16 == 12 )
+			printk("\n");
+	}
+}
+#endif
+
+static void obs_reset_pci_bus(struct pci_controller *hose)
+{
+	u16 brdgopt2;
+
+	/* obs_dump_pci_conf(hose, 0, PCI_DEVFN(0,0)); */
+	if( early_read_config_word(hose, 0, PCI_DEVFN(0,0), 0x60, &brdgopt2) ){
+		printk("OpenBlockS: read error PCI:(bus:%d,dev:%d,fn:%d,addr:%02x)\n", 0,0,0, 0x60);
+		return;
+	}
+	if( early_write_config_word(hose, 0, PCI_DEVFN(0,0), 0x60, brdgopt2 | 0x1000) ){
+		printk("OpenBlockS: read error PCI:(bus:%d,dev:%d,fn:%d,addr:%02x)\n", 0,0,0, 0x60);
+		return;
+	}
+
+	udelay(1000); udelay(1000); udelay(1000); udelay(1000);
+
+	if( early_write_config_word(hose, 0, PCI_DEVFN(0,0), 0x60, (brdgopt2 & ~0x1000) & 0xffff) ){
+		printk("OpenBlockS: read error PCI:(bus:%d,dev:%d,fn:%d,addr:%02x)\n", 0,0,0, 0x60);
+
+	}
+}
+
+#ifdef NEVER
+static void obs_hpt371_dump_pci_conf(struct pci_controller *hose)
+{
+	obs_dump_pci_conf(hose, 0, PCI_DEVFN(3,0));
+}
+
+static void obs_hpt371_load_vender_id(struct pci_controller *hose)
+{
+	u32 ids;
+	u8 reg7bh;
+
+	if( early_read_config_dword(hose, 0, PCI_DEVFN(3,0), PCI_VENDOR_ID, &ids) ){
+		printk("OpenBlockS: HPT371: read error 1\n");
+		return;
+	}
+	if( ids == 0xffffffff || ids == 0x00000000 || ids == 0x0000ffff || ids == 0xffff0000 ){
+		printk("OpenBlockS: HPT371: not found device\n");
+		return;
+	}
+	if( ids == 0x00071103 ){
+#ifdef DEBUG
+		printk("OpenBlockS: HPT371: no need loading Vender ID\n");
+#endif
+		return;
+	}
+
+	if( early_read_config_byte(hose, 0, PCI_DEVFN(3,0), 0x7b, &reg7bh) ){
+		printk("OpenBlockS: HPT371: read error\n");
+		return;
+	}
+	printk("OpenBlockS: HPT371: try to change Vender ID %08x --> %08x\n", ids, 0x00071103);
+	if( early_write_config_byte(hose, 0, PCI_DEVFN(3,0), 0x7b, reg7bh | 0x40) ){
+		printk("OpenBlockS: HPT371: write error\n");
+		return;
+	}
+	if( early_write_config_dword(hose, 0, PCI_DEVFN(3,0), PCI_VENDOR_ID, 0x00071103) ){
+		printk("OpenBlockS: HPT371: write error\n");
+		return;
+	}
+	if( early_write_config_byte(hose, 0, PCI_DEVFN(3,0), 0x7b, reg7bh & ~0x40) ){
+		printk("OpenBlockS: HPT371: read error\n");
+		return;
+	}
+	if( early_read_config_dword(hose, 0, PCI_DEVFN(3,0), 0x00, &ids) ){
+		printk("OpenBlockS: HPT371: read error\n");
+		return;
+	}
+	if( ids != 0x00071103 ){
+		printk("OpenBlockS: HPT371: fail to set Vender ID (%08x)\n", ids);
+		return;
+	}
+}
+#endif /* NEVER */
+
+void __init
+bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
+{
+	/* Aviod a HPT371 vender ID broken problem in restart machine */
+	obs_reset_pci_bus(hose);
+
+	/* obs_hpt371_dump_pci_conf(hose); */
+	/* obs_hpt371_load_vender_id(hose);*/ /* Don't work... */
+
+#ifdef NEVER	/* OpenBlockS bios fixup is done at 405GPr ROM Monitor */
+	unsigned int bar_response, bar;
+	/*
+	 * Expected PCI mapping:
+	 *
+	 *  PLB addr             PCI memory addr
+	 *  ---------------------       ---------------------
+	 *  0000'0000 - 7fff'ffff <---  0000'0000 - 7fff'ffff
+	 *  8000'0000 - Bfff'ffff --->  8000'0000 - Bfff'ffff
+	 *
+	 *  PLB addr             PCI io addr
+	 *  ---------------------       ---------------------
+	 *  e800'0000 - e800'ffff --->  0000'0000 - 0001'0000
+	 *
+	 * The following code is simplified by assuming that the bootrom
+	 * has been well behaved in following this mapping.
+	 */
+
+#ifdef DEBUG
+	int i;
+
+	printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
+	printk("PCI bridge regs before fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+
+	/* added for IBM boot rom version 1.15 bios bar changes  -AK */
+
+	/* Disable region first */
+	out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
+	/* PLB starting addr, PCI: 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
+	/* PCI start addr, 0x80000000 */
+	out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
+	/* 512MB range of PLB to PCI */
+	out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
+	/* Enable no pre-fetch, enable region */
+	out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
+						(PPC405_PCI_UPPER_MEM -
+						 PPC405_PCI_MEM_BASE)) | 0x01));
+
+	/* Disable region one */
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm1ms), 0x00000000);
+
+	/* Disable region two */
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
+	out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
+	out_le32((void *) &(pcip->ptm2ms), 0x00000000);
+
+	/* Zero config bars */
+	for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
+		early_write_config_dword(hose, hose->first_busno,
+					 PCI_FUNC(hose->first_busno), bar,
+					 0x00000000);
+		early_read_config_dword(hose, hose->first_busno,
+					PCI_FUNC(hose->first_busno), bar,
+					&bar_response);
+		DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
+		    hose->first_busno, PCI_SLOT(hose->first_busno),
+		    PCI_FUNC(hose->first_busno), bar, bar_response);
+	}
+	/* end work arround */
+
+#ifdef DEBUG
+	printk("PCI bridge regs after fixup \n");
+	for (i = 0; i <= 3; i++) {
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
+		printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
+	}
+	printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
+	printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
+	printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
+	printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
+
+#endif
+#endif /* NEVER */
+}
+
+void __init
+board_io_mapping(void)
+{
+	io_block_mapping(OPENBLOCKS266_RTC_VADDR,
+			 OPENBLOCKS266_RTC_PADDR, OPENBLOCKS266_RTC_SIZE, _PAGE_IO);
+}
+
+void __init
+board_setup_irq(void)
+{
+}
+
+void __init
+board_init(void)
+{
+	ppc_md.time_init = NULL;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.nvram_read_val = NULL;
+	ppc_md.nvram_write_val = NULL;
+}
diff -Naru linux-2.4.20.orig/arch/ppc/platforms/openblocks266.h linux-2.4.20/arch/ppc/platforms/openblocks266.h
--- linux-2.4.20.orig/arch/ppc/platforms/openblocks266.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/arch/ppc/platforms/openblocks266.h	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,92 @@
+/*
+ *
+ *    Copyright (c) 2003 AXE,Inc.
+ *    openblocks266.h: Based on walnut.h
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *
+ *    Module name: ppc405.h
+ *
+ *    Description:
+ *      Macros, definitions, and data structures specific to the IBM PowerPC
+ *      based boards.
+ *
+ *      This includes:
+ *
+ *         405GP "Walnut" evaluation board
+ *
+ * Please read the COPYING file for all license details.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_OPENBLOCKS266_H__
+#define __ASM_OPENBLOCKS266_H__
+
+/* We have a 405GPr core */
+#include <platforms/ibm405gpr.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * Data structure defining board information maintained by the boot
+ * ROM on IBM's "Walnut" evaluation board. An effort has been made to
+ * keep the field names consistent with the 8xx 'bd_t' board info
+ * structures.
+ */
+
+typedef struct board_info {
+	unsigned char	 bi_s_version[4];	/* Version of this structure */
+	unsigned char	 bi_r_version[30];	/* Version of the IBM ROM */
+	unsigned int	 bi_memsize;		/* DRAM installed, in bytes */
+	unsigned char	 bi_enetaddr[6];	/* Local Ethernet MAC address */
+	unsigned char	 bi_pci_enetaddr[6];	/* PCI Ethernet MAC address */
+	unsigned int	 bi_intfreq;		/* Processor speed, in Hz */
+	unsigned int	 bi_busfreq;		/* PLB Bus speed, in Hz */
+	unsigned int	 bi_pci_busfreq;	/* PCI Bus speed, in Hz */
+} bd_t;
+
+/* Some 4xx parts use a different timebase frequency from the internal clock.
+*/
+#define bi_tbfreq bi_intfreq
+
+
+/* Memory map for the OpenBlockS266.
+ * Generic 4xx plus RTC.
+ */
+
+extern void *openblocks266_rtc_base;
+#define OPENBLOCKS266_RTC_PADDR	((uint)0xf0000000)
+#define OPENBLOCKS266_RTC_VADDR	OPENBLOCKS266_RTC_PADDR
+#define OPENBLOCKS266_RTC_SIZE	((uint)8*1024)
+
+/* ps2 keyboard and mouse */
+#define KEYBOARD_IRQ		25
+#define AUX_IRQ			26
+
+#ifdef CONFIG_PPC405GP_INTERNAL_CLOCK
+#define BASE_BAUD		201600
+#else
+#define BASE_BAUD               (7372800/16)
+#endif
+
+#define OPENBLOCKS266_PS2_BASE	0xF0100000
+#define OPENBLOCKS266_FPGA_BASE	0xF0300000
+
+
+extern void *kb_cs;
+extern void *kb_data;
+#define kbd_read_input()	readb(kb_data)
+#define kbd_read_status()	readb(kb_cs)
+#define kbd_write_output(val)	writeb(val, kb_data)
+#define kbd_write_command(val)	writeb(val, kb_cs)
+
+#define PPC4xx_MACHINE_NAME	"OpenBlockS266"
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_OPENBLOCKS266_H__ */
+#endif /* __KERNEL__ */
diff -Naru linux-2.4.20.orig/drivers/char/Config.in linux-2.4.20/drivers/char/Config.in
--- linux-2.4.20.orig/drivers/char/Config.in	2002-12-11 02:39:52.000000000 +0000
+++ linux-2.4.20/drivers/char/Config.in	2003-04-01 15:14:18.000000000 +0000
@@ -272,6 +272,16 @@
 if [ "$CONFIG_PPC_ISERIES" != "y"  -a "$CONFIG_PPC_PSERIES" != "y" ]; then
    tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 fi   
+
+if [ "$CONFIG_I2C" = "y" ]; then
+	tristate 'X1226 RTC support' CONFIG_X1226_RTC
+	tristate 'I2C EEPROM support' CONFIG_I2C_EEPROM
+fi
+
+if [ "$CONFIG_OPENBLOCKS266" = "y" ]; then
+	tristate 'OpenBlockS Push button' CONFIG_OBS_PUSHSW
+	tristate 'OpenBlockS LED' CONFIG_OBS_LED
+fi
 if [ "$CONFIG_IA64" = "y" ]; then
    bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
 fi
diff -Naru linux-2.4.20.orig/drivers/char/Makefile linux-2.4.20/drivers/char/Makefile
--- linux-2.4.20.orig/drivers/char/Makefile	2002-12-11 02:39:46.000000000 +0000
+++ linux-2.4.20/drivers/char/Makefile	2003-04-01 15:14:18.000000000 +0000
@@ -228,12 +228,15 @@
 ifeq ($(CONFIG_ALL_PPC),)
   obj-$(CONFIG_NVRAM) += nvram.o
 endif
+obj-$(CONFIG_X1226_RTC) += x1226-rtc.o
+obj-$(CONFIG_I2C_EEPROM) += eepromi2c.o
+obj-$(CONFIG_OBS_PUSHSW) += pushsw.o
+obj-$(CONFIG_OBS_LED) += obs_led.o
 obj-$(CONFIG_TOSHIBA) += toshiba.o
 obj-$(CONFIG_I8K) += i8k.o
 obj-$(CONFIG_DS1620) += ds1620.o
 obj-$(CONFIG_INTEL_RNG) += i810_rng.o
 obj-$(CONFIG_AMD_RNG) += amd768_rng.o
-obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
 obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
 
 obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
diff -Naru linux-2.4.20.orig/drivers/char/eepromi2c.c linux-2.4.20/drivers/char/eepromi2c.c
--- linux-2.4.20.orig/drivers/char/eepromi2c.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/eepromi2c.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,444 @@
+/*
+ *  linux/drivers/char/eepromi2c.c
+ *
+ *
+ *  Copyright 
+ *  Author: 2002 AXE Inc.  
+ *     	takawata@axe-inc.co.jp
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  TODO:
+ *    - implement alarm and periodic IRQ support.
+ *
+ */
+/*
+ *  Based On 
+ *  linux/drivers/char/x1226-rtc.c
+ *
+ *  I2C Real Time Clock Client Driver for Xicor X1226 RTC/Calendar
+ *
+ *  Copyright 2002 MontaVista Software Inc.
+ *  Author: MontaVista Software, Inc.
+ *     	stevel@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  TODO:
+ *    - implement alarm and periodic IRQ support.
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <linux/devfs_fs_kernel.h>
+
+#define EEPROM_MAJOR 240
+struct eepromi2c_private
+{
+	u8 ei2_addr;
+	int ei2_size;
+	int ei2_maxpage;
+	int use_count;
+	unsigned char *tmpbuf;
+	struct i2c_client *ei2_i2c;
+	devfs_handle_t ei2_dfsh;
+};
+static spinlock_t eeprom_state_lock = SPIN_LOCK_UNLOCKED;
+
+
+struct eepromi2c_private eepromi2c_conf[]=
+{
+	{0x57, 0x200, 64, 0, NULL, NULL, NULL},
+	{0x51, 0x2000, 32, 0, NULL, NULL, NULL}
+};
+
+#define MAXEEPROMDEVS (sizeof(eepromi2c_conf)/ sizeof(struct eepromi2c_private))
+#ifndef I2C_DRIVER_ID_LARGEEEPROM
+#define I2C_DRIVERID_LARGEEEPROM I2C_DRIVERID_EXP1
+#endif
+#ifndef I2C_M_WR
+#define I2C_M_WR 0x0
+#endif
+
+#ifdef DEBUG_I2CEEPROM
+#define	dbg(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
+#else
+#define	dbg(fmt, args...)
+#endif
+
+#define I2CEEPROM_MODULE_NAME "LARGEEEPROM"
+#define PFX I2CEEPROM_MODULE_NAME
+
+#define err(format, arg...) printk(KERN_ERR PFX ": " format , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format , ## arg)
+#define emerg(format, arg...) printk(KERN_EMERG PFX ": " format , ## arg)
+
+static struct i2c_driver i2ceeprom_driver;
+
+static int i2ceeprom_read(struct i2c_client *client,
+			  u16 reg_offset, u8 *buf, int len)
+{
+	int ret;
+	u8 regbuf[2] = { reg_offset>>8, reg_offset };
+	struct i2c_msg random_addr_read[2] = {
+		{
+			/* "Set Current Address" */
+			client->addr,
+			client->flags | I2C_M_WR,
+			sizeof(regbuf),
+			regbuf
+		},
+		{
+			/* "Sequential Read" if len>1,
+			   "Current Address Read" if len=1 */
+			client->addr ,
+			client->flags| I2C_M_RD ,
+			len,
+			buf
+		}
+	};
+
+	if ((ret = i2c_transfer(client->adapter, random_addr_read, 2)) != 2) {
+		ret = -ENXIO;
+		dbg("i2c_transfer failed\n");
+	}
+
+	return ret;
+}
+
+static int i2ceeprom_write(struct i2c_client *client,
+			   u16 reg_offset, u8 *buf, int len)
+{
+	int ret;
+	u8* local_buf;
+	u8 regbuf[2] = { reg_offset>>8, reg_offset };
+	struct i2c_msg page_write = {
+		client->addr,
+		client->flags ,
+		len + sizeof(regbuf),
+		NULL
+	};
+
+	if ((local_buf = (u8*)kmalloc(len + sizeof(regbuf),
+				      GFP_KERNEL)) == NULL) {
+		err("buffer alloc failed\n");
+		return -ENOMEM;
+	}
+
+	memcpy(local_buf, regbuf, sizeof(regbuf));
+	memcpy(local_buf + sizeof(regbuf), buf, len);
+	page_write.buf = local_buf;
+	
+	if ((ret = i2c_transfer(client->adapter, &page_write, 1)) != 1) {
+		ret = -ENXIO;
+		dbg("i2c_transfer failed\n");
+	}
+
+	kfree(local_buf);
+	return ret;
+}
+
+static long long eepromi2c_llseek(struct file *file, loff_t offset, int origin)
+{
+	int minor;
+	struct inode *minode = file->f_dentry->d_inode;
+	struct eepromi2c_private *pri;
+
+	if ((minor = MINOR(minode->i_rdev)) >= MAXEEPROMDEVS)
+		return -ENXIO;
+	pri = &eepromi2c_conf[minor];
+	switch (origin) {
+	case 0:
+		file->f_pos = offset;
+		return file->f_pos;
+	case 1:
+		file->f_pos += offset;
+		return file->f_pos;
+	case 2:
+		file->f_pos = pri->ei2_size - offset;
+		return file->f_pos;
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t eepromi2c_read(struct file *file, char *buf, size_t count,
+			      loff_t *ppos)
+{
+	int minor;
+	struct i2c_client *client;
+	struct eepromi2c_private *pri;
+	int offset, remaining, copysize;
+	struct inode *minode = file->f_dentry->d_inode;
+	if ((minor = MINOR(minode->i_rdev)) >= MAXEEPROMDEVS)
+		return -ENXIO;
+	pri = &eepromi2c_conf[minor];
+	if (!(client = pri->ei2_i2c))
+		return -ENXIO;
+	offset = *ppos;
+	if ((offset + count) > pri->ei2_size)
+		count = pri->ei2_size - offset;
+	if (count <= 0) {
+		return 0;
+	}
+	remaining = count;
+	do {
+		copysize = (remaining > pri->ei2_maxpage)
+				? pri->ei2_maxpage : remaining;
+		dbg("; copysize=%d\n", copysize);	
+		i2ceeprom_read(client, offset, pri->tmpbuf, copysize);
+		if (copy_to_user(buf, pri->tmpbuf, copysize))
+			return -EFAULT;
+		*ppos += copysize;
+		offset += copysize;
+		buf += copysize;
+		remaining -= copysize;
+	} while (remaining > 0);
+	return count;
+}
+
+static ssize_t eepromi2c_write(struct file *file, const char *buf, size_t count,
+			       loff_t *ppos)
+{
+	int minor;
+	struct i2c_client *client;
+	struct eepromi2c_private *pri;
+	int offset, remaining, copysize;
+	struct inode *minode = file->f_dentry->d_inode;
+	if ((minor = MINOR(minode->i_rdev)) >= MAXEEPROMDEVS)
+		return -ENXIO;
+	pri = &eepromi2c_conf[minor];
+	if (!(client = pri->ei2_i2c))
+		return -ENXIO;
+	offset = *ppos;
+	if ((offset + count) > pri->ei2_size)
+		count = pri->ei2_size - offset;
+	if (count <= 0) {
+		return 0;
+	}
+	/*Write regeon should be aligned */
+	copysize = (count > pri->ei2_maxpage) ? pri->ei2_maxpage : count;
+	if ((offset / pri->ei2_maxpage) !=
+	    ((offset + copysize) / pri->ei2_maxpage))
+		copysize = pri->ei2_maxpage - (offset % pri->ei2_maxpage);
+	dbg("; offset=%d\n", offset);
+	remaining = count;
+	do {
+		dbg("; copysize=%d\n", copysize);
+		if (copy_from_user(pri->tmpbuf, buf, copysize)) {
+			return -EFAULT;
+		}
+
+		i2ceeprom_write(client, offset, pri->tmpbuf, copysize);
+		*ppos += copysize;
+		offset += copysize;
+		buf += copysize;
+		remaining -= copysize;
+		copysize = (remaining > pri->ei2_maxpage)
+				? pri->ei2_maxpage : remaining;
+	} while (remaining > 0);
+	return count;
+}
+
+int eepromi2c_open(struct inode *minode, struct file *mfile)
+{
+	int minor;
+	spin_lock(&eeprom_state_lock);
+	if ((minor = MINOR(minode->i_rdev)) >= MAXEEPROMDEVS)
+		return -ENXIO;
+	if (!eepromi2c_conf[minor].ei2_i2c)
+		return -ENXIO;
+
+	if (eepromi2c_conf[minor].use_count)
+		return -EBUSY;
+	eepromi2c_conf[minor].use_count++;
+	spin_unlock(&eeprom_state_lock);
+	return 0;
+}
+
+static int eepromi2c_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	return -ENOTTY;
+}
+
+static int eepromi2c_release(struct inode *inode, struct file *file)
+{
+	int minor;
+	spin_lock(&eeprom_state_lock);
+	if ((minor = MINOR(inode->i_rdev)) >= MAXEEPROMDEVS)
+		return -ENXIO;
+	eepromi2c_conf[minor].use_count--;
+	spin_unlock(&eeprom_state_lock);
+	return 0;
+}
+
+static struct file_operations eepromi2c_fops = {
+	owner:		THIS_MODULE,
+	llseek:		eepromi2c_llseek,
+	read:		eepromi2c_read,
+	write:		eepromi2c_write,
+	ioctl:		eepromi2c_ioctl,
+	open:		eepromi2c_open,
+	release:	eepromi2c_release,
+};
+
+
+
+
+static int i2ceeprom_probe(struct i2c_adapter *adap)
+{
+	int ret, res, i;
+#if 0
+	char nbuffer[15];
+#endif
+	unsigned char stat;
+	struct i2c_client *this_client;
+
+	res = -ENXIO;
+	devfs_register_chrdev(EEPROM_MAJOR, "eepromi2c", &eepromi2c_fops);
+
+	this_client = kmalloc(sizeof(*this_client), GFP_KERNEL);
+
+	for (i = 0; i < MAXEEPROMDEVS; i++) {
+		if (this_client == NULL) {
+			break;
+		}
+		strcpy(this_client->name, I2CEEPROM_MODULE_NAME);
+		this_client->id = i2ceeprom_driver.id;
+		this_client->flags = 0;
+		this_client->addr = eepromi2c_conf[i].ei2_addr;
+		this_client->adapter = adap;
+		this_client->driver = &i2ceeprom_driver;
+
+		if ((res = i2ceeprom_read(this_client, 0, &stat, 1)) < 0) {
+			printk("Probe read %d\n", res);
+			continue;
+		}
+
+		if ((eepromi2c_conf[i].tmpbuf =
+		     kmalloc(eepromi2c_conf[i].ei2_size, GFP_KERNEL)) == NULL) {
+			continue;
+		}
+
+		printk("Serial EEPROM FOUND at %x\n", this_client->addr);
+		if (i2c_attach_client(this_client)) {
+			continue;
+		}
+#if 0
+		/*DEVFS NOT SUPPORTED YET */
+		sprintf(buffer, "eepromi2c%d", i);
+		eepromi2c_conf[i].ei2_dfsh =
+			devfs_register(NULL, nbuffer, DEVFS_FL_DEFAULT,
+				       EEPROM_MAJOR, 2, S_IFCHR,
+				       &eepromi2c_fops, NULL);
+#endif
+		this_client->data = &eepromi2c_conf[i];
+		eepromi2c_conf[i].ei2_i2c = this_client;
+		ret = 0;	/*At least 1 dev found */
+		this_client = kmalloc(sizeof(*this_client), GFP_KERNEL);
+	}
+	kfree(this_client);
+	return ret;
+}
+
+static int i2ceeprom_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+
+	kfree(client);
+
+	return 0;
+}
+
+static int i2ceeprom_command(struct i2c_client *client, unsigned int cmd,
+			     void *arg)
+{
+
+	return -EINVAL;
+}
+
+
+static struct i2c_driver i2ceeprom_driver = {
+	name:		I2CEEPROM_MODULE_NAME,
+	id:		I2C_DRIVERID_LARGEEEPROM,
+	flags:		I2C_DF_NOTIFY,
+	attach_adapter:	i2ceeprom_probe,
+	detach_client:	i2ceeprom_detach,
+	command:	i2ceeprom_command
+};
+
+
+static __init int i2ceeprom_init(void)
+{
+	int ret;
+	
+	info("I2C based EEPROM driver.\n");
+	ret = i2c_add_driver(&i2ceeprom_driver);
+	if (ret) {
+		err("Register I2C driver failed, errno is %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void __exit i2ceeprom_exit(void)
+{
+	i2c_del_driver(&i2ceeprom_driver);
+}
+
+module_init(i2ceeprom_init);
+module_exit(i2ceeprom_exit);
diff -Naru linux-2.4.20.orig/drivers/char/obs_led.c linux-2.4.20/drivers/char/obs_led.c
--- linux-2.4.20.orig/drivers/char/obs_led.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/obs_led.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) AXE,Inc.
+ *	Based on ibm_ocp_gpio.c
+ */
+/*
+ * FILE NAME ibm_ocp_gpio.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *  API for IBM PowerPC 4xx GPIO device.
+ *  Driver for IBM PowerPC 4xx GPIO device.
+ *
+ *  Armin Kuster akuster@pacbell.net
+ *  Sept, 2001
+ *
+ *  Orignial driver
+ *  Author: MontaVista Software, Inc.  <source@mvista.com>
+ *          Frank Rowand <frank_rowand@mvista.com>
+ *          Debbie Chu   <debbie_chu@mvista.com>
+ *
+ * Copyright 2000,2001,2002 MontaVista Software Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE	LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *	TODO: devfs
+ *
+ *	Version: 02/01/12 - Armin
+ *			 converted to ocp and using ioremap
+ *
+ *	1.2 02/21/01 - Armin
+ *		minor compiler warning fixes
+ *
+ *	1.3 02/22/01 - Armin
+ *		added apm
+ *
+ *	1.4 05/07/02 - Armin/David Mueller
+ *		coverted to core_ocp[];
+ *
+ *	1.5 05/25/02 - Armin
+ *	 name change from *_driver to *_dev
+ *
+ *	1.6 06/04/02 - Matt Porter
+ *	ioremap paddr. Comment as 4xx generic driver.
+ *	Fix header to be userland safe and locate in
+ *	an accessible area.  Add ioctl to configure
+ *	multiplexed GPIO pins.
+ *
+ *	1.7 07/25/02 - Armin
+ *	added CPM to enable/disable in init/exit
+ *
+ */
+
+#define OBSLED_VER	"0.01"
+#define OBSLED_MINOR	171
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/pm.h>
+#include <linux/ibm_ocp_gpio.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ocp.h>
+
+struct miscdevice obsled_miscdev;
+static struct gpio_regs *gpiop;
+static int is_open = 0;
+
+#define GPIO_BIT(n)	(1 << (31 - (n)))
+#define PAT_1	GPIO_BIT(12)
+#define PAT_2	GPIO_BIT(13)
+#define PAT_4	GPIO_BIT(14)
+
+#ifdef CONFIG_PM
+static struct pm_dev *pm_gpio;
+
+static int
+gpio_save_state(u32 state)
+{
+	return 0;
+}
+
+static int
+gpio_suspend(u32 state)
+{
+	mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | state);
+	return 0;
+}
+
+static int
+gpio_resume(u32 state)
+{
+	mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~state);
+	return 0;
+}
+#endif
+
+static int
+obsled_out_reg(int led, u32 *or, u32 *tcr)
+{
+	__u32 data;
+	__u32 mask = PAT_1 | PAT_2 | PAT_4;
+	data = 0;
+	if (led & 1) data |= PAT_1;
+	if (led & 2) data |= PAT_2;
+	if (led & 4) data |= PAT_4;
+
+	*or = (*or & ~mask) | ((~data) & mask);
+	eieio();
+	*tcr = *tcr | mask;
+	eieio();
+	return 0;
+}
+
+int
+obsled_out_pat(int led)
+{
+#ifdef CONFIG_PM
+	pm_access(pm_gpio);
+#endif
+	return obsled_out_reg(led, &gpiop->or, &gpiop->tcr);
+}
+
+static int
+obsled_open(struct inode *inode, struct file *file)
+{
+	if (is_open) return -EALREADY;
+	is_open = 1;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+obsled_release(struct inode *inode, struct file *file)
+{
+	is_open = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static ssize_t obsled_write(struct file *file, const char *buf, size_t count,
+			    loff_t *ppos)
+{
+	int err, i, led;
+
+	if (count <= 0) {
+		return 0;
+	}
+
+	for (i = 0; i < count; i++) {
+		err = get_user(led, buf + i);
+		if (err) {
+			return err;
+		}
+		if (led < '0' || '7' < led) {
+			/* skip */
+			continue;
+		}
+		err = obsled_out_pat(led);
+		if (err) {
+			return err;
+		}
+	}
+
+	return count;
+}
+
+static struct file_operations obsled_fops = {
+	owner:		THIS_MODULE,
+	write:		obsled_write,
+	open:		obsled_open,
+	release:	obsled_release,
+};
+
+static int __init
+obsled_init(void)
+{
+	int curr_gpio = 0;
+	struct ocp_dev *gpio_dev;
+
+	printk("OBS_LED driver version %s\n", OBSLED_VER);
+	while (curr_gpio != -ENXIO) {
+		if (!(gpio_dev = ocp_alloc_dev(0)))
+			return -ENOMEM;
+
+		gpio_dev->type = GPIO;
+		if ((curr_gpio = ocp_register(gpio_dev)) == -ENXIO) {
+			ocp_free_dev(gpio_dev);
+			break;
+		} else {
+			obsled_miscdev.minor = OBSLED_MINOR;
+			obsled_miscdev.name = gpio_dev->name;
+			obsled_miscdev.fops = &obsled_fops;
+			misc_register(&obsled_miscdev);
+
+			gpiop = (struct gpio_regs *) ioremap(gpio_dev->paddr,
+					sizeof (struct gpio_regs));
+			mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR)
+					& ~ocp_get_pm(GPIO, curr_gpio));
+			printk("OBS_LED: GPIO #%d at 0x%lx\n", curr_gpio,
+			       (unsigned long) gpiop);
+
+		}
+	}
+
+	return (curr_gpio == -ENXIO) ? 0 : curr_gpio;
+}
+
+static void __exit
+obsled_exit(void)
+{
+	int i;
+	struct ocp_dev *gpio_dev;
+
+	for (i = 0; i < ocp_get_max(GPIO); i++) {
+		gpio_dev = ocp_get_dev(GPIO, i);
+		misc_deregister(&obsled_miscdev);
+		mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | ocp_get_pm(GPIO, i));
+		ocp_unregister(gpio_dev);
+	}
+}
+
+module_init(obsled_init);
+module_exit(obsled_exit);
+
+/* EXPORT_SYMBOL(obsled_out_pat); */
+
+MODULE_LICENSE("GPL");
+
+#define GPIO_OR		((u32 *)0xef600700)
+#define GPIO_TCR	((u32 *)0xef600704)
+int
+obsled_out(int led)
+{
+	return obsled_out_reg(led, GPIO_OR, GPIO_TCR);
+}
+
diff -Naru linux-2.4.20.orig/drivers/char/pushsw.c linux-2.4.20/drivers/char/pushsw.c
--- linux-2.4.20.orig/drivers/char/pushsw.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/pushsw.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,172 @@
+/*
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Century <www.centurysys.co.jp>
+ *		- Century's push button driver
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/pushsw.h>
+
+#define DBGON(x)	
+#define DBGOFF(x)	x
+
+
+#define PSW_VER		"0.01"
+#define PSW_IRQ		26 /* AIC_INT1 */
+
+/*----------------------------------------------------------------------------
+ *	Prototypes.
+ *----------------------------------------------------------------------------*/
+int psw_init(void);
+void psw_isr(int irq, void *dev_id, struct pt_regs *regs);
+static int psw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int psw_open(struct inode *inode, struct file *file);
+static int psw_release(struct inode *inode, struct file *file);
+
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+static struct file_operations	psw_fops = {
+	owner:		THIS_MODULE,
+	ioctl:		psw_ioctl,
+	open:		psw_open,
+	release:	psw_release,
+};
+static struct miscdevice	psw_miscdev =
+	{ 170, "pushsw", &psw_fops };
+static DECLARE_WAIT_QUEUE_HEAD(psw_wait);
+
+/* used to allow only one process at a time to "own" the push switch */
+static pid_t			psw_wait_pid = 0;
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+int
+psw_init(void)
+{
+	printk("Push switch driver v%s\n", PSW_VER);
+
+	/* Install the push switch interrupt handler */
+	if (request_irq(PSW_IRQ, psw_isr, SA_INTERRUPT, "push switch", NULL)) {
+		printk("[psw_open] interrupt %u not free\n", PSW_IRQ);
+		return (-EIO);
+	}
+	DBGOFF(printk("[psw_init] Push switch installed on interrupt %u\n", PSW_IRQ);)
+	misc_register(&psw_miscdev);
+	return (0);
+}	/* psw_init() */
+
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+void
+psw_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* DBGOFF(printk(KERN_CRIT "p");) */
+	wake_up_interruptible(&psw_wait);
+}	/* psw_isr() */
+
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+static int
+psw_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	unsigned long	flags;
+
+	if (MINOR(inode->i_rdev) != 170) {
+		return (-ENODEV);
+	}
+
+	switch (cmd) {
+	case PSWIOC_GETWAITPID:
+		return (put_user(psw_wait_pid, (int *) arg));
+	case PSWIOC_WAITPUSH:
+		/* protect psw_wait_pid */
+		save_flags(flags);
+		cli();
+		if (psw_wait_pid == 0) {
+			psw_wait_pid = current->pid;
+			restore_flags(flags);
+			DBGOFF(printk("[psw_ioctl] PSWIOC_WAITPUSH pid %u\n", psw_wait_pid);)
+			/* block until switch pushed */
+			interruptible_sleep_on(&psw_wait);
+			save_flags(flags);
+			cli();
+			psw_wait_pid = 0;
+			restore_flags(flags);
+
+			DBGOFF(printk("[psw_ioctl] unblocked\n");)
+			if (signal_pending(current)) {
+				DBGOFF(printk("[psw_ioctl] sig\n");)
+				return (-ERESTARTSYS);
+			}
+			return (0);
+		} else {
+			restore_flags(flags);
+			return (-EBUSY);
+		}
+	default:
+		break;
+	}
+	return (-ENOIOCTLCMD);
+}	/* psw_ioctl() */
+
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+static int
+psw_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+	case 170:
+		MOD_INC_USE_COUNT;
+		return (0);
+	default:
+		return (-ENODEV);
+	}
+}	/* psw_open() */
+
+/*----------------------------------------------------------------------------
+ *----------------------------------------------------------------------------*/
+static int
+psw_release(struct inode *inode, struct file *file)
+{
+	unsigned long	flags;
+
+	DBGOFF(printk("[psw_release] ");)
+	if (MINOR(inode->i_rdev) == 170) {
+		DBGOFF(printk("by pid %u\n", current->pid);)
+		save_flags(flags);
+		cli();
+		if (psw_wait_pid && (psw_wait_pid == current->pid)) {
+			psw_wait_pid = 0;
+			restore_flags(flags);
+			DBGOFF(printk("cleared\n");)
+		} else {
+			restore_flags(flags);
+			DBGOFF(if (psw_wait_pid) printk("psw_wait_pid %u, current->pid %u\n", psw_wait_pid, current->pid);)
+		}
+		MOD_DEC_USE_COUNT;
+	}
+	return (0);
+}	/* psw_release() */
+
+static void
+psw_exit(void)
+{
+	misc_deregister(&psw_miscdev);
+	free_irq(PSW_IRQ, NULL);
+}	/* cleanup_module() */
+module_init(psw_init);
+module_exit(psw_exit);
diff -Naru linux-2.4.20.orig/drivers/char/pushsw.h linux-2.4.20/drivers/char/pushsw.h
--- linux-2.4.20.orig/drivers/char/pushsw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/pushsw.h	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,19 @@
+/* 
+ *	Century <www.centurysys.co.jp>
+ *		- Century's push switch driver header
+ */
+
+#include <linux/ioctl.h>
+#include <linux/major.h>
+/* #include <linux/miscdevice.h> */
+
+#define PUSHSW_MAJOR		(MISC_MAJOR)
+
+#define	PUSHSW_IOCTL_BASE	'P'
+
+#define	PSWIOC_GETSTATUS	_IOR(PUSHSW_IOCTL_BASE, 0, int)
+#define	PSWIOC_WAITPUSH		_IOR(PUSHSW_IOCTL_BASE, 1, int)
+#define	PSWIOC_GETWAITPID	_IOR(PUSHSW_IOCTL_BASE, 2, int)
+
+#define PSWIOF_PUSHED		(1)
+#define PSWIOF_NOTPUSHED	(0)
diff -Naru linux-2.4.20.orig/drivers/char/serial.c-dbg linux-2.4.20/drivers/char/serial.c-dbg
--- linux-2.4.20.orig/drivers/char/serial.c-dbg	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/serial.c-dbg	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,6034 @@
+/*
+ *  linux/drivers/char/serial.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
+ * 		1998, 1999  Theodore Ts'o
+ *
+ *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
+ *  much more extensible to support other serial cards based on the
+ *  16450/16550A UART's.  Added support for the AST FourPort and the
+ *  Accent Async board.  
+ *
+ *  set_serial_info fixed to set the flags, custom divisor, and uart
+ * 	type fields.  Fix suggested by Michael K. Johnson 12/12/92.
+ *
+ *  11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
+ *
+ *  03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk>
+ *
+ *  rs_set_termios fixed to look also for changes of the input
+ *      flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
+ *                                            Bernd Anh��pl 05/17/96.
+ *
+ *  1/97:  Extended dumb serial ports are a config option now.  
+ *         Saves 4k.   Michael A. Griffith <grif@acm.org>
+ * 
+ *  8/97: Fix bug in rs_set_termios with RTS
+ *        Stanislav V. Voronyi <stas@uanet.kharkov.ua>
+ *
+ *  3/98: Change the IRQ detection, use of probe_irq_o*(),
+ *	  suppress TIOCSERGWILD and TIOCSERSWILD
+ *	  Etienne Lorrain <etienne.lorrain@ibm.net>
+ *
+ *  4/98: Added changes to support the ARM architecture proposed by
+ * 	  Russell King
+ *
+ *  5/99: Updated to include support for the XR16C850 and ST16C654
+ *        uarts.  Stuart MacDonald <stuartm@connecttech.com>
+ *
+ *  8/99: Generalized PCI support added.  Theodore Ts'o
+ * 
+ *  3/00: Rid circular buffer of redundant xmit_cnt.  Fix a
+ *	  few races on freeing buffers too.
+ *	  Alan Modra <alan@linuxcare.com>
+ *
+ *  5/00: Support for the RSA-DV II/S card added.
+ *	  Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ * 
+ *  6/00: Remove old-style timer, use timer_list
+ *        Andrew Morton <andrewm@uow.edu.au>
+ *
+ *  7/00: Support Timedia/Sunix/Exsys PCI cards
+ *
+ *  7/00: fix some returns on failure not using MOD_DEC_USE_COUNT.
+ *	  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * 10/00: add in optional software flow control for serial console.
+ *	  Kanoj Sarcar <kanoj@sgi.com>  (Modified by Theodore Ts'o)
+ *
+ * 02/02: Fix for AMD Elan bug in transmit irq routine, by
+ *        Christer Weinigel <wingel@hog.ctrl-c.liu.se>,
+ *        Robert Schwebel <robert@schwebel.de>,
+ *        Juergen Beisert <jbeisert@eurodsn.de>,
+ *        Theodore Ts'o <tytso@mit.edu>
+ */
+
+static char *serial_version = "5.05c";
+static char *serial_revdate = "2001-07-08";
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ *
+ * CONFIG_HUB6
+ *		Enables support for the venerable Bell Technologies
+ *		HUB6 card.
+ *
+ * CONFIG_SERIAL_MANY_PORTS
+ * 		Enables support for ports beyond the standard, stupid
+ * 		COM 1/2/3/4.
+ *
+ * CONFIG_SERIAL_MULTIPORT
+ * 		Enables support for special multiport board support.
+ *
+ * CONFIG_SERIAL_SHARE_IRQ
+ * 		Enables support for multiple serial ports on one IRQ
+ *
+ * CONFIG_SERIAL_DETECT_IRQ
+ *		Enable the autodetection of IRQ on standart ports
+ *
+ * SERIAL_PARANOIA_CHECK
+ * 		Check the magic number for the async_structure where
+ * 		ever possible.
+ *
+ * CONFIG_SERIAL_ACPI
+ *		Enable support for serial console port and serial 
+ *		debug port as defined by the SPCR and DBGP tables in 
+ *		ACPI 2.0.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#undef SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#if 0
+/* These defines are normally controlled by the autoconf.h */
+#define CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ
+#define CONFIG_SERIAL_MULTIPORT
+#define CONFIG_HUB6
+#endif
+
+#ifdef CONFIG_PCI
+#define ENABLE_SERIAL_PCI
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#endif
+
+#ifdef CONFIG_SERIAL_ACPI
+#define ENABLE_SERIAL_ACPI
+#endif
+
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#ifndef ENABLE_SERIAL_PNP
+#define ENABLE_SERIAL_PNP
+#endif
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_PCI
+#undef SERIAL_DEBUG_AUTOCONF
+
+/* Sanity checks */
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif
+
+#ifdef CONFIG_HUB6
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif
+
+#ifdef MODULE
+#undef CONFIG_SERIAL_CONSOLE
+#endif
+
+#define CONFIG_SERIAL_RSA
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT 256
+
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
+#define SERIAL_INLINE
+#endif
+  
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#ifdef LOCAL_HEADERS
+#include "serial_local.h"
+#else
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#define LOCAL_VERSTRING ""
+#endif
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#if (LINUX_VERSION_CODE >= 131343)
+#include <linux/init.h>
+#endif
+#if (LINUX_VERSION_CODE >= 131336)
+#include <asm/uaccess.h>
+#endif
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+#ifdef ENABLE_SERIAL_PCI
+#include <linux/pci.h>
+#endif
+#ifdef ENABLE_SERIAL_PNP
+#include <linux/isapnp.h>
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#include "serial_compat.h"
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#ifndef SERIAL_DEV_OFFSET
+#define SERIAL_DEV_OFFSET	0
+#endif
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#else
+#define _INLINE_
+#endif
+
+static char *serial_name = "Serial driver";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+static struct timer_list serial_timer;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
+ * IRQ_timeout		- How long the timeout should be for each IRQ
+ * 				should be after the IRQ has been active.
+ */
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+#ifdef CONFIG_SERIAL_MULTIPORT
+static struct rs_multiport_struct rs_multiport[NR_IRQS];
+#endif
+static int IRQ_timeout[NR_IRQS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+static int lsr_break_flag;
+#endif
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+static unsigned long break_pressed; /* break, really ... */
+#endif
+
+static unsigned detect_uart_irq (struct serial_state * state);
+static void autoconfig(struct serial_state * state);
+static void change_speed(struct async_struct *info, struct termios *old);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+	{ "unknown", 1, 0 }, 
+	{ "8250", 1, 0 }, 
+	{ "16450", 1, 0 }, 
+	{ "16550", 1, 0 }, 
+	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+	{ "cirrus", 1, 0 }, 	/* usurped by cyclades.c */
+	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, 
+	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+		  UART_STARTECH }, 
+	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "Startech", 1, 0},	/* usurped by cyclades.c */
+	{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+		  UART_STARTECH }, 
+	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+		  UART_STARTECH },
+	{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+	{ 0, 0}
+};
+
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+
+#define PORT_RSA_MAX 4
+static int probe_rsa[PORT_RSA_MAX];
+static int force_rsa[PORT_RSA_MAX];
+
+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
+#endif /* CONFIG_SERIAL_RSA  */
+
+struct serial_state rs_table[RS_TABLE_SIZE] = {
+	SERIAL_PORT_DFNS	/* Defined in serial.h */
+};
+
+#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+int serial_nr_ports = NR_PORTS;
+
+#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
+#define NR_PCI_BOARDS	8
+
+static struct pci_board_inst	serial_pci_board[NR_PCI_BOARDS];
+
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
+				      IORESOURCE_IO)
+#endif
+#ifndef IS_PCI_REGION_IOMEM
+#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
+				      IORESOURCE_MEM)
+#endif
+#ifndef PCI_IRQ_RESOURCE
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
+#endif
+#ifndef pci_get_subvendor
+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
+#define pci_get_subdevice(dev)  ((dev)->subsystem_device)
+#endif
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP  */
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev)  (dev->prepare)
+#define ACTIVATE_FUNC(dev)  (dev->activate)
+#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
+#endif
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+
+static inline int serial_paranoia_check(struct async_struct *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
+{
+	switch (info->io_type) {
+#ifdef CONFIG_HUB6
+	case SERIAL_IO_HUB6:
+		outb(info->hub6 - 1 + offset, info->port);
+		return inb(info->port+1);
+#endif
+	case SERIAL_IO_MEM:
+		return readb((unsigned long) info->iomem_base +
+			     (offset<<info->iomem_reg_shift));
+	default:
+		return inb(info->port + offset);
+	}
+}
+
+static _INLINE_ void serial_out(struct async_struct *info, int offset,
+				int value)
+{
+	switch (info->io_type) {
+#ifdef CONFIG_HUB6
+	case SERIAL_IO_HUB6:
+		outb(info->hub6 - 1 + offset, info->port);
+		outb(value, info->port+1);
+		break;
+#endif
+	case SERIAL_IO_MEM:
+		writeb(value, (unsigned long) info->iomem_base +
+			      (offset<<info->iomem_reg_shift));
+		break;
+	default:
+		outb(value, info->port+offset);
+	}
+}
+
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(info, offset)		serial_in(info, offset)
+#define serial_outp(info, offset, value)	serial_out(info, offset, value)
+
+
+/*
+ * For the 16C950
+ */
+void serial_icr_write(struct async_struct *info, int offset, int  value)
+{
+	serial_out(info, UART_SCR, offset);
+	serial_out(info, UART_ICR, value);
+}
+
+unsigned int serial_icr_read(struct async_struct *info, int offset)
+{
+	int	value;
+
+	serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
+	serial_out(info, UART_SCR, offset);
+	value = serial_in(info, UART_ICR);
+	serial_icr_write(info, UART_ACR, info->ACR);
+	return value;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->IER & UART_IER_THRI) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	if (info->state->type == PORT_16C950) {
+		info->ACR |= UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
+	restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit.head != info->xmit.tail
+	    && info->xmit.buf
+	    && !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	if (info->state->type == PORT_16C950) {
+		info->ACR &= ~UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct async_struct *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct async_struct *info,
+				 int *status, struct pt_regs * regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch;
+	struct	async_icount *icount;
+	int	max_count = 256;
+
+	icount = &info->state->icount;
+	do {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.tqueue.routine((void *) tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				return;		// if TTY_DONT_FLIP is set
+		}
+		ch = serial_inp(info, UART_RX);
+		*tty->flip.char_buf_ptr = ch;
+		icount->rx++;
+		
+#ifdef SERIAL_DEBUG_INTR
+		printk("DR%02x:%02x...", ch, *status);
+#endif
+		*tty->flip.flag_buf_ptr = 0;
+		if (*status & (UART_LSR_BI | UART_LSR_PE |
+			       UART_LSR_FE | UART_LSR_OE)) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				icount->brk++;
+				/*
+				 * We do the SysRQ and SAK checking
+				 * here because otherwise the break
+				 * may get masked by ignore_status_mask
+				 * or read_status_mask.
+				 */
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+				if (info->line == sercons.index) {
+					if (!break_pressed) {
+						break_pressed = jiffies;
+						goto ignore_char;
+					}
+					break_pressed = 0;
+				}
+#endif
+				if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			} else if (*status & UART_LSR_PE)
+				icount->parity++;
+			else if (*status & UART_LSR_FE)
+				icount->frame++;
+			if (*status & UART_LSR_OE)
+				icount->overrun++;
+
+			/*
+			 * Mask off conditions which should be ignored.
+			 */
+			*status &= info->read_status_mask;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+			if (info->line == sercons.index) {
+				/* Recover the break flag from console xmit */
+				*status |= lsr_break_flag;
+				lsr_break_flag = 0;
+			}
+#endif
+			if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+				printk("handling break....");
+#endif
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+			} else if (*status & UART_LSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+		if (break_pressed && info->line == sercons.index) {
+			if (ch != 0 &&
+			    time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
+		}
+#endif
+		if ((*status & info->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((*status & UART_LSR_OE) &&
+		    (tty->flip.count < TTY_FLIPBUF_SIZE)) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+			tty->flip.count++;
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+	ignore_char:
+#endif
+		*status = serial_inp(info, UART_LSR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+	tty_flip_buffer_push(tty);
+#else
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif	
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+{
+	int count;
+
+	if (info->x_char) {
+		serial_outp(info, UART_TX, info->x_char);
+		info->state->icount.tx++;
+		info->x_char = 0;
+		if (intr_done)
+			*intr_done = 0;
+		return;
+	}
+	if (info->xmit.head == info->xmit.tail
+	    || info->tty->stopped
+	    || info->tty->hw_stopped) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+		return;
+	}
+	
+	count = info->xmit_fifo_size;
+	do {
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+		if (info->xmit.head == info->xmit.tail)
+			break;
+	} while (--count > 0);
+	
+	if (CIRC_CNT(info->xmit.head,
+		     info->xmit.tail,
+		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+	if (intr_done)
+		*intr_done = 0;
+
+	if (info->xmit.head == info->xmit.tail) {
+		info->IER &= ~UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+	int	status;
+	struct	async_icount *icount;
+	
+	status = serial_in(info, UART_MSR);
+
+	if (status & UART_MSR_ANY_DELTA) {
+		icount = &info->state->icount;
+		/* update input line counters */
+		if (status & UART_MSR_TERI)
+			icount->rng++;
+		if (status & UART_MSR_DDSR)
+			icount->dsr++;
+		if (status & UART_MSR_DDCD) {
+			icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			    (status & UART_MSR_DCD))
+				hardpps();
+#endif
+		}
+		if (status & UART_MSR_DCTS)
+			icount->cts++;
+		wake_up_interruptible(&info->delta_msr_wait);
+	}
+
+	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+		printk("ttys%d CD now %s...", info->line,
+		       (status & UART_MSR_DCD) ? "on" : "off");
+#endif		
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+			printk("doing serial hangup...");
+#endif
+			if (info->tty)
+				tty_hangup(info->tty);
+		}
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx start...");
+#endif
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				return;
+			}
+		} else {
+			if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx stop...");
+#endif
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+			}
+		}
+	}
+}
+
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status, iir;
+	struct async_struct * info;
+	int pass_counter = 0;
+	struct async_struct *end_mark = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	int first_multi = 0;
+	struct rs_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("rs_interrupt(%d)...", irq);
+#endif
+
+	info = IRQ_ports[irq];
+	if (!info)
+		return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+#endif
+
+	do {
+		if (!info->tty ||
+		    ((iir=serial_in(info, UART_IIR)) & UART_IIR_NO_INT)) {
+			if (!end_mark)
+				end_mark = info;
+			goto next;
+		}
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", serial_in(info, UART_IIR));
+#endif
+		end_mark = 0;
+
+		info->last_active = jiffies;
+
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR)
+			receive_chars(info, &status, regs);
+		check_modem_status(info);
+		if ((status & UART_LSR_THRE) ||
+			/* for buggy ELAN processors */
+			((iir & UART_IIR_ID) == UART_IIR_THRI))
+			transmit_chars(info, 0);
+
+	next:
+		info = info->next_port;
+		if (!info) {
+			info = IRQ_ports[irq];
+			if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 0
+				printk("rs loop break\n");
+#endif
+				break; 	/* Prevent infinite loops */
+			}
+			continue;
+		}
+	} while (end_mark != info);
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	if (multi->port_monitor)
+		printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
+		       info->state->irq, first_multi,
+		       inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
+
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status, iir;
+	int pass_counter = 0;
+	struct async_struct * info;
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	int first_multi = 0;
+	struct rs_multiport_struct *multi;
+#endif
+	
+#ifdef SERIAL_DEBUG_INTR
+	printk("rs_interrupt_single(%d)...", irq);
+#endif
+
+	info = IRQ_ports[irq];
+	if (!info || !info->tty)
+		return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+#endif
+
+	iir = serial_in(info, UART_IIR);
+	do {
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR)
+			receive_chars(info, &status, regs);
+		check_modem_status(info);
+		if ((status & UART_LSR_THRE) ||
+		    /* For buggy ELAN processors */
+		    ((iir & UART_IIR_ID) == UART_IIR_THRI))
+			transmit_chars(info, 0);
+		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if SERIAL_DEBUG_INTR
+			printk("rs_single loop break.\n");
+#endif
+			break;
+		}
+		iir = serial_in(info, UART_IIR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("IIR = %x...", iir);
+#endif
+	} while ((iir & UART_IIR_NO_INT) == 0);
+	info->last_active = jiffies;
+#ifdef CONFIG_SERIAL_MULTIPORT	
+	if (multi->port_monitor)
+		printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+		       info->state->irq, first_multi,
+		       inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+
+#ifdef CONFIG_SERIAL_MULTIPORT	
+/*
+ * This is the serial driver's for multiport boards
+ */
+static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status;
+	struct async_struct * info;
+	int pass_counter = 0;
+	int first_multi= 0;
+	struct rs_multiport_struct *multi;
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("rs_interrupt_multi(%d)...", irq);
+#endif
+
+	info = IRQ_ports[irq];
+	if (!info)
+		return;
+	multi = &rs_multiport[irq];
+	if (!multi->port1) {
+		/* Should never happen */
+		printk("rs_interrupt_multi: NULL port1!\n");
+		return;
+	}
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+	
+	while (1) {
+		if (!info->tty ||
+		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
+			goto next;
+
+		info->last_active = jiffies;
+
+		status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR)
+			receive_chars(info, &status, regs);
+		check_modem_status(info);
+		if (status & UART_LSR_THRE)
+			transmit_chars(info, 0);
+
+	next:
+		info = info->next_port;
+		if (info)
+			continue;
+
+		info = IRQ_ports[irq];
+		/*
+		 * The user was a bonehead, and misconfigured their
+		 * multiport info.  Rather than lock up the kernel
+		 * in an infinite loop, if we loop too many times,
+		 * print a message and break out of the loop.
+		 */
+		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+			printk("Misconfigured multiport serial info "
+			       "for irq %d.  Breaking out irq loop\n", irq);
+			break; 
+		}
+		if (multi->port_monitor)
+			printk("rs port monitor irq %d: 0x%x, 0x%x\n",
+			       info->state->irq, first_multi,
+			       inb(multi->port_monitor));
+		if ((inb(multi->port1) & multi->mask1) != multi->match1)
+			continue;
+		if (!multi->port2)
+			break;
+		if ((inb(multi->port2) & multi->mask2) != multi->match2)
+			continue;
+		if (!multi->port3)
+			break;
+		if ((inb(multi->port3) & multi->mask3) != multi->match3)
+			continue;
+		if (!multi->port4)
+			break;
+		if ((inb(multi->port4) & multi->mask4) != multi->match4)
+			continue;
+		break;
+	} 
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct async_struct	*info = (struct async_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+		wake_up_interruptible(&tty->poll_wait);
+#endif
+	}
+}
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work very well for 16450's, but gives barely
+ * passable results for a 16550A.  (Although at the expense of much
+ * CPU overhead).
+ */
+static void rs_timer(unsigned long dummy)
+{
+	static unsigned long last_strobe;
+	struct async_struct *info;
+	unsigned int	i;
+	unsigned long flags;
+
+	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+		for (i=0; i < NR_IRQS; i++) {
+			info = IRQ_ports[i];
+			if (!info)
+				continue;
+			save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+			if (info->next_port) {
+				do {
+					serial_out(info, UART_IER, 0);
+					info->IER |= UART_IER_THRI;
+					serial_out(info, UART_IER, info->IER);
+					info = info->next_port;
+				} while (info);
+#ifdef CONFIG_SERIAL_MULTIPORT
+				if (rs_multiport[i].port1)
+					rs_interrupt_multi(i, NULL, NULL);
+				else
+#endif
+					rs_interrupt(i, NULL, NULL);
+			} else
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+				rs_interrupt_single(i, NULL, NULL);
+			restore_flags(flags);
+		}
+	}
+	last_strobe = jiffies;
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+
+	if (IRQ_ports[0]) {
+		save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+		rs_interrupt(0, NULL, NULL);
+#else
+		rs_interrupt_single(0, NULL, NULL);
+#endif
+		restore_flags(flags);
+
+		mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+	struct	async_struct	*info;
+	int	timeout = 60*HZ;	/* 60 seconds === a long time :-) */
+
+	info = IRQ_ports[irq];
+	if (!info) {
+		IRQ_timeout[irq] = 60*HZ;
+		return;
+	}
+	while (info) {
+		if (info->timeout < timeout)
+			timeout = info->timeout;
+		info = info->next_port;
+	}
+	if (!irq)
+		timeout = timeout / 2;
+	IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
+}
+
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO.  Returns zero on failure */
+static int enable_rsa(struct async_struct *info)
+{
+	unsigned char mode;
+	int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	mode = serial_inp(info, UART_RSA_MSR);
+	result = mode & UART_RSA_MSR_FIFO;
+
+	if (!result) {
+		serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+		mode = serial_inp(info, UART_RSA_MSR);
+		result = mode & UART_RSA_MSR_FIFO;
+	}
+
+	restore_flags(flags);
+	return result;
+}
+
+/* Attempts to turn off the RSA FIFO.  Returns zero on failure */
+static int disable_rsa(struct async_struct *info)
+{
+	unsigned char mode;
+	int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	mode = serial_inp(info, UART_RSA_MSR);
+	result = !(mode & UART_RSA_MSR_FIFO);
+
+	if (!result) {
+		serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+		mode = serial_inp(info, UART_RSA_MSR);
+		result = !(mode & UART_RSA_MSR_FIFO);
+	}
+
+	restore_flags(flags);
+	return result;
+}
+#endif /* CONFIG_SERIAL_RSA */
+
+static int startup(struct async_struct * info)
+{
+	unsigned long flags;
+	int	retval=0;
+	void (*handler)(int, void *, struct pt_regs *);
+	struct serial_state *state= info->state;
+	unsigned long page;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	unsigned short ICP;
+#endif
+
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		goto errout;
+	}
+
+	if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		free_page(page);
+		goto errout;
+	}
+
+	if (info->xmit.buf)
+		free_page(page);
+	else
+		info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+	if (uart_config[state->type].flags & UART_STARTECH) {
+		/* Wake up UART */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		/*
+		 * Turn off LCR == 0xBF so we actually set the IER
+		 * register on the XR16C850
+		 */
+		serial_outp(info, UART_LCR, 0);
+		serial_outp(info, UART_IER, 0);
+		/*
+		 * Now reset LCR so we can turn off the ECB bit
+		 */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, 0);
+		/*
+		 * For a XR16C850, we need to set the trigger levels
+		 */
+		if (state->type == PORT_16850) {
+			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+					UART_FCTR_RX);
+			serial_outp(info, UART_TRG, UART_TRG_96);
+			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+					UART_FCTR_TX);
+			serial_outp(info, UART_TRG, UART_TRG_96);
+		}
+		serial_outp(info, UART_LCR, 0);
+	}
+
+	if (state->type == PORT_16750) {
+		/* Wake up UART */
+		serial_outp(info, UART_IER, 0);
+	}
+
+	if (state->type == PORT_16C950) {
+		/* Wake up and initialize UART */
+		info->ACR = 0;
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_IER, 0);
+		serial_outp(info, UART_LCR, 0);
+		serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_LCR, 0);
+	}
+
+#ifdef CONFIG_SERIAL_RSA
+	/*
+	 * If this is an RSA port, see if we can kick it up to the
+	 * higher speed clock.
+	 */
+	if (state->type == PORT_RSA) {
+		if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
+		    enable_rsa(info))
+			state->baud_base = SERIAL_RSA_BAUD_BASE;
+		if (state->baud_base == SERIAL_RSA_BAUD_BASE)
+			serial_outp(info, UART_RSA_FRR, 0);
+	}
+#endif
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+	if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+					     UART_FCR_CLEAR_RCVR |
+					     UART_FCR_CLEAR_XMIT));
+		serial_outp(info, UART_FCR, 0);
+	}
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) serial_inp(info, UART_LSR);
+	(void) serial_inp(info, UART_RX);
+	(void) serial_inp(info, UART_IIR);
+	(void) serial_inp(info, UART_MSR);
+
+	/*
+	 * At this point there's no way the LSR could still be 0xFF;
+	 * if it is, then bail out, because there's likely no UART
+	 * here.
+	 */
+	if (!(info->flags & ASYNC_BUGGY_UART) &&
+	    (serial_inp(info, UART_LSR) == 0xff)) {
+		printk("ttyS%d: LSR safety check engaged!\n", state->line);
+		if (capable(CAP_SYS_ADMIN)) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+		} else
+			retval = -ENODEV;
+		goto errout;
+	}
+
+	/*
+	 * Allocate the IRQ if necessary
+	 */
+	if (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port) {
+		if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+#ifdef CONFIG_SERIAL_MULTIPORT				
+			if (rs_multiport[state->irq].port1)
+				handler = rs_interrupt_multi;
+			else
+#endif
+				handler = rs_interrupt;
+#else
+			retval = -EBUSY;
+			goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+		} else 
+			handler = rs_interrupt_single;
+
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
+		if (retval) {
+			if (capable(CAP_SYS_ADMIN)) {
+				if (info->tty)
+					set_bit(TTY_IO_ERROR,
+						&info->tty->flags);
+				retval = 0;
+			}
+			goto errout;
+		}
+	}
+
+	/*
+	 * Insert serial port into IRQ chain.
+	 */
+	info->prev_port = 0;
+	info->next_port = IRQ_ports[state->irq];
+	if (info->next_port)
+		info->next_port->prev_port = info;
+	IRQ_ports[state->irq] = info;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Now, initialize the UART 
+	 */
+	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		if (state->irq == 0)
+			info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+	{
+		if (state->irq != 0)
+			info->MCR |= UART_MCR_OUT2;
+	}
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
+	serial_outp(info, UART_MCR, info->MCR);
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* Enable interrupts on the AST Fourport board */
+		ICP = (info->port & 0xFE0) | 0x01F;
+		outb_p(0x80, ICP);
+		(void) inb_p(ICP);
+	}
+#endif
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void)serial_inp(info, UART_LSR);
+	(void)serial_inp(info, UART_RX);
+	(void)serial_inp(info, UART_IIR);
+	(void)serial_inp(info, UART_MSR);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit.head = info->xmit.tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+	mod_timer(&serial_timer, jiffies + 2*HZ/100);
+
+	/*
+	 * Set up the tty->alt_speed kludge
+	 */
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	if (info->tty) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			info->tty->alt_speed = 57600;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			info->tty->alt_speed = 115200;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			info->tty->alt_speed = 230400;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			info->tty->alt_speed = 460800;
+	}
+#endif
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info, 0);
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+	unsigned long	flags;
+	struct serial_state *state;
+	int		retval;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       state->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+	
+	/*
+	 * First unlink the serial port from the IRQ chain...
+	 */
+	if (info->next_port)
+		info->next_port->prev_port = info->prev_port;
+	if (info->prev_port)
+		info->prev_port->next_port = info->next_port;
+	else
+		IRQ_ports[state->irq] = info->next_port;
+	figure_IRQ_timeout(state->irq);
+	
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if ((!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq, rs_interrupt_single,
+					     SA_SHIRQ, "serial",
+					     &IRQ_ports[state->irq]);
+			
+			if (retval)
+				printk("serial shutdown: request_irq: error %d"
+				       "  Couldn't reacquire IRQ.\n", retval);
+		} else
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+	}
+
+	if (info->xmit.buf) {
+		unsigned long pg = (unsigned long) info->xmit.buf;
+		info->xmit.buf = 0;
+		free_page(pg);
+	}
+
+	info->IER = 0;
+	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (info->flags & ASYNC_FOURPORT) {
+		/* reset interrupts on the AST Fourport board */
+		(void) inb((info->port & 0xFE0) | 0x01F);
+		info->MCR |= UART_MCR_OUT1;
+	} else
+#endif
+		info->MCR &= ~UART_MCR_OUT2;
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
+	
+	/* disable break condition */
+	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+	
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+	serial_outp(info, UART_MCR, info->MCR);
+
+	/* disable FIFO's */	
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
+
+#ifdef CONFIG_SERIAL_RSA
+	/*
+	 * Reset the RSA board back to 115kbps compat mode.
+	 */
+	if ((state->type == PORT_RSA) &&
+	    (state->baud_base == SERIAL_RSA_BAUD_BASE &&
+	     disable_rsa(info)))
+		state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+	
+
+	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+	
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	if (uart_config[info->state->type].flags & UART_STARTECH) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_LCR, 0);
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, 0);
+		serial_outp(info, UART_LCR, 0);
+	}
+	if (info->state->type == PORT_16750) {
+		/* Arrange to enter sleep mode */
+		serial_outp(info, UART_IER, UART_IERX_SLEEP);
+	}
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300,
+	600, 1200, 1800, 2400, 4800, 9600, 19200,
+	38400, 57600, 115200, 230400, 460800, 0 };
+
+static int tty_get_baud_rate(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned int cflag, i;
+
+	cflag = tty->termios->c_cflag;
+
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 2) 
+			tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
+	}
+	if (i == 15) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			i += 1;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			i += 2;
+	}
+	return baud_table[i];
+}
+#endif
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct async_struct *info,
+			 struct termios *old_termios)
+{
+	int	quot = 0, baud_base, baud;
+	unsigned cflag, cval, fcr = 0;
+	int	bits;
+	unsigned long	flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	      case CS5: cval = 0x00; bits = 7; break;
+	      case CS6: cval = 0x01; bits = 8; break;
+	      case CS7: cval = 0x02; bits = 9; break;
+	      case CS8: cval = 0x03; bits = 10; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  cval = 0x00; bits = 7; break;
+	      }
+	if (cflag & CSTOPB) {
+		cval |= 0x04;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		cval |= UART_LCR_PARITY;
+		bits++;
+	}
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+	if (cflag & CMSPAR)
+		cval |= UART_LCR_SPAR;
+#endif
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(info->tty);
+	if (!baud)
+		baud = 9600;	/* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+	if ((info->state->type == PORT_RSA) &&
+	    (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+	    enable_rsa(info))
+		info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
+	baud_base = info->state->baud_base;
+	if (info->state->type == PORT_16C950) {
+		if (baud <= baud_base)
+			serial_icr_write(info, UART_TCR, 0);
+		else if (baud <= 2*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x8);
+			baud_base = baud_base * 2;
+		} else if (baud <= 4*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x4);
+			baud_base = baud_base * 4;
+		} else
+			serial_icr_write(info, UART_TCR, 0);
+	}
+	if (baud == 38400 &&
+	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->state->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2*baud_base / 269);
+		else if (baud)
+			quot = baud_base / baud;
+	}
+	/* If the quotient is zero refuse the change */
+	if (!quot && old_termios) {
+		info->tty->termios->c_cflag &= ~CBAUD;
+		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+		baud = tty_get_baud_rate(info->tty);
+		if (!baud)
+			baud = 9600;
+		if (baud == 38400 &&
+		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+			quot = info->state->custom_divisor;
+		else {
+			if (baud == 134)
+				/* Special case since 134 is really 134.5 */
+				quot = (2*baud_base / 269);
+			else if (baud)
+				quot = baud_base / baud;
+		}
+	}
+	/* As a last resort, if the quotient is zero, default to 9600 bps */
+	if (!quot)
+		quot = baud_base / 9600;
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+	    (info->state->revision == 0x5201))
+		quot++;
+	
+	info->quot = quot;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	/* Set up FIFO's */
+	if (uart_config[info->state->type].flags & UART_USE_FIFO) {
+		if ((info->state->baud_base / quot) < 2400)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_RSA
+		else if (info->state->type == PORT_RSA)
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
+		else
+			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+	}
+	if (info->state->type == PORT_16750)
+		fcr |= UART_FCR7_64BYTE;
+	
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= UART_LSR_BI;
+	
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= UART_LSR_OE;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->ignore_status_mask |= UART_LSR_DR;
+	save_flags(flags); cli();
+	if (uart_config[info->state->type].flags & UART_STARTECH) {
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR,
+			    (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+	}
+	serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	serial_outp(info, UART_DLL, quot & 0xff);	/* LS of divisor */
+	serial_outp(info, UART_DLM, quot >> 8);		/* MS of divisor */
+
+	if (info->state->type == PORT_16750)
+		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
+	info->LCR = cval;				/* Save LCR */
+ 	if (info->state->type != PORT_16750) {
+ 		if (fcr & UART_FCR_ENABLE_FIFO) {
+ 			/* emulated UARTs (Lucent Venus 167x) need two steps */
+ 			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ 		}
+		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
+	}
+	restore_flags(flags);
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+		return;
+
+	if (!tty || !info->xmit.buf)
+		return;
+
+	save_flags(flags); cli();
+	if (CIRC_SPACE(info->xmit.head,
+		       info->xmit.tail,
+		       SERIAL_XMIT_SIZE) == 0) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit.buf[info->xmit.head] = ch;
+	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
+	restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit.head == info->xmit.tail
+	    || tty->stopped
+	    || tty->hw_stopped
+	    || !info->xmit.buf)
+		return;
+
+	save_flags(flags); cli();
+	info->IER |= UART_IER_THRI;
+	serial_out(info, UART_IER, info->IER);
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit.buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+			cli();
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					       info->xmit.tail,
+					       SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			restore_flags(flags);
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		cli();
+		while (1) {
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
+			if (c <= 0) {
+				break;
+			}
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
+					   (SERIAL_XMIT_SIZE-1));
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		restore_flags(flags);
+	}
+	if (info->xmit.head != info->xmit.tail
+	    && !tty->stopped
+	    && !tty->hw_stopped
+	    && !(info->IER & UART_IER_THRI)) {
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+	return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	save_flags(flags); cli();
+	info->xmit.head = info->xmit.tail = 0;
+	restore_flags(flags);
+	wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+	wake_up_interruptible(&tty->poll_wait);
+#endif
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+		info->IER |= UART_IER_THRI;
+		serial_out(info, UART_IER, info->IER);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_send_xchar(tty, START_CHAR(tty));
+	}
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	save_flags(flags); cli();
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct serial_state *state = info->state;
+   
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = state->type;
+	tmp.line = state->line;
+	tmp.port = state->port;
+	if (HIGH_BITS_OFFSET)
+		tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+	else
+		tmp.port_high = 0;
+	tmp.irq = state->irq;
+	tmp.flags = state->flags;
+	tmp.xmit_fifo_size = state->xmit_fifo_size;
+	tmp.baud_base = state->baud_base;
+	tmp.close_delay = state->close_delay;
+	tmp.closing_wait = state->closing_wait;
+	tmp.custom_divisor = state->custom_divisor;
+	tmp.hub6 = state->hub6;
+	tmp.io_type = state->io_type;
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+ 	struct serial_state old_state, *state;
+	unsigned int		i,change_irq,change_port;
+	int 			retval = 0;
+	unsigned long		new_port;
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+	state = info->state;
+	old_state = *state;
+
+	new_port = new_serial.port;
+	if (HIGH_BITS_OFFSET)
+		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+	change_irq = new_serial.irq != state->irq;
+	change_port = (new_port != ((int) state->port)) ||
+		(new_serial.hub6 != state->hub6);
+  
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (change_irq || change_port ||
+		    (new_serial.baud_base != state->baud_base) ||
+		    (new_serial.type != state->type) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (state->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		state->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || 
+	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
+	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+	    (new_serial.type == PORT_STARTECH)) {
+		return -EINVAL;
+	}
+
+	if ((new_serial.type != state->type) ||
+	    (new_serial.xmit_fifo_size <= 0))
+		new_serial.xmit_fifo_size =
+			uart_config[new_serial.type].dfl_xmit_fifo_size;
+
+	/* Make sure address is not already in use */
+	if (new_serial.type) {
+		for (i = 0 ; i < NR_PORTS; i++)
+			if ((state != &rs_table[i]) &&
+			    (rs_table[i].io_type == SERIAL_IO_PORT) &&
+			    (rs_table[i].port == new_port) &&
+			    rs_table[i].type)
+				return -EADDRINUSE;
+	}
+
+	if ((change_port || change_irq) && (state->count > 1))
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	state->baud_base = new_serial.baud_base;
+	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+		       (info->flags & ASYNC_INTERNAL_FLAGS));
+	state->custom_divisor = new_serial.custom_divisor;
+	state->close_delay = new_serial.close_delay * HZ/100;
+	state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x20100)
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+	info->xmit_fifo_size = state->xmit_fifo_size =
+		new_serial.xmit_fifo_size;
+
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (old_state.type == PORT_RSA)
+			release_region(state->port + UART_RSA_BASE, 16);
+		else
+#endif
+		release_region(state->port,8);
+	}
+	state->type = new_serial.type;
+	if (change_port || change_irq) {
+		/*
+		 * We need to shutdown the serial port at the old
+		 * port/irq combination.
+		 */
+		shutdown(info);
+		state->irq = new_serial.irq;
+		info->port = state->port = new_port;
+		info->hub6 = state->hub6 = new_serial.hub6;
+		if (info->hub6)
+			info->io_type = state->io_type = SERIAL_IO_HUB6;
+		else if (info->io_type == SERIAL_IO_HUB6)
+			info->io_type = state->io_type = SERIAL_IO_PORT;
+	}
+	if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (state->type == PORT_RSA)
+			request_region(state->port + UART_RSA_BASE,
+				       16, "serial_rsa(set)");
+		else
+#endif
+			request_region(state->port,8,"serial(set)");
+	}
+
+	
+check_and_exit:
+	if ((!state->port && !state->iomem_base) || !state->type)
+		return 0;
+	if (info->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+		     (state->flags & ASYNC_SPD_MASK)) ||
+		    (old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->tty->alt_speed = 57600;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->tty->alt_speed = 115200;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->tty->alt_speed = 230400;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->tty->alt_speed = 460800;
+#endif
+			change_speed(info, 0);
+		}
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	status = serial_in(info, UART_LSR);
+	restore_flags(flags);
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+
+	/*
+	 * If we're about to load something into the transmit
+	 * register, we'll pretend the transmitter isn't empty to
+	 * avoid a race condition (depending on when the transmit
+	 * interrupt happens).
+	 */
+	if (info->x_char || 
+	    ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+		       SERIAL_XMIT_SIZE) > 0) &&
+	     !info->tty->stopped && !info->tty->hw_stopped))
+		result &= ~TIOCSER_TEMT;
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+	unsigned long flags;
+
+	control = info->MCR;
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	restore_flags(flags);
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+	unsigned long flags;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
+
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR |= UART_MCR_LOOP;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		if (arg & TIOCM_LOOP)
+			info->MCR &= ~UART_MCR_LOOP;
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+					    UART_MCR_OUT1 |
+					    UART_MCR_OUT2 |
+#endif
+					    UART_MCR_LOOP |
+					    UART_MCR_DTR))
+			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+			     | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
+			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	save_flags(flags); cli();
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
+	serial_out(info, UART_MCR, info->MCR);
+	restore_flags(flags);
+	return 0;
+}
+
+static int do_autoconfig(struct async_struct * info)
+{
+	int irq, retval;
+	
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	
+	if (info->state->count > 1)
+		return -EBUSY;
+	
+	shutdown(info);
+
+	autoconfig(info->state);
+	if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+	    (info->state->port != 0  || info->state->iomem_base != 0) &&
+	    (info->state->type != PORT_UNKNOWN)) {
+		irq = detect_uart_irq(info->state);
+		if (irq > 0)
+			info->state->irq = irq;
+	}
+
+	retval = startup(info);
+	if (retval)
+		return retval;
+	return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break(	struct async_struct * info, int duration)
+{
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	info->LCR |= UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
+	schedule();
+	info->LCR &= ~UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
+	sti();
+}
+#else
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	save_flags(flags); cli();
+	if (break_state == -1)
+		info->LCR |= UART_LCR_SBC;
+	else
+		info->LCR &= ~UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
+	restore_flags(flags);
+}
+#endif
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+static int get_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *retinfo)
+{
+	struct serial_multiport_struct ret;
+	struct rs_multiport_struct *multi;
+	
+	multi = &rs_multiport[info->state->irq];
+
+	ret.port_monitor = multi->port_monitor;
+	
+	ret.port1 = multi->port1;
+	ret.mask1 = multi->mask1;
+	ret.match1 = multi->match1;
+	
+	ret.port2 = multi->port2;
+	ret.mask2 = multi->mask2;
+	ret.match2 = multi->match2;
+	
+	ret.port3 = multi->port3;
+	ret.mask3 = multi->mask3;
+	ret.match3 = multi->match3;
+	
+	ret.port4 = multi->port4;
+	ret.mask4 = multi->mask4;
+	ret.match4 = multi->match4;
+
+	ret.irq = info->state->irq;
+
+	if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *in_multi)
+{
+	struct serial_multiport_struct new_multi;
+	struct rs_multiport_struct *multi;
+	struct serial_state *state;
+	int	was_multi, now_multi;
+	int	retval;
+	void (*handler)(int, void *, struct pt_regs *);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	state = info->state;
+	
+	if (copy_from_user(&new_multi, in_multi,
+			   sizeof(struct serial_multiport_struct)))
+		return -EFAULT;
+	
+	if (new_multi.irq != state->irq || state->irq == 0 ||
+	    !IRQ_ports[state->irq])
+		return -EINVAL;
+
+	multi = &rs_multiport[state->irq];
+	was_multi = (multi->port1 != 0);
+	
+	multi->port_monitor = new_multi.port_monitor;
+	
+	if (multi->port1)
+		release_region(multi->port1,1);
+	multi->port1 = new_multi.port1;
+	multi->mask1 = new_multi.mask1;
+	multi->match1 = new_multi.match1;
+	if (multi->port1)
+		request_region(multi->port1,1,"serial(multiport1)");
+
+	if (multi->port2)
+		release_region(multi->port2,1);
+	multi->port2 = new_multi.port2;
+	multi->mask2 = new_multi.mask2;
+	multi->match2 = new_multi.match2;
+	if (multi->port2)
+		request_region(multi->port2,1,"serial(multiport2)");
+
+	if (multi->port3)
+		release_region(multi->port3,1);
+	multi->port3 = new_multi.port3;
+	multi->mask3 = new_multi.mask3;
+	multi->match3 = new_multi.match3;
+	if (multi->port3)
+		request_region(multi->port3,1,"serial(multiport3)");
+
+	if (multi->port4)
+		release_region(multi->port4,1);
+	multi->port4 = new_multi.port4;
+	multi->mask4 = new_multi.mask4;
+	multi->match4 = new_multi.match4;
+	if (multi->port4)
+		request_region(multi->port4,1,"serial(multiport4)");
+
+	now_multi = (multi->port1 != 0);
+	
+	if (IRQ_ports[state->irq]->next_port &&
+	    (was_multi != now_multi)) {
+		free_irq(state->irq, &IRQ_ports[state->irq]);
+		if (now_multi)
+			handler = rs_interrupt_multi;
+		else
+			handler = rs_interrupt;
+
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
+		if (retval) {
+			printk("Couldn't reallocate serial interrupt "
+			       "driver!!\n");
+		}
+	}
+	return 0;
+}
+#endif
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;	/* kernel counter temps */
+	struct serial_icounter_struct icount;
+	unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+	int retval, tmp;
+#endif
+	
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4);	/* 1/4 second */
+				if (signal_pending(current))
+					return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCGSOFTCAR:
+			tmp = C_CLOCAL(tty) ? 1 : 0;
+			if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+				return -EFAULT;
+			return 0;
+		case TIOCSSOFTCAR:
+			if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+				return -EFAULT;
+
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (tmp ? CLOCAL : 0));
+			return 0;
+#endif
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERCONFIG:
+			return do_autoconfig(info);
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+					 info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+				
+#ifdef CONFIG_SERIAL_MULTIPORT
+		case TIOCSERGETMULTI:
+			return get_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+		case TIOCSERSETMULTI:
+			return set_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+#endif
+			
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			save_flags(flags); cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			restore_flags(flags);
+			/* Force modem status interrupts on */
+			info->IER |= UART_IER_MSI;
+			serial_out(info, UART_IER, info->IER);
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				save_flags(flags); cli();
+				cnow = info->state->icount; /* atomic copy */
+				restore_flags(flags);
+				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			save_flags(flags); cli();
+			cnow = info->state->icount;
+			restore_flags(flags);
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+			
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
+			return 0;
+		case TIOCSERGWILD:
+		case TIOCSERSWILD:
+			/* "setserial -W" is called in Debian boot */
+			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	unsigned int cflag = tty->termios->c_cflag;
+	
+	if (   (cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info, old_termios);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) || 
+		    !test_bit(TTY_THROTTLED, &tty->flags)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		save_flags(flags); cli();
+		serial_out(info, UART_MCR, info->MCR);
+		restore_flags(flags);
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	restore_flags(flags);
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~UART_IER_RLSI;
+	info->read_status_mask &= ~UART_LSR_DR;
+	if (info->flags & ASYNC_INITIALIZED) {
+		serial_out(info, UART_IER, info->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		rs_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+
+	if (info->xmit_fifo_size == 0)
+		return; /* Just in case.... */
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout && timeout < char_time)
+		char_time = timeout;
+	/*
+	 * If the transmitter hasn't cleared in twice the approximate
+	 * amount of time to send the entire FIFO, it probably won't
+	 * ever clear.  This assumes the UART isn't doing flow
+	 * control, which is currently the case.  Hence, if it ever
+	 * takes longer than info->timeout, this is probably due to a
+	 * UART bug of some kind.  So, we clamp the timeout parameter at
+	 * 2*info->timeout.
+	 */
+	if (!timeout || timeout > 2*info->timeout)
+		timeout = 2*info->timeout;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+	while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+			break;
+	}
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state = info->state;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	state = info->state;
+	
+	rs_flush_buffer(tty);
+	if (info->flags & ASYNC_CLOSING)
+		return;
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct async_struct *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct serial_state *state = info->state;
+	int		retval;
+	int		do_clocal = 0, extra_count = 0;
+	unsigned long	flags;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       state->line, state->count);
+#endif
+	save_flags(flags); cli();
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1;
+		state->count--;
+	}
+	restore_flags(flags);
+	info->blocked_open++;
+	while (1) {
+		save_flags(flags); cli();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		restore_flags(flags);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, state->count);
+#endif
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, state->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	sstate->count++;
+	if (sstate->info) {
+		*ret_info = sstate->info;
+		return 0;
+	}
+	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	if (!info) {
+		sstate->count--;
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
+	info->magic = SERIAL_MAGIC;
+	info->port = sstate->port;
+	info->flags = sstate->flags;
+	info->io_type = sstate->io_type;
+	info->iomem_base = sstate->iomem_base;
+	info->iomem_reg_shift = sstate->iomem_reg_shift;
+	info->xmit_fifo_size = sstate->xmit_fifo_size;
+	info->line = line;
+	info->tqueue.routine = do_softint;
+	info->tqueue.data = info;
+	info->state = sstate;
+	if (sstate->info) {
+		kfree(info);
+		*ret_info = sstate->info;
+		return 0;
+	}
+	*ret_info = sstate->info = info;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ *
+ * Note that on failure, we don't decrement the module use count - the tty
+ * later will call rs_close, which will decrement it for us as long as
+ * tty->driver_data is set non-NULL. --rmk
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct	*info;
+	int 			retval, line;
+	unsigned long		page;
+
+	MOD_INC_USE_COUNT;
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT;
+		return -ENODEV;
+	}
+
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	tty->driver_data = info;
+	info->tty = tty;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->state->count);
+#endif
+#if (LINUX_VERSION_CODE > 0x20100)
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+
+	/*
+	 *	This relies on lock_kernel() stuff so wants tidying for 2.5
+	 */
+	if (!tmp_buf) {
+		page = get_zeroed_page(GFP_KERNEL);
+		if (!page)
+			return -ENOMEM;
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else 
+			*tty->termios = info->state->callout_termios;
+		change_speed(info, 0);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (sercons.cflag && sercons.index == line) {
+		tty->termios->c_cflag = sercons.cflag;
+		sercons.cflag = 0;
+		change_speed(info, 0);
+	}
+#endif
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+	struct async_struct *info = state->info, scr_info;
+	char	stat_buf[30], control, status;
+	int	ret;
+	unsigned long flags;
+
+	/*
+	 * Return zero characters for ports not claimed by driver.
+	 */
+	if (state->type == PORT_UNKNOWN) {
+		return 0;	/* ignore unused ports */
+	}
+
+	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
+		      state->line, uart_config[state->type].name, 
+		      (state->port ? state->port : (long)state->iomem_base),
+		      state->irq);
+
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info;	/* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->hub6 = state->hub6;
+		info->io_type = state->io_type;
+		info->iomem_base = state->iomem_base;
+		info->iomem_reg_shift = state->iomem_reg_shift;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	save_flags(flags); cli();
+	status = serial_in(info, UART_MSR);
+	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
+	restore_flags(flags); 
+
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+		strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+		strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+		strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       state->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+	return ret;
+}
+
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+			int *eof, void *data)
+{
+	int i, len = 0, l;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
+		       serial_version, LOCAL_VERSTRING, serial_revdate);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		l = line_info(page + len, &rs_table[i]);
+		len += l;
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (off-begin);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static char serial_options[] __initdata =
+#ifdef CONFIG_HUB6
+       " HUB-6"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       " MANY_PORTS"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MULTIPORT
+       " MULTIPORT"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+       " SHARE_IRQ"
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+       " DETECT_IRQ"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PCI
+       " SERIAL_PCI"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       " ISAPNP"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_ACPI
+       " SERIAL_ACPI"
+#define SERIAL_OPT
+#endif
+#ifdef SERIAL_OPT
+       " enabled\n";
+#else
+       " no serial options enabled\n";
+#endif
+#undef SERIAL_OPT
+
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+	       serial_version, LOCAL_VERSTRING, serial_revdate,
+	       serial_options);
+}
+
+/*
+ * This routine detect the IRQ of a serial port by clearing OUT2 when
+ * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
+ * each time, as long as no other device permanently request the IRQ.
+ * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
+ * The variable "state" and the field "state->port" should not be null.
+ */
+static unsigned detect_uart_irq (struct serial_state * state)
+{
+	int irq;
+	unsigned long irqs;
+	unsigned char save_mcr, save_ier;
+	struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	unsigned char save_ICP=0; /* no warning */
+	unsigned short ICP=0;
+
+	if (state->flags & ASYNC_FOURPORT)  {
+		ICP = (state->port & 0xFE0) | 0x01F;
+		save_ICP = inb_p(ICP);
+		outb_p(0x80, ICP);
+		(void) inb_p(ICP);
+	}
+#endif
+	scr_info.magic = SERIAL_MAGIC;
+	scr_info.state = state;
+	scr_info.port = state->port;
+	scr_info.flags = state->flags;
+#ifdef CONFIG_HUB6
+	scr_info.hub6 = state->hub6;
+#endif
+	scr_info.io_type = state->io_type;
+	scr_info.iomem_base = state->iomem_base;
+	scr_info.iomem_reg_shift = state->iomem_reg_shift;
+
+	/* forget possible initially masked and pending IRQ */
+	probe_irq_off(probe_irq_on());
+	save_mcr = serial_inp(&scr_info, UART_MCR);
+	save_ier = serial_inp(&scr_info, UART_IER);
+	serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+	
+	irqs = probe_irq_on();
+	serial_outp(&scr_info, UART_MCR, 0);
+	udelay (10);
+	if (state->flags & ASYNC_FOURPORT)  {
+		serial_outp(&scr_info, UART_MCR,
+			    UART_MCR_DTR | UART_MCR_RTS);
+	} else {
+		serial_outp(&scr_info, UART_MCR,
+			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+	}
+	serial_outp(&scr_info, UART_IER, 0x0f);	/* enable all intrs */
+	(void)serial_inp(&scr_info, UART_LSR);
+	(void)serial_inp(&scr_info, UART_RX);
+	(void)serial_inp(&scr_info, UART_IIR);
+	(void)serial_inp(&scr_info, UART_MSR);
+	serial_outp(&scr_info, UART_TX, 0xFF);
+	udelay (20);
+	irq = probe_irq_off(irqs);
+
+	serial_outp(&scr_info, UART_MCR, save_mcr);
+	serial_outp(&scr_info, UART_IER, save_ier);
+#ifdef CONFIG_SERIAL_MANY_PORTS
+	if (state->flags & ASYNC_FOURPORT)
+		outb_p(save_ICP, ICP);
+#endif
+	return (irq > 0)? irq : 0;
+}
+
+/*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct async_struct *info)
+{
+	unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+	int count;
+
+	old_fcr = serial_inp(info, UART_FCR);
+	old_mcr = serial_inp(info, UART_MCR);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP);
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	old_dll = serial_inp(info, UART_DLL);
+	old_dlm = serial_inp(info, UART_DLM);
+	serial_outp(info, UART_DLL, 0x01);
+	serial_outp(info, UART_DLM, 0x00);
+	serial_outp(info, UART_LCR, 0x03);
+	for (count = 0; count < 256; count++)
+		serial_outp(info, UART_TX, count);
+	mdelay(20);
+	for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+	     (count < 256); count++)
+		serial_inp(info, UART_RX);
+	serial_outp(info, UART_FCR, old_fcr);
+	serial_outp(info, UART_MCR, old_mcr);
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	serial_outp(info, UART_DLL, old_dll);
+	serial_outp(info, UART_DLM, old_dlm);
+
+	return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones.  (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not?  Startech doesn't seem to even acknowledge its
+ * existence.)
+ * 
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_startech_uarts(struct async_struct *info,
+				      struct serial_state *state,
+				      unsigned long flags)
+{
+	unsigned char scratch, scratch2, scratch3, scratch4;
+
+	/*
+	 * First we check to see if it's an Oxford Semiconductor UART.
+	 *
+	 * If we have to do this here because some non-National
+	 * Semiconductor clone chips lock up if you try writing to the
+	 * LSR register (which serial_icr_read does)
+	 */
+	if (state->type == PORT_16550A) {
+		/*
+		 * EFR [4] must be set else this test fails
+		 *
+		 * This shouldn't be necessary, but Mike Hudson
+		 * (Exoray@isys.ca) claims that it's needed for 952
+		 * dual UART's (which are not recommended for new designs).
+		 */
+		info->ACR = 0;
+		serial_out(info, UART_LCR, 0xBF);
+		serial_out(info, UART_EFR, 0x10);
+		serial_out(info, UART_LCR, 0x00);
+		/* Check for Oxford Semiconductor 16C950 */
+		scratch = serial_icr_read(info, UART_ID1);
+		scratch2 = serial_icr_read(info, UART_ID2);
+		scratch3 = serial_icr_read(info, UART_ID3);
+		
+		if (scratch == 0x16 && scratch2 == 0xC9 &&
+		    (scratch3 == 0x50 || scratch3 == 0x52 ||
+		     scratch3 == 0x54)) {
+			state->type = PORT_16C950;
+			state->revision = serial_icr_read(info, UART_REV) |
+				(scratch3 << 8);
+			return;
+		}
+	}
+	
+	/*
+	 * We check for a XR16C850 by setting DLL and DLM to 0, and
+	 * then reading back DLL and DLM.  If DLM reads back 0x10,
+	 * then the UART is a XR16C850 and the DLL contains the chip
+	 * revision.  If DLM reads back 0x14, then the UART is a
+	 * XR16C854.
+	 * 
+	 */
+
+	/* Save the DLL and DLM */
+
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	scratch3 = serial_inp(info, UART_DLL);
+	scratch4 = serial_inp(info, UART_DLM);
+
+	serial_outp(info, UART_DLL, 0);
+	serial_outp(info, UART_DLM, 0);
+	scratch2 = serial_inp(info, UART_DLL);
+	scratch = serial_inp(info, UART_DLM);
+	serial_outp(info, UART_LCR, 0);
+
+	if (scratch == 0x10 || scratch == 0x14) {
+		if (scratch == 0x10)
+			state->revision = scratch2;
+		state->type = PORT_16850;
+		return;
+	}
+
+	/* Restore the DLL and DLM */
+
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	serial_outp(info, UART_DLL, scratch3);
+	serial_outp(info, UART_DLM, scratch4);
+	serial_outp(info, UART_LCR, 0);
+	/*
+	 * We distinguish between the '654 and the '650 by counting
+	 * how many bytes are in the FIFO.  I'm using this for now,
+	 * since that's the technique that was sent to me in the
+	 * serial driver update, but I'm not convinced this works.
+	 * I've had problems doing this in the past.  -TYT
+	 */
+	if (size_fifo(info) == 64)
+		state->type = PORT_16654;
+	else
+		state->type = PORT_16650V2;
+}
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void autoconfig(struct serial_state * state)
+{
+	unsigned char status1, status2, scratch, scratch2, scratch3;
+	unsigned char save_lcr, save_mcr;
+	struct async_struct *info, scr_info;
+	unsigned long flags;
+
+	state->type = PORT_UNKNOWN;
+
+#ifdef SERIAL_DEBUG_AUTOCONF
+	printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
+	       state->port, (unsigned) state->iomem_base);
+#endif
+	
+	if (!CONFIGURED_SERIAL_PORT(state))
+		return;
+		
+	info = &scr_info;	/* This is just for serial_{in,out} */
+
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+#ifdef CONFIG_HUB6
+	info->hub6 = state->hub6;
+#endif
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+
+	save_flags(flags); cli();
+	
+	if (!(state->flags & ASYNC_BUGGY_UART) &&
+	    !state->iomem_base) {
+		/*
+		 * Do a simple existence test first; if we fail this,
+		 * there's no point trying anything else.
+		 * 
+		 * 0x80 is used as a nonsense port to prevent against
+		 * false positives due to ISA bus float.  The
+		 * assumption is that 0x80 is a non-existent port;
+		 * which should be safe since include/asm/io.h also
+		 * makes this assumption.
+		 */
+		scratch = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0);
+#ifdef __i386__
+		outb(0xff, 0x080);
+#endif
+		scratch2 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0x0F);
+#ifdef __i386__
+		outb(0, 0x080);
+#endif
+		scratch3 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, scratch);
+		if (scratch2 || scratch3 != 0x0F) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyS%d: simple autoconfig failed "
+			       "(%02x, %02x)\n", state->line, 
+			       scratch2, scratch3);
+#endif
+			restore_flags(flags);
+			return;		/* We failed; there's nothing here */
+		}
+	}
+
+	save_mcr = serial_in(info, UART_MCR);
+	save_lcr = serial_in(info, UART_LCR);
+
+	/* 
+	 * Check to see if a UART is really there.  Certain broken
+	 * internal modems based on the Rockwell chipset fail this
+	 * test, because they apparently don't implement the loopback
+	 * test mode.  So this test is skipped on the COM 1 through
+	 * COM 4 ports.  This *should* be safe, since no board
+	 * manufacturer would be stupid enough to design a board
+	 * that conflicts with COM 1-4 --- we hope!
+	 */
+	if (!(state->flags & ASYNC_SKIP_TEST)) {
+		serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+		status1 = serial_inp(info, UART_MSR) & 0xF0;
+		serial_outp(info, UART_MCR, save_mcr);
+		if (status1 != 0x90) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyS%d: no UART loopback failed\n",
+			       state->line);
+#endif
+			restore_flags(flags);
+			return;
+		}
+	}
+	serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
+	serial_outp(info, UART_EFR, 0);	/* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, 0);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = serial_in(info, UART_IIR) >> 6;
+	switch (scratch) {
+		case 0:
+			state->type = PORT_16450;
+			break;
+		case 1:
+			state->type = PORT_UNKNOWN;
+			break;
+		case 2:
+			state->type = PORT_16550;
+			break;
+		case 3:
+			state->type = PORT_16550A;
+			break;
+	}
+	if (state->type == PORT_16550A) {
+		/* Check for Startech UART's */
+		serial_outp(info, UART_LCR, UART_LCR_DLAB);
+		if (serial_in(info, UART_EFR) == 0) {
+			state->type = PORT_16650;
+		} else {
+			serial_outp(info, UART_LCR, 0xBF);
+			if (serial_in(info, UART_EFR) == 0)
+				autoconfig_startech_uarts(info, state, flags);
+		}
+	}
+	if (state->type == PORT_16550A) {
+		/* Check for TI 16750 */
+		serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
+		serial_outp(info, UART_FCR,
+			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+		scratch = serial_in(info, UART_IIR) >> 5;
+		if (scratch == 7) {
+			/*
+			 * If this is a 16750, and not a cheap UART
+			 * clone, then it should only go into 64 byte
+			 * mode if the UART_FCR7_64BYTE bit was set
+			 * while UART_LCR_DLAB was latched.
+			 */
+ 			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR,
+				    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+			scratch = serial_in(info, UART_IIR) >> 5;
+			if (scratch == 6)
+				state->type = PORT_16750;
+		}
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	}
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+	if (state->type == PORT_16550A) {
+		int i;
+
+		for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+			if (!probe_rsa[i] && !force_rsa[i])
+				break;
+			if (((probe_rsa[i] != state->port) ||
+			     check_region(state->port + UART_RSA_BASE, 16)) &&
+			    (force_rsa[i] != state->port))
+				continue;
+			if (!enable_rsa(info))
+				continue;
+			state->type = PORT_RSA;
+			state->baud_base = SERIAL_RSA_BAUD_BASE;
+			break;
+		}
+	}
+#endif
+	serial_outp(info, UART_LCR, save_lcr);
+	if (state->type == PORT_16450) {
+		scratch = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0xa5);
+		status1 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, 0x5a);
+		status2 = serial_in(info, UART_SCR);
+		serial_outp(info, UART_SCR, scratch);
+
+		if ((status1 != 0xa5) || (status2 != 0x5a))
+			state->type = PORT_8250;
+	}
+	state->xmit_fifo_size =	uart_config[state->type].dfl_xmit_fifo_size;
+
+	if (state->type == PORT_UNKNOWN) {
+		restore_flags(flags);
+		return;
+	}
+
+	if (info->port) {
+#ifdef CONFIG_SERIAL_RSA
+		if (state->type == PORT_RSA)
+			request_region(info->port + UART_RSA_BASE, 16,
+				       "serial_rsa(auto)");
+		else
+#endif
+			request_region(info->port,8,"serial(auto)");
+	}
+
+	/*
+	 * Reset the UART.
+	 */
+#ifdef CONFIG_SERIAL_RSA
+	if (state->type == PORT_RSA)
+		serial_outp(info, UART_RSA_FRR, 0);
+#endif
+	serial_outp(info, UART_MCR, save_mcr);
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
+				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
+	(void)serial_in(info, UART_RX);
+	serial_outp(info, UART_IER, 0);
+	
+	restore_flags(flags);
+}
+
+int register_serial(struct serial_struct *req);
+void unregister_serial(int line);
+
+#if (LINUX_VERSION_CODE > 0x20100)
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+#else
+static struct symbol_table serial_syms = {
+#include <linux/symtab_begin.h>
+	X(register_serial),
+	X(unregister_serial),
+#include <linux/symtab_end.h>
+};
+#endif
+
+
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) 
+
+static void __devinit printk_pnp_dev_id(unsigned short vendor,
+				     unsigned short device)
+{
+	printk("%c%c%c%x%x%x%x",
+	       'A' + ((vendor >> 2) & 0x3f) - 1,
+	       'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+	       'A' + ((vendor >> 8) & 0x1f) - 1,
+	       (device >> 4) & 0x0f,
+	       device & 0x0f,
+	       (device >> 12) & 0x0f,
+	       (device >> 8) & 0x0f);
+}
+
+static _INLINE_ int get_pci_port(struct pci_dev *dev,
+				  struct pci_board *board,
+				  struct serial_struct *req,
+				  int idx)
+{
+	unsigned long port;
+	int base_idx;
+	int max_port;
+	int offset;
+
+	base_idx = SPCI_FL_GET_BASE(board->flags);
+	if (board->flags & SPCI_FL_BASE_TABLE)
+		base_idx += idx;
+
+	if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+		max_port = pci_resource_len(dev, base_idx) / 8;
+		if (idx >= max_port)
+			return 1;
+	}
+			
+	offset = board->first_uart_offset;
+
+	/* Timedia/SUNIX uses a mixture of BARs and offsets */
+	/* Ugh, this is ugly as all hell --- TYT */
+	if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
+		switch(idx) {
+			case 0: base_idx=0;
+				break;
+			case 1: base_idx=0; offset=8;
+				break;
+			case 2: base_idx=1; 
+				break;
+			case 3: base_idx=1; offset=8;
+				break;
+			case 4: /* BAR 2*/
+			case 5: /* BAR 3 */
+			case 6: /* BAR 4*/
+			case 7: base_idx=idx-2; /* BAR 5*/
+		}
+
+	/* Some Titan cards are also a little weird */
+	if (dev->vendor == PCI_VENDOR_ID_TITAN &&
+	    (dev->device == PCI_DEVICE_ID_TITAN_400L ||
+	     dev->device == PCI_DEVICE_ID_TITAN_800L)) {
+		switch (idx) {
+		case 0: base_idx = 1;
+			break;
+		case 1: base_idx = 2;
+			break;
+		default:
+			base_idx = 4;
+			offset = 8 * (idx - 2);
+		}
+		
+	}
+  
+	/* HP's Diva chip puts the 4th/5th serial port further out, and
+	 * some serial ports are supposed to be hidden on certain models.
+	 */
+	if (dev->vendor == PCI_VENDOR_ID_HP &&
+			dev->device == PCI_DEVICE_ID_HP_SAS) {
+		switch (dev->subsystem_device) {
+		case 0x104B: /* Maestro */
+			if (idx == 3) idx++;
+			break;
+		case 0x1282: /* Everest / Longs Peak */
+			if (idx > 0) idx++;
+			if (idx > 2) idx++;
+			break;
+		}
+		if (idx > 2) {
+			offset = 0x18;
+		}
+	}
+
+	port =  pci_resource_start(dev, base_idx) + offset;
+
+	if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+		port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+	if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
+		req->port = port;
+		if (HIGH_BITS_OFFSET)
+			req->port_high = port >> HIGH_BITS_OFFSET;
+		else
+			req->port_high = 0;
+		return 0;
+	}
+	req->io_type = SERIAL_IO_MEM;
+	req->iomem_base = ioremap(port, board->uart_offset);
+	req->iomem_reg_shift = board->reg_shift;
+	req->port = 0;
+	return 0;
+}
+
+static _INLINE_ int get_pci_irq(struct pci_dev *dev,
+				struct pci_board *board,
+				int idx)
+{
+	int base_idx;
+
+	if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
+		return dev->irq;
+
+	base_idx = SPCI_FL_GET_IRQBASE(board->flags);
+	if (board->flags & SPCI_FL_IRQ_TABLE)
+		base_idx += idx;
+	
+	return PCI_IRQ_RESOURCE(dev, base_idx);
+}
+
+/*
+ * Common enabler code shared by both PCI and ISAPNP probes
+ */
+static void __devinit start_pci_pnp_board(struct pci_dev *dev,
+				       struct pci_board *board)
+{
+	int k, line;
+	struct serial_struct serial_req;
+	int base_baud;
+
+       if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+	       printk("serial: PNP device '");
+	       printk_pnp_dev_id(dev->vendor, dev->device);
+	       printk("' prepare failed\n");
+	       return;
+       }
+
+       if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+	       printk("serial: PNP device '");
+	       printk_pnp_dev_id(dev->vendor, dev->device);
+	       printk("' activate failed\n");
+	       return;
+       }
+
+	/*
+	 * Run the initialization function, if any
+	 */
+	if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
+		return;
+
+	/*
+	 * Register the serial board in the array if we need to
+	 * shutdown the board on a module unload or card removal
+	 */
+	if (DEACTIVATE_FUNC(dev) || board->init_fn) {
+		for (k=0; k < NR_PCI_BOARDS; k++)
+			if (serial_pci_board[k].dev == 0)
+				break;
+		if (k >= NR_PCI_BOARDS)
+			return;
+		serial_pci_board[k].board = *board;
+		serial_pci_board[k].dev = dev;
+	}
+
+	base_baud = board->base_baud;
+	if (!base_baud)
+		base_baud = BASE_BAUD;
+	memset(&serial_req, 0, sizeof(serial_req));
+
+	for (k=0; k < board->num_ports; k++) {
+		serial_req.irq = get_pci_irq(dev, board, k);
+		if (get_pci_port(dev, board, &serial_req, k))
+			break;
+		serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
+#ifdef SERIAL_DEBUG_PCI
+		printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
+		       serial_req.port, serial_req.irq, serial_req.io_type);
+#endif
+		line = register_serial(&serial_req);
+		if (line < 0)
+			break;
+		rs_table[line].baud_base = base_baud;
+		rs_table[line].dev = dev;
+	}
+}
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+
+#ifdef ENABLE_SERIAL_PCI
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled.  This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int __devinit
+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	u8 data, *p, irq_config;
+	int pci_config;
+
+	irq_config = 0x41;
+	pci_config = PCI_COMMAND_MEMORY;
+	if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+		irq_config = 0x43;
+	if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+	    (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
+		/*
+		 * As the megawolf cards have the int pins active
+		 * high, and have 2 UART chips, both ints must be
+		 * enabled on the 9050. Also, the UARTS are set in
+		 * 16450 mode by default, so we have to enable the
+		 * 16C950 'enhanced' mode so that we can use the deep
+		 * FIFOs
+		 */
+		irq_config = 0x5b;
+		pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+	}
+	
+	pci_read_config_byte(dev, PCI_COMMAND, &data);
+
+	if (enable)
+		pci_write_config_byte(dev, PCI_COMMAND,
+				      data | pci_config);
+	
+	/* enable/disable interrupts */
+	p = ioremap(pci_resource_start(dev, 0), 0x80);
+	writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
+	iounmap(p);
+
+	if (!enable)
+		pci_write_config_byte(dev, PCI_COMMAND,
+				      data & ~pci_config);
+	return 0;
+}
+
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ *  SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
+ * 
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ *     - 10x cards have control registers in IO and/or memory space;
+ *     - 20x cards have control registers in standard PCI configuration space.
+ *
+ * SIIG initialization functions exported for use by parport_serial.c module.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+int __devinit
+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u16 data, *p;
+
+       if (!enable) return 0;
+
+       p = ioremap(pci_resource_start(dev, 0), 0x80);
+
+       switch (dev->device & 0xfff8) {
+               case PCI_DEVICE_ID_SIIG_1S_10x:         /* 1S */
+                       data = 0xffdf;
+                       break;
+               case PCI_DEVICE_ID_SIIG_2S_10x:         /* 2S, 2S1P */
+                       data = 0xf7ff;
+                       break;
+               default:                                /* 1S1P, 4S */
+                       data = 0xfffb;
+                       break;
+       }
+
+       writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
+       iounmap(p);
+       return 0;
+}
+EXPORT_SYMBOL(pci_siig10x_fn);
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+int __devinit
+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u8 data;
+
+       if (!enable) return 0;
+
+       /* Change clock frequency for the first UART. */
+       pci_read_config_byte(dev, 0x6f, &data);
+       pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+       /* If this card has 2 UART, we have to do the same with second UART. */
+       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+               pci_read_config_byte(dev, 0x73, &data);
+               pci_write_config_byte(dev, 0x73, data & 0xef);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(pci_siig20x_fn);
+
+/* Added for EKF Intel i960 serial boards */
+static int __devinit
+pci_inteli960ni_fn(struct pci_dev *dev,
+		   struct pci_board *board,
+		   int enable)
+{
+	unsigned long oldval;
+	
+	if (!(pci_get_subdevice(dev) & 0x1000))
+		return(-1);
+
+	if (!enable) /* is there something to deinit? */
+		return(0);
+   
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
+	       (unsigned long) board->subdevice);
+#endif
+	/* is firmware started? */
+	pci_read_config_dword(dev, 0x44, (void*) &oldval); 
+	if (oldval == 0x00001000L) { /* RESET value */ 
+		printk(KERN_DEBUG "Local i960 firmware missing");
+		return(-1); 
+	}
+	return(0);
+}
+
+/*
+ * Timedia has an explosion of boards, and to avoid the PCI table from
+ * growing *huge*, we use this function to collapse some 70 entries
+ * in the PCI table into one, for sanity's and compactness's sake.
+ */
+static unsigned short timedia_single_port[] = {
+	0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 };
+static unsigned short timedia_dual_port[] = {
+	0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
+	0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, 
+	0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 
+	0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
+	0xD079, 0 };
+static unsigned short timedia_quad_port[] = {
+	0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, 
+	0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 
+	0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
+	0xB157, 0 };
+static unsigned short timedia_eight_port[] = {
+	0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 
+	0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 };
+static struct timedia_struct {
+	int num;
+	unsigned short *ids;
+} timedia_data[] = {
+	{ 1, timedia_single_port },
+	{ 2, timedia_dual_port },
+	{ 4, timedia_quad_port },
+	{ 8, timedia_eight_port },
+	{ 0, 0 }
+};
+
+static int __devinit
+pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	int	i, j;
+	unsigned short *ids;
+
+	if (!enable)
+		return 0;
+
+	for (i=0; timedia_data[i].num; i++) {
+		ids = timedia_data[i].ids;
+		for (j=0; ids[j]; j++) {
+			if (pci_get_subdevice(dev) == ids[j]) {
+				board->num_ports = timedia_data[i].num;
+				return 0;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * HP's Remote Management Console.  The Diva chip came in several
+ * different versions.  N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused).  Superdome
+ * and Keystone have one Diva chip with 3 UARTs.  Some later machines have
+ * one Diva chip, but it has been expanded to 5 UARTs.
+ */
+static int __devinit
+pci_hp_diva(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	if (!enable)
+		return 0;
+
+	switch (dev->subsystem_device) {
+	case 0x1049: /* Prelude Diva 1 */
+	case 0x1223: /* Superdome */
+	case 0x1226: /* Keystone */
+	case 0x1282: /* Everest / Longs Peak */
+		board->num_ports = 3;
+		break;
+	case 0x104A: /* Prelude Diva 2 */
+		board->num_ports = 2;
+		break;
+	case 0x104B: /* Maestro */
+		board->num_ports = 4;
+		break;
+	case 0x1227: /* Powerbar */
+		board->num_ports = 1;
+		break;
+	}
+
+	return 0;
+}
+
+static int __devinit
+pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+	return 0;
+}
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.  It is directly indexed by the pci_board_num_t enum
+ * value, which is encoded in the pci_device_id PCI probe table's
+ * driver_data member.
+ */
+enum pci_board_num_t {
+	pbn_b0_1_115200,
+	pbn_default = 0,
+
+	pbn_b0_2_115200,
+	pbn_b0_4_115200,
+
+	pbn_b0_1_921600,
+	pbn_b0_2_921600,
+	pbn_b0_4_921600,
+
+	pbn_b0_bt_1_115200,
+	pbn_b0_bt_2_115200,
+	pbn_b0_bt_1_460800,
+	pbn_b0_bt_2_460800,
+	pbn_b0_bt_2_921600,
+
+	pbn_b1_1_115200,
+	pbn_b1_2_115200,
+	pbn_b1_4_115200,
+	pbn_b1_8_115200,
+
+	pbn_b1_2_921600,
+	pbn_b1_4_921600,
+	pbn_b1_8_921600,
+
+	pbn_b1_2_1382400,
+	pbn_b1_4_1382400,
+	pbn_b1_8_1382400,
+
+	pbn_b2_1_115200,
+	pbn_b2_8_115200,
+	pbn_b2_4_460800,
+	pbn_b2_8_460800,
+	pbn_b2_16_460800,
+	pbn_b2_4_921600,
+	pbn_b2_8_921600,
+
+	pbn_b2_bt_1_115200,
+	pbn_b2_bt_2_115200,
+	pbn_b2_bt_4_115200,
+	pbn_b2_bt_2_921600,
+
+	pbn_panacom,
+	pbn_panacom2,
+	pbn_panacom4,
+	pbn_plx_romulus,
+	pbn_oxsemi,
+	pbn_timedia,
+	pbn_intel_i960,
+	pbn_sgi_ioc3,
+	pbn_hp_diva,
+#ifdef CONFIG_DDB5074
+	pbn_nec_nile4,
+#endif
+#if 0
+	pbn_dci_pccom8,
+#endif
+	pbn_xircom_combo,
+
+	pbn_siig10x_0,
+	pbn_siig10x_1,
+	pbn_siig10x_2,
+	pbn_siig10x_4,
+	pbn_siig20x_0,
+	pbn_siig20x_2,
+	pbn_siig20x_4,
+	
+	pbn_computone_4,
+	pbn_computone_6,
+	pbn_computone_8,
+};
+
+static struct pci_board pci_boards[] __devinitdata = {
+	/*
+	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+	 * Offset to get to next UART's registers,
+	 * Register shift to use for memory-mapped I/O,
+	 * Initialization function, first UART offset
+	 */
+
+	/* Generic serial board, pbn_b0_1_115200, pbn_default */
+	{ SPCI_FL_BASE0, 1, 115200 },		/* pbn_b0_1_115200,
+						   pbn_default */
+
+	{ SPCI_FL_BASE0, 2, 115200 },		/* pbn_b0_2_115200 */
+	{ SPCI_FL_BASE0, 4, 115200 },		/* pbn_b0_4_115200 */
+
+	{ SPCI_FL_BASE0, 1, 921600 },		/* pbn_b0_1_921600 */
+	{ SPCI_FL_BASE0, 2, 921600 },		/* pbn_b0_2_921600 */
+	{ SPCI_FL_BASE0, 4, 921600 },		/* pbn_b0_4_921600 */
+
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
+
+	{ SPCI_FL_BASE1, 1, 115200 },		/* pbn_b1_1_115200 */
+	{ SPCI_FL_BASE1, 2, 115200 },		/* pbn_b1_2_115200 */
+	{ SPCI_FL_BASE1, 4, 115200 },		/* pbn_b1_4_115200 */
+	{ SPCI_FL_BASE1, 8, 115200 },		/* pbn_b1_8_115200 */
+
+	{ SPCI_FL_BASE1, 2, 921600 },		/* pbn_b1_2_921600 */
+	{ SPCI_FL_BASE1, 4, 921600 },		/* pbn_b1_4_921600 */
+	{ SPCI_FL_BASE1, 8, 921600 },		/* pbn_b1_8_921600 */
+
+	{ SPCI_FL_BASE1, 2, 1382400 },		/* pbn_b1_2_1382400 */
+	{ SPCI_FL_BASE1, 4, 1382400 },		/* pbn_b1_4_1382400 */
+	{ SPCI_FL_BASE1, 8, 1382400 },		/* pbn_b1_8_1382400 */
+
+	{ SPCI_FL_BASE2, 1, 115200 },		/* pbn_b2_1_115200 */
+	{ SPCI_FL_BASE2, 8, 115200 },		/* pbn_b2_8_115200 */
+	{ SPCI_FL_BASE2, 4, 460800 },		/* pbn_b2_4_460800 */
+	{ SPCI_FL_BASE2, 8, 460800 },		/* pbn_b2_8_460800 */
+	{ SPCI_FL_BASE2, 16, 460800 },		/* pbn_b2_16_460800 */
+	{ SPCI_FL_BASE2, 4, 921600 },		/* pbn_b2_4_921600 */
+	{ SPCI_FL_BASE2, 8, 921600 },		/* pbn_b2_8_921600 */
+
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
+
+	{ SPCI_FL_BASE2, 2, 921600, /* IOMEM */		   /* pbn_panacom */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_panacom2 */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_panacom4 */
+		0x400, 7, pci_plx9050_fn },
+	{ SPCI_FL_BASE2, 4, 921600,			   /* pbn_plx_romulus */
+		0x20, 2, pci_plx9050_fn, 0x03 },
+		/* This board uses the size of PCI Base region 0 to
+		 * signal now many ports are available */
+	{ SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
+	{ SPCI_FL_BASE_TABLE, 1, 921600,		   /* pbn_timedia */
+		0, 0, pci_timedia_fn },
+	/* EKF addition for i960 Boards form EKF with serial port */
+	{ SPCI_FL_BASE0, 32, 921600, /* max 256 ports */   /* pbn_intel_i960 */
+		8<<2, 2, pci_inteli960ni_fn, 0x10000},
+	{ SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,		   /* pbn_sgi_ioc3 */
+		1, 458333, 0, 0, 0, 0x20178 },
+	{ SPCI_FL_BASE0, 5, 115200, 8, 0, pci_hp_diva, 0},   /* pbn_hp_diva */
+#ifdef CONFIG_DDB5074
+	/*
+	 * NEC Vrc-5074 (Nile 4) builtin UART.
+	 * Conditionally compiled in since this is a motherboard device.
+	 */
+	{ SPCI_FL_BASE0, 1, 520833,			   /* pbn_nec_nile4 */
+		64, 3, NULL, 0x300 },
+#endif
+#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */		   /* pbn_dci_pccom8 */
+	{ SPCI_FL_BASE3, 8, 115200, 8 },
+#endif
+	{ SPCI_FL_BASE0, 1, 115200,			  /* pbn_xircom_combo */
+		0, 0, pci_xircom_fn },
+
+	{ SPCI_FL_BASE2, 1, 460800,			   /* pbn_siig10x_0 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2, 1, 921600,			   /* pbn_siig10x_1 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siig10x_2 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siig10x_4 */
+		0, 0, pci_siig10x_fn },
+	{ SPCI_FL_BASE0, 1, 921600,			   /* pbn_siix20x_0 */
+		0, 0, pci_siig20x_fn },
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siix20x_2 */
+		0, 0, pci_siig20x_fn },
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siix20x_4 */
+		0, 0, pci_siig20x_fn },
+
+	{ SPCI_FL_BASE0, 4, 921600, /* IOMEM */		   /* pbn_computone_4 */
+		0x40, 2, NULL, 0x200 },
+	{ SPCI_FL_BASE0, 6, 921600, /* IOMEM */		   /* pbn_computone_6 */
+		0x40, 2, NULL, 0x200 },
+	{ SPCI_FL_BASE0, 8, 921600, /* IOMEM */		   /* pbn_computone_8 */
+		0x40, 2, NULL, 0x200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int __devinit serial_pci_guess_board(struct pci_dev *dev,
+					   struct pci_board *board)
+{
+	int	num_iomem = 0, num_port = 0, first_port = -1;
+	int	i;
+	
+	/*
+	 * If it is not a communications device or the programming
+	 * interface is greater than 6, give up.
+	 *
+	 * (Should we try to make guesses for multiport serial devices
+	 * later?) 
+	 */
+	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+	    ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
+	    (dev->class & 0xff) > 6)
+		return 1;
+
+	for (i=0; i < 6; i++) {
+		if (IS_PCI_REGION_IOPORT(dev, i)) {
+			num_port++;
+			if (first_port == -1)
+				first_port = i;
+		}
+		if (IS_PCI_REGION_IOMEM(dev, i))
+			num_iomem++;
+	}
+
+	/*
+	 * If there is 1 or 0 iomem regions, and exactly one port, use
+	 * it.
+	 */
+	if (num_iomem <= 1 && num_port == 1) {
+		board->flags = first_port;
+		return 0;
+	}
+	return 1;
+}
+
+static int __devinit serial_init_one(struct pci_dev *dev,
+				     const struct pci_device_id *ent)
+{
+	struct pci_board *board, tmp;
+	int rc;
+
+	board = &pci_boards[ent->driver_data];
+
+	rc = pci_enable_device(dev);
+	if (rc) return rc;
+
+	if (ent->driver_data == pbn_default &&
+	    serial_pci_guess_board(dev, board))
+		return -ENODEV;
+	else if (serial_pci_guess_board(dev, &tmp) == 0) {
+		printk(KERN_INFO "Redundant entry in serial pci_table.  "
+		       "Please send the output of\n"
+		       "lspci -vv, this message (%04x,%04x,%04x,%04x)\n"
+		       "and the manufacturer and name of "
+		       "serial board or modem board\n"
+		       "to serial-pci-info@lists.sourceforge.net.\n",
+		       dev->vendor, dev->device,
+		       pci_get_subvendor(dev), pci_get_subdevice(dev));
+	}
+		       
+	start_pci_pnp_board(dev, board);
+
+	return 0;
+}
+
+static void __devexit serial_remove_one(struct pci_dev *dev)
+{
+	int	i;
+
+	/*
+	 * Iterate through all of the ports finding those that belong
+	 * to this PCI device.
+	 */
+	for(i = 0; i < NR_PORTS; i++) {
+		if (rs_table[i].dev != dev)
+			continue;
+		unregister_serial(i);
+		rs_table[i].dev = 0;
+	}
+	/*
+	 * Now execute any board-specific shutdown procedure
+	 */
+	for (i=0; i < NR_PCI_BOARDS; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+
+		if (serial_pci_board[i].dev != dev)
+			continue;
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
+		serial_pci_board[i].dev = 0;
+	}
+}
+
+
+static struct pci_device_id serial_pci_tbl[] __devinitdata = {
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+		pbn_b1_8_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+		pbn_b1_4_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+		pbn_b1_2_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
+		pbn_b1_8_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
+		pbn_b1_4_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
+		pbn_b1_2_1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
+		pbn_b1_8_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
+		pbn_b1_8_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
+		pbn_b1_4_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
+		pbn_b1_4_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
+		pbn_b1_2_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
+		pbn_b1_8_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
+		pbn_b1_8_921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
+		pbn_b1_4_921600 },
+
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_1_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_2_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_4_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_2_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_bt_4_115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_8_115200 },
+
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_115200 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_921600 },
+	/* VScom SPCOM800, from sl@s.pl */
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_8_921600 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b2_4_921600 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_KEYSPAN,
+		PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
+		pbn_panacom },
+	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_panacom4 },
+	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_panacom2 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, 
+		pbn_b2_4_460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, 
+		pbn_b2_8_460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, 
+		pbn_b2_16_460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, 
+		pbn_b2_16_460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, 
+		pbn_b2_4_460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, 
+		pbn_b2_8_460800 },
+	/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+	/* (Exoray@isys.ca) */
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
+		0x10b5, 0x106a, 0, 0,
+		pbn_plx_romulus },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_4_115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_2_115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_8_115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_8_115200 },
+	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, 
+		pbn_b0_4_921600 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_115200 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_bt_2_921600 },
+
+	/* Digitan DS560-558, from jimd@esoft.com */
+	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b1_1_115200 },
+
+	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+	{	PCI_VENDOR_ID_USR, 0x1008,
+		PCI_ANY_ID, PCI_ANY_ID, },
+
+	/* Titan Electronic cards */
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_1_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_2_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+		pbn_b0_4_921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 1, 921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
+	/* The 400L and 800L have a custom hack in get_pci_port */
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE_TABLE, 4, 921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE_TABLE, 8, 921600 },
+
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig10x_4 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_0 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_2 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_siig20x_4 },
+
+	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+		0, 0, pbn_computone_4 },
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+		0, 0, pbn_computone_8 },
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+		0, 0, pbn_computone_6 },
+
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
+	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+		PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
+
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_1_115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_1_460800 },
+
+	/* RAStel 2 port modem, gerg@moreton.com.au */
+	{	PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_bt_2_115200 },
+
+	/* EKF addition for i960 Boards form EKF with serial port */
+	{	PCI_VENDOR_ID_INTEL, 0x1960,
+		0xE4BF, PCI_ANY_ID, 0, 0,
+		pbn_intel_i960 },
+
+	/* Xircom Cardbus/Ethernet combos */
+	{	PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_xircom_combo },
+
+	/*
+	 * Untested PCI modems, sent in from various folks...
+	 */
+
+	/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
+	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
+		0x1048, 0x1500, 0, 0,
+		pbn_b1_1_115200 },
+
+	{	PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
+		0xFF00, 0, 0, 0,
+		pbn_sgi_ioc3 },
+
+	/* HP Diva card */
+	{	PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_SAS,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_hp_diva },
+	{	PCI_VENDOR_ID_HP, 0x1290,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b2_1_115200 },
+
+#ifdef CONFIG_DDB5074
+	/*
+	 * NEC Vrc-5074 (Nile 4) builtin UART.
+	 * Conditionally compiled in since this is a motherboard device.
+	 */
+	{	PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_nec_nile4 },
+#endif
+
+#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */
+	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_dci_pccom8 },
+#endif
+
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
+       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	 PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
+       { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
+
+static struct pci_driver serial_pci_driver = {
+       name:           "serial",
+       probe:          serial_init_one,
+       remove:	       __devexit_p(serial_remove_one),
+       id_table:       serial_pci_tbl,
+};
+
+
+/*
+ * Query PCI space for known serial boards
+ * If found, add them to the PCI device space in rs_table[]
+ *
+ * Accept a maximum of eight boards
+ *
+ */
+static void __devinit probe_serial_pci(void) 
+{
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+#endif
+
+	/* Register call PCI serial devices.  Null out
+	 * the driver name upon failure, as a signal
+	 * not to attempt to unregister the driver later
+	 */
+	if (pci_module_init (&serial_pci_driver) != 0)
+		serial_pci_driver.name = "";
+
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+#endif
+	return;
+}
+
+#endif /* ENABLE_SERIAL_PCI */
+
+#ifdef ENABLE_SERIAL_PNP
+
+struct pnp_board {
+	unsigned short vendor;
+	unsigned short device;
+};
+
+static struct pnp_board pnp_devices[] __devinitdata = {
+	/* Archtek America Corp. */
+	/* Archtek SmartLink Modem 3334BT Plug & Play */
+	{	ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+	/* Anchor Datacomm BV */
+	/* SXPro 144 External Data Fax Modem Plug & Play */
+	{	ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
+	/* SXPro 288 External Data Fax Modem Plug & Play */
+	{	ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
+	/* Rockwell 56K ACF II Fax+Data+Voice Modem */
+	{	ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
+	/* AZT3005 PnP SOUND DEVICE */
+	{	ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
+	/* Best Data Products Inc. Smart One 336F PnP Modem */
+	{	ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+	/*  Boca Research */
+	/* Boca Complete Ofc Communicator 14.4 Data-FAX */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+	/* Boca Research 33,600 ACF Modem */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
+	/* Boca 33.6 Kbps Internal FD34FSVD */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
+	/* Boca 33.6 Kbps Internal FD34FSVD */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+	/* Best Data Products Inc. Smart One 336F PnP Modem */
+	{	ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+	/* Computer Peripherals Inc */
+	/* EuroViVa CommCenter-33.6 SP PnP */
+	{	ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
+	/* Creative Labs */
+	/* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+	{	ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
+	/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+	{	ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
+	/* Creative */
+	/* Creative Modem Blaster Flash56 DI5601-1 */
+	{	ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
+	/* Creative Modem Blaster V.90 DI5660 */
+	{	ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
+	/* FUJITSU */
+	/* Fujitsu 33600 PnP-I2 R Plug & Play */
+	{	ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
+	/* Fujitsu FMV-FX431 Plug & Play */
+	{	ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
+	/* Fujitsu 33600 PnP-I4 R Plug & Play */
+	{	ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
+	/* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+	{	ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
+	/* Archtek America Corp. */
+	/* Archtek SmartLink Modem 3334BT Plug & Play */
+	{	ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
+	/* Hayes */
+	/* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
+	/* Hayes Optima 336 V.34 + FAX + Voice PnP */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
+	/* Hayes Optima 336B V.34 + FAX + Voice PnP */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
+	/* Hayes Accura 56K Ext Fax Modem PnP */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
+	/* Hayes Accura 56K Ext Fax Modem PnP */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
+	/* Hayes Accura 56K Fax Modem PnP */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
+	/* Hayes 288, V.34 + FAX */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
+	/* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+	{	ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
+	/* IBM */
+	/* IBM Thinkpad 701 Internal Modem Voice */
+	{	ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
+	/* Intertex */
+	/* Intertex 28k8 33k6 Voice EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
+	/* Intertex 33k6 56k Voice EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
+	/* Intertex 28k8 33k6 Voice SP EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
+	/* Intertex 33k6 56k Voice SP EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
+	/* Intertex 28k8 33k6 Voice SP INT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
+	/* Intertex 28k8 33k6 Voice SP EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
+	/* Intertex 33k6 56k Voice SP EXT PnP */
+	{	ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
+	/* Kortex International */
+	/* KORTEX 28800 Externe PnP */
+	{	ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
+	/* KXPro 33.6 Vocal ASVD PnP */
+	{	ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
+	/* Lasat */
+	/* LASAT Internet 33600 PnP */
+	{	ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
+	/* Lasat Safire 560 PnP */
+	{	ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
+	/* Lasat Safire 336  PnP */
+	{	ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
+	/* Microcom, Inc. */
+	/* Microcom TravelPorte FAST V.34 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
+	/* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
+	/* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
+	/* Microcom DeskPorte 28.8P Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
+	/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+	/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+	/* Microcom DeskPorte 28.8S Internal Plug & Play */
+	{	ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
+	/* Motorola */
+	/* Motorola BitSURFR Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
+	/* Motorola TA210 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
+	/* Motorola HMTA 200 (ISDN) Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
+	/* Motorola BitSURFR Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
+	/* Motorola Lifestyle 28.8 Internal */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
+	/* Motorola V.3400 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
+	/* Motorola Lifestyle 28.8 V.34 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
+	/* Motorola Power 28.8 V.34 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
+	/* Motorola ModemSURFR External 28.8 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
+	/* Motorola Premier 33.6 Desktop Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
+	/* Motorola VoiceSURFR 56K External PnP */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
+	/* Motorola ModemSURFR 56K External PnP */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
+	/* Motorola ModemSURFR 56K Internal PnP */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
+	/* Motorola ModemSURFR Internal 28.8 Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
+	/* Motorola Premier 33.6 Internal Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
+	/* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
+	/* Motorola VoiceSURFR 56K Internal PnP */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
+	/* Com 1 */
+	/*  Deskline K56 Phone System PnP */
+	{	ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
+	/* PC Rider K56 Phone System PnP */
+	{	ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
+	/* Pace 56 Voice Internal Plug & Play Modem */
+	{	ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
+	/* Generic */
+	/* Generic standard PC COM port	 */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+	/* Generic 16550A-compatible COM port */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+	/* Compaq 14400 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
+	/* Compaq 2400/9600 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
+	/* Dial-Up Networking Serial Cable between 2 PCs */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
+	/* Dial-Up Networking Parallel Cable between 2 PCs */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
+	/* Standard 9600 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
+	/* Standard 14400 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
+	/*  Standard 28800 bps Modem*/
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
+	/*  Standard Modem*/
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
+	/*  Standard 9600 bps Modem*/
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
+	/*  Standard 14400 bps Modem*/
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
+	/*  Standard 28800 bps Modem*/
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
+	/*  Standard Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
+	/* Standard 9600 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
+	/* Standard 14400 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
+	/* Standard 28800 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
+	/* Standard Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
+	/* Standard 9600 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
+	/* Standard 14400 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
+	/* Standard 28800 bps Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
+	/* Standard Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
+	/* Standard PCMCIA Card Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
+	/* Rockwell */
+	/* Modular Technology */
+	/* Rockwell 33.6 DPF Internal PnP */
+	/* Modular Technology 33.6 Internal PnP */
+	{	ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
+	/* Kortex International */
+	/* KORTEX 14400 Externe PnP */
+	{	ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
+	/* Viking Components, Inc */
+	/* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+	{	ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
+	/* Rockwell */
+	/* British Telecom */
+	/* Modular Technology */
+	/* Rockwell 33.6 DPF External PnP */
+	/* BT Prologue 33.6 External PnP */
+	/* Modular Technology 33.6 External PnP */
+	{	ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
+	/* Viking 56K FAX INT */
+	{	ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
+	/* SupraExpress 28.8 Data/Fax PnP modem */
+	{	ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
+	/* SupraExpress 33.6 Data/Fax PnP modem */
+	{	ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
+	/* SupraExpress 33.6 Data/Fax PnP modem */
+	{	ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
+	/* SupraExpress 33.6 Data/Fax PnP modem */
+	{	ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
+	/* Phoebe Micro */
+	/* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+	{	ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
+	/* Archtek America Corp. */
+	/* Archtek SmartLink Modem 3334BT Plug & Play */
+	{	ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+	/* 3Com Corp. */
+	/* Gateway Telepath IIvi 33.6 */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
+	/*  Sportster Vi 14.4 PnP FAX Voicemail */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
+	/* U.S. Robotics 33.6K Voice INT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
+	/* U.S. Robotics 33.6K Voice EXT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
+	/* U.S. Robotics 33.6K Voice INT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
+	/* U.S. Robotics 56K Voice INT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
+	/* U.S. Robotics 56K Voice EXT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
+	/* U.S. Robotics 56K FAX INT */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
+	/* U.S. Robotics 56K Voice INT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
+	/* U.S. Robotics 56K Voice EXT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
+	/* U.S. Robotics 56K Voice INT PnP */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
+	/* U.S. Robotics 56K Message  */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
+	/*  U.S. Robotics 56K FAX EXT PnP*/
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
+	/*  U.S. Robotics 56K FAX INT PnP*/
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
+	/*  U.S. Robotics 56K Voice EXT PnP*/
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
+	/*  U.S. Robotics 56K Voice INT PnP*/
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
+	{	0, }
+};
+
+static inline void avoid_irq_share(struct pci_dev *dev)
+{
+	int i, map = 0x1FF8;
+	struct serial_state *state = rs_table;
+	struct isapnp_irq *irq;
+	struct isapnp_resources *res = dev->sysdata;
+
+	for (i = 0; i < NR_PORTS; i++) {
+		if (state->type != PORT_UNKNOWN)
+			clear_bit(state->irq, &map);
+		state++;
+	}
+
+	for ( ; res; res = res->alt)
+		for(irq = res->irq; irq; irq = irq->next)
+			irq->map = map;
+}
+
+static char *modem_names[] __devinitdata = {
+       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+       "56K", "56k", "K56", "33.6", "28.8", "14.4",
+       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+       "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int __devinit check_name(char *name)
+{
+       char **tmp = modem_names;
+
+       while (*tmp) {
+               if (strstr(name, *tmp))
+                       return 1;
+               tmp++;
+       }
+       return 0;
+}
+
+static inline int check_compatible_id(struct pci_dev *dev)
+{
+       int i;
+       for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
+	       if ((dev->vendor_compatible[i] ==
+		    ISAPNP_VENDOR('P', 'N', 'P')) &&
+		   (swab16(dev->device_compatible[i]) >= 0xc000) &&
+		   (swab16(dev->device_compatible[i]) <= 0xdfff))
+		       return 0;
+       return 1;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ *     - dev->name or dev->bus->name must contain "modem" substring;
+ *     - device must have only one IO region (8 byte long) with base adress
+ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+					  struct pci_board *board)
+{
+       struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+       struct isapnp_resources *resa;
+
+       if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
+	   !(check_compatible_id(dev)))
+	       return 1;
+
+       if (!res || res->next)
+	       return 1;
+
+       for (resa = res->alt; resa; resa = resa->alt) {
+	       struct isapnp_port *port;
+	       for (port = res->port; port; port = port->next)
+		       if ((port->size == 8) &&
+			   ((port->min == 0x2f8) ||
+			    (port->min == 0x3f8) ||
+			    (port->min == 0x2e8) ||
+			    (port->min == 0x3e8)))
+			       return 0;
+       }
+
+       return 1;
+}
+
+static void __devinit probe_serial_pnp(void)
+{
+       struct pci_dev *dev = NULL;
+       struct pnp_board *pnp_board;
+       struct pci_board board;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Entered probe_serial_pnp()\n");
+#endif
+       if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+               printk("Leaving probe_serial_pnp() (no isapnp)\n");
+#endif
+               return;
+       }
+
+       isapnp_for_each_dev(dev) {
+	       if (dev->active)
+		       continue;
+
+	       memset(&board, 0, sizeof(board));
+	       board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
+	       board.num_ports = 1;
+	       board.base_baud = 115200;
+	       
+	       for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
+		       if ((dev->vendor == pnp_board->vendor) &&
+			   (dev->device == pnp_board->device))
+			       break;
+
+	       if (pnp_board->vendor) {
+		       /* Special case that's more efficient to hardcode */
+		       if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+			    pnp_board->device == ISAPNP_DEVICE(0x1021)))
+			       board.flags |= SPCI_FL_NO_SHIRQ;
+	       } else {
+		       if (serial_pnp_guess_board(dev, &board))
+			       continue;
+	       }
+	       
+	       if (board.flags & SPCI_FL_NO_SHIRQ)
+		       avoid_irq_share(dev);
+	       start_pci_pnp_board(dev, &board);
+       }
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Leaving probe_serial_pnp() (probe finished)\n");
+#endif
+       return;
+}
+
+#endif /* ENABLE_SERIAL_PNP */
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+static int __init rs_init(void)
+{
+	int i;
+	struct serial_state * state;
+
+	init_bh(SERIAL_BH, do_serial_bh);
+	init_timer(&serial_timer);
+	serial_timer.function = rs_timer;
+	mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
+
+	for (i = 0; i < NR_IRQS; i++) {
+		IRQ_ports[i] = 0;
+		IRQ_timeout[i] = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT
+		memset(&rs_multiport[i], 0,
+		       sizeof(struct rs_multiport_struct));
+#endif
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	/*
+	 *	The interrupt of the serial console port
+	 *	can't be shared.
+	 */
+	if (sercons.flags & CON_CONSDEV) {
+		for(i = 0; i < NR_PORTS; i++)
+			if (i != sercons.index &&
+			    rs_table[i].irq == rs_table[sercons.index].irq)
+				rs_table[i].irq = 0;
+	}
+#endif
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+	serial_driver.driver_name = "serial";
+#endif
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+	serial_driver.name = "tts/%d";
+#else
+	serial_driver.name = "ttyS";
+#endif
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
+	serial_driver.name_base = SERIAL_DEV_OFFSET;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.put_char = rs_put_char;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+	serial_driver.send_xchar = rs_send_xchar;
+	serial_driver.wait_until_sent = rs_wait_until_sent;
+	serial_driver.read_proc = rs_read_proc;
+#endif
+	
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+	callout_driver.name = "cua/%d";
+#else
+	callout_driver.name = "cua";
+#endif
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+#endif
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = PORT_UNKNOWN;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = callout_driver.init_termios;
+		state->normal_termios = serial_driver.init_termios;
+		state->icount.cts = state->icount.dsr = 
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		state->irq = irq_cannonicalize(state->irq);
+		if (state->hub6)
+			state->io_type = SERIAL_IO_HUB6;
+		if (state->port && check_region(state->port,8))
+			continue;
+#ifdef CONFIG_MCA			
+		if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+			continue;
+#endif			
+		if (state->flags & ASYNC_BOOT_AUTOCONF)
+			autoconfig(state);
+	}
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		if (state->type == PORT_UNKNOWN)
+			continue;
+		if (   (state->flags & ASYNC_BOOT_AUTOCONF)
+		    && (state->flags & ASYNC_AUTO_IRQ)
+		    && (state->port != 0 || state->iomem_base != 0))
+			state->irq = detect_uart_irq(state);
+		if (state->io_type == SERIAL_IO_MEM) {
+			printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n",
+	 		       state->line + SERIAL_DEV_OFFSET,
+			       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+			       state->iomem_base, state->irq,
+			       uart_config[state->type].name);
+		}
+		else {
+			printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
+	 		       state->line + SERIAL_DEV_OFFSET,
+			       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+			       state->port, state->irq,
+			       uart_config[state->type].name);
+		}
+		tty_register_devfs(&serial_driver, 0,
+				   serial_driver.minor_start + state->line);
+		tty_register_devfs(&callout_driver, 0,
+				   callout_driver.minor_start + state->line);
+	}
+#ifdef ENABLE_SERIAL_PCI
+	probe_serial_pci();
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       probe_serial_pnp();
+#endif
+	return 0;
+}
+
+/*
+ * This is for use by architectures that know their serial console 
+ * attributes only at run time. Not to be invoked after rs_init().
+ */
+int __init early_serial_setup(struct serial_struct *req)
+{
+	int i = req->line;
+
+	if (i >= NR_IRQS)
+		return(-ENOENT);
+	rs_table[i].magic = 0;
+	rs_table[i].baud_base = req->baud_base;
+	rs_table[i].port = req->port;
+	if (HIGH_BITS_OFFSET)
+		rs_table[i].port += (unsigned long) req->port_high << 
+							HIGH_BITS_OFFSET;
+	rs_table[i].irq = req->irq;
+	rs_table[i].flags = req->flags;
+	rs_table[i].close_delay = req->close_delay;
+	rs_table[i].io_type = req->io_type;
+	rs_table[i].hub6 = req->hub6;
+	rs_table[i].iomem_base = req->iomem_base;
+	rs_table[i].iomem_reg_shift = req->iomem_reg_shift;
+	rs_table[i].type = req->type;
+	rs_table[i].xmit_fifo_size = req->xmit_fifo_size;
+	rs_table[i].custom_divisor = req->custom_divisor;
+	rs_table[i].closing_wait = req->closing_wait;
+	return(0);
+}
+
+/*
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+ 
+/**
+ *	register_serial - configure a 16x50 serial port at runtime
+ *	@req: request structure
+ *
+ *	Configure the serial port specified by the request. If the
+ *	port exists and is in use an error is returned. If the port
+ *	is not currently in the table it is added.
+ *
+ *	The port is then probed and if neccessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+ 
+int register_serial(struct serial_struct *req)
+{
+	int i;
+	unsigned long flags;
+	struct serial_state *state;
+	struct async_struct *info;
+	unsigned long port;
+
+	port = req->port;
+	if (HIGH_BITS_OFFSET)
+		port += (unsigned long) req->port_high << HIGH_BITS_OFFSET;
+
+	save_flags(flags); cli();
+	for (i = 0; i < NR_PORTS; i++) {
+		if ((rs_table[i].port == port) &&
+		    (rs_table[i].iomem_base == req->iomem_base))
+			break;
+	}
+#ifdef __i386__
+	if (i == NR_PORTS) {
+		for (i = 4; i < NR_PORTS; i++)
+			if ((rs_table[i].type == PORT_UNKNOWN) &&
+			    (rs_table[i].count == 0))
+				break;
+	}
+#endif
+	if (i == NR_PORTS) {
+		for (i = 0; i < NR_PORTS; i++)
+			if ((rs_table[i].type == PORT_UNKNOWN) &&
+			    (rs_table[i].count == 0))
+				break;
+	}
+	if (i == NR_PORTS) {
+		restore_flags(flags);
+		return -1;
+	}
+	state = &rs_table[i];
+	if (rs_table[i].count) {
+		restore_flags(flags);
+		printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
+		       "device already open\n", i, port, req->irq);
+		return -1;
+	}
+	state->irq = req->irq;
+	state->port = port;
+	state->flags = req->flags;
+	state->io_type = req->io_type;
+	state->iomem_base = req->iomem_base;
+	state->iomem_reg_shift = req->iomem_reg_shift;
+	if (req->baud_base)
+		state->baud_base = req->baud_base;
+	if ((info = state->info) != NULL) {
+		info->port = port;
+		info->flags = req->flags;
+		info->io_type = req->io_type;
+		info->iomem_base = req->iomem_base;
+		info->iomem_reg_shift = req->iomem_reg_shift;
+	}
+	autoconfig(state);
+	if (state->type == PORT_UNKNOWN) {
+		restore_flags(flags);
+		printk("register_serial(): autoconfig failed\n");
+		return -1;
+	}
+	restore_flags(flags);
+
+	if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
+		state->irq = detect_uart_irq(state);
+
+       printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+	      state->line + SERIAL_DEV_OFFSET,
+	      state->iomem_base ? "iomem" : "port",
+	      state->iomem_base ? (unsigned long)state->iomem_base :
+	      state->port, state->irq, uart_config[state->type].name);
+	tty_register_devfs(&serial_driver, 0,
+			   serial_driver.minor_start + state->line); 
+	tty_register_devfs(&callout_driver, 0,
+			   callout_driver.minor_start + state->line);
+	return state->line + SERIAL_DEV_OFFSET;
+}
+
+/**
+ *	unregister_serial - deconfigure a 16x50 serial port
+ *	@line: line to deconfigure
+ *
+ *	The port specified is deconfigured and its resources are freed. Any
+ *	user of the port is disconnected as if carrier was dropped. Line is
+ *	the port number returned by register_serial().
+ */
+
+void unregister_serial(int line)
+{
+	unsigned long flags;
+	struct serial_state *state = &rs_table[line];
+
+	save_flags(flags); cli();
+	if (state->info && state->info->tty)
+		tty_hangup(state->info->tty);
+	state->type = PORT_UNKNOWN;
+	printk(KERN_INFO "ttyS%02d unloaded\n", state->line);
+	/* These will be hidden, because they are devices that will no longer
+	 * be available to the system. (ie, PCMCIA modems, once ejected)
+	 */
+	tty_unregister_devfs(&serial_driver,
+			     serial_driver.minor_start + state->line);
+	tty_unregister_devfs(&callout_driver,
+			     callout_driver.minor_start + state->line);
+	restore_flags(flags);
+}
+
+static void __exit rs_fini(void) 
+{
+	unsigned long flags;
+	int e1, e2;
+	int i;
+	struct async_struct *info;
+
+	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+	del_timer_sync(&serial_timer);
+	save_flags(flags); cli();
+        remove_bh(SERIAL_BH);
+	if ((e1 = tty_unregister_driver(&serial_driver)))
+		printk("serial: failed to unregister serial driver (%d)\n",
+		       e1);
+	if ((e2 = tty_unregister_driver(&callout_driver)))
+		printk("serial: failed to unregister callout driver (%d)\n", 
+		       e2);
+	restore_flags(flags);
+
+	for (i = 0; i < NR_PORTS; i++) {
+		if ((info = rs_table[i].info)) {
+			rs_table[i].info = NULL;
+			kfree(info);
+		}
+		if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+#ifdef CONFIG_SERIAL_RSA
+			if (rs_table[i].type == PORT_RSA)
+				release_region(rs_table[i].port +
+					       UART_RSA_BASE, 16);
+			else
+#endif
+				release_region(rs_table[i].port, 8);
+		}
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+		if (rs_table[i].iomem_base)
+			iounmap(rs_table[i].iomem_base);
+#endif
+	}
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+	for (i=0; i < NR_PCI_BOARDS; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+
+		if (serial_pci_board[i].dev == 0)
+			continue;
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
+	}
+#endif	
+	if (tmp_buf) {
+		unsigned long pg = (unsigned long) tmp_buf;
+		tmp_buf = NULL;
+		free_page(pg);
+	}
+	
+#ifdef ENABLE_SERIAL_PCI
+	if (serial_pci_driver.name[0])
+		pci_unregister_driver (&serial_pci_driver);
+#endif
+}
+
+module_init(rs_init);
+module_exit(rs_fini);
+MODULE_DESCRIPTION("Standard/generic (dumb) serial driver");
+MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static struct async_struct async_sercons;
+
+/*
+ *	Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *info)
+{
+	unsigned int status, tmout = 1000000;
+
+	do {
+		status = serial_in(info, UART_LSR);
+
+		if (status & UART_LSR_BI)
+			lsr_break_flag = UART_LSR_BI;
+		
+		if (--tmout == 0)
+			break;
+	} while((status & BOTH_EMPTY) != BOTH_EMPTY);
+
+	/* Wait for flow control if necessary */
+	if (info->flags & ASYNC_CONS_FLOW) {
+		tmout = 1000000;
+		while (--tmout &&
+		       ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0));
+	}	
+}
+
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ *
+ *	The console must be locked when we get here.
+ */
+static void serial_console_write(struct console *co, const char *s,
+				unsigned count)
+{
+	static struct async_struct *info = &async_sercons;
+	int ier;
+	unsigned i;
+
+	/*
+	 *	First save the IER then disable the interrupts
+	 */
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(info);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		serial_out(info, UART_TX, *s);
+		if (*s == 10) {
+			wait_for_xmitr(info);
+			serial_out(info, UART_TX, 13);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 * 	and restore the IER
+	 */
+	wait_for_xmitr(info);
+	serial_out(info, UART_IER, ier);
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity/flow control. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+#if 1
+#include <asm/machdep.h>
+#endif
+static int __init serial_console_setup(struct console *co, char *options)
+{
+	static struct async_struct *info;
+	struct serial_state *state;
+	unsigned cval;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	doflow = 0;
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	int	quot = 0;
+	char	*s;
+	char dbgbf[512];
+	
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s++ - '0';
+		if (*s) doflow = (*s++ == 'r');
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			/*
+			 * Set this to a sane value to prevent a divide error
+			 */
+			baud  = 9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	/*
+	 *	Divisor, bytesize and parity
+	 */
+	state = rs_table + co->index;
+
+	if (doflow)
+		state->flags |= ASYNC_CONS_FLOW;
+	info = &async_sercons;
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+#ifdef CONFIG_HUB6
+	info->hub6 = state->hub6;
+#endif
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+	quot = state->baud_base / baud;
+
+	cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+	cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+	cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+	if (cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+#if 1
+	sprintf(dbgbf, "%p %d", state->iomem_base, state->baud_base);
+	ppc_md.progress(dbgbf, 444);
+	sprintf(dbgbf, "quot %d", quot);
+	ppc_md.progress(dbgbf, 444);
+	sprintf(dbgbf, "regshift %d", state->iomem_reg_shift);
+	ppc_md.progress(dbgbf, 444);
+	sprintf(dbgbf, "flags %d", state->flags);
+	ppc_md.progress(dbgbf, 444);
+#endif
+ 
+	/*
+	 *	Disable UART interrupts, set DTR and RTS high
+	 *	and set speed.
+	 */
+	serial_out(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	serial_out(info, UART_DLL, quot & 0xff);	/* LS of divisor */
+	serial_out(info, UART_DLM, quot >> 8);		/* MS of divisor */
+	serial_out(info, UART_LCR, cval);		/* reset DLAB */
+	serial_out(info, UART_IER, 0);
+	serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+	/*
+	 *	If we read 0xff from the LSR, there is no UART here.
+	 */
+	if (serial_in(info, UART_LSR) == 0xff)
+		return -1;
+
+	return 0;
+}
+
+static struct console sercons = {
+	name:		"ttyS",
+	write:		serial_console_write,
+	device:		serial_console_device,
+	setup:		serial_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+/*
+ *	Register console.
+ */
+void __init serial_console_init(void)
+{
+	register_console(&sercons);
+}
+#endif
+
+/*
+  Local variables:
+  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
+  End:
+*/
diff -Naru linux-2.4.20.orig/drivers/char/tty_io.c linux-2.4.20/drivers/char/tty_io.c
--- linux-2.4.20.orig/drivers/char/tty_io.c	2002-12-11 02:39:49.000000000 +0000
+++ linux-2.4.20/drivers/char/tty_io.c	2003-04-01 15:14:18.000000000 +0000
@@ -2198,7 +2198,11 @@
 	memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
 	tty_std_termios.c_iflag = ICRNL | IXON;
 	tty_std_termios.c_oflag = OPOST | ONLCR;
+#ifdef CONFIG_OPENBLOCKS266
+	tty_std_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+#else
 	tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
+#endif
 	tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
 		ECHOCTL | ECHOKE | IEXTEN;
 
diff -Naru linux-2.4.20.orig/drivers/char/x1226-rtc.c linux-2.4.20/drivers/char/x1226-rtc.c
--- linux-2.4.20.orig/drivers/char/x1226-rtc.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/char/x1226-rtc.c	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,547 @@
+
+/*
+ *  linux/drivers/char/x1226-rtc.c
+ *
+ *  I2C Real Time Clock Client Driver for Xicor X1226 RTC/Calendar
+ *
+ *  Copyright 2002 MontaVista Software Inc.
+ *  Author: MontaVista Software, Inc.
+ *     	stevel@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  TODO:
+ *    - implement alarm and periodic IRQ support.
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/time.h>
+
+#ifdef DEBUG_X1226
+#define	dbg(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__, ## args)
+#else
+#define	dbg(fmt, args...)
+#endif
+
+#define X1226_MODULE_NAME "X1226"
+#define PFX X1226_MODULE_NAME
+#ifndef I2C_DRIVERID_X1226
+#define I2C_DRIVERID_X1226  I2C_DRIVERID_EXP0
+#endif
+
+#define err(format, arg...) printk(KERN_ERR PFX ": " format , ## arg)
+#define info(format, arg...) printk(KERN_INFO PFX ": " format , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING PFX ": " format , ## arg)
+#define emerg(format, arg...) printk(KERN_EMERG PFX ": " format , ## arg)
+
+#define EPOCH 2000
+#define SYS_EPOCH 1900
+
+#undef BCD_TO_BIN
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+
+#undef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+
+#define X1226_RTC_SR      0x3f
+#define   RTC_SR_RTCF  (1)
+#define   RTC_SR_WEL  (1<<1)
+#define   RTC_SR_RWEL (1<<2)
+
+#define X1226_RTC_BASE    0x30
+
+/* This is an image of the RTC registers starting at offset 0x30 */
+struct rtc_registers {
+	unsigned char secs;  // 30
+        unsigned char mins;  // 31
+        unsigned char hours; // 32
+        unsigned char day;   // 33
+        unsigned char mon;   // 34
+        unsigned char year;  // 35
+        unsigned char dayofweek; // 36
+        unsigned char epoch; // 37
+};
+
+#define X1226_CONTROL_DTR  0x13
+#define X1226_CONTROL_ATR  0x12
+#define X1226_CONTROL_INT  0x11
+#define X1226_CONTROL_BL   0x10
+
+#define DEVID_RTC          0x6F
+#define DEVID_NVRAM        0x57
+#define   SLAVE_READ 0x01
+#ifndef I2C_M_WR
+#define I2C_M_WR 0x0
+#endif
+#define ABITS           9
+#define EESIZE          (1 << ABITS)    /* size in bytes */
+
+#define NVSIZE          512             /* we use 512 bytes */
+#define NVOFFSET        (EESIZE-NVSIZE) /* at end of EEROM */
+
+static struct i2c_driver x1226_driver;
+
+static int x1226_use_count = 0;
+
+static struct i2c_client *this_client = NULL;
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+                         int count, int *eof, void *data);
+
+
+
+
+static int x1226_read (struct i2c_client *client,
+		       u8 reg_offset, u8* buf, int len)
+{
+	int ret;
+	u8 regbuf[2] = { 0, reg_offset };
+	struct i2c_msg random_addr_read[2] = {
+		{
+			/* "Set Current Address" */
+			client->addr,
+			client->flags | I2C_M_WR,
+			sizeof(regbuf),
+			regbuf
+		},
+		{
+			/* "Sequential Read" if len>1,
+			   "Current Address Read" if len=1 */
+			client->addr ,
+			client->flags| I2C_M_RD ,
+			len,
+			buf
+		}
+	};
+
+	if ((ret = i2c_transfer(client->adapter, random_addr_read, 2)) != 2) {
+		ret = -ENXIO;
+		dbg("i2c_transfer failed\n");
+	}
+
+	return ret;
+}
+
+static int x1226_write (struct i2c_client *client,
+			u8 reg_offset, u8* buf, int len)
+{
+	int ret;
+	u8* local_buf;
+	u8 regbuf[2] = { 0, reg_offset };
+	struct i2c_msg page_write = {
+		client->addr,
+		client->flags ,
+		len + sizeof(regbuf),
+		NULL
+	};
+
+	if ((local_buf = (u8*)kmalloc(len + sizeof(regbuf),
+				      GFP_KERNEL)) == NULL) {
+		err("buffer alloc failed\n");
+		return -ENOMEM;
+	}
+
+	memcpy(local_buf, regbuf, sizeof(regbuf));
+	memcpy(local_buf + sizeof(regbuf), buf, len);
+	page_write.buf = local_buf;
+	
+	if ((ret = i2c_transfer(client->adapter, &page_write, 1)) != 1) {
+		ret = -ENXIO;
+		dbg("i2c_transfer failed\n");
+	}
+
+	kfree(local_buf);
+	return ret;
+}
+
+
+static int ccr_write_enable(struct i2c_client *client)
+{
+	u8 sr = RTC_SR_WEL;
+	int ret;
+	if ((ret = x1226_write(client, X1226_RTC_SR, &sr, 1)) < 0)
+		return ret;
+	sr |= RTC_SR_RWEL;
+	if ((ret = x1226_write(client, X1226_RTC_SR, &sr, 1)) < 0)
+		return ret;
+	sr = 0;
+	if ((ret = x1226_read(client, X1226_RTC_SR, &sr, 1)) < 0)
+		return ret;
+
+	sr &= (RTC_SR_RWEL | RTC_SR_RWEL);
+	if (sr != (RTC_SR_RWEL | RTC_SR_RWEL)) {
+		dbg("verify SR failed\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int ccr_write_disable(struct i2c_client *client)
+{
+	int ret;
+	u8 sr = 0;
+	
+	if ((ret = x1226_write(client, X1226_RTC_SR, &sr, 1)) < 0)
+		return ret;
+	if ((ret = x1226_read(client, X1226_RTC_SR, &sr, 1)) < 0)
+		return ret;
+	if (sr != 0) {
+		dbg("verify SR failed\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+
+static int
+x1226_get_time(struct i2c_client *client, struct rtc_time *tm)
+{	
+	struct rtc_registers rtc;
+	u32 epoch;
+	int ret;
+	
+	/* read RTC registers */
+	if ((ret = x1226_read(client, X1226_RTC_BASE, (u8*)&rtc,
+			      sizeof(struct rtc_registers))) < 0) {
+		dbg("couldn't read RTC\n");
+		return ret;
+	}
+	dbg("IN: epoch=%02x, year=%02x, mon=%02x, day=%02x, hour=%02x, "
+	    "min=%02x, sec=%02x\n",
+	    rtc.epoch, rtc.year, rtc.mon, rtc.day, rtc.hours,
+	    rtc.mins, rtc.secs);
+	
+	epoch  = 100 * BCD_TO_BIN(rtc.epoch);   // 19 / 20
+	tm->tm_year = BCD_TO_BIN(rtc.year); // 0 - 99
+	tm->tm_year += (epoch - SYS_EPOCH);
+	tm->tm_mon = BCD_TO_BIN(rtc.mon);   // 1 - 12
+	tm->tm_mon--;                       /* tm_mon is 0 to 11 */
+	tm->tm_mday = BCD_TO_BIN(rtc.day);  // 1 - 31
+	tm->tm_hour = BCD_TO_BIN(rtc.hours & ~0x80);
+	if (!(rtc.hours & 0x80)) {
+		// AM/PM 1-12 format, convert to MIL
+		tm->tm_hour--; // 0 - 11
+		if (rtc.hours & (1<<5))
+			tm->tm_hour += 12; // PM
+	}
+	
+	tm->tm_min = BCD_TO_BIN(rtc.mins);
+	tm->tm_sec = BCD_TO_BIN(rtc.secs);
+
+	dbg("OUT: year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n",
+	    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+	    tm->tm_min, tm->tm_sec);
+	
+	return 0;
+}
+
+static int 
+x1226_set_time(struct i2c_client *client, const struct rtc_time *tm)
+{
+	struct rtc_registers rtc;
+	int ret;
+
+	dbg("IN: year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n",
+	    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+	    tm->tm_min, tm->tm_sec);
+
+	rtc.epoch = BIN_TO_BCD(EPOCH/100);
+	rtc.year  = BIN_TO_BCD(tm->tm_year + SYS_EPOCH - EPOCH);
+	rtc.mon   = BIN_TO_BCD(tm->tm_mon + 1); /* tm_mon is 0 to 11 */
+	rtc.day   = BIN_TO_BCD(tm->tm_mday);
+	rtc.dayofweek = 0; // ignore day of week
+	rtc.hours = BIN_TO_BCD(tm->tm_hour) | 0x80; /* 24 hour format */
+	rtc.mins  = BIN_TO_BCD(tm->tm_min);
+	rtc.secs  = BIN_TO_BCD(tm->tm_sec);
+	
+	dbg("OUT: epoch=%02x, year=%02x, mon=%02x, day=%02x, hour=%02x, "
+	    "min=%02x, sec=%02x\n",
+	    rtc.epoch, rtc.year, rtc.mon, rtc.day, rtc.hours,
+	    rtc.mins, rtc.secs);
+	
+	/* write RTC registers */
+	if ((ret = ccr_write_enable(client)) < 0)
+		return ret;
+	if ((ret = x1226_write(client, X1226_RTC_BASE, (u8*)&rtc,
+			       sizeof(struct rtc_registers))) < 0) {
+		dbg("couldn't write RTC\n");
+		return ret;
+	}
+	ccr_write_disable(client);
+
+	return 0;
+}
+
+static int
+x1226_probe(struct i2c_adapter *adap)
+{
+	int ret;
+	char stat;
+	unsigned char crs[4];
+	struct rtc_time dummy_tm={0,0,0, 1, 0, 100, 0, 0};
+	if (this_client != NULL)
+		return -EBUSY;
+	
+	this_client = kmalloc(sizeof(*this_client), GFP_KERNEL);
+	if (this_client == NULL) {
+		return -ENOMEM;
+	}
+
+	strcpy(this_client->name, X1226_MODULE_NAME);
+	this_client->id		= x1226_driver.id;
+
+	this_client->flags	= 0;
+	this_client->addr	= DEVID_RTC;
+	this_client->adapter	= adap;
+	this_client->driver	= &x1226_driver;
+	this_client->data	= NULL;
+
+	/*
+	 * use x1226_get_time() to probe for an X1226 on this bus.
+	 */
+	if((ret = x1226_read(this_client,X1226_RTC_SR, &stat, 1))< 0){
+		kfree(this_client);
+		this_client = NULL;
+		return ret;
+	}
+	info("found X1226 on %s\n", adap->name);
+	if(stat & RTC_SR_RTCF){
+	  printk("X1226:Timer Not Initialized after power fail. Setting 2002/1/1/0:00\n" );
+	  ret= x1226_set_time(this_client, &dummy_tm);
+	}
+	dbg("stat %x \n", stat);
+	x1226_read(this_client,0x10, &crs[0], 1);
+	x1226_read(this_client,0x11, &crs[1], 1);
+	x1226_read(this_client,0x12, &crs[2], 1);
+	x1226_read(this_client,0x13, &crs[3], 1);
+	dbg("CTLREG:%d %x %x %x %x\n", ret, crs[0],crs[1],crs[2],crs[3]);
+
+	if ((ret = x1226_get_time(this_client, &dummy_tm)) < 0) {
+	  printk("Fetch Timer Failed\n");
+	}else{
+#ifdef DEBUG_X1226
+	  struct rtc_time *tm = &dummy_tm;
+	  dbg("OUT: year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n",
+	    tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+	    tm->tm_min, tm->tm_sec);
+#endif
+	}
+
+	/* attach it. */
+	return i2c_attach_client(this_client);
+}
+
+static int
+x1226_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+
+	if (this_client != NULL) {
+		kfree(this_client);
+		this_client = NULL;
+	}
+
+	return 0;
+}
+
+int rtc_open(struct inode *minode, struct file *mfile)
+{
+	/*if(MOD_IN_USE)*/
+	if(x1226_use_count > 0) {
+		return -EBUSY;
+	}
+	MOD_INC_USE_COUNT;
+	++x1226_use_count;
+	return 0;
+}
+
+int rtc_release(struct inode *minode, struct file *mfile)
+{
+	MOD_DEC_USE_COUNT;
+	--x1226_use_count;
+	return 0;
+}
+
+static loff_t rtc_llseek(struct file *mfile, loff_t offset, int origint)
+{
+	return -ESPIPE;
+}
+
+static int
+x1226_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	return -EINVAL;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	struct rtc_time rtc_tm;
+	int ret;
+	
+	switch (cmd) {
+	case RTC_RD_TIME:	/* Read the time/date from RTC  */
+		if ((ret = x1226_get_time(this_client, &rtc_tm)) < 0)
+			return ret;
+		return copy_to_user((void *)arg, &rtc_tm, sizeof(rtc_tm)) ? 
+			-EFAULT : 0;
+	case RTC_SET_TIME:	/* Set the RTC */
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, 
+				   (struct rtc_time *) arg,
+		                   sizeof(struct rtc_time))) 
+			return -EFAULT;
+
+		return x1226_set_time(this_client, &rtc_tm);
+	default:
+		return -EINVAL;
+	}
+}
+
+
+static struct i2c_driver x1226_driver = {
+	name:		X1226_MODULE_NAME,
+	id:		I2C_DRIVERID_X1226,
+	flags:		I2C_DF_NOTIFY,
+	attach_adapter:	x1226_probe,
+	detach_client:	x1226_detach,
+	command:	x1226_command
+};
+
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	llseek:		rtc_llseek,
+	ioctl:		rtc_ioctl,
+	open:		rtc_open,
+	release:	rtc_release,
+};
+
+static struct miscdevice x1226rtc_miscdev = {
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+static __init int x1226_init(void)
+{
+	int ret;
+
+	info("I2C based RTC driver.\n");
+	ret = i2c_add_driver(&x1226_driver);
+	if (ret) {
+		err("Register I2C driver failed, errno is %d\n", ret);
+		return ret;
+	}
+	ret = misc_register(&x1226rtc_miscdev);
+	if (ret) {
+		err("Register misc driver failed, errno is %d\n", ret);
+		ret = i2c_del_driver(&x1226_driver);
+		if (ret) {
+			err("Unregister I2C driver failed, errno is %d\n",
+			    ret);
+		}
+		return ret;
+	}
+
+	create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc, NULL);
+
+	return 0;
+}
+
+static void __exit x1226_exit(void)
+{
+        remove_proc_entry("driver/rtc", NULL);
+        misc_deregister(&x1226rtc_miscdev);
+	i2c_del_driver(&x1226_driver);
+}
+
+
+module_init(x1226_init);
+module_exit(x1226_exit);
+
+/*
+ *	Info exported via "/proc/driver/rtc".
+ */
+
+static int rtc_proc_output(char *buf)
+{
+	char *p;
+	struct rtc_time tm;
+	int ret;
+	
+	if ((ret = x1226_get_time(this_client, &tm)) < 0)
+		return ret;
+
+	p = buf;
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+	p += sprintf(p,
+		     "rtc_time\t: %02d:%02d:%02d\n"
+		     "rtc_date\t: %04d-%02d-%02d\n"
+		     "rtc_epoch\t: %04d\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec,
+		     tm.tm_year + SYS_EPOCH, tm.tm_mon + 1,
+		     tm.tm_mday, EPOCH);
+
+	return p - buf;
+}
+
+static int rtc_read_proc(char *page, char **start, off_t off,
+			 int count, int *eof, void *data)
+{
+	int len = rtc_proc_output(page);
+	if (len <= off + count)
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+	if (len < 0)
+		len = 0;
+	return len;
+}
+
+MODULE_AUTHOR("Steve Longerbeam");
+MODULE_LICENSE("GPL");
+
diff -Naru linux-2.4.20.orig/drivers/i2c/i2c-adap-ibm_ocp.c linux-2.4.20/drivers/i2c/i2c-adap-ibm_ocp.c
--- linux-2.4.20.orig/drivers/i2c/i2c-adap-ibm_ocp.c	2002-12-11 02:39:43.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-adap-ibm_ocp.c	2003-04-01 15:14:18.000000000 +0000
@@ -281,8 +281,7 @@
 				    (iic_drv->irq,
 				     iic_ibmocp_handler, 0, "IBM OCP IIC",
 				     iic_drv)) {
-					printk(KERN_ERR "iic_hw_resrc_init: Request irq%d 
-				failed\n", iic_drv->irq);
+					printk(KERN_ERR "iic_hw_resrc_init: Request irq%d failed\n", iic_drv->irq);
 					iic_drv->irq = 0;
 				} else {
 					DEB3(printk
diff -Naru linux-2.4.20.orig/drivers/i2c/i2c-algo-ibm_ocp.c linux-2.4.20/drivers/i2c/i2c-algo-ibm_ocp.c
--- linux-2.4.20.orig/drivers/i2c/i2c-algo-ibm_ocp.c	2002-12-11 02:37:04.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-algo-ibm_ocp.c	2003-04-01 15:14:18.000000000 +0000
@@ -726,7 +726,6 @@
 	 */
 	DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n"));
 	ret = iic_doAddress(adap, pmsg, adap->retries);
-
 	/*
 	 * Check to see if the bus is busy
 	 */
@@ -736,7 +735,6 @@
 	/* When the bus is free, the BCS bits in the EXTSTS register are 0b100 */
 	if (ret != 0x40)
 		return IIC_ERR_LOST_ARB;
-
 	/*
 	 * Combined transaction (read and write)
 	 */
@@ -755,6 +753,7 @@
 		DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n"));
 		ret =
 		    iic_readbytes(adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+		ret = (ret == pmsg->len)? num: ret;
 	}
 	/*
 	 * Write only
@@ -767,6 +766,7 @@
 		DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n"));
 		ret =
 		    iic_sendbytes(adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+		ret = (ret == pmsg->len)? num: ret;
 	}
 
 	return ret;
diff -Naru linux-2.4.20.orig/drivers/i2c/i2c-algo-ibm_ocp.c.new linux-2.4.20/drivers/i2c/i2c-algo-ibm_ocp.c.new
--- linux-2.4.20.orig/drivers/i2c/i2c-algo-ibm_ocp.c.new	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/i2c/i2c-algo-ibm_ocp.c.new	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,978 @@
+/*
+   -------------------------------------------------------------------------
+   i2c-algo-ibm_ocp.c i2c driver algorithms for IBM PPC 405 adapters	    
+   -------------------------------------------------------------------------
+      
+   current Mainainers
+   Ian DaSilva and Armin Kuster, MontaVista Software, Inc.
+   idasilva@mvista.com, Akuster@mvista.com or source@mvista.com
+
+   Copyright 2000-2002 MontaVista Software Inc.
+
+   Changes made to support the IIC peripheral on the IBM PPC 405
+
+   ---------------------------------------------------------------------------
+   This file was highly leveraged from i2c-algo-pcf.c, which was created
+   by Simon G. Vogl and Hans Berglund:
+
+     Copyright (C) 1995-1997 Simon G. Vogl
+                   1998-2000 Hans Berglund
+
+   With some changes from Ky��ti M��kki <kmalkki@cc.hut.fi> and 
+   Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
+   <mbailey@littlefeet-inc.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   ---------------------------------------------------------------------------
+
+   History: 01/20/12 - Armin
+   	akuster@mvista.com
+   	ported up to 2.4.16+	
+
+   Version 02/03/25 - Armin
+       converted to ocp format
+       removed commented out or #if 0 code
+       added G��ard Basler's fix to iic_combined_transaction() such that it 
+       returns the number of successfully completed transfers .
+
+   Version 04/29/03 - Armin
+   	General cleanups
+	changes c++ style comments to c
+	converted to ocp
+	deleted unused printk's
+	Added scan routine from Andrew May
+
+   Version 05/25/02 - Armin
+      name change for *_driver to *_dev
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+
+#include <linux/i2c.h>
+#include <asm/ocp.h>
+
+#include <asm/ibm4xx.h>
+#include <asm/bootinfo.h>
+#define IIC_VER	"2002.30.04"
+
+/* ----- global defines ----------------------------------------------- */
+#define DEB(x) if (i2c_debug>=1) x
+#define DEB2(x) if (i2c_debug>=2) x
+#define DEB3(x) if (i2c_debug>=3) x	/* print several statistical values */
+#define DEBPROTO(x) if (i2c_debug>=9) x;
+	/* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 5
+
+#define IIC_DEV(x)	((struct ocp_dev *)adap->data)->x
+
+/* ----- global variables ---------------------------------------------	*/
+
+#ifdef SLO_IO
+int jif;
+#endif
+#define IIC_CNTL_HMT (1<<7)
+#define IIC_CNTL_AMD (1<<6)
+#define IIC_CNTL_TCT(x) (((x-1)&3)<<4)
+#define IIC_CNTL_RPST (1<<3)
+#define IIC_CNTL_CHT (1<<2)
+#define IIC_CNTL_RW (1<<1)
+#define IIC_CNTL_PT 1
+
+/* module parameters:
+ */
+static int i2c_debug = 0;
+static int iic_scan = 0;	/* have a look at what's hanging 'round         */
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+
+#define iic_outb( reg, val) writeb(val,&(reg))
+#define iic_inb( reg) readb(&(reg))
+
+#define IICO_I2C_SDAHIGH	0x0780
+#define IICO_I2C_SDALOW		0x0781
+#define IICO_I2C_SCLHIGH	0x0782
+#define IICO_I2C_SCLLOW		0x0783
+#define IICO_I2C_LINEREAD	0x0784
+
+#define IIC_SINGLE_XFER		0
+#define IIC_COMBINED_XFER	1
+#define IIC_ADDR10_XFER		2
+
+#define IIC_ERR_LOST_ARB        -2
+#define IIC_ERR_INCOMPLETE_XFR  -3
+#define IIC_ERR_NACK            -1
+#define IIC_TIMEOUT		100
+#define IIC_RETRY		3
+
+extern void iic_ibmocp_waitforpin(void *data);
+
+/* --- other auxiliary functions --------------------------------------	*/
+
+/*
+ *Description: Puts this process to sleep for a period equal to timeout 
+ */
+static inline void
+iic_sleep(unsigned long timeout)
+{
+	schedule_timeout(timeout * HZ);
+}
+
+/*
+ * Description: This performs the IBM PPC 405 IIC initialization sequence
+ * as described in the PPC405GP data book.
+ */
+static int
+iic_init(struct i2c_adapter *adap)
+{
+	struct iic_regs *iic;
+	unsigned short retval;
+
+	iic = (struct iic_regs *) ((struct ocp_dev *) adap->data)->vaddr;
+	printk("%p %p %p", iic, &iic->lmadr, &iic->hmadr);
+	/* Clear master low master address */
+	iic_outb(iic->lmadr, 0);
+
+	/* Clear high master address */
+	iic_outb(iic->hmadr, 0);
+
+	/* Clear low slave address */
+	iic_outb(iic->lsadr, 0);
+
+	/* Clear high slave address */
+	iic_outb(iic->hsadr, 0);
+
+	/* Clear status */
+	iic_outb(iic->sts, 0x0a);
+
+	/* Clear extended status */
+	iic_outb(iic->extsts, 0x8f);
+
+	/* Set clock division */
+	iic_outb(iic->clkdiv, 0x04);
+
+	retval = iic_inb(iic->clkdiv);
+	DEB(printk("iic_init: CLKDIV register = %x\n", retval));
+
+	/* Enable interrupts on Requested Master Transfer Complete */
+	iic_outb(iic->intmsk, 0x01);
+
+	/* Clear transfer count */
+	iic_outb(iic->xfrcnt, 0x0);
+
+	/* Clear extended control and status */
+	iic_outb(iic->xtcntlss, 0xf0);
+
+	/* Set mode control (flush master data buf, enable hold SCL, exit */
+	/* unknown state.                                                 */
+	iic_outb(iic->mdcntl, 0x47);
+
+	/* Clear control register */
+	iic_outb(iic->cntl, 0x0);
+
+	DEB2(printk(KERN_DEBUG "iic_init: Initialized IIC on PPC 405\n"));
+	return 0;
+}
+
+/*
+ * Description: After we issue a transaction on the IIC bus, this function
+ * is called.  It puts this process to sleep until we get an interrupt from
+ * from the controller telling us that the transaction we requested in complete.
+ */
+static int
+wait_for_pin(struct i2c_adapter *adap, int *status)
+{
+
+	int timeout = DEF_TIMEOUT;
+	int retval;
+	struct iic_regs *iic;
+
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+
+	*status = iic_inb(iic->sts);
+#ifndef STUB_I2C
+
+	while (timeout-- && (*status & 0x01)) {
+		iic_ibmocp_waitforpin(adap->data);
+		*status = iic_inb(iic->sts);
+	}
+#endif
+	if (timeout <= 0) {
+		/* Issue stop signal on the bus, and force an interrupt */
+		retval = iic_inb(iic->cntl);
+		iic_outb(iic->cntl, retval | 0x80);
+		/* Clear status register */
+		iic_outb(iic->sts, 0x0a);
+		/* Exit unknown bus state */
+		retval = iic_inb(iic->mdcntl);
+		iic_outb(iic->mdcntl, (retval | 0x02));
+
+		/* Check the status of the controller.  Does it still see a
+		 * pending transfer, even though we've tried to stop any
+		 * ongoing transaction?
+		 */
+		retval = iic_inb(iic->sts);
+		retval = retval & 0x01;
+		if (retval) {
+			/* The iic controller is hosed.  It is not responding to any
+			 * of our commands.  We have already tried to force it into
+			 * a known state, but it has not worked.  Our only choice now
+			 * is a soft reset, which will clear all registers, and force
+			 * us to re-initialize the controller.
+			 * Soft reset
+			 */
+			iic_outb(iic->xtcntlss, 0x01);
+			udelay(500);
+			iic_init(adap);
+			/* Is the pending transfer bit in the sts reg finally cleared? */
+			retval = iic_inb(iic->sts);
+			retval = retval & 0x01;
+			if (retval) {
+				printk(KERN_CRIT
+				       "The IIC Controller is hosed.  A processor reset is required\n");
+			}
+			/* For some reason, even though the interrupt bit in this
+			 * register was set during iic_init, it didn't take.  We
+			 * need to set it again.  Don't ask me why....this is just what
+			 * I saw when testing timeouts.
+			 */
+			iic_outb(iic->intmsk, 0x01);
+		}
+		return (-1);
+	} else
+		return (0);
+}
+
+/* ------------------------------------ */
+/*  Utility functions */
+
+/*  Description: Look at the status register to see if there was an error 
+ *  in the requested transaction.  If there is, look at the extended status 
+ *  register and determine the exact cause. 
+ */
+
+int
+analyze_status(struct i2c_adapter *adap, int *error_code)
+{
+	int ret;
+	struct iic_regs *iic;
+
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+
+	ret = iic_inb(iic->sts);
+	printk("ERR_CODE%x\n", ret);
+	if (ret & 0x04) {
+		/* Error occurred */
+		ret = iic_inb(iic->extsts);
+		if (ret & 0x04) {
+			/* Lost arbitration */
+			*error_code = IIC_ERR_LOST_ARB;
+		}
+		if (ret & 0x02) {
+			/* Incomplete transfer */
+			*error_code = IIC_ERR_INCOMPLETE_XFR;
+		}
+		if (ret & 0x01) {
+			/* Master transfer aborted by a NACK during the transfer of the address byte */
+			*error_code = IIC_ERR_NACK;
+		}
+		return -1;
+	}
+	return 0;
+}
+
+/*  Description: This function is called by the upper layers to do the 
+ *  grunt work for a master send transaction
+ */
+
+static int
+iic_sendbytes(struct i2c_adapter *adap, const char *buf,
+	      int count, int xfer_flag)
+{
+	struct iic_regs *iic;
+	int wrcount, status, timeout;
+	int loops, remainder, i, j;
+	int ret, error_code;
+	int cntl_value;
+
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+	printk("senbdyte:count%d \n", count);
+	if (count == 0)
+		return 0;
+	wrcount = 0;
+	loops = count / 4;
+	remainder = count % 4;
+	cntl_value = (xfer_flag & IIC_ADDR10_XFER) ?  IIC_CNTL_AMD : 0;
+
+	if ((loops > 1) && (remainder == 0)) {
+		for (i = 0; i < (loops - 1); i++) {
+
+			/* Write four bytes to master data buffer */
+
+			for (j = 0; j < 4; j++) {
+				iic_outb(iic->mdbuf, buf[wrcount++]);
+			}
+
+			/* Issue command to IICO device to begin transmission */
+
+			iic_outb(iic->cntl, cntl_value|0x35);
+
+			/*    Wait for transmission to complete.  When it does,  
+			 *    loop to the top of the for statement and write the  
+			 *    next four bytes. 
+			 */
+
+			timeout = wait_for_pin(adap, &status);
+			if (timeout < 0) {
+				  printk("TIMEOUT\n");
+				/* Error handling */
+
+				return wrcount;
+			}
+			ret = analyze_status(adap, &error_code);
+			if (ret < 0) {
+				if (error_code == IIC_ERR_INCOMPLETE_XFR) {
+				  printk("INCOMPLETE WRITE\n");
+					/* Return the number of bytes transferred */
+					ret = iic_inb(iic->xfrcnt);
+					ret = ret & 0x07;
+					return (wrcount - 4 + ret);
+				} else{
+				  printk("ERROR\n");
+					return error_code;
+				}
+			}
+		}
+	} else if ((loops >= 1) && (remainder > 0)) {
+		/*printk(KERN_DEBUG "iic_sendbytes: (loops >= 1)\n"); */
+		for (i = 0; i < loops; i++) {
+			/*
+			 * Write four bytes to master data buffer
+			 */
+			for (j = 0; j < 4; j++) {
+				iic_outb(iic->mdbuf, buf[wrcount++]);
+			}
+			/*
+			 * Issue command to IICO device to begin transmission
+			 */
+			iic_outb(iic->cntl, cntl_value |0x35);
+			/*
+			 * Wait for transmission to complete.  When it does,
+			 * loop to the top of the for statement and write the
+			 * next four bytes.
+			 */
+			timeout = wait_for_pin(adap, &status);
+			if (timeout < 0){
+			  printk("TIMEOUT\n");
+				return wrcount;
+			}
+			ret = analyze_status(adap, &error_code);
+			if (ret < 0) {
+				if (error_code == IIC_ERR_INCOMPLETE_XFR) {
+				  printk("INCOMPLETE\n");
+					/* Return the number of bytes transferred */
+					ret = iic_inb(iic->xfrcnt);
+					ret = ret & 0x07;
+					return (wrcount - 4 + ret);
+				} else
+					return error_code;
+			}
+		}
+	}
+
+	if (remainder == 0)
+		remainder = 4;
+	/* Write the remaining bytes (less than or equal to 4) */
+	printk("REMINDER %d\n", remainder);
+	for (i = 0; i < remainder; i++)
+		iic_outb(iic->mdbuf, buf[wrcount++]);
+	
+	if (xfer_flag & IIC_COMBINED_XFER) {
+		iic_outb(iic->cntl, (cntl_value|0x09 | ((remainder - 1) << 4)));
+	} else {
+		iic_outb(iic->cntl, (cntl_value | 0x01 | ((remainder - 1) << 4)));
+	}
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Waiting for interrupt\n"));
+	timeout = wait_for_pin(adap, &status);
+	printk("TIMO:%d\n", timeout);
+	if (timeout < 0){
+	  printk("TIMEOUT\n");
+		return wrcount;
+	}
+	ret = analyze_status(adap, &error_code);
+	if (ret < 0) {
+	  printk("RET %d\n", ret);
+		if (error_code == IIC_ERR_INCOMPLETE_XFR) {
+		  printk("INCOMPLETE\n");
+			/* Return the number of bytes transferred */
+			ret = iic_inb(iic->xfrcnt);
+			ret = ret & 0x07;
+			return (wrcount - 4 + ret);
+		} else
+			return error_code;
+	}
+	printk("wrcount %d\n", wrcount);
+	DEB2(printk(KERN_DEBUG "iic_sendbytes: Got interrupt\n"));
+	return wrcount;
+}
+
+/*
+ * Description: Called by the upper layers to do the grunt work for
+ * a master read transaction.
+ */
+static int
+iic_readbytes(struct i2c_adapter *adap, char *buf, int count, int xfer_type)
+{
+	struct iic_regs *iic;
+	int rdcount = 0, i, status, timeout;
+	int loops, remainder, j;
+	int ret, error_code;
+	int cntl_value;
+	
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+
+	if (count == 0)
+		return 0;
+	loops = count / 4;
+	remainder = count % 4;
+	cntl_value = (xfer_type & IIC_ADDR10_XFER) ?  IIC_CNTL_AMD : 0;
+
+	if ((loops > 1) && (remainder == 0)) {
+		for (i = 0; i < (loops - 1); i++) {
+			/* Issue command to begin master read (4 bytes maximum) */
+			iic_outb(iic->cntl, cntl_value | 0x37);
+			/*
+			 * Wait for transmission to complete.  When it does,
+			 * loop to the top of the for statement and write the
+			 * next four bytes.
+			 */
+			timeout = wait_for_pin(adap, &status);
+			if (timeout < 0)
+				return rdcount;
+
+			ret = analyze_status(adap, &error_code);
+			if (ret < 0) {
+				if (error_code == IIC_ERR_INCOMPLETE_XFR)
+					return rdcount;
+				else
+					return error_code;
+			}
+
+			for (j = 0; j < 4; j++) {
+				/* Wait for data to shuffle to top of data buffer
+				 * This value needs to optimized.
+				 */
+				udelay(1);
+				buf[rdcount] = iic_inb(iic->mdbuf);
+				rdcount++;
+			}
+		}
+	}
+
+	else if ((loops >= 1) && (remainder > 0)) {
+		for (i = 0; i < loops; i++) {
+			/* Issue command to begin master read (4 bytes maximum) */
+			iic_outb(iic->cntl, cntl_value |0x37);
+			/*
+			 * Wait for transmission to complete.  When it does,
+			 * loop to the top of the for statement and write the
+			 * next four bytes.
+			 */
+			timeout = wait_for_pin(adap, &status);
+			if (timeout < 0)
+				return rdcount;
+
+			ret = analyze_status(adap, &error_code);
+			if (ret < 0) {
+				if (error_code == IIC_ERR_INCOMPLETE_XFR)
+					return rdcount;
+				else
+					return error_code;
+			}
+
+			for (j = 0; j < 4; j++) {
+				/* Wait for data to shuffle to top of data buffer
+				 * This value needs to optimized.
+				 */
+				udelay(1);
+				buf[rdcount] = iic_inb(iic->mdbuf);
+				rdcount++;
+			}
+		}
+	}
+
+	if (remainder == 0)
+		remainder = 4;
+	DEB2(printk
+	     (KERN_DEBUG "iic_readbytes: writing %x to IICO_CNTL\n",
+	      (0x03 | ((remainder - 1) << 4))));
+
+	if (xfer_type & IIC_COMBINED_XFER) {
+		iic_outb(iic->cntl, (cntl_value |0x0b | ((remainder - 1) << 4)));
+	} else {
+		iic_outb(iic->cntl, ( cntl_value |0x03 | ((remainder - 1) << 4)));
+	}
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Wait for pin\n"));
+	timeout = wait_for_pin(adap, &status);
+	DEB2(printk(KERN_DEBUG "iic_readbytes: Got the interrupt\n"));
+	if (timeout < 0)
+		return rdcount;
+
+	ret = analyze_status(adap, &error_code);
+	if (ret < 0) {
+		if (error_code == IIC_ERR_INCOMPLETE_XFR)
+			return rdcount;
+		else
+			return error_code;
+	}
+
+	for (i = 0; i < remainder; i++) {
+		buf[rdcount] = iic_inb(iic->mdbuf);
+		rdcount++;
+	}
+
+	return rdcount;
+}
+
+/*
+ * Description:  This function implements combined transactions.  Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+static int
+iic_combined_transaction(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+			 int num)
+{
+	int i;
+	struct i2c_msg *pmsg;
+	int ret;
+	int transfer_flags;
+	DEB2(printk(KERN_DEBUG "Beginning combined transaction\n"));
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		transfer_flags =  (pmsg->flags &I2C_M_TEN) ?
+		  IIC_ADDR10_XFER : 0;
+		if (pmsg->flags & I2C_M_RD) {
+
+			/* Last read or write segment needs to be terminated with a stop */
+			if (i < num - 1) {
+				DEB2(printk(KERN_DEBUG "This one is a read\n"));
+			} else {
+				DEB2(printk
+				     (KERN_DEBUG "Doing the last read\n"));
+			}
+			transfer_flags |= (i < num - 1) ?IIC_COMBINED_XFER:
+			  IIC_SINGLE_XFER;
+			ret =
+			    iic_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+					  transfer_flags);
+
+			if (ret != pmsg->len) {
+			  printk("FAIL\n");
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+					    "only read %d bytes.\n", ret));
+				return i;
+			} else {
+				DEB2(printk
+				     ("i2c-algo-ppc405.o: read %d bytes.\n",
+				      ret));
+			}
+		} else if (!(pmsg->flags & I2C_M_RD)) {
+
+			/* Last read or write segment needs to be terminated with a stop */
+			if (i < num - 1) {
+				DEB2(printk
+				     (KERN_DEBUG "This one is a write\n"));
+			} else {
+				DEB2(printk
+				     (KERN_DEBUG "Doing the last write\n"));
+			}
+			transfer_flags |= (i < num - 1) ?IIC_COMBINED_XFER:
+			  IIC_SINGLE_XFER;
+			ret =
+			    iic_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+					  (i <
+					   num -
+					   1) ? IIC_COMBINED_XFER :
+					  IIC_SINGLE_XFER);
+
+			if (ret != pmsg->len) {
+			  printk("WR FAIL\n");
+				DEB2(printk("i2c-algo-ppc405.o: fail: "
+					    "only wrote %d bytes.\n", ret));
+				return i;
+			} else {
+				DEB2(printk
+				     ("i2c-algo-ppc405.o: wrote %d bytes.\n",
+				      ret));
+			}
+		}
+	}
+	printk("%d\n", num);
+	return num;
+}
+
+/*
+ * Description: Whenever we initiate a transaction, the first byte clocked
+ * onto the bus after the start condition is the address (7 bit) of the
+ * device we want to talk to.  This function manipulates the address specified
+ * so that it makes sense to the hardware when written to the IIC peripheral.
+ *
+ * Note: 10 bit addresses are not supported in this driver, although they are
+ * supported by the hardware.  This functionality needs to be implemented.
+ */
+static inline int
+iic_doAddress(struct i2c_adapter *adap, struct i2c_msg *msg, int retries)
+{
+	struct iic_regs *iic;
+	unsigned short flags = msg->flags;
+	unsigned char addr,addrh;
+
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+	
+/*
+ * The following segment for 10 bit addresses needs to be ported
+ */
+	/* Ten bit addresses not supported right now */
+	if ((flags & I2C_M_TEN)) {
+	  addr = msg->addr&0xff;
+	  addrh = ((msg->addr >> 8)&3 )| 0xf8;
+	} else
+		addr = (msg->addr&0x7f)<<1 ;
+	if (flags & I2C_M_RD)
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+	/*
+	 * Write to the low slave address
+	 */
+	iic_outb(iic->lmadr, addr);
+	/*
+	 * Write zero to the high slave register since we are
+	 * only using 7 bit addresses
+	 */
+	if ((flags & I2C_M_TEN)) {
+	  iic_outb(iic->hmadr, addrh);
+	}
+
+	return 0;
+}
+
+/*
+ * Description: Prepares the controller for a transaction (clearing status
+ * registers, data buffers, etc), and then calls either iic_readbytes or
+ * iic_sendbytes to do the actual transaction.
+ */
+static int
+iic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct iic_regs *iic;
+	struct i2c_msg *pmsg;
+	int i = 0;
+	int ret;
+
+	printk("A\n");
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+
+	pmsg = &msgs[i];
+
+	/*
+	 * Clear status register
+	 */
+	DEB2(printk
+	     (KERN_DEBUG "iic_xfer: iic_xfer: Clearing status register\n"));
+	iic_outb(iic->sts, 0x0a);
+
+	/*
+	 * Wait for any pending transfers to complete
+	 */
+	DEB2(printk
+	     (KERN_DEBUG
+	      "iic_xfer: Waiting for any pending transfers to complete\n"));
+	while ((ret = iic_inb(iic->sts)) == 0x01) {
+		;
+	}
+
+	/*
+	 * Flush master data buf
+	 */
+	DEB2(printk(KERN_DEBUG "iic_xfer: Clearing master data buffer\n"));
+	ret = iic_inb(iic->mdcntl);
+	iic_outb(iic->mdcntl, ret | 0x40);
+
+	/*
+	 * Load slave address
+	 */
+	DEB2(printk(KERN_DEBUG "iic_xfer: Loading slave address\n"));
+	ret = iic_doAddress(adap, pmsg, adap->retries);
+
+	/*
+	 * Check to see if the bus is busy
+	 */
+	ret = iic_inb(iic->extsts);
+	/* Mask off the irrelevent bits */
+	ret = ret & 0x70;
+	/* When the bus is free, the BCS bits in the EXTSTS register are 0b100 */
+	if (ret != 0x40)
+		return IIC_ERR_LOST_ARB;
+	printk("K\n");
+	/*
+	 * Combined transaction (read and write)
+	 */
+	if (num > 1) {
+	  printk("L\n");
+		DEB2(printk
+		     (KERN_DEBUG "iic_xfer: Call combined transaction\n"));
+		ret = iic_combined_transaction(adap, msgs, num);
+	}
+	/*
+	 * Read only
+	 */
+	else if ((num == 1) && (pmsg->flags & I2C_M_RD)) {
+	  
+	  printk("B");
+		/*
+		 * Tell device to begin reading data from the  master data 
+		 */
+		DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's read\n"));
+		ret =
+		    iic_readbytes(adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	}
+	/*
+	 * Write only
+	 */
+	else if ((num == 1) && (!(pmsg->flags & I2C_M_RD))) {
+	  printk("C");
+		/*
+		 * Write data to master data buffers and tell our device
+		 * to begin transmitting
+		 */
+		DEB2(printk(KERN_DEBUG "iic_xfer: Call adapter's write\n"));
+		ret =
+		    iic_sendbytes(adap, pmsg->buf, pmsg->len, IIC_SINGLE_XFER);
+	}
+
+	return ret;
+}
+
+/*
+ * Description: Implements device specific ioctls.  Higher level ioctls can
+ * be found in i2c-core.c and are typical of any i2c controller (specifying
+ * slave address, timeouts, etc).  These ioctls take advantage of any hardware
+ * features built into the controller for which this algorithm-adapter set
+ * was written.  These ioctls allow you to take control of the data and clock
+ * lines on the IBM PPC 405 IIC controller and set the either high or low,
+ * similar to a GPIO pin.
+ */
+static int
+algo_control(struct i2c_adapter *adap, unsigned int cmd, unsigned long arg)
+{
+	struct iic_regs *iic;
+	int ret = 0;
+	int lines;
+
+	iic = (struct iic_regs *) IIC_DEV(vaddr);
+
+	lines = iic_inb(iic->directcntl);
+
+	if (cmd == IICO_I2C_SDAHIGH) {
+		lines = lines & 0x01;
+		if (lines)
+			lines = 0x04;
+		else
+			lines = 0;
+		iic_outb(iic->directcntl, (0x08 | lines));
+	} else if (cmd == IICO_I2C_SDALOW) {
+		lines = lines & 0x01;
+		if (lines)
+			lines = 0x04;
+		else
+			lines = 0;
+		iic_outb(iic->directcntl, (0x00 | lines));
+	} else if (cmd == IICO_I2C_SCLHIGH) {
+		lines = lines & 0x02;
+		if (lines)
+			lines = 0x08;
+		else
+			lines = 0;
+		iic_outb(iic->directcntl, (0x04 | lines));
+	} else if (cmd == IICO_I2C_SCLLOW) {
+		lines = lines & 0x02;
+		if (lines)
+			lines = 0x08;
+		else
+			lines = 0;
+		iic_outb(iic->directcntl, (0x00 | lines));
+	} else if (cmd == IICO_I2C_LINEREAD) {
+		ret = lines;
+	}
+	return ret;
+}
+
+static u32
+iic_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+	    I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static struct i2c_algorithm iic_algo = {
+	"IBM on-chip IIC algorithm",
+	I2C_ALGO_OCP,
+	iic_xfer,
+	NULL,
+	NULL,			/* slave_xmit           */
+	NULL,			/* slave_recv           */
+	algo_control,		/* ioctl                */
+	iic_func,		/* functionality        */
+};
+
+/* 
+ * registering functions to load algorithms at runtime 
+ */
+
+/*
+ * Description: Register bus structure
+ */
+int
+i2c_iic_add_bus(struct i2c_adapter *adap)
+{
+
+	DEB2(printk
+	     (KERN_DEBUG "i2c-algo-iic.o: hw routines for %s registered.\n",
+	      adap->name));
+	adap->id |= iic_algo.id;
+	adap->algo = &iic_algo;
+	adap->timeout = IIC_TIMEOUT;
+	adap->retries = IIC_RETRY;
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+
+	iic_init(adap);
+	i2c_add_adapter(adap);
+	/* scan the I2C bus for valid 7 bit addresses
+	 * (ie things that ACK on 1byte read)
+	 * if i2c_debug is off we print everything on one line.
+	 * if i2c_debug is on we do a newline per print so we don't
+	 * clash too much with printk's in the other functions.
+	 * TODO: check for 10-bit mode and never run as a slave.
+	 */
+
+	if (iic_scan) {
+
+		int found = 0;
+		int i;
+		printk(KERN_INFO " i2c-algo-iic.o: scanning bus %s. Found ",
+		       adap->name);
+		if (i2c_debug)
+			printk("\n");
+		for (i = 0; i < 0x7f; i++) {
+			int ret;
+			struct i2c_msg msg;
+			char data[1];
+			msg.addr = i;
+			msg.buf = data;
+			msg.len = 1;
+			msg.flags = I2C_M_RD;
+			if ((ret = iic_xfer(adap, &msg, 1)) == 1) {
+				if (i2c_debug)
+					printk
+					    ("I2C Found 0x%02x ret %d Data 0x%02x\n",
+					     i, ret, data[0]);
+				else
+					printk("0x%02x ", i);
+				found++;
+			}
+		}
+		if (i2c_debug) {
+			if (!found)
+				printk("I2C Found Nothing\n");
+		} else {
+			if (found)
+				printk("\n");
+			else
+				printk("Nothing\n");
+		}
+
+	}
+	return 1;
+}
+
+int
+i2c_iic_del_bus(struct i2c_adapter *adap)
+{
+	int res;
+	if ((res = i2c_del_adapter(adap)) < 0)
+		return res;
+	DEB2(printk
+	     (KERN_DEBUG "i2c-algo-iic.o: adapter unregistered: %s\n",
+	      adap->name));
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 1;
+}
+
+int __init
+i2c_algo_iic_init(void)
+{
+	printk(KERN_INFO "IBM On-chip iic (i2c) algorithm module %s\n",
+	       IIC_VER);
+
+	return 0;
+}
+
+void
+i2c_algo_iic_exit(void)
+{
+	return;
+}
+
+EXPORT_SYMBOL(i2c_iic_add_bus);
+EXPORT_SYMBOL(i2c_iic_del_bus);
+
+/*
+ * The MODULE_* macros resolve to nothing if MODULES is not defined
+ * when this file is compiled.
+ */
+MODULE_AUTHOR("MontaVista Software <www.mvista.com>");
+MODULE_DESCRIPTION("PPC 405 iic algorithm");
+
+MODULE_PARM(iic_scan, "i");
+MODULE_PARM(i2c_debug, "i");
+
+MODULE_PARM_DESC(iic_scan, "Scan for active chips on the bus");
+MODULE_PARM_DESC(i2c_debug,
+		 "debug level - 0 off; 1 normal; 2,3 more verbose; 9 iic-protocol");
+
+MODULE_LICENSE("GPL");
+
+module_init(i2c_algo_iic_init);
+module_exit(i2c_algo_iic_exit);
diff -Naru linux-2.4.20.orig/drivers/ide/hpt366.c linux-2.4.20/drivers/ide/hpt366.c
--- linux-2.4.20.orig/drivers/ide/hpt366.c	2002-12-11 02:38:06.000000000 +0000
+++ linux-2.4.20/drivers/ide/hpt366.c	2003-04-01 15:14:18.000000000 +0000
@@ -75,6 +75,9 @@
 #include <linux/proc_fs.h>
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
+static unsigned int hpt_revision(struct pci_dev *dev);
+static unsigned int hpt_minimum_revision(struct pci_dev *dev, int revision);
+
 extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
 
 const char *quirk_drives[] = {
@@ -144,6 +147,7 @@
 	unsigned int	chipset_settings;
 };
 
+/* from linux-2.5.63/drivers/ide/pci/hpt366.h */
 /* key for bus clock timings
  * bit
  * 0:3    data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
@@ -166,9 +170,8 @@
  *        PIO.
  * 31     FIFO enable.
  */
-struct chipset_bus_clock_list_entry forty_base [] = {
-
-	{	XFER_UDMA_4,    0x900fd943	},
+struct chipset_bus_clock_list_entry forty_base_hpt366[] = {
+	{	XFER_UDMA_4,	0x900fd943	},
 	{	XFER_UDMA_3,	0x900ad943	},
 	{	XFER_UDMA_2,	0x900bd943	},
 	{	XFER_UDMA_1,	0x9008d943	},
@@ -186,8 +189,7 @@
 	{	0,		0x0120d9d9	}
 };
 
-struct chipset_bus_clock_list_entry thirty_three_base [] = {
-
+struct chipset_bus_clock_list_entry thirty_three_base_hpt366[] = {
 	{	XFER_UDMA_4,	0x90c9a731	},
 	{	XFER_UDMA_3,	0x90cfa731	},
 	{	XFER_UDMA_2,	0x90caa731	},
@@ -206,7 +208,7 @@
 	{	0,		0x0120a7a7	}
 };
 
-struct chipset_bus_clock_list_entry twenty_five_base [] = {
+struct chipset_bus_clock_list_entry twenty_five_base_hpt366[] = {
 
 	{	XFER_UDMA_4,	0x90c98521	},
 	{	XFER_UDMA_3,	0x90cf8521	},
@@ -226,51 +228,9 @@
 	{	0,		0x01208585	}
 };
 
-#if 1
-/* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-        {       XFER_UDMA_5,    0x12446231      },
-        {       XFER_UDMA_4,    0x12446231      },
-        {       XFER_UDMA_3,    0x126c6231      },
-        {       XFER_UDMA_2,    0x12486231      },
-        {       XFER_UDMA_1,    0x124c6233      },
-        {       XFER_UDMA_0,    0x12506297      },
-
-        {       XFER_MW_DMA_2,  0x22406c31      },
-        {       XFER_MW_DMA_1,  0x22406c33      },
-        {       XFER_MW_DMA_0,  0x22406c97      },
-
-        {       XFER_PIO_4,     0x06414e31      },
-        {       XFER_PIO_3,     0x06414e42      },
-        {       XFER_PIO_2,     0x06414e53      },
-        {       XFER_PIO_1,     0x06814e93      },
-        {       XFER_PIO_0,     0x06814ea7      },
-        {       0,              0x06814ea7      }
-};
-
-/* 2x 33MHz timings */
-struct chipset_bus_clock_list_entry sixty_six_base_hpt370[] = {
-	{       XFER_UDMA_5,    0x1488e673       },
-	{       XFER_UDMA_4,    0x1488e673       },
-	{       XFER_UDMA_3,    0x1498e673       },
-	{       XFER_UDMA_2,    0x1490e673       },
-	{       XFER_UDMA_1,    0x1498e677       },
-	{       XFER_UDMA_0,    0x14a0e73f       },
-
-	{       XFER_MW_DMA_2,  0x2480fa73       },
-	{       XFER_MW_DMA_1,  0x2480fa77       }, 
-	{       XFER_MW_DMA_0,  0x2480fb3f       },
-
-	{       XFER_PIO_4,     0x0c82be73       },
-	{       XFER_PIO_3,     0x0c82be95       },
-	{       XFER_PIO_2,     0x0c82beb7       },
-	{       XFER_PIO_1,     0x0d02bf37       },
-	{       XFER_PIO_0,     0x0d02bf5f       },
-	{       0,              0x0d02bf5f       }
-};
-#else
 /* from highpoint documentation. these are old values */
 struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
+/*	{	XFER_UDMA_5,	0x1A85F442,	0x16454e31	}, */
 	{	XFER_UDMA_5,	0x16454e31	},
 	{	XFER_UDMA_4,	0x16454e31	},
 	{	XFER_UDMA_3,	0x166d4e31	},
@@ -309,9 +269,50 @@
 	{       XFER_PIO_0,     0x06914e57      },
 	{       0,              0x06514e57      }
 };
-#endif
 
-struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
+/* these are the current (4 sep 2001) timings from highpoint */
+struct chipset_bus_clock_list_entry thirty_three_base_hpt370a[] = {
+        {       XFER_UDMA_5,    0x12446231      },
+        {       XFER_UDMA_4,    0x12446231      },
+        {       XFER_UDMA_3,    0x126c6231      },
+        {       XFER_UDMA_2,    0x12486231      },
+        {       XFER_UDMA_1,    0x124c6233      },
+        {       XFER_UDMA_0,    0x12506297      },
+
+        {       XFER_MW_DMA_2,  0x22406c31      },
+        {       XFER_MW_DMA_1,  0x22406c33      },
+        {       XFER_MW_DMA_0,  0x22406c97      },
+
+        {       XFER_PIO_4,     0x06414e31      },
+        {       XFER_PIO_3,     0x06414e42      },
+        {       XFER_PIO_2,     0x06414e53      },
+        {       XFER_PIO_1,     0x06814e93      },
+        {       XFER_PIO_0,     0x06814ea7      },
+        {       0,              0x06814ea7      }
+};
+
+/* 2x 33MHz timings */
+struct chipset_bus_clock_list_entry sixty_six_base_hpt370a[] = {
+	{       XFER_UDMA_5,    0x1488e673       },
+	{       XFER_UDMA_4,    0x1488e673       },
+	{       XFER_UDMA_3,    0x1498e673       },
+	{       XFER_UDMA_2,    0x1490e673       },
+	{       XFER_UDMA_1,    0x1498e677       },
+	{       XFER_UDMA_0,    0x14a0e73f       },
+
+	{       XFER_MW_DMA_2,  0x2480fa73       },
+	{       XFER_MW_DMA_1,  0x2480fa77       }, 
+	{       XFER_MW_DMA_0,  0x2480fb3f       },
+
+	{       XFER_PIO_4,     0x0c82be73       },
+	{       XFER_PIO_3,     0x0c82be95       },
+	{       XFER_PIO_2,     0x0c82beb7       },
+	{       XFER_PIO_1,     0x0d02bf37       },
+	{       XFER_PIO_0,     0x0d02bf5f       },
+	{       0,              0x0d02bf5f       }
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt370a[] = {
 	{       XFER_UDMA_5,    0x12848242      },
 	{       XFER_UDMA_4,    0x12ac8242      },
 	{       XFER_UDMA_3,    0x128c8242      },
@@ -331,7 +332,149 @@
 	{       0,              0x0ac1f48a      }
 };
 
+struct chipset_bus_clock_list_entry thirty_three_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c81dc62	},
+	{	XFER_UDMA_5,	0x1c6ddc62	},
+	{	XFER_UDMA_4,	0x1c8ddc62	},
+	{	XFER_UDMA_3,	0x1c8edc62	},	/* checkme */
+	{	XFER_UDMA_2,	0x1c91dc62	},
+	{	XFER_UDMA_1,	0x1c9adc62	},	/* checkme */
+	{	XFER_UDMA_0,	0x1c82dc62	},	/* checkme */
+
+	{	XFER_MW_DMA_2,	0x2c829262	},
+	{	XFER_MW_DMA_1,	0x2c829266	},	/* checkme */
+	{	XFER_MW_DMA_0,	0x2c82922e	},	/* checkme */
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d5e	}
+};
+
+struct chipset_bus_clock_list_entry fifty_base_hpt372[] = {
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x0a81f443	}
+};
+
+struct chipset_bus_clock_list_entry sixty_six_base_hpt372[] = {
+	{	XFER_UDMA_6,	0x1c869c62	},
+	{	XFER_UDMA_5,	0x1cae9c62	},
+	{	XFER_UDMA_4,	0x1c8a9c62	},
+	{	XFER_UDMA_3,	0x1c8e9c62	},
+	{	XFER_UDMA_2,	0x1c929c62	},
+	{	XFER_UDMA_1,	0x1c9a9c62	},
+	{	XFER_UDMA_0,	0x1c829c62	},
+
+	{	XFER_MW_DMA_2,	0x2c829c62	},
+	{	XFER_MW_DMA_1,	0x2c829c66	},
+	{	XFER_MW_DMA_0,	0x2c829d2e	},
+
+	{	XFER_PIO_4,	0x0c829c62	},
+	{	XFER_PIO_3,	0x0c829c84	},
+	{	XFER_PIO_2,	0x0c829ca6	},
+	{	XFER_PIO_1,	0x0d029d26	},
+	{	XFER_PIO_0,	0x0d029d5e	},
+	{	0,		0x0d029d26	}
+};
+
+struct chipset_bus_clock_list_entry thirty_three_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12808242	},
+	{	XFER_UDMA_5,	0x12848242	},
+	{	XFER_UDMA_4,	0x12ac8242	},
+	{	XFER_UDMA_3,	0x128c8242	},
+	{	XFER_UDMA_2,	0x120c8242	},
+	{	XFER_UDMA_1,	0x12148254	},
+	{	XFER_UDMA_0,	0x121882ea	},
+
+	{	XFER_MW_DMA_2,	0x22808242	},
+	{	XFER_MW_DMA_1,	0x22808254	},
+	{	XFER_MW_DMA_0,	0x228082ea	},
+
+	{	XFER_PIO_4,	0x0a81f442	},
+	{	XFER_PIO_3,	0x0a81f443	},
+	{	XFER_PIO_2,	0x0a81f454	},
+	{	XFER_PIO_1,	0x0ac1f465	},
+	{	XFER_PIO_0,	0x0ac1f48a	},
+	{	0,		0x06814e93	}
+};
+
+#if 0
+struct chipset_bus_clock_list_entry fifty_base_hpt374[] = {
+	{	XFER_UDMA_6,	},
+	{	XFER_UDMA_5,	},
+	{	XFER_UDMA_4,	},
+	{	XFER_UDMA_3,	},
+	{	XFER_UDMA_2,	},
+	{	XFER_UDMA_1,	},
+	{	XFER_UDMA_0,	},
+	{	XFER_MW_DMA_2,	},
+	{	XFER_MW_DMA_1,	},
+	{	XFER_MW_DMA_0,	},
+	{	XFER_PIO_4,	},
+	{	XFER_PIO_3,	},
+	{	XFER_PIO_2,	},
+	{	XFER_PIO_1,	},
+	{	XFER_PIO_0,	},
+	{	0,	}
+};
+#endif
+#if 0
+struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
+	{	XFER_UDMA_6,	0x12406231	},	/* checkme */
+	{	XFER_UDMA_5,	0x12446231	},
+				0x14846231
+	{	XFER_UDMA_4,		0x16814ea7	},
+				0x14886231
+	{	XFER_UDMA_3,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_2,		0x16814ea7	},
+				0x148c6231
+	{	XFER_UDMA_1,		0x16814ea7	},
+				0x14906231
+	{	XFER_UDMA_0,		0x16814ea7	},
+				0x14986231
+	{	XFER_MW_DMA_2,		0x16814ea7	},
+				0x26514e21
+	{	XFER_MW_DMA_1,		0x16814ea7	},
+				0x26514e97
+	{	XFER_MW_DMA_0,		0x16814ea7	},
+				0x26514e97
+	{	XFER_PIO_4,		0x06814ea7	},
+				0x06514e21
+	{	XFER_PIO_3,		0x06814ea7	},
+				0x06514e22
+	{	XFER_PIO_2,		0x06814ea7	},
+				0x06514e33
+	{	XFER_PIO_1,		0x06814ea7	},
+				0x06914e43
+	{	XFER_PIO_0,		0x06814ea7	},
+				0x06914e57
+	{	0,		0x06814ea7	}
+};
+#endif
+
 #define HPT366_DEBUG_DRIVE_INFO		0
+#define HPT374_ALLOW_ATA133_6		0
+#define HPT371_ALLOW_ATA133_6		0
+#define HPT302_ALLOW_ATA133_6		0
+#define HPT372_ALLOW_ATA133_6		1
 #define HPT370_ALLOW_ATA100_5		1
 #define HPT366_ALLOW_ATA66_4		1
 #define HPT366_ALLOW_ATA66_3		1
@@ -345,13 +488,13 @@
 static struct pci_dev *hpt_devs[HPT366_MAX_DEVS];
 static int n_hpt_devs;
 
-static unsigned int pci_rev_check_hpt3xx(struct pci_dev *dev);
-static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
 byte hpt366_proc = 0;
 byte hpt363_shared_irq;
 byte hpt363_shared_pin;
 extern char *ide_xfer_verbose (byte xfer_rate);
 
+static int hpt37x_ide_dma_check_done=0;
+
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
@@ -360,21 +503,20 @@
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
 	char *p	= buffer;
-	char *chipset_nums[] = {"366", "366", "368", "370", "370A"};
+	char *chipset_nums[] = {"366", "366", "368", "370", "370A",
+				"372", "302", "371",  "374" };
 	int i;
 
 	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370\n");
+		     "HighPoint HPT366/368/370/371\n");
 	for (i = 0; i < n_hpt_devs; i++) {
 		struct pci_dev *dev = hpt_devs[i];
 		unsigned long iobase = dev->resource[4].start;
-		u32 class_rev;
+		u32 class_rev = hpt_revision(dev);
 		u8 c0, c1;
 
-		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-		class_rev &= 0xff;
-
 		p += sprintf(p, "\nController: %d\n", i);
+
 		p += sprintf(p, "Chipset: HPT%s\n", chipset_nums[class_rev]);
 		p += sprintf(p, "--------------- Primary Channel "
 				"--------------- Secondary Channel "
@@ -388,7 +530,8 @@
 			(c0 & 0x80) ? "no" : "yes",
 			(c1 & 0x80) ? "no" : "yes");
 
-		if (pci_rev_check_hpt3xx(dev)) {
+#ifdef NEVER
+		if (hpt_minimum_revision(dev, 3)) {
 			u8 cbl;
 			cbl = inb_p(iobase + 0x7b);
 			outb_p(cbl | 1, iobase + 0x7b);
@@ -400,6 +543,7 @@
 				(cbl & 0x01) ? 33 : 66);
 			p += sprintf(p, "\n");
 		}
+#endif
 
 		p += sprintf(p, "--------------- drive0 --------- drive1 "
 				"------- drive0 ---------- drive1 -------\n");
@@ -437,20 +581,111 @@
 }
 #endif  /* defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS) */
 
-static unsigned int pci_rev_check_hpt3xx (struct pci_dev *dev)
+static u32 hpt_revision (struct pci_dev *dev)
 {
-	unsigned int class_rev;
+	u32 class_rev;
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
-	return ((int) (class_rev > 0x02) ? 1 : 0);
+
+	switch(dev->device) {
+		case PCI_DEVICE_ID_TTI_HPT374:
+			class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
+		case PCI_DEVICE_ID_TTI_HPT371:
+			class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
+		case PCI_DEVICE_ID_TTI_HPT302:
+			class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
+		case PCI_DEVICE_ID_TTI_HPT372:
+			class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
+		default:
+			break;
+	}
+	return class_rev;
 }
 
-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
+static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
 {
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x01) ? 1 : 0);
+	unsigned int class_rev = hpt_revision(dev);
+	revision--;
+	return ((int) (class_rev > revision) ? 1 : 0);
+}
+
+static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+
+static u8 hpt3xx_ratemask (ide_drive_t *drive)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= 0;
+
+	if (hpt_minimum_revision(dev, 8)) {		/* HPT374 */
+		mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 7)) {	/* HPT371 */
+		mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 6)) {	/* HPT302 */
+		mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 5)) {	/* HPT372 */
+		mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
+	} else if (hpt_minimum_revision(dev, 4)) {	/* HPT370A */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+	} else if (hpt_minimum_revision(dev, 3)) {	/* HPT370 */
+		mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
+	} else {				/* HPT366 and HPT368 */
+		mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
+	}
+	if (!eighty_ninty_three(drive) && (mode))
+		mode = min(mode, (u8)1);
+	return mode;
+}
+
+static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 mode			= hpt3xx_ratemask(drive);
+
+	if (drive->media != ide_disk)
+		return min(speed, (u8)XFER_PIO_4);
+
+	switch(mode) {
+		case 0x04:
+			speed = min(speed, (u8)XFER_UDMA_6);
+			break;
+		case 0x03:
+			speed = min(speed, (u8)XFER_UDMA_5);
+			if (hpt_minimum_revision(dev, 5))
+				break;
+			if (check_in_drive_lists(drive, bad_ata100_5))
+				speed = min(speed, (u8)XFER_UDMA_4);
+			break;
+		case 0x02:
+			speed = min(speed, (u8)XFER_UDMA_4);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if ((check_in_drive_lists(drive, bad_ata66_4)) ||
+			    (!(HPT366_ALLOW_ATA66_4)))
+				speed = min(speed, (u8)XFER_UDMA_3);
+			if ((check_in_drive_lists(drive, bad_ata66_3)) ||
+			    (!(HPT366_ALLOW_ATA66_3)))
+				speed = min(speed, (u8)XFER_UDMA_2);
+			break;
+		case 0x01:
+			speed = min(speed, (u8)XFER_UDMA_2);
+	/*
+	 * CHECK ME, Does this need to be set to 5 ??
+	 */
+			if (hpt_minimum_revision(dev, 3))
+				break;
+			if (check_in_drive_lists(drive, bad_ata33))
+				speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+		case 0x00:
+		default:
+			speed = min(speed, (u8)XFER_MW_DMA_2);
+			break;
+	}
+	return speed;
 }
 
 static int check_in_drive_lists (ide_drive_t *drive, const char **list)
@@ -498,28 +733,28 @@
 	 * Disable the "fast interrupt" prediction. 
 	 */
 	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x80);
 
 	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
+			reg2 = pci_bus_clock_list(speed, forty_base_hpt366);
 			break;
 		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
+			reg2 = pci_bus_clock_list(speed, twenty_five_base_hpt366);
 			break;
 		default:
 		case 7:
-			reg2 = pci_bus_clock_list(speed, thirty_three_base);
+			reg2 = pci_bus_clock_list(speed, thirty_three_base_hpt366);
 			break;
 	}
 #if 0
 	/* this is a nice idea ... */
 	list_conf = pci_bus_clock_list(speed,
 				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
+				       pci_get_drvdata(dev));
 #endif
 	/*
 	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
@@ -534,6 +769,11 @@
 	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
 }
 
+static void hpt368_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt366_tune_chipset(drive, speed);
+}
+
 static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
@@ -544,6 +784,7 @@
 	byte new_fast, drive_fast		= 0;
 	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
 
+	printk("HPT366: use old code -- fix me\n");
 	/*
 	 * Disable the "fast interrupt" prediction.
 	 * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
@@ -565,7 +806,7 @@
 
 	list_conf = pci_bus_clock_list(speed, 
 				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
+				       pci_get_drvdata(dev));
 
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
@@ -577,19 +818,65 @@
 	pci_write_config_dword(dev, drive_pci, list_conf);
 }
 
+static void hpt372_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	u8 speed	= hpt3xx_ratefilter(drive, xferspeed);
+//	u8 speed	= ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
+	u8 regfast	= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	u8 drive_fast	= 0, drive_pci = 0x40 + (drive->dn * 4);
+	u32 list_conf	= 0, drive_conf = 0;
+	u32 conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 * don't holdoff on interrupts. (== 0x01 despite what the docs say)
+	 */
+	pci_read_config_byte(dev, regfast, &drive_fast);
+	drive_fast &= ~0x07;
+	pci_write_config_byte(dev, regfast, drive_fast);
+					
+	list_conf = pci_bus_clock_list(speed,
+			(struct chipset_bus_clock_list_entry *)
+					pci_get_drvdata(dev));
+	pci_read_config_dword(dev, drive_pci, &drive_conf);
+	list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+	if (speed < XFER_MW_DMA_0)
+		list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+	pci_write_config_dword(dev, drive_pci, list_conf);
+}
+
+static void hpt374_tune_chipset (ide_drive_t *drive, u8 speed)
+{
+	hpt372_tune_chipset(drive, speed);
+}
+
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
 {
+	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+
 	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
 		return -1;
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+	if (hpt_minimum_revision(dev, 8))
+		hpt374_tune_chipset(drive, speed);
+#if 0
+	else if (hpt_minimum_revision(dev, 7))
+		hpt371_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 6))
+		hpt302_tune_chipset(drive, speed);
+#endif
+	else if (hpt_minimum_revision(dev, 5))
+		hpt372_tune_chipset(drive, speed);
+	else if (hpt_minimum_revision(dev, 3))
 		hpt370_tune_chipset(drive, speed);
-        } else {
+	else if (hpt_minimum_revision(dev, 2))
+		hpt368_tune_chipset(drive, speed);
+	else
                 hpt366_tune_chipset(drive, speed);
-        }
 	drive->current_speed = speed;
 	return ((int) ide_config_drive_speed(drive, speed));
 }
@@ -642,6 +929,9 @@
 		case 1:		speed = XFER_PIO_1;break;
 		default:	speed = XFER_PIO_0;break;
 	}
+
+	/* no check a range of pio -- fix me */
+
 	(void) hpt3xx_tune_chipset(drive, speed);
 }
 
@@ -662,28 +952,36 @@
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
 	byte ultra66		= eighty_ninty_three(drive);
+	byte mode		= hpt3xx_ratemask(drive);
 	int  rval;
 
 	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
 		return ((int) ide_dma_off_quietly);
 
-	if ((id->dma_ultra & 0x0020) &&
+	if ((id->dma_ultra & 0x0040) &&
+	    (HPT370_ALLOW_ATA100_5)  &&
+	    (mode >= 0x04) &&
+	    (ultra66)) {
+		speed = XFER_UDMA_6;
+	} else if ((id->dma_ultra & 0x0020) &&
 	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
 	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
+	    (mode >= 0x03) &&
 	    (ultra66)) {
 		speed = XFER_UDMA_5;
 	} else if ((id->dma_ultra & 0x0010) &&
 		   (!check_in_drive_lists(drive, bad_ata66_4)) &&
-		   (HPT366_ALLOW_ATA66_4) &&
+		   (mode >= 0x02) &&
 		   (ultra66)) {
 		speed = XFER_UDMA_4;
 	} else if ((id->dma_ultra & 0x0008) &&
 		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
-		   (HPT366_ALLOW_ATA66_3) &&
+		   (mode >= 0x02) &&
 		   (ultra66)) {
 		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
+	} else if (id->dma_ultra &&
+		   (mode >= 0x01) &&
+		   (!check_in_drive_lists(drive, bad_ata33))) {
 		if (id->dma_ultra & 0x0004) {
 			speed = XFER_UDMA_2;
 		} else if (id->dma_ultra & 0x0002) {
@@ -727,7 +1025,7 @@
 void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 {
 	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+		if (hpt_minimum_revision(HWIF(drive)->pci_dev,3)) {
 			byte reg5a = 0;
 			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
 			if (((reg5a & 0x10) >> 4) != mask)
@@ -751,6 +1049,7 @@
 	ide_dma_action_t dma_func = ide_dma_on;
 
 	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+		hpt37x_ide_dma_check_done = 1;
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -767,7 +1066,7 @@
 			}
 		} else if (id->field_valid & 2) {
 try_dma_modes:
-			if (id->dma_mword & 0x0007) {
+			if (id->dma_mword & 0x0007) {  /* xxx */
 				/* Force if Capable regular DMA modes */
 				dma_func = config_chipset_for_dma(drive);
 				if (dma_func != ide_dma_on)
@@ -784,12 +1083,16 @@
 		} else {
 			goto fast_ata_pio;
 		}
-	} else if ((id->capability & 8) || (id->field_valid & 2)) {
+	} else if ( (id && (id->capability & 8)) || (id->field_valid & 2)) {
 fast_ata_pio:
 		dma_func = ide_dma_off_quietly;
 no_dma_set:
-
 		config_chipset_for_pio(drive);
+	} else {
+		if( !(id && (id->capability & 1)) ){
+			printk("HPT37X: %s: unsupported DMA drive\n", drive->name);
+			return 1;
+		}
 	}
 	return HWIF(drive)->dmaproc(dma_func, drive);
 }
@@ -889,6 +1192,41 @@
 	}
 	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
 }
+
+int hpt37x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	byte msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
+	byte bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
+
+	switch (func) {
+		case ide_dma_check:
+			return config_drive_xfer_rate(drive);
+		case ide_dma_end:
+			pci_read_config_byte(dev, 0x6a, &bwsr_stat);
+			pci_read_config_byte(dev, mscreg, &msc_stat);
+			if ((bwsr_stat & bwsr_mask) == bwsr_mask)
+				pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+			break;
+		case ide_dma_on:
+			if( !hpt37x_ide_dma_check_done ){
+				/* kernel parameter: ide0=noautotune or ide=nodma */
+				if( !hwif->autodma ){
+					/* kernel parameter: ide=nodma */
+
+					printk("HPT37X: Allow DMA\n");
+					hwif->autodma = 1;
+				}
+				(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
+				(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+			}
+			break;
+		default:
+			break;
+	}
+	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
+}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 /*
@@ -1006,13 +1344,20 @@
 	return 0;
 }
 
-static void __init init_hpt370(struct pci_dev *dev)
+static int __init init_hpt37x(struct pci_dev *dev)
 {
 	int adjust, i;
 	u16 freq;
 	u32 pll;
 	byte reg5bh;
 
+#if 1
+	u8 reg5ah = 0;
+	pci_read_config_byte(dev, 0x5a, &reg5ah);
+	/* interrupt force enable */
+	pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
+#endif
+
 	/*
 	 * default to pci clock. make sure MA15/16 are set to output
 	 * to prevent drives having problems with 40-pin cables.
@@ -1027,18 +1372,41 @@
 	freq &= 0x1FF;
 	if (freq < 0x9c) {
 		pll = F_LOW_PCI_33;
-		dev->sysdata = (void *) thirty_three_base_hpt370;
-		printk("HPT370: using 33MHz PCI clock\n");
+		if (hpt_minimum_revision(dev,8))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
+		printk("HPT37X: using 33MHz PCI clock\n");
 	} else if (freq < 0xb0) {
 		pll = F_LOW_PCI_40;
 	} else if (freq < 0xc8) {
 		pll = F_LOW_PCI_50;
-		dev->sysdata = (void *) fifty_base_hpt370;
-		printk("HPT370: using 50MHz PCI clock\n");
+		if (hpt_minimum_revision(dev,8))
+			pci_set_drvdata(dev, (void *) NULL);
+		else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+		
+		printk("HPT37X: using 50MHz PCI clock\n");
 	} else {
 		pll = F_LOW_PCI_66;
-		dev->sysdata = (void *) sixty_six_base_hpt370;
-		printk("HPT370: using 66MHz PCI clock\n");
+		if (hpt_minimum_revision(dev,8)){
+			printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
+			pci_set_drvdata(dev, (void *) NULL);
+		}else if (hpt_minimum_revision(dev,5))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
+		else if (hpt_minimum_revision(dev,4))
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+		else
+			pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
+		printk("HPT37X: using 66MHz PCI clock\n");
 	}
 	
 	/*
@@ -1048,8 +1416,8 @@
 	 * don't like to use the PLL because it will cause glitches
 	 * on PRST/SRST when the HPT state engine gets reset.
 	 */
-	if (dev->sysdata) 
-		goto init_hpt370_done;
+	if (pci_get_drvdata(dev)) 
+		goto init_hpt37X_done;
 	
 	/*
 	 * adjust PLL based upon PCI clock, enable it, and wait for
@@ -1076,9 +1444,16 @@
 				pci_write_config_dword(dev, 0x5c, 
 						       pll & ~0x100);
 				pci_write_config_byte(dev, 0x5b, 0x21);
-				dev->sysdata = (void *) fifty_base_hpt370;
-				printk("HPT370: using 50MHz internal PLL\n");
-				goto init_hpt370_done;
+				if (hpt_minimum_revision(dev,8))
+					return -EOPNOTSUPP;
+				else if (hpt_minimum_revision(dev,5))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
+				else if (hpt_minimum_revision(dev,4))
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				else
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+				printk("HPT37X: using 50MHz internal PLL\n");
+				goto init_hpt37X_done;
 			}
 		}
 pll_recal:
@@ -1088,15 +1463,52 @@
 			pll += (adjust >> 1);
 	} 
 
-init_hpt370_done:
+init_hpt37X_done:
 	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
+	pci_write_config_byte(dev, 0x50, 0x37);
 	pci_write_config_byte(dev, 0x54, 0x37); 
 	udelay(100);
+	return 0;
+}
+
+static int __init init_hpt366 (struct pci_dev *dev)
+{
+	u32 reg1	= 0;
+	u8 drive_fast	= 0;
+
+	/*
+	 * Disable the "fast interrupt" prediction.
+	 */
+	pci_read_config_byte(dev, 0x51, &drive_fast);
+	if (drive_fast & 0x80)
+		pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+	pci_read_config_dword(dev, 0x40, &reg1);
+									
+	/* detect bus speed by looking at control reg timing: */
+	switch((reg1 >> 8) & 7) {
+		case 5:
+			pci_set_drvdata(dev, (void *) forty_base_hpt366);
+			break;
+		case 9:
+			pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
+			break;
+		case 7:
+		default:
+			pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
+			break;
+	}
+
+	if (pci_get_drvdata(dev))
+	{
+		printk(KERN_ERR "hpt366: unknown bus timing.\n");
+		pci_set_drvdata(dev, (void *) NULL);
+	}
+	return 0;
 }
 
 unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
 {
+	int ret = 0;
 	byte test = 0;
 
 	if (dev->resource[PCI_ROM_RESOURCE].start)
@@ -1118,12 +1530,15 @@
 	if (test != 0x08)
 		pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
-	if (pci_rev_check_hpt3xx(dev)) {
-		init_hpt370(dev);
-		hpt_devs[n_hpt_devs++] = dev;
+	if (hpt_minimum_revision(dev, 3)) {
+		ret = init_hpt37x(dev);
 	} else {
-		hpt_devs[n_hpt_devs++] = dev;
+		ret = init_hpt366(dev);
 	}
+
+	if (ret)
+		return ret;
+	hpt_devs[n_hpt_devs++] = dev;
 	
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!hpt366_proc) {
@@ -1151,8 +1566,6 @@
 
 void __init ide_init_hpt366 (ide_hwif_t *hwif)
 {
-	int hpt_rev;
-
 	hwif->tuneproc	= &hpt3xx_tune_drive;
 	hwif->speedproc	= &hpt3xx_tune_chipset;
 	hwif->quirkproc	= &hpt3xx_quirkproc;
@@ -1165,25 +1578,29 @@
 		hwif->serialized = hwif->mate->serialized = 1;
 #endif
 
-	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
-	if (hpt_rev) {
-		/* set up ioctl for power status. note: power affects both
-		 * drives on each channel */
-		hwif->busproc   = &hpt370_busproc;
-	}
-
-	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-		/* do nothing now but will split device types */
+	if (hpt_minimum_revision(hwif->pci_dev,3)) {
+		u8 reg5ah = 0;
+			pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
+		/*
+		 * set up ioctl for power status.
+		 * note: power affects both
+		 * drives on each channel
+		 */
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt370_busproc;
+	} else if (hpt_minimum_revision(hwif->pci_dev,2)) {
+		hwif->resetproc	= &hpt3xx_reset;
+		hwif->busproc	= &hpt3xx_tristate;
+	} else {
 		hwif->resetproc = &hpt3xx_reset;
-/*
- * don't do until we can parse out the cobalt box argh ...
- *		hwif->busproc   = &hpt3xx_tristate;
- */
+		hwif->busproc   = &hpt3xx_tristate;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
-		if (hpt_rev) {
+		if (hpt_minimum_revision(hwif->pci_dev,5)) {
+			hwif->dmaproc = &hpt37x_dmaproc;
+		}else if (hpt_minimum_revision(hwif->pci_dev,3)) {	/* xxx */
 			byte reg5ah = 0;
 			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
 			if (reg5ah & 0x10)	/* interrupt force enable */
@@ -1194,8 +1611,6 @@
 		}
 		if (!noautodma)
 			hwif->autodma = 1;
-		else
-			hwif->autodma = 0;
 	} else {
 		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
@@ -1211,23 +1626,25 @@
 void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
 {
 	byte masterdma = 0, slavedma = 0;
-	byte dma_new = 0, dma_old = inb(dmabase+2);
+	byte dma_m_new, dma_m_old = inb(dmabase+0x2);
+	byte dma_s_new, dma_s_old = inb(dmabase+0xa);
 	byte primary	= hwif->channel ? 0x4b : 0x43;
 	byte secondary	= hwif->channel ? 0x4f : 0x47;
 	unsigned long flags;
 
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
+	local_irq_save(flags);
 
-	dma_new = dma_old;
+	dma_m_new = dma_m_old;
+	dma_s_new = dma_s_old;
 	pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
 	pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
 
-	if (masterdma & 0x30)	dma_new |= 0x20;
-	if (slavedma & 0x30)	dma_new |= 0x40;
-	if (dma_new != dma_old) outb(dma_new, dmabase+2);
+	if (masterdma & 0x30)	dma_m_new |= 0x60;
+	if (slavedma & 0x30)	dma_s_new |= 0x40;
+	if (dma_m_new != dma_m_old) outb(dma_m_new, dmabase+0x2);
+	if (dma_s_new != dma_s_old) outb(dma_s_new, dmabase+0xa);
 
-	__restore_flags(flags);	/* local CPU only */
+	local_irq_restore(flags);
 
 	ide_setup_dma(hwif, dmabase, 8);
 }
diff -Naru linux-2.4.20.orig/drivers/ide/ide-disk.c linux-2.4.20/drivers/ide/ide-disk.c
--- linux-2.4.20.orig/drivers/ide/ide-disk.c	2002-12-11 02:37:57.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-disk.c	2003-04-01 15:14:18.000000000 +0000
@@ -1425,6 +1425,12 @@
 	if (drive->id->cfs_enable_2 & 0x3000)
 		write_cache(drive, (id->cfs_enable_2 & 0x3000));
 	(void) probe_lba_addressing(drive, 1);
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+{
+	extern int obsled_out(int);
+	obsled_out(4);
+}
+#endif
 }
 
 static int idedisk_cleanup (ide_drive_t *drive)
diff -Naru linux-2.4.20.orig/drivers/ide/ide-pci.c linux-2.4.20/drivers/ide/ide-pci.c
--- linux-2.4.20.orig/drivers/ide/ide-pci.c	2002-12-11 02:38:03.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-pci.c	2003-04-01 15:14:18.000000000 +0000
@@ -81,6 +81,7 @@
 #define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
 #define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
 #define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
+#define DEVID_HPT371	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     0x0007})
 #define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
 #define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
 #define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
@@ -454,6 +455,7 @@
 	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
 	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
 	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
+	{DEVID_HPT371,	"HPT371",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD, 0 },
 	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
@@ -748,6 +750,8 @@
 controller_ok:			
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03))
 			return;
+		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) && (port == 0))
+			continue;
 		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
 			ctl  = dev->resource[(2*port)+1].start;
 			base = dev->resource[2*port].start;
@@ -832,6 +836,7 @@
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6280R) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
+		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT371) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
 		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
diff -Naru linux-2.4.20.orig/drivers/ide/ide-probe.c linux-2.4.20/drivers/ide/ide-probe.c
--- linux-2.4.20.orig/drivers/ide/ide-probe.c	2002-12-11 02:37:04.000000000 +0000
+++ linux-2.4.20/drivers/ide/ide-probe.c	2003-04-01 15:14:18.000000000 +0000
@@ -261,7 +261,9 @@
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 	ide_hwif_t *hwif = HWIF(drive);
+#ifdef CONFIG_IDEPCI_SHARE_IRQ
 	int irqdefense = 0;
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
 
 	if (IDE_CONTROL_REG && !hwif->irq) {
 		autoprobe = 1;
@@ -275,7 +277,7 @@
 		disable_irq(hwif->irq);
 		irqdefense = 1;
 	}
-#endif CONFIG_IDEPCI_SHARE_IRQ
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
 
 	retval = actual_try_to_identify(drive, cmd);
 
@@ -305,7 +307,7 @@
 #ifdef CONFIG_IDEPCI_SHARE_IRQ
 	if (irqdefense)
 		enable_irq(hwif->irq);
-#endif CONFIG_IDEPCI_SHARE_IRQ
+#endif /* CONFIG_IDEPCI_SHARE_IRQ */
 
 	return retval;
 }
diff -Naru linux-2.4.20.orig/drivers/mtd/maps/Config.in linux-2.4.20/drivers/mtd/maps/Config.in
--- linux-2.4.20.orig/drivers/mtd/maps/Config.in	2002-12-11 02:39:44.000000000 +0000
+++ linux-2.4.20/drivers/mtd/maps/Config.in	2003-04-01 15:14:18.000000000 +0000
@@ -51,8 +51,16 @@
    if [ "$CONFIG_MBX" = "y" ]; then
       dep_tristate '  System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI
    fi
-   if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then
+   if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" -o "$CONFIG_OPENBLOCKS266" ]; then
       dep_tristate '  CFI Flash device mapped on IBM Redwood' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI
+#	if [ "$CONFIG_MTD_REDWOOD" = "y" ]; then 
+#	  if [ "$CONFIG_OPENBLOCKS266" = "y" ]; then
+#	   bool 'Reserve flash for user' CONFIG_MTD_OPENBLOCKSUSER $CONFIG_MTD_OPENBLOCKSUSER
+#	     if [ "$CONFIG_MTD_OPENBLOCKSUSER" = "y" ]; then
+#		int 'Max compressed kernel size' CONFIG_OPENBLOCKS_MAXKERNSIZE $CONFIG_OPENBLOCKS_MAXKERNSIZE
+#	     fi
+#	  fi
+#       fi
    fi
    if [ "$CONFIG_BEECH" = "y" ]; then
       dep_tristate '  CFI Flash device mapped on IBM Beech' CONFIG_MTD_BEECH $CONFIG_MTD_CFI
diff -Naru linux-2.4.20.orig/drivers/mtd/maps/redwood.c linux-2.4.20/drivers/mtd/maps/redwood.c
--- linux-2.4.20.orig/drivers/mtd/maps/redwood.c	2002-12-11 02:39:51.000000000 +0000
+++ linux-2.4.20/drivers/mtd/maps/redwood.c	2003-04-01 15:14:18.000000000 +0000
@@ -47,7 +47,7 @@
 #define STBXX_OB_SZ	0x20000
 #define STBXX_4MB	0x4000000
 
-#if !defined (CONFIG_REDWOOD_6)
+#if !defined (CONFIG_REDWOOD_6) && !defined(CONFIG_OPENBLOCKS266)
 #define WINDOW_ADDR 0xffc00000
 #define WINDOW_SIZE 0x00400000
 
@@ -97,6 +97,7 @@
 #define WINDOW_ADDR 0xff800000
 #define WINDOW_SIZE 0x00800000
 
+#ifdef CONFIG_REDWOOD_6
 #define RW_PART0_OF	0
 #define RW_PART0_SZ	0x400000	/* 4 MB data */
 #define RW_PART1_OF	RW_PART0_OF + RW_PART0_SZ 	
@@ -129,48 +130,96 @@
 		mask_flags: MTD_WRITEABLE	/* force read-only */
 	}
 };
-
+#else
+#define RW_CONF_OF     0
+#define RW_CONF_SZ     0x10000          /*64Kb Variable data*/
+#define RW_BIOS_OF	0x7c0000         /* BIOS area */
+#define RW_BIOS_SZ	0x40000
+#define RW_KERN_OF	(RW_CONF_OF)+(RW_CONF_SZ)
+#if defined(CONFIG_OPENBLOCKS_MAXKERNSIZE) && (CONFIG_OPENBLOCKS_MAXKERNSIZE != 0)
+#define RW_KERN_SZ     CONFIG_OPENBLOCKS_MAXKERNSIZE
+#else
+#define RW_KERN_SZ     (RW_BIOS_OF) - (RW_KERN_OF)
+#endif
+#define RW_USER_OF     (RW_KERN_OF) + (RW_KERN_SZ)
+#define RW_USER_SZ     (RW_BIOS_OF) - (RW_USER_OF)
+static struct mtd_partition redwood_flash_partitions[] = {
+	{
+		name: "OpenBlockS Configuration Data",
+		offset: RW_CONF_OF,
+		size: RW_CONF_SZ
+	},
+	{
+		name: "OpenBlockS Boot Image",
+		offset: RW_KERN_OF,
+		size: RW_KERN_SZ
+	},
+	{
+		name: "OpenBlockS OpenBIOS",
+		offset: RW_BIOS_OF,
+		size: RW_BIOS_SZ,
+		mask_flags: MTD_WRITEABLE	/* force read-only */
+	},
+#if  (RW_USER_SZ > 0)
+	{
+		name: "OpenBlockS User Flash",
+		offset: RW_USER_OF,
+		size: RW_USER_SZ,
+	}
+#elif (RW_USER_SZ < 0)
+#error  "Kernel Size Invalid"
+#endif	
+};
+#endif
 #endif
 
 __u8 redwood_flash_read8(struct map_info *map, unsigned long ofs)
 {
+  iobarrier_rw();
 	return *(__u8 *)(map->map_priv_1 + ofs);
 }
 
 __u16 redwood_flash_read16(struct map_info *map, unsigned long ofs)
 {
+  iobarrier_rw();
 	return *(__u16 *)(map->map_priv_1 + ofs);
 }
 
 __u32 redwood_flash_read32(struct map_info *map, unsigned long ofs)
 {
+  iobarrier_rw();
 	return *(volatile unsigned int *)(map->map_priv_1 + ofs);
 }
 
 void redwood_flash_copy_from(struct map_info *map, void *to,
 		unsigned long from, ssize_t len)
 {
+  iobarrier_rw();
 	memcpy(to, (void *)(map->map_priv_1 + from), len);
 }
 
 void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
+  iobarrier_rw();
 	*(__u8 *)(map->map_priv_1 + adr) = d;
 }
 
 void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
+  iobarrier_rw();
 	*(__u16 *)(map->map_priv_1 + adr) = d;
 }
 
 void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
 {
+  iobarrier_rw();
 	*(__u32 *)(map->map_priv_1 + adr) = d;
 }
 
 void redwood_flash_copy_to(struct map_info *map, unsigned long to,
 		const void *from, ssize_t len)
 {
+  iobarrier_rw();
 	memcpy((void *)(map->map_priv_1 + to), from, len);
 }
 
diff -Naru linux-2.4.20.orig/drivers/net/Makefile linux-2.4.20/drivers/net/Makefile
--- linux-2.4.20.orig/drivers/net/Makefile	2002-12-11 02:38:36.000000000 +0000
+++ linux-2.4.20/drivers/net/Makefile	2003-04-01 15:14:18.000000000 +0000
@@ -21,14 +21,14 @@
 list-multi	:=	rcpci.o
 rcpci-objs	:=	rcpci45.o rclanmtl.o
 
-ifeq ($(CONFIG_TULIP),y)
-  obj-y += tulip/tulip.o
-endif
-
 ifeq ($(CONFIG_OCP_NET),y)
   obj-y += ibm_ocp/ocp.o
 endif
 
+ifeq ($(CONFIG_TULIP),y)
+  obj-y += tulip/tulip.o
+endif
+
 ifeq ($(CONFIG_E1000),y)
   obj-y += e1000/e1000.o
 endif
diff -Naru linux-2.4.20.orig/drivers/net/tulip/tulip.h linux-2.4.20/drivers/net/tulip/tulip.h
--- linux-2.4.20.orig/drivers/net/tulip/tulip.h	2002-12-11 02:40:35.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/tulip.h	2003-04-01 15:14:18.000000000 +0000
@@ -332,6 +332,10 @@
 
 struct ring_info {
 	struct sk_buff	*skb;
+#ifdef CONFIG_OPENBLOCKS266 
+  char *bounce_buffer;
+  size_t bb_size;
+#endif
 	dma_addr_t	mapping;
 };
 
diff -Naru linux-2.4.20.orig/drivers/net/tulip/tulip_core.c linux-2.4.20/drivers/net/tulip/tulip_core.c
--- linux-2.4.20.orig/drivers/net/tulip/tulip_core.c	2002-12-11 02:37:38.000000000 +0000
+++ linux-2.4.20/drivers/net/tulip/tulip_core.c	2003-04-01 15:14:18.000000000 +0000
@@ -702,6 +702,10 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		tp->tx_buffers[i].skb = NULL;
 		tp->tx_buffers[i].mapping = 0;
+#ifdef CONFIG_OPENBLOCKS266
+		tp->tx_buffers[i].bounce_buffer = NULL;
+		tp->tx_buffers[i].bb_size = 0;
+#endif
 		tp->tx_ring[i].status = 0x00000000;
 		tp->tx_ring[i].buffer2 = cpu_to_le32(tp->tx_ring_dma + sizeof(struct tulip_tx_desc) * (i + 1));
 	}
@@ -723,8 +727,28 @@
 	entry = tp->cur_tx % TX_RING_SIZE;
 
 	tp->tx_buffers[entry].skb = skb;
+#ifdef CONFIG_OPENBLOCKS266
+	{
+	  /*realloc bounce buffer*/
+	  u32 ptr; /*XXX I want to use uintptr_t */
+	  if(tp->tx_buffers[entry].bb_size < skb->len){ 
+	    tp->tx_buffers[entry].bb_size = skb->len;
+	    if(tp->tx_buffers[entry].bounce_buffer)
+	      kfree(tp->tx_buffers[entry].bounce_buffer);
+	    tp->tx_buffers[entry].bounce_buffer = kmalloc(skb->len+3,
+							  GFP_ATOMIC);
+	  }
+	  /*Align 4 byte boundary*/
+	  ptr = (u32)tp->tx_buffers[entry].bounce_buffer + 3;
+	  ptr &= ~3;
+	  
+	  memcpy((void *)ptr, skb->data, skb->len);
+	  mapping = pci_map_single(tp->pdev, (void *)ptr, skb->len, PCI_DMA_TODEVICE);
+	}
+#else
 	mapping = pci_map_single(tp->pdev, skb->data,
 				 skb->len, PCI_DMA_TODEVICE);
+#endif
 	tp->tx_buffers[entry].mapping = mapping;
 	tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
 
diff -Naru linux-2.4.20.orig/drivers/pci/pci.c-ugly linux-2.4.20/drivers/pci/pci.c-ugly
--- linux-2.4.20.orig/drivers/pci/pci.c-ugly	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/drivers/pci/pci.c-ugly	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,2218 @@
+/*
+ *	$Id: linux-ppc-2.4.20-obs266.diff,v 1.2 2003/04/01 13:11:41 todoroki Exp $
+ *
+ *	PCI Bus Services, see include/linux/pci.h for further explanation.
+ *
+ *	Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
+ *	David Mosberger-Tang
+ *
+ *	Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/kmod.h>		/* for hotplug_path */
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/cache.h>
+
+#include <asm/page.h>
+#include <asm/dma.h>	/* isa_dma_bridge_buggy */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+LIST_HEAD(pci_root_buses);
+LIST_HEAD(pci_devices);
+
+/**
+ * pci_find_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI 
+ * device resides and the logical device number within that slot 
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device 
+ * is located in system global list of PCI devices.  If the device
+ * is found, a pointer to its data structure is returned.  If no 
+ * device is found, %NULL is returned.
+ */
+struct pci_dev *
+pci_find_slot(unsigned int bus, unsigned int devfn)
+{
+	struct pci_dev *dev;
+
+	pci_for_each_dev(dev) {
+		if (dev->bus->number == bus && dev->devfn == devfn)
+			return dev;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * device structure is returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_subsys(unsigned int vendor, unsigned int device,
+		unsigned int ss_vendor, unsigned int ss_device,
+		const struct pci_dev *from)
+{
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
+		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+		    (device == PCI_ANY_ID || dev->device == device) &&
+		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+			return dev;
+		n = n->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pci_find_device - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @vendor and @device, a pointer to its device structure is
+ * returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ */
+struct pci_dev *
+pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
+{
+	return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
+}
+
+
+/**
+ * pci_find_class - begin or continue searching for a PCI device by class
+ * @class: search for a PCI device with this class designation
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices.  If a PCI device is
+ * found with a matching @class, a pointer to its device structure is
+ * returned.  Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL to the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
+ */
+struct pci_dev *
+pci_find_class(unsigned int class, const struct pci_dev *from)
+{
+	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+
+	while (n != &pci_devices) {
+		struct pci_dev *dev = pci_dev_g(n);
+		if (dev->class == class)
+			return dev;
+		n = n->next;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_capability - query for devices' capabilities 
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Tell if a device supports a given PCI capability.
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.  Possible values for @cap:
+ *
+ *  %PCI_CAP_ID_PM           Power Management 
+ *
+ *  %PCI_CAP_ID_AGP          Accelerated Graphics Port 
+ *
+ *  %PCI_CAP_ID_VPD          Vital Product Data 
+ *
+ *  %PCI_CAP_ID_SLOTID       Slot Identification 
+ *
+ *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
+ *
+ *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
+ */
+int
+pci_find_capability(struct pci_dev *dev, int cap)
+{
+	u16 status;
+	u8 pos, id;
+	int ttl = 48;
+
+	pci_read_config_word(dev, PCI_STATUS, &status);
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+		pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
+		break;
+	default:
+		return 0;
+	}
+	while (ttl-- && pos >= 0x40) {
+		pos &= ~3;
+		pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
+	}
+	return 0;
+}
+
+
+/**
+ * pci_find_parent_resource - return resource region of parent bus of given region
+ * @dev: PCI device structure contains resources to be searched
+ * @res: child resource record for which parent is sought
+ *
+ *  For given resource region of given device, return the resource
+ *  region of parent bus the given region is contained in or where
+ *  it should be allocated from.
+ */
+struct resource *
+pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
+{
+	const struct pci_bus *bus = dev->bus;
+	int i;
+	struct resource *best = NULL;
+
+	for(i=0; i<4; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+		if (res->start && !(res->start >= r->start && res->end <= r->end))
+			continue;	/* Not contained */
+		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+			continue;	/* Wrong type */
+		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
+			return r;	/* Exact match */
+		if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
+			best = r;	/* Approximating prefetchable by non-prefetchable */
+	}
+	return best;
+}
+
+/**
+ * pci_set_power_state - Set the power state of a PCI device
+ * @dev: PCI device to be suspended
+ * @state: Power state we're entering
+ *
+ * Transition a device to a new power state, using the Power Management 
+ * Capabilities in the device's config space.
+ *
+ * RETURN VALUE: 
+ * -EINVAL if trying to enter a lower state than we're already in.
+ * 0 if we're already in the requested state.
+ * -EIO if device does not support PCI PM.
+ * 0 if we can successfully change the power state.
+ */
+
+int
+pci_set_power_state(struct pci_dev *dev, int state)
+{
+	int pm;
+	u16 pmcsr;
+
+	/* bound the state we're entering */
+	if (state > 3) state = 3;
+
+	/* Validate current state:
+	 * Can enter D0 from any state, but if we can only go deeper 
+	 * to sleep if we're already in a low power state
+	 */
+	if (state > 0 && dev->current_state > state)
+		return -EINVAL;
+	else if (dev->current_state == state) 
+		return 0;        /* we're already there */
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+	
+	/* abort if the device doesn't support PM capabilities */
+	if (!pm) return -EIO; 
+
+	/* check if this device supports the desired state */
+	if (state == 1 || state == 2) {
+		u16 pmc;
+		pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
+		if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO;
+		else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO;
+	}
+
+	/* If we're in D3, force entire word to 0.
+	 * This doesn't affect PME_Status, disables PME_En, and
+	 * sets PowerState to 0.
+	 */
+	if (dev->current_state >= 3)
+		pmcsr = 0;
+	else {
+		pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
+		pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+		pmcsr |= state;
+	}
+
+	/* enter specified state */
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+
+	/* Mandatory power management transition delays */
+	/* see PCI PM 1.1 5.6.1 table 18 */
+	if(state == 3 || dev->current_state == 3)
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+	else if(state == 2 || dev->current_state == 2)
+		udelay(200);
+	dev->current_state = state;
+
+	return 0;
+}
+
+/**
+ * pci_save_state - save the PCI configuration space of a device before suspending
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - buffer to hold config space context
+ *
+ * @buffer must be large enough to hold the entire PCI 2.2 config space 
+ * (>= 64 bytes).
+ */
+int
+pci_save_state(struct pci_dev *dev, u32 *buffer)
+{
+	int i;
+	if (buffer) {
+		/* XXX: 100% dword access ok here? */
+		for (i = 0; i < 16; i++)
+			pci_read_config_dword(dev, i * 4,&buffer[i]);
+	}
+	return 0;
+}
+
+/** 
+ * pci_restore_state - Restore the saved state of a PCI device
+ * @dev: - PCI device that we're dealing with
+ * @buffer: - saved PCI config space
+ *
+ */
+int 
+pci_restore_state(struct pci_dev *dev, u32 *buffer)
+{
+	int i;
+
+	if (buffer) {
+		for (i = 0; i < 16; i++)
+			pci_write_config_dword(dev,i * 4, buffer[i]);
+	}
+	/*
+	 * otherwise, write the context information we know from bootup.
+	 * This works around a problem where warm-booting from Windows
+	 * combined with a D3(hot)->D0 transition causes PCI config
+	 * header data to be forgotten.
+	 */	
+	else {
+		for (i = 0; i < 6; i ++)
+			pci_write_config_dword(dev,
+					       PCI_BASE_ADDRESS_0 + (i * 4),
+					       dev->resource[i].start);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+	return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
+ * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable selected I/O and memory resources. Wake up the device if it 
+ *  was suspended. Beware, this function can fail.
+ */
+ 
+int
+pci_enable_device_bars(struct pci_dev *dev, int bars)
+{
+	int err;
+
+	pci_set_power_state(dev, 0);
+	if ((err = pcibios_enable_device(dev, bars)) < 0)
+		return err;
+	return 0;
+}
+
+/**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ *
+ *  Initialize device before it's used by a driver. Ask low-level code
+ *  to enable I/O and memory. Wake up the device if it was suspended.
+ *  Beware, this function can fail.
+ */
+int
+pci_enable_device(struct pci_dev *dev)
+{
+	return pci_enable_device_bars(dev, 0x3F);
+}
+
+/**
+ * pci_disable_device - Disable PCI device after use
+ * @dev: PCI device to be disabled
+ *
+ * Signal to the system that the PCI device is not in use by the system
+ * anymore.  This only involves disabling PCI bus-mastering, if active.
+ */
+void
+pci_disable_device(struct pci_dev *dev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_MASTER) {
+		pci_command &= ~PCI_COMMAND_MASTER;
+		pci_write_config_word(dev, PCI_COMMAND, pci_command);
+	}
+}
+
+/**
+ * pci_enable_wake - enable device to generate PME# when suspended
+ * @dev: - PCI device to operate on
+ * @state: - Current state of device.
+ * @enable: - Flag to enable or disable generation
+ * 
+ * Set the bits in the device's PM Capabilities to generate PME# when
+ * the system is suspended. 
+ *
+ * -EIO is returned if device doesn't have PM Capabilities. 
+ * -EINVAL is returned if device supports it, but can't generate wake events.
+ * 0 if operation is successful.
+ * 
+ */
+int pci_enable_wake(struct pci_dev *dev, u32 state, int enable)
+{
+	int pm;
+	u16 value;
+
+	/* find PCI PM capability in list */
+	pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+	/* If device doesn't support PM Capabilities, but request is to disable
+	 * wake events, it's a nop; otherwise fail */
+	if (!pm) 
+		return enable ? -EIO : 0; 
+
+	/* Check device's ability to generate PME# */
+	pci_read_config_word(dev,pm+PCI_PM_PMC,&value);
+
+	value &= PCI_PM_CAP_PME_MASK;
+	value >>= ffs(value);   /* First bit of mask */
+
+	/* Check if it can generate PME# from requested state. */
+	if (!value || !(value & (1 << state))) 
+		return enable ? -EINVAL : 0;
+
+	pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);
+
+	/* Clear PME_Status by writing 1 to it and enable PME# */
+	value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;
+
+	if (!enable)
+		value &= ~PCI_PM_CTRL_PME_ENABLE;
+
+	pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
+	
+	return 0;
+}
+
+int
+pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
+{
+	u8 pin;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	if (!pin)
+		return -1;
+	pin--;
+	while (dev->bus->self) {
+		pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		dev = dev->bus->self;
+	}
+	*bridge = dev;
+	return pin;
+}
+
+/**
+ *	pci_release_region - Release a PCI bar
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_region
+ *	@bar: BAR to release
+ *
+ *	Releases the PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_region.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+void pci_release_region(struct pci_dev *pdev, int bar)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return;
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		release_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		release_mem_region(pci_resource_start(pdev, bar),
+				pci_resource_len(pdev, bar));
+}
+
+/**
+ *	pci_request_region - Reserved PCI I/O and memory resource
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@bar: BAR to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark the PCI region associated with PCI device @pdev BR @bar as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, char *res_name)
+{
+	if (pci_resource_len(pdev, bar) == 0)
+		return 0;
+		
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_IO) {
+		if (!request_region(pci_resource_start(pdev, bar),
+			    pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
+		if (!request_mem_region(pci_resource_start(pdev, bar),
+				        pci_resource_len(pdev, bar), res_name))
+			goto err_out;
+	}
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
+		bar + 1, /* PCI BAR # */
+		pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+		pdev->slot_name);
+	return -EBUSY;
+}
+
+
+/**
+ *	pci_release_regions - Release reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources were previously reserved by pci_request_regions
+ *
+ *	Releases all PCI I/O and memory resources previously reserved by a
+ *	successful call to pci_request_regions.  Call this function only
+ *	after all use of the PCI regions has ceased.
+ */
+
+void pci_release_regions(struct pci_dev *pdev)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++)
+		pci_release_region(pdev, i);
+}
+
+/**
+ *	pci_request_regions - Reserved PCI I/O and memory resources
+ *	@pdev: PCI device whose resources are to be reserved
+ *	@res_name: Name to be associated with resource.
+ *
+ *	Mark all PCI regions associated with PCI device @pdev as
+ *	being reserved by owner @res_name.  Do not access any
+ *	address inside the PCI regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int pci_request_regions(struct pci_dev *pdev, char *res_name)
+{
+	int i;
+	
+	for (i = 0; i < 6; i++)
+		if(pci_request_region(pdev, i, res_name))
+			goto err_out;
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+		pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem",
+		i + 1, /* PCI BAR # */
+		pci_resource_len(pdev, i), pci_resource_start(pdev, i),
+		pdev->slot_name);
+	while(--i >= 0)
+		pci_release_region(pdev, i);
+		
+	return -EBUSY;
+}
+
+
+/*
+ *  Registration of PCI drivers and handling of hot-pluggable devices.
+ */
+
+static LIST_HEAD(pci_drivers);
+
+/**
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * 
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices.Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
+ */
+const struct pci_device_id *
+pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
+{
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+		    (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+		    (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
+		    (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
+		    !((ids->class ^ dev->class) & ids->class_mask))
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+	const struct pci_device_id *id;
+	int ret = 0;
+
+	if (drv->id_table) {
+		id = pci_match_device(drv->id_table, dev);
+		if (!id) {
+			ret = 0;
+			goto out;
+		}
+	} else
+		id = NULL;
+
+	dev_probe_lock();
+	if (drv->probe(dev, id) >= 0) {
+		dev->driver = drv;
+		ret = 1;
+	}
+	dev_probe_unlock();
+out:
+	return ret;
+}
+
+/**
+ * pci_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int
+pci_register_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0;
+
+	list_add_tail(&drv->node, &pci_drivers);
+	pci_for_each_dev(dev) {
+		if (!pci_dev_driver(dev))
+			count += pci_announce_device(drv, dev);
+	}
+	return count;
+}
+
+/**
+ * pci_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PCI drivers,
+ * gives it a chance to clean up by calling its remove() function for
+ * each device it was responsible for, and marks those devices as
+ * driverless.
+ */
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	pci_for_each_dev(dev) {
+		if (dev->driver == drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+}
+
+#ifdef CONFIG_HOTPLUG
+
+#ifndef FALSE
+#define FALSE	(0)
+#define TRUE	(!FALSE)
+#endif
+
+static void
+run_sbin_hotplug(struct pci_dev *pdev, int insert)
+{
+	int i;
+	char *argv[3], *envp[8];
+	char id[20], sub_id[24], bus_id[24], class_id[20];
+
+	if (!hotplug_path[0])
+		return;
+
+	sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+	sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+	sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
+	sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "pci";
+	argv[i] = 0;
+
+	i = 0;
+	/* minimal command environment */
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	
+	/* other stuff we want to pass to /sbin/hotplug */
+	envp[i++] = class_id;
+	envp[i++] = id;
+	envp[i++] = sub_id;
+	envp[i++] = bus_id;
+	if (insert)
+		envp[i++] = "ACTION=add";
+	else
+		envp[i++] = "ACTION=remove";
+	envp[i] = 0;
+
+	call_usermodehelper (argv [0], argv, envp);
+}
+
+/**
+ * pci_announce_device_to_drivers - tell the drivers a new device has appeared
+ * @dev: the device that has shown up
+ *
+ * Notifys the drivers that a new device has appeared, and also notifys
+ * userspace through /sbin/hotplug.
+ */
+void
+pci_announce_device_to_drivers(struct pci_dev *dev)
+{
+	struct list_head *ln;
+
+	for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
+		struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
+		if (drv->remove && pci_announce_device(drv, dev))
+			break;
+	}
+
+	/* notify userspace of new hotplug device */
+	run_sbin_hotplug(dev, TRUE);
+}
+
+/**
+ * pci_insert_device - insert a hotplug device
+ * @dev: the device to insert
+ * @bus: where to insert it
+ *
+ * Add a new device to the device lists and notify userspace (/sbin/hotplug).
+ */
+void
+pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
+{
+	list_add_tail(&dev->bus_list, &bus->devices);
+	list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_device(dev);
+#endif
+	pci_announce_device_to_drivers(dev);
+}
+
+static void
+pci_free_resources(struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *res = dev->resource + i;
+		if (res->parent)
+			release_resource(res);
+	}
+}
+
+/**
+ * pci_remove_device - remove a hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and 
+ * notify userspace (/sbin/hotplug).
+ */
+void
+pci_remove_device(struct pci_dev *dev)
+{
+	if (dev->driver) {
+		if (dev->driver->remove)
+			dev->driver->remove(dev);
+		dev->driver = NULL;
+	}
+	list_del(&dev->bus_list);
+	list_del(&dev->global_list);
+	pci_free_resources(dev);
+#ifdef CONFIG_PROC_FS
+	pci_proc_detach_device(dev);
+#endif
+
+	/* notify userspace of hotplug device removal */
+	run_sbin_hotplug(dev, FALSE);
+}
+
+#endif
+
+static struct pci_driver pci_compat_driver = {
+	name: "compat"
+};
+
+/**
+ * pci_dev_driver - get the pci_driver of a device
+ * @dev: the device to query
+ *
+ * Returns the appropriate pci_driver structure or %NULL if there is no 
+ * registered driver for the device.
+ */
+struct pci_driver *
+pci_dev_driver(const struct pci_dev *dev)
+{
+	if (dev->driver)
+		return dev->driver;
+	else {
+		int i;
+		for(i=0; i<=PCI_ROM_RESOURCE; i++)
+			if (dev->resource[i].flags & IORESOURCE_BUSY)
+				return &pci_compat_driver;
+	}
+	return NULL;
+}
+
+
+/*
+ * This interrupt-safe spinlock protects all accesses to PCI
+ * configuration space.
+ */
+
+static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *  Wrappers for all PCI configuration access functions.  They just check
+ *  alignment, do locking and call the low-level functions pointed to
+ *  by pci_dev->ops.
+ */
+
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_OP(rw,size,type) \
+int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
+{									\
+	int res;							\
+	unsigned long flags;						\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	spin_lock_irqsave(&pci_lock, flags);				\
+	res = dev->bus->ops->rw##_##size(dev, pos, value);		\
+	spin_unlock_irqrestore(&pci_lock, flags);			\
+	return res;							\
+}
+
+PCI_OP(read, byte, u8 *)
+PCI_OP(read, word, u16 *)
+PCI_OP(read, dword, u32 *)
+PCI_OP(write, byte, u8)
+PCI_OP(write, word, u16)
+PCI_OP(write, dword, u32)
+
+/**
+ * pci_set_master - enables bus-mastering for device dev
+ * @dev: the PCI device to enable
+ *
+ * Enables bus-mastering on the device and calls pcibios_set_master()
+ * to do the needed arch specific settings.
+ */
+void
+pci_set_master(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (! (cmd & PCI_COMMAND_MASTER)) {
+		DBG("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
+		cmd |= PCI_COMMAND_MASTER;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	pcibios_set_master(dev);
+}
+
+/**
+ * pdev_set_mwi - arch helper function for pcibios_set_mwi
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Helper function for implementation the arch-specific pcibios_set_mwi
+ * function.  Originally copied from drivers/net/acenic.c.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pdev_set_mwi(struct pci_dev *dev)
+{
+	int rc = 0;
+	u8 cache_size;
+
+	/*
+	 * Looks like this is necessary to deal with on all architectures,
+	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
+	 * Ie. having two NICs in the machine, one will have the cache
+	 * line set at boot time, the other will not.
+	 */
+	pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
+	cache_size <<= 2;
+	if (cache_size != SMP_CACHE_BYTES) {
+		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, ",
+		       dev->slot_name, cache_size);
+		if (cache_size > SMP_CACHE_BYTES) {
+			printk("expecting %i\n", SMP_CACHE_BYTES);
+			rc = -EINVAL;
+		} else {
+			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+					      SMP_CACHE_BYTES >> 2);
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
+ * and then calls @pcibios_set_mwi to do the needed arch specific
+ * operations or a generic mwi-prep function.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pci_set_mwi(struct pci_dev *dev)
+{
+	int rc;
+	u16 cmd;
+
+#ifdef HAVE_ARCH_PCI_MWI
+	rc = pcibios_set_mwi(dev);
+#else
+	rc = pdev_set_mwi(dev);
+#endif
+
+	if (rc)
+		return rc;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (! (cmd & PCI_COMMAND_INVALIDATE)) {
+		DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name);
+		cmd |= PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	
+	return 0;
+}
+
+/**
+ * pci_clear_mwi - disables Memory-Write-Invalidate for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables PCI Memory-Write-Invalidate transaction on the device
+ */
+void
+pci_clear_mwi(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (cmd & PCI_COMMAND_INVALIDATE) {
+		cmd &= ~PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+int
+pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dma_mask = mask;
+
+	return 0;
+}
+    
+int
+pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dac_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->dma_mask = mask;
+
+	return 0;
+}
+    
+/*
+ * Translate the low bits of the PCI base
+ * to the resource type
+ */
+static inline unsigned int pci_calc_resource_flags(unsigned int flags)
+{
+	if (flags & PCI_BASE_ADDRESS_SPACE_IO)
+		return IORESOURCE_IO;
+
+	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
+		return IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+	return IORESOURCE_MEM;
+}
+
+/*
+ * Find the extent of a PCI decode..
+ */
+static u32 pci_size(u32 base, unsigned long mask)
+{
+	u32 size = mask & base;		/* Find the significant bits */
+	size = size & ~(size-1);	/* Get the lowest of them to find the decode size */
+	return size-1;			/* extent = size - 1 */
+}
+
+static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
+{
+	unsigned int pos, reg, next;
+	u32 l, sz;
+	struct resource *res;
+
+	for(pos=0; pos<howmany; pos = next) {
+		next = pos+1;
+		res = &dev->resource[pos];
+		res->name = dev->name;
+		reg = PCI_BASE_ADDRESS_0 + (pos << 2);
+		pci_read_config_dword(dev, reg, &l);
+		pci_write_config_dword(dev, reg, ~0);
+		pci_read_config_dword(dev, reg, &sz);
+		pci_write_config_dword(dev, reg, l);
+		if (!sz || sz == 0xffffffff)
+			continue;
+		if (l == 0xffffffff)
+			l = 0;
+		if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+			res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
+			sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
+		} else {
+			res->start = l & PCI_BASE_ADDRESS_IO_MASK;
+			res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
+			sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
+		}
+		res->end = res->start + (unsigned long) sz;
+		res->flags |= pci_calc_resource_flags(l);
+		if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+		    == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+			pci_read_config_dword(dev, reg+4, &l);
+			next++;
+#if BITS_PER_LONG == 64
+			res->start |= ((unsigned long) l) << 32;
+			res->end = res->start + sz;
+			pci_write_config_dword(dev, reg+4, ~0);
+			pci_read_config_dword(dev, reg+4, &sz);
+			pci_write_config_dword(dev, reg+4, l);
+			if (~sz)
+				res->end = res->start + 0xffffffff +
+						(((unsigned long) ~sz) << 32);
+#else
+			if (l) {
+				printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
+				res->start = 0;
+				res->flags = 0;
+				continue;
+			}
+#endif
+		}
+	}
+	if (rom) {
+		dev->rom_base_reg = rom;
+		res = &dev->resource[PCI_ROM_RESOURCE];
+		pci_read_config_dword(dev, rom, &l);
+		pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
+		pci_read_config_dword(dev, rom, &sz);
+		pci_write_config_dword(dev, rom, l);
+		if (l == 0xffffffff)
+			l = 0;
+		if (sz && sz != 0xffffffff) {
+			res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
+			  IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+			res->start = l & PCI_ROM_ADDRESS_MASK;
+			sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
+			res->end = res->start + (unsigned long) sz;
+		}
+		res->name = dev->name;
+	}
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+	struct pci_dev *dev = child->self;
+	u8 io_base_lo, io_limit_lo;
+	u16 mem_base_lo, mem_limit_lo;
+	unsigned long base, limit;
+	struct resource *res;
+	int i;
+
+	if (!dev)		/* It's a host bus, nothing to read */
+		return;
+
+	if (dev->transparent) {
+		printk("Transparent bridge - %s\n", dev->name);
+		for(i = 0; i < 4; i++)
+			child->resource[i] = child->parent->resource[i];
+		return;
+	}
+
+	for(i=0; i<3; i++)
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+	res = child->resource[0];
+	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
+	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
+	base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
+	limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
+
+	if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+		u16 io_base_hi, io_limit_hi;
+		pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
+		pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
+		base |= (unsigned long)(io_base_hi << 16);
+		limit |= (unsigned long)(io_limit_hi << 16);
+	}
+
+	if ((base || limit) && base <= limit) {
+		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
+		res->start = base;
+		res->end = limit + 0xfff;
+	} else if (base == limit + 0x1000) {
+		/* Firmware/BIOS has deactivated this window */
+		res->start = res->end = 0;
+		res->flags = 0;
+		printk(KERN_ERR "Bridge %s resource %d was deactivated by"
+		       " firmware\n", dev->slot_name, 0);
+	}
+
+	res = child->resource[1];
+	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
+	if (base && base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
+		res->start = base;
+		res->end = limit + 0xfffff;
+	} else if (base == limit + 0x100000) {
+		/* Firmware/BIOS has deactivated this window */
+		res->start = res->end = 0;
+		res->flags = 0;
+		printk(KERN_ERR "Bridge %s resource %d was deactivated by"
+		       " firmware\n", dev->slot_name, 1);
+	}
+
+	res = child->resource[2];
+	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
+	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
+	base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
+	limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
+
+	if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+		u32 mem_base_hi, mem_limit_hi;
+		pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
+		pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+#if BITS_PER_LONG == 64
+		base |= ((long) mem_base_hi) << 32;
+		limit |= ((long) mem_limit_hi) << 32;
+#else
+		if (mem_base_hi || mem_limit_hi) {
+			printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
+			return;
+		}
+#endif
+	}
+	if (base && base <= limit) {
+		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		res->start = base;
+		res->end = limit + 0xfffff;
+	} else if (base == limit + 0x100000) {
+		/* Firmware/BIOS has deactivated this window */
+		res->start = res->end = 0;
+		res->flags = 0;
+		printk(KERN_ERR "Bridge %s resource %d was deactivated by"
+		       " firmware\n", dev->slot_name, 2);
+	}
+}
+
+static struct pci_bus * __devinit pci_alloc_bus(void)
+{
+	struct pci_bus *b;
+
+	b = kmalloc(sizeof(*b), GFP_KERNEL);
+	if (b) {
+		memset(b, 0, sizeof(*b));
+		INIT_LIST_HEAD(&b->children);
+		INIT_LIST_HEAD(&b->devices);
+	}
+	return b;
+}
+
+struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+{
+	struct pci_bus *child;
+	int i;
+
+	/*
+	 * Allocate a new bus, and inherit stuff from the parent..
+	 */
+	child = pci_alloc_bus();
+
+	list_add_tail(&child->node, &parent->children);
+	child->self = dev;
+	dev->subordinate = child;
+	child->parent = parent;
+	child->ops = parent->ops;
+	child->sysdata = parent->sysdata;
+
+	/*
+	 * Set up the primary, secondary and subordinate
+	 * bus numbers.
+	 */
+	child->number = child->secondary = busnr;
+	child->primary = parent->secondary;
+	child->subordinate = 0xff;
+
+	/* Set up default resource pointers and names.. */
+	for (i = 0; i < 4; i++) {
+		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+		child->resource[i]->name = child->name;
+	}
+
+	return child;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus);
+
+/*
+ * If it's a bridge, configure it and scan the bus behind it.
+ * For CardBus bridges, we don't scan behind as the devices will
+ * be handled by the bridge driver itself.
+ *
+ * We need to process bridges in two passes -- first we scan those
+ * already configured by the BIOS and after we are done with all of
+ * them, we proceed to assigning numbers to the remaining buses in
+ * order to avoid overlaps between old and new bus numbers.
+ */
+static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+{
+	unsigned int buses;
+	unsigned short cr;
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+	DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
+	if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
+		/*
+		 * Bus already configured by firmware, process it in the first
+		 * pass and just note the configuration.
+		 */
+		if (pass)
+			return max;
+		child = pci_add_new_bus(bus, dev, 0);
+		child->primary = buses & 0xFF;
+		child->secondary = (buses >> 8) & 0xFF;
+		child->subordinate = (buses >> 16) & 0xFF;
+		child->number = child->secondary;
+		if (!is_cardbus) {
+			unsigned int cmax = pci_do_scan_bus(child);
+			if (cmax > max) max = cmax;
+		} else {
+			unsigned int cmax = child->subordinate;
+			if (cmax > max) max = cmax;
+		}
+	} else {
+		/*
+		 * We need to assign a number to this bus which we always
+		 * do in the second pass. We also keep all address decoders
+		 * on the bridge disabled during scanning.  FIXME: Why?
+		 */
+		if (!pass)
+			return max;
+		pci_read_config_word(dev, PCI_COMMAND, &cr);
+		pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+		pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+		child = pci_add_new_bus(bus, dev, ++max);
+		buses = (buses & 0xff000000)
+		      | ((unsigned int)(child->primary)     <<  0)
+		      | ((unsigned int)(child->secondary)   <<  8)
+		      | ((unsigned int)(child->subordinate) << 16);
+		/*
+		 * We need to blast all three values with a single write.
+		 */
+		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+		if (!is_cardbus) {
+			/* Now we can scan all subordinate buses... */
+			max = pci_do_scan_bus(child);
+		} else {
+			/*
+			 * For CardBus bridges, we leave 4 bus numbers
+			 * as cards with a PCI-to-PCI bridge can be
+			 * inserted later.
+			 */
+			max += 3;
+		}
+		/*
+		 * Set the subordinate bus number to its real value.
+		 */
+		child->subordinate = max;
+		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+		pci_write_config_word(dev, PCI_COMMAND, cr);
+	}
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+	return max;
+}
+
+/*
+ * Read interrupt line and base address registers.
+ * The architecture-dependent code can tweak these, of course.
+ */
+static void pci_read_irq(struct pci_dev *dev)
+{
+	unsigned char irq;
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
+	if (irq)
+		pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+	dev->irq = irq;
+}
+
+/**
+ * pci_setup_device - fill in class and map information of a device
+ * @dev: the device structure to fill
+ *
+ * Initialize the device structure with information about the device's 
+ * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * Called at initialisation of the PCI subsystem and by CardBus services.
+ * Returns 0 on success and -1 if unknown type of device (not normal, bridge
+ * or CardBus).
+ */
+int pci_setup_device(struct pci_dev * dev)
+{
+	u32 class;
+
+	sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+	
+	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+	class >>= 8;				    /* upper 3 bytes */
+	dev->class = class;
+	class >>= 8;
+
+	DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
+
+	/* "Unknown power state" */
+	dev->current_state = 4;
+
+	switch (dev->hdr_type) {		    /* header type */
+	case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
+		if (class == PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	case PCI_HEADER_TYPE_BRIDGE:		    /* bridge header */
+		if (class != PCI_CLASS_BRIDGE_PCI)
+			goto bad;
+		/* The PCI-to-PCI bridge spec requires that subtractive
+		   decoding (i.e. transparent) bridge must have programming
+		   interface code of 0x01. */ 
+		dev->transparent = ((class & 0xff) == 1);
+		pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
+		break;
+
+	case PCI_HEADER_TYPE_CARDBUS:		    /* CardBus bridge header */
+		if (class != PCI_CLASS_BRIDGE_CARDBUS)
+			goto bad;
+		pci_read_irq(dev);
+		pci_read_bases(dev, 1, 0);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
+		pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
+		break;
+
+	default:				    /* unknown header */
+		printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
+			dev->slot_name, dev->hdr_type);
+		return -1;
+
+	bad:
+		printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
+		       dev->slot_name, class, dev->hdr_type);
+		dev->class = PCI_CLASS_NOT_DEFINED;
+	}
+
+	/* We found a fine healthy device, go go go... */
+	return 0;
+}
+
+/*
+ * Read the config data for a PCI device, sanity-check it
+ * and fill in the dev structure...
+ */
+struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
+{
+	struct pci_dev *dev;
+	u32 l;
+
+	if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
+		return NULL;
+
+	/* some broken boards return 0 or ~0 if a slot is empty: */
+	if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
+		return NULL;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	memcpy(dev, temp, sizeof(*dev));
+	dev->vendor = l & 0xffff;
+	dev->device = (l >> 16) & 0xffff;
+
+#ifdef CONFIG_OPENBLOCKS266	/* koko: Ugly! */
+	if (dev->vendor == 0x1100 && dev->device == 0x0007) {
+		printk("pci_scan_device: vendor change(0x%04x)\n", dev->vendor);
+		dev->vendor = 0x1103;
+	}
+#endif
+
+	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
+	   set this higher, assuming the system even supports it.  */
+	dev->dma_mask = 0xffffffff;
+	if (pci_setup_device(dev) < 0) {
+		kfree(dev);
+		dev = NULL;
+	}
+	return dev;
+}
+
+struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	struct pci_dev *first_dev = NULL;
+	int func = 0;
+	int is_multi = 0;
+	u8 hdr_type;
+
+	for (func = 0; func < 8; func++, temp->devfn++) {
+		if (func && !is_multi)		/* not a multi-function device */
+			continue;
+		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		temp->hdr_type = hdr_type & 0x7f;
+
+		dev = pci_scan_device(temp);
+		if (!dev)
+			continue;
+		pci_name_device(dev);
+		if (!func) {
+			is_multi = hdr_type & 0x80;
+			first_dev = dev;
+		}
+
+		/*
+		 * Link the device to both the global PCI device chain and
+		 * the per-bus list of devices.
+		 */
+		list_add_tail(&dev->global_list, &pci_devices);
+		list_add_tail(&dev->bus_list, &bus->devices);
+
+		/* Fix up broken headers */
+		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+	}
+	return first_dev;
+}
+
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+	unsigned int devfn, max, pass;
+	struct list_head *ln;
+	struct pci_dev *dev, dev0;
+
+	DBG("Scanning bus %02x\n", bus->number);
+	max = bus->secondary;
+
+	/* Create a device template */
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = bus;
+	dev0.sysdata = bus->sysdata;
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev0.devfn = devfn;
+		pci_scan_slot(&dev0);
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	DBG("Fixups for bus %02x\n", bus->number);
+	pcibios_fixup_bus(bus);
+	for (pass=0; pass < 2; pass++)
+		for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+			dev = pci_dev_b(ln);
+			if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+				max = pci_scan_bridge(bus, dev, max, pass);
+		}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	return max;
+}
+
+int __devinit pci_bus_exists(const struct list_head *list, int nr)
+{
+	const struct list_head *l;
+
+	for(l=list->next; l != list; l = l->next) {
+		const struct pci_bus *b = pci_bus_b(l);
+		if (b->number == nr || pci_bus_exists(&b->children, nr))
+			return 1;
+	}
+	return 0;
+}
+
+struct pci_bus * __devinit pci_alloc_primary_bus(int bus)
+{
+	struct pci_bus *b;
+
+	if (pci_bus_exists(&pci_root_buses, bus)) {
+		/* If we already got to this bus through a different bridge, ignore it */
+		DBG("PCI: Bus %02x already known\n", bus);
+		return NULL;
+	}
+
+	b = pci_alloc_bus();
+	list_add_tail(&b->node, &pci_root_buses);
+
+	b->number = b->secondary = bus;
+	b->resource[0] = &ioport_resource;
+	b->resource[1] = &iomem_resource;
+	return b;
+}
+
+struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
+{
+	struct pci_bus *b = pci_alloc_primary_bus(bus);
+	if (b) {
+		b->sysdata = sysdata;
+		b->ops = ops;
+		b->subordinate = pci_do_scan_bus(b);
+	}
+	return b;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * PCI Power management..
+ *
+ * This needs to be done centralized, so that we power manage PCI
+ * devices in the right order: we should not shut down PCI bridges
+ * before we've shut down the devices behind them, and we should
+ * not wake up devices before we've woken up the bridge to the
+ * device.. Eh?
+ *
+ * We do not touch devices that don't have a driver that exports
+ * a suspend/resume function. That is just too dangerous. If the default
+ * PCI suspend/resume functions work for a device, the driver can
+ * easily implement them (ie just have a suspend function that calls
+ * the pci_set_power_state() function).
+ */
+
+static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->save_state) 
+			error = driver->save_state(dev,state);
+	}
+	return error;
+}
+
+static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->suspend)
+			error = driver->suspend(dev,state);
+	}
+	return error;
+}
+
+static int pci_pm_resume_device(struct pci_dev *dev)
+{
+	int error = 0;
+	if (dev) {
+		struct pci_driver *driver = dev->driver;
+		if (driver && driver->resume)
+			error = driver->resume(dev);
+	}
+	return error;
+}
+
+static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
+{
+	struct list_head *list;
+	int error = 0;
+
+	list_for_each(list, &bus->children) {
+		error = pci_pm_save_state_bus(pci_bus_b(list),state);
+		if (error) return error;
+	}
+	list_for_each(list, &bus->devices) {
+		error = pci_pm_save_state_device(pci_dev_b(list),state);
+		if (error) return error;
+	}
+	return 0;
+}
+
+static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
+{
+	struct list_head *list;
+
+	/* Walk the bus children list */
+	list_for_each(list, &bus->children) 
+		pci_pm_suspend_bus(pci_bus_b(list),state);
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_suspend_device(pci_dev_b(list),state);
+	return 0;
+}
+
+static int pci_pm_resume_bus(struct pci_bus *bus)
+{
+	struct list_head *list;
+
+	/* Walk the device children list */
+	list_for_each(list, &bus->devices)
+		pci_pm_resume_device(pci_dev_b(list));
+
+	/* And then walk the bus children */
+	list_for_each(list, &bus->children)
+		pci_pm_resume_bus(pci_bus_b(list));
+	return 0;
+}
+
+static int pci_pm_save_state(u32 state)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+	int error = 0;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		error = pci_pm_save_state_bus(bus,state);
+		if (!error)
+			error = pci_pm_save_state_device(bus->self,state);
+	}
+	return error;
+}
+
+static int pci_pm_suspend(u32 state)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_suspend_bus(bus,state);
+		pci_pm_suspend_device(bus->self,state);
+	}
+	return 0;
+}
+
+int pci_pm_resume(void)
+{
+	struct list_head *list;
+	struct pci_bus *bus;
+
+	list_for_each(list, &pci_root_buses) {
+		bus = pci_bus_b(list);
+		pci_pm_resume_device(bus->self);
+		pci_pm_resume_bus(bus);
+	}
+	return 0;
+}
+
+static int 
+pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
+{
+	int error = 0;
+
+	switch (rqst) {
+	case PM_SAVE_STATE:
+		error = pci_pm_save_state((unsigned long)data);
+		break;
+	case PM_SUSPEND:
+		error = pci_pm_suspend((unsigned long)data);
+		break;
+	case PM_RESUME:
+		error = pci_pm_resume();
+		break;
+	default: break;
+	}
+	return error;
+}
+
+#endif
+
+/*
+ * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
+ * small blocks are easily used by drivers for bus mastering controllers.
+ * This should probably be sharing the guts of the slab allocator.
+ */
+
+struct pci_pool {	/* the pool */
+	struct list_head	page_list;
+	spinlock_t		lock;
+	size_t			blocks_per_page;
+	size_t			size;
+	int			flags;
+	struct pci_dev		*dev;
+	size_t			allocation;
+	char			name [32];
+	wait_queue_head_t	waitq;
+};
+
+struct pci_page {	/* cacheable header for 'allocation' bytes */
+	struct list_head	page_list;
+	void			*vaddr;
+	dma_addr_t		dma;
+	unsigned long		bitmap [0];
+};
+
+#define	POOL_TIMEOUT_JIFFIES	((100 /* msec */ * HZ) / 1000)
+#define	POOL_POISON_BYTE	0xa7
+
+// #define CONFIG_PCIPOOL_DEBUG
+
+
+/**
+ * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
+ * @name: name of pool, for diagnostics
+ * @pdev: pci device that will be doing the DMA
+ * @size: size of the blocks in this pool.
+ * @align: alignment requirement for blocks; must be a power of two
+ * @allocation: returned blocks won't cross this boundary (or zero)
+ * @flags: SLAB_* flags (not all are supported).
+ *
+ * Returns a pci allocation pool with the requested characteristics, or
+ * null if one can't be created.  Given one of these pools, pci_pool_alloc()
+ * may be used to allocate memory.  Such memory will all have "consistent"
+ * DMA mappings, accessible by the device and its driver without using
+ * cache flushing primitives.  The actual size of blocks allocated may be
+ * larger than requested because of alignment.
+ *
+ * If allocation is nonzero, objects returned from pci_pool_alloc() won't
+ * cross that size boundary.  This is useful for devices which have
+ * addressing restrictions on individual DMA transfers, such as not crossing
+ * boundaries of 4KBytes.
+ */
+struct pci_pool *
+pci_pool_create (const char *name, struct pci_dev *pdev,
+	size_t size, size_t align, size_t allocation, int flags)
+{
+	struct pci_pool		*retval;
+
+	if (align == 0)
+		align = 1;
+	if (size == 0)
+		return 0;
+	else if (size < align)
+		size = align;
+	else if ((size % align) != 0) {
+		size += align + 1;
+		size &= ~(align - 1);
+	}
+
+	if (allocation == 0) {
+		if (PAGE_SIZE < size)
+			allocation = size;
+		else
+			allocation = PAGE_SIZE;
+		// FIXME: round up for less fragmentation
+	} else if (allocation < size)
+		return 0;
+
+	if (!(retval = kmalloc (sizeof *retval, flags)))
+		return retval;
+
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	flags |= SLAB_POISON;
+#endif
+
+	strncpy (retval->name, name, sizeof retval->name);
+	retval->name [sizeof retval->name - 1] = 0;
+
+	retval->dev = pdev;
+	INIT_LIST_HEAD (&retval->page_list);
+	spin_lock_init (&retval->lock);
+	retval->size = size;
+	retval->flags = flags;
+	retval->allocation = allocation;
+	retval->blocks_per_page = allocation / size;
+	init_waitqueue_head (&retval->waitq);
+
+#ifdef CONFIG_PCIPOOL_DEBUG
+	printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n",
+		pdev ? pdev->slot_name : NULL, retval->name, size,
+		retval->blocks_per_page, allocation);
+#endif
+
+	return retval;
+}
+
+
+static struct pci_page *
+pool_alloc_page (struct pci_pool *pool, int mem_flags)
+{
+	struct pci_page	*page;
+	int		mapsize;
+
+	mapsize = pool->blocks_per_page;
+	mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
+	mapsize *= sizeof (long);
+
+	page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
+	if (!page)
+		return 0;
+	page->vaddr = pci_alloc_consistent (pool->dev,
+					    pool->allocation,
+					    &page->dma);
+	if (page->vaddr) {
+		memset (page->bitmap, 0xff, mapsize);	// bit set == free
+		if (pool->flags & SLAB_POISON)
+			memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+		list_add (&page->page_list, &pool->page_list);
+	} else {
+		kfree (page);
+		page = 0;
+	}
+	return page;
+}
+
+
+static inline int
+is_page_busy (int blocks, unsigned long *bitmap)
+{
+	while (blocks > 0) {
+		if (*bitmap++ != ~0UL)
+			return 1;
+		blocks -= BITS_PER_LONG;
+	}
+	return 0;
+}
+
+static void
+pool_free_page (struct pci_pool *pool, struct pci_page *page)
+{
+	dma_addr_t	dma = page->dma;
+
+	if (pool->flags & SLAB_POISON)
+		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+	pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
+	list_del (&page->page_list);
+	kfree (page);
+}
+
+
+/**
+ * pci_pool_destroy - destroys a pool of pci memory blocks.
+ * @pool: pci pool that will be destroyed
+ *
+ * Caller guarantees that no more memory from the pool is in use,
+ * and that nothing will try to use the pool after this call.
+ */
+void
+pci_pool_destroy (struct pci_pool *pool)
+{
+	unsigned long		flags;
+
+#ifdef CONFIG_PCIPOOL_DEBUG
+	printk (KERN_DEBUG "pcipool destroy %s/%s\n",
+		pool->dev ? pool->dev->slot_name : NULL,
+		pool->name);
+#endif
+
+	spin_lock_irqsave (&pool->lock, flags);
+	while (!list_empty (&pool->page_list)) {
+		struct pci_page		*page;
+		page = list_entry (pool->page_list.next,
+				struct pci_page, page_list);
+		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
+			printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
+				pool->dev ? pool->dev->slot_name : NULL,
+				pool->name, page->vaddr);
+			/* leak the still-in-use consistent memory */
+			list_del (&page->page_list);
+			kfree (page);
+		} else
+			pool_free_page (pool, page);
+	}
+	spin_unlock_irqrestore (&pool->lock, flags);
+	kfree (pool);
+}
+
+
+/**
+ * pci_pool_alloc - get a block of consistent memory
+ * @pool: pci pool that will produce the block
+ * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
+ * @handle: pointer to dma address of block
+ *
+ * This returns the kernel virtual address of a currently unused block,
+ * and reports its dma address through the handle.
+ * If such a memory block can't be allocated, null is returned.
+ */
+void *
+pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+	int			map, block;
+	size_t			offset;
+	void			*retval;
+
+restart:
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		int		i;
+		page = list_entry (entry, struct pci_page, page_list);
+		/* only cachable accesses here ... */
+		for (map = 0, i = 0;
+				i < pool->blocks_per_page;
+				i += BITS_PER_LONG, map++) {
+			if (page->bitmap [map] == 0)
+				continue;
+			block = ffz (~ page->bitmap [map]);
+			if ((i + block) < pool->blocks_per_page) {
+				clear_bit (block, &page->bitmap [map]);
+				offset = (BITS_PER_LONG * map) + block;
+				offset *= pool->size;
+				goto ready;
+			}
+		}
+	}
+	if (!(page = pool_alloc_page (pool, mem_flags))) {
+		if (mem_flags == SLAB_KERNEL) {
+			DECLARE_WAITQUEUE (wait, current);
+
+			current->state = TASK_INTERRUPTIBLE;
+			add_wait_queue (&pool->waitq, &wait);
+			spin_unlock_irqrestore (&pool->lock, flags);
+
+			schedule_timeout (POOL_TIMEOUT_JIFFIES);
+
+			current->state = TASK_RUNNING;
+			remove_wait_queue (&pool->waitq, &wait);
+			goto restart;
+		}
+		retval = 0;
+		goto done;
+	}
+
+	clear_bit (0, &page->bitmap [0]);
+	offset = 0;
+ready:
+	retval = offset + page->vaddr;
+	*handle = offset + page->dma;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return retval;
+}
+
+
+static struct pci_page *
+pool_find_page (struct pci_pool *pool, dma_addr_t dma)
+{
+	unsigned long		flags;
+	struct list_head	*entry;
+	struct pci_page		*page;
+
+	spin_lock_irqsave (&pool->lock, flags);
+	list_for_each (entry, &pool->page_list) {
+		page = list_entry (entry, struct pci_page, page_list);
+		if (dma < page->dma)
+			continue;
+		if (dma < (page->dma + pool->allocation))
+			goto done;
+	}
+	page = 0;
+done:
+	spin_unlock_irqrestore (&pool->lock, flags);
+	return page;
+}
+
+
+/**
+ * pci_pool_free - put block back into pci pool
+ * @pool: the pci pool holding the block
+ * @vaddr: virtual address of block
+ * @dma: dma address of block
+ *
+ * Caller promises neither device nor driver will again touch this block
+ * unless it is first re-allocated.
+ */
+void
+pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
+{
+	struct pci_page		*page;
+	unsigned long		flags;
+	int			map, block;
+
+	if ((page = pool_find_page (pool, dma)) == 0) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, (int) (dma & 0xffffffff));
+		return;
+	}
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, (int) (dma & 0xffffffff));
+		return;
+	}
+#endif
+
+	block = dma - page->dma;
+	block /= pool->size;
+	map = block / BITS_PER_LONG;
+	block %= BITS_PER_LONG;
+
+#ifdef	CONFIG_PCIPOOL_DEBUG
+	if (page->bitmap [map] & (1UL << block)) {
+		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, dma);
+		return;
+	}
+#endif
+	if (pool->flags & SLAB_POISON)
+		memset (vaddr, POOL_POISON_BYTE, pool->size);
+
+	spin_lock_irqsave (&pool->lock, flags);
+	set_bit (block, &page->bitmap [map]);
+	if (waitqueue_active (&pool->waitq))
+		wake_up (&pool->waitq);
+	/*
+	 * Resist a temptation to do
+	 *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
+	 * it is not interrupt safe. Better have empty pages hang around.
+	 */
+	spin_unlock_irqrestore (&pool->lock, flags);
+}
+
+
+void __devinit  pci_init(void)
+{
+	struct pci_dev *dev;
+
+	pcibios_init();
+
+	pci_for_each_dev(dev) {
+		pci_fixup_device(PCI_FIXUP_FINAL, dev);
+	}
+
+#ifdef CONFIG_PM
+	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
+#endif
+}
+
+static int __devinit pci_setup(char *str)
+{
+	while (str) {
+		char *k = strchr(str, ',');
+		if (k)
+			*k++ = 0;
+		if (*str && (str = pcibios_setup(str)) && *str) {
+			/* PCI layer options should be handled here */
+			printk(KERN_ERR "PCI: Unknown option `%s'\n", str);
+		}
+		str = k;
+	}
+	return 1;
+}
+
+__setup("pci=", pci_setup);
+
+EXPORT_SYMBOL(pci_read_config_byte);
+EXPORT_SYMBOL(pci_read_config_word);
+EXPORT_SYMBOL(pci_read_config_dword);
+EXPORT_SYMBOL(pci_write_config_byte);
+EXPORT_SYMBOL(pci_write_config_word);
+EXPORT_SYMBOL(pci_write_config_dword);
+EXPORT_SYMBOL(pci_devices);
+EXPORT_SYMBOL(pci_root_buses);
+EXPORT_SYMBOL(pci_enable_device_bars);
+EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pci_disable_device);
+EXPORT_SYMBOL(pci_find_capability);
+EXPORT_SYMBOL(pci_release_regions);
+EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_release_region);
+EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_find_class);
+EXPORT_SYMBOL(pci_find_device);
+EXPORT_SYMBOL(pci_find_slot);
+EXPORT_SYMBOL(pci_find_subsys);
+EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_set_mwi);
+EXPORT_SYMBOL(pci_clear_mwi);
+EXPORT_SYMBOL(pdev_set_mwi);
+EXPORT_SYMBOL(pci_set_dma_mask);
+EXPORT_SYMBOL(pci_dac_set_dma_mask);
+EXPORT_SYMBOL(pci_assign_resource);
+EXPORT_SYMBOL(pci_register_driver);
+EXPORT_SYMBOL(pci_unregister_driver);
+EXPORT_SYMBOL(pci_dev_driver);
+EXPORT_SYMBOL(pci_match_device);
+EXPORT_SYMBOL(pci_find_parent_resource);
+
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_setup_device);
+EXPORT_SYMBOL(pci_insert_device);
+EXPORT_SYMBOL(pci_remove_device);
+EXPORT_SYMBOL(pci_announce_device_to_drivers);
+EXPORT_SYMBOL(pci_add_new_bus);
+EXPORT_SYMBOL(pci_do_scan_bus);
+EXPORT_SYMBOL(pci_scan_slot);
+EXPORT_SYMBOL(pci_scan_bus);
+#ifdef CONFIG_PROC_FS
+EXPORT_SYMBOL(pci_proc_attach_device);
+EXPORT_SYMBOL(pci_proc_detach_device);
+EXPORT_SYMBOL(pci_proc_attach_bus);
+EXPORT_SYMBOL(pci_proc_detach_bus);
+EXPORT_SYMBOL(proc_bus_pci_dir);
+#endif
+#endif
+
+EXPORT_SYMBOL(pci_set_power_state);
+EXPORT_SYMBOL(pci_save_state);
+EXPORT_SYMBOL(pci_restore_state);
+EXPORT_SYMBOL(pci_enable_wake);
+
+/* Obsolete functions */
+
+EXPORT_SYMBOL(pcibios_present);
+EXPORT_SYMBOL(pcibios_read_config_byte);
+EXPORT_SYMBOL(pcibios_read_config_word);
+EXPORT_SYMBOL(pcibios_read_config_dword);
+EXPORT_SYMBOL(pcibios_write_config_byte);
+EXPORT_SYMBOL(pcibios_write_config_word);
+EXPORT_SYMBOL(pcibios_write_config_dword);
+EXPORT_SYMBOL(pcibios_find_class);
+EXPORT_SYMBOL(pcibios_find_device);
+
+/* Quirk info */
+
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
+EXPORT_SYMBOL(pci_pci_problems);
+
+/* Pool allocator */
+
+EXPORT_SYMBOL (pci_pool_create);
+EXPORT_SYMBOL (pci_pool_destroy);
+EXPORT_SYMBOL (pci_pool_alloc);
+EXPORT_SYMBOL (pci_pool_free);
+
diff -Naru linux-2.4.20.orig/include/asm-ppc/ibm4xx.h linux-2.4.20/include/asm-ppc/ibm4xx.h
--- linux-2.4.20.orig/include/asm-ppc/ibm4xx.h	2002-12-11 02:38:55.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/ibm4xx.h	2003-04-01 15:14:18.000000000 +0000
@@ -105,6 +105,14 @@
 #include <platforms/walnut.h>
 #endif
 
+#if defined(CONFIG_EBK405GPR)
+#include <platforms/ebk405gpr.h>
+#endif
+
+#if defined(CONFIG_OPENBLOCKS266)
+#include <platforms/openblocks266.h>
+#endif
+
 #if defined(CONFIG_BEECH)
 #include <platforms/beech.h>
 #endif
diff -Naru linux-2.4.20.orig/include/asm-ppc/pgtable.h linux-2.4.20/include/asm-ppc/pgtable.h
--- linux-2.4.20.orig/include/asm-ppc/pgtable.h	2002-12-11 02:37:04.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pgtable.h	2003-04-01 15:17:15.000000000 +0000
@@ -1,5 +1,9 @@
 /*
  * BK Id: %F% %I% %G% %U% %#%
+ *
+ *     PlatHome <openlab.plathome.co.jp>
+ *             by yhirano@mbc.nifty.com
+ *
  */
 #ifdef __KERNEL__
 #ifndef _PPC_PGTABLE_H
@@ -686,11 +690,19 @@
  * must not include the _PAGE_PRESENT bit, or the _PAGE_HASHPTE bit
  * (if used).  -- paulus
  */
-#define SWP_TYPE(entry)			((entry).val & 0x3f)
-#define SWP_OFFSET(entry)		((entry).val >> 6)
-#define SWP_ENTRY(type, offset)		((swp_entry_t) { (type) | ((offset) << 6) })
-#define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) >> 2 })
-#define swp_entry_to_pte(x)		((pte_t) { (x).val << 2 })
+#ifdef CONFIG_OPENBLOCKS266
+#define SWP_TYPE(entry)                 ((entry).val & 0x3f)
+#define SWP_OFFSET(entry)               ((entry).val >> 10)
+#define SWP_ENTRY(type, offset)         ((swp_entry_t) { (type) | ((offset) << 10) })
+#define pte_to_swp_entry(pte)           ((swp_entry_t) { pte_val(pte) >> 2 })
+#define swp_entry_to_pte(x)             ((pte_t) { (x).val << 2 })
+#else
+#define SWP_TYPE(entry)                 ((entry).val & 0x3f)
+#define SWP_OFFSET(entry)               ((entry).val >> 6)
+#define SWP_ENTRY(type, offset)         ((swp_entry_t) { (type) | ((offset) << 6) })
+#define pte_to_swp_entry(pte)           ((swp_entry_t) { pte_val(pte) >> 2 })
+#define swp_entry_to_pte(x)             ((pte_t) { (x).val << 2 })
+#endif
 
 /* CONFIG_APUS */
 /* For virtual address to physical address conversion */
diff -Naru linux-2.4.20.orig/include/asm-ppc/pushsw.h linux-2.4.20/include/asm-ppc/pushsw.h
--- linux-2.4.20.orig/include/asm-ppc/pushsw.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.4.20/include/asm-ppc/pushsw.h	2003-04-01 15:14:18.000000000 +0000
@@ -0,0 +1,19 @@
+/* 
+ *	Century <www.centurysys.co.jp>
+ *		- Century's push switch driver header
+ */
+
+#include <linux/ioctl.h>
+#include <linux/major.h>
+/* #include <linux/miscdevice.h> */
+
+#define PUSHSW_MAJOR		(MISC_MAJOR)
+
+#define	PUSHSW_IOCTL_BASE	'P'
+
+#define	PSWIOC_GETSTATUS	_IOR(PUSHSW_IOCTL_BASE, 0, int)
+#define	PSWIOC_WAITPUSH		_IOR(PUSHSW_IOCTL_BASE, 1, int)
+#define	PSWIOC_GETWAITPID	_IOR(PUSHSW_IOCTL_BASE, 2, int)
+
+#define PSWIOF_PUSHED		(1)
+#define PSWIOF_NOTPUSHED	(0)
diff -Naru linux-2.4.20.orig/init/do_mounts.c linux-2.4.20/init/do_mounts.c
--- linux-2.4.20.orig/init/do_mounts.c	2002-12-11 02:40:07.000000000 +0000
+++ linux-2.4.20/init/do_mounts.c	2003-04-01 15:14:18.000000000 +0000
@@ -549,8 +549,7 @@
 
 #ifdef CONFIG_BLK_DEV_RAM
 	int in_fd, out_fd;
-	unsigned long rd_blocks, devblocks;
-	int nblocks, i;
+	int nblocks, rd_blocks, devblocks, i;
 	char *buf;
 	unsigned short rotate = 0;
 #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES)
@@ -779,6 +778,26 @@
 	return execve(shell, argv, envp_init);
 }
 
+#ifdef CONFIG_OPENBLOCKS266
+static int do_restore(void *shell)
+{
+	static char *argv[] = { "flashcfg", NULL, };
+	extern char *envp_init[];
+
+	close(old_fd);
+	close(root_fd);
+	close(0);
+	close(1);
+	close(2);
+	setsid();
+	(void) open("/dev/console",O_RDWR,0);
+	(void) dup(0);
+	(void) dup(0);
+	execve(shell, argv, envp_init);
+	printk("[do_restore] Error starting restore thread!\n");
+	return (-1);
+}
+#endif
 #endif
 
 static void __init handle_initrd(void)
@@ -857,6 +876,12 @@
  */
 void prepare_namespace(void)
 {
+#if defined(CONFIG_BLK_DEV_INITRD) && defined(CONFIG_OPENBLOCKS266)
+	bd_t *bip = (bd_t *)__res;
+/*		2003/03/13 Plat'C2 Todoroki modify start */
+	int real_root_mountflags;
+/*		2003/03/13 Plat'C2 Todoroki modify end */
+#endif
 	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
 #ifdef CONFIG_ALL_PPC
 	extern void arch_discover_root(void);
@@ -883,12 +908,48 @@
 		}
 	} else if (is_floppy && rd_doload && rd_load_disk(0))
 		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+/*		2003/03/13 Plat'C2 Todoroki modify start */
+#if defined(CONFIG_BLK_DEV_INITRD) && defined(CONFIG_OPENBLOCKS266)
+	/* write able root mount if load user configuration from flash necessary. */
+	if (bip->bi_r_version[0] && mount_initrd) {
+		real_root_mountflags = root_mountflags;
+		root_mountflags &= ~MS_RDONLY;
+	}
+#endif
+/*		2003/03/13 Plat'C2 Todoroki modify end */
 	mount_root();
 out:
 	sys_umount("/dev", 0);
 	sys_mount(".", "/", NULL, MS_MOVE, NULL);
 	sys_chroot(".");
 	mount_devfs_fs ();
+
+#if defined(CONFIG_BLK_DEV_INITRD) && defined(CONFIG_OPENBLOCKS266)
+	/* 
+	 *	If initrd has been mounted, load user configuration
+	 *	from flash if necessary.
+	 */
+	if (bip->bi_s_version[0])
+	{
+/*		2003/03/13 Plat'C2 Todoroki modify start */
+		root_mountflags = real_root_mountflags;
+/*		2003/03/13 Plat'C2 Todoroki modify end */
+		printk("[prepare_namespace] Executing flashcfg...\n");
+		if (mount_initrd && (MAJOR(ROOT_DEV) == RAMDISK_MAJOR) &&
+			(MINOR(ROOT_DEV) == 0)) 
+		{
+			int	i, pid;
+
+			pid = kernel_thread(do_restore, "/usr/sbin/flashcfg", SIGCHLD);
+			if (pid > 0) 
+			{
+				while (pid != wait(&i));
+			}
+			else printk("[prepare_namespace] Error starting restore thread!\n");
+		}	/* if initrd RAM disk has been loaded */
+		printk("[prepare_namespace] Finished executing flashcfg\n");
+	}
+#endif
 }
 
 #if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
diff -Naru linux-2.4.20.orig/init/main.c linux-2.4.20/init/main.c
--- linux-2.4.20.orig/init/main.c	2002-12-11 02:37:59.000000000 +0000
+++ linux-2.4.20/init/main.c	2003-04-01 15:14:18.000000000 +0000
@@ -107,6 +107,10 @@
 extern void ipc_init(void);
 #endif
 
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+extern int obsled_out(int);
+#endif
+
 /*
  * Boot command-line arguments
  */
@@ -354,6 +358,9 @@
  * enable them
  */
 	lock_kernel();
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	obsled_out(2);
+#endif
 	printk(linux_banner);
 	setup_arch(&command_line);
 	printk("Kernel command line: %s\n", saved_command_line);
@@ -543,9 +550,15 @@
 static int init(void * unused)
 {
 	lock_kernel();
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	obsled_out(3);
+#endif
 	do_basic_setup();
 
 	prepare_namespace();
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	obsled_out(5);
+#endif
 
 	/*
 	 * Ok, we have completed the initial bootup, and
@@ -568,6 +581,9 @@
 	 * trying to recover a really broken machine.
 	 */
 
+#if defined(CONFIG_OPENBLOCKS266) && defined(CONFIG_OBS_LED)
+	obsled_out(6);
+#endif
 	if (execute_command)
 		execve(execute_command,argv_init,envp_init);
 	execve("/sbin/init",argv_init,envp_init);