Sync'd u-boot-net with mainline

Merge git://www.denx.de/git/u-boot

Conflicts:

	drivers/bcm570x.c
	drivers/tigon3.c
diff --git a/drivers/Makefile b/drivers/Makefile
index d68cba6..fc98040 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -27,11 +27,11 @@
 
 LIB	= $(obj)libdrivers.a
 
-COBJS	= 3c589.o 5701rls.o ali512x.o atmel_usart.o \
+COBJS	= 3c589.o 5701rls.o ali512x.o ata_piix.o atmel_usart.o \
 	  bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \
 	  cs8900.o ct69000.o dataflash.o dc2114x.o dm9000x.o \
-	  e1000.o eepro100.o \
-	  i8042.o inca-ip_sw.o keyboard.o \
+	  e1000.o eepro100.o enc28j60.o \
+	  i8042.o inca-ip_sw.o isp116x-hcd.o keyboard.o \
 	  lan91c96.o macb.o \
 	  natsemi.o ne2000.o netarm_eth.o netconsole.o \
 	  ns16550.o ns8382x.o ns87308.o ns7520_eth.o omap1510_i2c.o \
@@ -47,12 +47,14 @@
 	  status_led.o sym53c8xx.o systemace.o ahci.o \
 	  ti_pci1410a.o tigon3.o tsec.o \
 	  tsi108_eth.o tsi108_i2c.o tsi108_pci.o \
-	  usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \
+	  usb_ohci.o \
+	  usbdcore.o usbdcore_ep0.o usbdcore_mpc8xx.o usbdcore_omap1510.o \
+	  usbtty.o \
 	  videomodes.o w83c553f.o \
 	  ks8695eth.o \
 	  pxa_pcmcia.o mpc8xx_pcmcia.o tqm8xx_pcmcia.o	\
 	  rpx_pcmcia.o \
-	  fsl_i2c.o
+	  fsl_i2c.o fsl_pci_init.o ati_radeon_fb.o
 
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
diff --git a/drivers/ahci.c b/drivers/ahci.c
index 8ceff00..ccd4d71 100644
--- a/drivers/ahci.c
+++ b/drivers/ahci.c
@@ -253,7 +253,8 @@
 
 static int ahci_init_one(pci_dev_t pdev)
 {
-	u32 iobase, vendor;
+	u32 iobase;
+	u16 vendor;
 	int rc;
 
 	memset((void *)ataid, 0, sizeof(hd_driveid_t *) * AHCI_MAX_PORTS);
diff --git a/drivers/ata_piix.c b/drivers/ata_piix.c
new file mode 100644
index 0000000..42456d7
--- /dev/null
+++ b/drivers/ata_piix.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) Procsys. All rights reserved.
+ * Author: Mushtaq Khan <mushtaq_k@procsys.com>
+ *			<mushtaqk_921@yahoo.co.in>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * with the reference to ata_piix driver in kernel 2.4.32
+ */
+
+/*
+ * This file contains SATA controller and SATA drive initialization functions
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <command.h>
+#include <config.h>
+#include <asm/byteorder.h>
+#include <ide.h>
+#include <ata.h>
+
+#ifdef CFG_ATA_PIIX		/*ata_piix driver */
+
+#define DEBUG_SATA 0		/*For debug prints set DEBUG_SATA to 1 */
+
+#define DRV_DECL		/*For file specific declarations */
+#include <sata.h>
+#undef DRV_DECL
+
+/*Macros realted to PCI*/
+#define PCI_SATA_BUS	0x00
+#define PCI_SATA_DEV	0x1f
+#define PCI_SATA_FUNC	0x02
+
+#define PCI_SATA_BASE1 0x10
+#define PCI_SATA_BASE2 0x14
+#define PCI_SATA_BASE3 0x18
+#define PCI_SATA_BASE4 0x1c
+#define PCI_SATA_BASE5 0x20
+#define PCI_PMR         0x90
+#define PCI_PI          0x09
+#define PCI_PCS         0x92
+#define PCI_DMA_CTL     0x48
+
+#define PORT_PRESENT (1<<0)
+#define PORT_ENABLED (1<<4)
+
+u32 bdf;
+u32 iobase1 = 0;		/*Primary cmd block */
+u32 iobase2 = 0;		/*Primary ctl block */
+u32 iobase3 = 0;		/*Sec cmd block */
+u32 iobase4 = 0;		/*sec ctl block */
+u32 iobase5 = 0;		/*BMDMA*/
+int
+pci_sata_init (void)
+{
+	u32 bus = PCI_SATA_BUS;
+	u32 dev = PCI_SATA_DEV;
+	u32 fun = PCI_SATA_FUNC;
+	u16 cmd = 0;
+	u8 lat = 0, pcibios_max_latency = 0xff;
+	u8 pmr;			/*Port mapping reg */
+	u8 pi;			/*Prgming Interface reg */
+
+	bdf = PCI_BDF (bus, dev, fun);
+	pci_read_config_dword (bdf, PCI_SATA_BASE1, &iobase1);
+	pci_read_config_dword (bdf, PCI_SATA_BASE2, &iobase2);
+	pci_read_config_dword (bdf, PCI_SATA_BASE3, &iobase3);
+	pci_read_config_dword (bdf, PCI_SATA_BASE4, &iobase4);
+	pci_read_config_dword (bdf, PCI_SATA_BASE5, &iobase5);
+
+	if ((iobase1 == 0xFFFFFFFF) || (iobase2 == 0xFFFFFFFF) ||
+	    (iobase3 == 0xFFFFFFFF) || (iobase4 == 0xFFFFFFFF) ||
+	    (iobase5 == 0xFFFFFFFF)) {
+		printf ("error no base addr for SATA controller\n");
+		return 1;
+	 /*ERROR*/}
+
+	iobase1 &= 0xFFFFFFFE;
+	iobase2 &= 0xFFFFFFFE;
+	iobase3 &= 0xFFFFFFFE;
+	iobase4 &= 0xFFFFFFFE;
+	iobase5 &= 0xFFFFFFFE;
+
+	/*check for mode */
+	pci_read_config_byte (bdf, PCI_PMR, &pmr);
+	if (pmr > 1) {
+		printf ("combined mode not supported\n");
+		return 1;
+	}
+
+	pci_read_config_byte (bdf, PCI_PI, &pi);
+	if ((pi & 0x05) != 0x05) {
+		printf ("Sata is in Legacy mode\n");
+		return 1;
+	} else {
+		printf ("sata is in Native mode\n");
+	}
+
+	/*MASTER CFG AND IO CFG */
+	pci_read_config_word (bdf, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+	pci_write_config_word (bdf, PCI_COMMAND, cmd);
+	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &lat);
+
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	pci_write_config_byte (dev, PCI_LATENCY_TIMER, lat);
+
+	return 0;
+}
+
+int
+sata_bus_probe (int port_no)
+{
+	int orig_mask, mask;
+	u16 pcs;
+
+	mask = (PORT_PRESENT << port_no);
+	pci_read_config_word (bdf, PCI_PCS, &pcs);
+	orig_mask = (int) pcs & 0xff;
+	if ((orig_mask & mask) != mask)
+		return 0;
+	else
+		return 1;
+}
+
+int
+init_sata (void)
+{
+	u8 i, rv = 0;
+
+	for (i = 0; i < CFG_SATA_MAXDEVICES; i++) {
+		sata_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+		sata_dev_desc[i].if_type = IF_TYPE_IDE;
+		sata_dev_desc[i].dev = i;
+		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+		sata_dev_desc[i].blksz = 0;
+		sata_dev_desc[i].lba = 0;
+		sata_dev_desc[i].block_read = sata_read;
+	}
+
+	rv = pci_sata_init ();
+	if (rv == 1) {
+		printf ("pci initialization failed\n");
+		return 1;
+	}
+
+	port[0].port_no = 0;
+	port[0].ioaddr.cmd_addr = iobase1;
+	port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr =
+	    iobase2 | ATA_PCI_CTL_OFS;
+	port[0].ioaddr.bmdma_addr = iobase5;
+
+	port[1].port_no = 1;
+	port[1].ioaddr.cmd_addr = iobase3;
+	port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr =
+	    iobase4 | ATA_PCI_CTL_OFS;
+	port[1].ioaddr.bmdma_addr = iobase5 + 0x8;
+
+	for (i = 0; i < CFG_SATA_MAXBUS; i++)
+		sata_port (&port[i].ioaddr);
+
+	for (i = 0; i < CFG_SATA_MAXBUS; i++) {
+		if (!(sata_bus_probe (i))) {
+			port[i].port_state = 0;
+			printf ("SATA#%d port is not present \n", i);
+		} else {
+			printf ("SATA#%d port is present\n", i);
+			if (sata_bus_softreset (i)) {
+				port[i].port_state = 0;
+			} else {
+				port[i].port_state = 1;
+			}
+		}
+	}
+
+	for (i = 0; i < CFG_SATA_MAXBUS; i++) {
+		u8 j, devno;
+
+		if (port[i].port_state == 0)
+			continue;
+		for (j = 0; j < CFG_SATA_DEVS_PER_BUS; j++) {
+			sata_identify (i, j);
+			set_Feature_cmd (i, j);
+			devno = i * CFG_SATA_DEVS_PER_BUS + j;
+			if ((sata_dev_desc[devno].lba > 0) &&
+			    (sata_dev_desc[devno].blksz > 0)) {
+				dev_print (&sata_dev_desc[devno]);
+				/* initialize partition type */
+				init_part (&sata_dev_desc[devno]);
+				if (curr_dev < 0)
+					curr_dev =
+					    i * CFG_SATA_DEVS_PER_BUS + j;
+			}
+		}
+	}
+	return 0;
+}
+#endif
diff --git a/drivers/ati_ids.h b/drivers/ati_ids.h
new file mode 100644
index 0000000..3e72a7d
--- /dev/null
+++ b/drivers/ati_ids.h
@@ -0,0 +1,211 @@
+/*
+ * ATI PCI IDs from XFree86, kept here to make sync'ing with
+ * XFree much simpler. Currently, this list is only used by
+ * radeonfb
+ */
+
+#define PCI_CHIP_RV380_3150             0x3150
+#define PCI_CHIP_RV380_3151             0x3151
+#define PCI_CHIP_RV380_3152             0x3152
+#define PCI_CHIP_RV380_3153             0x3153
+#define PCI_CHIP_RV380_3154             0x3154
+#define PCI_CHIP_RV380_3156             0x3156
+#define PCI_CHIP_RV380_3E50             0x3E50
+#define PCI_CHIP_RV380_3E51             0x3E51
+#define PCI_CHIP_RV380_3E52             0x3E52
+#define PCI_CHIP_RV380_3E53             0x3E53
+#define PCI_CHIP_RV380_3E54             0x3E54
+#define PCI_CHIP_RV380_3E56             0x3E56
+#define PCI_CHIP_RS100_4136		0x4136
+#define PCI_CHIP_RS200_4137		0x4137
+#define PCI_CHIP_R300_AD		0x4144
+#define PCI_CHIP_R300_AE		0x4145
+#define PCI_CHIP_R300_AF		0x4146
+#define PCI_CHIP_R300_AG		0x4147
+#define PCI_CHIP_R350_AH                0x4148
+#define PCI_CHIP_R350_AI                0x4149
+#define PCI_CHIP_R350_AJ                0x414A
+#define PCI_CHIP_R350_AK                0x414B
+#define PCI_CHIP_RV350_AP               0x4150
+#define PCI_CHIP_RV350_AQ               0x4151
+#define PCI_CHIP_RV360_AR               0x4152
+#define PCI_CHIP_RV350_AS               0x4153
+#define PCI_CHIP_RV350_AT               0x4154
+#define PCI_CHIP_RV350_AV               0x4156
+#define PCI_CHIP_MACH32		0x4158
+#define PCI_CHIP_RS250_4237		0x4237
+#define PCI_CHIP_R200_BB		0x4242
+#define PCI_CHIP_R200_BC		0x4243
+#define PCI_CHIP_RS100_4336		0x4336
+#define PCI_CHIP_RS200_4337		0x4337
+#define PCI_CHIP_MACH64CT		0x4354
+#define PCI_CHIP_MACH64CX		0x4358
+#define PCI_CHIP_RS250_4437		0x4437
+#define PCI_CHIP_MACH64ET		0x4554
+#define PCI_CHIP_MACH64GB		0x4742
+#define PCI_CHIP_MACH64GD		0x4744
+#define PCI_CHIP_MACH64GI		0x4749
+#define PCI_CHIP_MACH64GL		0x474C
+#define PCI_CHIP_MACH64GM		0x474D
+#define PCI_CHIP_MACH64GN		0x474E
+#define PCI_CHIP_MACH64GO		0x474F
+#define PCI_CHIP_MACH64GP		0x4750
+#define PCI_CHIP_MACH64GQ		0x4751
+#define PCI_CHIP_MACH64GR		0x4752
+#define PCI_CHIP_MACH64GS		0x4753
+#define PCI_CHIP_MACH64GT		0x4754
+#define PCI_CHIP_MACH64GU		0x4755
+#define PCI_CHIP_MACH64GV		0x4756
+#define PCI_CHIP_MACH64GW		0x4757
+#define PCI_CHIP_MACH64GX		0x4758
+#define PCI_CHIP_MACH64GY		0x4759
+#define PCI_CHIP_MACH64GZ		0x475A
+#define PCI_CHIP_RV250_Id		0x4964
+#define PCI_CHIP_RV250_Ie		0x4965
+#define PCI_CHIP_RV250_If		0x4966
+#define PCI_CHIP_RV250_Ig		0x4967
+#define PCI_CHIP_R420_JH                0x4A48
+#define PCI_CHIP_R420_JI                0x4A49
+#define PCI_CHIP_R420_JJ                0x4A4A
+#define PCI_CHIP_R420_JK                0x4A4B
+#define PCI_CHIP_R420_JL                0x4A4C
+#define PCI_CHIP_R420_JM                0x4A4D
+#define PCI_CHIP_R420_JN                0x4A4E
+#define PCI_CHIP_R420_JP                0x4A50
+#define PCI_CHIP_MACH64LB		0x4C42
+#define PCI_CHIP_MACH64LD		0x4C44
+#define PCI_CHIP_RAGE128LE		0x4C45
+#define PCI_CHIP_RAGE128LF		0x4C46
+#define PCI_CHIP_MACH64LG		0x4C47
+#define PCI_CHIP_MACH64LI		0x4C49
+#define PCI_CHIP_MACH64LM		0x4C4D
+#define PCI_CHIP_MACH64LN		0x4C4E
+#define PCI_CHIP_MACH64LP		0x4C50
+#define PCI_CHIP_MACH64LQ		0x4C51
+#define PCI_CHIP_MACH64LR		0x4C52
+#define PCI_CHIP_MACH64LS		0x4C53
+#define PCI_CHIP_MACH64LT		0x4C54
+#define PCI_CHIP_RADEON_LW		0x4C57
+#define PCI_CHIP_RADEON_LX		0x4C58
+#define PCI_CHIP_RADEON_LY		0x4C59
+#define PCI_CHIP_RADEON_LZ		0x4C5A
+#define PCI_CHIP_RV250_Ld		0x4C64
+#define PCI_CHIP_RV250_Le		0x4C65
+#define PCI_CHIP_RV250_Lf		0x4C66
+#define PCI_CHIP_RV250_Lg		0x4C67
+#define PCI_CHIP_RV250_Ln		0x4C6E
+#define PCI_CHIP_RAGE128MF		0x4D46
+#define PCI_CHIP_RAGE128ML		0x4D4C
+#define PCI_CHIP_R300_ND		0x4E44
+#define PCI_CHIP_R300_NE		0x4E45
+#define PCI_CHIP_R300_NF		0x4E46
+#define PCI_CHIP_R300_NG		0x4E47
+#define PCI_CHIP_R350_NH                0x4E48
+#define PCI_CHIP_R350_NI                0x4E49
+#define PCI_CHIP_R360_NJ                0x4E4A
+#define PCI_CHIP_R350_NK                0x4E4B
+#define PCI_CHIP_RV350_NP               0x4E50
+#define PCI_CHIP_RV350_NQ               0x4E51
+#define PCI_CHIP_RV350_NR               0x4E52
+#define PCI_CHIP_RV350_NS               0x4E53
+#define PCI_CHIP_RV350_NT               0x4E54
+#define PCI_CHIP_RV350_NV               0x4E56
+#define PCI_CHIP_RAGE128PA		0x5041
+#define PCI_CHIP_RAGE128PB		0x5042
+#define PCI_CHIP_RAGE128PC		0x5043
+#define PCI_CHIP_RAGE128PD		0x5044
+#define PCI_CHIP_RAGE128PE		0x5045
+#define PCI_CHIP_RAGE128PF		0x5046
+#define PCI_CHIP_RAGE128PG		0x5047
+#define PCI_CHIP_RAGE128PH		0x5048
+#define PCI_CHIP_RAGE128PI		0x5049
+#define PCI_CHIP_RAGE128PJ		0x504A
+#define PCI_CHIP_RAGE128PK		0x504B
+#define PCI_CHIP_RAGE128PL		0x504C
+#define PCI_CHIP_RAGE128PM		0x504D
+#define PCI_CHIP_RAGE128PN		0x504E
+#define PCI_CHIP_RAGE128PO		0x504F
+#define PCI_CHIP_RAGE128PP		0x5050
+#define PCI_CHIP_RAGE128PQ		0x5051
+#define PCI_CHIP_RAGE128PR		0x5052
+#define PCI_CHIP_RAGE128PS		0x5053
+#define PCI_CHIP_RAGE128PT		0x5054
+#define PCI_CHIP_RAGE128PU		0x5055
+#define PCI_CHIP_RAGE128PV		0x5056
+#define PCI_CHIP_RAGE128PW		0x5057
+#define PCI_CHIP_RAGE128PX		0x5058
+#define PCI_CHIP_RADEON_QD		0x5144
+#define PCI_CHIP_RADEON_QE		0x5145
+#define PCI_CHIP_RADEON_QF		0x5146
+#define PCI_CHIP_RADEON_QG		0x5147
+#define PCI_CHIP_R200_QH		0x5148
+#define PCI_CHIP_R200_QI		0x5149
+#define PCI_CHIP_R200_QJ		0x514A
+#define PCI_CHIP_R200_QK		0x514B
+#define PCI_CHIP_R200_QL		0x514C
+#define PCI_CHIP_R200_QM		0x514D
+#define PCI_CHIP_R200_QN		0x514E
+#define PCI_CHIP_R200_QO		0x514F
+#define PCI_CHIP_RV200_QW		0x5157
+#define PCI_CHIP_RV200_QX		0x5158
+#define PCI_CHIP_RV100_QY		0x5159
+#define PCI_CHIP_RV100_QZ		0x515A
+#define PCI_CHIP_RN50			0x515E
+#define PCI_CHIP_RAGE128RE		0x5245
+#define PCI_CHIP_RAGE128RF		0x5246
+#define PCI_CHIP_RAGE128RG		0x5247
+#define PCI_CHIP_RAGE128RK		0x524B
+#define PCI_CHIP_RAGE128RL		0x524C
+#define PCI_CHIP_RAGE128SE		0x5345
+#define PCI_CHIP_RAGE128SF		0x5346
+#define PCI_CHIP_RAGE128SG		0x5347
+#define PCI_CHIP_RAGE128SH		0x5348
+#define PCI_CHIP_RAGE128SK		0x534B
+#define PCI_CHIP_RAGE128SL		0x534C
+#define PCI_CHIP_RAGE128SM		0x534D
+#define PCI_CHIP_RAGE128SN		0x534E
+#define PCI_CHIP_RAGE128TF		0x5446
+#define PCI_CHIP_RAGE128TL		0x544C
+#define PCI_CHIP_RAGE128TR		0x5452
+#define PCI_CHIP_RAGE128TS		0x5453
+#define PCI_CHIP_RAGE128TT		0x5454
+#define PCI_CHIP_RAGE128TU		0x5455
+#define PCI_CHIP_RV370_5460             0x5460
+#define PCI_CHIP_RV370_5461             0x5461
+#define PCI_CHIP_RV370_5462             0x5462
+#define PCI_CHIP_RV370_5463             0x5463
+#define PCI_CHIP_RV370_5464             0x5464
+#define PCI_CHIP_RV370_5465             0x5465
+#define PCI_CHIP_RV370_5466             0x5466
+#define PCI_CHIP_RV370_5467             0x5467
+#define PCI_CHIP_R423_UH                0x5548
+#define PCI_CHIP_R423_UI                0x5549
+#define PCI_CHIP_R423_UJ                0x554A
+#define PCI_CHIP_R423_UK                0x554B
+#define PCI_CHIP_R423_UQ                0x5551
+#define PCI_CHIP_R423_UR                0x5552
+#define PCI_CHIP_R423_UT                0x5554
+#define PCI_CHIP_MACH64VT		0x5654
+#define PCI_CHIP_MACH64VU		0x5655
+#define PCI_CHIP_MACH64VV		0x5656
+#define PCI_CHIP_RS300_5834		0x5834
+#define PCI_CHIP_RS300_5835		0x5835
+#define PCI_CHIP_RS300_5836		0x5836
+#define PCI_CHIP_RS300_5837		0x5837
+#define PCI_CHIP_RV370_5B60             0x5B60
+#define PCI_CHIP_RV370_5B61             0x5B61
+#define PCI_CHIP_RV370_5B62             0x5B62
+#define PCI_CHIP_RV370_5B63             0x5B63
+#define PCI_CHIP_RV370_5B64             0x5B64
+#define PCI_CHIP_RV370_5B65             0x5B65
+#define PCI_CHIP_RV370_5B66             0x5B66
+#define PCI_CHIP_RV370_5B67             0x5B67
+#define PCI_CHIP_RV280_5960		0x5960
+#define PCI_CHIP_RV280_5961		0x5961
+#define PCI_CHIP_RV280_5962		0x5962
+#define PCI_CHIP_RV280_5964		0x5964
+#define PCI_CHIP_RV280_5C61		0x5C61
+#define PCI_CHIP_RV280_5C63		0x5C63
+#define PCI_CHIP_R423_5D57              0x5D57
+#define PCI_CHIP_RS350_7834             0x7834
+#define PCI_CHIP_RS350_7835             0x7835
diff --git a/drivers/ati_radeon_fb.c b/drivers/ati_radeon_fb.c
new file mode 100644
index 0000000..c174f37
--- /dev/null
+++ b/drivers/ati_radeon_fb.c
@@ -0,0 +1,486 @@
+/*
+ * ATI Radeon Video card Framebuffer driver.
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ * Zhang Wei <wei.zhang@freescale.com>
+ * Jason Jin <jason.jin@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Some codes of this file is partly ported from Linux kernel
+ * ATI video framebuffer driver.
+ *
+ * Now the driver is tested on below ATI chips:
+ *   9200
+ *   X300
+ *   X700
+ *
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_ATI_RADEON_FB
+
+#include <command.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <video_fb.h>
+
+#include <radeon.h>
+#include "ati_ids.h"
+#include "ati_radeon_fb.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DPRINT(x...) printf(x)
+#else
+#define DPRINT(x...) do{}while(0)
+#endif
+
+#ifndef min_t
+#define min_t(type,x,y) \
+	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#endif
+
+#define MAX_MAPPED_VRAM	(2048*2048*4)
+#define MIN_MAPPED_VRAM	(1024*768*1)
+
+/*#define PCI_VENDOR_ID_ATI*/
+#define PCI_CHIP_RV280_5960		0x5960
+#define PCI_CHIP_RV280_5961		0x5961
+#define PCI_CHIP_RV280_5962		0x5962
+#define PCI_CHIP_RV280_5964		0x5964
+#define PCI_CHIP_RV370_5B60		0x5B60
+#define PCI_CHIP_RV380_5657		0x5657
+#define PCI_CHIP_R420_554d		0x554d
+
+static struct pci_device_id ati_radeon_pci_ids[] = {
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5960},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5961},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5962},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5964},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV370_5B60},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_RV380_5657},
+	{PCI_VENDOR_ID_ATI, PCI_CHIP_R420_554d},
+	{0, 0}
+};
+
+static u16 ati_radeon_id_family_table[][2] = {
+	{PCI_CHIP_RV280_5960, CHIP_FAMILY_RV280},
+	{PCI_CHIP_RV280_5961, CHIP_FAMILY_RV280},
+	{PCI_CHIP_RV280_5962, CHIP_FAMILY_RV280},
+	{PCI_CHIP_RV280_5964, CHIP_FAMILY_RV280},
+	{PCI_CHIP_RV370_5B60, CHIP_FAMILY_RV380},
+	{PCI_CHIP_RV380_5657, CHIP_FAMILY_RV380},
+	{PCI_CHIP_R420_554d,  CHIP_FAMILY_R420},
+	{0, 0}
+};
+
+u16 get_radeon_id_family(u16 device)
+{
+	int i;
+	for (i=0; ati_radeon_id_family_table[0][i]; i+=2)
+		if (ati_radeon_id_family_table[0][i] == device)
+			return ati_radeon_id_family_table[0][i + 1];
+	return 0;
+}
+
+struct radeonfb_info *rinfo;
+
+static void radeon_identify_vram(struct radeonfb_info *rinfo)
+{
+	u32 tmp;
+
+	/* framebuffer size */
+	if ((rinfo->family == CHIP_FAMILY_RS100) ||
+		(rinfo->family == CHIP_FAMILY_RS200) ||
+		(rinfo->family == CHIP_FAMILY_RS300)) {
+		u32 tom = INREG(NB_TOM);
+		tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
+
+		radeon_fifo_wait(6);
+		OUTREG(MC_FB_LOCATION, tom);
+		OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+		OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+		OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+		/* This is supposed to fix the crtc2 noise problem. */
+		OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+		if ((rinfo->family == CHIP_FAMILY_RS100) ||
+			(rinfo->family == CHIP_FAMILY_RS200)) {
+		/* This is to workaround the asic bug for RMX, some versions
+		   of BIOS dosen't have this register initialized correctly.
+		*/
+			OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
+				~CRTC_H_CUTOFF_ACTIVE_EN);
+		}
+	} else {
+		tmp = INREG(CONFIG_MEMSIZE);
+	}
+
+	/* mem size is bits [28:0], mask off the rest */
+	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
+
+	/*
+	 * Hack to get around some busted production M6's
+	 * reporting no ram
+	 */
+	if (rinfo->video_ram == 0) {
+		switch (rinfo->pdev.device) {
+		case PCI_CHIP_RADEON_LY:
+		case PCI_CHIP_RADEON_LZ:
+			rinfo->video_ram = 8192 * 1024;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * Now try to identify VRAM type
+	 */
+	if ((rinfo->family >= CHIP_FAMILY_R300) ||
+	    (INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
+		rinfo->vram_ddr = 1;
+	else
+		rinfo->vram_ddr = 0;
+
+	tmp = INREG(MEM_CNTL);
+	if (IS_R300_VARIANT(rinfo)) {
+		tmp &=  R300_MEM_NUM_CHANNELS_MASK;
+		switch (tmp) {
+		case 0:  rinfo->vram_width = 64; break;
+		case 1:  rinfo->vram_width = 128; break;
+		case 2:  rinfo->vram_width = 256; break;
+		default: rinfo->vram_width = 128; break;
+		}
+	} else if ((rinfo->family == CHIP_FAMILY_RV100) ||
+		   (rinfo->family == CHIP_FAMILY_RS100) ||
+		   (rinfo->family == CHIP_FAMILY_RS200)){
+		if (tmp & RV100_MEM_HALF_MODE)
+			rinfo->vram_width = 32;
+		else
+			rinfo->vram_width = 64;
+	} else {
+		if (tmp & MEM_NUM_CHANNELS_MASK)
+			rinfo->vram_width = 128;
+		else
+			rinfo->vram_width = 64;
+	}
+
+	/* This may not be correct, as some cards can have half of channel disabled
+	 * ToDo: identify these cases
+	 */
+
+	DPRINT("radeonfb: Found %ldk of %s %d bits wide videoram\n",
+	       rinfo->video_ram / 1024,
+	       rinfo->vram_ddr ? "DDR" : "SDRAM",
+	       rinfo->vram_width);
+
+}
+
+static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
+{
+	int i;
+
+	radeon_fifo_wait(20);
+
+#if 0
+	/* Workaround from XFree */
+	if (rinfo->is_mobility) {
+		/* A temporal workaround for the occational blanking on certain laptop
+		 * panels. This appears to related to the PLL divider registers
+		 * (fail to lock?). It occurs even when all dividers are the same
+		 * with their old settings. In this case we really don't need to
+		 * fiddle with PLL registers. By doing this we can avoid the blanking
+		 * problem with some panels.
+		 */
+		if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
+		    (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
+					  (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
+			/* We still have to force a switch to selected PPLL div thanks to
+			 * an XFree86 driver bug which will switch it away in some cases
+			 * even when using UseFDev */
+			OUTREGP(CLOCK_CNTL_INDEX,
+				mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+				~PPLL_DIV_SEL_MASK);
+			radeon_pll_errata_after_index(rinfo);
+			radeon_pll_errata_after_data(rinfo);
+			return;
+		}
+	}
+#endif
+	if(rinfo->pdev.device == PCI_CHIP_RV370_5B60) return;
+
+	/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
+	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
+
+	/* Reset PPLL & enable atomic update */
+	OUTPLLP(PPLL_CNTL,
+		PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
+		~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
+
+	/* Switch to selected PPLL divider */
+	OUTREGP(CLOCK_CNTL_INDEX,
+		mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
+		~PPLL_DIV_SEL_MASK);
+
+	/* Set PPLL ref. div */
+	if (rinfo->family == CHIP_FAMILY_R300 ||
+	    rinfo->family == CHIP_FAMILY_RS300 ||
+	    rinfo->family == CHIP_FAMILY_R350 ||
+	    rinfo->family == CHIP_FAMILY_RV350) {
+		if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
+			/* When restoring console mode, use saved PPLL_REF_DIV
+			 * setting.
+			 */
+			OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
+		} else {
+			/* R300 uses ref_div_acc field as real ref divider */
+			OUTPLLP(PPLL_REF_DIV,
+				(mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
+				~R300_PPLL_REF_DIV_ACC_MASK);
+		}
+	} else
+		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
+
+	/* Set PPLL divider 3 & post divider*/
+	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
+	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
+
+	/* Write update */
+	while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
+		;
+	OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
+
+	/* Wait read update complete */
+	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of
+	   the cause yet, but this workaround will mask the problem for now.
+	   Other chips usually will pass at the very first test, so the
+	   workaround shouldn't have any effect on them. */
+	for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
+		;
+
+	OUTPLL(HTOTAL_CNTL, 0);
+
+	/* Clear reset & atomic update */
+	OUTPLLP(PPLL_CNTL, 0,
+		~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
+
+	/* We may want some locking ... oh well */
+	udelay(5000);
+
+	/* Switch back VCLK source to PPLL */
+	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
+}
+
+typedef struct {
+	u16 reg;
+	u32 val;
+} reg_val;
+
+
+/* these common regs are cleared before mode setting so they do not
+ * interfere with anything
+ */
+static reg_val common_regs[] = {
+	{ OVR_CLR, 0 },
+	{ OVR_WID_LEFT_RIGHT, 0 },
+	{ OVR_WID_TOP_BOTTOM, 0 },
+	{ OV0_SCALE_CNTL, 0 },
+	{ SUBPIC_CNTL, 0 },
+	{ VIPH_CONTROL, 0 },
+	{ I2C_CNTL_1, 0 },
+	{ GEN_INT_CNTL, 0 },
+	{ CAP0_TRIG_CNTL, 0 },
+	{ CAP1_TRIG_CNTL, 0 },
+};
+
+
+void radeon_setmode(void)
+{
+	int i;
+	struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
+
+	mode->crtc_gen_cntl = 0x03000200;
+	mode->crtc_ext_cntl = 0x00008048;
+	mode->dac_cntl = 0xff002100;
+	mode->crtc_h_total_disp = 0x4f0063;
+	mode->crtc_h_sync_strt_wid = 0x8c02a2;
+	mode->crtc_v_total_disp = 0x01df020c;
+	mode->crtc_v_sync_strt_wid = 0x8201ea;
+	mode->crtc_pitch = 0x00500050;
+
+	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
+	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
+		~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
+	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
+	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
+	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
+	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
+	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
+	OUTREG(CRTC_OFFSET, 0);
+	OUTREG(CRTC_OFFSET_CNTL, 0);
+	OUTREG(CRTC_PITCH, mode->crtc_pitch);
+
+	mode->clk_cntl_index = 0x300;
+	mode->ppll_ref_div = 0xc;
+	mode->ppll_div_3 = 0x00030059;
+
+	radeon_write_pll_regs(rinfo, mode);
+}
+
+int radeon_probe(struct radeonfb_info *rinfo)
+{
+	pci_dev_t pdev;
+	u16 did;
+
+	pdev = pci_find_devices(ati_radeon_pci_ids, 0);
+
+	if (pdev != -1) {
+		pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
+		printf("ATI Radeon video card (%04x, %04x) found @(%d:%d:%d)\n",
+				PCI_VENDOR_ID_ATI, did, (pdev >> 16) & 0xff,
+				(pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
+
+		strcpy(rinfo->name, "ATI Radeon");
+		rinfo->pdev.vendor = PCI_VENDOR_ID_ATI;
+		rinfo->pdev.device = did;
+		rinfo->family = get_radeon_id_family(rinfo->pdev.device);
+		pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
+				&rinfo->fb_base_phys);
+		pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
+				&rinfo->mmio_base_phys);
+		rinfo->fb_base_phys &= 0xfffff000;
+		rinfo->mmio_base_phys &= ~0x04;
+
+		rinfo->mmio_base = (void *)rinfo->mmio_base_phys;
+		DPRINT("rinfo->mmio_base = 0x%x\n",rinfo->mmio_base);
+		rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
+		DPRINT("rinfo->fb_local_base = 0x%x\n",rinfo->fb_local_base);
+		/* PostBIOS with x86 emulater */
+		BootVideoCardBIOS(pdev, NULL, 0);
+
+		/*
+		 * Check for errata
+		 * (These will be added in the future for the chipfamily
+		 * R300, RV200, RS200, RV100, RS100.)
+		 */
+
+		/* Get VRAM size and type */
+		radeon_identify_vram(rinfo);
+
+		rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM,
+				rinfo->video_ram);
+		rinfo->fb_base = (void *)rinfo->fb_base_phys;
+
+		DPRINT("Radeon: framebuffer base phy address 0x%08x," \
+		      "MMIO base phy address 0x%08x," \
+		      "framebuffer local base 0x%08x.\n ",
+		      rinfo->fb_base_phys, rinfo->mmio_base_phys,
+		      rinfo->fb_local_base);
+
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * The Graphic Device
+ */
+GraphicDevice ctfb;
+
+#define CURSOR_SIZE	0x1000	/* in KByte for HW Cursor */
+#define PATTERN_ADR	(pGD->dprBase + CURSOR_SIZE)	/* pattern Memory after Cursor Memory */
+#define PATTERN_SIZE	8*8*4	/* 4 Bytes per Pixel 8 x 8 Pixel */
+#define ACCELMEMORY	(CURSOR_SIZE + PATTERN_SIZE)	/* reserved Memory for BITBlt and hw cursor */
+
+void *video_hw_init(void)
+{
+	GraphicDevice *pGD = (GraphicDevice *) & ctfb;
+	int i;
+	u32 *vm;
+
+	rinfo = malloc(sizeof(struct radeonfb_info));
+
+	if(radeon_probe(rinfo)) {
+		printf("No radeon video card found!\n");
+		return NULL;
+	}
+
+	/* fill in Graphic device struct */
+	sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", 640,
+		 480, 16, (1000 / 1000),
+		 (2000 / 1000));
+	printf ("%s\n", pGD->modeIdent);
+
+	pGD->winSizeX = 640;
+	pGD->winSizeY = 480;
+	pGD->plnSizeX = 640;
+	pGD->plnSizeY = 480;
+
+	pGD->gdfBytesPP = 1;
+	pGD->gdfIndex = GDF__8BIT_INDEX;
+
+	pGD->isaBase = CFG_ISA_IO_BASE_ADDRESS;
+	pGD->pciBase = rinfo->fb_base_phys;
+	pGD->frameAdrs = rinfo->fb_base_phys;
+	pGD->memSize = 64 * 1024 * 1024;
+
+	/* Cursor Start Address */
+	pGD->dprBase =
+	    (pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP) + rinfo->fb_base_phys;
+	if ((pGD->dprBase & 0x0fff) != 0) {
+		/* allign it */
+		pGD->dprBase &= 0xfffff000;
+		pGD->dprBase += 0x00001000;
+	}
+	DPRINT ("Cursor Start %x Pattern Start %x\n", pGD->dprBase,
+		PATTERN_ADR);
+	pGD->vprBase = rinfo->fb_base_phys;	/* Dummy */
+	pGD->cprBase = rinfo->fb_base_phys;	/* Dummy */
+	/* set up Hardware */
+
+	/* Clear video memory */
+	i = pGD->memSize / 4;
+	vm = (unsigned int *) pGD->pciBase;
+	while (i--)
+		*vm++ = 0;
+	/*SetDrawingEngine (bits_per_pixel);*/
+
+	radeon_setmode();
+
+	return ((void *) pGD);
+}
+
+void video_set_lut (unsigned int index,	/* color number */
+	       unsigned char r,	/* red */
+	       unsigned char g,	/* green */
+	       unsigned char b	/* blue */
+	       )
+{
+	OUTREG(PALETTE_INDEX, index);
+	OUTREG(PALETTE_DATA, (r << 16) | (g << 8) | b);
+}
+#endif
diff --git a/drivers/ati_radeon_fb.h b/drivers/ati_radeon_fb.h
new file mode 100644
index 0000000..b5c4b8b
--- /dev/null
+++ b/drivers/ati_radeon_fb.h
@@ -0,0 +1,282 @@
+#ifndef __ATI_RADEON_FB_H
+#define __ATI_RADEON_FB_H
+
+/***************************************************************
+ * Most of the definitions here are adapted right from XFree86 *
+ ***************************************************************/
+
+/*
+ * Chip families. Must fit in the low 16 bits of a long word
+ */
+enum radeon_family {
+	CHIP_FAMILY_UNKNOW,
+	CHIP_FAMILY_LEGACY,
+	CHIP_FAMILY_RADEON,
+	CHIP_FAMILY_RV100,
+	CHIP_FAMILY_RS100,    /* U1 (IGP320M) or A3 (IGP320)*/
+	CHIP_FAMILY_RV200,
+	CHIP_FAMILY_RS200,    /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350),
+				 RS250 (IGP 7000) */
+	CHIP_FAMILY_R200,
+	CHIP_FAMILY_RV250,
+	CHIP_FAMILY_RS300,    /* Radeon 9000 IGP */
+	CHIP_FAMILY_RV280,
+	CHIP_FAMILY_R300,
+	CHIP_FAMILY_R350,
+	CHIP_FAMILY_RV350,
+	CHIP_FAMILY_RV380,    /* RV370/RV380/M22/M24 */
+	CHIP_FAMILY_R420,     /* R420/R423/M18 */
+	CHIP_FAMILY_LAST,
+};
+
+#define IS_RV100_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_RV100)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV200)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS100)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS200)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV250)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RV280)  || \
+				 ((rinfo)->family == CHIP_FAMILY_RS300))
+
+#define IS_R300_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_R300)  || \
+				((rinfo)->family == CHIP_FAMILY_RV350) || \
+				((rinfo)->family == CHIP_FAMILY_R350)  || \
+				((rinfo)->family == CHIP_FAMILY_RV380) || \
+				((rinfo)->family == CHIP_FAMILY_R420))
+
+struct radeonfb_info {
+	char name[20];
+
+	struct pci_device_id	pdev;
+	u16 			family;
+
+	u32 			fb_base_phys;
+	u32 			mmio_base_phys;
+
+	void 			*mmio_base;
+	void 			*fb_base;
+
+	u32			video_ram;
+	u32			mapped_vram;
+	int			vram_width;
+	int			vram_ddr;
+
+	u32 			fb_local_base;
+};
+
+#define INREG8(addr)		readb((rinfo->mmio_base)+addr)
+#define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
+#define INREG16(addr)		readw((rinfo->mmio_base)+addr)
+#define OUTREG16(addr,val)	writew(val, (rinfo->mmio_base)+addr)
+#define INREG(addr)		readl((rinfo->mmio_base)+addr)
+#define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)
+
+static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
+		       u32 val, u32 mask)
+{
+	unsigned int tmp;
+
+	tmp = INREG(addr);
+	tmp &= (mask);
+	tmp |= (val);
+	OUTREG(addr, tmp);
+}
+
+#define OUTREGP(addr,val,mask)	_OUTREGP(rinfo, addr, val,mask)
+
+/*
+ * 2D Engine helper routines
+ */
+static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* initiate flush */
+	OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+	        ~RB2D_DC_FLUSH_ALL);
+
+	for (i=0; i < 2000000; i++) {
+		if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+			return;
+		udelay(1);
+	}
+	printf("radeonfb: Flush Timeout !\n");
+}
+
+static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
+{
+	int i;
+
+	for (i=0; i<2000000; i++) {
+		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
+			return;
+		udelay(1);
+	}
+	printf("radeonfb: FIFO Timeout !\n");
+}
+
+static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* ensure FIFO is empty before waiting for idle */
+	_radeon_fifo_wait (rinfo, 64);
+
+	for (i=0; i<2000000; i++) {
+		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
+			radeon_engine_flush (rinfo);
+			return;
+		}
+		udelay(1);
+	}
+	printf("radeonfb: Idle Timeout !\n");
+}
+
+#define radeon_engine_idle()		_radeon_engine_idle(rinfo)
+#define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
+#define radeon_msleep(ms)		_radeon_msleep(rinfo,ms)
+
+/*
+ * This structure contains the various registers manipulated by this
+ * driver for setting or restoring a mode. It's mostly copied from
+ * XFree's RADEONSaveRec structure. A few chip settings might still be
+ * tweaked without beeing reflected or saved in these registers though
+ */
+struct radeon_regs {
+	/* Common registers */
+	u32		ovr_clr;
+	u32		ovr_wid_left_right;
+	u32		ovr_wid_top_bottom;
+	u32		ov0_scale_cntl;
+	u32		mpp_tb_config;
+	u32		mpp_gp_config;
+	u32		subpic_cntl;
+	u32		viph_control;
+	u32		i2c_cntl_1;
+	u32		gen_int_cntl;
+	u32		cap0_trig_cntl;
+	u32		cap1_trig_cntl;
+	u32		bus_cntl;
+	u32		surface_cntl;
+	u32		bios_5_scratch;
+
+	/* Other registers to save for VT switches or driver load/unload */
+	u32		dp_datatype;
+	u32		rbbm_soft_reset;
+	u32		clock_cntl_index;
+	u32		amcgpio_en_reg;
+	u32		amcgpio_mask;
+
+	/* Surface/tiling registers */
+	u32		surf_lower_bound[8];
+	u32		surf_upper_bound[8];
+	u32		surf_info[8];
+
+	/* CRTC registers */
+	u32		crtc_gen_cntl;
+	u32		crtc_ext_cntl;
+	u32		dac_cntl;
+	u32		crtc_h_total_disp;
+	u32		crtc_h_sync_strt_wid;
+	u32		crtc_v_total_disp;
+	u32		crtc_v_sync_strt_wid;
+	u32		crtc_offset;
+	u32		crtc_offset_cntl;
+	u32		crtc_pitch;
+	u32		disp_merge_cntl;
+	u32		grph_buffer_cntl;
+	u32		crtc_more_cntl;
+
+	/* CRTC2 registers */
+	u32		crtc2_gen_cntl;
+	u32		dac2_cntl;
+	u32		disp_output_cntl;
+	u32		disp_hw_debug;
+	u32		disp2_merge_cntl;
+	u32		grph2_buffer_cntl;
+	u32		crtc2_h_total_disp;
+	u32		crtc2_h_sync_strt_wid;
+	u32		crtc2_v_total_disp;
+	u32		crtc2_v_sync_strt_wid;
+	u32		crtc2_offset;
+	u32		crtc2_offset_cntl;
+	u32		crtc2_pitch;
+
+	/* Flat panel regs */
+	u32 		fp_crtc_h_total_disp;
+	u32		fp_crtc_v_total_disp;
+	u32		fp_gen_cntl;
+	u32		fp2_gen_cntl;
+	u32		fp_h_sync_strt_wid;
+	u32		fp2_h_sync_strt_wid;
+	u32		fp_horz_stretch;
+	u32		fp_panel_cntl;
+	u32		fp_v_sync_strt_wid;
+	u32		fp2_v_sync_strt_wid;
+	u32		fp_vert_stretch;
+	u32		lvds_gen_cntl;
+	u32		lvds_pll_cntl;
+	u32		tmds_crc;
+	u32		tmds_transmitter_cntl;
+
+	/* Computed values for PLL */
+	u32		dot_clock_freq;
+	int		feedback_div;
+	int		post_div;
+
+	/* PLL registers */
+	u32		ppll_div_3;
+	u32		ppll_ref_div;
+	u32		vclk_ecp_cntl;
+	u32		clk_cntl_index;
+
+	/* Computed values for PLL2 */
+	u32		dot_clock_freq_2;
+	int		feedback_div_2;
+	int		post_div_2;
+
+	/* PLL2 registers */
+	u32		p2pll_ref_div;
+	u32		p2pll_div_0;
+	u32		htotal_cntl2;
+
+	/* Palette */
+	int		palette_valid;
+};
+
+static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
+{
+	u32 data;
+
+	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
+	/* radeon_pll_errata_after_index(rinfo); */
+	data = INREG(CLOCK_CNTL_DATA);
+	/* radeon_pll_errata_after_data(rinfo); */
+	return data;
+}
+
+static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
+			    u32 val)
+{
+
+	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
+	/* radeon_pll_errata_after_index(rinfo); */
+	OUTREG(CLOCK_CNTL_DATA, val);
+	/* radeon_pll_errata_after_data(rinfo); */
+}
+
+static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+			     u32 val, u32 mask)
+{
+	unsigned int tmp;
+
+	tmp  = __INPLL(rinfo, index);
+	tmp &= (mask);
+	tmp |= (val);
+	__OUTPLL(rinfo, index, tmp);
+}
+
+#define INPLL(addr)			__INPLL(rinfo, addr)
+#define OUTPLL(index, val)		__OUTPLL(rinfo, index, val)
+#define OUTPLLP(index, val, mask)	__OUTPLLP(rinfo, index, val, mask)
+
+#endif
diff --git a/drivers/bcm570x.c b/drivers/bcm570x.c
index 7aeb547..c8f4064 100644
--- a/drivers/bcm570x.c
+++ b/drivers/bcm570x.c
@@ -6,8 +6,8 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && (!defined(CONFIG_NET_MULTI)) && \
-	defined(CONFIG_BCM570x)
+#if defined(CONFIG_CMD_NET) \
+	&& (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x)
 
 #ifdef CONFIG_BMW
 #include <mpc824x.h>
@@ -1600,4 +1600,4 @@
 	return pQueue->Array[Idx];
 }
 
-#endif				/* CFG_CMD_NET, !CONFIG_NET_MULTI, CONFIG_BCM570x */
+#endif
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile
new file mode 100644
index 0000000..586e83b
--- /dev/null
+++ b/drivers/bios_emulator/Makefile
@@ -0,0 +1,30 @@
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libatibiosemu.a
+
+X86DIR  = ./x86emu
+
+OBJS	= atibios.o biosemu.o besys.o bios.o  \
+	$(X86DIR)/decode.o \
+	$(X86DIR)/ops2.o \
+	$(X86DIR)/ops.o \
+	$(X86DIR)/prim_ops.o \
+	$(X86DIR)/sys.o \
+	$(X86DIR)/debug.o
+
+CFLAGS += -I. -I./include  -I$(X86DIR) -I$(TOPDIR)/include \
+	-D__PPC__  -D__BIG_ENDIAN__
+
+all:	$(LIB)
+
+$(LIB): $(OBJS)
+	$(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend:	Makefile $(OBJS:.o=.c)
+		$(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
new file mode 100644
index 0000000..5779f99
--- /dev/null
+++ b/drivers/bios_emulator/atibios.c
@@ -0,0 +1,340 @@
+/****************************************************************************
+*
+*		     Video BOOT Graphics Card POST Module
+*
+*  ========================================================================
+*   Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*   Jason Jin <Jason.jin@freescale.com>
+*
+*   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
+*
+*   This file may be distributed and/or modified under the terms of the
+*   GNU General Public License version 2.0 as published by the Free
+*   Software Foundation and appearing in the file LICENSE.GPL included
+*   in the packaging of this file.
+*
+*   Licensees holding a valid Commercial License for this product from
+*   SciTech Software, Inc. may use this file in accordance with the
+*   Commercial License Agreement provided with the Software.
+*
+*   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
+*   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+*   PURPOSE.
+*
+*   See http://www.scitechsoft.com/license/ for information about
+*   the licensing options available and how to purchase a Commercial
+*   License Agreement.
+*
+*   Contact license@scitechsoft.com if any conditions of this licensing
+*   are not clear to you, or you have questions about licensing options.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Linux Kernel
+* Developer:	Kendall Bennett
+*
+* Description:	Module to implement booting PCI/AGP controllers on the
+*		bus. We use the x86 real mode emulator to run the BIOS on
+*		graphics controllers to bring the cards up.
+*
+*		Note that at present this module does *not* support
+*		multiple controllers.
+*
+*		The orignal name of this file is warmboot.c.
+*		Jason ported this file to u-boot to run the ATI video card
+*		BIOS in u-boot.
+****************************************************************************/
+#include <common.h>
+
+#ifdef CONFIG_BIOSEMU
+
+#include "biosemui.h"
+#include <malloc.h>
+
+/* Length of the BIOS image */
+#define MAX_BIOSLEN	    (128 * 1024L)
+
+/* Define some useful types and macros */
+#define true		    1
+#define false		    0
+
+/* Place to save PCI BAR's that we change and later restore */
+static u32 saveROMBaseAddress;
+static u32 saveBaseAddress10;
+static u32 saveBaseAddress14;
+static u32 saveBaseAddress18;
+static u32 saveBaseAddress20;
+
+/****************************************************************************
+PARAMETERS:
+pcidev	- PCI device info for the video card on the bus to boot
+VGAInfo - BIOS emulator VGA info structure
+
+REMARKS:
+This function executes the BIOS POST code on the controller. We assume that
+at this stage the controller has its I/O and memory space enabled and
+that all other controllers are in a disabled state.
+****************************************************************************/
+static void PCI_doBIOSPOST(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+{
+	RMREGS regs;
+	RMSREGS sregs;
+
+	/* Determine the value to store in AX for BIOS POST. Per the PCI specs,
+	 AH must contain the bus and AL must contain the devfn, encoded as
+	 (dev << 3) | fn
+	 */
+	memset(&regs, 0, sizeof(regs));
+	memset(&sregs, 0, sizeof(sregs));
+	regs.x.ax = ((int)PCI_BUS(pcidev) << 8) |
+	    ((int)PCI_DEV(pcidev) << 3) | (int)PCI_FUNC(pcidev);
+
+	/*Setup the X86 emulator for the VGA BIOS*/
+	BE_setVGA(VGAInfo);
+
+	/*Execute the BIOS POST code*/
+	BE_callRealMode(0xC000, 0x0003, &regs, &sregs);
+
+	/*Cleanup and exit*/
+	BE_getVGA(VGAInfo);
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev	- PCI device info for the video card on the bus
+bar	- Place to return the base address register offset to use
+
+RETURNS:
+The address to use to map the secondary BIOS (AGP devices)
+
+REMARKS:
+Searches all the PCI base address registers for the device looking for a
+memory mapping that is large enough to hold our ROM BIOS. We usually end up
+finding the framebuffer mapping (usually BAR 0x10), and we use this mapping
+to map the BIOS for the device into. We use a mapping that is already
+assigned to the device to ensure the memory range will be passed through
+by any PCI->PCI or AGP->PCI bridge that may be present.
+
+NOTE: Usually this function is only used for AGP devices, but it may be
+      used for PCI devices that have already been POST'ed and the BIOS
+      ROM base address has been zero'ed out.
+
+NOTE: This function leaves the original memory aperture disabled by leaving
+      it programmed to all 1's. It must be restored to the correct value
+      later.
+****************************************************************************/
+static u32 PCI_findBIOSAddr(pci_dev_t pcidev, int *bar)
+{
+	u32 base, size;
+
+	for (*bar = 0x10; *bar <= 0x14; (*bar) += 4) {
+		pci_read_config_dword(pcidev, *bar, &base);
+		if (!(base & 0x1)) {
+			pci_write_config_dword(pcidev, *bar, 0xFFFFFFFF);
+			pci_read_config_dword(pcidev, *bar, &size);
+			size = ~(size & ~0xFF) + 1;
+			if (size >= MAX_BIOSLEN)
+				return base & ~0xFF;
+		}
+	}
+	return 0;
+}
+
+/****************************************************************************
+REMARKS:
+Some non-x86 Linux kernels map PCI relocateable I/O to values that
+are above 64K, which will not work with the BIOS image that requires
+the offset for the I/O ports to be a maximum of 16-bits. Ideally
+someone should fix the kernel to map the I/O ports for VGA compatible
+devices to a different location (or just all I/O ports since it is
+unlikely you can have enough devices in the machine to use up all
+64K of the I/O space - a total of more than 256 cards would be
+necessary).
+
+Anyway to fix this we change all I/O mapped base registers and
+chop off the top bits.
+****************************************************************************/
+static void PCI_fixupIObase(pci_dev_t pcidev, int reg, u32 * base)
+{
+	if ((*base & 0x1) && (*base > 0xFFFE)) {
+		*base &= 0xFFFF;
+		pci_write_config_dword(pcidev, reg, *base);
+
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev	- PCI device info for the video card on the bus
+
+RETURNS:
+Pointers to the mapped BIOS image
+
+REMARKS:
+Maps a pointer to the BIOS image on the graphics card on the PCI bus.
+****************************************************************************/
+void *PCI_mapBIOSImage(pci_dev_t pcidev)
+{
+	u32 BIOSImagePhys;
+	int BIOSImageBAR;
+	u8 *BIOSImage;
+
+	/*Save PCI BAR registers that might get changed*/
+	pci_read_config_dword(pcidev, PCI_ROM_ADDRESS, &saveROMBaseAddress);
+	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &saveBaseAddress10);
+	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
+	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_2, &saveBaseAddress18);
+	pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
+
+	/*Fix up I/O base registers to less than 64K */
+	if(saveBaseAddress14 != 0)
+		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_1, &saveBaseAddress14);
+	else
+		PCI_fixupIObase(pcidev, PCI_BASE_ADDRESS_4, &saveBaseAddress20);
+
+	/* Some cards have problems that stop us from being able to read the
+	 BIOS image from the ROM BAR. To fix this we have to do some chipset
+	 specific programming for different cards to solve this problem.
+	*/
+
+	if ((BIOSImagePhys = PCI_findBIOSAddr(pcidev, &BIOSImageBAR)) == 0) {
+		printf("Find bios addr error\n");
+		return NULL;
+	}
+
+	BIOSImage = (u8 *) BIOSImagePhys;
+
+	/*Change the PCI BAR registers to map it onto the bus.*/
+	pci_write_config_dword(pcidev, BIOSImageBAR, 0);
+	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, BIOSImagePhys | 0x1);
+
+	udelay(1);
+
+	/*Check that the BIOS image is valid. If not fail, or return the
+	 compiled in BIOS image if that option was enabled
+	 */
+	if (BIOSImage[0] != 0x55 || BIOSImage[1] != 0xAA || BIOSImage[2] == 0) {
+		return NULL;
+	}
+
+	return BIOSImage;
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev	- PCI device info for the video card on the bus
+
+REMARKS:
+Unmaps the BIOS image for the device and restores framebuffer mappings
+****************************************************************************/
+void PCI_unmapBIOSImage(pci_dev_t pcidev, void *BIOSImage)
+{
+	pci_write_config_dword(pcidev, PCI_ROM_ADDRESS, saveROMBaseAddress);
+	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, saveBaseAddress10);
+	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_1, saveBaseAddress14);
+	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_2, saveBaseAddress18);
+	pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_4, saveBaseAddress20);
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev	- PCI device info for the video card on the bus to boot
+VGAInfo - BIOS emulator VGA info structure
+
+RETURNS:
+True if successfully initialised, false if not.
+
+REMARKS:
+Loads and POST's the display controllers BIOS, directly from the BIOS
+image we can extract over the PCI bus.
+****************************************************************************/
+static int PCI_postController(pci_dev_t pcidev, BE_VGAInfo * VGAInfo)
+{
+	u32 BIOSImageLen;
+	uchar *mappedBIOS;
+	uchar *copyOfBIOS;
+
+	/*Allocate memory to store copy of BIOS from display controller*/
+	if ((mappedBIOS = PCI_mapBIOSImage(pcidev)) == NULL) {
+		printf("videoboot: Video ROM failed to map!\n");
+		return false;
+	}
+
+	BIOSImageLen = mappedBIOS[2] * 512;
+
+	if ((copyOfBIOS = malloc(BIOSImageLen)) == NULL) {
+		printf("videoboot: Out of memory!\n");
+		return false;
+	}
+	memcpy(copyOfBIOS, mappedBIOS, BIOSImageLen);
+
+	PCI_unmapBIOSImage(pcidev, mappedBIOS);
+
+	/*Save information in VGAInfo structure*/
+	VGAInfo->function = PCI_FUNC(pcidev);
+	VGAInfo->device = PCI_DEV(pcidev);
+	VGAInfo->bus = PCI_BUS(pcidev);
+	VGAInfo->pcidev = pcidev;
+	VGAInfo->BIOSImage = copyOfBIOS;
+	VGAInfo->BIOSImageLen = BIOSImageLen;
+
+	/*Now execute the BIOS POST for the device*/
+	if (copyOfBIOS[0] != 0x55 || copyOfBIOS[1] != 0xAA) {
+		printf("videoboot: Video ROM image is invalid!\n");
+		return false;
+	}
+
+	PCI_doBIOSPOST(pcidev, VGAInfo);
+
+	/*Reset the size of the BIOS image to the final size*/
+	VGAInfo->BIOSImageLen = copyOfBIOS[2] * 512;
+	return true;
+}
+
+/****************************************************************************
+PARAMETERS:
+pcidev	    - PCI device info for the video card on the bus to boot
+pVGAInfo    - Place to return VGA info structure is requested
+cleanUp	    - True to clean up on exit, false to leave emulator active
+
+REMARKS:
+Boots the PCI/AGP video card on the bus using the Video ROM BIOS image
+and the X86 BIOS emulator module.
+****************************************************************************/
+int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp)
+{
+	BE_VGAInfo *VGAInfo;
+
+	printf("videoboot: Booting PCI video card bus %d, function %d, device %d\n",
+	     PCI_BUS(pcidev), PCI_FUNC(pcidev), PCI_DEV(pcidev));
+
+	/*Initialise the x86 BIOS emulator*/
+	if ((VGAInfo = malloc(sizeof(*VGAInfo))) == NULL) {
+		printf("videoboot: Out of memory!\n");
+		return false;
+	}
+	memset(VGAInfo, 0, sizeof(*VGAInfo));
+	BE_init(0, 65536, VGAInfo, 0);
+
+	/*Post all the display controller BIOS'es*/
+	PCI_postController(pcidev, VGAInfo);
+
+	/*Cleanup and exit the emulator if requested. If the BIOS emulator
+	is needed after booting the card, we will not call BE_exit and
+	leave it enabled for further use (ie: VESA driver etc).
+	*/
+	if (cleanUp) {
+		BE_exit();
+		if (VGAInfo->BIOSImage)
+			free(VGAInfo->BIOSImage);
+		free(VGAInfo);
+		VGAInfo = NULL;
+	}
+	/*Return VGA info pointer if the caller requested it*/
+	if (pVGAInfo)
+		*pVGAInfo = VGAInfo;
+	return true;
+}
+
+#endif
diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c
new file mode 100644
index 0000000..4c4bc8d
--- /dev/null
+++ b/drivers/bios_emulator/besys.c
@@ -0,0 +1,721 @@
+/****************************************************************************
+*
+*                        BIOS emulator and interface
+*                      to Realmode X86 Emulator Library
+*
+*  ========================================================================
+*
+*   Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*   Jason Jin<Jason.jin@freescale.com>
+*
+*   Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved.
+*
+*   This file may be distributed and/or modified under the terms of the
+*   GNU General Public License version 2.0 as published by the Free
+*   Software Foundation and appearing in the file LICENSE.GPL included
+*   in the packaging of this file.
+*
+*   Licensees holding a valid Commercial License for this product from
+*   SciTech Software, Inc. may use this file in accordance with the
+*   Commercial License Agreement provided with the Software.
+*
+*   This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
+*   THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+*   PURPOSE.
+*
+*   See http://www.scitechsoft.com/license/ for information about
+*   the licensing options available and how to purchase a Commercial
+*   License Agreement.
+*
+*   Contact license@scitechsoft.com if any conditions of this licensing
+*   are not clear to you, or you have questions about licensing options.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  This file includes BIOS emulator I/O and memory access
+*               functions.
+*
+*		Jason ported this file to u-boot to run the ATI video card
+*		BIOS in u-boot. Removed some emulate functions such as the
+*		timer port access. Made all the VGA port except reading 0x3c3
+*		be emulated. Seems like reading 0x3c3 should return the high
+*		16 bit of the io port.
+*
+****************************************************************************/
+
+#include "biosemui.h"
+
+#if defined(CONFIG_BIOSEMU)
+/*------------------------- Global Variables ------------------------------*/
+
+#ifndef __i386__
+static char *BE_biosDate = "08/14/99";
+static u8 BE_model = 0xFC;
+static u8 BE_submodel = 0x00;
+#endif
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to convert
+
+RETURNS:
+Actual memory address to read or write the data
+
+REMARKS:
+This function converts an emulator memory address in a 32-bit range to
+a real memory address that we wish to access. It handles splitting up the
+memory address space appropriately to access the emulator BIOS image, video
+memory and system BIOS etc.
+****************************************************************************/
+static u8 *BE_memaddr(u32 addr)
+{
+	if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
+		return (u8*)(_BE_env.biosmem_base + addr - 0xC0000);
+	} else if (addr > _BE_env.biosmem_limit && addr < 0xD0000) {
+		DB(printf("BE_memaddr: address %#lx may be invalid!\n", addr);)
+		return M.mem_base;
+	} else if (addr >= 0xA0000 && addr <= 0xBFFFF) {
+		return (u8*)(_BE_env.busmem_base + addr - 0xA0000);
+	}
+#ifdef __i386__
+	else if (addr >= 0xD0000 && addr <= 0xFFFFF) {
+		/* We map the real System BIOS directly on real PC's */
+		DB(printf("BE_memaddr: System BIOS address %#lx\n", addr);)
+		    return _BE_env.busmem_base + addr - 0xA0000;
+	}
+#else
+	else if (addr >= 0xFFFF5 && addr < 0xFFFFE) {
+		/* Return a faked BIOS date string for non-x86 machines */
+		DB(printf("BE_memaddr - Returning BIOS date\n");)
+		return BE_biosDate + addr - 0xFFFF5;
+	} else if (addr == 0xFFFFE) {
+		/* Return system model identifier for non-x86 machines */
+		DB(printf("BE_memaddr - Returning model\n");)
+		return &BE_model;
+	} else if (addr == 0xFFFFF) {
+		/* Return system submodel identifier for non-x86 machines */
+		DB(printf("BE_memaddr - Returning submodel\n");)
+		return &BE_submodel;
+	}
+#endif
+	else if (addr > M.mem_size - 1) {
+		HALT_SYS();
+		return M.mem_base;
+	}
+
+	return M.mem_base + addr;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Byte value read from emulator memory.
+
+REMARKS:
+Reads a byte value from the emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+u8 X86API BE_rdb(u32 addr)
+{
+	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
+		return 0;
+	else {
+		u8 val = readb_le(BE_memaddr(addr));
+		return val;
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Word value read from emulator memory.
+
+REMARKS:
+Reads a word value from the emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+u16 X86API BE_rdw(u32 addr)
+{
+	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
+		return 0;
+	else {
+		u8 *base = BE_memaddr(addr);
+		u16 val = readw_le(base);
+		return val;
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Long value read from emulator memory.
+
+REMARKS:
+Reads a 32-bit value from the emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+u32 X86API BE_rdl(u32 addr)
+{
+	if (_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)
+		return 0;
+	else {
+		u8 *base = BE_memaddr(addr);
+		u32 val = readl_le(base);
+		return val;
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a byte value to emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+void X86API BE_wrb(u32 addr, u8 val)
+{
+	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
+		writeb_le(BE_memaddr(addr), val);
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a word value to emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+void X86API BE_wrw(u32 addr, u16 val)
+{
+	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
+		u8 *base = BE_memaddr(addr);
+		writew_le(base, val);
+
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a 32-bit value to emulator memory. We have three distinct memory
+regions that are handled differently, which this function handles.
+****************************************************************************/
+void X86API BE_wrl(u32 addr, u32 val)
+{
+	if (!(_BE_env.emulateVGA && addr >= 0xA0000 && addr <= 0xBFFFF)) {
+		u8 *base = BE_memaddr(addr);
+		writel_le(base, val);
+	}
+}
+
+#if defined(DEBUG) || !defined(__i386__)
+
+/* For Non-Intel machines we may need to emulate some I/O port accesses that
+ * the BIOS may try to access, such as the PCI config registers.
+ */
+
+#define IS_TIMER_PORT(port) (0x40 <= port && port <= 0x43)
+#define IS_CMOS_PORT(port)  (0x70 <= port && port <= 0x71)
+/*#define IS_VGA_PORT(port)   (_BE_env.emulateVGA && 0x3C0 <= port && port <= 0x3DA)*/
+#define IS_VGA_PORT(port)   (0x3C0 <= port && port <= 0x3DA)
+#define IS_PCI_PORT(port)   (0xCF8 <= port && port <= 0xCFF)
+#define IS_SPKR_PORT(port)  (port == 0x61)
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to read from
+type    - Type of access to perform
+
+REMARKS:
+Performs an emulated read from the Standard VGA I/O ports. If the target
+hardware does not support mapping the VGA I/O and memory (such as some
+PowerPC systems), we emulate the VGA so that the BIOS will still be able to
+set NonVGA display modes such as on ATI hardware.
+****************************************************************************/
+static u8 VGA_inpb (const int port)
+{
+	u8 val = 0xff;
+
+	switch (port) {
+	case 0x3C0:
+		/* 3C0 has funky characteristics because it can act as either
+		   a data register or index register depending on the state
+		   of an internal flip flop in the hardware. Hence we have
+		   to emulate that functionality in here. */
+		if (_BE_env.flipFlop3C0 == 0) {
+			/* Access 3C0 as index register */
+			val = _BE_env.emu3C0;
+		} else {
+			/* Access 3C0 as data register */
+			if (_BE_env.emu3C0 < ATT_C)
+				val = _BE_env.emu3C1[_BE_env.emu3C0];
+		}
+		_BE_env.flipFlop3C0 ^= 1;
+		break;
+	case 0x3C1:
+		if (_BE_env.emu3C0 < ATT_C)
+			return _BE_env.emu3C1[_BE_env.emu3C0];
+		break;
+	case 0x3CC:
+		return _BE_env.emu3C2;
+	case 0x3C4:
+		return _BE_env.emu3C4;
+	case 0x3C5:
+		if (_BE_env.emu3C4 < ATT_C)
+			return _BE_env.emu3C5[_BE_env.emu3C4];
+		break;
+	case 0x3C6:
+		return _BE_env.emu3C6;
+	case 0x3C7:
+		return _BE_env.emu3C7;
+	case 0x3C8:
+		return _BE_env.emu3C8;
+	case 0x3C9:
+		if (_BE_env.emu3C7 < PAL_C)
+			return _BE_env.emu3C9[_BE_env.emu3C7++];
+		break;
+	case 0x3CE:
+		return _BE_env.emu3CE;
+	case 0x3CF:
+		if (_BE_env.emu3CE < GRA_C)
+			return _BE_env.emu3CF[_BE_env.emu3CE];
+		break;
+	case 0x3D4:
+		if (_BE_env.emu3C2 & 0x1)
+			return _BE_env.emu3D4;
+		break;
+	case 0x3D5:
+		if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
+			return _BE_env.emu3D5[_BE_env.emu3D4];
+		break;
+	case 0x3DA:
+		_BE_env.flipFlop3C0 = 0;
+		val = _BE_env.emu3DA;
+		_BE_env.emu3DA ^= 0x9;
+		break;
+	}
+	return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+type    - Type of access to perform
+
+REMARKS:
+Performs an emulated write to one of the 8253 timer registers. For now
+we only emulate timer 0 which is the only timer that the BIOS code appears
+to use.
+****************************************************************************/
+static void VGA_outpb (int port, u8 val)
+{
+	switch (port) {
+	case 0x3C0:
+		/* 3C0 has funky characteristics because it can act as either
+		   a data register or index register depending on the state
+		   of an internal flip flop in the hardware. Hence we have
+		   to emulate that functionality in here. */
+		if (_BE_env.flipFlop3C0 == 0) {
+			/* Access 3C0 as index register */
+			_BE_env.emu3C0 = val;
+		} else {
+			/* Access 3C0 as data register */
+			if (_BE_env.emu3C0 < ATT_C)
+				_BE_env.emu3C1[_BE_env.emu3C0] = val;
+		}
+		_BE_env.flipFlop3C0 ^= 1;
+		break;
+	case 0x3C2:
+		_BE_env.emu3C2 = val;
+		break;
+	case 0x3C4:
+		_BE_env.emu3C4 = val;
+		break;
+	case 0x3C5:
+		if (_BE_env.emu3C4 < ATT_C)
+			_BE_env.emu3C5[_BE_env.emu3C4] = val;
+		break;
+	case 0x3C6:
+		_BE_env.emu3C6 = val;
+		break;
+	case 0x3C7:
+		_BE_env.emu3C7 = (int) val *3;
+
+		break;
+	case 0x3C8:
+		_BE_env.emu3C8 = (int) val *3;
+
+		break;
+	case 0x3C9:
+		if (_BE_env.emu3C8 < PAL_C)
+			_BE_env.emu3C9[_BE_env.emu3C8++] = val;
+		break;
+	case 0x3CE:
+		_BE_env.emu3CE = val;
+		break;
+	case 0x3CF:
+		if (_BE_env.emu3CE < GRA_C)
+			_BE_env.emu3CF[_BE_env.emu3CE] = val;
+		break;
+	case 0x3D4:
+		if (_BE_env.emu3C2 & 0x1)
+			_BE_env.emu3D4 = val;
+		break;
+	case 0x3D5:
+		if ((_BE_env.emu3C2 & 0x1) && (_BE_env.emu3D4 < CRT_C))
+			_BE_env.emu3D5[_BE_env.emu3D4] = val;
+		break;
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+regOffset   - Offset into register space for non-DWORD accesses
+value       - Value to write to register for PCI_WRITE_* operations
+func        - Function to perform (PCIAccessRegFlags)
+
+RETURNS:
+Value read from configuration register for PCI_READ_* operations
+
+REMARKS:
+Accesses a PCI configuration space register by decoding the value currently
+stored in the _BE_env.configAddress variable and passing it through to the
+portable PCI_accessReg function.
+****************************************************************************/
+static u32 BE_accessReg(int regOffset, u32 value, int func)
+{
+#ifdef __KERNEL__
+	int function, device, bus;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+
+	/* Decode the configuration register values for the register we wish to
+	 * access
+	 */
+	regOffset += (_BE_env.configAddress & 0xFF);
+	function = (_BE_env.configAddress >> 8) & 0x7;
+	device = (_BE_env.configAddress >> 11) & 0x1F;
+	bus = (_BE_env.configAddress >> 16) & 0xFF;
+
+	/* Ignore accesses to all devices other than the one we're POSTing */
+	if ((function == _BE_env.vgaInfo.function) &&
+	    (device == _BE_env.vgaInfo.device) &&
+	    (bus == _BE_env.vgaInfo.bus)) {
+		switch (func) {
+		case REG_READ_BYTE:
+			pci_read_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
+					     &val8);
+			return val8;
+		case REG_READ_WORD:
+			pci_read_config_word(_BE_env.vgaInfo.pcidev, regOffset,
+					     &val16);
+			return val16;
+		case REG_READ_DWORD:
+			pci_read_config_dword(_BE_env.vgaInfo.pcidev, regOffset,
+					      &val32);
+			return val32;
+		case REG_WRITE_BYTE:
+			pci_write_config_byte(_BE_env.vgaInfo.pcidev, regOffset,
+					      value);
+
+			return 0;
+		case REG_WRITE_WORD:
+			pci_write_config_word(_BE_env.vgaInfo.pcidev, regOffset,
+					      value);
+
+			return 0;
+		case REG_WRITE_DWORD:
+			pci_write_config_dword(_BE_env.vgaInfo.pcidev,
+					       regOffset, value);
+
+			return 0;
+		}
+	}
+	return 0;
+#else
+	PCIDeviceInfo pciInfo;
+
+	pciInfo.mech1 = 1;
+	pciInfo.slot.i = 0;
+	pciInfo.slot.p.Function = (_BE_env.configAddress >> 8) & 0x7;
+	pciInfo.slot.p.Device = (_BE_env.configAddress >> 11) & 0x1F;
+	pciInfo.slot.p.Bus = (_BE_env.configAddress >> 16) & 0xFF;
+	pciInfo.slot.p.Enable = 1;
+
+	/* Ignore accesses to all devices other than the one we're POSTing */
+	if ((pciInfo.slot.p.Function ==
+	     _BE_env.vgaInfo.pciInfo->slot.p.Function)
+	    && (pciInfo.slot.p.Device == _BE_env.vgaInfo.pciInfo->slot.p.Device)
+	    && (pciInfo.slot.p.Bus == _BE_env.vgaInfo.pciInfo->slot.p.Bus))
+		return PCI_accessReg((_BE_env.configAddress & 0xFF) + regOffset,
+				     value, func, &pciInfo);
+	return 0;
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to read from
+type    - Type of access to perform
+
+REMARKS:
+Performs an emulated read from one of the PCI configuration space registers.
+We emulate this using our PCI_accessReg function which will access the PCI
+configuration space registers in a portable fashion.
+****************************************************************************/
+static u32 PCI_inp(int port, int type)
+{
+	switch (type) {
+	case REG_READ_BYTE:
+		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
+		    && port <= 0xCFF)
+			return BE_accessReg(port - 0xCFC, 0, REG_READ_BYTE);
+		break;
+	case REG_READ_WORD:
+		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
+		    && port <= 0xCFF)
+			return BE_accessReg(port - 0xCFC, 0, REG_READ_WORD);
+		break;
+	case REG_READ_DWORD:
+		if (port == 0xCF8)
+			return _BE_env.configAddress;
+		else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
+			return BE_accessReg(0, 0, REG_READ_DWORD);
+		break;
+	}
+	return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+type    - Type of access to perform
+
+REMARKS:
+Performs an emulated write to one of the PCI control registers.
+****************************************************************************/
+static void PCI_outp(int port, u32 val, int type)
+{
+	switch (type) {
+	case REG_WRITE_BYTE:
+		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
+		    && port <= 0xCFF)
+			BE_accessReg(port - 0xCFC, val, REG_WRITE_BYTE);
+		break;
+	case REG_WRITE_WORD:
+		if ((_BE_env.configAddress & 0x80000000) && 0xCFC <= port
+		    && port <= 0xCFF)
+			BE_accessReg(port - 0xCFC, val, REG_WRITE_WORD);
+		break;
+	case REG_WRITE_DWORD:
+		if (port == 0xCF8)
+		{
+			_BE_env.configAddress = val & 0x80FFFFFC;
+		}
+		else if ((_BE_env.configAddress & 0x80000000) && port == 0xCFC)
+			BE_accessReg(0, val, REG_WRITE_DWORD);
+		break;
+	}
+}
+
+#endif
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+
+RETURNS:
+Value read from the I/O port
+
+REMARKS:
+Performs an emulated 8-bit read from an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+u8 X86API BE_inb(X86EMU_pioAddr port)
+{
+	u8 val = 0;
+
+#if defined(DEBUG) || !defined(__i386__)
+	if (IS_VGA_PORT(port)){
+		/*seems reading port 0x3c3 return the high 16 bit of io port*/
+		if(port == 0x3c3)
+			val = LOG_inpb(port);
+		else
+			val = VGA_inpb(port);
+	}
+	else if (IS_TIMER_PORT(port))
+		DB(printf("Can not interept TIMER port now!\n");)
+	else if (IS_SPKR_PORT(port))
+		DB(printf("Can not interept SPEAKER port now!\n");)
+	else if (IS_CMOS_PORT(port))
+		DB(printf("Can not interept CMOS port now!\n");)
+	else if (IS_PCI_PORT(port))
+		val = PCI_inp(port, REG_READ_BYTE);
+	else if (port < 0x100) {
+		DB(printf("WARN: INVALID inb.%04X -> %02X\n", (u16) port, val);)
+		val = LOG_inpb(port);
+	} else
+#endif
+		val = LOG_inpb(port);
+	return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+
+RETURNS:
+Value read from the I/O port
+
+REMARKS:
+Performs an emulated 16-bit read from an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+u16 X86API BE_inw(X86EMU_pioAddr port)
+{
+	u16 val = 0;
+
+#if defined(DEBUG) || !defined(__i386__)
+	if (IS_PCI_PORT(port))
+		val = PCI_inp(port, REG_READ_WORD);
+	else if (port < 0x100) {
+		DB(printf("WARN: Maybe INVALID inw.%04X -> %04X\n", (u16) port, val);)
+		val = LOG_inpw(port);
+	} else
+#endif
+		val = LOG_inpw(port);
+	return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+
+RETURNS:
+Value read from the I/O port
+
+REMARKS:
+Performs an emulated 32-bit read from an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+u32 X86API BE_inl(X86EMU_pioAddr port)
+{
+	u32 val = 0;
+
+#if defined(DEBUG) || !defined(__i386__)
+	if (IS_PCI_PORT(port))
+		val = PCI_inp(port, REG_READ_DWORD);
+	else if (port < 0x100) {
+		val = LOG_inpd(port);
+	} else
+#endif
+		val = LOG_inpd(port);
+	return val;
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+val     - Value to write to port
+
+REMARKS:
+Performs an emulated 8-bit write to an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+void X86API BE_outb(X86EMU_pioAddr port, u8 val)
+{
+#if defined(DEBUG) || !defined(__i386__)
+	if (IS_VGA_PORT(port))
+		VGA_outpb(port, val);
+	else if (IS_TIMER_PORT(port))
+		DB(printf("Can not interept TIMER port now!\n");)
+	else if (IS_SPKR_PORT(port))
+		DB(printf("Can not interept SPEAKER port now!\n");)
+	else if (IS_CMOS_PORT(port))
+		DB(printf("Can not interept CMOS port now!\n");)
+	else if (IS_PCI_PORT(port))
+		PCI_outp(port, val, REG_WRITE_BYTE);
+	else if (port < 0x100) {
+		DB(printf("WARN:Maybe INVALID outb.%04X <- %02X\n", (u16) port, val);)
+		LOG_outpb(port, val);
+	} else
+#endif
+		LOG_outpb(port, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+val     - Value to write to port
+
+REMARKS:
+Performs an emulated 16-bit write to an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+void X86API BE_outw(X86EMU_pioAddr port, u16 val)
+{
+#if defined(DEBUG) || !defined(__i386__)
+		if (IS_VGA_PORT(port)) {
+			VGA_outpb(port, val);
+			VGA_outpb(port + 1, val >> 8);
+		} else if (IS_PCI_PORT(port))
+			PCI_outp(port, val, REG_WRITE_WORD);
+		else if (port < 0x100) {
+			DB(printf("WARN: MAybe INVALID outw.%04X <- %04X\n", (u16) port,
+			       val);)
+			LOG_outpw(port, val);
+		} else
+#endif
+			LOG_outpw(port, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+port    - Port to write to
+val     - Value to write to port
+
+REMARKS:
+Performs an emulated 32-bit write to an I/O port. We handle special cases
+that we need to emulate in here, and fall through to reflecting the write
+through to the real hardware if we don't need to special case it.
+****************************************************************************/
+void X86API BE_outl(X86EMU_pioAddr port, u32 val)
+{
+#if defined(DEBUG) || !defined(__i386__)
+	if (IS_PCI_PORT(port))
+		PCI_outp(port, val, REG_WRITE_DWORD);
+	else if (port < 0x100) {
+		DB(printf("WARN: INVALID outl.%04X <- %08X\n", (u16) port,val);)
+		LOG_outpd(port, val);
+	} else
+#endif
+		LOG_outpd(port, val);
+}
+#endif
diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c
new file mode 100644
index 0000000..7aa1bfb2e
--- /dev/null
+++ b/drivers/bios_emulator/bios.c
@@ -0,0 +1,323 @@
+/****************************************************************************
+*
+*                        BIOS emulator and interface
+*                      to Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*  Jason Jin <Jason.jin@freescale.com>
+*
+*               Copyright (C) 1996-1999 SciTech Software, Inc.
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Module implementing the BIOS specific functions.
+*
+* 		Jason ported this file to u-boot to run the ATI video card
+* 		video BIOS.
+*
+****************************************************************************/
+
+#include "biosemui.h"
+
+#if defined(CONFIG_BIOSEMU)
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+intno   - Interrupt number being serviced
+
+REMARKS:
+Handler for undefined interrupts.
+****************************************************************************/
+static void X86API undefined_intr(int intno)
+{
+	if (BE_rdw(intno * 4 + 2) == BIOS_SEG) {
+		DB(printf("biosEmu: undefined interrupt %xh called!\n", intno);)
+	} else
+		X86EMU_prepareForInt(intno);
+}
+
+/****************************************************************************
+PARAMETERS:
+intno   - Interrupt number being serviced
+
+REMARKS:
+This function handles the default system BIOS Int 10h (the default is stored
+in the Int 42h vector by the system BIOS at bootup). We only need to handle
+a small number of special functions used by the BIOS during POST time.
+****************************************************************************/
+static void X86API int42(int intno)
+{
+	if (M.x86.R_AH == 0x12 && M.x86.R_BL == 0x32) {
+		if (M.x86.R_AL == 0) {
+			/* Enable CPU accesses to video memory */
+			PM_outpb(0x3c2, PM_inpb(0x3cc) | (u8) 0x02);
+			return;
+		} else if (M.x86.R_AL == 1) {
+			/* Disable CPU accesses to video memory */
+			PM_outpb(0x3c2, PM_inpb(0x3cc) & (u8) ~ 0x02);
+			return;
+		}
+#ifdef  DEBUG
+		else {
+			printf("int42: unknown function AH=0x12, BL=0x32, AL=%#02x\n",
+			     M.x86.R_AL);
+		}
+#endif
+	}
+#ifdef  DEBUG
+	else {
+		printf("int42: unknown function AH=%#02x, AL=%#02x, BL=%#02x\n",
+		     M.x86.R_AH, M.x86.R_AL, M.x86.R_BL);
+	}
+#endif
+}
+
+/****************************************************************************
+PARAMETERS:
+intno   - Interrupt number being serviced
+
+REMARKS:
+This function handles the default system BIOS Int 10h. If the POST code
+has not yet re-vectored the Int 10h BIOS interrupt vector, we handle this
+by simply calling the int42 interrupt handler above. Very early in the
+BIOS POST process, the vector gets replaced and we simply let the real
+mode interrupt handler process the interrupt.
+****************************************************************************/
+static void X86API int10(int intno)
+{
+	if (BE_rdw(intno * 4 + 2) == BIOS_SEG)
+		int42(intno);
+	else
+		X86EMU_prepareForInt(intno);
+}
+
+/* Result codes returned by the PCI BIOS */
+
+#define SUCCESSFUL          0x00
+#define FUNC_NOT_SUPPORT    0x81
+#define BAD_VENDOR_ID       0x83
+#define DEVICE_NOT_FOUND    0x86
+#define BAD_REGISTER_NUMBER 0x87
+#define SET_FAILED          0x88
+#define BUFFER_TOO_SMALL    0x89
+
+/****************************************************************************
+PARAMETERS:
+intno   - Interrupt number being serviced
+
+REMARKS:
+This function handles the default Int 1Ah interrupt handler for the real
+mode code, which provides support for the PCI BIOS functions. Since we only
+want to allow the real mode BIOS code *only* see the PCI config space for
+its own device, we only return information for the specific PCI config
+space that we have passed in to the init function. This solves problems
+when using the BIOS to warm boot a secondary adapter when there is an
+identical adapter before it on the bus (some BIOS'es get confused in this
+case).
+****************************************************************************/
+static void X86API int1A(int unused)
+{
+	u16 pciSlot;
+
+#ifdef __KERNEL__
+	u8 interface, subclass, baseclass;
+
+	/* Initialise the PCI slot number */
+	pciSlot = ((int)_BE_env.vgaInfo.bus << 8) |
+	    ((int)_BE_env.vgaInfo.device << 3) | (int)_BE_env.vgaInfo.function;
+#else
+/* Fail if no PCI device information has been registered */
+	if (!_BE_env.vgaInfo.pciInfo)
+		return;
+
+	pciSlot = (u16) (_BE_env.vgaInfo.pciInfo->slot.i >> 8);
+#endif
+	switch (M.x86.R_AX) {
+	case 0xB101:		/* PCI bios present? */
+		M.x86.R_AL = 0x00;	/* no config space/special cycle generation support */
+		M.x86.R_EDX = 0x20494350;	/* " ICP" */
+		M.x86.R_BX = 0x0210;	/* Version 2.10 */
+		M.x86.R_CL = 0;	/* Max bus number in system */
+		CLEAR_FLAG(F_CF);
+		break;
+	case 0xB102:		/* Find PCI device */
+		M.x86.R_AH = DEVICE_NOT_FOUND;
+#ifdef __KERNEL__
+		if (M.x86.R_DX == _BE_env.vgaInfo.VendorID &&
+		    M.x86.R_CX == _BE_env.vgaInfo.DeviceID && M.x86.R_SI == 0) {
+#else
+		if (M.x86.R_DX == _BE_env.vgaInfo.pciInfo->VendorID &&
+		    M.x86.R_CX == _BE_env.vgaInfo.pciInfo->DeviceID &&
+		    M.x86.R_SI == 0) {
+#endif
+			M.x86.R_AH = SUCCESSFUL;
+			M.x86.R_BX = pciSlot;
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB103:		/* Find PCI class code */
+		M.x86.R_AH = DEVICE_NOT_FOUND;
+#ifdef __KERNEL__
+		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_PROG,
+				     &interface);
+		pci_read_config_byte(_BE_env.vgaInfo.pcidev, PCI_CLASS_DEVICE,
+				     &subclass);
+		pci_read_config_byte(_BE_env.vgaInfo.pcidev,
+				     PCI_CLASS_DEVICE + 1, &baseclass);
+		if (M.x86.R_CL == interface && M.x86.R_CH == subclass
+		    && (u8) (M.x86.R_ECX >> 16) == baseclass) {
+#else
+		if (M.x86.R_CL == _BE_env.vgaInfo.pciInfo->Interface &&
+		    M.x86.R_CH == _BE_env.vgaInfo.pciInfo->SubClass &&
+		    (u8) (M.x86.R_ECX >> 16) ==
+		    _BE_env.vgaInfo.pciInfo->BaseClass) {
+#endif
+			M.x86.R_AH = SUCCESSFUL;
+			M.x86.R_BX = pciSlot;
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB108:		/* Read configuration byte */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_read_config_byte(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
+					     &M.x86.R_CL);
+#else
+			M.x86.R_CL =
+			    (u8) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_BYTE,
+					       _BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB109:		/* Read configuration word */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_read_config_word(_BE_env.vgaInfo.pcidev, M.x86.R_DI,
+					     &M.x86.R_CX);
+#else
+			M.x86.R_CX =
+			    (u16) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_WORD,
+						_BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB10A:		/* Read configuration dword */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_read_config_dword(_BE_env.vgaInfo.pcidev,
+					      M.x86.R_DI, &M.x86.R_ECX);
+#else
+			M.x86.R_ECX =
+			    (u32) PCI_accessReg(M.x86.R_DI, 0, PCI_READ_DWORD,
+						_BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB10B:		/* Write configuration byte */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_write_config_byte(_BE_env.vgaInfo.pcidev,
+					      M.x86.R_DI, M.x86.R_CL);
+#else
+			PCI_accessReg(M.x86.R_DI, M.x86.R_CL, PCI_WRITE_BYTE,
+				      _BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB10C:		/* Write configuration word */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_write_config_word(_BE_env.vgaInfo.pcidev,
+					      M.x86.R_DI, M.x86.R_CX);
+#else
+			PCI_accessReg(M.x86.R_DI, M.x86.R_CX, PCI_WRITE_WORD,
+				      _BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	case 0xB10D:		/* Write configuration dword */
+		M.x86.R_AH = BAD_REGISTER_NUMBER;
+		if (M.x86.R_BX == pciSlot) {
+			M.x86.R_AH = SUCCESSFUL;
+#ifdef __KERNEL__
+			pci_write_config_dword(_BE_env.vgaInfo.pcidev,
+					       M.x86.R_DI, M.x86.R_ECX);
+#else
+			PCI_accessReg(M.x86.R_DI, M.x86.R_ECX, PCI_WRITE_DWORD,
+				      _BE_env.vgaInfo.pciInfo);
+#endif
+		}
+		CONDITIONAL_SET_FLAG((M.x86.R_AH != SUCCESSFUL), F_CF);
+		break;
+	default:
+		printf("biosEmu/bios.int1a: unknown function AX=%#04x\n",
+		       M.x86.R_AX);
+	}
+}
+
+/****************************************************************************
+REMARKS:
+This function initialises the BIOS emulation functions for the specific
+PCI display device. We insulate the real mode BIOS from any other devices
+on the bus, so that it will work correctly thinking that it is the only
+device present on the bus (ie: avoiding any adapters present in from of
+the device we are trying to control).
+****************************************************************************/
+#define BE_constLE_32(v)    ((((((v)&0xff00)>>8)|(((v)&0xff)<<8))<<16)|(((((v)&0xff000000)>>8)|(((v)&0x00ff0000)<<8))>>16))
+
+void _BE_bios_init(u32 * intrTab)
+{
+	int i;
+	X86EMU_intrFuncs bios_intr_tab[256];
+
+	for (i = 0; i < 256; ++i) {
+		intrTab[i] = BE_constLE_32(BIOS_SEG << 16);
+		bios_intr_tab[i] = undefined_intr;
+	}
+	bios_intr_tab[0x10] = int10;
+	bios_intr_tab[0x1A] = int1A;
+	bios_intr_tab[0x42] = int42;
+	bios_intr_tab[0x6D] = int10;
+	X86EMU_setupIntrFuncs(bios_intr_tab);
+}
+#endif
diff --git a/drivers/bios_emulator/biosemu.c b/drivers/bios_emulator/biosemu.c
new file mode 100644
index 0000000..4c3aedf
--- /dev/null
+++ b/drivers/bios_emulator/biosemu.c
@@ -0,0 +1,373 @@
+/****************************************************************************
+*
+*			 BIOS emulator and interface
+*		       to Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*  Jason Jin <Jason.jin@freescale.com>
+*
+*		Copyright (C) 1996-1999 SciTech Software, Inc.
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	Module implementing the system specific functions. This
+*		module is always compiled and linked in the OS depedent
+*		libraries, and never in a binary portable driver.
+*
+*		Jason ported this file to u-boot to run the ATI video card BIOS
+*		in u-boot. Made all the video memory be emulated during the
+*		BIOS runing process which may affect the VGA function but the
+*		frambuffer function can work after run the BIOS.
+*
+****************************************************************************/
+
+#include "biosemui.h"
+#include <malloc.h>
+
+#if defined(CONFIG_BIOSEMU)
+
+BE_sysEnv _BE_env = {{0}};
+static X86EMU_memFuncs _BE_mem __attribute__((section(".got2"))) = {
+	BE_rdb,
+	BE_rdw,
+	BE_rdl,
+	BE_wrb,
+	BE_wrw,
+	BE_wrl,
+	};
+
+static X86EMU_pioFuncs _BE_pio __attribute__((section(".got2"))) = {
+	BE_inb,
+	BE_inw,
+	BE_inl,
+	BE_outb,
+	BE_outw,
+	BE_outl,
+	};
+
+#define OFF(addr)	(u16)(((addr) >> 0) & 0xffff)
+#define SEG(addr)	(u16)(((addr) >> 4) & 0xf000)
+
+/****************************************************************************
+PARAMETERS:
+debugFlags  - Flags to enable debugging options (debug builds only)
+memSize	    - Amount of memory to allocate for real mode machine
+info	    - Pointer to default VGA device information
+
+REMARKS:
+This functions initialises the BElib, and uses the passed in
+BIOS image as the BIOS that is used and emulated at 0xC0000.
+****************************************************************************/
+int X86API BE_init(u32 debugFlags, int memSize, BE_VGAInfo * info, int shared)
+{
+#if !defined(__DRIVER__)  && !defined(__KERNEL__)
+
+	PM_init();
+#endif
+	memset(&M, 0, sizeof(M));
+	if (memSize < 20480){
+		printf("Emulator requires at least 20Kb of memory!\n");
+		return 0;
+	}
+
+	M.mem_base = (unsigned long)malloc(memSize);
+
+	if (M.mem_base == NULL){
+		printf("Biosemu:Out of memory!");
+		return 0;
+	}
+	M.mem_size = memSize;
+
+	_BE_env.emulateVGA = 0;
+	_BE_env.busmem_base = (unsigned long)malloc(128 * 1024);
+	if (_BE_env.busmem_base == NULL){
+		printf("Biosemu:Out of memory!");
+		return 0;
+	}
+	M.x86.debug = debugFlags;
+	_BE_bios_init((u32*)info->LowMem);
+	X86EMU_setupMemFuncs(&_BE_mem);
+	X86EMU_setupPioFuncs(&_BE_pio);
+	BE_setVGA(info);
+	return 1;
+}
+
+/****************************************************************************
+PARAMETERS:
+info	    - Pointer to VGA device information to make current
+
+REMARKS:
+This function sets the VGA BIOS functions in the emulator to point to the
+specific VGA BIOS in use. This includes swapping the BIOS interrupt
+vectors, BIOS image and BIOS data area to the new BIOS. This allows the
+real mode BIOS to be swapped without resetting the entire emulator.
+****************************************************************************/
+void X86API BE_setVGA(BE_VGAInfo * info)
+{
+
+#ifdef __KERNEL__
+	_BE_env.vgaInfo.function = info->function;
+	_BE_env.vgaInfo.device = info->device;
+	_BE_env.vgaInfo.bus = info->bus;
+	_BE_env.vgaInfo.pcidev = info->pcidev;
+#else
+	_BE_env.vgaInfo.pciInfo = info->pciInfo;
+#endif
+	_BE_env.vgaInfo.BIOSImage = info->BIOSImage;
+	if (info->BIOSImage) {
+		_BE_env.biosmem_base = (ulong) info->BIOSImage;
+		_BE_env.biosmem_limit = 0xC0000 + info->BIOSImageLen - 1;
+	} else {
+		_BE_env.biosmem_base = _BE_env.busmem_base + 0x20000;
+		_BE_env.biosmem_limit = 0xC7FFF;
+	}
+	if (*((u32 *) info->LowMem) == 0)
+		_BE_bios_init((u32 *) info->LowMem);
+	memcpy((u8 *) M.mem_base, info->LowMem, sizeof(info->LowMem));
+}
+
+/****************************************************************************
+PARAMETERS:
+info	    - Pointer to VGA device information to retrieve current
+
+REMARKS:
+This function returns the VGA BIOS functions currently active in the
+emulator, so they can be restored at a later date.
+****************************************************************************/
+void X86API BE_getVGA(BE_VGAInfo * info)
+{
+#ifdef __KERNEL__
+	info->function = _BE_env.vgaInfo.function;
+	info->device = _BE_env.vgaInfo.device;
+	info->bus = _BE_env.vgaInfo.bus;
+	info->pcidev = _BE_env.vgaInfo.pcidev;
+#else
+	info->pciInfo = _BE_env.vgaInfo.pciInfo;
+#endif
+	info->BIOSImage = _BE_env.vgaInfo.BIOSImage;
+	memcpy(info->LowMem, (u8 *) M.mem_base, sizeof(info->LowMem));
+}
+
+/****************************************************************************
+PARAMETERS:
+r_seg	- Segment for pointer to convert
+r_off	- Offset for pointer to convert
+
+REMARKS:
+This function maps a real mode pointer in the emulator memory to a protected
+mode pointer that can be used to directly access the memory.
+
+NOTE:	The memory is *always* in little endian format, son on non-x86
+	systems you will need to do endian translations to access this
+	memory.
+****************************************************************************/
+void *X86API BE_mapRealPointer(uint r_seg, uint r_off)
+{
+	u32 addr = ((u32) r_seg << 4) + r_off;
+
+	if (addr >= 0xC0000 && addr <= _BE_env.biosmem_limit) {
+		return (void *)(_BE_env.biosmem_base + addr - 0xC0000);
+	} else if (addr >= 0xA0000 && addr <= 0xFFFFF) {
+		return (void *)(_BE_env.busmem_base + addr - 0xA0000);
+	}
+	return (void *)(M.mem_base + addr);
+}
+
+/****************************************************************************
+PARAMETERS:
+len	- Return the length of the VESA buffer
+rseg	- Place to store VESA buffer segment
+roff	- Place to store VESA buffer offset
+
+REMARKS:
+This function returns the address of the VESA transfer buffer in real
+_BE_piomode emulator memory. The VESA transfer buffer is always 1024 bytes long,
+and located at 15Kb into the start of the real mode memory (16Kb is where
+we put the real mode code we execute for issuing interrupts).
+
+NOTE:	The memory is *always* in little endian format, son on non-x86
+	systems you will need to do endian translations to access this
+	memory.
+****************************************************************************/
+void *X86API BE_getVESABuf(uint * len, uint * rseg, uint * roff)
+{
+	*len = 1024;
+	*rseg = SEG(0x03C00);
+	*roff = OFF(0x03C00);
+	return (void *)(M.mem_base + ((u32) * rseg << 4) + *roff);
+}
+
+/****************************************************************************
+REMARKS:
+Cleans up and exits the emulator.
+****************************************************************************/
+void X86API BE_exit(void)
+{
+	free(M.mem_base);
+	free(_BE_env.busmem_base);
+}
+
+/****************************************************************************
+PARAMETERS:
+seg	- Segment of code to call
+off	- Offset of code to call
+regs	- Real mode registers to load
+sregs	- Real mode segment registers to load
+
+REMARKS:
+This functions calls a real mode far function at the specified address,
+and loads all the x86 registers from the passed in registers structure.
+On exit the registers returned from the call are returned in the same
+structures.
+****************************************************************************/
+void X86API BE_callRealMode(uint seg, uint off, RMREGS * regs, RMSREGS * sregs)
+{
+	M.x86.R_EAX = regs->e.eax;
+	M.x86.R_EBX = regs->e.ebx;
+	M.x86.R_ECX = regs->e.ecx;
+	M.x86.R_EDX = regs->e.edx;
+	M.x86.R_ESI = regs->e.esi;
+	M.x86.R_EDI = regs->e.edi;
+	M.x86.R_DS = sregs->ds;
+	M.x86.R_ES = sregs->es;
+	M.x86.R_FS = sregs->fs;
+	M.x86.R_GS = sregs->gs;
+
+	((u8 *) M.mem_base)[0x4000] = 0x9A;
+	((u8 *) M.mem_base)[0x4001] = (u8) off;
+	((u8 *) M.mem_base)[0x4002] = (u8) (off >> 8);
+	((u8 *) M.mem_base)[0x4003] = (u8) seg;
+	((u8 *) M.mem_base)[0x4004] = (u8) (seg >> 8);
+	((u8 *) M.mem_base)[0x4005] = 0xF1;	/* Illegal op-code */
+	M.x86.R_CS = SEG(0x04000);
+	M.x86.R_IP = OFF(0x04000);
+
+	M.x86.R_SS = SEG(M.mem_size - 2);
+	M.x86.R_SP = OFF(M.mem_size - 2) + 2;
+
+	X86EMU_exec();
+
+	regs->e.cflag = M.x86.R_EFLG & F_CF;
+	regs->e.eax = M.x86.R_EAX;
+	regs->e.ebx = M.x86.R_EBX;
+	regs->e.ecx = M.x86.R_ECX;
+	regs->e.edx = M.x86.R_EDX;
+	regs->e.esi = M.x86.R_ESI;
+	regs->e.edi = M.x86.R_EDI;
+	sregs->ds = M.x86.R_DS;
+	sregs->es = M.x86.R_ES;
+	sregs->fs = M.x86.R_FS;
+	sregs->gs = M.x86.R_GS;
+}
+
+/****************************************************************************
+PARAMETERS:
+intno	- Interrupt number to execute
+in	- Real mode registers to load
+out	- Place to store resulting real mode registers
+
+REMARKS:
+This functions calls a real mode interrupt function at the specified address,
+and loads all the x86 registers from the passed in registers structure.
+On exit the registers returned from the call are returned in out stucture.
+****************************************************************************/
+int X86API BE_int86(int intno, RMREGS * in, RMREGS * out)
+{
+	M.x86.R_EAX = in->e.eax;
+	M.x86.R_EBX = in->e.ebx;
+	M.x86.R_ECX = in->e.ecx;
+	M.x86.R_EDX = in->e.edx;
+	M.x86.R_ESI = in->e.esi;
+	M.x86.R_EDI = in->e.edi;
+	((u8 *) M.mem_base)[0x4000] = 0xCD;
+	((u8 *) M.mem_base)[0x4001] = (u8) intno;
+	((u8 *) M.mem_base)[0x4002] = 0xF1;
+	M.x86.R_CS = SEG(0x04000);
+	M.x86.R_IP = OFF(0x04000);
+
+	M.x86.R_SS = SEG(M.mem_size - 1);
+	M.x86.R_SP = OFF(M.mem_size - 1) - 1;
+
+	X86EMU_exec();
+	out->e.cflag = M.x86.R_EFLG & F_CF;
+	out->e.eax = M.x86.R_EAX;
+	out->e.ebx = M.x86.R_EBX;
+	out->e.ecx = M.x86.R_ECX;
+	out->e.edx = M.x86.R_EDX;
+	out->e.esi = M.x86.R_ESI;
+	out->e.edi = M.x86.R_EDI;
+	return out->x.ax;
+}
+
+/****************************************************************************
+PARAMETERS:
+intno	- Interrupt number to execute
+in	- Real mode registers to load
+out	- Place to store resulting real mode registers
+sregs	- Real mode segment registers to load
+
+REMARKS:
+This functions calls a real mode interrupt function at the specified address,
+and loads all the x86 registers from the passed in registers structure.
+On exit the registers returned from the call are returned in out stucture.
+****************************************************************************/
+int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, RMSREGS * sregs)
+{
+	M.x86.R_EAX = in->e.eax;
+	M.x86.R_EBX = in->e.ebx;
+	M.x86.R_ECX = in->e.ecx;
+	M.x86.R_EDX = in->e.edx;
+	M.x86.R_ESI = in->e.esi;
+	M.x86.R_EDI = in->e.edi;
+	M.x86.R_DS = sregs->ds;
+	M.x86.R_ES = sregs->es;
+	M.x86.R_FS = sregs->fs;
+	M.x86.R_GS = sregs->gs;
+	((u8 *) M.mem_base)[0x4000] = 0xCD;
+	((u8 *) M.mem_base)[0x4001] = (u8) intno;
+	((u8 *) M.mem_base)[0x4002] = 0xF1;
+	M.x86.R_CS = SEG(0x04000);
+	M.x86.R_IP = OFF(0x04000);
+
+	M.x86.R_SS = SEG(M.mem_size - 1);
+	M.x86.R_SP = OFF(M.mem_size - 1) - 1;
+
+	X86EMU_exec();
+	out->e.cflag = M.x86.R_EFLG & F_CF;
+	out->e.eax = M.x86.R_EAX;
+	out->e.ebx = M.x86.R_EBX;
+	out->e.ecx = M.x86.R_ECX;
+	out->e.edx = M.x86.R_EDX;
+	out->e.esi = M.x86.R_ESI;
+	out->e.edi = M.x86.R_EDI;
+	sregs->ds = M.x86.R_DS;
+	sregs->es = M.x86.R_ES;
+	sregs->fs = M.x86.R_FS;
+	sregs->gs = M.x86.R_GS;
+	return out->x.ax;
+}
+#endif
diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h
new file mode 100644
index 0000000..e85e656
--- /dev/null
+++ b/drivers/bios_emulator/biosemui.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+*
+*			 BIOS emulator and interface
+*		       to Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*  Jason Jin <Jason.jin@freescale.com>
+*
+*		Copyright (C) 1996-1999 SciTech Software, Inc.
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	Internal header file for the BIOS emulator library.
+*
+*		Jason ported this file to u-boot, Added some architecture
+*		related Macro.
+*
+****************************************************************************/
+
+#ifndef __BIOSEMUI_H
+#define __BIOSEMUI_H
+
+#include "biosemu.h"
+#include <asm/io.h>
+/*---------------------- Macros and type definitions ----------------------*/
+
+#ifdef DEBUG
+#define DB(x)	x
+#else
+#define DB(x)	do{}while(0);
+#endif
+
+#define BIOS_SEG	0xfff0
+extern X86EMU_sysEnv _X86EMU_env;
+#define M		_X86EMU_env
+
+/* Macros to read and write values to x86 emulator memory. Memory is always
+ * considered to be little endian, so we use macros to do endian swapping
+ * where necessary.
+ */
+
+#ifdef __BIG_ENDIAN__
+#define readb_le(base)	    *((u8*)(base))
+#define readw_le(base)	    ((u16)readb_le(base) | ((u16)readb_le((base) + 1) << 8))
+#define readl_le(base)	    ((u32)readb_le((base) + 0) | ((u32)readb_le((base) + 1) << 8) | \
+			    ((u32)readb_le((base) + 2) << 16) | ((u32)readb_le((base) + 3) << 24))
+#define writeb_le(base, v)  *((u8*)(base)) = (v)
+#define writew_le(base, v)  writeb_le(base + 0, (v >> 0) & 0xff),	\
+			    writeb_le(base + 1, (v >> 8) & 0xff)
+#define writel_le(base, v)  writeb_le(base + 0, (v >> 0) & 0xff),	\
+			    writeb_le(base + 1, (v >> 8) & 0xff),	\
+			    writeb_le(base + 2, (v >> 16) & 0xff),	\
+			    writeb_le(base + 3, (v >> 24) & 0xff)
+#else
+#define readb_le(base)	    *((u8*)(base))
+#define readw_le(base)	    *((u16*)(base))
+#define readl_le(base)	    *((u32*)(base))
+#define writeb_le(base, v)  *((u8*)(base)) = (v)
+#define writew_le(base, v)  *((u16*)(base)) = (v)
+#define writel_le(base, v)  *((u32*)(base)) = (v)
+#endif
+
+/****************************************************************************
+REMARKS:
+Function codes passed to the emulated I/O port functions to determine the
+type of operation to perform.
+****************************************************************************/
+typedef enum {
+	REG_READ_BYTE = 0,
+	REG_READ_WORD = 1,
+	REG_READ_DWORD = 2,
+	REG_WRITE_BYTE = 3,
+	REG_WRITE_WORD = 4,
+	REG_WRITE_DWORD = 5
+} RegisterFlags;
+
+/****************************************************************************
+REMARKS:
+Function codes passed to the emulated I/O port functions to determine the
+type of operation to perform.
+****************************************************************************/
+typedef enum {
+	PORT_BYTE = 1,
+	PORT_WORD = 2,
+	PORT_DWORD = 3,
+} PortInfoFlags;
+
+/****************************************************************************
+REMARKS:
+Data structure used to describe the details for the BIOS emulator system
+environment as used by the X86 emulator library.
+
+HEADER:
+biosemu.h
+
+MEMBERS:
+type	    - Type of port access (1 = byte, 2 = word, 3 = dword)
+defVal	    - Default power on value
+finalVal    - Final value
+****************************************************************************/
+typedef struct {
+	u8 type;
+	u32 defVal;
+	u32 finalVal;
+} BE_portInfo;
+
+#define PM_inpb(port)	inb(port+VIDEO_IO_OFFSET)
+#define PM_inpw(port)	inw(port+VIDEO_IO_OFFSET)
+#define PM_inpd(port)	inl(port+VIDEO_IO_OFFSET)
+#define PM_outpb(port,val)	outb(val,port+VIDEO_IO_OFFSET)
+#define PM_outpw(port,val)	outw(val,port+VIDEO_IO_OFFSET)
+#define PM_outpd(port,val)	outl(val,port+VIDEO_IO_OFFSET)
+
+#define LOG_inpb(port)	PM_inpb(port)
+#define LOG_inpw(port)	PM_inpw(port)
+#define LOG_inpd(port)	PM_inpd(port)
+#define LOG_outpb(port,val)	PM_outpb(port,val)
+#define LOG_outpw(port,val)	PM_outpw(port,val)
+#define LOG_outpd(port,val)	PM_outpd(port,val)
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+/* bios.c */
+
+void _BE_bios_init(u32 * intrTab);
+void _BE_setup_funcs(void);
+
+/* besys.c */
+#define DEBUG_IO()	(M.x86.debug & DEBUG_IO_TRACE_F)
+
+u8 X86API BE_rdb(u32 addr);
+u16 X86API BE_rdw(u32 addr);
+u32 X86API BE_rdl(u32 addr);
+void X86API BE_wrb(u32 addr, u8 val);
+void X86API BE_wrw(u32 addr, u16 val);
+void X86API BE_wrl(u32 addr, u32 val);
+
+u8 X86API BE_inb(X86EMU_pioAddr port);
+u16 X86API BE_inw(X86EMU_pioAddr port);
+u32 X86API BE_inl(X86EMU_pioAddr port);
+void X86API BE_outb(X86EMU_pioAddr port, u8 val);
+void X86API BE_outw(X86EMU_pioAddr port, u16 val);
+void X86API BE_outl(X86EMU_pioAddr port, u32 val);
+#endif
+/* __BIOSEMUI_H */
diff --git a/drivers/bios_emulator/include/biosemu.h b/drivers/bios_emulator/include/biosemu.h
new file mode 100644
index 0000000..13cb317
--- /dev/null
+++ b/drivers/bios_emulator/include/biosemu.h
@@ -0,0 +1,392 @@
+/****************************************************************************
+*
+*                        BIOS emulator and interface
+*                      to Realmode X86 Emulator Library
+*
+*               Copyright (C) 1996-1999 SciTech Software, Inc.
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for the real mode x86 BIOS emulator, which is
+*               used to warmboot any number of VGA compatible PCI/AGP
+*               controllers under any OS, on any processor family that
+*               supports PCI. We also allow the user application to call
+*               real mode BIOS functions and Int 10h functions (including
+*               the VESA BIOS).
+*
+****************************************************************************/
+
+#ifndef __BIOSEMU_H
+#define __BIOSEMU_H
+
+#ifdef __KERNEL__
+#include "x86emu.h"
+#else
+#include "x86emu.h"
+#include "pmapi.h"
+#include "pcilib.h"
+#endif
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+#ifndef __KERNEL__
+/****************************************************************************
+REMARKS:
+Data structure used to describe the details specific to a particular VGA
+controller. This information is used to allow the VGA controller to be
+swapped on the fly within the BIOS emulator.
+
+HEADER:
+biosemu.h
+
+MEMBERS:
+pciInfo         - PCI device information block for the controller
+BIOSImage       - Pointer to a read/write copy of the BIOS image
+BIOSImageLen    - Length of the BIOS image
+LowMem          - Copy of key low memory areas
+****************************************************************************/
+typedef struct {
+	PCIDeviceInfo *pciInfo;
+	void *BIOSImage;
+	ulong BIOSImageLen;
+	uchar LowMem[1536];
+} BE_VGAInfo;
+#else
+/****************************************************************************
+REMARKS:
+Data structure used to describe the details for the BIOS emulator system
+environment as used by the X86 emulator library.
+
+HEADER:
+biosemu.h
+
+MEMBERS:
+vgaInfo         - VGA BIOS information structure
+biosmem_base    - Base of the BIOS image
+biosmem_limit   - Limit of the BIOS image
+busmem_base     - Base of the VGA bus memory
+****************************************************************************/
+typedef struct {
+	int function;
+	int device;
+	int bus;
+	u32 VendorID;
+	u32 DeviceID;
+	pci_dev_t pcidev;
+	void *BIOSImage;
+	u32 BIOSImageLen;
+	u8 LowMem[1536];
+} BE_VGAInfo;
+
+#endif				/* __KERNEL__ */
+
+#define CRT_C   24		/* 24  CRT Controller Registers             */
+#define ATT_C   21		/* 21  Attribute Controller Registers       */
+#define GRA_C   9		/* 9   Graphics Controller Registers        */
+#define SEQ_C   5		/* 5   Sequencer Registers                  */
+#define PAL_C   768		/* 768 Palette Registers                    */
+
+/****************************************************************************
+REMARKS:
+Data structure used to describe the details for the BIOS emulator system
+environment as used by the X86 emulator library.
+
+HEADER:
+biosemu.h
+
+MEMBERS:
+vgaInfo         - VGA BIOS information structure
+biosmem_base    - Base of the BIOS image
+biosmem_limit   - Limit of the BIOS image
+busmem_base     - Base of the VGA bus memory
+timer           - Timer used to emulate PC timer ports
+timer0          - Latched value for timer 0
+timer0Latched   - True if timer 0 value was just latched
+timer2          - Current value for timer 2
+emulateVGA      - True to emulate VGA I/O and memory accesses
+****************************************************************************/
+
+typedef struct {
+	BE_VGAInfo vgaInfo;
+	ulong biosmem_base;
+	ulong biosmem_limit;
+	ulong busmem_base;
+
+	u32 timer0;
+	int timer0Latched;
+	u32 timer1;
+	int timer1Latched;
+	u32 timer2;
+	int timer2Latched;
+
+	int emulateVGA;
+	u8 emu61;
+	u8 emu70;
+	int flipFlop3C0;
+	u32 configAddress;
+	u8 emu3C0;
+	u8 emu3C1[ATT_C];
+	u8 emu3C2;
+	u8 emu3C4;
+	u8 emu3C5[SEQ_C];
+	u8 emu3C6;
+	uint emu3C7;
+	uint emu3C8;
+	u8 emu3C9[PAL_C];
+	u8 emu3CE;
+	u8 emu3CF[GRA_C];
+	u8 emu3D4;
+	u8 emu3D5[CRT_C];
+	u8 emu3DA;
+
+} BE_sysEnv;
+
+#ifdef __KERNEL__
+
+/* Define some types when compiling for the Linux kernel that normally
+ * come from the SciTech PM library.
+ */
+
+/****************************************************************************
+REMARKS:
+Structure describing the 32-bit extended x86 CPU registers
+
+HEADER:
+pmapi.h
+
+MEMBERS:
+eax     - Value of the EAX register
+ebx     - Value of the EBX register
+ecx     - Value of the ECX register
+edx     - Value of the EDX register
+esi     - Value of the ESI register
+edi     - Value of the EDI register
+cflag   - Value of the carry flag
+****************************************************************************/
+typedef struct {
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+	u32 esi;
+	u32 edi;
+	u32 cflag;
+} RMDWORDREGS;
+
+/****************************************************************************
+REMARKS:
+Structure describing the 16-bit x86 CPU registers
+
+HEADER:
+pmapi.h
+
+MEMBERS:
+ax      - Value of the AX register
+bx      - Value of the BX register
+cx      - Value of the CX register
+dx      - Value of the DX register
+si      - Value of the SI register
+di      - Value of the DI register
+cflag   - Value of the carry flag
+****************************************************************************/
+#ifdef __BIG_ENDIAN__
+typedef struct {
+	u16 ax_hi, ax;
+	u16 bx_hi, bx;
+	u16 cx_hi, cx;
+	u16 dx_hi, dx;
+	u16 si_hi, si;
+	u16 di_hi, di;
+	u16 cflag_hi, cflag;
+} RMWORDREGS;
+#else
+typedef struct {
+	u16 ax, ax_hi;
+	u16 bx, bx_hi;
+	u16 cx, cx_hi;
+	u16 dx, dx_hi;
+	u16 si, si_hi;
+	u16 di, di_hi;
+	u16 cflag, cflag_hi;
+} RMWORDREGS;
+#endif
+
+/****************************************************************************
+REMARKS:
+Structure describing the 8-bit x86 CPU registers
+
+HEADER:
+pmapi.h
+
+MEMBERS:
+al      - Value of the AL register
+ah      - Value of the AH register
+bl      - Value of the BL register
+bh      - Value of the BH register
+cl      - Value of the CL register
+ch      - Value of the CH register
+dl      - Value of the DL register
+dh      - Value of the DH register
+****************************************************************************/
+#ifdef __BIG_ENDIAN__
+typedef struct {
+	u16 ax_hi;
+	u8 ah, al;
+	u16 bx_hi;
+	u8 bh, bl;
+	u16 cx_hi;
+	u8 ch, cl;
+	u16 dx_hi;
+	u8 dh, dl;
+} RMBYTEREGS;
+#else
+typedef struct {
+	u8 al;
+	u8 ah;
+	u16 ax_hi;
+	u8 bl;
+	u8 bh;
+	u16 bx_hi;
+	u8 cl;
+	u8 ch;
+	u16 cx_hi;
+	u8 dl;
+	u8 dh;
+	u16 dx_hi;
+} RMBYTEREGS;
+#endif
+
+/****************************************************************************
+REMARKS:
+Structure describing all the x86 CPU registers
+
+HEADER:
+pmapi.h
+
+MEMBERS:
+e   - Member to access registers as 32-bit values
+x   - Member to access registers as 16-bit values
+h   - Member to access registers as 8-bit values
+****************************************************************************/
+typedef union {
+	RMDWORDREGS e;
+	RMWORDREGS x;
+	RMBYTEREGS h;
+} RMREGS;
+
+/****************************************************************************
+REMARKS:
+Structure describing all the x86 segment registers
+
+HEADER:
+pmapi.h
+
+MEMBERS:
+es  - ES segment register
+cs  - CS segment register
+ss  - SS segment register
+ds  - DS segment register
+fs  - FS segment register
+gs  - GS segment register
+****************************************************************************/
+typedef struct {
+	u16 es;
+	u16 cs;
+	u16 ss;
+	u16 ds;
+	u16 fs;
+	u16 gs;
+} RMSREGS;
+
+#endif				/* __KERNEL__ */
+
+#ifndef __KERNEL__
+
+/****************************************************************************
+REMARKS:
+Structure defining all the BIOS Emulator API functions as exported from
+the Binary Portable DLL.
+{secret}
+****************************************************************************/
+typedef struct {
+	ulong dwSize;
+	 ibool(PMAPIP BE_init) (u32 debugFlags, int memSize, BE_VGAInfo * info);
+	void (PMAPIP BE_setVGA) (BE_VGAInfo * info);
+	void (PMAPIP BE_getVGA) (BE_VGAInfo * info);
+	void *(PMAPIP BE_mapRealPointer) (uint r_seg, uint r_off);
+	void *(PMAPIP BE_getVESABuf) (uint * len, uint * rseg, uint * roff);
+	void (PMAPIP BE_callRealMode) (uint seg, uint off, RMREGS * regs,
+				       RMSREGS * sregs);
+	int (PMAPIP BE_int86) (int intno, RMREGS * in, RMREGS * out);
+	int (PMAPIP BE_int86x) (int intno, RMREGS * in, RMREGS * out,
+				RMSREGS * sregs);
+	void *reserved1;
+	void (PMAPIP BE_exit) (void);
+} BE_exports;
+
+/****************************************************************************
+REMARKS:
+Function pointer type for the Binary Portable DLL initialisation entry point.
+{secret}
+****************************************************************************/
+typedef BE_exports *(PMAPIP BE_initLibrary_t) (PM_imports * PMImp);
+#endif
+
+#pragma pack()
+
+/*---------------------------- Global variables ---------------------------*/
+
+#ifdef  __cplusplus
+extern "C" {			/* Use "C" linkage when in C++ mode */
+#endif
+
+/* {secret} Global BIOS emulator system environment */
+	extern BE_sysEnv _BE_env;
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+/* BIOS emulator library entry points */
+	int X86API BE_init(u32 debugFlags, int memSize, BE_VGAInfo * info,
+			   int shared);
+	void X86API BE_setVGA(BE_VGAInfo * info);
+	void X86API BE_getVGA(BE_VGAInfo * info);
+	void X86API BE_setDebugFlags(u32 debugFlags);
+	void *X86API BE_mapRealPointer(uint r_seg, uint r_off);
+	void *X86API BE_getVESABuf(uint * len, uint * rseg, uint * roff);
+	void X86API BE_callRealMode(uint seg, uint off, RMREGS * regs,
+				    RMSREGS * sregs);
+	int X86API BE_int86(int intno, RMREGS * in, RMREGS * out);
+	int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out,
+			     RMSREGS * sregs);
+	void X86API BE_exit(void);
+
+#ifdef  __cplusplus
+}				/* End of "C" linkage for C++       */
+#endif
+#endif				/* __BIOSEMU_H */
diff --git a/drivers/bios_emulator/include/x86emu.h b/drivers/bios_emulator/include/x86emu.h
new file mode 100644
index 0000000..6004beb
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1996-1999 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for public specific functions.
+*               Any application linking against us should only
+*               include this header
+*
+****************************************************************************/
+
+#ifndef __X86EMU_X86EMU_H
+#define __X86EMU_X86EMU_H
+
+#include <asm/types.h>
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#define X86API
+#define X86APIP *
+typedef u16 X86EMU_pioAddr;
+
+#include "x86emu/regs.h"
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/****************************************************************************
+REMARKS:
+Data structure containing ponters to programmed I/O functions used by the
+emulator. This is used so that the user program can hook all programmed
+I/O for the emulator to handled as necessary by the user program. By
+default the emulator contains simple functions that do not do access the
+hardware in any way. To allow the emualtor access the hardware, you will
+need to override the programmed I/O functions using the X86EMU_setupPioFuncs
+function.
+
+HEADER:
+x86emu.h
+
+MEMBERS:
+inb     - Function to read a byte from an I/O port
+inw     - Function to read a word from an I/O port
+inl     - Function to read a dword from an I/O port
+outb    - Function to write a byte to an I/O port
+outw    - Function to write a word to an I/O port
+outl    - Function to write a dword to an I/O port
+****************************************************************************/
+typedef struct {
+	u8(X86APIP inb) (X86EMU_pioAddr addr);
+	u16(X86APIP inw) (X86EMU_pioAddr addr);
+	u32(X86APIP inl) (X86EMU_pioAddr addr);
+	void (X86APIP outb) (X86EMU_pioAddr addr, u8 val);
+	void (X86APIP outw) (X86EMU_pioAddr addr, u16 val);
+	void (X86APIP outl) (X86EMU_pioAddr addr, u32 val);
+} X86EMU_pioFuncs;
+
+/****************************************************************************
+REMARKS:
+Data structure containing ponters to memory access functions used by the
+emulator. This is used so that the user program can hook all memory
+access functions as necessary for the emulator. By default the emulator
+contains simple functions that only access the internal memory of the
+emulator. If you need specialised functions to handle access to different
+types of memory (ie: hardware framebuffer accesses and BIOS memory access
+etc), you will need to override this using the X86EMU_setupMemFuncs
+function.
+
+HEADER:
+x86emu.h
+
+MEMBERS:
+rdb     - Function to read a byte from an address
+rdw     - Function to read a word from an address
+rdl     - Function to read a dword from an address
+wrb     - Function to write a byte to an address
+wrw     - Function to write a word to an address
+wrl     - Function to write a dword to an address
+****************************************************************************/
+typedef struct {
+	u8(X86APIP rdb) (u32 addr);
+	u16(X86APIP rdw) (u32 addr);
+	u32(X86APIP rdl) (u32 addr);
+	void (X86APIP wrb) (u32 addr, u8 val);
+	void (X86APIP wrw) (u32 addr, u16 val);
+	void (X86APIP wrl) (u32 addr, u32 val);
+} X86EMU_memFuncs;
+
+/****************************************************************************
+  Here are the default memory read and write
+  function in case they are needed as fallbacks.
+***************************************************************************/
+extern u8 X86API rdb(u32 addr);
+extern u16 X86API rdw(u32 addr);
+extern u32 X86API rdl(u32 addr);
+extern void X86API wrb(u32 addr, u8 val);
+extern void X86API wrw(u32 addr, u16 val);
+extern void X86API wrl(u32 addr, u32 val);
+
+#pragma pack()
+
+/*--------------------- type definitions -----------------------------------*/
+
+typedef void (X86APIP X86EMU_intrFuncs) (int num);
+extern X86EMU_intrFuncs _X86EMU_intrTab[256];
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef  __cplusplus
+extern "C" {			/* Use "C" linkage when in C++ mode */
+#endif
+
+	void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs);
+	void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs);
+	void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[]);
+	void X86EMU_prepareForInt(int num);
+
+/* decode.c */
+
+	void X86EMU_exec(void);
+	void X86EMU_halt_sys(void);
+
+#ifdef  DEBUG
+#define HALT_SYS()  \
+    printf("halt_sys: file %s, line %d\n", __FILE__, __LINE__), \
+    X86EMU_halt_sys()
+#else
+#define HALT_SYS()  X86EMU_halt_sys()
+#endif
+
+/* Debug options */
+
+#define DEBUG_DECODE_F          0x0001	/* print decoded instruction  */
+#define DEBUG_TRACE_F           0x0002	/* dump regs before/after execution */
+#define DEBUG_STEP_F            0x0004
+#define DEBUG_DISASSEMBLE_F     0x0008
+#define DEBUG_BREAK_F           0x0010
+#define DEBUG_SVC_F             0x0020
+#define DEBUG_SAVE_CS_IP        0x0040
+#define DEBUG_FS_F              0x0080
+#define DEBUG_PROC_F            0x0100
+#define DEBUG_SYSINT_F          0x0200	/* bios system interrupts. */
+#define DEBUG_TRACECALL_F       0x0400
+#define DEBUG_INSTRUMENT_F      0x0800
+#define DEBUG_MEM_TRACE_F       0x1000
+#define DEBUG_IO_TRACE_F        0x2000
+#define DEBUG_TRACECALL_REGS_F  0x4000
+#define DEBUG_DECODE_NOPRINT_F  0x8000
+#define DEBUG_EXIT              0x10000
+#define DEBUG_SYS_F             (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F)
+
+	void X86EMU_trace_regs(void);
+	void X86EMU_trace_xregs(void);
+	void X86EMU_dump_memory(u16 seg, u16 off, u32 amt);
+	int X86EMU_trace_on(void);
+	int X86EMU_trace_off(void);
+
+#ifdef  __cplusplus
+}				/* End of "C" linkage for C++       */
+#endif
+#endif				/* __X86EMU_X86EMU_H */
diff --git a/drivers/bios_emulator/include/x86emu/debug.h b/drivers/bios_emulator/include/x86emu/debug.h
new file mode 100644
index 0000000..268c9d3
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/debug.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+*
+*			Realmode X86 Emulator Library
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*		     Copyright (C) David Mosberger-Tang
+*		       Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	Header file for debug definitions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_DEBUG_H
+#define __X86EMU_DEBUG_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* checks to be enabled for "runtime" */
+
+#define CHECK_IP_FETCH_F		0x1
+#define CHECK_SP_ACCESS_F		0x2
+#define CHECK_MEM_ACCESS_F		0x4	/*using regular linear pointer */
+#define CHECK_DATA_ACCESS_F		0x8	/*using segment:offset */
+
+#ifdef DEBUG
+# define CHECK_IP_FETCH()		(M.x86.check & CHECK_IP_FETCH_F)
+# define CHECK_SP_ACCESS()		(M.x86.check & CHECK_SP_ACCESS_F)
+# define CHECK_MEM_ACCESS()		(M.x86.check & CHECK_MEM_ACCESS_F)
+# define CHECK_DATA_ACCESS()		(M.x86.check & CHECK_DATA_ACCESS_F)
+#else
+# define CHECK_IP_FETCH()
+# define CHECK_SP_ACCESS()
+# define CHECK_MEM_ACCESS()
+# define CHECK_DATA_ACCESS()
+#endif
+
+#ifdef DEBUG
+# define DEBUG_INSTRUMENT()	(M.x86.debug & DEBUG_INSTRUMENT_F)
+# define DEBUG_DECODE()		(M.x86.debug & DEBUG_DECODE_F)
+# define DEBUG_TRACE()		(M.x86.debug & DEBUG_TRACE_F)
+# define DEBUG_STEP()		(M.x86.debug & DEBUG_STEP_F)
+# define DEBUG_DISASSEMBLE()	(M.x86.debug & DEBUG_DISASSEMBLE_F)
+# define DEBUG_BREAK()		(M.x86.debug & DEBUG_BREAK_F)
+# define DEBUG_SVC()		(M.x86.debug & DEBUG_SVC_F)
+# define DEBUG_SAVE_IP_CS()	(M.x86.debug & DEBUG_SAVE_CS_IP)
+
+# define DEBUG_FS()		(M.x86.debug & DEBUG_FS_F)
+# define DEBUG_PROC()		(M.x86.debug & DEBUG_PROC_F)
+# define DEBUG_SYSINT()		(M.x86.debug & DEBUG_SYSINT_F)
+# define DEBUG_TRACECALL()	(M.x86.debug & DEBUG_TRACECALL_F)
+# define DEBUG_TRACECALLREGS()	(M.x86.debug & DEBUG_TRACECALL_REGS_F)
+# define DEBUG_SYS()		(M.x86.debug & DEBUG_SYS_F)
+# define DEBUG_MEM_TRACE()	(M.x86.debug & DEBUG_MEM_TRACE_F)
+# define DEBUG_IO_TRACE()	(M.x86.debug & DEBUG_IO_TRACE_F)
+# define DEBUG_DECODE_NOPRINT() (M.x86.debug & DEBUG_DECODE_NOPRINT_F)
+#else
+# define DEBUG_INSTRUMENT()	0
+# define DEBUG_DECODE()		0
+# define DEBUG_TRACE()		0
+# define DEBUG_STEP()		0
+# define DEBUG_DISASSEMBLE()	0
+# define DEBUG_BREAK()		0
+# define DEBUG_SVC()		0
+# define DEBUG_SAVE_IP_CS()	0
+# define DEBUG_FS()		0
+# define DEBUG_PROC()		0
+# define DEBUG_SYSINT()		0
+# define DEBUG_TRACECALL()	0
+# define DEBUG_TRACECALLREGS()	0
+# define DEBUG_SYS()		0
+# define DEBUG_MEM_TRACE()	0
+# define DEBUG_IO_TRACE()	0
+# define DEBUG_DECODE_NOPRINT() 0
+#endif
+
+#ifdef DEBUG
+
+# define DECODE_PRINTF(x)	if (DEBUG_DECODE()) \
+				    x86emu_decode_printf(x)
+# define DECODE_PRINTF2(x,y)	if (DEBUG_DECODE()) \
+				    x86emu_decode_printf2(x,y)
+
+/*
+ * The following allow us to look at the bytes of an instruction.  The
+ * first INCR_INSTRN_LEN, is called everytime bytes are consumed in
+ * the decoding process.  The SAVE_IP_CS is called initially when the
+ * major opcode of the instruction is accessed.
+ */
+#define INC_DECODED_INST_LEN(x)			    \
+    if (DEBUG_DECODE())				    \
+	x86emu_inc_decoded_inst_len(x)
+
+#define SAVE_IP_CS(x,y)						\
+    if (DEBUG_DECODE() | DEBUG_TRACECALL() | DEBUG_BREAK() \
+	      | DEBUG_IO_TRACE() | DEBUG_SAVE_IP_CS()) { \
+	M.x86.saved_cs = x;					\
+	M.x86.saved_ip = y;					\
+    }
+#else
+# define INC_DECODED_INST_LEN(x)
+# define DECODE_PRINTF(x)
+# define DECODE_PRINTF2(x,y)
+# define SAVE_IP_CS(x,y)
+#endif
+
+#ifdef DEBUG
+#define TRACE_REGS()					    \
+    if (DEBUG_DISASSEMBLE()) {				    \
+	x86emu_just_disassemble();			    \
+	goto EndOfTheInstructionProcedure;		    \
+    }							    \
+    if (DEBUG_TRACE() || DEBUG_DECODE()) X86EMU_trace_regs()
+#else
+# define TRACE_REGS()
+#endif
+
+#ifdef DEBUG
+# define SINGLE_STEP()	    if (DEBUG_STEP()) x86emu_single_step()
+#else
+# define SINGLE_STEP()
+#endif
+
+#define TRACE_AND_STEP()    \
+    TRACE_REGS();	    \
+    SINGLE_STEP()
+
+#ifdef DEBUG
+# define START_OF_INSTR()
+# define END_OF_INSTR()	    EndOfTheInstructionProcedure: x86emu_end_instr();
+# define END_OF_INSTR_NO_TRACE()    x86emu_end_instr();
+#else
+# define START_OF_INSTR()
+# define END_OF_INSTR()
+# define END_OF_INSTR_NO_TRACE()
+#endif
+
+#ifdef DEBUG
+# define  CALL_TRACE(u,v,w,x,s)					\
+    if (DEBUG_TRACECALLREGS())					\
+	x86emu_dump_regs();					\
+    if (DEBUG_TRACECALL())					\
+	printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x);
+# define RETURN_TRACE(n,u,v)					\
+    if (DEBUG_TRACECALLREGS())					\
+	x86emu_dump_regs();					\
+    if (DEBUG_TRACECALL())					\
+	printk("%04x:%04x: %s\n",u,v,n);
+#else
+# define CALL_TRACE(u,v,w,x,s)
+# define RETURN_TRACE(n,u,v)
+#endif
+
+#ifdef DEBUG
+#define DB(x)	x
+#else
+#define DB(x)
+#endif
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef	__cplusplus
+extern "C" {			/* Use "C" linkage when in C++ mode */
+#endif
+
+	extern void x86emu_inc_decoded_inst_len(int x);
+	extern void x86emu_decode_printf(char *x);
+	extern void x86emu_decode_printf2(char *x, int y);
+	extern void x86emu_just_disassemble(void);
+	extern void x86emu_single_step(void);
+	extern void x86emu_end_instr(void);
+	extern void x86emu_dump_regs(void);
+	extern void x86emu_dump_xregs(void);
+	extern void x86emu_print_int_vect(u16 iv);
+	extern void x86emu_instrument_instruction(void);
+	extern void x86emu_check_ip_access(void);
+	extern void x86emu_check_sp_access(void);
+	extern void x86emu_check_mem_access(u32 p);
+	extern void x86emu_check_data_access(uint s, uint o);
+
+#ifdef	__cplusplus
+}				/* End of "C" linkage for C++	    */
+#endif
+#endif				/* __X86EMU_DEBUG_H */
diff --git a/drivers/bios_emulator/include/x86emu/decode.h b/drivers/bios_emulator/include/x86emu/decode.h
new file mode 100644
index 0000000..77769f0
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/decode.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for instruction decoding logic.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_DECODE_H
+#define __X86EMU_DECODE_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+/* Instruction Decoding Stuff */
+
+#define FETCH_DECODE_MODRM(mod,rh,rl)   fetch_decode_modrm(&mod,&rh,&rl)
+#define DECODE_RM_BYTE_REGISTER(r)      decode_rm_byte_register(r)
+#define DECODE_RM_WORD_REGISTER(r)      decode_rm_word_register(r)
+#define DECODE_RM_LONG_REGISTER(r)      decode_rm_long_register(r)
+#define DECODE_CLEAR_SEGOVR()           M.x86.mode &= ~SYSMODE_CLRMASK
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+#ifdef  __cplusplus
+extern "C" {                        /* Use "C" linkage when in C++ mode */
+#endif
+
+void    x86emu_intr_raise (u8 type);
+void    fetch_decode_modrm (int *mod,int *regh,int *regl);
+u8      fetch_byte_imm (void);
+u16     fetch_word_imm (void);
+u32     fetch_long_imm (void);
+u8      fetch_data_byte (uint offset);
+u8      fetch_data_byte_abs (uint segment, uint offset);
+u16     fetch_data_word (uint offset);
+u16     fetch_data_word_abs (uint segment, uint offset);
+u32     fetch_data_long (uint offset);
+u32     fetch_data_long_abs (uint segment, uint offset);
+void    store_data_byte (uint offset, u8 val);
+void    store_data_byte_abs (uint segment, uint offset, u8 val);
+void    store_data_word (uint offset, u16 val);
+void    store_data_word_abs (uint segment, uint offset, u16 val);
+void    store_data_long (uint offset, u32 val);
+void    store_data_long_abs (uint segment, uint offset, u32 val);
+u8*     decode_rm_byte_register(int reg);
+u16*    decode_rm_word_register(int reg);
+u32*    decode_rm_long_register(int reg);
+u16*    decode_rm_seg_register(int reg);
+unsigned decode_rm00_address(int rm);
+unsigned decode_rm01_address(int rm);
+unsigned decode_rm10_address(int rm);
+unsigned decode_rmXX_address(int mod, int rm);
+
+#ifdef  __cplusplus
+}                                   /* End of "C" linkage for C++       */
+#endif
+
+#endif /* __X86EMU_DECODE_H */
diff --git a/drivers/bios_emulator/include/x86emu/ops.h b/drivers/bios_emulator/include/x86emu/ops.h
new file mode 100644
index 0000000..a4f2316
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/ops.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for operand decoding functions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_OPS_H
+#define __X86EMU_OPS_H
+
+extern void (*x86emu_optab[0x100])(u8 op1);
+extern void (*x86emu_optab2[0x100])(u8 op2);
+
+#endif /* __X86EMU_OPS_H */
diff --git a/drivers/bios_emulator/include/x86emu/prim_asm.h b/drivers/bios_emulator/include/x86emu/prim_asm.h
new file mode 100644
index 0000000..4cb4cab
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/prim_asm.h
@@ -0,0 +1,970 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     Watcom C++ 10.6 or later
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Inline assembler versions of the primitive operand
+*               functions for faster performance. At the moment this is
+*               x86 inline assembler, but these functions could be replaced
+*               with native inline assembler for each supported processor
+*               platform.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_PRIM_ASM_H
+#define __X86EMU_PRIM_ASM_H
+
+#ifdef  __WATCOMC__
+
+#ifndef VALIDATE
+#define __HAVE_INLINE_ASSEMBLER__
+#endif
+
+u32 get_flags_asm(void);
+#pragma aux get_flags_asm =         \
+    "pushf"                         \
+    "pop    eax"                    \
+    value [eax]                     \
+    modify exact [eax];
+
+u16 aaa_word_asm(u32 * flags, u16 d);
+#pragma aux aaa_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "aaa"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u16 aas_word_asm(u32 * flags, u16 d);
+#pragma aux aas_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "aas"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u16 aad_word_asm(u32 * flags, u16 d);
+#pragma aux aad_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "aad"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u16 aam_word_asm(u32 * flags, u8 d);
+#pragma aux aam_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "aam"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u8 adc_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux adc_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "adc    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 adc_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux adc_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "adc    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 adc_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux adc_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "adc    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 add_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux add_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "add    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 add_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux add_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "add    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 add_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux add_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "add    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 and_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux and_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "and    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 and_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux and_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "and    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 and_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux and_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "and    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 cmp_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux cmp_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "cmp    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 cmp_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux cmp_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "cmp    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 cmp_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux cmp_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "cmp    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 daa_byte_asm(u32 * flags, u8 d);
+#pragma aux daa_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "daa"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u8 das_byte_asm(u32 * flags, u8 d);
+#pragma aux das_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "das"                           \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u8 dec_byte_asm(u32 * flags, u8 d);
+#pragma aux dec_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "dec    al"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u16 dec_word_asm(u32 * flags, u16 d);
+#pragma aux dec_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "dec    ax"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u32 dec_long_asm(u32 * flags, u32 d);
+#pragma aux dec_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "dec    eax"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax]                \
+    value [eax]                     \
+    modify exact [eax];
+
+u8 inc_byte_asm(u32 * flags, u8 d);
+#pragma aux inc_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "inc    al"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u16 inc_word_asm(u32 * flags, u16 d);
+#pragma aux inc_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "inc    ax"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u32 inc_long_asm(u32 * flags, u32 d);
+#pragma aux inc_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "inc    eax"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax]                \
+    value [eax]                     \
+    modify exact [eax];
+
+u8 or_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux or_byte_asm =           \
+    "push   [edi]"                  \
+    "popf"                          \
+    "or al,bl"                      \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 or_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux or_word_asm =           \
+    "push   [edi]"                  \
+    "popf"                          \
+    "or ax,bx"                      \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 or_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux or_long_asm =           \
+    "push   [edi]"                  \
+    "popf"                          \
+    "or eax,ebx"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 neg_byte_asm(u32 * flags, u8 d);
+#pragma aux neg_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "neg    al"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u16 neg_word_asm(u32 * flags, u16 d);
+#pragma aux neg_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "neg    ax"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u32 neg_long_asm(u32 * flags, u32 d);
+#pragma aux neg_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "neg    eax"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax]                \
+    value [eax]                     \
+    modify exact [eax];
+
+u8 not_byte_asm(u32 * flags, u8 d);
+#pragma aux not_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "not    al"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al]                 \
+    value [al]                      \
+    modify exact [al];
+
+u16 not_word_asm(u32 * flags, u16 d);
+#pragma aux not_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "not    ax"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax]                 \
+    value [ax]                      \
+    modify exact [ax];
+
+u32 not_long_asm(u32 * flags, u32 d);
+#pragma aux not_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "not    eax"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax]                \
+    value [eax]                     \
+    modify exact [eax];
+
+u8 rcl_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux rcl_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcl    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 rcl_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux rcl_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcl    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 rcl_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux rcl_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcl    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 rcr_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux rcr_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcr    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 rcr_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux rcr_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcr    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 rcr_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux rcr_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rcr    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 rol_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux rol_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rol    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 rol_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux rol_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rol    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 rol_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux rol_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "rol    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 ror_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux ror_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "ror    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 ror_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux ror_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "ror    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 ror_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux ror_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "ror    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 shl_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux shl_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shl    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 shl_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux shl_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shl    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 shl_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux shl_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shl    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 shr_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux shr_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shr    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 shr_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux shr_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shr    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 shr_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux shr_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shr    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u8 sar_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux sar_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sar    al,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [cl]            \
+    value [al]                      \
+    modify exact [al cl];
+
+u16 sar_word_asm(u32 * flags, u16 d, u8 s);
+#pragma aux sar_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sar    ax,cl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [cl]            \
+    value [ax]                      \
+    modify exact [ax cl];
+
+u32 sar_long_asm(u32 * flags, u32 d, u8 s);
+#pragma aux sar_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sar    eax,cl"                 \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [cl]           \
+    value [eax]                     \
+    modify exact [eax cl];
+
+u16 shld_word_asm(u32 * flags, u16 d, u16 fill, u8 s);
+#pragma aux shld_word_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shld   ax,dx,cl"               \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [dx] [cl]       \
+    value [ax]                      \
+    modify exact [ax dx cl];
+
+u32 shld_long_asm(u32 * flags, u32 d, u32 fill, u8 s);
+#pragma aux shld_long_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shld   eax,edx,cl"             \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [edx] [cl]     \
+    value [eax]                     \
+    modify exact [eax edx cl];
+
+u16 shrd_word_asm(u32 * flags, u16 d, u16 fill, u8 s);
+#pragma aux shrd_word_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shrd   ax,dx,cl"               \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [dx] [cl]       \
+    value [ax]                      \
+    modify exact [ax dx cl];
+
+u32 shrd_long_asm(u32 * flags, u32 d, u32 fill, u8 s);
+#pragma aux shrd_long_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "shrd   eax,edx,cl"             \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [edx] [cl]     \
+    value [eax]                     \
+    modify exact [eax edx cl];
+
+u8 sbb_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux sbb_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sbb    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 sbb_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux sbb_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sbb    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 sbb_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux sbb_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sbb    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+u8 sub_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux sub_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sub    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 sub_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux sub_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sub    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 sub_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux sub_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "sub    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+void test_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux test_byte_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "test   al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    modify exact [al bl];
+
+void test_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux test_word_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "test   ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    modify exact [ax bx];
+
+void test_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux test_long_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "test   eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    modify exact [eax ebx];
+
+u8 xor_byte_asm(u32 * flags, u8 d, u8 s);
+#pragma aux xor_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "xor    al,bl"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [al] [bl]            \
+    value [al]                      \
+    modify exact [al bl];
+
+u16 xor_word_asm(u32 * flags, u16 d, u16 s);
+#pragma aux xor_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "xor    ax,bx"                  \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [ax] [bx]            \
+    value [ax]                      \
+    modify exact [ax bx];
+
+u32 xor_long_asm(u32 * flags, u32 d, u32 s);
+#pragma aux xor_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "xor    eax,ebx"                \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    parm [edi] [eax] [ebx]          \
+    value [eax]                     \
+    modify exact [eax ebx];
+
+void imul_byte_asm(u32 * flags, u16 * ax, u8 d, u8 s);
+#pragma aux imul_byte_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "imul   bl"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    parm [edi] [esi] [al] [bl]      \
+    modify exact [esi ax bl];
+
+void imul_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 d, u16 s);
+#pragma aux imul_word_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "imul   bx"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    "mov    [ecx],dx"               \
+    parm [edi] [esi] [ecx] [ax] [bx]\
+    modify exact [esi edi ax bx dx];
+
+void imul_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 d, u32 s);
+#pragma aux imul_long_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "imul   ebx"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],eax"              \
+    "mov    [ecx],edx"              \
+    parm [edi] [esi] [ecx] [eax] [ebx] \
+    modify exact [esi edi eax ebx edx];
+
+void mul_byte_asm(u32 * flags, u16 * ax, u8 d, u8 s);
+#pragma aux mul_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "mul    bl"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    parm [edi] [esi] [al] [bl]      \
+    modify exact [esi ax bl];
+
+void mul_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 d, u16 s);
+#pragma aux mul_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "mul    bx"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    "mov    [ecx],dx"               \
+    parm [edi] [esi] [ecx] [ax] [bx]\
+    modify exact [esi edi ax bx dx];
+
+void mul_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 d, u32 s);
+#pragma aux mul_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "mul    ebx"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],eax"              \
+    "mov    [ecx],edx"              \
+    parm [edi] [esi] [ecx] [eax] [ebx] \
+    modify exact [esi edi eax ebx edx];
+
+void idiv_byte_asm(u32 * flags, u8 * al, u8 * ah, u16 d, u8 s);
+#pragma aux idiv_byte_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "idiv   bl"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],al"               \
+    "mov    [ecx],ah"               \
+    parm [edi] [esi] [ecx] [ax] [bl]\
+    modify exact [esi edi ax bl];
+
+void idiv_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 dlo, u16 dhi, u16 s);
+#pragma aux idiv_word_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "idiv   bx"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    "mov    [ecx],dx"               \
+    parm [edi] [esi] [ecx] [ax] [dx] [bx]\
+    modify exact [esi edi ax dx bx];
+
+void idiv_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 dlo, u32 dhi, u32 s);
+#pragma aux idiv_long_asm =         \
+    "push   [edi]"                  \
+    "popf"                          \
+    "idiv   ebx"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],eax"              \
+    "mov    [ecx],edx"              \
+    parm [edi] [esi] [ecx] [eax] [edx] [ebx]\
+    modify exact [esi edi eax edx ebx];
+
+void div_byte_asm(u32 * flags, u8 * al, u8 * ah, u16 d, u8 s);
+#pragma aux div_byte_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "div    bl"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],al"               \
+    "mov    [ecx],ah"               \
+    parm [edi] [esi] [ecx] [ax] [bl]\
+    modify exact [esi edi ax bl];
+
+void div_word_asm(u32 * flags, u16 * ax, u16 * dx, u16 dlo, u16 dhi, u16 s);
+#pragma aux div_word_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "div    bx"                     \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],ax"               \
+    "mov    [ecx],dx"               \
+    parm [edi] [esi] [ecx] [ax] [dx] [bx]\
+    modify exact [esi edi ax dx bx];
+
+void div_long_asm(u32 * flags, u32 * eax, u32 * edx, u32 dlo, u32 dhi, u32 s);
+#pragma aux div_long_asm =          \
+    "push   [edi]"                  \
+    "popf"                          \
+    "div    ebx"                    \
+    "pushf"                         \
+    "pop    [edi]"                  \
+    "mov    [esi],eax"              \
+    "mov    [ecx],edx"              \
+    parm [edi] [esi] [ecx] [eax] [edx] [ebx]\
+    modify exact [esi edi eax edx ebx];
+
+#endif
+
+#endif				/* __X86EMU_PRIM_ASM_H */
diff --git a/drivers/bios_emulator/include/x86emu/prim_ops.h b/drivers/bios_emulator/include/x86emu/prim_ops.h
new file mode 100644
index 0000000..2291e84
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/prim_ops.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for primitive operation functions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_PRIM_OPS_H
+#define __X86EMU_PRIM_OPS_H
+
+#ifdef  __cplusplus
+extern "C" {                        /* Use "C" linkage when in C++ mode */
+#endif
+
+u16     aaa_word (u16 d);
+u16     aas_word (u16 d);
+u16     aad_word (u16 d);
+u16     aam_word (u8 d);
+u8      adc_byte (u8 d, u8 s);
+u16     adc_word (u16 d, u16 s);
+u32     adc_long (u32 d, u32 s);
+u8      add_byte (u8 d, u8 s);
+u16     add_word (u16 d, u16 s);
+u32     add_long (u32 d, u32 s);
+u8      and_byte (u8 d, u8 s);
+u16     and_word (u16 d, u16 s);
+u32     and_long (u32 d, u32 s);
+u8      cmp_byte (u8 d, u8 s);
+u16     cmp_word (u16 d, u16 s);
+u32     cmp_long (u32 d, u32 s);
+u8      daa_byte (u8 d);
+u8      das_byte (u8 d);
+u8      dec_byte (u8 d);
+u16     dec_word (u16 d);
+u32     dec_long (u32 d);
+u8      inc_byte (u8 d);
+u16     inc_word (u16 d);
+u32     inc_long (u32 d);
+u8      or_byte (u8 d, u8 s);
+u16     or_word (u16 d, u16 s);
+u32     or_long (u32 d, u32 s);
+u8      neg_byte (u8 s);
+u16     neg_word (u16 s);
+u32     neg_long (u32 s);
+u8      not_byte (u8 s);
+u16     not_word (u16 s);
+u32     not_long (u32 s);
+u8      rcl_byte (u8 d, u8 s);
+u16     rcl_word (u16 d, u8 s);
+u32     rcl_long (u32 d, u8 s);
+u8      rcr_byte (u8 d, u8 s);
+u16     rcr_word (u16 d, u8 s);
+u32     rcr_long (u32 d, u8 s);
+u8      rol_byte (u8 d, u8 s);
+u16     rol_word (u16 d, u8 s);
+u32     rol_long (u32 d, u8 s);
+u8      ror_byte (u8 d, u8 s);
+u16     ror_word (u16 d, u8 s);
+u32     ror_long (u32 d, u8 s);
+u8      shl_byte (u8 d, u8 s);
+u16     shl_word (u16 d, u8 s);
+u32     shl_long (u32 d, u8 s);
+u8      shr_byte (u8 d, u8 s);
+u16     shr_word (u16 d, u8 s);
+u32     shr_long (u32 d, u8 s);
+u8      sar_byte (u8 d, u8 s);
+u16     sar_word (u16 d, u8 s);
+u32     sar_long (u32 d, u8 s);
+u16     shld_word (u16 d, u16 fill, u8 s);
+u32     shld_long (u32 d, u32 fill, u8 s);
+u16     shrd_word (u16 d, u16 fill, u8 s);
+u32     shrd_long (u32 d, u32 fill, u8 s);
+u8      sbb_byte (u8 d, u8 s);
+u16     sbb_word (u16 d, u16 s);
+u32     sbb_long (u32 d, u32 s);
+u8      sub_byte (u8 d, u8 s);
+u16     sub_word (u16 d, u16 s);
+u32     sub_long (u32 d, u32 s);
+void    test_byte (u8 d, u8 s);
+void    test_word (u16 d, u16 s);
+void    test_long (u32 d, u32 s);
+u8      xor_byte (u8 d, u8 s);
+u16     xor_word (u16 d, u16 s);
+u32     xor_long (u32 d, u32 s);
+void    imul_byte (u8 s);
+void    imul_word (u16 s);
+void    imul_long (u32 s);
+void    imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s);
+void    mul_byte (u8 s);
+void    mul_word (u16 s);
+void    mul_long (u32 s);
+void    idiv_byte (u8 s);
+void    idiv_word (u16 s);
+void    idiv_long (u32 s);
+void    div_byte (u8 s);
+void    div_word (u16 s);
+void    div_long (u32 s);
+void    ins (int size);
+void    outs (int size);
+u16     mem_access_word (int addr);
+void    push_word (u16 w);
+void    push_long (u32 w);
+u16     pop_word (void);
+u32     pop_long (void);
+
+#ifdef  __cplusplus
+}                                   /* End of "C" linkage for C++       */
+#endif
+
+#endif /* __X86EMU_PRIM_OPS_H */
diff --git a/drivers/bios_emulator/include/x86emu/regs.h b/drivers/bios_emulator/include/x86emu/regs.h
new file mode 100644
index 0000000..a7fedd2
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/regs.h
@@ -0,0 +1,340 @@
+/****************************************************************************
+*
+*			Realmode X86 Emulator Library
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*		     Copyright (C) David Mosberger-Tang
+*		       Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	Header file for x86 register definitions.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_REGS_H
+#define __X86EMU_REGS_H
+
+/*---------------------- Macros and type definitions ----------------------*/
+
+#pragma pack(1)
+
+/*
+ * General EAX, EBX, ECX, EDX type registers.  Note that for
+ * portability, and speed, the issue of byte swapping is not addressed
+ * in the registers.  All registers are stored in the default format
+ * available on the host machine.  The only critical issue is that the
+ * registers should line up EXACTLY in the same manner as they do in
+ * the 386.  That is:
+ *
+ * EAX & 0xff  === AL
+ * EAX & 0xffff == AX
+ *
+ * etc.	 The result is that alot of the calculations can then be
+ * done using the native instruction set fully.
+ */
+
+#ifdef	__BIG_ENDIAN__
+
+typedef struct {
+	u32 e_reg;
+} I32_reg_t;
+
+typedef struct {
+	u16 filler0, x_reg;
+} I16_reg_t;
+
+typedef struct {
+	u8 filler0, filler1, h_reg, l_reg;
+} I8_reg_t;
+
+#else				/* !__BIG_ENDIAN__ */
+
+typedef struct {
+	u32 e_reg;
+} I32_reg_t;
+
+typedef struct {
+	u16 x_reg;
+} I16_reg_t;
+
+typedef struct {
+	u8 l_reg, h_reg;
+} I8_reg_t;
+
+#endif				/* BIG_ENDIAN */
+
+typedef union {
+	I32_reg_t I32_reg;
+	I16_reg_t I16_reg;
+	I8_reg_t I8_reg;
+} i386_general_register;
+
+struct i386_general_regs {
+	i386_general_register A, B, C, D;
+};
+
+typedef struct i386_general_regs Gen_reg_t;
+
+struct i386_special_regs {
+	i386_general_register SP, BP, SI, DI, IP;
+	u32 FLAGS;
+};
+
+/*
+ * Segment registers here represent the 16 bit quantities
+ * CS, DS, ES, SS.
+ */
+
+#undef CS
+#undef DS
+#undef SS
+#undef ES
+#undef FS
+#undef GS
+
+struct i386_segment_regs {
+	u16 CS, DS, SS, ES, FS, GS;
+};
+
+/* 8 bit registers */
+#define R_AH  gen.A.I8_reg.h_reg
+#define R_AL  gen.A.I8_reg.l_reg
+#define R_BH  gen.B.I8_reg.h_reg
+#define R_BL  gen.B.I8_reg.l_reg
+#define R_CH  gen.C.I8_reg.h_reg
+#define R_CL  gen.C.I8_reg.l_reg
+#define R_DH  gen.D.I8_reg.h_reg
+#define R_DL  gen.D.I8_reg.l_reg
+
+/* 16 bit registers */
+#define R_AX  gen.A.I16_reg.x_reg
+#define R_BX  gen.B.I16_reg.x_reg
+#define R_CX  gen.C.I16_reg.x_reg
+#define R_DX  gen.D.I16_reg.x_reg
+
+/* 32 bit extended registers */
+#define R_EAX  gen.A.I32_reg.e_reg
+#define R_EBX  gen.B.I32_reg.e_reg
+#define R_ECX  gen.C.I32_reg.e_reg
+#define R_EDX  gen.D.I32_reg.e_reg
+
+/* special registers */
+#define R_SP  spc.SP.I16_reg.x_reg
+#define R_BP  spc.BP.I16_reg.x_reg
+#define R_SI  spc.SI.I16_reg.x_reg
+#define R_DI  spc.DI.I16_reg.x_reg
+#define R_IP  spc.IP.I16_reg.x_reg
+#define R_FLG spc.FLAGS
+
+/* special registers */
+#define R_SP  spc.SP.I16_reg.x_reg
+#define R_BP  spc.BP.I16_reg.x_reg
+#define R_SI  spc.SI.I16_reg.x_reg
+#define R_DI  spc.DI.I16_reg.x_reg
+#define R_IP  spc.IP.I16_reg.x_reg
+#define R_FLG spc.FLAGS
+
+/* special registers */
+#define R_ESP  spc.SP.I32_reg.e_reg
+#define R_EBP  spc.BP.I32_reg.e_reg
+#define R_ESI  spc.SI.I32_reg.e_reg
+#define R_EDI  spc.DI.I32_reg.e_reg
+#define R_EIP  spc.IP.I32_reg.e_reg
+#define R_EFLG spc.FLAGS
+
+/* segment registers */
+#define R_CS  seg.CS
+#define R_DS  seg.DS
+#define R_SS  seg.SS
+#define R_ES  seg.ES
+#define R_FS  seg.FS
+#define R_GS  seg.GS
+
+/* flag conditions   */
+#define FB_CF 0x0001		/* CARRY flag  */
+#define FB_PF 0x0004		/* PARITY flag */
+#define FB_AF 0x0010		/* AUX	flag   */
+#define FB_ZF 0x0040		/* ZERO flag   */
+#define FB_SF 0x0080		/* SIGN flag   */
+#define FB_TF 0x0100		/* TRAP flag   */
+#define FB_IF 0x0200		/* INTERRUPT ENABLE flag */
+#define FB_DF 0x0400		/* DIR flag    */
+#define FB_OF 0x0800		/* OVERFLOW flag */
+
+/* 80286 and above always have bit#1 set */
+#define F_ALWAYS_ON  (0x0002)	/* flag bits always on */
+
+/*
+ * Define a mask for only those flag bits we will ever pass back
+ * (via PUSHF)
+ */
+#define F_MSK (FB_CF|FB_PF|FB_AF|FB_ZF|FB_SF|FB_TF|FB_IF|FB_DF|FB_OF)
+
+/* following bits masked in to a 16bit quantity */
+
+#define F_CF 0x0001		/* CARRY flag  */
+#define F_PF 0x0004		/* PARITY flag */
+#define F_AF 0x0010		/* AUX	flag   */
+#define F_ZF 0x0040		/* ZERO flag   */
+#define F_SF 0x0080		/* SIGN flag   */
+#define F_TF 0x0100		/* TRAP flag   */
+#define F_IF 0x0200		/* INTERRUPT ENABLE flag */
+#define F_DF 0x0400		/* DIR flag    */
+#define F_OF 0x0800		/* OVERFLOW flag */
+
+#define TOGGLE_FLAG(flag)	(M.x86.R_FLG ^= (flag))
+#define SET_FLAG(flag)		(M.x86.R_FLG |= (flag))
+#define CLEAR_FLAG(flag)	(M.x86.R_FLG &= ~(flag))
+#define ACCESS_FLAG(flag)	(M.x86.R_FLG & (flag))
+#define CLEARALL_FLAG(m)	(M.x86.R_FLG = 0)
+
+#define CONDITIONAL_SET_FLAG(COND,FLAG) \
+  if (COND) SET_FLAG(FLAG); else CLEAR_FLAG(FLAG)
+
+#define F_PF_CALC 0x010000	/* PARITY flag has been calced	  */
+#define F_ZF_CALC 0x020000	/* ZERO flag has been calced	  */
+#define F_SF_CALC 0x040000	/* SIGN flag has been calced	  */
+
+#define F_ALL_CALC	0xff0000	/* All have been calced	  */
+
+/*
+ * Emulator machine state.
+ * Segment usage control.
+ */
+#define SYSMODE_SEG_DS_SS	0x00000001
+#define SYSMODE_SEGOVR_CS	0x00000002
+#define SYSMODE_SEGOVR_DS	0x00000004
+#define SYSMODE_SEGOVR_ES	0x00000008
+#define SYSMODE_SEGOVR_FS	0x00000010
+#define SYSMODE_SEGOVR_GS	0x00000020
+#define SYSMODE_SEGOVR_SS	0x00000040
+#define SYSMODE_PREFIX_REPE	0x00000080
+#define SYSMODE_PREFIX_REPNE	0x00000100
+#define SYSMODE_PREFIX_DATA	0x00000200
+#define SYSMODE_PREFIX_ADDR	0x00000400
+#define SYSMODE_INTR_PENDING	0x10000000
+#define SYSMODE_EXTRN_INTR	0x20000000
+#define SYSMODE_HALTED		0x40000000
+
+#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS	| \
+			 SYSMODE_SEGOVR_CS	| \
+			 SYSMODE_SEGOVR_DS	| \
+			 SYSMODE_SEGOVR_ES	| \
+			 SYSMODE_SEGOVR_FS	| \
+			 SYSMODE_SEGOVR_GS	| \
+			 SYSMODE_SEGOVR_SS)
+#define SYSMODE_CLRMASK (SYSMODE_SEG_DS_SS	| \
+			 SYSMODE_SEGOVR_CS	| \
+			 SYSMODE_SEGOVR_DS	| \
+			 SYSMODE_SEGOVR_ES	| \
+			 SYSMODE_SEGOVR_FS	| \
+			 SYSMODE_SEGOVR_GS	| \
+			 SYSMODE_SEGOVR_SS	| \
+			 SYSMODE_PREFIX_DATA	| \
+			 SYSMODE_PREFIX_ADDR)
+
+#define	 INTR_SYNCH	      0x1
+#define	 INTR_ASYNCH	      0x2
+#define	 INTR_HALTED	      0x4
+
+typedef struct {
+	struct i386_general_regs gen;
+	struct i386_special_regs spc;
+	struct i386_segment_regs seg;
+	/*
+	 * MODE contains information on:
+	 *  REPE prefix		    2 bits  repe,repne
+	 *  SEGMENT overrides	    5 bits  normal,DS,SS,CS,ES
+	 *  Delayed flag set	    3 bits  (zero, signed, parity)
+	 *  reserved		    6 bits
+	 *  interrupt #		    8 bits  instruction raised interrupt
+	 *  BIOS video segregs	    4 bits
+	 *  Interrupt Pending	    1 bits
+	 *  Extern interrupt	    1 bits
+	 *  Halted		    1 bits
+	 */
+	long mode;
+	u8 intno;
+	volatile int intr;	/* mask of pending interrupts */
+	int debug;
+#ifdef DEBUG
+	int check;
+	u16 saved_ip;
+	u16 saved_cs;
+	int enc_pos;
+	int enc_str_pos;
+	char decode_buf[32];	/* encoded byte stream	*/
+	char decoded_buf[256];	/* disassembled strings */
+#endif
+} X86EMU_regs;
+
+/****************************************************************************
+REMARKS:
+Structure maintaining the emulator machine state.
+
+MEMBERS:
+x86		- X86 registers
+mem_base	- Base real mode memory for the emulator
+mem_size	- Size of the real mode memory block for the emulator
+****************************************************************************/
+#undef x86
+typedef struct {
+	X86EMU_regs x86;
+	u8 *mem_base;
+	u32 mem_size;
+	void *private;
+} X86EMU_sysEnv;
+
+#pragma pack()
+
+/*----------------------------- Global Variables --------------------------*/
+
+#ifdef	__cplusplus
+extern "C" {			/* Use "C" linkage when in C++ mode */
+#endif
+
+/* Global emulator machine state.
+ *
+ * We keep it global to avoid pointer dereferences in the code for speed.
+ */
+
+	extern X86EMU_sysEnv _X86EMU_env;
+#define	  M		_X86EMU_env
+
+/*-------------------------- Function Prototypes --------------------------*/
+
+/* Function to log information at runtime */
+
+#ifndef __KERNEL__
+	void printk(const char *fmt, ...);
+#endif
+
+#ifdef	__cplusplus
+}				/* End of "C" linkage for C++	    */
+#endif
+#endif				/* __X86EMU_REGS_H */
diff --git a/drivers/bios_emulator/include/x86emu/x86emui.h b/drivers/bios_emulator/include/x86emu/x86emui.h
new file mode 100644
index 0000000..a74957d
--- /dev/null
+++ b/drivers/bios_emulator/include/x86emu/x86emui.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  Header file for system specific functions. These functions
+*               are always compiled and linked in the OS depedent libraries,
+*               and never in a binary portable driver.
+*
+****************************************************************************/
+
+#ifndef __X86EMU_X86EMUI_H
+#define __X86EMU_X86EMUI_H
+
+/* If we are compiling in C++ mode, we can compile some functions as
+ * inline to increase performance (however the code size increases quite
+ * dramatically in this case).
+ */
+
+#if defined(__cplusplus) && !defined(_NO_INLINE)
+#define _INLINE inline
+#else
+#define _INLINE static
+#endif
+
+/* Get rid of unused parameters in C++ compilation mode */
+
+#ifdef __cplusplus
+#define X86EMU_UNUSED(v)
+#else
+#define X86EMU_UNUSED(v)    v
+#endif
+
+#include "x86emu.h"
+#include "x86emu/regs.h"
+#include "x86emu/debug.h"
+#include "x86emu/decode.h"
+#include "x86emu/ops.h"
+#include "x86emu/prim_ops.h"
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#define printk printf
+
+
+/*--------------------------- Inline Functions ----------------------------*/
+
+#ifdef  __cplusplus
+extern "C" {			/* Use "C" linkage when in C++ mode */
+#endif
+
+	extern u8(X86APIP sys_rdb) (u32 addr);
+	extern u16(X86APIP sys_rdw) (u32 addr);
+	extern u32(X86APIP sys_rdl) (u32 addr);
+	extern void (X86APIP sys_wrb) (u32 addr, u8 val);
+	extern void (X86APIP sys_wrw) (u32 addr, u16 val);
+	extern void (X86APIP sys_wrl) (u32 addr, u32 val);
+
+	extern u8(X86APIP sys_inb) (X86EMU_pioAddr addr);
+	extern u16(X86APIP sys_inw) (X86EMU_pioAddr addr);
+	extern u32(X86APIP sys_inl) (X86EMU_pioAddr addr);
+	extern void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val);
+	extern void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val);
+	extern void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val);
+
+#ifdef  __cplusplus
+}				/* End of "C" linkage for C++       */
+#endif
+#endif				/* __X86EMU_X86EMUI_H */
diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c
new file mode 100644
index 0000000..915739c
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/debug.c
@@ -0,0 +1,465 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  This file contains the code to handle debugging of the
+*               emulator.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+#include <stdarg.h>
+
+#if defined(CONFIG_BIOSEMU)
+
+/*----------------------------- Implementation ----------------------------*/
+
+#ifdef DEBUG
+
+static void print_encoded_bytes(u16 s, u16 o);
+static void print_decoded_instruction(void);
+static int parse_line(char *s, int *ps, int *n);
+
+/* should look something like debug's output. */
+void X86EMU_trace_regs(void)
+{
+	if (DEBUG_TRACE()) {
+		x86emu_dump_regs();
+	}
+	if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) {
+		printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
+		print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
+		print_decoded_instruction();
+	}
+}
+
+void X86EMU_trace_xregs(void)
+{
+	if (DEBUG_TRACE()) {
+		x86emu_dump_xregs();
+	}
+}
+
+void x86emu_just_disassemble(void)
+{
+	/*
+	 * This routine called if the flag DEBUG_DISASSEMBLE is set kind
+	 * of a hack!
+	 */
+	printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
+	print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
+	print_decoded_instruction();
+}
+
+static void disassemble_forward(u16 seg, u16 off, int n)
+{
+	X86EMU_sysEnv tregs;
+	int i;
+	u8 op1;
+	/*
+	 * hack, hack, hack.  What we do is use the exact machinery set up
+	 * for execution, except that now there is an additional state
+	 * flag associated with the "execution", and we are using a copy
+	 * of the register struct.  All the major opcodes, once fully
+	 * decoded, have the following two steps: TRACE_REGS(r,m);
+	 * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
+	 * the preprocessor.  The TRACE_REGS macro expands to:
+	 *
+	 * if (debug&DEBUG_DISASSEMBLE)
+	 *     {just_disassemble(); goto EndOfInstruction;}
+	 *     if (debug&DEBUG_TRACE) trace_regs(r,m);
+	 *
+	 * ......  and at the last line of the routine.
+	 *
+	 * EndOfInstruction: end_instr();
+	 *
+	 * Up to the point where TRACE_REG is expanded, NO modifications
+	 * are done to any register EXCEPT the IP register, for fetch and
+	 * decoding purposes.
+	 *
+	 * This was done for an entirely different reason, but makes a
+	 * nice way to get the system to help debug codes.
+	 */
+	tregs = M;
+	tregs.x86.R_IP = off;
+	tregs.x86.R_CS = seg;
+
+	/* reset the decoding buffers */
+	tregs.x86.enc_str_pos = 0;
+	tregs.x86.enc_pos = 0;
+
+	/* turn on the "disassemble only, no execute" flag */
+	tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
+
+	/* DUMP NEXT n instructions to screen in straight_line fashion */
+	/*
+	 * This looks like the regular instruction fetch stream, except
+	 * that when this occurs, each fetched opcode, upon seeing the
+	 * DEBUG_DISASSEMBLE flag set, exits immediately after decoding
+	 * the instruction.  XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
+	 * Note the use of a copy of the register structure...
+	 */
+	for (i = 0; i < n; i++) {
+		op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
+		(x86emu_optab[op1]) (op1);
+	}
+	/* end major hack mode. */
+}
+
+void x86emu_check_ip_access(void)
+{
+	/* NULL as of now */
+}
+
+void x86emu_check_sp_access(void)
+{
+}
+
+void x86emu_check_mem_access(u32 dummy)
+{
+	/*  check bounds, etc */
+}
+
+void x86emu_check_data_access(uint dummy1, uint dummy2)
+{
+	/*  check bounds, etc */
+}
+
+void x86emu_inc_decoded_inst_len(int x)
+{
+	M.x86.enc_pos += x;
+}
+
+void x86emu_decode_printf(char *x)
+{
+	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x);
+	M.x86.enc_str_pos += strlen(x);
+}
+
+void x86emu_decode_printf2(char *x, int y)
+{
+	char temp[100];
+	sprintf(temp, x, y);
+	sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp);
+	M.x86.enc_str_pos += strlen(temp);
+}
+
+void x86emu_end_instr(void)
+{
+	M.x86.enc_str_pos = 0;
+	M.x86.enc_pos = 0;
+}
+
+static void print_encoded_bytes(u16 s, u16 o)
+{
+	int i;
+	char buf1[64];
+	for (i = 0; i < M.x86.enc_pos; i++) {
+		sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i));
+	}
+	printk("%-20s", buf1);
+}
+
+static void print_decoded_instruction(void)
+{
+	printk("%s", M.x86.decoded_buf);
+}
+
+void x86emu_print_int_vect(u16 iv)
+{
+	u16 seg, off;
+
+	if (iv > 256)
+		return;
+	seg = fetch_data_word_abs(0, iv * 4);
+	off = fetch_data_word_abs(0, iv * 4 + 2);
+	printk("%04x:%04x ", seg, off);
+}
+
+void X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
+{
+	u32 start = off & 0xfffffff0;
+	u32 end = (off + 16) & 0xfffffff0;
+	u32 i;
+	u32 current;
+
+	current = start;
+	while (end <= off + amt) {
+		printk("%04x:%04x ", seg, start);
+		for (i = start; i < off; i++)
+			printk("   ");
+		for (; i < end; i++)
+			printk("%02x ", fetch_data_byte_abs(seg, i));
+		printk("\n");
+		start = end;
+		end = start + 16;
+	}
+}
+
+void x86emu_single_step(void)
+{
+	char s[1024];
+	int ps[10];
+	int ntok;
+	int cmd;
+	int done;
+	int segment;
+	int offset;
+	static int breakpoint;
+	static int noDecode = 1;
+
+	char *p;
+
+	if (DEBUG_BREAK()) {
+		if (M.x86.saved_ip != breakpoint) {
+			return;
+		} else {
+			M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+			M.x86.debug |= DEBUG_TRACE_F;
+			M.x86.debug &= ~DEBUG_BREAK_F;
+			print_decoded_instruction();
+			X86EMU_trace_regs();
+		}
+	}
+	done = 0;
+	offset = M.x86.saved_ip;
+	while (!done) {
+		printk("-");
+		cmd = parse_line(s, ps, &ntok);
+		switch (cmd) {
+		case 'u':
+			disassemble_forward(M.x86.saved_cs, (u16) offset, 10);
+			break;
+		case 'd':
+			if (ntok == 2) {
+				segment = M.x86.saved_cs;
+				offset = ps[1];
+				X86EMU_dump_memory(segment, (u16) offset, 16);
+				offset += 16;
+			} else if (ntok == 3) {
+				segment = ps[1];
+				offset = ps[2];
+				X86EMU_dump_memory(segment, (u16) offset, 16);
+				offset += 16;
+			} else {
+				segment = M.x86.saved_cs;
+				X86EMU_dump_memory(segment, (u16) offset, 16);
+				offset += 16;
+			}
+			break;
+		case 'c':
+			M.x86.debug ^= DEBUG_TRACECALL_F;
+			break;
+		case 's':
+			M.x86.debug ^=
+			    DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
+			break;
+		case 'r':
+			X86EMU_trace_regs();
+			break;
+		case 'x':
+			X86EMU_trace_xregs();
+			break;
+		case 'g':
+			if (ntok == 2) {
+				breakpoint = ps[1];
+				if (noDecode) {
+					M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
+				} else {
+					M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
+				}
+				M.x86.debug &= ~DEBUG_TRACE_F;
+				M.x86.debug |= DEBUG_BREAK_F;
+				done = 1;
+			}
+			break;
+		case 'q':
+			M.x86.debug |= DEBUG_EXIT;
+			return;
+		case 'P':
+			noDecode = (noDecode) ? 0 : 1;
+			printk("Toggled decoding to %s\n",
+			       (noDecode) ? "FALSE" : "TRUE");
+			break;
+		case 't':
+		case 0:
+			done = 1;
+			break;
+		}
+	}
+}
+
+int X86EMU_trace_on(void)
+{
+	return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
+}
+
+int X86EMU_trace_off(void)
+{
+	return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
+}
+
+static int parse_line(char *s, int *ps, int *n)
+{
+	int cmd;
+
+	*n = 0;
+	while (*s == ' ' || *s == '\t')
+		s++;
+	ps[*n] = *s;
+	switch (*s) {
+	case '\n':
+		*n += 1;
+		return 0;
+	default:
+		cmd = *s;
+		*n += 1;
+	}
+
+	while (1) {
+		while (*s != ' ' && *s != '\t' && *s != '\n')
+			s++;
+
+		if (*s == '\n')
+			return cmd;
+
+		while (*s == ' ' || *s == '\t')
+			s++;
+
+		*n += 1;
+	}
+}
+
+#endif				/* DEBUG */
+
+void x86emu_dump_regs(void)
+{
+	printk("\tAX=%04x  ", M.x86.R_AX);
+	printk("BX=%04x  ", M.x86.R_BX);
+	printk("CX=%04x  ", M.x86.R_CX);
+	printk("DX=%04x  ", M.x86.R_DX);
+	printk("SP=%04x  ", M.x86.R_SP);
+	printk("BP=%04x  ", M.x86.R_BP);
+	printk("SI=%04x  ", M.x86.R_SI);
+	printk("DI=%04x\n", M.x86.R_DI);
+	printk("\tDS=%04x  ", M.x86.R_DS);
+	printk("ES=%04x  ", M.x86.R_ES);
+	printk("SS=%04x  ", M.x86.R_SS);
+	printk("CS=%04x  ", M.x86.R_CS);
+	printk("IP=%04x   ", M.x86.R_IP);
+	if (ACCESS_FLAG(F_OF))
+		printk("OV ");	/* CHECKED... */
+	else
+		printk("NV ");
+	if (ACCESS_FLAG(F_DF))
+		printk("DN ");
+	else
+		printk("UP ");
+	if (ACCESS_FLAG(F_IF))
+		printk("EI ");
+	else
+		printk("DI ");
+	if (ACCESS_FLAG(F_SF))
+		printk("NG ");
+	else
+		printk("PL ");
+	if (ACCESS_FLAG(F_ZF))
+		printk("ZR ");
+	else
+		printk("NZ ");
+	if (ACCESS_FLAG(F_AF))
+		printk("AC ");
+	else
+		printk("NA ");
+	if (ACCESS_FLAG(F_PF))
+		printk("PE ");
+	else
+		printk("PO ");
+	if (ACCESS_FLAG(F_CF))
+		printk("CY ");
+	else
+		printk("NC ");
+	printk("\n");
+}
+
+void x86emu_dump_xregs(void)
+{
+	printk("\tEAX=%08x  ", M.x86.R_EAX);
+	printk("EBX=%08x  ", M.x86.R_EBX);
+	printk("ECX=%08x  ", M.x86.R_ECX);
+	printk("EDX=%08x  \n", M.x86.R_EDX);
+	printk("\tESP=%08x  ", M.x86.R_ESP);
+	printk("EBP=%08x  ", M.x86.R_EBP);
+	printk("ESI=%08x  ", M.x86.R_ESI);
+	printk("EDI=%08x\n", M.x86.R_EDI);
+	printk("\tDS=%04x  ", M.x86.R_DS);
+	printk("ES=%04x  ", M.x86.R_ES);
+	printk("SS=%04x  ", M.x86.R_SS);
+	printk("CS=%04x  ", M.x86.R_CS);
+	printk("EIP=%08x\n\t", M.x86.R_EIP);
+	if (ACCESS_FLAG(F_OF))
+		printk("OV ");	/* CHECKED... */
+	else
+		printk("NV ");
+	if (ACCESS_FLAG(F_DF))
+		printk("DN ");
+	else
+		printk("UP ");
+	if (ACCESS_FLAG(F_IF))
+		printk("EI ");
+	else
+		printk("DI ");
+	if (ACCESS_FLAG(F_SF))
+		printk("NG ");
+	else
+		printk("PL ");
+	if (ACCESS_FLAG(F_ZF))
+		printk("ZR ");
+	else
+		printk("NZ ");
+	if (ACCESS_FLAG(F_AF))
+		printk("AC ");
+	else
+		printk("NA ");
+	if (ACCESS_FLAG(F_PF))
+		printk("PE ");
+	else
+		printk("PO ");
+	if (ACCESS_FLAG(F_CF))
+		printk("CY ");
+	else
+		printk("NC ");
+	printk("\n");
+}
+
+#endif
diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c
new file mode 100644
index 0000000..879f0a0
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/decode.c
@@ -0,0 +1,1148 @@
+/****************************************************************************
+*
+*			Realmode X86 Emulator Library
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*		     Copyright (C) David Mosberger-Tang
+*		       Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	This file includes subroutines which are related to
+*		instruction decoding and accessess of immediate data via IP.  etc.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+#if defined(CONFIG_BIOSEMU)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+REMARKS:
+Handles any pending asychronous interrupts.
+****************************************************************************/
+static void x86emu_intr_handle(void)
+{
+    u8	intno;
+
+    if (M.x86.intr & INTR_SYNCH) {
+	intno = M.x86.intno;
+	if (_X86EMU_intrTab[intno]) {
+	    (*_X86EMU_intrTab[intno])(intno);
+	} else {
+	    push_word((u16)M.x86.R_FLG);
+	    CLEAR_FLAG(F_IF);
+	    CLEAR_FLAG(F_TF);
+	    push_word(M.x86.R_CS);
+	    M.x86.R_CS = mem_access_word(intno * 4 + 2);
+	    push_word(M.x86.R_IP);
+	    M.x86.R_IP = mem_access_word(intno * 4);
+	    M.x86.intr = 0;
+	}
+    }
+}
+
+/****************************************************************************
+PARAMETERS:
+intrnum - Interrupt number to raise
+
+REMARKS:
+Raise the specified interrupt to be handled before the execution of the
+next instruction.
+****************************************************************************/
+void x86emu_intr_raise(
+    u8 intrnum)
+{
+    M.x86.intno = intrnum;
+    M.x86.intr |= INTR_SYNCH;
+}
+
+/****************************************************************************
+REMARKS:
+Main execution loop for the emulator. We return from here when the system
+halts, which is normally caused by a stack fault when we return from the
+original real mode call.
+****************************************************************************/
+void X86EMU_exec(void)
+{
+    u8 op1;
+
+    M.x86.intr = 0;
+    DB(x86emu_end_instr();)
+
+    for (;;) {
+DB(	if (CHECK_IP_FETCH())
+	    x86emu_check_ip_access();)
+	/* If debugging, save the IP and CS values. */
+	SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP);
+	INC_DECODED_INST_LEN(1);
+	if (M.x86.intr) {
+	    if (M.x86.intr & INTR_HALTED) {
+DB(		if (M.x86.R_SP != 0) {
+		    printk("halted\n");
+		    X86EMU_trace_regs();
+		    }
+		else {
+		    if (M.x86.debug)
+			printk("Service completed successfully\n");
+		    })
+		return;
+	    }
+	    if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) ||
+		!ACCESS_FLAG(F_IF)) {
+		x86emu_intr_handle();
+	    }
+	}
+	op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+	(*x86emu_optab[op1])(op1);
+	if (M.x86.debug & DEBUG_EXIT) {
+	    M.x86.debug &= ~DEBUG_EXIT;
+	    return;
+	}
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Halts the system by setting the halted system flag.
+****************************************************************************/
+void X86EMU_halt_sys(void)
+{
+    M.x86.intr |= INTR_HALTED;
+}
+
+/****************************************************************************
+PARAMETERS:
+mod	- Mod value from decoded byte
+regh	- Reg h value from decoded byte
+regl	- Reg l value from decoded byte
+
+REMARKS:
+Raise the specified interrupt to be handled before the execution of the
+next instruction.
+
+NOTE: Do not inline this function, as (*sys_rdb) is already inline!
+****************************************************************************/
+void fetch_decode_modrm(
+    int *mod,
+    int *regh,
+    int *regl)
+{
+    int fetched;
+
+DB( if (CHECK_IP_FETCH())
+	x86emu_check_ip_access();)
+    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+    INC_DECODED_INST_LEN(1);
+    *mod  = (fetched >> 6) & 0x03;
+    *regh = (fetched >> 3) & 0x07;
+    *regl = (fetched >> 0) & 0x07;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate byte value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdb) is already inline!
+****************************************************************************/
+u8 fetch_byte_imm(void)
+{
+    u8 fetched;
+
+DB( if (CHECK_IP_FETCH())
+	x86emu_check_ip_access();)
+    fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+    INC_DECODED_INST_LEN(1);
+    return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate word value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdw) is already inline!
+****************************************************************************/
+u16 fetch_word_imm(void)
+{
+    u16 fetched;
+
+DB( if (CHECK_IP_FETCH())
+	x86emu_check_ip_access();)
+    fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+    M.x86.R_IP += 2;
+    INC_DECODED_INST_LEN(2);
+    return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Immediate lone value read from instruction queue
+
+REMARKS:
+This function returns the immediate byte from the instruction queue, and
+moves the instruction pointer to the next value.
+
+NOTE: Do not inline this function, as (*sys_rdw) is already inline!
+****************************************************************************/
+u32 fetch_long_imm(void)
+{
+    u32 fetched;
+
+DB( if (CHECK_IP_FETCH())
+	x86emu_check_ip_access();)
+    fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP));
+    M.x86.R_IP += 4;
+    INC_DECODED_INST_LEN(4);
+    return fetched;
+}
+
+/****************************************************************************
+RETURNS:
+Value of the default data segment
+
+REMARKS:
+Inline function that returns the default data segment for the current
+instruction.
+
+On the x86 processor, the default segment is not always DS if there is
+no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
+addresses relative to SS (ie: on the stack). So, at the minimum, all
+decodings of addressing modes would have to set/clear a bit describing
+whether the access is relative to DS or SS.  That is the function of the
+cpu-state-varible M.x86.mode. There are several potential states:
+
+    repe prefix seen  (handled elsewhere)
+    repne prefix seen  (ditto)
+
+    cs segment override
+    ds segment override
+    es segment override
+    fs segment override
+    gs segment override
+    ss segment override
+
+    ds/ss select (in absense of override)
+
+Each of the above 7 items are handled with a bit in the mode field.
+****************************************************************************/
+_INLINE u32 get_data_segment(void)
+{
+#define GET_SEGMENT(segment)
+    switch (M.x86.mode & SYSMODE_SEGMASK) {
+      case 0:			/* default case: use ds register */
+      case SYSMODE_SEGOVR_DS:
+      case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_DS;
+      case SYSMODE_SEG_DS_SS:	/* non-overridden, use ss register */
+	return	M.x86.R_SS;
+      case SYSMODE_SEGOVR_CS:
+      case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_CS;
+      case SYSMODE_SEGOVR_ES:
+      case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_ES;
+      case SYSMODE_SEGOVR_FS:
+      case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_FS;
+      case SYSMODE_SEGOVR_GS:
+      case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_GS;
+      case SYSMODE_SEGOVR_SS:
+      case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS:
+	return	M.x86.R_SS;
+      default:
+#ifdef	DEBUG
+	printk("error: should not happen:  multiple overrides.\n");
+#endif
+	HALT_SYS();
+	return 0;
+    }
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to load data from
+
+RETURNS:
+Byte value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdb)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to load data from
+
+RETURNS:
+Word value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdw)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to load data from
+
+RETURNS:
+Long value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long(
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    return (*sys_rdl)((get_data_segment() << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset	- Offset to load data from
+
+RETURNS:
+Byte value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u8 fetch_data_byte_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdb)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset	- Offset to load data from
+
+RETURNS:
+Word value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 fetch_data_word_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdw)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to load data from
+offset	- Offset to load data from
+
+RETURNS:
+Long value read from the absolute memory location.
+
+NOTE: Do not inline this function as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 fetch_data_long_abs(
+    uint segment,
+    uint offset)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    return (*sys_rdl)(((u32)segment << 4) + offset);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a word value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte(
+    uint offset,
+    u8 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrb)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a word value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word(
+    uint offset,
+    u16 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrw)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a long value to an segmented memory location. The segment used is
+the current 'default' segment, which may have been overridden.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long(
+    uint offset,
+    u32 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access((u16)get_data_segment(), offset);
+#endif
+    (*sys_wrl)((get_data_segment() << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a byte value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_byte_abs(
+    uint segment,
+    uint offset,
+    u8 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrb)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a word value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_word_abs(
+    uint segment,
+    uint offset,
+    u16 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrw)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+segment - Segment to store data at
+offset	- Offset to store data at
+val	- Value to store
+
+REMARKS:
+Writes a long value to an absolute memory location.
+
+NOTE: Do not inline this function as (*sys_wrX) is already inline!
+****************************************************************************/
+void store_data_long_abs(
+    uint segment,
+    uint offset,
+    u32 val)
+{
+#ifdef DEBUG
+    if (CHECK_DATA_ACCESS())
+	x86emu_check_data_access(segment, offset);
+#endif
+    (*sys_wrl)(((u32)segment << 4) + offset, val);
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for byte operands. Also enables the decoding of instructions.
+****************************************************************************/
+u8* decode_rm_byte_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+	DECODE_PRINTF("AL");
+	return &M.x86.R_AL;
+      case 1:
+	DECODE_PRINTF("CL");
+	return &M.x86.R_CL;
+      case 2:
+	DECODE_PRINTF("DL");
+	return &M.x86.R_DL;
+      case 3:
+	DECODE_PRINTF("BL");
+	return &M.x86.R_BL;
+      case 4:
+	DECODE_PRINTF("AH");
+	return &M.x86.R_AH;
+      case 5:
+	DECODE_PRINTF("CH");
+	return &M.x86.R_CH;
+      case 6:
+	DECODE_PRINTF("DH");
+	return &M.x86.R_DH;
+      case 7:
+	DECODE_PRINTF("BH");
+	return &M.x86.R_BH;
+    }
+    HALT_SYS();
+    return NULL;		/* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for word operands.	Also enables the decoding of instructions.
+****************************************************************************/
+u16* decode_rm_word_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+	DECODE_PRINTF("AX");
+	return &M.x86.R_AX;
+      case 1:
+	DECODE_PRINTF("CX");
+	return &M.x86.R_CX;
+      case 2:
+	DECODE_PRINTF("DX");
+	return &M.x86.R_DX;
+      case 3:
+	DECODE_PRINTF("BX");
+	return &M.x86.R_BX;
+      case 4:
+	DECODE_PRINTF("SP");
+	return &M.x86.R_SP;
+      case 5:
+	DECODE_PRINTF("BP");
+	return &M.x86.R_BP;
+      case 6:
+	DECODE_PRINTF("SI");
+	return &M.x86.R_SI;
+      case 7:
+	DECODE_PRINTF("DI");
+	return &M.x86.R_DI;
+    }
+    HALT_SYS();
+    return NULL;		/* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for dword operands.	 Also enables the decoding of instructions.
+****************************************************************************/
+u32* decode_rm_long_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+	DECODE_PRINTF("EAX");
+	return &M.x86.R_EAX;
+      case 1:
+	DECODE_PRINTF("ECX");
+	return &M.x86.R_ECX;
+      case 2:
+	DECODE_PRINTF("EDX");
+	return &M.x86.R_EDX;
+      case 3:
+	DECODE_PRINTF("EBX");
+	return &M.x86.R_EBX;
+      case 4:
+	DECODE_PRINTF("ESP");
+	return &M.x86.R_ESP;
+      case 5:
+	DECODE_PRINTF("EBP");
+	return &M.x86.R_EBP;
+      case 6:
+	DECODE_PRINTF("ESI");
+	return &M.x86.R_ESI;
+      case 7:
+	DECODE_PRINTF("EDI");
+	return &M.x86.R_EDI;
+    }
+    HALT_SYS();
+    return NULL;		/* NOTREACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+reg - Register to decode
+
+RETURNS:
+Pointer to the appropriate register
+
+REMARKS:
+Return a pointer to the register given by the R/RM field of the
+modrm byte, for word operands, modified from above for the weirdo
+special case of segreg operands.  Also enables the decoding of instructions.
+****************************************************************************/
+u16* decode_rm_seg_register(
+    int reg)
+{
+    switch (reg) {
+      case 0:
+	DECODE_PRINTF("ES");
+	return &M.x86.R_ES;
+      case 1:
+	DECODE_PRINTF("CS");
+	return &M.x86.R_CS;
+      case 2:
+	DECODE_PRINTF("SS");
+	return &M.x86.R_SS;
+      case 3:
+	DECODE_PRINTF("DS");
+	return &M.x86.R_DS;
+      case 4:
+	DECODE_PRINTF("FS");
+	return &M.x86.R_FS;
+      case 5:
+	DECODE_PRINTF("GS");
+	return &M.x86.R_GS;
+      case 6:
+      case 7:
+	DECODE_PRINTF("ILLEGAL SEGREG");
+	break;
+    }
+    HALT_SYS();
+    return NULL;		/* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+scale - scale value of SIB byte
+index - index value of SIB byte
+
+RETURNS:
+Value of scale * index
+
+REMARKS:
+Decodes scale/index of SIB byte and returns relevant offset part of
+effective address.
+****************************************************************************/
+unsigned decode_sib_si(
+    int scale,
+    int index)
+{
+    scale = 1 << scale;
+    if (scale > 1) {
+	DECODE_PRINTF2("[%d*", scale);
+    } else {
+	DECODE_PRINTF("[");
+    }
+    switch (index) {
+      case 0:
+	DECODE_PRINTF("EAX]");
+	return M.x86.R_EAX * index;
+      case 1:
+	DECODE_PRINTF("ECX]");
+	return M.x86.R_ECX * index;
+      case 2:
+	DECODE_PRINTF("EDX]");
+	return M.x86.R_EDX * index;
+      case 3:
+	DECODE_PRINTF("EBX]");
+	return M.x86.R_EBX * index;
+      case 4:
+	DECODE_PRINTF("0]");
+	return 0;
+      case 5:
+	DECODE_PRINTF("EBP]");
+	return M.x86.R_EBP * index;
+      case 6:
+	DECODE_PRINTF("ESI]");
+	return M.x86.R_ESI * index;
+      case 7:
+	DECODE_PRINTF("EDI]");
+	return M.x86.R_EDI * index;
+    }
+    HALT_SYS();
+    return 0;			/* NOT REACHED OR REACHED ON ERROR */
+}
+
+/****************************************************************************
+PARAMETERS:
+mod - MOD value of preceding ModR/M byte
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Decodes SIB addressing byte and returns calculated effective address.
+****************************************************************************/
+unsigned decode_sib_address(
+    int mod)
+{
+    int sib   = fetch_byte_imm();
+    int ss    = (sib >> 6) & 0x03;
+    int index = (sib >> 3) & 0x07;
+    int base  = sib & 0x07;
+    int offset = 0;
+    int displacement;
+
+    switch (base) {
+      case 0:
+	DECODE_PRINTF("[EAX]");
+	offset = M.x86.R_EAX;
+	break;
+      case 1:
+	DECODE_PRINTF("[ECX]");
+	offset = M.x86.R_ECX;
+	break;
+      case 2:
+	DECODE_PRINTF("[EDX]");
+	offset = M.x86.R_EDX;
+	break;
+      case 3:
+	DECODE_PRINTF("[EBX]");
+	offset = M.x86.R_EBX;
+	break;
+      case 4:
+	DECODE_PRINTF("[ESP]");
+	offset = M.x86.R_ESP;
+	break;
+      case 5:
+	switch (mod) {
+	  case 0:
+	    displacement = (s32)fetch_long_imm();
+	    DECODE_PRINTF2("[%d]", displacement);
+	    offset = displacement;
+	    break;
+	  case 1:
+	    displacement = (s8)fetch_byte_imm();
+	    DECODE_PRINTF2("[%d][EBP]", displacement);
+	    offset = M.x86.R_EBP + displacement;
+	    break;
+	  case 2:
+	    displacement = (s32)fetch_long_imm();
+	    DECODE_PRINTF2("[%d][EBP]", displacement);
+	    offset = M.x86.R_EBP + displacement;
+	    break;
+	  default:
+	    HALT_SYS();
+	}
+	DECODE_PRINTF("[EAX]");
+	offset = M.x86.R_EAX;
+	break;
+      case 6:
+	DECODE_PRINTF("[ESI]");
+	offset = M.x86.R_ESI;
+	break;
+      case 7:
+	DECODE_PRINTF("[EDI]");
+	offset = M.x86.R_EDI;
+	break;
+      default:
+	HALT_SYS();
+    }
+    offset += decode_sib_si(ss, index);
+    return offset;
+
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=00 addressing.  Also enables the
+decoding of instructions.
+
+NOTE:	The code which specifies the corresponding segment (ds vs ss)
+	below in the case of [BP+..].  The assumption here is that at the
+	point that this subroutine is called, the bit corresponding to
+	SYSMODE_SEG_DS_SS will be zero.	 After every instruction
+	except the segment override instructions, this bit (as well
+	as any bits indicating segment overrides) will be clear.  So
+	if a SS access is needed, set this bit.	 Otherwise, DS access
+	occurs (unless any of the segment override bits are set).
+****************************************************************************/
+unsigned decode_rm00_address(
+    int rm)
+{
+    unsigned offset;
+
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+	/* 32-bit addressing */
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF("[EAX]");
+	    return M.x86.R_EAX;
+	  case 1:
+	    DECODE_PRINTF("[ECX]");
+	    return M.x86.R_ECX;
+	  case 2:
+	    DECODE_PRINTF("[EDX]");
+	    return M.x86.R_EDX;
+	  case 3:
+	    DECODE_PRINTF("[EBX]");
+	    return M.x86.R_EBX;
+	  case 4:
+	    return decode_sib_address(0);
+	  case 5:
+	    offset = fetch_long_imm();
+	    DECODE_PRINTF2("[%08x]", offset);
+	    return offset;
+	  case 6:
+	    DECODE_PRINTF("[ESI]");
+	    return M.x86.R_ESI;
+	  case 7:
+	    DECODE_PRINTF("[EDI]");
+	    return M.x86.R_EDI;
+	}
+    } else {
+	/* 16-bit addressing */
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF("[BX+SI]");
+	    return (M.x86.R_BX + M.x86.R_SI) & 0xffff;
+	  case 1:
+	    DECODE_PRINTF("[BX+DI]");
+	    return (M.x86.R_BX + M.x86.R_DI) & 0xffff;
+	  case 2:
+	    DECODE_PRINTF("[BP+SI]");
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_SI) & 0xffff;
+	  case 3:
+	    DECODE_PRINTF("[BP+DI]");
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_DI) & 0xffff;
+	  case 4:
+	    DECODE_PRINTF("[SI]");
+	    return M.x86.R_SI;
+	  case 5:
+	    DECODE_PRINTF("[DI]");
+	    return M.x86.R_DI;
+	  case 6:
+	    offset = fetch_word_imm();
+	    DECODE_PRINTF2("[%04x]", offset);
+	    return offset;
+	  case 7:
+	    DECODE_PRINTF("[BX]");
+	    return M.x86.R_BX;
+	}
+    }
+    HALT_SYS();
+    return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=01 addressing.  Also enables the
+decoding of instructions.
+****************************************************************************/
+unsigned decode_rm01_address(
+    int rm)
+{
+    int displacement;
+
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+	/* 32-bit addressing */
+	if (rm != 4)
+	    displacement = (s8)fetch_byte_imm();
+	else
+	    displacement = 0;
+
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF2("%d[EAX]", displacement);
+	    return M.x86.R_EAX + displacement;
+	  case 1:
+	    DECODE_PRINTF2("%d[ECX]", displacement);
+	    return M.x86.R_ECX + displacement;
+	  case 2:
+	    DECODE_PRINTF2("%d[EDX]", displacement);
+	    return M.x86.R_EDX + displacement;
+	  case 3:
+	    DECODE_PRINTF2("%d[EBX]", displacement);
+	    return M.x86.R_EBX + displacement;
+	  case 4: {
+	    int offset = decode_sib_address(1);
+	    displacement = (s8)fetch_byte_imm();
+	    DECODE_PRINTF2("[%d]", displacement);
+	    return offset + displacement;
+	  }
+	  case 5:
+	    DECODE_PRINTF2("%d[EBP]", displacement);
+	    return M.x86.R_EBP + displacement;
+	  case 6:
+	    DECODE_PRINTF2("%d[ESI]", displacement);
+	    return M.x86.R_ESI + displacement;
+	  case 7:
+	    DECODE_PRINTF2("%d[EDI]", displacement);
+	    return M.x86.R_EDI + displacement;
+	}
+    } else {
+	/* 16-bit addressing */
+	displacement = (s8)fetch_byte_imm();
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF2("%d[BX+SI]", displacement);
+	    return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+	  case 1:
+	    DECODE_PRINTF2("%d[BX+DI]", displacement);
+	    return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+	  case 2:
+	    DECODE_PRINTF2("%d[BP+SI]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+	  case 3:
+	    DECODE_PRINTF2("%d[BP+DI]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+	  case 4:
+	    DECODE_PRINTF2("%d[SI]", displacement);
+	    return (M.x86.R_SI + displacement) & 0xffff;
+	  case 5:
+	    DECODE_PRINTF2("%d[DI]", displacement);
+	    return (M.x86.R_DI + displacement) & 0xffff;
+	  case 6:
+	    DECODE_PRINTF2("%d[BP]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + displacement) & 0xffff;
+	  case 7:
+	    DECODE_PRINTF2("%d[BX]", displacement);
+	    return (M.x86.R_BX + displacement) & 0xffff;
+	}
+    }
+    HALT_SYS();
+    return 0;			/* SHOULD NOT HAPPEN */
+}
+
+/****************************************************************************
+PARAMETERS:
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding
+
+REMARKS:
+Return the offset given by mod=10 addressing.  Also enables the
+decoding of instructions.
+****************************************************************************/
+unsigned decode_rm10_address(
+    int rm)
+{
+    if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
+	int displacement;
+
+	/* 32-bit addressing */
+	if (rm != 4)
+	    displacement = (s32)fetch_long_imm();
+	else
+	    displacement = 0;
+
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF2("%d[EAX]", displacement);
+	    return M.x86.R_EAX + displacement;
+	  case 1:
+	    DECODE_PRINTF2("%d[ECX]", displacement);
+	    return M.x86.R_ECX + displacement;
+	  case 2:
+	    DECODE_PRINTF2("%d[EDX]", displacement);
+	    return M.x86.R_EDX + displacement;
+	  case 3:
+	    DECODE_PRINTF2("%d[EBX]", displacement);
+	    return M.x86.R_EBX + displacement;
+	  case 4: {
+	    int offset = decode_sib_address(2);
+	    displacement = (s32)fetch_long_imm();
+	    DECODE_PRINTF2("[%d]", displacement);
+	    return offset + displacement;
+	  }
+	  case 5:
+	    DECODE_PRINTF2("%d[EBP]", displacement);
+	    return M.x86.R_EBP + displacement;
+	  case 6:
+	    DECODE_PRINTF2("%d[ESI]", displacement);
+	    return M.x86.R_ESI + displacement;
+	  case 7:
+	    DECODE_PRINTF2("%d[EDI]", displacement);
+	    return M.x86.R_EDI + displacement;
+	}
+    } else {
+	int displacement = (s16)fetch_word_imm();
+
+	/* 16-bit addressing */
+	switch (rm) {
+	  case 0:
+	    DECODE_PRINTF2("%d[BX+SI]", displacement);
+	    return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff;
+	  case 1:
+	    DECODE_PRINTF2("%d[BX+DI]", displacement);
+	    return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff;
+	  case 2:
+	    DECODE_PRINTF2("%d[BP+SI]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff;
+	  case 3:
+	    DECODE_PRINTF2("%d[BP+DI]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff;
+	  case 4:
+	    DECODE_PRINTF2("%d[SI]", displacement);
+	    return (M.x86.R_SI + displacement) & 0xffff;
+	  case 5:
+	    DECODE_PRINTF2("%d[DI]", displacement);
+	    return (M.x86.R_DI + displacement) & 0xffff;
+	  case 6:
+	    DECODE_PRINTF2("%d[BP]", displacement);
+	    M.x86.mode |= SYSMODE_SEG_DS_SS;
+	    return (M.x86.R_BP + displacement) & 0xffff;
+	  case 7:
+	    DECODE_PRINTF2("%d[BX]", displacement);
+	    return (M.x86.R_BX + displacement) & 0xffff;
+	}
+    }
+    HALT_SYS();
+    return 0;			/* SHOULD NOT HAPPEN */
+}
+
+/****************************************************************************
+PARAMETERS:
+mod - modifier
+rm  - RM value to decode
+
+RETURNS:
+Offset in memory for the address decoding, multiplexing calls to
+the decode_rmXX_address functions
+
+REMARKS:
+Return the offset given by "mod" addressing.
+****************************************************************************/
+
+unsigned decode_rmXX_address(int mod, int rm)
+{
+  if(mod == 0)
+    return decode_rm00_address(rm);
+  if(mod == 1)
+    return decode_rm01_address(rm);
+  return decode_rm10_address(rm);
+}
+
+#endif
diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c
new file mode 100644
index 0000000..d334fb5
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/ops.c
@@ -0,0 +1,5436 @@
+/****************************************************************************
+*			Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*  Jason Jin <Jason.jin@freescale.com>
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*				     Copyright (C) David Mosberger-Tang
+*					   Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:		ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	This file includes subroutines to implement the decoding
+*		and emulation of all the x86 processor instructions.
+*
+* There are approximately 250 subroutines in here, which correspond
+* to the 256 byte-"opcodes" found on the 8086.	The table which
+* dispatches this is found in the files optab.[ch].
+*
+* Each opcode proc has a comment preceeding it which gives it's table
+* address.  Several opcodes are missing (undefined) in the table.
+*
+* Each proc includes information for decoding (DECODE_PRINTF and
+* DECODE_PRINTF2), debugging (TRACE_REGS, SINGLE_STEP), and misc
+* functions (START_OF_INSTR, END_OF_INSTR).
+*
+* Many of the procedures are *VERY* similar in coding.	This has
+* allowed for a very large amount of code to be generated in a fairly
+* short amount of time (i.e. cut, paste, and modify).  The result is
+* that much of the code below could have been folded into subroutines
+* for a large reduction in size of this file.  The downside would be
+* that there would be a penalty in execution speed.  The file could
+* also have been *MUCH* larger by inlining certain functions which
+* were called.	This could have resulted even faster execution.	 The
+* prime directive I used to decide whether to inline the code or to
+* modularize it, was basically: 1) no unnecessary subroutine calls,
+* 2) no routines more than about 200 lines in size, and 3) modularize
+* any code that I might not get right the first time.  The fetch_*
+* subroutines fall into the latter category.  The The decode_* fall
+* into the second category.  The coding of the "switch(mod){ .... }"
+* in many of the subroutines below falls into the first category.
+* Especially, the coding of {add,and,or,sub,...}_{byte,word}
+* subroutines are an especially glaring case of the third guideline.
+* Since so much of the code is cloned from other modules (compare
+* opcode #00 to opcode #01), making the basic operations subroutine
+* calls is especially important; otherwise mistakes in coding an
+* "add" would represent a nightmare in maintenance.
+*
+* Jason ported this file to u-boot. place all the function pointer in
+* the got2 sector. Removed some opcode.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+#if defined(CONFIG_BIOSEMU)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/* constant arrays to do several instructions in just one function */
+
+#ifdef DEBUG
+static char *x86emu_GenOpName[8] = {
+    "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"};
+#endif
+
+/* used by several opcodes  */
+static u8 (*genop_byte_operation[])(u8 d, u8 s) __attribute__ ((section(".got2"))) =
+{
+    add_byte,		/* 00 */
+    or_byte,		/* 01 */
+    adc_byte,		/* 02 */
+    sbb_byte,		/* 03 */
+    and_byte,		/* 04 */
+    sub_byte,		/* 05 */
+    xor_byte,		/* 06 */
+    cmp_byte,		/* 07 */
+};
+
+static u16 (*genop_word_operation[])(u16 d, u16 s) __attribute__ ((section(".got2"))) =
+{
+    add_word,		/*00 */
+    or_word,		/*01 */
+    adc_word,		/*02 */
+    sbb_word,		/*03 */
+    and_word,		/*04 */
+    sub_word,		/*05 */
+    xor_word,		/*06 */
+    cmp_word,		/*07 */
+};
+
+static u32 (*genop_long_operation[])(u32 d, u32 s) __attribute__ ((section(".got2"))) =
+{
+    add_long,		/*00 */
+    or_long,		/*01 */
+    adc_long,		/*02 */
+    sbb_long,		/*03 */
+    and_long,		/*04 */
+    sub_long,		/*05 */
+    xor_long,		/*06 */
+    cmp_long,		/*07 */
+};
+
+/* used by opcodes 80, c0, d0, and d2. */
+static u8(*opcD0_byte_operation[])(u8 d, u8 s) __attribute__ ((section(".got2"))) =
+{
+    rol_byte,
+    ror_byte,
+    rcl_byte,
+    rcr_byte,
+    shl_byte,
+    shr_byte,
+    shl_byte,		/* sal_byte === shl_byte  by definition */
+    sar_byte,
+};
+
+/* used by opcodes c1, d1, and d3. */
+static u16(*opcD1_word_operation[])(u16 s, u8 d) __attribute__ ((section(".got2"))) =
+{
+    rol_word,
+    ror_word,
+    rcl_word,
+    rcr_word,
+    shl_word,
+    shr_word,
+    shl_word,		/* sal_byte === shl_byte  by definition */
+    sar_word,
+};
+
+/* used by opcodes c1, d1, and d3. */
+static u32 (*opcD1_long_operation[])(u32 s, u8 d) __attribute__ ((section(".got2"))) =
+{
+    rol_long,
+    ror_long,
+    rcl_long,
+    rcr_long,
+    shl_long,
+    shr_long,
+    shl_long,		/* sal_byte === shl_byte  by definition */
+    sar_long,
+};
+
+#ifdef DEBUG
+
+static char *opF6_names[8] =
+  { "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" };
+
+#endif
+
+/****************************************************************************
+PARAMETERS:
+op1 - Instruction op code
+
+REMARKS:
+Handles illegal opcodes.
+****************************************************************************/
+void x86emuOp_illegal_op(
+    u8 op1)
+{
+    START_OF_INSTR();
+    if (M.x86.R_SP != 0) {
+	DECODE_PRINTF("ILLEGAL X86 OPCODE\n");
+	TRACE_REGS();
+	DB( printk("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n",
+	    M.x86.R_CS, M.x86.R_IP-1,op1));
+	HALT_SYS();
+	}
+    else {
+	/* If we get here, it means the stack pointer is back to zero
+	 * so we are just returning from an emulator service call
+	 * so therte is no need to display an error message. We trap
+	 * the emulator with an 0xF1 opcode to finish the service
+	 * call.
+	 */
+	X86EMU_halt_sys();
+	}
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
+****************************************************************************/
+void x86emuOp_genop_byte_RM_R(u8 op1)
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8 *destreg, *srcreg;
+    u8 destval;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF(x86emu_GenOpName[op1]);
+    DECODE_PRINTF("\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if(mod<3)
+	{ destoffset = decode_rmXX_address(mod,rl);
+	DECODE_PRINTF(",");
+	destval = fetch_data_byte(destoffset);
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	destval = genop_byte_operation[op1](destval, *srcreg);
+	store_data_byte(destoffset, destval);
+	}
+    else
+	{			/* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = genop_byte_operation[op1](*destreg, *srcreg);
+	}
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39
+****************************************************************************/
+void x86emuOp_genop_word_RM_R(u8 op1)
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF(x86emu_GenOpName[op1]);
+    DECODE_PRINTF("\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+
+    if(mod<3) {
+	destoffset = decode_rmXX_address(mod,rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_long(destoffset);
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = genop_long_operation[op1](destval, *srcreg);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+	    u16 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_word(destoffset);
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = genop_word_operation[op1](destval, *srcreg);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			/* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = genop_long_operation[op1](*destreg, *srcreg);
+	} else {
+	    u16 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = genop_word_operation[op1](*destreg, *srcreg);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a
+****************************************************************************/
+void x86emuOp_genop_byte_R_RM(u8 op1)
+{
+    int mod, rl, rh;
+    u8 *destreg, *srcreg;
+    uint srcoffset;
+    u8 srcval;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF(x86emu_GenOpName[op1]);
+    DECODE_PRINTF("\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod,rl);
+	srcval = fetch_data_byte(srcoffset);
+    } else {	 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	srcval = *srcreg;
+    }
+    DECODE_PRINTF("\n");
+    TRACE_AND_STEP();
+    *destreg = genop_byte_operation[op1](*destreg, srcval);
+
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b
+****************************************************************************/
+void x86emuOp_genop_word_R_RM(u8 op1)
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    u32 *destreg32, srcval;
+    u16 *destreg;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF(x86emu_GenOpName[op1]);
+    DECODE_PRINTF("\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod,rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    destreg32 = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_long(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg32 = genop_long_operation[op1](*destreg32, srcval);
+	} else {
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_word(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = genop_word_operation[op1](*destreg, srcval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg;
+	    destreg32 = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg32 = genop_long_operation[op1](*destreg32, *srcreg);
+	} else {
+	    u16 *srcreg;
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = genop_word_operation[op1](*destreg, *srcreg);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c
+****************************************************************************/
+void x86emuOp_genop_byte_AL_IMM(u8 op1)
+{
+    u8 srcval;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF(x86emu_GenOpName[op1]);
+    DECODE_PRINTF("\tAL,");
+    srcval = fetch_byte_imm();
+    DECODE_PRINTF2("%x\n", srcval);
+    TRACE_AND_STEP();
+    M.x86.R_AL = genop_byte_operation[op1](M.x86.R_AL, srcval);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcodes 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d
+****************************************************************************/
+void x86emuOp_genop_word_AX_IMM(u8 op1)
+{
+    u32 srcval;
+
+    op1 = (op1 >> 3) & 0x7;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF(x86emu_GenOpName[op1]);
+	DECODE_PRINTF("\tEAX,");
+	srcval = fetch_long_imm();
+    } else {
+	DECODE_PRINTF(x86emu_GenOpName[op1]);
+	DECODE_PRINTF("\tAX,");
+	srcval = fetch_word_imm();
+    }
+    DECODE_PRINTF2("%x\n", srcval);
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EAX = genop_long_operation[op1](M.x86.R_EAX, srcval);
+    } else {
+	M.x86.R_AX = genop_word_operation[op1](M.x86.R_AX, (u16)srcval);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x06
+****************************************************************************/
+void x86emuOp_push_ES(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tES\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_ES);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x07
+****************************************************************************/
+void x86emuOp_pop_ES(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\tES\n");
+    TRACE_AND_STEP();
+    M.x86.R_ES = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0e
+****************************************************************************/
+void x86emuOp_push_CS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tCS\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_CS);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f. Escape for two-byte opcode (286 or better)
+****************************************************************************/
+void x86emuOp_two_byte(u8 X86EMU_UNUSED(op1))
+{
+    u8 op2 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
+    INC_DECODED_INST_LEN(1);
+    (*x86emu_optab2[op2])(op2);
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x16
+****************************************************************************/
+void x86emuOp_push_SS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tSS\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_SS);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x17
+****************************************************************************/
+void x86emuOp_pop_SS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\tSS\n");
+    TRACE_AND_STEP();
+    M.x86.R_SS = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1e
+****************************************************************************/
+void x86emuOp_push_DS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tDS\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_DS);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x1f
+****************************************************************************/
+void x86emuOp_pop_DS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\tDS\n");
+    TRACE_AND_STEP();
+    M.x86.R_DS = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x26
+****************************************************************************/
+void x86emuOp_segovr_ES(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("ES:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_ES;
+    /*
+     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+     * opcode subroutines we do not want to do this.
+     */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x27
+****************************************************************************/
+void x86emuOp_daa(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("DAA\n");
+    TRACE_AND_STEP();
+    M.x86.R_AL = daa_byte(M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2e
+****************************************************************************/
+void x86emuOp_segovr_CS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("CS:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_CS;
+    /* note no DECODE_CLEAR_SEGOVR here. */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x2f
+****************************************************************************/
+void x86emuOp_das(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("DAS\n");
+    TRACE_AND_STEP();
+    M.x86.R_AL = das_byte(M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x36
+****************************************************************************/
+void x86emuOp_segovr_SS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("SS:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_SS;
+    /* no DECODE_CLEAR_SEGOVR ! */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x37
+****************************************************************************/
+void x86emuOp_aaa(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("AAA\n");
+    TRACE_AND_STEP();
+    M.x86.R_AX = aaa_word(M.x86.R_AX);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3e
+****************************************************************************/
+void x86emuOp_segovr_DS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("DS:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_DS;
+    /* NO DECODE_CLEAR_SEGOVR! */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x3f
+****************************************************************************/
+void x86emuOp_aas(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("AAS\n");
+    TRACE_AND_STEP();
+    M.x86.R_AX = aas_word(M.x86.R_AX);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x40 - 0x47
+****************************************************************************/
+void x86emuOp_inc_register(u8 op1)
+{
+    START_OF_INSTR();
+    op1 &= 0x7;
+    DECODE_PRINTF("INC\t");
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg;
+	reg = DECODE_RM_LONG_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = inc_long(*reg);
+    } else {
+	u16 *reg;
+	reg = DECODE_RM_WORD_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = inc_word(*reg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x48 - 0x4F
+****************************************************************************/
+void x86emuOp_dec_register(u8 op1)
+{
+    START_OF_INSTR();
+    op1 &= 0x7;
+    DECODE_PRINTF("DEC\t");
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg;
+	reg = DECODE_RM_LONG_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = dec_long(*reg);
+    } else {
+	u16 *reg;
+	reg = DECODE_RM_WORD_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = dec_word(*reg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x50 - 0x57
+****************************************************************************/
+void x86emuOp_push_register(u8 op1)
+{
+    START_OF_INSTR();
+    op1 &= 0x7;
+    DECODE_PRINTF("PUSH\t");
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg;
+	reg = DECODE_RM_LONG_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	push_long(*reg);
+    } else {
+	u16 *reg;
+	reg = DECODE_RM_WORD_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	push_word(*reg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x58 - 0x5F
+****************************************************************************/
+void x86emuOp_pop_register(u8 op1)
+{
+    START_OF_INSTR();
+    op1 &= 0x7;
+    DECODE_PRINTF("POP\t");
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg;
+	reg = DECODE_RM_LONG_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = pop_long();
+    } else {
+	u16 *reg;
+	reg = DECODE_RM_WORD_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*reg = pop_word();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x60
+****************************************************************************/
+void x86emuOp_push_all(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("PUSHAD\n");
+    } else {
+	DECODE_PRINTF("PUSHA\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 old_sp = M.x86.R_ESP;
+
+	push_long(M.x86.R_EAX);
+	push_long(M.x86.R_ECX);
+	push_long(M.x86.R_EDX);
+	push_long(M.x86.R_EBX);
+	push_long(old_sp);
+	push_long(M.x86.R_EBP);
+	push_long(M.x86.R_ESI);
+	push_long(M.x86.R_EDI);
+    } else {
+	u16 old_sp = M.x86.R_SP;
+
+	push_word(M.x86.R_AX);
+	push_word(M.x86.R_CX);
+	push_word(M.x86.R_DX);
+	push_word(M.x86.R_BX);
+	push_word(old_sp);
+	push_word(M.x86.R_BP);
+	push_word(M.x86.R_SI);
+	push_word(M.x86.R_DI);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x61
+****************************************************************************/
+void x86emuOp_pop_all(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("POPAD\n");
+    } else {
+	DECODE_PRINTF("POPA\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EDI = pop_long();
+	M.x86.R_ESI = pop_long();
+	M.x86.R_EBP = pop_long();
+	M.x86.R_ESP += 4;	       /* skip ESP */
+	M.x86.R_EBX = pop_long();
+	M.x86.R_EDX = pop_long();
+	M.x86.R_ECX = pop_long();
+	M.x86.R_EAX = pop_long();
+    } else {
+	M.x86.R_DI = pop_word();
+	M.x86.R_SI = pop_word();
+	M.x86.R_BP = pop_word();
+	M.x86.R_SP += 2;	       /* skip SP */
+	M.x86.R_BX = pop_word();
+	M.x86.R_DX = pop_word();
+	M.x86.R_CX = pop_word();
+	M.x86.R_AX = pop_word();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/*opcode 0x62	ILLEGAL OP, calls x86emuOp_illegal_op() */
+/*opcode 0x63	ILLEGAL OP, calls x86emuOp_illegal_op() */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x64
+****************************************************************************/
+void x86emuOp_segovr_FS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("FS:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_FS;
+    /*
+     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+     * opcode subroutines we do not want to do this.
+     */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x65
+****************************************************************************/
+void x86emuOp_segovr_GS(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("GS:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_SEGOVR_GS;
+    /*
+     * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
+     * opcode subroutines we do not want to do this.
+     */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x66 - prefix for 32-bit register
+****************************************************************************/
+void x86emuOp_prefix_data(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("DATA:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_PREFIX_DATA;
+    /* note no DECODE_CLEAR_SEGOVR here. */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x67 - prefix for 32-bit address
+****************************************************************************/
+void x86emuOp_prefix_addr(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("ADDR:\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_PREFIX_ADDR;
+    /* note no DECODE_CLEAR_SEGOVR here. */
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x68
+****************************************************************************/
+void x86emuOp_push_word_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u32 imm;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	imm = fetch_long_imm();
+    } else {
+	imm = fetch_word_imm();
+    }
+    DECODE_PRINTF2("PUSH\t%x\n", imm);
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	push_long(imm);
+    } else {
+	push_word((u16)imm);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x69
+****************************************************************************/
+void x86emuOp_imul_word_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("IMUL\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+	    u32 res_lo,res_hi;
+	    s32 imm;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_long(srcoffset);
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+	    if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
+		(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+	    u32 res;
+	    s16 imm;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_word(srcoffset);
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    res = (s16)srcval * (s16)imm;
+	    if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
+		(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+	    u32 res_lo,res_hi;
+	    s32 imm;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
+	    if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
+		(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg,*srcreg;
+	    u32 res;
+	    s16 imm;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    res = (s16)*srcreg * (s16)imm;
+	    if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
+		(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6a
+****************************************************************************/
+void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+    s16 imm;
+
+    START_OF_INSTR();
+    imm = (s8)fetch_byte_imm();
+    DECODE_PRINTF2("PUSH\t%d\n", imm);
+    TRACE_AND_STEP();
+    push_word(imm);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6b
+****************************************************************************/
+void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    s8	imm;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("IMUL\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+	    u32 res_lo,res_hi;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_long(srcoffset);
+	    imm = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
+	    if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
+		(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+	    u32 res;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcval = fetch_data_word(srcoffset);
+	    imm = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    res = (s16)srcval * (s16)imm;
+	    if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
+		(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+	    u32 res_lo,res_hi;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    imm = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
+	    if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
+		(((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg,*srcreg;
+	    u32 res;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    imm = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", (s32)imm);
+	    TRACE_AND_STEP();
+	    res = (s16)*srcreg * (s16)imm;
+	    if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
+		(((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    } else {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6c
+****************************************************************************/
+void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("INSB\n");
+    ins(1);
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6d
+****************************************************************************/
+void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("INSD\n");
+	ins(4);
+    } else {
+	DECODE_PRINTF("INSW\n");
+	ins(2);
+    }
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6e
+****************************************************************************/
+void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("OUTSB\n");
+    outs(1);
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x6f
+****************************************************************************/
+void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("OUTSD\n");
+	outs(4);
+    } else {
+	DECODE_PRINTF("OUTSW\n");
+	outs(2);
+    }
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x70 - 0x7F
+****************************************************************************/
+int x86emu_check_jump_condition(u8 op);
+
+void x86emuOp_jump_near_cond(u8 op1)
+{
+    s8 offset;
+    u16 target;
+    int cond;
+
+    /* jump to byte offset if overflow flag is set */
+    START_OF_INSTR();
+    cond = x86emu_check_jump_condition(op1 & 0xF);
+    offset = (s8)fetch_byte_imm();
+    target = (u16)(M.x86.R_IP + (s16)offset);
+    DECODE_PRINTF2("%x\n", target);
+    TRACE_AND_STEP();
+    if (cond)
+	M.x86.R_IP = target;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x80
+****************************************************************************/
+void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 imm;
+    u8 destval;
+
+    /*
+     * Weirdo special case instruction format.	Part of the opcode
+     * held below in "RH".  Doubly nested case would result, except
+     * that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ADD\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("OR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("ADC\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("SBB\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("AND\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SUB\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("XOR\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("CMP\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	destval = fetch_data_byte(destoffset);
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2("%x\n", imm);
+	TRACE_AND_STEP();
+	destval = (*genop_byte_operation[rh]) (destval, imm);
+	if (rh != 7)
+	    store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",");
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2("%x\n", imm);
+	TRACE_AND_STEP();
+	destval = (*genop_byte_operation[rh]) (*destreg, imm);
+	if (rh != 7)
+	    *destreg = destval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x81
+****************************************************************************/
+void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    /*
+     * Weirdo special case instruction format.	Part of the opcode
+     * held below in "RH".  Doubly nested case would result, except
+     * that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ADD\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("OR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("ADC\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("SBB\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("AND\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SUB\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("XOR\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("CMP\t");
+	    break;
+	}
+    }
+#endif
+    /*
+     * Know operation, decode the mod byte to find the addressing
+     * mode.
+     */
+    if (mod < 3) {
+	DECODE_PRINTF("DWORD PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval,imm;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_long(destoffset);
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2("%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_long_operation[rh]) (destval, imm);
+	    if (rh != 7)
+		store_data_long(destoffset, destval);
+	} else {
+	    u16 destval,imm;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_word(destoffset);
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2("%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_word_operation[rh]) (destval, imm);
+	    if (rh != 7)
+		store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 destval,imm;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2("%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_long_operation[rh]) (*destreg, imm);
+	    if (rh != 7)
+		*destreg = destval;
+	} else {
+	    u16 *destreg;
+	    u16 destval,imm;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2("%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_word_operation[rh]) (*destreg, imm);
+	    if (rh != 7)
+		*destreg = destval;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x82
+****************************************************************************/
+void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 imm;
+    u8 destval;
+
+    /*
+     * Weirdo special case instruction format.	Part of the opcode
+     * held below in "RH".  Doubly nested case would result, except
+     * that the decoded instruction Similar to opcode 81, except that
+     * the immediate byte is sign extended to a word length.
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ADD\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("OR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("ADC\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("SBB\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("AND\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SUB\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("XOR\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("CMP\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	destval = fetch_data_byte(destoffset);
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2(",%x\n", imm);
+	TRACE_AND_STEP();
+	destval = (*genop_byte_operation[rh]) (destval, imm);
+	if (rh != 7)
+	    store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2(",%x\n", imm);
+	TRACE_AND_STEP();
+	destval = (*genop_byte_operation[rh]) (*destreg, imm);
+	if (rh != 7)
+	    *destreg = destval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x83
+****************************************************************************/
+void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    /*
+     * Weirdo special case instruction format.	Part of the opcode
+     * held below in "RH".  Doubly nested case would result, except
+     * that the decoded instruction Similar to opcode 81, except that
+     * the immediate byte is sign extended to a word length.
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+       switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ADD\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("OR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("ADC\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("SBB\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("AND\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SUB\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("XOR\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("CMP\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	DECODE_PRINTF("DWORD PTR ");
+	destoffset = decode_rmXX_address(mod,rl);
+
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval,imm;
+
+	    destval = fetch_data_long(destoffset);
+	    imm = (s8) fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_long_operation[rh]) (destval, imm);
+	    if (rh != 7)
+		store_data_long(destoffset, destval);
+	} else {
+	    u16 destval,imm;
+
+	    destval = fetch_data_word(destoffset);
+	    imm = (s8) fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_word_operation[rh]) (destval, imm);
+	    if (rh != 7)
+		store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 destval,imm;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    imm = (s8) fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_long_operation[rh]) (*destreg, imm);
+	    if (rh != 7)
+		*destreg = destval;
+	} else {
+	    u16 *destreg;
+	    u16 destval,imm;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    imm = (s8) fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    destval = (*genop_word_operation[rh]) (*destreg, imm);
+	    if (rh != 7)
+		*destreg = destval;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x84
+****************************************************************************/
+void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg, *srcreg;
+    uint destoffset;
+    u8 destval;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("TEST\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	destval = fetch_data_byte(destoffset);
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	test_byte(destval, *srcreg);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	test_byte(*destreg, *srcreg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x85
+****************************************************************************/
+void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("TEST\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_long(destoffset);
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    test_long(destval, *srcreg);
+	} else {
+	    u16 destval;
+	    u16 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    destval = fetch_data_word(destoffset);
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    test_word(destval, *srcreg);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    test_long(*destreg, *srcreg);
+	} else {
+	    u16 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    test_word(*destreg, *srcreg);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x86
+****************************************************************************/
+void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg, *srcreg;
+    uint destoffset;
+    u8 destval;
+    u8 tmp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("XCHG\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	destval = fetch_data_byte(destoffset);
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	tmp = *srcreg;
+	*srcreg = destval;
+	destval = tmp;
+	store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	tmp = *srcreg;
+	*srcreg = *destreg;
+	*destreg = tmp;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x87
+****************************************************************************/
+void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("XCHG\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg;
+	    u32 destval,tmp;
+
+	    destval = fetch_data_long(destoffset);
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    tmp = *srcreg;
+	    *srcreg = destval;
+	    destval = tmp;
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 *srcreg;
+	    u16 destval,tmp;
+
+	    destval = fetch_data_word(destoffset);
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    tmp = *srcreg;
+	    *srcreg = destval;
+	    destval = tmp;
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+	    u32 tmp;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    tmp = *srcreg;
+	    *srcreg = *destreg;
+	    *destreg = tmp;
+	} else {
+	    u16 *destreg,*srcreg;
+	    u16 tmp;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    tmp = *srcreg;
+	    *srcreg = *destreg;
+	    *destreg = tmp;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x88
+****************************************************************************/
+void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg, *srcreg;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	store_data_byte(destoffset, *srcreg);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = *srcreg;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x89
+****************************************************************************/
+void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    store_data_long(destoffset, *srcreg);
+	} else {
+	    u16 *srcreg;
+
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    store_data_word(destoffset, *srcreg);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	} else {
+	    u16 *destreg,*srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8a
+****************************************************************************/
+void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg, *srcreg;
+    uint srcoffset;
+    u8 srcval;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	srcval = fetch_data_byte(srcoffset);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = srcval;
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = *srcreg;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8b
+****************************************************************************/
+void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_long(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_word(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg, *srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	} else {
+	    u16 *destreg, *srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8c
+****************************************************************************/
+void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u16 *destreg, *srcreg;
+    uint destoffset;
+    u16 destval;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	srcreg = decode_rm_seg_register(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	destval = *srcreg;
+	store_data_word(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_WORD_REGISTER(rl);
+	DECODE_PRINTF(",");
+	srcreg = decode_rm_seg_register(rh);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = *srcreg;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8d
+****************************************************************************/
+void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u16 *srcreg;
+    uint destoffset;
+
+/*
+ * TODO: Need to handle address size prefix!
+ *
+ * lea	eax,[eax+ebx*2] ??
+ */
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LEA\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*srcreg = (u16)destoffset;
+	}
+    /* } else { undefined.  Do nothing. } */
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8e
+****************************************************************************/
+void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u16 *destreg, *srcreg;
+    uint srcoffset;
+    u16 srcval;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destreg = decode_rm_seg_register(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	srcval = fetch_data_word(srcoffset);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = srcval;
+    } else {			 /* register to register */
+	destreg = decode_rm_seg_register(rh);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_WORD_REGISTER(rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = *srcreg;
+    }
+    /*
+     * Clean up, and reset all the R_xSP pointers to the correct
+     * locations.  This is about 3x too much overhead (doing all the
+     * segreg ptrs when only one is needed, but this instruction
+     * *cannot* be that common, and this isn't too much work anyway.
+     */
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x8f
+****************************************************************************/
+void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (rh != 0) {
+	DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+	HALT_SYS();
+    }
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = pop_long();
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = pop_word();
+	    store_data_word(destoffset, destval);
+	}
+    } else {			/* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = pop_long();
+	} else {
+	    u16 *destreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = pop_word();
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x90
+****************************************************************************/
+void x86emuOp_nop(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("NOP\n");
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x91-0x97
+****************************************************************************/
+void x86emuOp_xchg_word_AX_register(u8 X86EMU_UNUSED(op1))
+{
+    u32 tmp;
+
+    op1 &= 0x7;
+
+    START_OF_INSTR();
+
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg32;
+	DECODE_PRINTF("XCHG\tEAX,");
+	reg32 = DECODE_RM_LONG_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	tmp = M.x86.R_EAX;
+	M.x86.R_EAX = *reg32;
+	*reg32 = tmp;
+    } else {
+	u16 *reg16;
+	DECODE_PRINTF("XCHG\tAX,");
+	reg16 = DECODE_RM_WORD_REGISTER(op1);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	tmp = M.x86.R_AX;
+	M.x86.R_EAX = *reg16;
+	*reg16 = (u16)tmp;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x98
+****************************************************************************/
+void x86emuOp_cbw(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("CWDE\n");
+    } else {
+	DECODE_PRINTF("CBW\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	if (M.x86.R_AX & 0x8000) {
+	    M.x86.R_EAX |= 0xffff0000;
+	} else {
+	    M.x86.R_EAX &= 0x0000ffff;
+	}
+    } else {
+	if (M.x86.R_AL & 0x80) {
+	    M.x86.R_AH = 0xff;
+	} else {
+	    M.x86.R_AH = 0x0;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x99
+****************************************************************************/
+void x86emuOp_cwd(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("CDQ\n");
+    } else {
+	DECODE_PRINTF("CWD\n");
+    }
+    DECODE_PRINTF("CWD\n");
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	if (M.x86.R_EAX & 0x80000000) {
+	    M.x86.R_EDX = 0xffffffff;
+	} else {
+	    M.x86.R_EDX = 0x0;
+	}
+    } else {
+	if (M.x86.R_AX & 0x8000) {
+	    M.x86.R_DX = 0xffff;
+	} else {
+	    M.x86.R_DX = 0x0;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9a
+****************************************************************************/
+void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 farseg, faroff;
+
+    START_OF_INSTR();
+	DECODE_PRINTF("CALL\t");
+	faroff = fetch_word_imm();
+	farseg = fetch_word_imm();
+	DECODE_PRINTF2("%04x:", farseg);
+	DECODE_PRINTF2("%04x\n", faroff);
+	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
+
+    /* XXX
+     *
+     * Hooked interrupt vectors calling into our "BIOS" will cause
+     * problems unless all intersegment stuff is checked for BIOS
+     * access.	Check needed here.  For moment, let it alone.
+     */
+    TRACE_AND_STEP();
+    push_word(M.x86.R_CS);
+    M.x86.R_CS = farseg;
+    push_word(M.x86.R_IP);
+    M.x86.R_IP = faroff;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9b
+****************************************************************************/
+void x86emuOp_wait(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("WAIT");
+    TRACE_AND_STEP();
+    /* NADA.  */
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9c
+****************************************************************************/
+void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1))
+{
+    u32 flags;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("PUSHFD\n");
+    } else {
+	DECODE_PRINTF("PUSHF\n");
+    }
+    TRACE_AND_STEP();
+
+    /* clear out *all* bits not representing flags, and turn on real bits */
+    flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	push_long(flags);
+    } else {
+	push_word((u16)flags);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9d
+****************************************************************************/
+void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("POPFD\n");
+    } else {
+	DECODE_PRINTF("POPF\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EFLG = pop_long();
+    } else {
+	M.x86.R_FLG = pop_word();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9e
+****************************************************************************/
+void x86emuOp_sahf(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("SAHF\n");
+    TRACE_AND_STEP();
+    /* clear the lower bits of the flag register */
+    M.x86.R_FLG &= 0xffffff00;
+    /* or in the AH register into the flags register */
+    M.x86.R_FLG |= M.x86.R_AH;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x9f
+****************************************************************************/
+void x86emuOp_lahf(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("LAHF\n");
+    TRACE_AND_STEP();
+	M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff);
+    /*undocumented TC++ behavior??? Nope.  It's documented, but
+       you have too look real hard to notice it. */
+    M.x86.R_AH |= 0x2;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa0
+****************************************************************************/
+void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 offset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\tAL,");
+    offset = fetch_word_imm();
+    DECODE_PRINTF2("[%04x]\n", offset);
+    TRACE_AND_STEP();
+    M.x86.R_AL = fetch_data_byte(offset);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa1
+****************************************************************************/
+void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 offset;
+
+    START_OF_INSTR();
+    offset = fetch_word_imm();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset);
+    } else {
+	DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset);
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EAX = fetch_data_long(offset);
+    } else {
+	M.x86.R_AX = fetch_data_word(offset);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa2
+****************************************************************************/
+void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 offset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    offset = fetch_word_imm();
+    DECODE_PRINTF2("[%04x],AL\n", offset);
+    TRACE_AND_STEP();
+    store_data_byte(offset, M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa3
+****************************************************************************/
+void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 offset;
+
+    START_OF_INSTR();
+    offset = fetch_word_imm();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset);
+    } else {
+	DECODE_PRINTF2("MOV\t[%04x],AX\n", offset);
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	store_data_long(offset, M.x86.R_EAX);
+    } else {
+	store_data_word(offset, M.x86.R_AX);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa4
+****************************************************************************/
+void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1))
+{
+    u8	val;
+    u32 count;
+    int inc;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOVS\tBYTE\n");
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -1;
+    else
+	inc = 1;
+    TRACE_AND_STEP();
+    count = 1;
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	count = M.x86.R_CX;
+	M.x86.R_CX = 0;
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    }
+    while (count--) {
+	val = fetch_data_byte(M.x86.R_SI);
+	store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val);
+	M.x86.R_SI += inc;
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa5
+****************************************************************************/
+void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1))
+{
+    u32 val;
+    int inc;
+    u32 count;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("MOVS\tDWORD\n");
+	if (ACCESS_FLAG(F_DF))	    /* down */
+	    inc = -4;
+	else
+	    inc = 4;
+    } else {
+	DECODE_PRINTF("MOVS\tWORD\n");
+	if (ACCESS_FLAG(F_DF))	    /* down */
+	    inc = -2;
+	else
+	    inc = 2;
+    }
+    TRACE_AND_STEP();
+    count = 1;
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	count = M.x86.R_CX;
+	M.x86.R_CX = 0;
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    }
+    while (count--) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    val = fetch_data_long(M.x86.R_SI);
+	    store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val);
+	} else {
+	    val = fetch_data_word(M.x86.R_SI);
+	    store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val);
+	}
+	M.x86.R_SI += inc;
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa6
+****************************************************************************/
+void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1))
+{
+    s8 val1, val2;
+    int inc;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("CMPS\tBYTE\n");
+    TRACE_AND_STEP();
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -1;
+    else
+	inc = 1;
+
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* REPE	 */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    val1 = fetch_data_byte(M.x86.R_SI);
+	    val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+		     cmp_byte(val1, val2);
+	    M.x86.R_CX -= 1;
+	    M.x86.R_SI += inc;
+	    M.x86.R_DI += inc;
+	    if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break;
+	    if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	val1 = fetch_data_byte(M.x86.R_SI);
+	val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+	cmp_byte(val1, val2);
+	M.x86.R_SI += inc;
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa7
+****************************************************************************/
+void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1))
+{
+    u32 val1,val2;
+    int inc;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("CMPS\tDWORD\n");
+	inc = 4;
+    } else {
+	DECODE_PRINTF("CMPS\tWORD\n");
+	inc = 2;
+    }
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -inc;
+
+    TRACE_AND_STEP();
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* REPE	 */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		val1 = fetch_data_long(M.x86.R_SI);
+		val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_long(val1, val2);
+	    } else {
+		val1 = fetch_data_word(M.x86.R_SI);
+		val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_word((u16)val1, (u16)val2);
+	    }
+	    M.x86.R_CX -= 1;
+	    M.x86.R_SI += inc;
+	    M.x86.R_DI += inc;
+	    if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break;
+	    if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    val1 = fetch_data_long(M.x86.R_SI);
+	    val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_long(val1, val2);
+	} else {
+	    val1 = fetch_data_word(M.x86.R_SI);
+	    val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_word((u16)val1, (u16)val2);
+	}
+	M.x86.R_SI += inc;
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa8
+****************************************************************************/
+void x86emuOp_test_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int imm;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("TEST\tAL,");
+    imm = fetch_byte_imm();
+    DECODE_PRINTF2("%04x\n", imm);
+    TRACE_AND_STEP();
+	test_byte(M.x86.R_AL, (u8)imm);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xa9
+****************************************************************************/
+void x86emuOp_test_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u32 srcval;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("TEST\tEAX,");
+	srcval = fetch_long_imm();
+    } else {
+	DECODE_PRINTF("TEST\tAX,");
+	srcval = fetch_word_imm();
+    }
+    DECODE_PRINTF2("%x\n", srcval);
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	test_long(M.x86.R_EAX, srcval);
+    } else {
+	test_word(M.x86.R_AX, (u16)srcval);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xaa
+****************************************************************************/
+void x86emuOp_stos_byte(u8 X86EMU_UNUSED(op1))
+{
+    int inc;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("STOS\tBYTE\n");
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -1;
+    else
+	inc = 1;
+    TRACE_AND_STEP();
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
+	    M.x86.R_CX -= 1;
+	    M.x86.R_DI += inc;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL);
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xab
+****************************************************************************/
+void x86emuOp_stos_word(u8 X86EMU_UNUSED(op1))
+{
+    int inc;
+    u32 count;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("STOS\tDWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -4;
+	else
+	    inc = 4;
+    } else {
+	DECODE_PRINTF("STOS\tWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -2;
+	else
+	    inc = 2;
+    }
+    TRACE_AND_STEP();
+    count = 1;
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	count = M.x86.R_CX;
+	M.x86.R_CX = 0;
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    }
+    while (count--) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    store_data_long_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_EAX);
+	} else {
+	    store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX);
+	}
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xac
+****************************************************************************/
+void x86emuOp_lods_byte(u8 X86EMU_UNUSED(op1))
+{
+    int inc;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LODS\tBYTE\n");
+    TRACE_AND_STEP();
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -1;
+    else
+	inc = 1;
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    M.x86.R_AL = fetch_data_byte(M.x86.R_SI);
+	    M.x86.R_CX -= 1;
+	    M.x86.R_SI += inc;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	M.x86.R_AL = fetch_data_byte(M.x86.R_SI);
+	M.x86.R_SI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xad
+****************************************************************************/
+void x86emuOp_lods_word(u8 X86EMU_UNUSED(op1))
+{
+    int inc;
+    u32 count;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("LODS\tDWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -4;
+	else
+	    inc = 4;
+    } else {
+	DECODE_PRINTF("LODS\tWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -2;
+	else
+	    inc = 2;
+    }
+    TRACE_AND_STEP();
+    count = 1;
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* move them until CX is ZERO. */
+	count = M.x86.R_CX;
+	M.x86.R_CX = 0;
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    }
+    while (count--) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    M.x86.R_EAX = fetch_data_long(M.x86.R_SI);
+	} else {
+	    M.x86.R_AX = fetch_data_word(M.x86.R_SI);
+	}
+	M.x86.R_SI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xae
+****************************************************************************/
+void x86emuOp_scas_byte(u8 X86EMU_UNUSED(op1))
+{
+    s8 val2;
+    int inc;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("SCAS\tBYTE\n");
+    TRACE_AND_STEP();
+    if (ACCESS_FLAG(F_DF))   /* down */
+	inc = -1;
+    else
+	inc = 1;
+    if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+	/* REPE	 */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_byte(M.x86.R_AL, val2);
+	    M.x86.R_CX -= 1;
+	    M.x86.R_DI += inc;
+	    if (ACCESS_FLAG(F_ZF) == 0)
+		break;
+	}
+	M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+	/* REPNE  */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_byte(M.x86.R_AL, val2);
+	    M.x86.R_CX -= 1;
+	    M.x86.R_DI += inc;
+	    if (ACCESS_FLAG(F_ZF))
+		break;		/* zero flag set means equal */
+	}
+	M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+    } else {
+	val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
+	cmp_byte(M.x86.R_AL, val2);
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xaf
+****************************************************************************/
+void x86emuOp_scas_word(u8 X86EMU_UNUSED(op1))
+{
+    int inc;
+    u32 val;
+
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("SCAS\tDWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -4;
+	else
+	    inc = 4;
+    } else {
+	DECODE_PRINTF("SCAS\tWORD\n");
+	if (ACCESS_FLAG(F_DF))	 /* down */
+	    inc = -2;
+	else
+	    inc = 2;
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_REPE) {
+	/* REPE	 */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_long(M.x86.R_EAX, val);
+	    } else {
+		val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_word(M.x86.R_AX, (u16)val);
+	    }
+	    M.x86.R_CX -= 1;
+	    M.x86.R_DI += inc;
+	    if (ACCESS_FLAG(F_ZF) == 0)
+		break;
+	}
+	M.x86.mode &= ~SYSMODE_PREFIX_REPE;
+    } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) {
+	/* REPNE  */
+	/* move them until CX is ZERO. */
+	while (M.x86.R_CX != 0) {
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_long(M.x86.R_EAX, val);
+	    } else {
+		val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+		cmp_word(M.x86.R_AX, (u16)val);
+	    }
+	    M.x86.R_CX -= 1;
+	    M.x86.R_DI += inc;
+	    if (ACCESS_FLAG(F_ZF))
+		break;		/* zero flag set means equal */
+	}
+	M.x86.mode &= ~SYSMODE_PREFIX_REPNE;
+    } else {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_long(M.x86.R_EAX, val);
+	} else {
+	    val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI);
+	    cmp_word(M.x86.R_AX, (u16)val);
+	}
+	M.x86.R_DI += inc;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb0 - 0xb7
+****************************************************************************/
+void x86emuOp_mov_byte_register_IMM(u8 op1)
+{
+    u8 imm, *ptr;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    ptr = DECODE_RM_BYTE_REGISTER(op1 & 0x7);
+    DECODE_PRINTF(",");
+    imm = fetch_byte_imm();
+    DECODE_PRINTF2("%x\n", imm);
+    TRACE_AND_STEP();
+    *ptr = imm;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xb8 - 0xbf
+****************************************************************************/
+void x86emuOp_mov_word_register_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u32 srcval;
+
+    op1 &= 0x7;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	u32 *reg32;
+	reg32 = DECODE_RM_LONG_REGISTER(op1);
+	srcval = fetch_long_imm();
+	DECODE_PRINTF2(",%x\n", srcval);
+	TRACE_AND_STEP();
+	*reg32 = srcval;
+    } else {
+	u16 *reg16;
+	reg16 = DECODE_RM_WORD_REGISTER(op1);
+	srcval = fetch_word_imm();
+	DECODE_PRINTF2(",%x\n", srcval);
+	TRACE_AND_STEP();
+	*reg16 = (u16)srcval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc0
+****************************************************************************/
+void x86emuOp_opcC0_byte_RM_MEM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 destval;
+    u8 amt;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	amt = fetch_byte_imm();
+	DECODE_PRINTF2(",%x\n", amt);
+	destval = fetch_data_byte(destoffset);
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (destval, amt);
+	store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	amt = fetch_byte_imm();
+	DECODE_PRINTF2(",%x\n", amt);
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (*destreg, amt);
+	*destreg = destval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc1
+****************************************************************************/
+void x86emuOp_opcC1_word_RM_MEM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8 amt;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+
+	    DECODE_PRINTF("DWORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    amt = fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", amt);
+	    destval = fetch_data_long(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_long_operation[rh]) (destval, amt);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+
+	    DECODE_PRINTF("WORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    amt = fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", amt);
+	    destval = fetch_data_word(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_word_operation[rh]) (destval, amt);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    amt = fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", amt);
+	    TRACE_AND_STEP();
+	    *destreg = (*opcD1_long_operation[rh]) (*destreg, amt);
+	} else {
+	    u16 *destreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    amt = fetch_byte_imm();
+	    DECODE_PRINTF2(",%x\n", amt);
+	    TRACE_AND_STEP();
+	    *destreg = (*opcD1_word_operation[rh]) (*destreg, amt);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc2
+****************************************************************************/
+void x86emuOp_ret_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 imm;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("RET\t");
+    imm = fetch_word_imm();
+    DECODE_PRINTF2("%x\n", imm);
+	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+	TRACE_AND_STEP();
+    M.x86.R_IP = pop_word();
+    M.x86.R_SP += imm;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc3
+****************************************************************************/
+void x86emuOp_ret_near(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("RET\n");
+	RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip);
+	TRACE_AND_STEP();
+    M.x86.R_IP = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc4
+****************************************************************************/
+void x86emuOp_les_R_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rh, rl;
+    u16 *dstreg;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LES\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	dstreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*dstreg = fetch_data_word(srcoffset);
+	M.x86.R_ES = fetch_data_word(srcoffset + 2);
+    }
+    /* else UNDEFINED!			 register to register */
+
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc5
+****************************************************************************/
+void x86emuOp_lds_R_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rh, rl;
+    u16 *dstreg;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LDS\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	dstreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*dstreg = fetch_data_word(srcoffset);
+	M.x86.R_DS = fetch_data_word(srcoffset + 2);
+    }
+    /* else UNDEFINED! */
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc6
+****************************************************************************/
+void x86emuOp_mov_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 imm;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (rh != 0) {
+	DECODE_PRINTF("ILLEGAL DECODE OF OPCODE c6\n");
+	HALT_SYS();
+    }
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2(",%2x\n", imm);
+	TRACE_AND_STEP();
+	store_data_byte(destoffset, imm);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	imm = fetch_byte_imm();
+	DECODE_PRINTF2(",%2x\n", imm);
+	TRACE_AND_STEP();
+	*destreg = imm;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc7
+****************************************************************************/
+void x86emuOp_mov_word_RM_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOV\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (rh != 0) {
+	DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
+	HALT_SYS();
+    }
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 imm;
+
+	    DECODE_PRINTF("DWORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    store_data_long(destoffset, imm);
+	} else {
+	    u16 imm;
+
+	    DECODE_PRINTF("WORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    store_data_word(destoffset, imm);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+			u32 *destreg;
+			u32 imm;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    imm = fetch_long_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    *destreg = imm;
+	} else {
+			u16 *destreg;
+			u16 imm;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    imm = fetch_word_imm();
+	    DECODE_PRINTF2(",%x\n", imm);
+	    TRACE_AND_STEP();
+	    *destreg = imm;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc8
+****************************************************************************/
+void x86emuOp_enter(u8 X86EMU_UNUSED(op1))
+{
+    u16 local,frame_pointer;
+    u8	nesting;
+    int i;
+
+    START_OF_INSTR();
+    local = fetch_word_imm();
+    nesting = fetch_byte_imm();
+    DECODE_PRINTF2("ENTER %x\n", local);
+    DECODE_PRINTF2(",%x\n", nesting);
+    TRACE_AND_STEP();
+    push_word(M.x86.R_BP);
+    frame_pointer = M.x86.R_SP;
+    if (nesting > 0) {
+	for (i = 1; i < nesting; i++) {
+	    M.x86.R_BP -= 2;
+	    push_word(fetch_data_word_abs(M.x86.R_SS, M.x86.R_BP));
+	    }
+	push_word(frame_pointer);
+	}
+    M.x86.R_BP = frame_pointer;
+    M.x86.R_SP = (u16)(M.x86.R_SP - local);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xc9
+****************************************************************************/
+void x86emuOp_leave(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("LEAVE\n");
+    TRACE_AND_STEP();
+    M.x86.R_SP = M.x86.R_BP;
+    M.x86.R_BP = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xca
+****************************************************************************/
+void x86emuOp_ret_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 imm;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("RETF\t");
+    imm = fetch_word_imm();
+    DECODE_PRINTF2("%x\n", imm);
+	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+	TRACE_AND_STEP();
+    M.x86.R_IP = pop_word();
+    M.x86.R_CS = pop_word();
+    M.x86.R_SP += imm;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcb
+****************************************************************************/
+void x86emuOp_ret_far(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("RETF\n");
+	RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip);
+	TRACE_AND_STEP();
+    M.x86.R_IP = pop_word();
+    M.x86.R_CS = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcc
+****************************************************************************/
+void x86emuOp_int3(u8 X86EMU_UNUSED(op1))
+{
+    u16 tmp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("INT 3\n");
+    tmp = (u16) mem_access_word(3 * 4 + 2);
+    /* access the segment register */
+    TRACE_AND_STEP();
+	if (_X86EMU_intrTab[3]) {
+		(*_X86EMU_intrTab[3])(3);
+    } else {
+	push_word((u16)M.x86.R_FLG);
+	CLEAR_FLAG(F_IF);
+	CLEAR_FLAG(F_TF);
+	push_word(M.x86.R_CS);
+	M.x86.R_CS = mem_access_word(3 * 4 + 2);
+	push_word(M.x86.R_IP);
+	M.x86.R_IP = mem_access_word(3 * 4);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcd
+****************************************************************************/
+void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 tmp;
+    u8 intnum;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("INT\t");
+    intnum = fetch_byte_imm();
+    DECODE_PRINTF2("%x\n", intnum);
+    tmp = mem_access_word(intnum * 4 + 2);
+    TRACE_AND_STEP();
+	if (_X86EMU_intrTab[intnum]) {
+		(*_X86EMU_intrTab[intnum])(intnum);
+    } else {
+	push_word((u16)M.x86.R_FLG);
+	CLEAR_FLAG(F_IF);
+	CLEAR_FLAG(F_TF);
+	push_word(M.x86.R_CS);
+	M.x86.R_CS = mem_access_word(intnum * 4 + 2);
+	push_word(M.x86.R_IP);
+	M.x86.R_IP = mem_access_word(intnum * 4);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xce
+****************************************************************************/
+void x86emuOp_into(u8 X86EMU_UNUSED(op1))
+{
+    u16 tmp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("INTO\n");
+    TRACE_AND_STEP();
+    if (ACCESS_FLAG(F_OF)) {
+	tmp = mem_access_word(4 * 4 + 2);
+		if (_X86EMU_intrTab[4]) {
+			(*_X86EMU_intrTab[4])(4);
+	} else {
+	    push_word((u16)M.x86.R_FLG);
+	    CLEAR_FLAG(F_IF);
+	    CLEAR_FLAG(F_TF);
+	    push_word(M.x86.R_CS);
+	    M.x86.R_CS = mem_access_word(4 * 4 + 2);
+	    push_word(M.x86.R_IP);
+	    M.x86.R_IP = mem_access_word(4 * 4);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xcf
+****************************************************************************/
+void x86emuOp_iret(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("IRET\n");
+
+    TRACE_AND_STEP();
+
+    M.x86.R_IP = pop_word();
+    M.x86.R_CS = pop_word();
+    M.x86.R_FLG = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd0
+****************************************************************************/
+void x86emuOp_opcD0_byte_RM_1(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 destval;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",1\n");
+	destval = fetch_data_byte(destoffset);
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (destval, 1);
+	store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",1\n");
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (*destreg, 1);
+	*destreg = destval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd1
+****************************************************************************/
+void x86emuOp_opcD1_word_RM_1(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+
+	    DECODE_PRINTF("DWORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    DECODE_PRINTF(",1\n");
+	    destval = fetch_data_long(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_long_operation[rh]) (destval, 1);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+
+	    DECODE_PRINTF("WORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    DECODE_PRINTF(",1\n");
+	    destval = fetch_data_word(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_word_operation[rh]) (destval, 1);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+			u32 destval;
+			u32 *destreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",1\n");
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_long_operation[rh]) (*destreg, 1);
+	    *destreg = destval;
+	} else {
+			u16 destval;
+			u16 *destreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",1\n");
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_word_operation[rh]) (*destreg, 1);
+	    *destreg = destval;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd2
+****************************************************************************/
+void x86emuOp_opcD2_byte_RM_CL(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 destval;
+    u8 amt;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    amt = M.x86.R_CL;
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",CL\n");
+	destval = fetch_data_byte(destoffset);
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (destval, amt);
+	store_data_byte(destoffset, destval);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF(",CL\n");
+	TRACE_AND_STEP();
+	destval = (*opcD0_byte_operation[rh]) (*destreg, amt);
+	*destreg = destval;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd3
+****************************************************************************/
+void x86emuOp_opcD3_word_RM_CL(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8 amt;
+
+    /*
+     * Yet another weirdo special case instruction format.  Part of
+     * the opcode held below in "RH".  Doubly nested case would
+     * result, except that the decoded instruction
+     */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("ROL\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("ROR\t");
+	    break;
+	case 2:
+	    DECODE_PRINTF("RCL\t");
+	    break;
+	case 3:
+	    DECODE_PRINTF("RCR\t");
+	    break;
+	case 4:
+	    DECODE_PRINTF("SHL\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("SHR\t");
+	    break;
+	case 6:
+	    DECODE_PRINTF("SAL\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("SAR\t");
+	    break;
+	}
+    }
+#endif
+    /* know operation, decode the mod byte to find the addressing
+       mode. */
+    amt = M.x86.R_CL;
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+
+	    DECODE_PRINTF("DWORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    DECODE_PRINTF(",CL\n");
+	    destval = fetch_data_long(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_long_operation[rh]) (destval, amt);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+
+	    DECODE_PRINTF("WORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    DECODE_PRINTF(",CL\n");
+	    destval = fetch_data_word(destoffset);
+	    TRACE_AND_STEP();
+	    destval = (*opcD1_word_operation[rh]) (destval, amt);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = (*opcD1_long_operation[rh]) (*destreg, amt);
+	} else {
+	    u16 *destreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = (*opcD1_word_operation[rh]) (*destreg, amt);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd4
+****************************************************************************/
+void x86emuOp_aam(u8 X86EMU_UNUSED(op1))
+{
+    u8 a;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("AAM\n");
+    a = fetch_byte_imm();      /* this is a stupid encoding. */
+    if (a != 10) {
+	DECODE_PRINTF("ERROR DECODING AAM\n");
+	TRACE_REGS();
+	HALT_SYS();
+    }
+    TRACE_AND_STEP();
+    /* note the type change here --- returning AL and AH in AX. */
+    M.x86.R_AX = aam_word(M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd5
+****************************************************************************/
+void x86emuOp_aad(u8 X86EMU_UNUSED(op1))
+{
+    u8 a;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("AAD\n");
+    a = fetch_byte_imm();
+    TRACE_AND_STEP();
+    M.x86.R_AX = aad_word(M.x86.R_AX);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/* opcode 0xd6 ILLEGAL OPCODE */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xd7
+****************************************************************************/
+void x86emuOp_xlat(u8 X86EMU_UNUSED(op1))
+{
+    u16 addr;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("XLAT\n");
+    TRACE_AND_STEP();
+	addr = (u16)(M.x86.R_BX + (u8)M.x86.R_AL);
+    M.x86.R_AL = fetch_data_byte(addr);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/* instuctions	D8 .. DF are in i87_ops.c */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe0
+****************************************************************************/
+void x86emuOp_loopne(u8 X86EMU_UNUSED(op1))
+{
+    s16 ip;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LOOPNE\t");
+    ip = (s8) fetch_byte_imm();
+    ip += (s16) M.x86.R_IP;
+    DECODE_PRINTF2("%04x\n", ip);
+    TRACE_AND_STEP();
+    M.x86.R_CX -= 1;
+    if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF))	    /* CX != 0 and !ZF */
+	M.x86.R_IP = ip;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe1
+****************************************************************************/
+void x86emuOp_loope(u8 X86EMU_UNUSED(op1))
+{
+    s16 ip;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LOOPE\t");
+    ip = (s8) fetch_byte_imm();
+    ip += (s16) M.x86.R_IP;
+    DECODE_PRINTF2("%04x\n", ip);
+    TRACE_AND_STEP();
+    M.x86.R_CX -= 1;
+    if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF))	    /* CX != 0 and ZF */
+	M.x86.R_IP = ip;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe2
+****************************************************************************/
+void x86emuOp_loop(u8 X86EMU_UNUSED(op1))
+{
+    s16 ip;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LOOP\t");
+    ip = (s8) fetch_byte_imm();
+    ip += (s16) M.x86.R_IP;
+    DECODE_PRINTF2("%04x\n", ip);
+    TRACE_AND_STEP();
+    M.x86.R_CX -= 1;
+    if (M.x86.R_CX != 0)
+	M.x86.R_IP = ip;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe3
+****************************************************************************/
+void x86emuOp_jcxz(u8 X86EMU_UNUSED(op1))
+{
+    u16 target;
+    s8	offset;
+
+    /* jump to byte offset if overflow flag is set */
+    START_OF_INSTR();
+    DECODE_PRINTF("JCXZ\t");
+    offset = (s8)fetch_byte_imm();
+    target = (u16)(M.x86.R_IP + offset);
+    DECODE_PRINTF2("%x\n", target);
+    TRACE_AND_STEP();
+    if (M.x86.R_CX == 0)
+	M.x86.R_IP = target;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe4
+****************************************************************************/
+void x86emuOp_in_byte_AL_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u8 port;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("IN\t");
+	port = (u8) fetch_byte_imm();
+    DECODE_PRINTF2("%x,AL\n", port);
+    TRACE_AND_STEP();
+    M.x86.R_AL = (*sys_inb)(port);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe5
+****************************************************************************/
+void x86emuOp_in_word_AX_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u8 port;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("IN\t");
+	port = (u8) fetch_byte_imm();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF2("EAX,%x\n", port);
+    } else {
+	DECODE_PRINTF2("AX,%x\n", port);
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EAX = (*sys_inl)(port);
+    } else {
+	M.x86.R_AX = (*sys_inw)(port);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe6
+****************************************************************************/
+void x86emuOp_out_byte_IMM_AL(u8 X86EMU_UNUSED(op1))
+{
+    u8 port;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("OUT\t");
+	port = (u8) fetch_byte_imm();
+    DECODE_PRINTF2("%x,AL\n", port);
+    TRACE_AND_STEP();
+    (*sys_outb)(port, M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe7
+****************************************************************************/
+void x86emuOp_out_word_IMM_AX(u8 X86EMU_UNUSED(op1))
+{
+    u8 port;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("OUT\t");
+	port = (u8) fetch_byte_imm();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF2("%x,EAX\n", port);
+    } else {
+	DECODE_PRINTF2("%x,AX\n", port);
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	(*sys_outl)(port, M.x86.R_EAX);
+    } else {
+	(*sys_outw)(port, M.x86.R_AX);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe8
+****************************************************************************/
+void x86emuOp_call_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+    s16 ip;
+
+    START_OF_INSTR();
+	DECODE_PRINTF("CALL\t");
+	ip = (s16) fetch_word_imm();
+	ip += (s16) M.x86.R_IP;	   /* CHECK SIGN */
+	DECODE_PRINTF2("%04x\n", ip);
+	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, "");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_IP);
+    M.x86.R_IP = ip;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xe9
+****************************************************************************/
+void x86emuOp_jump_near_IMM(u8 X86EMU_UNUSED(op1))
+{
+    int ip;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("JMP\t");
+    ip = (s16)fetch_word_imm();
+    ip += (s16)M.x86.R_IP;
+    DECODE_PRINTF2("%04x\n", ip);
+    TRACE_AND_STEP();
+    M.x86.R_IP = (u16)ip;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xea
+****************************************************************************/
+void x86emuOp_jump_far_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 cs, ip;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("JMP\tFAR ");
+    ip = fetch_word_imm();
+    cs = fetch_word_imm();
+    DECODE_PRINTF2("%04x:", cs);
+    DECODE_PRINTF2("%04x\n", ip);
+    TRACE_AND_STEP();
+    M.x86.R_IP = ip;
+    M.x86.R_CS = cs;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xeb
+****************************************************************************/
+void x86emuOp_jump_byte_IMM(u8 X86EMU_UNUSED(op1))
+{
+    u16 target;
+    s8 offset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("JMP\t");
+    offset = (s8)fetch_byte_imm();
+    target = (u16)(M.x86.R_IP + offset);
+    DECODE_PRINTF2("%x\n", target);
+    TRACE_AND_STEP();
+    M.x86.R_IP = target;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xec
+****************************************************************************/
+void x86emuOp_in_byte_AL_DX(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("IN\tAL,DX\n");
+    TRACE_AND_STEP();
+    M.x86.R_AL = (*sys_inb)(M.x86.R_DX);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xed
+****************************************************************************/
+void x86emuOp_in_word_AX_DX(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("IN\tEAX,DX\n");
+    } else {
+	DECODE_PRINTF("IN\tAX,DX\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	M.x86.R_EAX = (*sys_inl)(M.x86.R_DX);
+    } else {
+	M.x86.R_AX = (*sys_inw)(M.x86.R_DX);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xee
+****************************************************************************/
+void x86emuOp_out_byte_DX_AL(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("OUT\tDX,AL\n");
+    TRACE_AND_STEP();
+    (*sys_outb)(M.x86.R_DX, M.x86.R_AL);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xef
+****************************************************************************/
+void x86emuOp_out_word_DX_AX(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	DECODE_PRINTF("OUT\tDX,EAX\n");
+    } else {
+	DECODE_PRINTF("OUT\tDX,AX\n");
+    }
+    TRACE_AND_STEP();
+    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	(*sys_outl)(M.x86.R_DX, M.x86.R_EAX);
+    } else {
+	(*sys_outw)(M.x86.R_DX, M.x86.R_AX);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf0
+****************************************************************************/
+void x86emuOp_lock(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("LOCK:\n");
+    TRACE_AND_STEP();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/*opcode 0xf1 ILLEGAL OPERATION */
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf2
+****************************************************************************/
+void x86emuOp_repne(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("REPNE\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_PREFIX_REPNE;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf3
+****************************************************************************/
+void x86emuOp_repe(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("REPE\n");
+    TRACE_AND_STEP();
+    M.x86.mode |= SYSMODE_PREFIX_REPE;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf4
+****************************************************************************/
+void x86emuOp_halt(u8 X86EMU_UNUSED(op1))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("HALT\n");
+    TRACE_AND_STEP();
+    HALT_SYS();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf5
+****************************************************************************/
+void x86emuOp_cmc(u8 X86EMU_UNUSED(op1))
+{
+    /* complement the carry flag. */
+    START_OF_INSTR();
+    DECODE_PRINTF("CMC\n");
+    TRACE_AND_STEP();
+    TOGGLE_FLAG(F_CF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf6
+****************************************************************************/
+void x86emuOp_opcF6_byte_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    u8 *destreg;
+    uint destoffset;
+    u8 destval, srcval;
+
+    /* long, drawn out code follows.  Double switch for a total
+       of 32 cases.  */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    DECODE_PRINTF(opF6_names[rh]);
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	destval = fetch_data_byte(destoffset);
+
+	switch (rh) {
+	case 0:		/* test byte imm */
+	    DECODE_PRINTF(",");
+	    srcval = fetch_byte_imm();
+	    DECODE_PRINTF2("%02x\n", srcval);
+	    TRACE_AND_STEP();
+	    test_byte(destval, srcval);
+	    break;
+	case 1:
+	    DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+	    HALT_SYS();
+	    break;
+	case 2:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = not_byte(destval);
+	    store_data_byte(destoffset, destval);
+	    break;
+	case 3:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    destval = neg_byte(destval);
+	    store_data_byte(destoffset, destval);
+	    break;
+	case 4:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    mul_byte(destval);
+	    break;
+	case 5:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    imul_byte(destval);
+	    break;
+	case 6:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    div_byte(destval);
+	    break;
+	default:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    idiv_byte(destval);
+	    break;
+	}
+    } else {			 /* mod=11 */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	switch (rh) {
+	case 0:		/* test byte imm */
+	    DECODE_PRINTF(",");
+	    srcval = fetch_byte_imm();
+	    DECODE_PRINTF2("%02x\n", srcval);
+	    TRACE_AND_STEP();
+	    test_byte(*destreg, srcval);
+	    break;
+	case 1:
+	    DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+	    HALT_SYS();
+	    break;
+	case 2:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = not_byte(*destreg);
+	    break;
+	case 3:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = neg_byte(*destreg);
+	    break;
+	case 4:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    mul_byte(*destreg);	     /*!!!  */
+	    break;
+	case 5:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    imul_byte(*destreg);
+	    break;
+	case 6:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    div_byte(*destreg);
+	    break;
+	default:
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    idiv_byte(*destreg);
+	    break;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf7
+****************************************************************************/
+void x86emuOp_opcF7_word_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    DECODE_PRINTF(opF6_names[rh]);
+    if (mod < 3) {
+
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval, srcval;
+
+	    DECODE_PRINTF("DWORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    destval = fetch_data_long(destoffset);
+
+	    switch (rh) {
+	    case 0:
+		DECODE_PRINTF(",");
+		srcval = fetch_long_imm();
+		DECODE_PRINTF2("%x\n", srcval);
+		TRACE_AND_STEP();
+		test_long(destval, srcval);
+		break;
+	    case 1:
+		DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
+		HALT_SYS();
+		break;
+	    case 2:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		destval = not_long(destval);
+		store_data_long(destoffset, destval);
+		break;
+	    case 3:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		destval = neg_long(destval);
+		store_data_long(destoffset, destval);
+		break;
+	    case 4:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		mul_long(destval);
+		break;
+	    case 5:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		imul_long(destval);
+		break;
+	    case 6:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		div_long(destval);
+		break;
+	    case 7:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		idiv_long(destval);
+		break;
+	    }
+	} else {
+	    u16 destval, srcval;
+
+	    DECODE_PRINTF("WORD PTR ");
+	    destoffset = decode_rmXX_address(mod, rl);
+	    destval = fetch_data_word(destoffset);
+
+	    switch (rh) {
+	    case 0:	    /* test word imm */
+		DECODE_PRINTF(",");
+		srcval = fetch_word_imm();
+		DECODE_PRINTF2("%x\n", srcval);
+		TRACE_AND_STEP();
+		test_word(destval, srcval);
+		break;
+	    case 1:
+		DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F7\n");
+		HALT_SYS();
+		break;
+	    case 2:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		destval = not_word(destval);
+		store_data_word(destoffset, destval);
+		break;
+	    case 3:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		destval = neg_word(destval);
+		store_data_word(destoffset, destval);
+		break;
+	    case 4:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		mul_word(destval);
+		break;
+	    case 5:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		imul_word(destval);
+		break;
+	    case 6:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		div_word(destval);
+		break;
+	    case 7:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		idiv_word(destval);
+		break;
+	    }
+	}
+
+    } else {			 /* mod=11 */
+
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+
+	    switch (rh) {
+	    case 0:	    /* test word imm */
+		DECODE_PRINTF(",");
+		srcval = fetch_long_imm();
+		DECODE_PRINTF2("%x\n", srcval);
+		TRACE_AND_STEP();
+		test_long(*destreg, srcval);
+		break;
+	    case 1:
+		DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+		HALT_SYS();
+		break;
+	    case 2:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = not_long(*destreg);
+		break;
+	    case 3:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = neg_long(*destreg);
+		break;
+	    case 4:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		mul_long(*destreg);	 /*!!!	*/
+		break;
+	    case 5:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		imul_long(*destreg);
+		break;
+	    case 6:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		div_long(*destreg);
+		break;
+	    case 7:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		idiv_long(*destreg);
+		break;
+	    }
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+
+	    switch (rh) {
+	    case 0:	    /* test word imm */
+		DECODE_PRINTF(",");
+		srcval = fetch_word_imm();
+		DECODE_PRINTF2("%x\n", srcval);
+		TRACE_AND_STEP();
+		test_word(*destreg, srcval);
+		break;
+	    case 1:
+		DECODE_PRINTF("ILLEGAL OP MOD=00 RH=01 OP=F6\n");
+		HALT_SYS();
+		break;
+	    case 2:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = not_word(*destreg);
+		break;
+	    case 3:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = neg_word(*destreg);
+		break;
+	    case 4:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		mul_word(*destreg);	 /*!!!	*/
+		break;
+	    case 5:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		imul_word(*destreg);
+		break;
+	    case 6:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		div_word(*destreg);
+		break;
+	    case 7:
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		idiv_word(*destreg);
+		break;
+	    }
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf8
+****************************************************************************/
+void x86emuOp_clc(u8 X86EMU_UNUSED(op1))
+{
+    /* clear the carry flag. */
+    START_OF_INSTR();
+    DECODE_PRINTF("CLC\n");
+    TRACE_AND_STEP();
+    CLEAR_FLAG(F_CF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xf9
+****************************************************************************/
+void x86emuOp_stc(u8 X86EMU_UNUSED(op1))
+{
+    /* set the carry flag. */
+    START_OF_INSTR();
+    DECODE_PRINTF("STC\n");
+    TRACE_AND_STEP();
+    SET_FLAG(F_CF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfa
+****************************************************************************/
+void x86emuOp_cli(u8 X86EMU_UNUSED(op1))
+{
+    /* clear interrupts. */
+    START_OF_INSTR();
+    DECODE_PRINTF("CLI\n");
+    TRACE_AND_STEP();
+    CLEAR_FLAG(F_IF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfb
+****************************************************************************/
+void x86emuOp_sti(u8 X86EMU_UNUSED(op1))
+{
+    /* enable  interrupts. */
+    START_OF_INSTR();
+    DECODE_PRINTF("STI\n");
+    TRACE_AND_STEP();
+    SET_FLAG(F_IF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfc
+****************************************************************************/
+void x86emuOp_cld(u8 X86EMU_UNUSED(op1))
+{
+    /* clear interrupts. */
+    START_OF_INSTR();
+    DECODE_PRINTF("CLD\n");
+    TRACE_AND_STEP();
+    CLEAR_FLAG(F_DF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfd
+****************************************************************************/
+void x86emuOp_std(u8 X86EMU_UNUSED(op1))
+{
+    /* clear interrupts. */
+    START_OF_INSTR();
+    DECODE_PRINTF("STD\n");
+    TRACE_AND_STEP();
+    SET_FLAG(F_DF);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xfe
+****************************************************************************/
+void x86emuOp_opcFE_byte_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rh, rl;
+    u8 destval;
+    uint destoffset;
+    u8 *destreg;
+
+    /* Yet another special case instruction. */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    DECODE_PRINTF("INC\t");
+	    break;
+	case 1:
+	    DECODE_PRINTF("DEC\t");
+	    break;
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+	case 7:
+	    DECODE_PRINTF2("ILLEGAL OP MAJOR OP 0xFE MINOR OP %x \n", mod);
+	    HALT_SYS();
+	    break;
+	}
+    }
+#endif
+    if (mod < 3) {
+	DECODE_PRINTF("BYTE PTR ");
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	destval = fetch_data_byte(destoffset);
+	TRACE_AND_STEP();
+	if (rh == 0)
+	  destval = inc_byte(destval);
+	else
+	  destval = dec_byte(destval);
+	store_data_byte(destoffset, destval);
+    } else {
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	if (rh == 0)
+	  *destreg = inc_byte(*destreg);
+	else
+	  *destreg = dec_byte(*destreg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0xff
+****************************************************************************/
+void x86emuOp_opcFF_word_RM(u8 X86EMU_UNUSED(op1))
+{
+    int mod, rh, rl;
+    uint destoffset = 0;
+	u16 *destreg;
+	u16 destval,destval2;
+
+    /* Yet another special case instruction. */
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+#ifdef DEBUG
+    if (DEBUG_DECODE()) {
+	/* XXX DECODE_PRINTF may be changed to something more
+	   general, so that it is important to leave the strings
+	   in the same format, even though the result is that the
+	   above test is done twice. */
+
+	switch (rh) {
+	case 0:
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		DECODE_PRINTF("INC\tDWORD PTR ");
+	    } else {
+		DECODE_PRINTF("INC\tWORD PTR ");
+	    }
+	    break;
+	case 1:
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		DECODE_PRINTF("DEC\tDWORD PTR ");
+	    } else {
+		DECODE_PRINTF("DEC\tWORD PTR ");
+	    }
+	    break;
+	case 2:
+	    DECODE_PRINTF("CALL\t ");
+	    break;
+	case 3:
+	    DECODE_PRINTF("CALL\tFAR ");
+	    break;
+	case 4:
+	    DECODE_PRINTF("JMP\t");
+	    break;
+	case 5:
+	    DECODE_PRINTF("JMP\tFAR ");
+	    break;
+	case 6:
+	    DECODE_PRINTF("PUSH\t");
+	    break;
+	case 7:
+	    DECODE_PRINTF("ILLEGAL DECODING OF OPCODE FF\t");
+	    HALT_SYS();
+	    break;
+	}
+    }
+#endif
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	switch (rh) {
+	case 0:		/* inc word ptr ... */
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 destval;
+
+		destval = fetch_data_long(destoffset);
+		TRACE_AND_STEP();
+		destval = inc_long(destval);
+		store_data_long(destoffset, destval);
+	    } else {
+		u16 destval;
+
+		destval = fetch_data_word(destoffset);
+		TRACE_AND_STEP();
+		destval = inc_word(destval);
+		store_data_word(destoffset, destval);
+	    }
+	    break;
+	case 1:		/* dec word ptr ... */
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 destval;
+
+		destval = fetch_data_long(destoffset);
+		TRACE_AND_STEP();
+		destval = dec_long(destval);
+		store_data_long(destoffset, destval);
+	    } else {
+		u16 destval;
+
+		destval = fetch_data_word(destoffset);
+		TRACE_AND_STEP();
+		destval = dec_word(destval);
+		store_data_word(destoffset, destval);
+	    }
+	    break;
+	case 2:		/* call word ptr ... */
+	    destval = fetch_data_word(destoffset);
+	    TRACE_AND_STEP();
+	    push_word(M.x86.R_IP);
+	    M.x86.R_IP = destval;
+	    break;
+	case 3:		/* call far ptr ... */
+	    destval = fetch_data_word(destoffset);
+	    destval2 = fetch_data_word(destoffset + 2);
+	    TRACE_AND_STEP();
+	    push_word(M.x86.R_CS);
+	    M.x86.R_CS = destval2;
+	    push_word(M.x86.R_IP);
+	    M.x86.R_IP = destval;
+	    break;
+	case 4:		/* jmp word ptr ... */
+	    destval = fetch_data_word(destoffset);
+	    TRACE_AND_STEP();
+	    M.x86.R_IP = destval;
+	    break;
+	case 5:		/* jmp far ptr ... */
+	    destval = fetch_data_word(destoffset);
+	    destval2 = fetch_data_word(destoffset + 2);
+	    TRACE_AND_STEP();
+	    M.x86.R_IP = destval;
+	    M.x86.R_CS = destval2;
+	    break;
+	case 6:		/*  push word ptr ... */
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 destval;
+
+		destval = fetch_data_long(destoffset);
+		TRACE_AND_STEP();
+		push_long(destval);
+	    } else {
+		u16 destval;
+
+		destval = fetch_data_word(destoffset);
+		TRACE_AND_STEP();
+		push_word(destval);
+	    }
+	    break;
+	}
+    } else {
+	switch (rh) {
+	case 0:
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 *destreg;
+
+		destreg = DECODE_RM_LONG_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = inc_long(*destreg);
+	    } else {
+		u16 *destreg;
+
+		destreg = DECODE_RM_WORD_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = inc_word(*destreg);
+	    }
+	    break;
+	case 1:
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 *destreg;
+
+		destreg = DECODE_RM_LONG_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = dec_long(*destreg);
+	    } else {
+		u16 *destreg;
+
+		destreg = DECODE_RM_WORD_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		*destreg = dec_word(*destreg);
+	    }
+	    break;
+	case 2:		/* call word ptr ... */
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    push_word(M.x86.R_IP);
+	    M.x86.R_IP = *destreg;
+	    break;
+	case 3:		/* jmp far ptr ... */
+	    DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+	    TRACE_AND_STEP();
+	    HALT_SYS();
+	    break;
+
+	case 4:		/* jmp	... */
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    M.x86.R_IP = (u16) (*destreg);
+	    break;
+	case 5:		/* jmp far ptr ... */
+	    DECODE_PRINTF("OPERATION UNDEFINED 0XFF \n");
+	    TRACE_AND_STEP();
+	    HALT_SYS();
+	    break;
+	case 6:
+	    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+		u32 *destreg;
+
+		destreg = DECODE_RM_LONG_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		push_long(*destreg);
+	    } else {
+		u16 *destreg;
+
+		destreg = DECODE_RM_WORD_REGISTER(rl);
+		DECODE_PRINTF("\n");
+		TRACE_AND_STEP();
+		push_word(*destreg);
+	    }
+	    break;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/***************************************************************************
+ * Single byte operation code table:
+ **************************************************************************/
+void (*x86emu_optab[256])(u8) __attribute__ ((section(".got2"))) =
+{
+/*  0x00 */ x86emuOp_genop_byte_RM_R,
+/*  0x01 */ x86emuOp_genop_word_RM_R,
+/*  0x02 */ x86emuOp_genop_byte_R_RM,
+/*  0x03 */ x86emuOp_genop_word_R_RM,
+/*  0x04 */ x86emuOp_genop_byte_AL_IMM,
+/*  0x05 */ x86emuOp_genop_word_AX_IMM,
+/*  0x06 */ x86emuOp_push_ES,
+/*  0x07 */ x86emuOp_pop_ES,
+
+/*  0x08 */ x86emuOp_genop_byte_RM_R,
+/*  0x09 */ x86emuOp_genop_word_RM_R,
+/*  0x0a */ x86emuOp_genop_byte_R_RM,
+/*  0x0b */ x86emuOp_genop_word_R_RM,
+/*  0x0c */ x86emuOp_genop_byte_AL_IMM,
+/*  0x0d */ x86emuOp_genop_word_AX_IMM,
+/*  0x0e */ x86emuOp_push_CS,
+/*  0x0f */ x86emuOp_two_byte,
+
+/*  0x10 */ x86emuOp_genop_byte_RM_R,
+/*  0x11 */ x86emuOp_genop_word_RM_R,
+/*  0x12 */ x86emuOp_genop_byte_R_RM,
+/*  0x13 */ x86emuOp_genop_word_R_RM,
+/*  0x14 */ x86emuOp_genop_byte_AL_IMM,
+/*  0x15 */ x86emuOp_genop_word_AX_IMM,
+/*  0x16 */ x86emuOp_push_SS,
+/*  0x17 */ x86emuOp_pop_SS,
+
+/*  0x18 */ x86emuOp_genop_byte_RM_R,
+/*  0x19 */ x86emuOp_genop_word_RM_R,
+/*  0x1a */ x86emuOp_genop_byte_R_RM,
+/*  0x1b */ x86emuOp_genop_word_R_RM,
+/*  0x1c */ x86emuOp_genop_byte_AL_IMM,
+/*  0x1d */ x86emuOp_genop_word_AX_IMM,
+/*  0x1e */ x86emuOp_push_DS,
+/*  0x1f */ x86emuOp_pop_DS,
+
+/*  0x20 */ x86emuOp_genop_byte_RM_R,
+/*  0x21 */ x86emuOp_genop_word_RM_R,
+/*  0x22 */ x86emuOp_genop_byte_R_RM,
+/*  0x23 */ x86emuOp_genop_word_R_RM,
+/*  0x24 */ x86emuOp_genop_byte_AL_IMM,
+/*  0x25 */ x86emuOp_genop_word_AX_IMM,
+/*  0x26 */ x86emuOp_segovr_ES,
+/*  0x27 */ x86emuOp_daa,
+
+/*  0x28 */ x86emuOp_genop_byte_RM_R,
+/*  0x29 */ x86emuOp_genop_word_RM_R,
+/*  0x2a */ x86emuOp_genop_byte_R_RM,
+/*  0x2b */ x86emuOp_genop_word_R_RM,
+/*  0x2c */ x86emuOp_genop_byte_AL_IMM,
+/*  0x2d */ x86emuOp_genop_word_AX_IMM,
+/*  0x2e */ x86emuOp_segovr_CS,
+/*  0x2f */ x86emuOp_das,
+
+/*  0x30 */ x86emuOp_genop_byte_RM_R,
+/*  0x31 */ x86emuOp_genop_word_RM_R,
+/*  0x32 */ x86emuOp_genop_byte_R_RM,
+/*  0x33 */ x86emuOp_genop_word_R_RM,
+/*  0x34 */ x86emuOp_genop_byte_AL_IMM,
+/*  0x35 */ x86emuOp_genop_word_AX_IMM,
+/*  0x36 */ x86emuOp_segovr_SS,
+/*  0x37 */ x86emuOp_aaa,
+
+/*  0x38 */ x86emuOp_genop_byte_RM_R,
+/*  0x39 */ x86emuOp_genop_word_RM_R,
+/*  0x3a */ x86emuOp_genop_byte_R_RM,
+/*  0x3b */ x86emuOp_genop_word_R_RM,
+/*  0x3c */ x86emuOp_genop_byte_AL_IMM,
+/*  0x3d */ x86emuOp_genop_word_AX_IMM,
+/*  0x3e */ x86emuOp_segovr_DS,
+/*  0x3f */ x86emuOp_aas,
+
+/*  0x40 */ x86emuOp_inc_register,
+/*  0x41 */ x86emuOp_inc_register,
+/*  0x42 */ x86emuOp_inc_register,
+/*  0x43 */ x86emuOp_inc_register,
+/*  0x44 */ x86emuOp_inc_register,
+/*  0x45 */ x86emuOp_inc_register,
+/*  0x46 */ x86emuOp_inc_register,
+/*  0x47 */ x86emuOp_inc_register,
+
+/*  0x48 */ x86emuOp_dec_register,
+/*  0x49 */ x86emuOp_dec_register,
+/*  0x4a */ x86emuOp_dec_register,
+/*  0x4b */ x86emuOp_dec_register,
+/*  0x4c */ x86emuOp_dec_register,
+/*  0x4d */ x86emuOp_dec_register,
+/*  0x4e */ x86emuOp_dec_register,
+/*  0x4f */ x86emuOp_dec_register,
+
+/*  0x50 */ x86emuOp_push_register,
+/*  0x51 */ x86emuOp_push_register,
+/*  0x52 */ x86emuOp_push_register,
+/*  0x53 */ x86emuOp_push_register,
+/*  0x54 */ x86emuOp_push_register,
+/*  0x55 */ x86emuOp_push_register,
+/*  0x56 */ x86emuOp_push_register,
+/*  0x57 */ x86emuOp_push_register,
+
+/*  0x58 */ x86emuOp_pop_register,
+/*  0x59 */ x86emuOp_pop_register,
+/*  0x5a */ x86emuOp_pop_register,
+/*  0x5b */ x86emuOp_pop_register,
+/*  0x5c */ x86emuOp_pop_register,
+/*  0x5d */ x86emuOp_pop_register,
+/*  0x5e */ x86emuOp_pop_register,
+/*  0x5f */ x86emuOp_pop_register,
+
+/*  0x60 */ x86emuOp_push_all,
+/*  0x61 */ x86emuOp_pop_all,
+/*  0x62 */ x86emuOp_illegal_op,   /* bound */
+/*  0x63 */ x86emuOp_illegal_op,   /* arpl */
+/*  0x64 */ x86emuOp_segovr_FS,
+/*  0x65 */ x86emuOp_segovr_GS,
+/*  0x66 */ x86emuOp_prefix_data,
+/*  0x67 */ x86emuOp_prefix_addr,
+
+/*  0x68 */ x86emuOp_push_word_IMM,
+/*  0x69 */ x86emuOp_imul_word_IMM,
+/*  0x6a */ x86emuOp_push_byte_IMM,
+/*  0x6b */ x86emuOp_imul_byte_IMM,
+/*  0x6c */ x86emuOp_ins_byte,
+/*  0x6d */ x86emuOp_ins_word,
+/*  0x6e */ x86emuOp_outs_byte,
+/*  0x6f */ x86emuOp_outs_word,
+
+/*  0x70 */ x86emuOp_jump_near_cond,
+/*  0x71 */ x86emuOp_jump_near_cond,
+/*  0x72 */ x86emuOp_jump_near_cond,
+/*  0x73 */ x86emuOp_jump_near_cond,
+/*  0x74 */ x86emuOp_jump_near_cond,
+/*  0x75 */ x86emuOp_jump_near_cond,
+/*  0x76 */ x86emuOp_jump_near_cond,
+/*  0x77 */ x86emuOp_jump_near_cond,
+
+/*  0x78 */ x86emuOp_jump_near_cond,
+/*  0x79 */ x86emuOp_jump_near_cond,
+/*  0x7a */ x86emuOp_jump_near_cond,
+/*  0x7b */ x86emuOp_jump_near_cond,
+/*  0x7c */ x86emuOp_jump_near_cond,
+/*  0x7d */ x86emuOp_jump_near_cond,
+/*  0x7e */ x86emuOp_jump_near_cond,
+/*  0x7f */ x86emuOp_jump_near_cond,
+
+/*  0x80 */ x86emuOp_opc80_byte_RM_IMM,
+/*  0x81 */ x86emuOp_opc81_word_RM_IMM,
+/*  0x82 */ x86emuOp_opc82_byte_RM_IMM,
+/*  0x83 */ x86emuOp_opc83_word_RM_IMM,
+/*  0x84 */ x86emuOp_test_byte_RM_R,
+/*  0x85 */ x86emuOp_test_word_RM_R,
+/*  0x86 */ x86emuOp_xchg_byte_RM_R,
+/*  0x87 */ x86emuOp_xchg_word_RM_R,
+
+/*  0x88 */ x86emuOp_mov_byte_RM_R,
+/*  0x89 */ x86emuOp_mov_word_RM_R,
+/*  0x8a */ x86emuOp_mov_byte_R_RM,
+/*  0x8b */ x86emuOp_mov_word_R_RM,
+/*  0x8c */ x86emuOp_mov_word_RM_SR,
+/*  0x8d */ x86emuOp_lea_word_R_M,
+/*  0x8e */ x86emuOp_mov_word_SR_RM,
+/*  0x8f */ x86emuOp_pop_RM,
+
+/*  0x90 */ x86emuOp_nop,
+/*  0x91 */ x86emuOp_xchg_word_AX_register,
+/*  0x92 */ x86emuOp_xchg_word_AX_register,
+/*  0x93 */ x86emuOp_xchg_word_AX_register,
+/*  0x94 */ x86emuOp_xchg_word_AX_register,
+/*  0x95 */ x86emuOp_xchg_word_AX_register,
+/*  0x96 */ x86emuOp_xchg_word_AX_register,
+/*  0x97 */ x86emuOp_xchg_word_AX_register,
+
+/*  0x98 */ x86emuOp_cbw,
+/*  0x99 */ x86emuOp_cwd,
+/*  0x9a */ x86emuOp_call_far_IMM,
+/*  0x9b */ x86emuOp_wait,
+/*  0x9c */ x86emuOp_pushf_word,
+/*  0x9d */ x86emuOp_popf_word,
+/*  0x9e */ x86emuOp_sahf,
+/*  0x9f */ x86emuOp_lahf,
+
+/*  0xa0 */ x86emuOp_mov_AL_M_IMM,
+/*  0xa1 */ x86emuOp_mov_AX_M_IMM,
+/*  0xa2 */ x86emuOp_mov_M_AL_IMM,
+/*  0xa3 */ x86emuOp_mov_M_AX_IMM,
+/*  0xa4 */ x86emuOp_movs_byte,
+/*  0xa5 */ x86emuOp_movs_word,
+/*  0xa6 */ x86emuOp_cmps_byte,
+/*  0xa7 */ x86emuOp_cmps_word,
+/*  0xa8 */ x86emuOp_test_AL_IMM,
+/*  0xa9 */ x86emuOp_test_AX_IMM,
+/*  0xaa */ x86emuOp_stos_byte,
+/*  0xab */ x86emuOp_stos_word,
+/*  0xac */ x86emuOp_lods_byte,
+/*  0xad */ x86emuOp_lods_word,
+/*  0xac */ x86emuOp_scas_byte,
+/*  0xad */ x86emuOp_scas_word,
+
+/*  0xb0 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb1 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb2 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb3 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb4 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb5 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb6 */ x86emuOp_mov_byte_register_IMM,
+/*  0xb7 */ x86emuOp_mov_byte_register_IMM,
+
+/*  0xb8 */ x86emuOp_mov_word_register_IMM,
+/*  0xb9 */ x86emuOp_mov_word_register_IMM,
+/*  0xba */ x86emuOp_mov_word_register_IMM,
+/*  0xbb */ x86emuOp_mov_word_register_IMM,
+/*  0xbc */ x86emuOp_mov_word_register_IMM,
+/*  0xbd */ x86emuOp_mov_word_register_IMM,
+/*  0xbe */ x86emuOp_mov_word_register_IMM,
+/*  0xbf */ x86emuOp_mov_word_register_IMM,
+
+/*  0xc0 */ x86emuOp_opcC0_byte_RM_MEM,
+/*  0xc1 */ x86emuOp_opcC1_word_RM_MEM,
+/*  0xc2 */ x86emuOp_ret_near_IMM,
+/*  0xc3 */ x86emuOp_ret_near,
+/*  0xc4 */ x86emuOp_les_R_IMM,
+/*  0xc5 */ x86emuOp_lds_R_IMM,
+/*  0xc6 */ x86emuOp_mov_byte_RM_IMM,
+/*  0xc7 */ x86emuOp_mov_word_RM_IMM,
+/*  0xc8 */ x86emuOp_enter,
+/*  0xc9 */ x86emuOp_leave,
+/*  0xca */ x86emuOp_ret_far_IMM,
+/*  0xcb */ x86emuOp_ret_far,
+/*  0xcc */ x86emuOp_int3,
+/*  0xcd */ x86emuOp_int_IMM,
+/*  0xce */ x86emuOp_into,
+/*  0xcf */ x86emuOp_iret,
+
+/*  0xd0 */ x86emuOp_opcD0_byte_RM_1,
+/*  0xd1 */ x86emuOp_opcD1_word_RM_1,
+/*  0xd2 */ x86emuOp_opcD2_byte_RM_CL,
+/*  0xd3 */ x86emuOp_opcD3_word_RM_CL,
+/*  0xd4 */ x86emuOp_aam,
+/*  0xd5 */ x86emuOp_aad,
+/*  0xd6 */ x86emuOp_illegal_op,   /* Undocumented SETALC instruction */
+/*  0xd7 */ x86emuOp_xlat,
+/*  0xd8 */ NULL, /*x86emuOp_esc_coprocess_d8,*/
+/*  0xd9 */ NULL, /*x86emuOp_esc_coprocess_d9,*/
+/*  0xda */ NULL, /*x86emuOp_esc_coprocess_da,*/
+/*  0xdb */ NULL, /*x86emuOp_esc_coprocess_db,*/
+/*  0xdc */ NULL, /*x86emuOp_esc_coprocess_dc,*/
+/*  0xdd */ NULL, /*x86emuOp_esc_coprocess_dd,*/
+/*  0xde */ NULL, /*x86emuOp_esc_coprocess_de,*/
+/*  0xdf */ NULL, /*x86emuOp_esc_coprocess_df,*/
+
+/*  0xe0 */ x86emuOp_loopne,
+/*  0xe1 */ x86emuOp_loope,
+/*  0xe2 */ x86emuOp_loop,
+/*  0xe3 */ x86emuOp_jcxz,
+/*  0xe4 */ x86emuOp_in_byte_AL_IMM,
+/*  0xe5 */ x86emuOp_in_word_AX_IMM,
+/*  0xe6 */ x86emuOp_out_byte_IMM_AL,
+/*  0xe7 */ x86emuOp_out_word_IMM_AX,
+
+/*  0xe8 */ x86emuOp_call_near_IMM,
+/*  0xe9 */ x86emuOp_jump_near_IMM,
+/*  0xea */ x86emuOp_jump_far_IMM,
+/*  0xeb */ x86emuOp_jump_byte_IMM,
+/*  0xec */ x86emuOp_in_byte_AL_DX,
+/*  0xed */ x86emuOp_in_word_AX_DX,
+/*  0xee */ x86emuOp_out_byte_DX_AL,
+/*  0xef */ x86emuOp_out_word_DX_AX,
+
+/*  0xf0 */ x86emuOp_lock,
+/*  0xf1 */ x86emuOp_illegal_op,
+/*  0xf2 */ x86emuOp_repne,
+/*  0xf3 */ x86emuOp_repe,
+/*  0xf4 */ x86emuOp_halt,
+/*  0xf5 */ x86emuOp_cmc,
+/*  0xf6 */ x86emuOp_opcF6_byte_RM,
+/*  0xf7 */ x86emuOp_opcF7_word_RM,
+
+/*  0xf8 */ x86emuOp_clc,
+/*  0xf9 */ x86emuOp_stc,
+/*  0xfa */ x86emuOp_cli,
+/*  0xfb */ x86emuOp_sti,
+/*  0xfc */ x86emuOp_cld,
+/*  0xfd */ x86emuOp_std,
+/*  0xfe */ x86emuOp_opcFE_byte_RM,
+/*  0xff */ x86emuOp_opcFF_word_RM,
+};
+
+#endif
diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c
new file mode 100644
index 0000000..81c0d49
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/ops2.c
@@ -0,0 +1,1774 @@
+/****************************************************************************
+*
+*			Realmode X86 Emulator Library
+*
+*  Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+*  Jason Jin <Jason.jin@freescale.com>
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*		     Copyright (C) David Mosberger-Tang
+*		       Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	This file includes subroutines to implement the decoding
+*		and emulation of all the x86 extended two-byte processor
+*		instructions.
+*
+*		Jason port this file to u-boot. Put the function pointer into
+*		got2 sector.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+#if defined(CONFIG_BIOSEMU)
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+op1 - Instruction op code
+
+REMARKS:
+Handles illegal opcodes.
+****************************************************************************/
+void x86emuOp2_illegal_op(
+    u8 op2)
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+    TRACE_REGS();
+    printk("%04x:%04x: %02X ILLEGAL EXTENDED X86 OPCODE!\n",
+	M.x86.R_CS, M.x86.R_IP-2,op2);
+    HALT_SYS();
+    END_OF_INSTR();
+}
+
+#define xorl(a,b)   ((a) && !(b)) || (!(a) && (b))
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0x80-0x8F
+****************************************************************************/
+int x86emu_check_jump_condition(u8 op)
+{
+    switch (op) {
+      case 0x0:
+	DECODE_PRINTF("JO\t");
+	return ACCESS_FLAG(F_OF);
+      case 0x1:
+	DECODE_PRINTF("JNO\t");
+	return !ACCESS_FLAG(F_OF);
+	break;
+      case 0x2:
+	DECODE_PRINTF("JB\t");
+	return ACCESS_FLAG(F_CF);
+	break;
+      case 0x3:
+	DECODE_PRINTF("JNB\t");
+	return !ACCESS_FLAG(F_CF);
+	break;
+      case 0x4:
+	DECODE_PRINTF("JZ\t");
+	return ACCESS_FLAG(F_ZF);
+	break;
+      case 0x5:
+	DECODE_PRINTF("JNZ\t");
+	return !ACCESS_FLAG(F_ZF);
+	break;
+      case 0x6:
+	DECODE_PRINTF("JBE\t");
+	return ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF);
+	break;
+      case 0x7:
+	DECODE_PRINTF("JNBE\t");
+	return !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+	break;
+      case 0x8:
+	DECODE_PRINTF("JS\t");
+	return ACCESS_FLAG(F_SF);
+	break;
+      case 0x9:
+	DECODE_PRINTF("JNS\t");
+	return !ACCESS_FLAG(F_SF);
+	break;
+      case 0xa:
+	DECODE_PRINTF("JP\t");
+	return ACCESS_FLAG(F_PF);
+	break;
+      case 0xb:
+	DECODE_PRINTF("JNP\t");
+	return !ACCESS_FLAG(F_PF);
+	break;
+      case 0xc:
+	DECODE_PRINTF("JL\t");
+	return xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+	break;
+      case 0xd:
+	DECODE_PRINTF("JNL\t");
+	return !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+	break;
+      case 0xe:
+	DECODE_PRINTF("JLE\t");
+	return (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		ACCESS_FLAG(F_ZF));
+	break;
+      default:
+	DECODE_PRINTF("JNLE\t");
+	return !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		 ACCESS_FLAG(F_ZF));
+    }
+}
+
+void x86emuOp2_long_jump(u8 op2)
+{
+    s32 target;
+    int cond;
+
+    /* conditional jump to word offset. */
+    START_OF_INSTR();
+    cond = x86emu_check_jump_condition(op2 & 0xF);
+    target = (s16) fetch_word_imm();
+    target += (s16) M.x86.R_IP;
+    DECODE_PRINTF2("%04x\n", target);
+    TRACE_AND_STEP();
+    if (cond)
+	M.x86.R_IP = (u16)target;
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0x90-0x9F
+****************************************************************************/
+void x86emuOp2_set_byte(u8 op2)
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8	*destreg;
+    char *name = 0;
+    int cond = 0;
+
+    START_OF_INSTR();
+    switch (op2) {
+      case 0x90:
+	name = "SETO\t";
+	cond =	ACCESS_FLAG(F_OF);
+	break;
+      case 0x91:
+	name = "SETNO\t";
+	cond = !ACCESS_FLAG(F_OF);
+	break;
+      case 0x92:
+	name = "SETB\t";
+	cond = ACCESS_FLAG(F_CF);
+	break;
+      case 0x93:
+	name = "SETNB\t";
+	cond = !ACCESS_FLAG(F_CF);
+	break;
+      case 0x94:
+	name = "SETZ\t";
+	cond = ACCESS_FLAG(F_ZF);
+	break;
+      case 0x95:
+	name = "SETNZ\t";
+	cond = !ACCESS_FLAG(F_ZF);
+	break;
+      case 0x96:
+	name = "SETBE\t";
+	cond = ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF);
+	break;
+      case 0x97:
+	name = "SETNBE\t";
+	cond = !(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF));
+	break;
+      case 0x98:
+	name = "SETS\t";
+	cond = ACCESS_FLAG(F_SF);
+	break;
+      case 0x99:
+	name = "SETNS\t";
+	cond = !ACCESS_FLAG(F_SF);
+	break;
+      case 0x9a:
+	name = "SETP\t";
+	cond = ACCESS_FLAG(F_PF);
+	break;
+      case 0x9b:
+	name = "SETNP\t";
+	cond = !ACCESS_FLAG(F_PF);
+	break;
+      case 0x9c:
+	name = "SETL\t";
+	cond = xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+	break;
+      case 0x9d:
+	name = "SETNL\t";
+	cond = !xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF));
+	break;
+      case 0x9e:
+	name = "SETLE\t";
+	cond = (xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		ACCESS_FLAG(F_ZF));
+	break;
+      case 0x9f:
+	name = "SETNLE\t";
+	cond = !(xorl(ACCESS_FLAG(F_SF), ACCESS_FLAG(F_OF)) ||
+		 ACCESS_FLAG(F_ZF));
+	break;
+    }
+    DECODE_PRINTF(name);
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	TRACE_AND_STEP();
+	store_data_byte(destoffset, cond ? 0x01 : 0x00);
+    } else {			 /* register to register */
+	destreg = DECODE_RM_BYTE_REGISTER(rl);
+	TRACE_AND_STEP();
+	*destreg = cond ? 0x01 : 0x00;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa0
+****************************************************************************/
+void x86emuOp2_push_FS(u8 X86EMU_UNUSED(op2))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tFS\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_FS);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa1
+****************************************************************************/
+void x86emuOp2_pop_FS(u8 X86EMU_UNUSED(op2))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\tFS\n");
+    TRACE_AND_STEP();
+    M.x86.R_FS = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa3
+****************************************************************************/
+void x86emuOp2_bt_R(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    int bit,disp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BT\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval;
+	    u32 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    disp = (s16)*shiftreg >> 5;
+	    srcval = fetch_data_long(srcoffset+disp);
+	    CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+	} else {
+	    u16 srcval;
+	    u16 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    disp = (s16)*shiftreg >> 4;
+	    srcval = fetch_data_word(srcoffset+disp);
+	    CONDITIONAL_SET_FLAG(srcval & (0x1 << bit),F_CF);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg,*shiftreg;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF);
+	} else {
+	    u16 *srcreg,*shiftreg;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    CONDITIONAL_SET_FLAG(*srcreg & (0x1 << bit),F_CF);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa4
+****************************************************************************/
+void x86emuOp2_shld_IMM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8 shift;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("SHLD\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    destval = fetch_data_long(destoffset);
+	    destval = shld_long(destval,*shiftreg,shift);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+	    u16 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    destval = fetch_data_word(destoffset);
+	    destval = shld_word(destval,*shiftreg,shift);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    *destreg = shld_long(*destreg,*shiftreg,shift);
+	} else {
+	    u16 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    *destreg = shld_word(*destreg,*shiftreg,shift);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa5
+****************************************************************************/
+void x86emuOp2_shld_CL(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("SHLD\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    destval = fetch_data_long(destoffset);
+	    destval = shld_long(destval,*shiftreg,M.x86.R_CL);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+	    u16 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    destval = fetch_data_word(destoffset);
+	    destval = shld_word(destval,*shiftreg,M.x86.R_CL);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = shld_long(*destreg,*shiftreg,M.x86.R_CL);
+	} else {
+	    u16 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = shld_word(*destreg,*shiftreg,M.x86.R_CL);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa8
+****************************************************************************/
+void x86emuOp2_push_GS(u8 X86EMU_UNUSED(op2))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("PUSH\tGS\n");
+    TRACE_AND_STEP();
+    push_word(M.x86.R_GS);
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xa9
+****************************************************************************/
+void x86emuOp2_pop_GS(u8 X86EMU_UNUSED(op2))
+{
+    START_OF_INSTR();
+    DECODE_PRINTF("POP\tGS\n");
+    TRACE_AND_STEP();
+    M.x86.R_GS = pop_word();
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xaa
+****************************************************************************/
+void x86emuOp2_bts_R(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    int bit,disp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BTS\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval,mask;
+	    u32 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    disp = (s16)*shiftreg >> 5;
+	    srcval = fetch_data_long(srcoffset+disp);
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_long(srcoffset+disp, srcval | mask);
+	} else {
+	    u16 srcval,mask;
+	    u16 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    disp = (s16)*shiftreg >> 4;
+	    srcval = fetch_data_word(srcoffset+disp);
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_word(srcoffset+disp, srcval | mask);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg,*shiftreg;
+	    u32 mask;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg |= mask;
+	} else {
+	    u16 *srcreg,*shiftreg;
+	    u16 mask;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg |= mask;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xac
+****************************************************************************/
+void x86emuOp2_shrd_IMM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint destoffset;
+    u8 shift;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("SHLD\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    destval = fetch_data_long(destoffset);
+	    destval = shrd_long(destval,*shiftreg,shift);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+	    u16 *shiftreg;
+
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    destval = fetch_data_word(destoffset);
+	    destval = shrd_word(destval,*shiftreg,shift);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    *destreg = shrd_long(*destreg,*shiftreg,shift);
+	} else {
+	    u16 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2("%d\n", shift);
+	    TRACE_AND_STEP();
+	    *destreg = shrd_word(*destreg,*shiftreg,shift);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xad
+****************************************************************************/
+void x86emuOp2_shrd_CL(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint destoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("SHLD\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 destval;
+	    u32 *shiftreg;
+
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    destval = fetch_data_long(destoffset);
+	    destval = shrd_long(destval,*shiftreg,M.x86.R_CL);
+	    store_data_long(destoffset, destval);
+	} else {
+	    u16 destval;
+	    u16 *shiftreg;
+
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    destval = fetch_data_word(destoffset);
+	    destval = shrd_word(destval,*shiftreg,M.x86.R_CL);
+	    store_data_word(destoffset, destval);
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = shrd_long(*destreg,*shiftreg,M.x86.R_CL);
+	} else {
+	    u16 *destreg,*shiftreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",CL\n");
+	    TRACE_AND_STEP();
+	    *destreg = shrd_word(*destreg,*shiftreg,M.x86.R_CL);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xaf
+****************************************************************************/
+void x86emuOp2_imul_R_RM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("IMUL\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+	    u32 res_lo,res_hi;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_long(srcoffset);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)srcval);
+	    if (res_hi != 0) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    } else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+	    u32 res;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_word(srcoffset);
+	    TRACE_AND_STEP();
+	    res = (s16)*destreg * (s16)srcval;
+	    if (res > 0xFFFF) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    } else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg,*srcreg;
+	    u32 res_lo,res_hi;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    TRACE_AND_STEP();
+	    imul_long_direct(&res_lo,&res_hi,(s32)*destreg,(s32)*srcreg);
+	    if (res_hi != 0) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    } else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    }
+	    *destreg = (u32)res_lo;
+	} else {
+	    u16 *destreg,*srcreg;
+	    u32 res;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    res = (s16)*destreg * (s16)*srcreg;
+	    if (res > 0xFFFF) {
+		SET_FLAG(F_CF);
+		SET_FLAG(F_OF);
+	    } else {
+		CLEAR_FLAG(F_CF);
+		CLEAR_FLAG(F_OF);
+	    }
+	    *destreg = (u16)res;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb2
+****************************************************************************/
+void x86emuOp2_lss_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rh, rl;
+    u16 *dstreg;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LSS\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	dstreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*dstreg = fetch_data_word(srcoffset);
+	M.x86.R_SS = fetch_data_word(srcoffset + 2);
+    } else {			 /* register to register */
+	/* UNDEFINED! */
+	TRACE_AND_STEP();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb3
+****************************************************************************/
+void x86emuOp2_btr_R(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    int bit,disp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BTR\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval,mask;
+	    u32 *shiftreg;
+
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    disp = (s16)*shiftreg >> 5;
+	    srcval = fetch_data_long(srcoffset+disp);
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_long(srcoffset+disp, srcval & ~mask);
+	} else {
+	    u16 srcval,mask;
+	    u16 *shiftreg;
+
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    disp = (s16)*shiftreg >> 4;
+	    srcval = fetch_data_word(srcoffset+disp);
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_word(srcoffset+disp, (u16)(srcval & ~mask));
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg,*shiftreg;
+	    u32 mask;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg &= ~mask;
+	} else {
+	    u16 *srcreg,*shiftreg;
+	    u16 mask;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg &= ~mask;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb4
+****************************************************************************/
+void x86emuOp2_lfs_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rh, rl;
+    u16 *dstreg;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LFS\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	dstreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*dstreg = fetch_data_word(srcoffset);
+	M.x86.R_FS = fetch_data_word(srcoffset + 2);
+    } else {			 /* register to register */
+	/* UNDEFINED! */
+	TRACE_AND_STEP();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb5
+****************************************************************************/
+void x86emuOp2_lgs_R_IMM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rh, rl;
+    u16 *dstreg;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("LGS\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	dstreg = DECODE_RM_WORD_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*dstreg = fetch_data_word(srcoffset);
+	M.x86.R_GS = fetch_data_word(srcoffset + 2);
+    } else {			 /* register to register */
+	/* UNDEFINED! */
+	TRACE_AND_STEP();
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb6
+****************************************************************************/
+void x86emuOp2_movzx_byte_R_RM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOVZX\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_byte(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = fetch_data_byte(srcoffset);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u8	*srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	} else {
+	    u16 *destreg;
+	    u8	*srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = *srcreg;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xb7
+****************************************************************************/
+void x86emuOp2_movzx_word_R_RM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    u32 *destreg;
+    u32 srcval;
+    u16 *srcreg;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOVZX\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destreg = DECODE_RM_LONG_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	srcval = fetch_data_word(srcoffset);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = srcval;
+    } else {			 /* register to register */
+	destreg = DECODE_RM_LONG_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_WORD_REGISTER(rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = *srcreg;
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xba
+****************************************************************************/
+void x86emuOp2_btX_I(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    u8 shift;
+    int bit;
+
+    START_OF_INSTR();
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    switch (rh) {
+    case 4:
+	DECODE_PRINTF("BT\t");
+	break;
+    case 5:
+	DECODE_PRINTF("BTS\t");
+	break;
+    case 6:
+	DECODE_PRINTF("BTR\t");
+	break;
+    case 7:
+	DECODE_PRINTF("BTC\t");
+	break;
+    default:
+	DECODE_PRINTF("ILLEGAL EXTENDED X86 OPCODE\n");
+	TRACE_REGS();
+	printk("%04x:%04x: %02X%02X ILLEGAL EXTENDED X86 OPCODE EXTENSION!\n",
+		M.x86.R_CS, M.x86.R_IP-3,op2, (mod<<6)|(rh<<3)|rl);
+	HALT_SYS();
+    }
+    if (mod < 3) {
+
+	srcoffset = decode_rmXX_address(mod, rl);
+	shift = fetch_byte_imm();
+	DECODE_PRINTF2(",%d\n", shift);
+	TRACE_AND_STEP();
+
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval, mask;
+
+	    bit = shift & 0x1F;
+	    srcval = fetch_data_long(srcoffset);
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    switch (rh) {
+	    case 5:
+		store_data_long(srcoffset, srcval | mask);
+		break;
+	    case 6:
+		store_data_long(srcoffset, srcval & ~mask);
+		break;
+	    case 7:
+		store_data_long(srcoffset, srcval ^ mask);
+		break;
+	    default:
+		break;
+	    }
+	} else {
+	    u16 srcval, mask;
+
+	    bit = shift & 0xF;
+	    srcval = fetch_data_word(srcoffset);
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    switch (rh) {
+	    case 5:
+		store_data_word(srcoffset, srcval | mask);
+		break;
+	    case 6:
+		store_data_word(srcoffset, srcval & ~mask);
+		break;
+	    case 7:
+		store_data_word(srcoffset, srcval ^ mask);
+		break;
+	    default:
+		break;
+	    }
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg;
+	    u32 mask;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", shift);
+	    TRACE_AND_STEP();
+	    bit = shift & 0x1F;
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    switch (rh) {
+	    case 5:
+		*srcreg |= mask;
+		break;
+	    case 6:
+		*srcreg &= ~mask;
+		break;
+	    case 7:
+		*srcreg ^= mask;
+		break;
+	    default:
+		break;
+	    }
+	} else {
+	    u16 *srcreg;
+	    u16 mask;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    shift = fetch_byte_imm();
+	    DECODE_PRINTF2(",%d\n", shift);
+	    TRACE_AND_STEP();
+	    bit = shift & 0xF;
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    switch (rh) {
+	    case 5:
+		*srcreg |= mask;
+		break;
+	    case 6:
+		*srcreg &= ~mask;
+		break;
+	    case 7:
+		*srcreg ^= mask;
+		break;
+	    default:
+		break;
+	    }
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbb
+****************************************************************************/
+void x86emuOp2_btc_R(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    int bit,disp;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BTC\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval,mask;
+	    u32 *shiftreg;
+
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    disp = (s16)*shiftreg >> 5;
+	    srcval = fetch_data_long(srcoffset+disp);
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_long(srcoffset+disp, srcval ^ mask);
+	} else {
+	    u16 srcval,mask;
+	    u16 *shiftreg;
+
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    disp = (s16)*shiftreg >> 4;
+	    srcval = fetch_data_word(srcoffset+disp);
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(srcval & mask,F_CF);
+	    store_data_word(srcoffset+disp, (u16)(srcval ^ mask));
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg,*shiftreg;
+	    u32 mask;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0x1F;
+	    mask = (0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg ^= mask;
+	} else {
+	    u16 *srcreg,*shiftreg;
+	    u16 mask;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    shiftreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    bit = *shiftreg & 0xF;
+	    mask = (u16)(0x1 << bit);
+	    CONDITIONAL_SET_FLAG(*srcreg & mask,F_CF);
+	    *srcreg ^= mask;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbc
+****************************************************************************/
+void x86emuOp2_bsf(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BSF\n");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval, *dstreg;
+
+	    dstreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    srcval = fetch_data_long(srcoffset);
+	    CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	    for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+		if ((srcval >> *dstreg) & 1) break;
+	} else {
+	    u16 srcval, *dstreg;
+
+	    dstreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    srcval = fetch_data_word(srcoffset);
+	    CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	    for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+		if ((srcval >> *dstreg) & 1) break;
+	}
+    } else {		 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg, *dstreg;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    dstreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF);
+	    for(*dstreg = 0; *dstreg < 32; (*dstreg)++)
+		if ((*srcreg >> *dstreg) & 1) break;
+	} else {
+	    u16 *srcreg, *dstreg;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    dstreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF);
+	    for(*dstreg = 0; *dstreg < 16; (*dstreg)++)
+		if ((*srcreg >> *dstreg) & 1) break;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbd
+****************************************************************************/
+void x86emuOp2_bsr(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("BSF\n");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	srcoffset = decode_rmXX_address(mod, rl);
+	DECODE_PRINTF(",");
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 srcval, *dstreg;
+
+	    dstreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    srcval = fetch_data_long(srcoffset);
+	    CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	    for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+		if ((srcval >> *dstreg) & 1) break;
+	} else {
+	    u16 srcval, *dstreg;
+
+	    dstreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    srcval = fetch_data_word(srcoffset);
+	    CONDITIONAL_SET_FLAG(srcval == 0, F_ZF);
+	    for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+		if ((srcval >> *dstreg) & 1) break;
+	}
+    } else {		 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *srcreg, *dstreg;
+
+	    srcreg = DECODE_RM_LONG_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    dstreg = DECODE_RM_LONG_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF);
+	    for(*dstreg = 31; *dstreg > 0; (*dstreg)--)
+		if ((*srcreg >> *dstreg) & 1) break;
+	} else {
+	    u16 *srcreg, *dstreg;
+
+	    srcreg = DECODE_RM_WORD_REGISTER(rl);
+	    DECODE_PRINTF(",");
+	    dstreg = DECODE_RM_WORD_REGISTER(rh);
+	    TRACE_AND_STEP();
+	    CONDITIONAL_SET_FLAG(*srcreg == 0, F_ZF);
+	    for(*dstreg = 15; *dstreg > 0; (*dstreg)--)
+		if ((*srcreg >> *dstreg) & 1) break;
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbe
+****************************************************************************/
+void x86emuOp2_movsx_byte_R_RM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOVSX\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u32 srcval;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = (s32)((s8)fetch_data_byte(srcoffset));
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	} else {
+	    u16 *destreg;
+	    u16 srcval;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcoffset = decode_rmXX_address(mod, rl);
+	    srcval = (s16)((s8)fetch_data_byte(srcoffset));
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = srcval;
+	}
+    } else {			 /* register to register */
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    u32 *destreg;
+	    u8	*srcreg;
+
+	    destreg = DECODE_RM_LONG_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = (s32)((s8)*srcreg);
+	} else {
+	    u16 *destreg;
+	    u8	*srcreg;
+
+	    destreg = DECODE_RM_WORD_REGISTER(rh);
+	    DECODE_PRINTF(",");
+	    srcreg = DECODE_RM_BYTE_REGISTER(rl);
+	    DECODE_PRINTF("\n");
+	    TRACE_AND_STEP();
+	    *destreg = (s16)((s8)*srcreg);
+	}
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/****************************************************************************
+REMARKS:
+Handles opcode 0x0f,0xbf
+****************************************************************************/
+void x86emuOp2_movsx_word_R_RM(u8 X86EMU_UNUSED(op2))
+{
+    int mod, rl, rh;
+    uint srcoffset;
+    u32 *destreg;
+    u32 srcval;
+    u16 *srcreg;
+
+    START_OF_INSTR();
+    DECODE_PRINTF("MOVSX\t");
+    FETCH_DECODE_MODRM(mod, rh, rl);
+    if (mod < 3) {
+	destreg = DECODE_RM_LONG_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcoffset = decode_rmXX_address(mod, rl);
+	srcval = (s32)((s16)fetch_data_word(srcoffset));
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = srcval;
+    } else {			 /* register to register */
+	destreg = DECODE_RM_LONG_REGISTER(rh);
+	DECODE_PRINTF(",");
+	srcreg = DECODE_RM_WORD_REGISTER(rl);
+	DECODE_PRINTF("\n");
+	TRACE_AND_STEP();
+	*destreg = (s32)((s16)*srcreg);
+    }
+    DECODE_CLEAR_SEGOVR();
+    END_OF_INSTR();
+}
+
+/***************************************************************************
+ * Double byte operation code table:
+ **************************************************************************/
+void (*x86emu_optab2[256])(u8) __attribute__((section(".got2"))) =
+{
+/*  0x00 */ x86emuOp2_illegal_op,  /* Group F (ring 0 PM)      */
+/*  0x01 */ x86emuOp2_illegal_op,  /* Group G (ring 0 PM)      */
+/*  0x02 */ x86emuOp2_illegal_op,  /* lar (ring 0 PM)	       */
+/*  0x03 */ x86emuOp2_illegal_op,  /* lsl (ring 0 PM)	       */
+/*  0x04 */ x86emuOp2_illegal_op,
+/*  0x05 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */
+/*  0x06 */ x86emuOp2_illegal_op,  /* clts (ring 0 PM)	       */
+/*  0x07 */ x86emuOp2_illegal_op,  /* loadall (undocumented)   */
+/*  0x08 */ x86emuOp2_illegal_op,  /* invd (ring 0 PM)	       */
+/*  0x09 */ x86emuOp2_illegal_op,  /* wbinvd (ring 0 PM)       */
+/*  0x0a */ x86emuOp2_illegal_op,
+/*  0x0b */ x86emuOp2_illegal_op,
+/*  0x0c */ x86emuOp2_illegal_op,
+/*  0x0d */ x86emuOp2_illegal_op,
+/*  0x0e */ x86emuOp2_illegal_op,
+/*  0x0f */ x86emuOp2_illegal_op,
+
+/*  0x10 */ x86emuOp2_illegal_op,
+/*  0x11 */ x86emuOp2_illegal_op,
+/*  0x12 */ x86emuOp2_illegal_op,
+/*  0x13 */ x86emuOp2_illegal_op,
+/*  0x14 */ x86emuOp2_illegal_op,
+/*  0x15 */ x86emuOp2_illegal_op,
+/*  0x16 */ x86emuOp2_illegal_op,
+/*  0x17 */ x86emuOp2_illegal_op,
+/*  0x18 */ x86emuOp2_illegal_op,
+/*  0x19 */ x86emuOp2_illegal_op,
+/*  0x1a */ x86emuOp2_illegal_op,
+/*  0x1b */ x86emuOp2_illegal_op,
+/*  0x1c */ x86emuOp2_illegal_op,
+/*  0x1d */ x86emuOp2_illegal_op,
+/*  0x1e */ x86emuOp2_illegal_op,
+/*  0x1f */ x86emuOp2_illegal_op,
+
+/*  0x20 */ x86emuOp2_illegal_op,  /* mov reg32,creg (ring 0 PM) */
+/*  0x21 */ x86emuOp2_illegal_op,  /* mov reg32,dreg (ring 0 PM) */
+/*  0x22 */ x86emuOp2_illegal_op,  /* mov creg,reg32 (ring 0 PM) */
+/*  0x23 */ x86emuOp2_illegal_op,  /* mov dreg,reg32 (ring 0 PM) */
+/*  0x24 */ x86emuOp2_illegal_op,  /* mov reg32,treg (ring 0 PM) */
+/*  0x25 */ x86emuOp2_illegal_op,
+/*  0x26 */ x86emuOp2_illegal_op,  /* mov treg,reg32 (ring 0 PM) */
+/*  0x27 */ x86emuOp2_illegal_op,
+/*  0x28 */ x86emuOp2_illegal_op,
+/*  0x29 */ x86emuOp2_illegal_op,
+/*  0x2a */ x86emuOp2_illegal_op,
+/*  0x2b */ x86emuOp2_illegal_op,
+/*  0x2c */ x86emuOp2_illegal_op,
+/*  0x2d */ x86emuOp2_illegal_op,
+/*  0x2e */ x86emuOp2_illegal_op,
+/*  0x2f */ x86emuOp2_illegal_op,
+
+/*  0x30 */ x86emuOp2_illegal_op,
+/*  0x31 */ x86emuOp2_illegal_op,
+/*  0x32 */ x86emuOp2_illegal_op,
+/*  0x33 */ x86emuOp2_illegal_op,
+/*  0x34 */ x86emuOp2_illegal_op,
+/*  0x35 */ x86emuOp2_illegal_op,
+/*  0x36 */ x86emuOp2_illegal_op,
+/*  0x37 */ x86emuOp2_illegal_op,
+/*  0x38 */ x86emuOp2_illegal_op,
+/*  0x39 */ x86emuOp2_illegal_op,
+/*  0x3a */ x86emuOp2_illegal_op,
+/*  0x3b */ x86emuOp2_illegal_op,
+/*  0x3c */ x86emuOp2_illegal_op,
+/*  0x3d */ x86emuOp2_illegal_op,
+/*  0x3e */ x86emuOp2_illegal_op,
+/*  0x3f */ x86emuOp2_illegal_op,
+
+/*  0x40 */ x86emuOp2_illegal_op,
+/*  0x41 */ x86emuOp2_illegal_op,
+/*  0x42 */ x86emuOp2_illegal_op,
+/*  0x43 */ x86emuOp2_illegal_op,
+/*  0x44 */ x86emuOp2_illegal_op,
+/*  0x45 */ x86emuOp2_illegal_op,
+/*  0x46 */ x86emuOp2_illegal_op,
+/*  0x47 */ x86emuOp2_illegal_op,
+/*  0x48 */ x86emuOp2_illegal_op,
+/*  0x49 */ x86emuOp2_illegal_op,
+/*  0x4a */ x86emuOp2_illegal_op,
+/*  0x4b */ x86emuOp2_illegal_op,
+/*  0x4c */ x86emuOp2_illegal_op,
+/*  0x4d */ x86emuOp2_illegal_op,
+/*  0x4e */ x86emuOp2_illegal_op,
+/*  0x4f */ x86emuOp2_illegal_op,
+
+/*  0x50 */ x86emuOp2_illegal_op,
+/*  0x51 */ x86emuOp2_illegal_op,
+/*  0x52 */ x86emuOp2_illegal_op,
+/*  0x53 */ x86emuOp2_illegal_op,
+/*  0x54 */ x86emuOp2_illegal_op,
+/*  0x55 */ x86emuOp2_illegal_op,
+/*  0x56 */ x86emuOp2_illegal_op,
+/*  0x57 */ x86emuOp2_illegal_op,
+/*  0x58 */ x86emuOp2_illegal_op,
+/*  0x59 */ x86emuOp2_illegal_op,
+/*  0x5a */ x86emuOp2_illegal_op,
+/*  0x5b */ x86emuOp2_illegal_op,
+/*  0x5c */ x86emuOp2_illegal_op,
+/*  0x5d */ x86emuOp2_illegal_op,
+/*  0x5e */ x86emuOp2_illegal_op,
+/*  0x5f */ x86emuOp2_illegal_op,
+
+/*  0x60 */ x86emuOp2_illegal_op,
+/*  0x61 */ x86emuOp2_illegal_op,
+/*  0x62 */ x86emuOp2_illegal_op,
+/*  0x63 */ x86emuOp2_illegal_op,
+/*  0x64 */ x86emuOp2_illegal_op,
+/*  0x65 */ x86emuOp2_illegal_op,
+/*  0x66 */ x86emuOp2_illegal_op,
+/*  0x67 */ x86emuOp2_illegal_op,
+/*  0x68 */ x86emuOp2_illegal_op,
+/*  0x69 */ x86emuOp2_illegal_op,
+/*  0x6a */ x86emuOp2_illegal_op,
+/*  0x6b */ x86emuOp2_illegal_op,
+/*  0x6c */ x86emuOp2_illegal_op,
+/*  0x6d */ x86emuOp2_illegal_op,
+/*  0x6e */ x86emuOp2_illegal_op,
+/*  0x6f */ x86emuOp2_illegal_op,
+
+/*  0x70 */ x86emuOp2_illegal_op,
+/*  0x71 */ x86emuOp2_illegal_op,
+/*  0x72 */ x86emuOp2_illegal_op,
+/*  0x73 */ x86emuOp2_illegal_op,
+/*  0x74 */ x86emuOp2_illegal_op,
+/*  0x75 */ x86emuOp2_illegal_op,
+/*  0x76 */ x86emuOp2_illegal_op,
+/*  0x77 */ x86emuOp2_illegal_op,
+/*  0x78 */ x86emuOp2_illegal_op,
+/*  0x79 */ x86emuOp2_illegal_op,
+/*  0x7a */ x86emuOp2_illegal_op,
+/*  0x7b */ x86emuOp2_illegal_op,
+/*  0x7c */ x86emuOp2_illegal_op,
+/*  0x7d */ x86emuOp2_illegal_op,
+/*  0x7e */ x86emuOp2_illegal_op,
+/*  0x7f */ x86emuOp2_illegal_op,
+
+/*  0x80 */ x86emuOp2_long_jump,
+/*  0x81 */ x86emuOp2_long_jump,
+/*  0x82 */ x86emuOp2_long_jump,
+/*  0x83 */ x86emuOp2_long_jump,
+/*  0x84 */ x86emuOp2_long_jump,
+/*  0x85 */ x86emuOp2_long_jump,
+/*  0x86 */ x86emuOp2_long_jump,
+/*  0x87 */ x86emuOp2_long_jump,
+/*  0x88 */ x86emuOp2_long_jump,
+/*  0x89 */ x86emuOp2_long_jump,
+/*  0x8a */ x86emuOp2_long_jump,
+/*  0x8b */ x86emuOp2_long_jump,
+/*  0x8c */ x86emuOp2_long_jump,
+/*  0x8d */ x86emuOp2_long_jump,
+/*  0x8e */ x86emuOp2_long_jump,
+/*  0x8f */ x86emuOp2_long_jump,
+
+/*  0x90 */ x86emuOp2_set_byte,
+/*  0x91 */ x86emuOp2_set_byte,
+/*  0x92 */ x86emuOp2_set_byte,
+/*  0x93 */ x86emuOp2_set_byte,
+/*  0x94 */ x86emuOp2_set_byte,
+/*  0x95 */ x86emuOp2_set_byte,
+/*  0x96 */ x86emuOp2_set_byte,
+/*  0x97 */ x86emuOp2_set_byte,
+/*  0x98 */ x86emuOp2_set_byte,
+/*  0x99 */ x86emuOp2_set_byte,
+/*  0x9a */ x86emuOp2_set_byte,
+/*  0x9b */ x86emuOp2_set_byte,
+/*  0x9c */ x86emuOp2_set_byte,
+/*  0x9d */ x86emuOp2_set_byte,
+/*  0x9e */ x86emuOp2_set_byte,
+/*  0x9f */ x86emuOp2_set_byte,
+
+/*  0xa0 */ x86emuOp2_push_FS,
+/*  0xa1 */ x86emuOp2_pop_FS,
+/*  0xa2 */ x86emuOp2_illegal_op,
+/*  0xa3 */ x86emuOp2_bt_R,
+/*  0xa4 */ x86emuOp2_shld_IMM,
+/*  0xa5 */ x86emuOp2_shld_CL,
+/*  0xa6 */ x86emuOp2_illegal_op,
+/*  0xa7 */ x86emuOp2_illegal_op,
+/*  0xa8 */ x86emuOp2_push_GS,
+/*  0xa9 */ x86emuOp2_pop_GS,
+/*  0xaa */ x86emuOp2_illegal_op,
+/*  0xab */ x86emuOp2_bt_R,
+/*  0xac */ x86emuOp2_shrd_IMM,
+/*  0xad */ x86emuOp2_shrd_CL,
+/*  0xae */ x86emuOp2_illegal_op,
+/*  0xaf */ x86emuOp2_imul_R_RM,
+
+/*  0xb0 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */
+/*  0xb1 */ x86emuOp2_illegal_op,  /* TODO: cmpxchg */
+/*  0xb2 */ x86emuOp2_lss_R_IMM,
+/*  0xb3 */ x86emuOp2_btr_R,
+/*  0xb4 */ x86emuOp2_lfs_R_IMM,
+/*  0xb5 */ x86emuOp2_lgs_R_IMM,
+/*  0xb6 */ x86emuOp2_movzx_byte_R_RM,
+/*  0xb7 */ x86emuOp2_movzx_word_R_RM,
+/*  0xb8 */ x86emuOp2_illegal_op,
+/*  0xb9 */ x86emuOp2_illegal_op,
+/*  0xba */ x86emuOp2_btX_I,
+/*  0xbb */ x86emuOp2_btc_R,
+/*  0xbc */ x86emuOp2_bsf,
+/*  0xbd */ x86emuOp2_bsr,
+/*  0xbe */ x86emuOp2_movsx_byte_R_RM,
+/*  0xbf */ x86emuOp2_movsx_word_R_RM,
+
+/*  0xc0 */ x86emuOp2_illegal_op,  /* TODO: xadd */
+/*  0xc1 */ x86emuOp2_illegal_op,  /* TODO: xadd */
+/*  0xc2 */ x86emuOp2_illegal_op,
+/*  0xc3 */ x86emuOp2_illegal_op,
+/*  0xc4 */ x86emuOp2_illegal_op,
+/*  0xc5 */ x86emuOp2_illegal_op,
+/*  0xc6 */ x86emuOp2_illegal_op,
+/*  0xc7 */ x86emuOp2_illegal_op,
+/*  0xc8 */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xc9 */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xca */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xcb */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xcc */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xcd */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xce */ x86emuOp2_illegal_op,  /* TODO: bswap */
+/*  0xcf */ x86emuOp2_illegal_op,  /* TODO: bswap */
+
+/*  0xd0 */ x86emuOp2_illegal_op,
+/*  0xd1 */ x86emuOp2_illegal_op,
+/*  0xd2 */ x86emuOp2_illegal_op,
+/*  0xd3 */ x86emuOp2_illegal_op,
+/*  0xd4 */ x86emuOp2_illegal_op,
+/*  0xd5 */ x86emuOp2_illegal_op,
+/*  0xd6 */ x86emuOp2_illegal_op,
+/*  0xd7 */ x86emuOp2_illegal_op,
+/*  0xd8 */ x86emuOp2_illegal_op,
+/*  0xd9 */ x86emuOp2_illegal_op,
+/*  0xda */ x86emuOp2_illegal_op,
+/*  0xdb */ x86emuOp2_illegal_op,
+/*  0xdc */ x86emuOp2_illegal_op,
+/*  0xdd */ x86emuOp2_illegal_op,
+/*  0xde */ x86emuOp2_illegal_op,
+/*  0xdf */ x86emuOp2_illegal_op,
+
+/*  0xe0 */ x86emuOp2_illegal_op,
+/*  0xe1 */ x86emuOp2_illegal_op,
+/*  0xe2 */ x86emuOp2_illegal_op,
+/*  0xe3 */ x86emuOp2_illegal_op,
+/*  0xe4 */ x86emuOp2_illegal_op,
+/*  0xe5 */ x86emuOp2_illegal_op,
+/*  0xe6 */ x86emuOp2_illegal_op,
+/*  0xe7 */ x86emuOp2_illegal_op,
+/*  0xe8 */ x86emuOp2_illegal_op,
+/*  0xe9 */ x86emuOp2_illegal_op,
+/*  0xea */ x86emuOp2_illegal_op,
+/*  0xeb */ x86emuOp2_illegal_op,
+/*  0xec */ x86emuOp2_illegal_op,
+/*  0xed */ x86emuOp2_illegal_op,
+/*  0xee */ x86emuOp2_illegal_op,
+/*  0xef */ x86emuOp2_illegal_op,
+
+/*  0xf0 */ x86emuOp2_illegal_op,
+/*  0xf1 */ x86emuOp2_illegal_op,
+/*  0xf2 */ x86emuOp2_illegal_op,
+/*  0xf3 */ x86emuOp2_illegal_op,
+/*  0xf4 */ x86emuOp2_illegal_op,
+/*  0xf5 */ x86emuOp2_illegal_op,
+/*  0xf6 */ x86emuOp2_illegal_op,
+/*  0xf7 */ x86emuOp2_illegal_op,
+/*  0xf8 */ x86emuOp2_illegal_op,
+/*  0xf9 */ x86emuOp2_illegal_op,
+/*  0xfa */ x86emuOp2_illegal_op,
+/*  0xfb */ x86emuOp2_illegal_op,
+/*  0xfc */ x86emuOp2_illegal_op,
+/*  0xfd */ x86emuOp2_illegal_op,
+/*  0xfe */ x86emuOp2_illegal_op,
+/*  0xff */ x86emuOp2_illegal_op,
+};
+
+#endif
diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c
new file mode 100644
index 0000000..c1152ea
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/prim_ops.c
@@ -0,0 +1,2449 @@
+/****************************************************************************
+*
+*			Realmode X86 Emulator Library
+*
+*		Copyright (C) 1991-2004 SciTech Software, Inc.
+*		     Copyright (C) David Mosberger-Tang
+*		       Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.	The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:	ANSI C
+* Environment:	Any
+* Developer:	Kendall Bennett
+*
+* Description:	This file contains the code to implement the primitive
+*		machine operations used by the emulation code in ops.c
+*
+* Carry Chain Calculation
+*
+* This represents a somewhat expensive calculation which is
+* apparently required to emulate the setting of the OF343364 and AF flag.
+* The latter is not so important, but the former is.  The overflow
+* flag is the XOR of the top two bits of the carry chain for an
+* addition (similar for subtraction).  Since we do not want to
+* simulate the addition in a bitwise manner, we try to calculate the
+* carry chain given the two operands and the result.
+*
+* So, given the following table, which represents the addition of two
+* bits, we can derive a formula for the carry chain.
+*
+* a   b	  cin	r     cout
+* 0   0	  0	0     0
+* 0   0	  1	1     0
+* 0   1	  0	1     0
+* 0   1	  1	0     1
+* 1   0	  0	1     0
+* 1   0	  1	0     1
+* 1   1	  0	0     1
+* 1   1	  1	1     1
+*
+* Construction of table for cout:
+*
+* ab
+* r  \	00   01	  11  10
+* |------------------
+* 0  |	 0    1	   1   1
+* 1  |	 0    0	   1   0
+*
+* By inspection, one gets:  cc = ab +  r'(a + b)
+*
+* That represents alot of operations, but NO CHOICE....
+*
+* Borrow Chain Calculation.
+*
+* The following table represents the subtraction of two bits, from
+* which we can derive a formula for the borrow chain.
+*
+* a   b	  bin	r     bout
+* 0   0	  0	0     0
+* 0   0	  1	1     1
+* 0   1	  0	1     1
+* 0   1	  1	0     1
+* 1   0	  0	1     0
+* 1   0	  1	0     0
+* 1   1	  0	0     0
+* 1   1	  1	1     1
+*
+* Construction of table for cout:
+*
+* ab
+* r  \	00   01	  11  10
+* |------------------
+* 0  |	 0    1	   0   0
+* 1  |	 1    1	   1   0
+*
+* By inspection, one gets:  bc = a'b +	r(a' + b)
+*
+****************************************************************************/
+
+#define PRIM_OPS_NO_REDEFINE_ASM
+#include "x86emu/x86emui.h"
+
+#if defined(CONFIG_BIOSEMU)
+
+/*------------------------- Global Variables ------------------------------*/
+
+static u32 x86emu_parity_tab[8] =
+{
+    0x96696996,
+    0x69969669,
+    0x69969669,
+    0x96696996,
+    0x69969669,
+    0x96696996,
+    0x96696996,
+    0x69969669,
+};
+
+#define PARITY(x)   (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
+#define XOR2(x)	    (((x) ^ ((x)>>1)) & 0x1)
+/*----------------------------- Implementation ----------------------------*/
+int abs(int v)
+{
+	return (v>0)?v:-v;
+}
+
+/*----------------------------- Implementation ----------------------------*/
+
+
+/*--------- Side effects helper functions -------*/
+
+/****************************************************************************
+REMARKS:
+implements side efects for byte operations that don't overflow
+****************************************************************************/
+
+static void set_parity_flag(u32 res)
+{
+    CONDITIONAL_SET_FLAG(PARITY(res & 0xFF), F_PF);
+}
+
+static void set_szp_flags_8(u8 res)
+{
+    CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
+    CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+    set_parity_flag(res);
+}
+
+static void set_szp_flags_16(u16 res)
+{
+    CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
+    CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+    set_parity_flag(res);
+}
+
+static void set_szp_flags_32(u32 res)
+{
+    CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
+    CONDITIONAL_SET_FLAG(res == 0, F_ZF);
+    set_parity_flag(res);
+}
+
+static void no_carry_byte_side_eff(u8 res)
+{
+    CLEAR_FLAG(F_OF);
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_AF);
+    set_szp_flags_8(res);
+}
+
+static void no_carry_word_side_eff(u16 res)
+{
+    CLEAR_FLAG(F_OF);
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_AF);
+    set_szp_flags_16(res);
+}
+
+static void no_carry_long_side_eff(u32 res)
+{
+    CLEAR_FLAG(F_OF);
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_AF);
+    set_szp_flags_32(res);
+}
+
+static void calc_carry_chain(int bits, u32 d, u32 s, u32 res, int set_carry)
+{
+    u32 cc;
+
+    cc = (s & d) | ((~res) & (s | d));
+    CONDITIONAL_SET_FLAG(XOR2(cc >> (bits - 2)), F_OF);
+    CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
+    if (set_carry) {
+	CONDITIONAL_SET_FLAG(res & (1 << bits), F_CF);
+    }
+}
+
+static void calc_borrow_chain(int bits, u32 d, u32 s, u32 res, int set_carry)
+{
+    u32 bc;
+
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> (bits - 2)), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    if (set_carry) {
+	CONDITIONAL_SET_FLAG(bc & (1 << (bits - 1)), F_CF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAA instruction and side effects.
+****************************************************************************/
+u16 aaa_word(u16 d)
+{
+    u16 res;
+    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+	d += 0x6;
+	d += 0x100;
+	SET_FLAG(F_AF);
+	SET_FLAG(F_CF);
+    } else {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+    }
+    res = (u16)(d & 0xFF0F);
+    set_szp_flags_16(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAA instruction and side effects.
+****************************************************************************/
+u16 aas_word(u16 d)
+{
+    u16 res;
+    if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) {
+	d -= 0x6;
+	d -= 0x100;
+	SET_FLAG(F_AF);
+	SET_FLAG(F_CF);
+    } else {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_AF);
+    }
+    res = (u16)(d & 0xFF0F);
+    set_szp_flags_16(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAD instruction and side effects.
+****************************************************************************/
+u16 aad_word(u16 d)
+{
+    u16 l;
+    u8 hb, lb;
+
+    hb = (u8)((d >> 8) & 0xff);
+    lb = (u8)((d & 0xff));
+    l = (u16)((lb + 10 * hb) & 0xFF);
+
+    no_carry_byte_side_eff(l & 0xFF);
+    return l;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AAM instruction and side effects.
+****************************************************************************/
+u16 aam_word(u8 d)
+{
+    u16 h, l;
+
+    h = (u16)(d / 10);
+    l = (u16)(d % 10);
+    l |= (u16)(h << 8);
+
+    no_carry_byte_side_eff(l & 0xFF);
+    return l;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u8 adc_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + s;
+    if (ACCESS_FLAG(F_CF)) res++;
+
+    set_szp_flags_8(res);
+    calc_carry_chain(8,s,d,res,1);
+
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u16 adc_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + s;
+    if (ACCESS_FLAG(F_CF))
+	res++;
+
+    set_szp_flags_16((u16)res);
+    calc_carry_chain(16,s,d,res,1);
+
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADC instruction and side effects.
+****************************************************************************/
+u32 adc_long(u32 d, u32 s)
+{
+    u32 lo;    /* all operands in native machine order */
+    u32 hi;
+    u32 res;
+
+    lo = (d & 0xFFFF) + (s & 0xFFFF);
+    res = d + s;
+
+    if (ACCESS_FLAG(F_CF)) {
+	lo++;
+	res++;
+    }
+
+    hi = (lo >> 16) + (d >> 16) + (s >> 16);
+
+    set_szp_flags_32(res);
+    calc_carry_chain(32,s,d,res,0);
+
+    CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u8 add_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + s;
+    set_szp_flags_8((u8)res);
+    calc_carry_chain(8,s,d,res,1);
+
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u16 add_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + s;
+    set_szp_flags_16((u16)res);
+    calc_carry_chain(16,s,d,res,1);
+
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ADD instruction and side effects.
+****************************************************************************/
+u32 add_long(u32 d, u32 s)
+{
+    u32 res;
+
+    res = d + s;
+    set_szp_flags_32(res);
+    calc_carry_chain(32,s,d,res,0);
+
+    CONDITIONAL_SET_FLAG(res < d || res < s, F_CF);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u8 and_byte(u8 d, u8 s)
+{
+    u8 res;    /* all operands in native machine order */
+
+    res = d & s;
+
+    no_carry_byte_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u16 and_word(u16 d, u16 s)
+{
+    u16 res;   /* all operands in native machine order */
+
+    res = d & s;
+
+    no_carry_word_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the AND instruction and side effects.
+****************************************************************************/
+u32 and_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d & s;
+    no_carry_long_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u8 cmp_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - s;
+    set_szp_flags_8((u8)res);
+    calc_borrow_chain(8, d, s, res, 1);
+
+    return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u16 cmp_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - s;
+    set_szp_flags_16((u16)res);
+    calc_borrow_chain(16, d, s, res, 1);
+
+    return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the CMP instruction and side effects.
+****************************************************************************/
+u32 cmp_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - s;
+    set_szp_flags_32(res);
+    calc_borrow_chain(32, d, s, res, 1);
+
+    return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DAA instruction and side effects.
+****************************************************************************/
+u8 daa_byte(u8 d)
+{
+    u32 res = d;
+    if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+	res += 6;
+	SET_FLAG(F_AF);
+    }
+    if (res > 0x9F || ACCESS_FLAG(F_CF)) {
+	res += 0x60;
+	SET_FLAG(F_CF);
+    }
+    set_szp_flags_8((u8)res);
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DAS instruction and side effects.
+****************************************************************************/
+u8 das_byte(u8 d)
+{
+    if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
+	d -= 6;
+	SET_FLAG(F_AF);
+    }
+    if (d > 0x9F || ACCESS_FLAG(F_CF)) {
+	d -= 0x60;
+	SET_FLAG(F_CF);
+    }
+    set_szp_flags_8(d);
+    return d;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u8 dec_byte(u8 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - 1;
+    set_szp_flags_8((u8)res);
+    calc_borrow_chain(8, d, 1, res, 0);
+
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u16 dec_word(u16 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - 1;
+    set_szp_flags_16((u16)res);
+    calc_borrow_chain(16, d, 1, res, 0);
+
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DEC instruction and side effects.
+****************************************************************************/
+u32 dec_long(u32 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d - 1;
+
+    set_szp_flags_32(res);
+    calc_borrow_chain(32, d, 1, res, 0);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u8 inc_byte(u8 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + 1;
+    set_szp_flags_8((u8)res);
+    calc_carry_chain(8, d, 1, res, 0);
+
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u16 inc_word(u16 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + 1;
+    set_szp_flags_16((u16)res);
+    calc_carry_chain(16, d, 1, res, 0);
+
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the INC instruction and side effects.
+****************************************************************************/
+u32 inc_long(u32 d)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d + 1;
+    set_szp_flags_32(res);
+    calc_carry_chain(32, d, 1, res, 0);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u8 or_byte(u8 d, u8 s)
+{
+    u8 res;    /* all operands in native machine order */
+
+    res = d | s;
+    no_carry_byte_side_eff(res);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u16 or_word(u16 d, u16 s)
+{
+    u16 res;   /* all operands in native machine order */
+
+    res = d | s;
+    no_carry_word_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u32 or_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d | s;
+    no_carry_long_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u8 neg_byte(u8 s)
+{
+    u8 res;
+
+    CONDITIONAL_SET_FLAG(s != 0, F_CF);
+    res = (u8)-s;
+    set_szp_flags_8(res);
+    calc_borrow_chain(8, 0, s, res, 0);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u16 neg_word(u16 s)
+{
+    u16 res;
+
+    CONDITIONAL_SET_FLAG(s != 0, F_CF);
+    res = (u16)-s;
+    set_szp_flags_16((u16)res);
+    calc_borrow_chain(16, 0, s, res, 0);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OR instruction and side effects.
+****************************************************************************/
+u32 neg_long(u32 s)
+{
+    u32 res;
+
+    CONDITIONAL_SET_FLAG(s != 0, F_CF);
+    res = (u32)-s;
+    set_szp_flags_32(res);
+    calc_borrow_chain(32, 0, s, res, 0);
+
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u8 not_byte(u8 s)
+{
+    return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u16 not_word(u16 s)
+{
+    return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the NOT instruction and side effects.
+****************************************************************************/
+u32 not_long(u32 s)
+{
+    return ~s;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u8 rcl_byte(u8 d, u8 s)
+{
+    unsigned int res, cnt, mask, cf;
+
+    /* s is the rotate distance.  It varies from 0 - 8. */
+    /* have
+
+       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+
+       want to rotate through the carry by "s" bits.  We could
+       loop, but that's inefficient.  So the width is 9,
+       and we split into three parts:
+
+       The new carry flag   (was B_n)
+       the stuff in B_n-1 .. B_0
+       the stuff in B_7 .. B_n+1
+
+       The new rotate is done mod 9, and given this,
+       for a rotation of n bits (mod 9) the new carry flag is
+       then located n bits from the MSB.  The low part is
+       then shifted up cnt bits, and the high part is or'd
+       in.  Using CAPS for new values, and lowercase for the
+       original values, this can be expressed as:
+
+       IF n > 0
+       1) CF <-	 b_(8-n)
+       2) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0
+       3) B_(n-1) <- cf
+       4) B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1))
+     */
+    res = d;
+    if ((cnt = s % 9) != 0) {
+	/* extract the new CARRY FLAG. */
+	/* CF <-  b_(8-n)	      */
+	cf = (d >> (8 - cnt)) & 0x1;
+
+	/* get the low stuff which rotated
+	   into the range B_7 .. B_cnt */
+	/* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_0  */
+	/* note that the right hand side done by the mask */
+	res = (d << cnt) & 0xff;
+
+	/* now the high stuff which rotated around
+	   into the positions B_cnt-2 .. B_0 */
+	/* B_(n-2) .. B_0 <-  b_7 .. b_(8-(n-1)) */
+	/* shift it downward, 7-(n-2) = 9-n positions.
+	   and mask off the result before or'ing in.
+	 */
+	mask = (1 << (cnt - 1)) - 1;
+	res |= (d >> (9 - cnt)) & mask;
+
+	/* if the carry flag was set, or it in.	 */
+	if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
+	    /*	B_(n-1) <- cf */
+	    res |= 1 << (cnt - 1);
+	}
+	/* set the new carry flag, based on the variable "cf" */
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	/* OVERFLOW is set *IFF* cnt==1, then it is the
+	   xor of CF and the most significant bit.  Blecck. */
+	/* parenthesized this expression since it appears to
+	   be causing OF to be misset */
+	CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)),
+			     F_OF);
+
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u16 rcl_word(u16 d, u8 s)
+{
+    unsigned int res, cnt, mask, cf;
+
+    res = d;
+    if ((cnt = s % 17) != 0) {
+	cf = (d >> (16 - cnt)) & 0x1;
+	res = (d << cnt) & 0xffff;
+	mask = (1 << (cnt - 1)) - 1;
+	res |= (d >> (17 - cnt)) & mask;
+	if (ACCESS_FLAG(F_CF)) {
+	    res |= 1 << (cnt - 1);
+	}
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)),
+			     F_OF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCL instruction and side effects.
+****************************************************************************/
+u32 rcl_long(u32 d, u8 s)
+{
+    u32 res, cnt, mask, cf;
+
+    res = d;
+    if ((cnt = s % 33) != 0) {
+	cf = (d >> (32 - cnt)) & 0x1;
+	res = (d << cnt) & 0xffffffff;
+	mask = (1 << (cnt - 1)) - 1;
+	res |= (d >> (33 - cnt)) & mask;
+	if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
+	    res |= 1 << (cnt - 1);
+	}
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)),
+			     F_OF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u8 rcr_byte(u8 d, u8 s)
+{
+    u32 res, cnt;
+    u32 mask, cf, ocf = 0;
+
+    /* rotate right through carry */
+    /*
+       s is the rotate distance.  It varies from 0 - 8.
+       d is the byte object rotated.
+
+       have
+
+       CF  B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
+
+       The new rotate is done mod 9, and given this,
+       for a rotation of n bits (mod 9) the new carry flag is
+       then located n bits from the LSB.  The low part is
+       then shifted up cnt bits, and the high part is or'd
+       in.  Using CAPS for new values, and lowercase for the
+       original values, this can be expressed as:
+
+       IF n > 0
+       1) CF <-	 b_(n-1)
+       2) B_(8-(n+1)) .. B_(0)	<-  b_(7) .. b_(n)
+       3) B_(8-n) <- cf
+       4) B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0)
+     */
+    res = d;
+    if ((cnt = s % 9) != 0) {
+	/* extract the new CARRY FLAG. */
+	/* CF <-  b_(n-1)	       */
+	if (cnt == 1) {
+	    cf = d & 0x1;
+	    /* note hackery here.  Access_flag(..) evaluates to either
+	       0 if flag not set
+	       non-zero if flag is set.
+	       doing access_flag(..) != 0 casts that into either
+	       0..1 in any representation of the flags register
+	       (i.e. packed bit array or unpacked.)
+	     */
+	    ocf = ACCESS_FLAG(F_CF) != 0;
+	} else
+	    cf = (d >> (cnt - 1)) & 0x1;
+
+	/* B_(8-(n+1)) .. B_(0)	 <-  b_(7) .. b_n  */
+	/* note that the right hand side done by the mask
+	   This is effectively done by shifting the
+	   object to the right.	 The result must be masked,
+	   in case the object came in and was treated
+	   as a negative number.  Needed??? */
+
+	mask = (1 << (8 - cnt)) - 1;
+	res = (d >> cnt) & mask;
+
+	/* now the high stuff which rotated around
+	   into the positions B_cnt-2 .. B_0 */
+	/* B_(7) .. B_(8-(n-1)) <-  b_(n-2) .. b_(0) */
+	/* shift it downward, 7-(n-2) = 9-n positions.
+	   and mask off the result before or'ing in.
+	 */
+	res |= (d << (9 - cnt));
+
+	/* if the carry flag was set, or it in.	 */
+	if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
+	    /*	B_(8-n) <- cf */
+	    res |= 1 << (8 - cnt);
+	}
+	/* set the new carry flag, based on the variable "cf" */
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	/* OVERFLOW is set *IFF* cnt==1, then it is the
+	   xor of CF and the most significant bit.  Blecck. */
+	/* parenthesized... */
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)),
+				 F_OF);
+	}
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u16 rcr_word(u16 d, u8 s)
+{
+    u32 res, cnt;
+    u32 mask, cf, ocf = 0;
+
+    /* rotate right through carry */
+    res = d;
+    if ((cnt = s % 17) != 0) {
+	if (cnt == 1) {
+	    cf = d & 0x1;
+	    ocf = ACCESS_FLAG(F_CF) != 0;
+	} else
+	    cf = (d >> (cnt - 1)) & 0x1;
+	mask = (1 << (16 - cnt)) - 1;
+	res = (d >> cnt) & mask;
+	res |= (d << (17 - cnt));
+	if (ACCESS_FLAG(F_CF)) {
+	    res |= 1 << (16 - cnt);
+	}
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)),
+				 F_OF);
+	}
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the RCR instruction and side effects.
+****************************************************************************/
+u32 rcr_long(u32 d, u8 s)
+{
+    u32 res, cnt;
+    u32 mask, cf, ocf = 0;
+
+    /* rotate right through carry */
+    res = d;
+    if ((cnt = s % 33) != 0) {
+	if (cnt == 1) {
+	    cf = d & 0x1;
+	    ocf = ACCESS_FLAG(F_CF) != 0;
+	} else
+	    cf = (d >> (cnt - 1)) & 0x1;
+	mask = (1 << (32 - cnt)) - 1;
+	res = (d >> cnt) & mask;
+	if (cnt != 1)
+	    res |= (d << (33 - cnt));
+	if (ACCESS_FLAG(F_CF)) {     /* carry flag is set */
+	    res |= 1 << (32 - cnt);
+	}
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)),
+				 F_OF);
+	}
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u8 rol_byte(u8 d, u8 s)
+{
+    unsigned int res, cnt, mask;
+
+    /* rotate left */
+    /*
+       s is the rotate distance.  It varies from 0 - 8.
+       d is the byte object rotated.
+
+       have
+
+       CF  B_7 ... B_0
+
+       The new rotate is done mod 8.
+       Much simpler than the "rcl" or "rcr" operations.
+
+       IF n > 0
+       1) B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0)
+       2) B_(n-1) .. B_(0) <-  b_(7) .. b_(8-n)
+     */
+    res = d;
+    if ((cnt = s % 8) != 0) {
+	/* B_(7) .. B_(n)  <-  b_(8-(n+1)) .. b_(0) */
+	res = (d << cnt);
+
+	/* B_(n-1) .. B_(0) <-	b_(7) .. b_(8-n) */
+	mask = (1 << cnt) - 1;
+	res |= (d >> (8 - cnt)) & mask;
+
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	/* OVERFLOW is set *IFF* s==1, then it is the
+	   xor of CF and the most significant bit.  Blecck. */
+	CONDITIONAL_SET_FLAG(s == 1 &&
+			     XOR2((res & 0x1) + ((res >> 6) & 0x2)),
+			     F_OF);
+    } if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u16 rol_word(u16 d, u8 s)
+{
+    unsigned int res, cnt, mask;
+
+    res = d;
+    if ((cnt = s % 16) != 0) {
+	res = (d << cnt);
+	mask = (1 << cnt) - 1;
+	res |= (d >> (16 - cnt)) & mask;
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	CONDITIONAL_SET_FLAG(s == 1 &&
+			     XOR2((res & 0x1) + ((res >> 14) & 0x2)),
+			     F_OF);
+    } if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROL instruction and side effects.
+****************************************************************************/
+u32 rol_long(u32 d, u8 s)
+{
+    u32 res, cnt, mask;
+
+    res = d;
+    if ((cnt = s % 32) != 0) {
+	res = (d << cnt);
+	mask = (1 << cnt) - 1;
+	res |= (d >> (32 - cnt)) & mask;
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+	CONDITIONAL_SET_FLAG(s == 1 &&
+			     XOR2((res & 0x1) + ((res >> 30) & 0x2)),
+			     F_OF);
+    } if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u8 ror_byte(u8 d, u8 s)
+{
+    unsigned int res, cnt, mask;
+
+    /* rotate right */
+    /*
+       s is the rotate distance.  It varies from 0 - 8.
+       d is the byte object rotated.
+
+       have
+
+       B_7 ... B_0
+
+       The rotate is done mod 8.
+
+       IF n > 0
+       1) B_(8-(n+1)) .. B_(0)	<-  b_(7) .. b_(n)
+       2) B_(7) .. B_(8-n) <-  b_(n-1) .. b_(0)
+     */
+    res = d;
+    if ((cnt = s % 8) != 0) {		/* not a typo, do nada if cnt==0 */
+	/* B_(7) .. B_(8-n) <-	b_(n-1) .. b_(0) */
+	res = (d << (8 - cnt));
+
+	/* B_(8-(n+1)) .. B_(0)	 <-  b_(7) .. b_(n) */
+	mask = (1 << (8 - cnt)) - 1;
+	res |= (d >> (cnt)) & mask;
+
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+	/* OVERFLOW is set *IFF* s==1, then it is the
+	   xor of the two most significant bits.  Blecck. */
+	CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
+    } else if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u16 ror_word(u16 d, u8 s)
+{
+    unsigned int res, cnt, mask;
+
+    res = d;
+    if ((cnt = s % 16) != 0) {
+	res = (d << (16 - cnt));
+	mask = (1 << (16 - cnt)) - 1;
+	res |= (d >> (cnt)) & mask;
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+	CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
+    } else if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the ROR instruction and side effects.
+****************************************************************************/
+u32 ror_long(u32 d, u8 s)
+{
+    u32 res, cnt, mask;
+
+    res = d;
+    if ((cnt = s % 32) != 0) {
+	res = (d << (32 - cnt));
+	mask = (1 << (32 - cnt)) - 1;
+	res |= (d >> (cnt)) & mask;
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+	CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
+    } else if (s != 0) {
+	/* set the new carry flag, Note that it is the low order
+	   bit of the result!!!				      */
+	CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u8 shl_byte(u8 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 8) {
+	cnt = s % 8;
+
+	/* last bit shifted out goes into carry flag */
+	if (cnt > 0) {
+	    res = d << cnt;
+	    cf = d & (1 << (8 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_8((u8)res);
+	} else {
+	    res = (u8) d;
+	}
+
+	if (cnt == 1) {
+	    /* Needs simplification. */
+	    CONDITIONAL_SET_FLAG(
+				    (((res & 0x80) == 0x80) ^
+				     (ACCESS_FLAG(F_CF) != 0)),
+	    /* was (M.x86.R_FLG&F_CF)==F_CF)), */
+				    F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u16 shl_word(u16 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 16) {
+	cnt = s % 16;
+	if (cnt > 0) {
+	    res = d << cnt;
+	    cf = d & (1 << (16 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_16((u16)res);
+	} else {
+	    res = (u16) d;
+	}
+
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(
+				    (((res & 0x8000) == 0x8000) ^
+				     (ACCESS_FLAG(F_CF) != 0)),
+				    F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHL instruction and side effects.
+****************************************************************************/
+u32 shl_long(u32 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 32) {
+	cnt = s % 32;
+	if (cnt > 0) {
+	    res = d << cnt;
+	    cf = d & (1 << (32 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_32((u32)res);
+	} else {
+	    res = d;
+	}
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
+				  (ACCESS_FLAG(F_CF) != 0)), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u8 shr_byte(u8 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 8) {
+	cnt = s % 8;
+	if (cnt > 0) {
+	    cf = d & (1 << (cnt - 1));
+	    res = d >> cnt;
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_8((u8)res);
+	} else {
+	    res = (u8) d;
+	}
+
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d >> (s-1)) & 0x1, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u16 shr_word(u16 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 16) {
+	cnt = s % 16;
+	if (cnt > 0) {
+	    cf = d & (1 << (cnt - 1));
+	    res = d >> cnt;
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_16((u16)res);
+	} else {
+	    res = d;
+	}
+
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+	SET_FLAG(F_ZF);
+	CLEAR_FLAG(F_SF);
+	CLEAR_FLAG(F_PF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHR instruction and side effects.
+****************************************************************************/
+u32 shr_long(u32 d, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 32) {
+	cnt = s % 32;
+	if (cnt > 0) {
+	    cf = d & (1 << (cnt - 1));
+	    res = d >> cnt;
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_32((u32)res);
+	} else {
+	    res = d;
+	}
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+	SET_FLAG(F_ZF);
+	CLEAR_FLAG(F_SF);
+	CLEAR_FLAG(F_PF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u8 sar_byte(u8 d, u8 s)
+{
+    unsigned int cnt, res, cf, mask, sf;
+
+    res = d;
+    sf = d & 0x80;
+    cnt = s % 8;
+    if (cnt > 0 && cnt < 8) {
+	mask = (1 << (8 - cnt)) - 1;
+	cf = d & (1 << (cnt - 1));
+	res = (d >> cnt) & mask;
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	if (sf) {
+	    res |= ~mask;
+	}
+	set_szp_flags_8((u8)res);
+    } else if (cnt >= 8) {
+	if (sf) {
+	    res = 0xff;
+	    SET_FLAG(F_CF);
+	    CLEAR_FLAG(F_ZF);
+	    SET_FLAG(F_SF);
+	    SET_FLAG(F_PF);
+	} else {
+	    res = 0;
+	    CLEAR_FLAG(F_CF);
+	    SET_FLAG(F_ZF);
+	    CLEAR_FLAG(F_SF);
+	    CLEAR_FLAG(F_PF);
+	}
+    }
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u16 sar_word(u16 d, u8 s)
+{
+    unsigned int cnt, res, cf, mask, sf;
+
+    sf = d & 0x8000;
+    cnt = s % 16;
+    res = d;
+    if (cnt > 0 && cnt < 16) {
+	mask = (1 << (16 - cnt)) - 1;
+	cf = d & (1 << (cnt - 1));
+	res = (d >> cnt) & mask;
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	if (sf) {
+	    res |= ~mask;
+	}
+	set_szp_flags_16((u16)res);
+    } else if (cnt >= 16) {
+	if (sf) {
+	    res = 0xffff;
+	    SET_FLAG(F_CF);
+	    CLEAR_FLAG(F_ZF);
+	    SET_FLAG(F_SF);
+	    SET_FLAG(F_PF);
+	} else {
+	    res = 0;
+	    CLEAR_FLAG(F_CF);
+	    SET_FLAG(F_ZF);
+	    CLEAR_FLAG(F_SF);
+	    CLEAR_FLAG(F_PF);
+	}
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SAR instruction and side effects.
+****************************************************************************/
+u32 sar_long(u32 d, u8 s)
+{
+    u32 cnt, res, cf, mask, sf;
+
+    sf = d & 0x80000000;
+    cnt = s % 32;
+    res = d;
+    if (cnt > 0 && cnt < 32) {
+	mask = (1 << (32 - cnt)) - 1;
+	cf = d & (1 << (cnt - 1));
+	res = (d >> cnt) & mask;
+	CONDITIONAL_SET_FLAG(cf, F_CF);
+	if (sf) {
+	    res |= ~mask;
+	}
+	set_szp_flags_32(res);
+    } else if (cnt >= 32) {
+	if (sf) {
+	    res = 0xffffffff;
+	    SET_FLAG(F_CF);
+	    CLEAR_FLAG(F_ZF);
+	    SET_FLAG(F_SF);
+	    SET_FLAG(F_PF);
+	} else {
+	    res = 0;
+	    CLEAR_FLAG(F_CF);
+	    SET_FLAG(F_ZF);
+	    CLEAR_FLAG(F_SF);
+	    CLEAR_FLAG(F_PF);
+	}
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHLD instruction and side effects.
+****************************************************************************/
+u16 shld_word (u16 d, u16 fill, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 16) {
+	cnt = s % 16;
+	if (cnt > 0) {
+	    res = (d << cnt) | (fill >> (16-cnt));
+	    cf = d & (1 << (16 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_16((u16)res);
+	} else {
+	    res = d;
+	}
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
+				  (ACCESS_FLAG(F_CF) != 0)), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHLD instruction and side effects.
+****************************************************************************/
+u32 shld_long (u32 d, u32 fill, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 32) {
+	cnt = s % 32;
+	if (cnt > 0) {
+	    res = (d << cnt) | (fill >> (32-cnt));
+	    cf = d & (1 << (32 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_32((u32)res);
+	} else {
+	    res = d;
+	}
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
+				  (ACCESS_FLAG(F_CF) != 0)), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CONDITIONAL_SET_FLAG((d << (s-1)) & 0x80000000, F_CF);
+	CLEAR_FLAG(F_OF);
+	CLEAR_FLAG(F_SF);
+	SET_FLAG(F_PF);
+	SET_FLAG(F_ZF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHRD instruction and side effects.
+****************************************************************************/
+u16 shrd_word (u16 d, u16 fill, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 16) {
+	cnt = s % 16;
+	if (cnt > 0) {
+	    cf = d & (1 << (cnt - 1));
+	    res = (d >> cnt) | (fill << (16 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_16((u16)res);
+	} else {
+	    res = d;
+	}
+
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+	SET_FLAG(F_ZF);
+	CLEAR_FLAG(F_SF);
+	CLEAR_FLAG(F_PF);
+    }
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SHRD instruction and side effects.
+****************************************************************************/
+u32 shrd_long (u32 d, u32 fill, u8 s)
+{
+    unsigned int cnt, res, cf;
+
+    if (s < 32) {
+	cnt = s % 32;
+	if (cnt > 0) {
+	    cf = d & (1 << (cnt - 1));
+	    res = (d >> cnt) | (fill << (32 - cnt));
+	    CONDITIONAL_SET_FLAG(cf, F_CF);
+	    set_szp_flags_32((u32)res);
+	} else {
+	    res = d;
+	}
+	if (cnt == 1) {
+	    CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
+	} else {
+	    CLEAR_FLAG(F_OF);
+	}
+    } else {
+	res = 0;
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+	SET_FLAG(F_ZF);
+	CLEAR_FLAG(F_SF);
+	CLEAR_FLAG(F_PF);
+    }
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u8 sbb_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    if (ACCESS_FLAG(F_CF))
+	res = d - s - 1;
+    else
+	res = d - s;
+    set_szp_flags_8((u8)res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u16 sbb_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    if (ACCESS_FLAG(F_CF))
+	res = d - s - 1;
+    else
+	res = d - s;
+    set_szp_flags_16((u16)res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SBB instruction and side effects.
+****************************************************************************/
+u32 sbb_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    if (ACCESS_FLAG(F_CF))
+	res = d - s - 1;
+    else
+	res = d - s;
+
+    set_szp_flags_32(res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u8 sub_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    res = d - s;
+    set_szp_flags_8((u8)res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return (u8)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u16 sub_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    res = d - s;
+    set_szp_flags_16((u16)res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return (u16)res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the SUB instruction and side effects.
+****************************************************************************/
+u32 sub_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+    u32 bc;
+
+    res = d - s;
+    set_szp_flags_32(res);
+
+    /* calculate the borrow chain.  See note at top */
+    bc = (res & (~d | s)) | (~d & s);
+    CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
+    CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
+    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_byte(u8 d, u8 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d & s;
+
+    CLEAR_FLAG(F_OF);
+    set_szp_flags_8((u8)res);
+    /* AF == dont care */
+    CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_word(u16 d, u16 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d & s;
+
+    CLEAR_FLAG(F_OF);
+    set_szp_flags_16((u16)res);
+    /* AF == dont care */
+    CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the TEST instruction and side effects.
+****************************************************************************/
+void test_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d & s;
+
+    CLEAR_FLAG(F_OF);
+    set_szp_flags_32(res);
+    /* AF == dont care */
+    CLEAR_FLAG(F_CF);
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u8 xor_byte(u8 d, u8 s)
+{
+    u8 res;    /* all operands in native machine order */
+
+    res = d ^ s;
+    no_carry_byte_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u16 xor_word(u16 d, u16 s)
+{
+    u16 res;   /* all operands in native machine order */
+
+    res = d ^ s;
+    no_carry_word_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the XOR instruction and side effects.
+****************************************************************************/
+u32 xor_long(u32 d, u32 s)
+{
+    u32 res;   /* all operands in native machine order */
+
+    res = d ^ s;
+    no_carry_long_side_eff(res);
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_byte(u8 s)
+{
+    s16 res = (s16)((s8)M.x86.R_AL * (s8)s);
+
+    M.x86.R_AX = res;
+    if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) ||
+	((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_word(u16 s)
+{
+    s32 res = (s16)M.x86.R_AX * (s16)s;
+
+    M.x86.R_AX = (u16)res;
+    M.x86.R_DX = (u16)(res >> 16);
+    if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x0000) ||
+	((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFFFF)) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s)
+{
+#ifdef	__HAS_LONG_LONG__
+    s64 res = (s32)d * (s32)s;
+
+    *res_lo = (u32)res;
+    *res_hi = (u32)(res >> 32);
+#else
+    u32 d_lo,d_hi,d_sign;
+    u32 s_lo,s_hi,s_sign;
+    u32 rlo_lo,rlo_hi,rhi_lo;
+
+    if ((d_sign = d & 0x80000000) != 0)
+	d = -d;
+    d_lo = d & 0xFFFF;
+    d_hi = d >> 16;
+    if ((s_sign = s & 0x80000000) != 0)
+	s = -s;
+    s_lo = s & 0xFFFF;
+    s_hi = s >> 16;
+    rlo_lo = d_lo * s_lo;
+    rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16);
+    rhi_lo = d_hi * s_hi + (rlo_hi >> 16);
+    *res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
+    *res_hi = rhi_lo;
+    if (d_sign != s_sign) {
+	d = ~*res_lo;
+	s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16);
+	*res_lo = ~*res_lo+1;
+	*res_hi = ~*res_hi+(s >> 16);
+	}
+#endif
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IMUL instruction and side effects.
+****************************************************************************/
+void imul_long(u32 s)
+{
+    imul_long_direct(&M.x86.R_EAX,&M.x86.R_EDX,M.x86.R_EAX,s);
+    if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00000000) ||
+	((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFFFFFFFF)) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_byte(u8 s)
+{
+    u16 res = (u16)(M.x86.R_AL * s);
+
+    M.x86.R_AX = res;
+    if (M.x86.R_AH == 0) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_word(u16 s)
+{
+    u32 res = M.x86.R_AX * s;
+
+    M.x86.R_AX = (u16)res;
+    M.x86.R_DX = (u16)(res >> 16);
+    if (M.x86.R_DX == 0) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the MUL instruction and side effects.
+****************************************************************************/
+void mul_long(u32 s)
+{
+#ifdef	__HAS_LONG_LONG__
+    u64 res = (u32)M.x86.R_EAX * (u32)s;
+
+    M.x86.R_EAX = (u32)res;
+    M.x86.R_EDX = (u32)(res >> 32);
+#else
+    u32 a,a_lo,a_hi;
+    u32 s_lo,s_hi;
+    u32 rlo_lo,rlo_hi,rhi_lo;
+
+    a = M.x86.R_EAX;
+    a_lo = a & 0xFFFF;
+    a_hi = a >> 16;
+    s_lo = s & 0xFFFF;
+    s_hi = s >> 16;
+    rlo_lo = a_lo * s_lo;
+    rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16);
+    rhi_lo = a_hi * s_hi + (rlo_hi >> 16);
+    M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
+    M.x86.R_EDX = rhi_lo;
+#endif
+    if (M.x86.R_EDX == 0) {
+	CLEAR_FLAG(F_CF);
+	CLEAR_FLAG(F_OF);
+    } else {
+	SET_FLAG(F_CF);
+	SET_FLAG(F_OF);
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_byte(u8 s)
+{
+    s32 dvd, div, mod;
+
+    dvd = (s16)M.x86.R_AX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (s8)s;
+    mod = dvd % (s8)s;
+    if (abs(div) > 0x7f) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    M.x86.R_AL = (s8) div;
+    M.x86.R_AH = (s8) mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_word(u16 s)
+{
+    s32 dvd, div, mod;
+
+    dvd = (((s32)M.x86.R_DX) << 16) | M.x86.R_AX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (s16)s;
+    mod = dvd % (s16)s;
+    if (abs(div) > 0x7fff) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_SF);
+    CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+    set_parity_flag(mod);
+
+    M.x86.R_AX = (u16)div;
+    M.x86.R_DX = (u16)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IDIV instruction and side effects.
+****************************************************************************/
+void idiv_long(u32 s)
+{
+#ifdef	__HAS_LONG_LONG__
+    s64 dvd, div, mod;
+
+    dvd = (((s64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (s32)s;
+    mod = dvd % (s32)s;
+    if (abs(div) > 0x7fffffff) {
+	x86emu_intr_raise(0);
+	return;
+    }
+#else
+    s32 div = 0, mod;
+    s32 h_dvd = M.x86.R_EDX;
+    u32 l_dvd = M.x86.R_EAX;
+    u32 abs_s = s & 0x7FFFFFFF;
+    u32 abs_h_dvd = h_dvd & 0x7FFFFFFF;
+    u32 h_s = abs_s >> 1;
+    u32 l_s = abs_s << 31;
+    int counter = 31;
+    int carry;
+
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    do {
+	div <<= 1;
+	carry = (l_dvd >= l_s) ? 0 : 1;
+
+	if (abs_h_dvd < (h_s + carry)) {
+	    h_s >>= 1;
+	    l_s = abs_s << (--counter);
+	    continue;
+	} else {
+	    abs_h_dvd -= (h_s + carry);
+	    l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
+		: (l_dvd - l_s);
+	    h_s >>= 1;
+	    l_s = abs_s << (--counter);
+	    div |= 1;
+	    continue;
+	}
+
+    } while (counter > -1);
+    /* overflow */
+    if (abs_h_dvd || (l_dvd > abs_s)) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    /* sign */
+    div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000));
+    mod = l_dvd;
+
+#endif
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_AF);
+    CLEAR_FLAG(F_SF);
+    SET_FLAG(F_ZF);
+    set_parity_flag(mod);
+
+    M.x86.R_EAX = (u32)div;
+    M.x86.R_EDX = (u32)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_byte(u8 s)
+{
+    u32 dvd, div, mod;
+
+    dvd = M.x86.R_AX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (u8)s;
+    mod = dvd % (u8)s;
+    if (abs(div) > 0xff) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    M.x86.R_AL = (u8)div;
+    M.x86.R_AH = (u8)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_word(u16 s)
+{
+    u32 dvd, div, mod;
+
+    dvd = (((u32)M.x86.R_DX) << 16) | M.x86.R_AX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (u16)s;
+    mod = dvd % (u16)s;
+    if (abs(div) > 0xffff) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_SF);
+    CONDITIONAL_SET_FLAG(div == 0, F_ZF);
+    set_parity_flag(mod);
+
+    M.x86.R_AX = (u16)div;
+    M.x86.R_DX = (u16)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the DIV instruction and side effects.
+****************************************************************************/
+void div_long(u32 s)
+{
+#ifdef	__HAS_LONG_LONG__
+    u64 dvd, div, mod;
+
+    dvd = (((u64)M.x86.R_EDX) << 32) | M.x86.R_EAX;
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    div = dvd / (u32)s;
+    mod = dvd % (u32)s;
+    if (abs(div) > 0xffffffff) {
+	x86emu_intr_raise(0);
+	return;
+    }
+#else
+    s32 div = 0, mod;
+    s32 h_dvd = M.x86.R_EDX;
+    u32 l_dvd = M.x86.R_EAX;
+
+    u32 h_s = s;
+    u32 l_s = 0;
+    int counter = 32;
+    int carry;
+
+    if (s == 0) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    do {
+	div <<= 1;
+	carry = (l_dvd >= l_s) ? 0 : 1;
+
+	if (h_dvd < (h_s + carry)) {
+	    h_s >>= 1;
+	    l_s = s << (--counter);
+	    continue;
+	} else {
+	    h_dvd -= (h_s + carry);
+	    l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
+		: (l_dvd - l_s);
+	    h_s >>= 1;
+	    l_s = s << (--counter);
+	    div |= 1;
+	    continue;
+	}
+
+    } while (counter > -1);
+    /* overflow */
+    if (h_dvd || (l_dvd > s)) {
+	x86emu_intr_raise(0);
+	return;
+    }
+    mod = l_dvd;
+#endif
+    CLEAR_FLAG(F_CF);
+    CLEAR_FLAG(F_AF);
+    CLEAR_FLAG(F_SF);
+    SET_FLAG(F_ZF);
+    set_parity_flag(mod);
+
+    M.x86.R_EAX = (u32)div;
+    M.x86.R_EDX = (u32)mod;
+}
+
+/****************************************************************************
+REMARKS:
+Implements the IN string instruction and side effects.
+****************************************************************************/
+
+static void single_in(int size)
+{
+    if(size == 1)
+	store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inb)(M.x86.R_DX));
+    else if (size == 2)
+	store_data_word_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inw)(M.x86.R_DX));
+    else
+	store_data_long_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inl)(M.x86.R_DX));
+}
+
+void ins(int size)
+{
+    int inc = size;
+
+    if (ACCESS_FLAG(F_DF)) {
+	inc = -size;
+    }
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* in until CX is ZERO. */
+	u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
+		     M.x86.R_ECX : M.x86.R_CX);
+
+	while (count--) {
+	  single_in(size);
+	  M.x86.R_DI += inc;
+	  }
+	M.x86.R_CX = 0;
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    M.x86.R_ECX = 0;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	single_in(size);
+	M.x86.R_DI += inc;
+    }
+}
+
+/****************************************************************************
+REMARKS:
+Implements the OUT string instruction and side effects.
+****************************************************************************/
+
+static void single_out(int size)
+{
+     if(size == 1)
+       (*sys_outb)(M.x86.R_DX,fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
+     else if (size == 2)
+       (*sys_outw)(M.x86.R_DX,fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
+     else
+       (*sys_outl)(M.x86.R_DX,fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
+}
+
+void outs(int size)
+{
+    int inc = size;
+
+    if (ACCESS_FLAG(F_DF)) {
+	inc = -size;
+    }
+    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
+	/* dont care whether REPE or REPNE */
+	/* out until CX is ZERO. */
+	u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
+		     M.x86.R_ECX : M.x86.R_CX);
+	while (count--) {
+	  single_out(size);
+	  M.x86.R_SI += inc;
+	  }
+	M.x86.R_CX = 0;
+	if (M.x86.mode & SYSMODE_PREFIX_DATA) {
+	    M.x86.R_ECX = 0;
+	}
+	M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
+    } else {
+	single_out(size);
+	M.x86.R_SI += inc;
+    }
+}
+
+/****************************************************************************
+PARAMETERS:
+addr	- Address to fetch word from
+
+REMARKS:
+Fetches a word from emulator memory using an absolute address.
+****************************************************************************/
+u16 mem_access_word(int addr)
+{
+DB( if (CHECK_MEM_ACCESS())
+      x86emu_check_mem_access(addr);)
+    return (*sys_rdw)(addr);
+}
+
+/****************************************************************************
+REMARKS:
+Pushes a word onto the stack.
+
+NOTE: Do not inline this, as (*sys_wrX) is already inline!
+****************************************************************************/
+void push_word(u16 w)
+{
+DB( if (CHECK_SP_ACCESS())
+      x86emu_check_sp_access();)
+    M.x86.R_SP -= 2;
+    (*sys_wrw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w);
+}
+
+/****************************************************************************
+REMARKS:
+Pushes a long onto the stack.
+
+NOTE: Do not inline this, as (*sys_wrX) is already inline!
+****************************************************************************/
+void push_long(u32 w)
+{
+DB( if (CHECK_SP_ACCESS())
+      x86emu_check_sp_access();)
+    M.x86.R_SP -= 4;
+    (*sys_wrl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP, w);
+}
+
+/****************************************************************************
+REMARKS:
+Pops a word from the stack.
+
+NOTE: Do not inline this, as (*sys_rdX) is already inline!
+****************************************************************************/
+u16 pop_word(void)
+{
+    u16 res;
+
+DB( if (CHECK_SP_ACCESS())
+      x86emu_check_sp_access();)
+    res = (*sys_rdw)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP);
+    M.x86.R_SP += 2;
+    return res;
+}
+
+/****************************************************************************
+REMARKS:
+Pops a long from the stack.
+
+NOTE: Do not inline this, as (*sys_rdX) is already inline!
+****************************************************************************/
+u32 pop_long(void)
+{
+    u32 res;
+
+DB( if (CHECK_SP_ACCESS())
+      x86emu_check_sp_access();)
+    res = (*sys_rdl)(((u32)M.x86.R_SS << 4)  + M.x86.R_SP);
+    M.x86.R_SP += 4;
+    return res;
+}
+
+#endif
diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c
new file mode 100644
index 0000000..566389f
--- /dev/null
+++ b/drivers/bios_emulator/x86emu/sys.c
@@ -0,0 +1,326 @@
+/****************************************************************************
+*
+*                       Realmode X86 Emulator Library
+*
+*               Copyright (C) 1991-2004 SciTech Software, Inc.
+*                    Copyright (C) David Mosberger-Tang
+*                      Copyright (C) 1999 Egbert Eich
+*
+*  ========================================================================
+*
+*  Permission to use, copy, modify, distribute, and sell this software and
+*  its documentation for any purpose is hereby granted without fee,
+*  provided that the above copyright notice appear in all copies and that
+*  both that copyright notice and this permission notice appear in
+*  supporting documentation, and that the name of the authors not be used
+*  in advertising or publicity pertaining to distribution of the software
+*  without specific, written prior permission.  The authors makes no
+*  representations about the suitability of this software for any purpose.
+*  It is provided "as is" without express or implied warranty.
+*
+*  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+*  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+*  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+*  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+*  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+*  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+*  PERFORMANCE OF THIS SOFTWARE.
+*
+*  ========================================================================
+*
+* Language:     ANSI C
+* Environment:  Any
+* Developer:    Kendall Bennett
+*
+* Description:  This file includes subroutines which are related to
+*               programmed I/O and memory access. Included in this module
+*               are default functions that do nothing. For real uses these
+*               functions will have to be overriden by the user library.
+*
+****************************************************************************/
+
+#include "x86emu/x86emui.h"
+
+#if defined(CONFIG_BIOSEMU)
+
+/*------------------------- Global Variables ------------------------------*/
+
+X86EMU_sysEnv _X86EMU_env;	/* Global emulator machine state */
+X86EMU_intrFuncs _X86EMU_intrTab[256];
+
+int debug_intr;
+
+/*----------------------------- Implementation ----------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Byte value read from emulator memory.
+
+REMARKS:
+Reads a byte value from the emulator memory.
+****************************************************************************/
+u8 X86API rdb(u32 addr)
+{
+	return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Word value read from emulator memory.
+
+REMARKS:
+Reads a word value from the emulator memory.
+****************************************************************************/
+u16 X86API rdw(u32 addr)
+{
+	return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+
+RETURNS:
+Long value read from emulator memory.
+REMARKS:
+Reads a long value from the emulator memory.
+****************************************************************************/
+u32 X86API rdl(u32 addr)
+{
+	return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a byte value to emulator memory.
+****************************************************************************/
+void X86API wrb(u32 addr, u8 val)
+{
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a word value to emulator memory.
+****************************************************************************/
+void X86API wrw(u32 addr, u16 val)
+{
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - Emulator memory address to read
+val     - Value to store
+
+REMARKS:
+Writes a long value to emulator memory.
+****************************************************************************/
+void X86API wrl(u32 addr, u32 val)
+{
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO byte read function. Doesn't perform real inb.
+****************************************************************************/
+static u8 X86API p_inb(X86EMU_pioAddr addr)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("inb %#04x \n", addr);)
+		return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO word read function. Doesn't perform real inw.
+****************************************************************************/
+static u16 X86API p_inw(X86EMU_pioAddr addr)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("inw %#04x \n", addr);)
+		return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to read
+RETURN:
+0
+REMARKS:
+Default PIO long read function. Doesn't perform real inl.
+****************************************************************************/
+static u32 X86API p_inl(X86EMU_pioAddr addr)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("inl %#04x \n", addr);)
+		return 0;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to write
+val     - Value to store
+REMARKS:
+Default PIO byte write function. Doesn't perform real outb.
+****************************************************************************/
+static void X86API p_outb(X86EMU_pioAddr addr, u8 val)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("outb %#02x -> %#04x \n", val, addr);)
+		return;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to write
+val     - Value to store
+REMARKS:
+Default PIO word write function. Doesn't perform real outw.
+****************************************************************************/
+static void X86API p_outw(X86EMU_pioAddr addr, u16 val)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("outw %#04x -> %#04x \n", val, addr);)
+		return;
+}
+
+/****************************************************************************
+PARAMETERS:
+addr    - PIO address to write
+val     - Value to store
+REMARKS:
+Default PIO ;ong write function. Doesn't perform real outl.
+****************************************************************************/
+static void X86API p_outl(X86EMU_pioAddr addr, u32 val)
+{
+	DB(if (DEBUG_IO_TRACE())
+	   printk("outl %#08x -> %#04x \n", val, addr);)
+		return;
+}
+
+/*------------------------- Global Variables ------------------------------*/
+
+u8(X86APIP sys_rdb) (u32 addr) = rdb;
+u16(X86APIP sys_rdw) (u32 addr) = rdw;
+u32(X86APIP sys_rdl) (u32 addr) = rdl;
+void (X86APIP sys_wrb) (u32 addr, u8 val) = wrb;
+void (X86APIP sys_wrw) (u32 addr, u16 val) = wrw;
+void (X86APIP sys_wrl) (u32 addr, u32 val) = wrl;
+u8(X86APIP sys_inb) (X86EMU_pioAddr addr) = p_inb;
+u16(X86APIP sys_inw) (X86EMU_pioAddr addr) = p_inw;
+u32(X86APIP sys_inl) (X86EMU_pioAddr addr) = p_inl;
+void (X86APIP sys_outb) (X86EMU_pioAddr addr, u8 val) = p_outb;
+void (X86APIP sys_outw) (X86EMU_pioAddr addr, u16 val) = p_outw;
+void (X86APIP sys_outl) (X86EMU_pioAddr addr, u32 val) = p_outl;
+
+/*----------------------------- Setup -------------------------------------*/
+
+/****************************************************************************
+PARAMETERS:
+funcs   - New memory function pointers to make active
+
+REMARKS:
+This function is used to set the pointers to functions which access
+memory space, allowing the user application to override these functions
+and hook them out as necessary for their application.
+****************************************************************************/
+void X86EMU_setupMemFuncs(X86EMU_memFuncs * funcs)
+{
+	sys_rdb = funcs->rdb;
+	sys_rdw = funcs->rdw;
+	sys_rdl = funcs->rdl;
+	sys_wrb = funcs->wrb;
+	sys_wrw = funcs->wrw;
+	sys_wrl = funcs->wrl;
+}
+
+/****************************************************************************
+PARAMETERS:
+funcs   - New programmed I/O function pointers to make active
+
+REMARKS:
+This function is used to set the pointers to functions which access
+I/O space, allowing the user application to override these functions
+and hook them out as necessary for their application.
+****************************************************************************/
+void X86EMU_setupPioFuncs(X86EMU_pioFuncs * funcs)
+{
+	sys_inb = funcs->inb;
+	sys_inw = funcs->inw;
+	sys_inl = funcs->inl;
+	sys_outb = funcs->outb;
+	sys_outw = funcs->outw;
+	sys_outl = funcs->outl;
+}
+
+/****************************************************************************
+PARAMETERS:
+funcs   - New interrupt vector table to make active
+
+REMARKS:
+This function is used to set the pointers to functions which handle
+interrupt processing in the emulator, allowing the user application to
+hook interrupts as necessary for their application. Any interrupts that
+are not hooked by the user application, and reflected and handled internally
+in the emulator via the interrupt vector table. This allows the application
+to get control when the code being emulated executes specific software
+interrupts.
+****************************************************************************/
+void X86EMU_setupIntrFuncs(X86EMU_intrFuncs funcs[])
+{
+	int i;
+
+	for (i = 0; i < 256; i++)
+		_X86EMU_intrTab[i] = NULL;
+	if (funcs) {
+		for (i = 0; i < 256; i++)
+			_X86EMU_intrTab[i] = funcs[i];
+	}
+}
+
+/****************************************************************************
+PARAMETERS:
+int - New software interrupt to prepare for
+
+REMARKS:
+This function is used to set up the emulator state to exceute a software
+interrupt. This can be used by the user application code to allow an
+interrupt to be hooked, examined and then reflected back to the emulator
+so that the code in the emulator will continue processing the software
+interrupt as per normal. This essentially allows system code to actively
+hook and handle certain software interrupts as necessary.
+****************************************************************************/
+void X86EMU_prepareForInt(int num)
+{
+	push_word((u16) M.x86.R_FLG);
+	CLEAR_FLAG(F_IF);
+	CLEAR_FLAG(F_TF);
+	push_word(M.x86.R_CS);
+	M.x86.R_CS = mem_access_word(num * 4 + 2);
+	push_word(M.x86.R_IP);
+	M.x86.R_IP = mem_access_word(num * 4);
+	M.x86.intr = 0;
+}
+
+#endif
diff --git a/drivers/cfb_console.c b/drivers/cfb_console.c
index 9727aeb..bcf8771 100644
--- a/drivers/cfb_console.c
+++ b/drivers/cfb_console.c
@@ -63,7 +63,7 @@
 			       loop in VIDEO_TSTC_FCT (i8042)
  CFG_CONSOLE_BLINK_COUNT     - value for delay loop - blink rate
  CONFIG_CONSOLE_TIME	     - display time/date in upper right corner,
-			       needs CFG_CMD_DATE and CONFIG_CONSOLE_CURSOR
+			       needs CONFIG_CMD_DATE and CONFIG_CONSOLE_CURSOR
  CONFIG_VIDEO_LOGO	     - display Linux Logo in upper left corner
  CONFIG_VIDEO_BMP_LOGO	     - use bmp_logo instead of linux_logo
  CONFIG_CONSOLE_EXTRA_INFO   - display additional board information strings
@@ -175,15 +175,15 @@
 #include <linux/types.h>
 #include <devices.h>
 #include <video_font.h>
-#ifdef CFG_CMD_DATE
-#include <rtc.h>
 
+#if defined(CONFIG_CMD_DATE)
+#include <rtc.h>
 #endif
 
-#if (CONFIG_COMMANDS & CFG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
+#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
 #include <watchdog.h>
 #include <bmp_layout.h>
-#endif /* (CONFIG_COMMANDS & CFG_CMD_BMP) || CONFIG_SPLASH_SCREEN */
+#endif
 
 /*****************************************************************************/
 /* Cursor definition:							     */
@@ -709,7 +709,7 @@
 
 /*****************************************************************************/
 
-#if (CONFIG_COMMANDS & CFG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
+#if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN)
 
 #define FILL_8BIT_332RGB(r,g,b)	{			\
 	*fb = ((r>>5)<<5) | ((g>>5)<<2) | (b>>6);	\
@@ -1004,7 +1004,7 @@
 
 	return (0);
 }
-#endif /* (CONFIG_COMMANDS & CFG_CMD_BMP) || CONFIG_SPLASH_SCREEN */
+#endif
 
 /*****************************************************************************/
 
diff --git a/drivers/cs8900.c b/drivers/cs8900.c
index 082434c..80c4ba2 100644
--- a/drivers/cs8900.c
+++ b/drivers/cs8900.c
@@ -43,7 +43,7 @@
 
 #ifdef CONFIG_DRIVER_CS8900
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_CMD_NET)
 
 #undef DEBUG
 
diff --git a/drivers/dc2114x.c b/drivers/dc2114x.c
index c43cd5e..d5275dc 100644
--- a/drivers/dc2114x.c
+++ b/drivers/dc2114x.c
@@ -20,8 +20,8 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
-	&& defined(CONFIG_TULIP)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_TULIP)
 
 #include <malloc.h>
 #include <net.h>
@@ -768,4 +768,4 @@
 }
 #endif	/* UPDATE_SROM */
 
-#endif	/* CFG_CMD_NET && CONFIG_NET_MULTI && CONFIG_TULIP */
+#endif
diff --git a/drivers/e1000.c b/drivers/e1000.c
index 927acbb..f0741da 100644
--- a/drivers/e1000.c
+++ b/drivers/e1000.c
@@ -44,8 +44,8 @@
 
 #include "e1000.h"
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
-	defined(CONFIG_E1000)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_E1000)
 
 #define TOUT_LOOP   100000
 
diff --git a/drivers/eepro100.c b/drivers/eepro100.c
index 04c17f6..738146e 100644
--- a/drivers/eepro100.c
+++ b/drivers/eepro100.c
@@ -30,8 +30,8 @@
 
 #undef DEBUG
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
-	defined(CONFIG_EEPRO100)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_EEPRO100)
 
 	/* Ethernet chip registers.
 	 */
@@ -272,7 +272,7 @@
 	*(volatile u32 *) ((addr + dev->iobase)) = cpu_to_le32 (command);
 }
 
-#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 static inline int INL (struct eth_device *dev, u_long addr)
 {
 	return le32_to_cpu (*(volatile u32 *) (addr + dev->iobase));
@@ -386,7 +386,7 @@
 	return 0;
 }
 
-#endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) */
+#endif
 
 /* Wait for the chip get the command.
 */
@@ -462,7 +462,7 @@
 
 		eth_register (dev);
 
-#if defined (CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+#if defined (CONFIG_MII) || defined(CONFIG_CMD_MII)
 		/* register mii command access routines */
 		miiphy_register(dev->name,
 				eepro100_miiphy_read, eepro100_miiphy_write);
diff --git a/drivers/enc28j60.c b/drivers/enc28j60.c
new file mode 100644
index 0000000..98303ac
--- /dev/null
+++ b/drivers/enc28j60.c
@@ -0,0 +1,983 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#ifdef CONFIG_ENC28J60
+#include <net.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/spi.h>
+
+/*
+ * Control Registers in Bank 0
+ */
+
+#define CTL_REG_ERDPTL	 0x00
+#define CTL_REG_ERDPTH	 0x01
+#define CTL_REG_EWRPTL	 0x02
+#define CTL_REG_EWRPTH	 0x03
+#define CTL_REG_ETXSTL	 0x04
+#define CTL_REG_ETXSTH	 0x05
+#define CTL_REG_ETXNDL	 0x06
+#define CTL_REG_ETXNDH	 0x07
+#define CTL_REG_ERXSTL	 0x08
+#define CTL_REG_ERXSTH	 0x09
+#define CTL_REG_ERXNDL	 0x0A
+#define CTL_REG_ERXNDH	 0x0B
+#define CTL_REG_ERXRDPTL 0x0C
+#define CTL_REG_ERXRDPTH 0x0D
+#define CTL_REG_ERXWRPTL 0x0E
+#define CTL_REG_ERXWRPTH 0x0F
+#define CTL_REG_EDMASTL  0x10
+#define CTL_REG_EDMASTH  0x11
+#define CTL_REG_EDMANDL  0x12
+#define CTL_REG_EDMANDH  0x13
+#define CTL_REG_EDMADSTL 0x14
+#define CTL_REG_EDMADSTH 0x15
+#define CTL_REG_EDMACSL  0x16
+#define CTL_REG_EDMACSH  0x17
+/* these are common in all banks */
+#define CTL_REG_EIE	 0x1B
+#define CTL_REG_EIR	 0x1C
+#define CTL_REG_ESTAT	 0x1D
+#define CTL_REG_ECON2	 0x1E
+#define CTL_REG_ECON1	 0x1F
+
+/*
+ * Control Registers in Bank 1
+ */
+
+#define CTL_REG_EHT0	0x00
+#define CTL_REG_EHT1	0x01
+#define CTL_REG_EHT2	0x02
+#define CTL_REG_EHT3	0x03
+#define CTL_REG_EHT4	0x04
+#define CTL_REG_EHT5	0x05
+#define CTL_REG_EHT6	0x06
+#define CTL_REG_EHT7	0x07
+#define CTL_REG_EPMM0	0x08
+#define CTL_REG_EPMM1	0x09
+#define CTL_REG_EPMM2	0x0A
+#define CTL_REG_EPMM3	0x0B
+#define CTL_REG_EPMM4	0x0C
+#define CTL_REG_EPMM5	0x0D
+#define CTL_REG_EPMM6	0x0E
+#define CTL_REG_EPMM7	0x0F
+#define CTL_REG_EPMCSL	0x10
+#define CTL_REG_EPMCSH	0x11
+#define CTL_REG_EPMOL	0x14
+#define CTL_REG_EPMOH	0x15
+#define CTL_REG_EWOLIE	0x16
+#define CTL_REG_EWOLIR	0x17
+#define CTL_REG_ERXFCON 0x18
+#define CTL_REG_EPKTCNT 0x19
+
+/*
+ * Control Registers in Bank 2
+ */
+
+#define CTL_REG_MACON1	 0x00
+#define CTL_REG_MACON2	 0x01
+#define CTL_REG_MACON3	 0x02
+#define CTL_REG_MACON4	 0x03
+#define CTL_REG_MABBIPG  0x04
+#define CTL_REG_MAIPGL	 0x06
+#define CTL_REG_MAIPGH	 0x07
+#define CTL_REG_MACLCON1 0x08
+#define CTL_REG_MACLCON2 0x09
+#define CTL_REG_MAMXFLL  0x0A
+#define CTL_REG_MAMXFLH  0x0B
+#define CTL_REG_MAPHSUP  0x0D
+#define CTL_REG_MICON	 0x11
+#define CTL_REG_MICMD	 0x12
+#define CTL_REG_MIREGADR 0x14
+#define CTL_REG_MIWRL	 0x16
+#define CTL_REG_MIWRH	 0x17
+#define CTL_REG_MIRDL	 0x18
+#define CTL_REG_MIRDH	 0x19
+
+/*
+ * Control Registers in Bank 3
+ */
+
+#define CTL_REG_MAADR1	0x00
+#define CTL_REG_MAADR0	0x01
+#define CTL_REG_MAADR3	0x02
+#define CTL_REG_MAADR2	0x03
+#define CTL_REG_MAADR5	0x04
+#define CTL_REG_MAADR4	0x05
+#define CTL_REG_EBSTSD	0x06
+#define CTL_REG_EBSTCON 0x07
+#define CTL_REG_EBSTCSL 0x08
+#define CTL_REG_EBSTCSH 0x09
+#define CTL_REG_MISTAT	0x0A
+#define CTL_REG_EREVID	0x12
+#define CTL_REG_ECOCON	0x15
+#define CTL_REG_EFLOCON 0x17
+#define CTL_REG_EPAUSL	0x18
+#define CTL_REG_EPAUSH	0x19
+
+
+/*
+ * PHY Register
+ */
+
+#define PHY_REG_PHID1 0x02
+#define PHY_REG_PHID2 0x03
+/* taken from the Linux driver */
+#define PHY_REG_PHCON1 0x00
+#define PHY_REG_PHCON2 0x10
+#define PHY_REG_PHLCON 0x14
+
+/*
+ * Receive Filter Register (ERXFCON) bits
+ */
+
+#define ENC_RFR_UCEN  0x80
+#define ENC_RFR_ANDOR 0x40
+#define ENC_RFR_CRCEN 0x20
+#define ENC_RFR_PMEN  0x10
+#define ENC_RFR_MPEN  0x08
+#define ENC_RFR_HTEN  0x04
+#define ENC_RFR_MCEN  0x02
+#define ENC_RFR_BCEN  0x01
+
+/*
+ * ECON1 Register Bits
+ */
+
+#define ENC_ECON1_TXRST  0x80
+#define ENC_ECON1_RXRST  0x40
+#define ENC_ECON1_DMAST  0x20
+#define ENC_ECON1_CSUMEN 0x10
+#define ENC_ECON1_TXRTS  0x08
+#define ENC_ECON1_RXEN	 0x04
+#define ENC_ECON1_BSEL1  0x02
+#define ENC_ECON1_BSEL0  0x01
+
+/*
+ * ECON2 Register Bits
+ */
+#define ENC_ECON2_AUTOINC 0x80
+#define ENC_ECON2_PKTDEC  0x40
+#define ENC_ECON2_PWRSV   0x20
+#define ENC_ECON2_VRPS	  0x08
+
+/*
+ * EIR Register Bits
+ */
+#define ENC_EIR_PKTIF  0x40
+#define ENC_EIR_DMAIF  0x20
+#define ENC_EIR_LINKIF 0x10
+#define ENC_EIR_TXIF   0x08
+#define ENC_EIR_WOLIF  0x04
+#define ENC_EIR_TXERIF 0x02
+#define ENC_EIR_RXERIF 0x01
+
+/*
+ * ESTAT Register Bits
+ */
+
+#define ENC_ESTAT_INT	  0x80
+#define ENC_ESTAT_LATECOL 0x10
+#define ENC_ESTAT_RXBUSY  0x04
+#define ENC_ESTAT_TXABRT  0x02
+#define ENC_ESTAT_CLKRDY  0x01
+
+/*
+ * EIE Register Bits
+ */
+
+#define ENC_EIE_INTIE  0x80
+#define ENC_EIE_PKTIE  0x40
+#define ENC_EIE_DMAIE  0x20
+#define ENC_EIE_LINKIE 0x10
+#define ENC_EIE_TXIE   0x08
+#define ENC_EIE_WOLIE  0x04
+#define ENC_EIE_TXERIE 0x02
+#define ENC_EIE_RXERIE 0x01
+
+/*
+ * MACON1 Register Bits
+ */
+#define ENC_MACON1_LOOPBK  0x10
+#define ENC_MACON1_TXPAUS  0x08
+#define ENC_MACON1_RXPAUS  0x04
+#define ENC_MACON1_PASSALL 0x02
+#define ENC_MACON1_MARXEN  0x01
+
+
+/*
+ * MACON2 Register Bits
+ */
+#define ENC_MACON2_MARST   0x80
+#define ENC_MACON2_RNDRST  0x40
+#define ENC_MACON2_MARXRST 0x08
+#define ENC_MACON2_RFUNRST 0x04
+#define ENC_MACON2_MATXRST 0x02
+#define ENC_MACON2_TFUNRST 0x01
+
+/*
+ * MACON3 Register Bits
+ */
+#define ENC_MACON3_PADCFG2 0x80
+#define ENC_MACON3_PADCFG1 0x40
+#define ENC_MACON3_PADCFG0 0x20
+#define ENC_MACON3_TXCRCEN 0x10
+#define ENC_MACON3_PHDRLEN 0x08
+#define ENC_MACON3_HFRMEN  0x04
+#define ENC_MACON3_FRMLNEN 0x02
+#define ENC_MACON3_FULDPX  0x01
+
+/*
+ * MICMD Register Bits
+ */
+#define ENC_MICMD_MIISCAN 0x02
+#define ENC_MICMD_MIIRD   0x01
+
+/*
+ * MISTAT Register Bits
+ */
+#define ENC_MISTAT_NVALID 0x04
+#define ENC_MISTAT_SCAN   0x02
+#define ENC_MISTAT_BUSY   0x01
+
+/*
+ * PHID1 and PHID2 values
+ */
+#define ENC_PHID1_VALUE 0x0083
+#define ENC_PHID2_VALUE 0x1400
+#define ENC_PHID2_MASK	0xFC00
+
+
+#define ENC_SPI_SLAVE_CS 0x00010000	/* pin P1.16 */
+#define ENC_RESET	 0x00020000	/* pin P1.17 */
+
+#define FAILSAFE_VALUE 5000
+
+/*
+ * Controller memory layout:
+ *
+ * 0x0000 - 0x17ff  6k bytes receive buffer
+ * 0x1800 - 0x1fff  2k bytes transmit buffer
+ */
+/* Use the lower memory for receiver buffer. See errata pt. 5 */
+#define ENC_RX_BUF_START 0x0000
+#define ENC_TX_BUF_START 0x1800
+/* taken from the Linux driver */
+#define ENC_RX_BUF_END   0x17ff
+#define ENC_TX_BUF_END   0x1fff
+
+/* maximum frame length */
+#define ENC_MAX_FRM_LEN 1518
+
+#define enc_enable() PUT32(IO1CLR, ENC_SPI_SLAVE_CS)
+#define enc_disable() PUT32(IO1SET, ENC_SPI_SLAVE_CS)
+#define enc_cfg_spi() spi_set_cfg(0, 0, 0); spi_set_clock(8);
+
+
+static unsigned char encReadReg (unsigned char regNo);
+static void encWriteReg (unsigned char regNo, unsigned char data);
+static void encWriteRegRetry (unsigned char regNo, unsigned char data, int c);
+static void encReadBuff (unsigned short length, unsigned char *pBuff);
+static void encWriteBuff (unsigned short length, unsigned char *pBuff);
+static void encBitSet (unsigned char regNo, unsigned char data);
+static void encBitClr (unsigned char regNo, unsigned char data);
+static void encReset (void);
+static void encInit (unsigned char *pEthAddr);
+static unsigned short phyRead (unsigned char addr);
+static void phyWrite(unsigned char, unsigned short);
+static void encPoll (void);
+static void encRx (void);
+
+#define m_nic_read(reg) encReadReg(reg)
+#define m_nic_write(reg, data) encWriteReg(reg, data)
+#define m_nic_write_retry(reg, data, count) encWriteRegRetry(reg, data, count)
+#define m_nic_read_data(len, buf) encReadBuff((len), (buf))
+#define m_nic_write_data(len, buf) encWriteBuff((len), (buf))
+
+/* bit field set */
+#define m_nic_bfs(reg, data) encBitSet(reg, data)
+
+/* bit field clear */
+#define m_nic_bfc(reg, data) encBitClr(reg, data)
+
+static unsigned char bank = 0;	/* current bank in enc28j60 */
+static unsigned char next_pointer_lsb;
+static unsigned char next_pointer_msb;
+
+static unsigned char buffer[ENC_MAX_FRM_LEN];
+static int rxResetCounter = 0;
+
+#define RX_RESET_COUNTER 1000;
+
+/*-----------------------------------------------------------------------------
+ * Always returns 0
+ */
+int eth_init (bd_t * bis)
+{
+	unsigned char estatVal;
+
+	/* configure GPIO */
+	(*((volatile unsigned long *) IO1DIR)) |= ENC_SPI_SLAVE_CS;
+	(*((volatile unsigned long *) IO1DIR)) |= ENC_RESET;
+
+	/* CS and RESET active low */
+	PUT32 (IO1SET, ENC_SPI_SLAVE_CS);
+	PUT32 (IO1SET, ENC_RESET);
+
+	spi_init ();
+
+	/* taken from the Linux driver - dangerous stuff here! */
+	/* Wait for CLKRDY to become set (i.e., check that we can communicate with
+	   the ENC) */
+	do
+	{
+		estatVal = m_nic_read(CTL_REG_ESTAT);
+	} while ((estatVal & 0x08) || (~estatVal & ENC_ESTAT_CLKRDY));
+
+	/* initialize controller */
+	encReset ();
+	encInit (bis->bi_enetaddr);
+
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+
+	return 0;
+}
+
+int eth_send (volatile void *packet, int length)
+{
+	/* check frame length, etc. */
+	/* TODO: */
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	/* set EWRPT */
+	m_nic_write (CTL_REG_EWRPTL, (ENC_TX_BUF_START & 0xff));
+	m_nic_write (CTL_REG_EWRPTH, (ENC_TX_BUF_START >> 8));
+
+	/* set ETXND */
+	m_nic_write (CTL_REG_ETXNDL, (length + ENC_TX_BUF_START) & 0xFF);
+	m_nic_write (CTL_REG_ETXNDH, (length + ENC_TX_BUF_START) >> 8);
+
+	/* set ETXST */
+	m_nic_write (CTL_REG_ETXSTL, ENC_TX_BUF_START & 0xFF);
+	m_nic_write (CTL_REG_ETXSTH, ENC_TX_BUF_START >> 8);
+
+	/* write packet */
+	m_nic_write_data (length, (unsigned char *) packet);
+
+	/* taken from the Linux driver */
+	/* Verify that the internal transmit logic has not been altered by excessive
+	   collisions.  See Errata B4 12 and 14.
+	 */
+	if (m_nic_read(CTL_REG_EIR) & ENC_EIR_TXERIF) {
+		m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_TXRST);
+		m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_TXRST);
+	}
+	m_nic_bfc(CTL_REG_EIR, (ENC_EIR_TXERIF | ENC_EIR_TXIF));
+
+	/* set ECON1.TXRTS */
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_TXRTS);
+
+	return 0;
+}
+
+
+/*****************************************************************************
+ * This function resets the receiver only. This function may be called from
+ * interrupt-context.
+ */
+static void encReceiverReset (void)
+{
+	unsigned char econ1;
+
+	econ1 = m_nic_read (CTL_REG_ECON1);
+	if ((econ1 & ENC_ECON1_RXRST) == 0) {
+		m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXRST);
+		rxResetCounter = RX_RESET_COUNTER;
+	}
+}
+
+/*****************************************************************************
+ * receiver reset timer
+ */
+static void encReceiverResetCallback (void)
+{
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_RXRST);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* enable receive */
+}
+
+/*-----------------------------------------------------------------------------
+ * Check for received packets. Call NetReceive for each packet. The return
+ * value is ignored by the caller.
+ */
+int eth_rx (void)
+{
+	if (rxResetCounter > 0 && --rxResetCounter == 0) {
+		encReceiverResetCallback ();
+	}
+
+	encPoll ();
+
+	return 0;
+}
+
+void eth_halt (void)
+{
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_RXEN);	/* disable receive */
+}
+
+/*****************************************************************************/
+
+static void encPoll (void)
+{
+	unsigned char eir_reg;
+	volatile unsigned char estat_reg;
+	unsigned char pkt_cnt;
+
+#ifdef CONFIG_USE_IRQ
+	/* clear global interrupt enable bit in enc28j60 */
+	m_nic_bfc (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+	estat_reg = m_nic_read (CTL_REG_ESTAT);
+
+	eir_reg = m_nic_read (CTL_REG_EIR);
+
+	if (eir_reg & ENC_EIR_TXIF) {
+		/* clear TXIF bit in EIR */
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_TXIF);
+	}
+
+	/* We have to use pktcnt and not pktif bit, see errata pt. 6 */
+
+	/* move to bank 1 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+	/* read pktcnt */
+	pkt_cnt = m_nic_read (CTL_REG_EPKTCNT);
+
+	if (pkt_cnt > 0) {
+		if ((eir_reg & ENC_EIR_PKTIF) == 0) {
+			/*printf("encPoll: pkt cnt > 0, but pktif not set\n"); */
+		}
+		encRx ();
+		/* clear PKTIF bit in EIR, this should not need to be done but it
+		   seems like we get problems if we do not */
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_PKTIF);
+	}
+
+	if (eir_reg & ENC_EIR_RXERIF) {
+		printf ("encPoll: rx error\n");
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_RXERIF);
+	}
+	if (eir_reg & ENC_EIR_TXERIF) {
+		printf ("encPoll: tx error\n");
+		m_nic_bfc (CTL_REG_EIR, ENC_EIR_TXERIF);
+	}
+
+#ifdef CONFIG_USE_IRQ
+	/* set global interrupt enable bit in enc28j60 */
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+static void encRx (void)
+{
+	unsigned short pkt_len;
+	unsigned short copy_len;
+	unsigned short status;
+	unsigned char eir_reg;
+	unsigned char pkt_cnt = 0;
+	unsigned short rxbuf_rdpt;
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	m_nic_write (CTL_REG_ERDPTL, next_pointer_lsb);
+	m_nic_write (CTL_REG_ERDPTH, next_pointer_msb);
+
+	do {
+		m_nic_read_data (6, buffer);
+		next_pointer_lsb = buffer[0];
+		next_pointer_msb = buffer[1];
+		pkt_len = buffer[2];
+		pkt_len |= (unsigned short) buffer[3] << 8;
+		status = buffer[4];
+		status |= (unsigned short) buffer[5] << 8;
+
+		if (pkt_len <= ENC_MAX_FRM_LEN)
+			copy_len = pkt_len;
+		else
+			copy_len = 0;
+
+		if ((status & (1L << 7)) == 0) /* check Received Ok bit */
+			copy_len = 0;
+
+		/* taken from the Linux driver */
+		/* check if next pointer is resonable */
+		if ((((unsigned int)next_pointer_msb << 8) |
+			(unsigned int)next_pointer_lsb) >= ENC_TX_BUF_START)
+			copy_len = 0;
+
+		if (copy_len > 0) {
+			m_nic_read_data (copy_len, buffer);
+		}
+
+		/* advance read pointer to next pointer */
+		m_nic_write (CTL_REG_ERDPTL, next_pointer_lsb);
+		m_nic_write (CTL_REG_ERDPTH, next_pointer_msb);
+
+		/* decrease packet counter */
+		m_nic_bfs (CTL_REG_ECON2, ENC_ECON2_PKTDEC);
+
+		/* taken from the Linux driver */
+		/* Only odd values should be written to ERXRDPTL,
+		 * see errata B4 pt.13
+		 */
+		rxbuf_rdpt = (next_pointer_msb << 8 | next_pointer_lsb) - 1;
+		if ((rxbuf_rdpt < (m_nic_read(CTL_REG_ERXSTH) << 8 |
+				m_nic_read(CTL_REG_ERXSTL))) || (rxbuf_rdpt >
+				(m_nic_read(CTL_REG_ERXNDH) << 8 |
+				m_nic_read(CTL_REG_ERXNDL)))) {
+			m_nic_write(CTL_REG_ERXRDPTL, m_nic_read(CTL_REG_ERXNDL));
+			m_nic_write(CTL_REG_ERXRDPTH, m_nic_read(CTL_REG_ERXNDH));
+		} else {
+			m_nic_write(CTL_REG_ERXRDPTL, rxbuf_rdpt & 0xFF);
+			m_nic_write(CTL_REG_ERXRDPTH, rxbuf_rdpt >> 8);
+		}
+
+		/* move to bank 1 */
+		m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+		m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+
+		/* read pktcnt */
+		pkt_cnt = m_nic_read (CTL_REG_EPKTCNT);
+
+		/* switch to bank 0 */
+		m_nic_bfc (CTL_REG_ECON1,
+			   (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+		if (copy_len == 0) {
+			eir_reg = m_nic_read (CTL_REG_EIR);
+			encReceiverReset ();
+			printf ("eth_rx: copy_len=0\n");
+			continue;
+		}
+
+		NetReceive ((unsigned char *) buffer, pkt_len);
+
+		eir_reg = m_nic_read (CTL_REG_EIR);
+	} while (pkt_cnt);	/* Use EPKTCNT not EIR.PKTIF flag, see errata pt. 6 */
+}
+
+static void encWriteReg (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x40 | regNo);	/* write in regNo */
+	spi_write (data);
+
+	enc_disable ();
+	enc_enable ();
+
+	spi_write (0x1f);	/* write reg 0x1f */
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encWriteRegRetry (unsigned char regNo, unsigned char data, int c)
+{
+	unsigned char readback;
+	int i;
+
+	spi_lock ();
+
+	for (i = 0; i < c; i++) {
+		enc_cfg_spi ();
+		enc_enable ();
+
+		spi_write (0x40 | regNo);	/* write in regNo */
+		spi_write (data);
+
+		enc_disable ();
+		enc_enable ();
+
+		spi_write (0x1f);	/* write reg 0x1f */
+
+		enc_disable ();
+
+		spi_unlock ();	/* we must unlock spi first */
+
+		readback = encReadReg (regNo);
+
+		spi_lock ();
+
+		if (readback == data)
+			break;
+	}
+	spi_unlock ();
+
+	if (i == c) {
+		printf ("enc28j60: write reg %d failed\n", regNo);
+	}
+}
+
+static unsigned char encReadReg (unsigned char regNo)
+{
+	unsigned char rxByte;
+
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x1f);	/* read reg 0x1f */
+
+	bank = spi_read () & 0x3;
+
+	enc_disable ();
+	enc_enable ();
+
+	spi_write (regNo);
+	rxByte = spi_read ();
+
+	/* check if MAC or MII register */
+	if (((bank == 2) && (regNo <= 0x1a)) ||
+	    ((bank == 3) && (regNo <= 0x05 || regNo == 0x0a))) {
+		/* ignore first byte and read another byte */
+		rxByte = spi_read ();
+	}
+
+	enc_disable ();
+	spi_unlock ();
+
+	return rxByte;
+}
+
+static void encReadBuff (unsigned short length, unsigned char *pBuff)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x20 | 0x1a);	/* read buffer memory */
+
+	while (length--) {
+		if (pBuff != NULL)
+			*pBuff++ = spi_read ();
+		else
+			spi_write (0);
+	}
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encWriteBuff (unsigned short length, unsigned char *pBuff)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x60 | 0x1a);	/* write buffer memory */
+
+	spi_write (0x00);	/* control byte */
+
+	while (length--)
+		spi_write (*pBuff++);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encBitSet (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0x80 | regNo);	/* bit field set */
+	spi_write (data);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encBitClr (unsigned char regNo, unsigned char data)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0xA0 | regNo);	/* bit field clear */
+	spi_write (data);
+
+	enc_disable ();
+	spi_unlock ();
+}
+
+static void encReset (void)
+{
+	spi_lock ();
+	enc_cfg_spi ();
+	enc_enable ();
+
+	spi_write (0xff);	/* soft reset */
+
+	enc_disable ();
+	spi_unlock ();
+
+	/* sleep 1 ms. See errata pt. 2 */
+	udelay (1000);
+}
+
+static void encInit (unsigned char *pEthAddr)
+{
+	unsigned short phid1 = 0;
+	unsigned short phid2 = 0;
+
+	/* switch to bank 0 */
+	m_nic_bfc (CTL_REG_ECON1, (ENC_ECON1_BSEL1 | ENC_ECON1_BSEL0));
+
+	/*
+	 * Setup the buffer space. The reset values are valid for the
+	 * other pointers.
+	 */
+	/* We shall not write to ERXST, see errata pt. 5. Instead we
+	   have to make sure that ENC_RX_BUS_START is 0. */
+	m_nic_write_retry (CTL_REG_ERXSTL, (ENC_RX_BUF_START & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERXSTH, (ENC_RX_BUF_START >> 8), 1);
+
+	/* taken from the Linux driver */
+	m_nic_write_retry (CTL_REG_ERXNDL, (ENC_RX_BUF_END & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERXNDH, (ENC_RX_BUF_END >> 8), 1);
+
+	m_nic_write_retry (CTL_REG_ERDPTL, (ENC_RX_BUF_START & 0xFF), 1);
+	m_nic_write_retry (CTL_REG_ERDPTH, (ENC_RX_BUF_START >> 8), 1);
+
+	next_pointer_lsb = (ENC_RX_BUF_START & 0xFF);
+	next_pointer_msb = (ENC_RX_BUF_START >> 8);
+
+	/* verify identification */
+	phid1 = phyRead (PHY_REG_PHID1);
+	phid2 = phyRead (PHY_REG_PHID2);
+
+	if (phid1 != ENC_PHID1_VALUE
+	    || (phid2 & ENC_PHID2_MASK) != ENC_PHID2_VALUE) {
+		printf ("ERROR: failed to identify controller\n");
+		printf ("phid1 = %x, phid2 = %x\n",
+			phid1, (phid2 & ENC_PHID2_MASK));
+		printf ("should be phid1 = %x, phid2 = %x\n",
+			ENC_PHID1_VALUE, ENC_PHID2_VALUE);
+	}
+
+	/*
+	 * --- MAC Initialization ---
+	 */
+
+	/* Pull MAC out of Reset */
+
+	/* switch to bank 2 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* enable MAC to receive frames */
+	/* added some bits from the Linux driver */
+	m_nic_write_retry (CTL_REG_MACON1
+		,(ENC_MACON1_MARXEN | ENC_MACON1_TXPAUS | ENC_MACON1_RXPAUS)
+		,10);
+
+	/* configure pad, tx-crc and duplex */
+	/* added a bit from the Linux driver */
+	m_nic_write_retry (CTL_REG_MACON3
+		,(ENC_MACON3_PADCFG0 | ENC_MACON3_TXCRCEN | ENC_MACON3_FRMLNEN)
+		,10);
+
+	/* added 4 new lines from the Linux driver */
+	/* Allow infinite deferals if the medium is continously busy */
+	m_nic_write_retry(CTL_REG_MACON4, (1<<6) /*ENC_MACON4_DEFER*/, 10);
+
+	/* Late collisions occur beyond 63 bytes */
+	m_nic_write_retry(CTL_REG_MACLCON2, 63, 10);
+
+	/* Set (low byte) Non-Back-to_Back Inter-Packet Gap. Recommended 0x12 */
+	m_nic_write_retry(CTL_REG_MAIPGL, 0x12, 10);
+
+	/*
+	* Set (high byte) Non-Back-to_Back Inter-Packet Gap. Recommended
+	* 0x0c for half-duplex. Nothing for full-duplex
+	*/
+	m_nic_write_retry(CTL_REG_MAIPGH, 0x0C, 10);
+
+	/* set maximum frame length */
+	m_nic_write_retry (CTL_REG_MAMXFLL, (ENC_MAX_FRM_LEN & 0xff), 10);
+	m_nic_write_retry (CTL_REG_MAMXFLH, (ENC_MAX_FRM_LEN >> 8), 10);
+
+	/*
+	 * Set MAC back-to-back inter-packet gap. Recommended 0x12 for half duplex
+	 * and 0x15 for full duplex.
+	 */
+	m_nic_write_retry (CTL_REG_MABBIPG, 0x12, 10);
+
+	/* set MAC address */
+
+	/* switch to bank 3 */
+	m_nic_bfs (CTL_REG_ECON1, (ENC_ECON1_BSEL0 | ENC_ECON1_BSEL1));
+
+	m_nic_write_retry (CTL_REG_MAADR0, pEthAddr[5], 1);
+	m_nic_write_retry (CTL_REG_MAADR1, pEthAddr[4], 1);
+	m_nic_write_retry (CTL_REG_MAADR2, pEthAddr[3], 1);
+	m_nic_write_retry (CTL_REG_MAADR3, pEthAddr[2], 1);
+	m_nic_write_retry (CTL_REG_MAADR4, pEthAddr[1], 1);
+	m_nic_write_retry (CTL_REG_MAADR5, pEthAddr[0], 1);
+
+	/*
+	* PHY Initialization taken from the Linux driver
+	 */
+
+	/* Prevent automatic loopback of data beeing transmitted by setting
+	   ENC_PHCON2_HDLDIS */
+	phyWrite(PHY_REG_PHCON2, (1<<8));
+
+	/* LEDs configuration
+	 * LEDA: LACFG = 0100 -> display link status
+	 * LEDB: LBCFG = 0111 -> display TX & RX activity
+	 * STRCH = 1 -> LED pulses
+	 */
+	phyWrite(PHY_REG_PHLCON, 0x0472);
+
+	/* Reset PDPXMD-bit => half duplex */
+	phyWrite(PHY_REG_PHCON1, 0);
+
+	/*
+	 * Receive settings
+	 */
+
+#ifdef CONFIG_USE_IRQ
+	/* enable interrupts */
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_PKTIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_TXIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_RXERIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_TXERIE);
+	m_nic_bfs (CTL_REG_EIE, ENC_EIE_INTIE);
+#endif
+}
+
+/*****************************************************************************
+ *
+ * Description:
+ *    Read PHY registers.
+ *
+ *    NOTE! This function will change to Bank 2.
+ *
+ * Params:
+ *    [in] addr address of the register to read
+ *
+ * Returns:
+ *    The value in the register
+ */
+static unsigned short phyRead (unsigned char addr)
+{
+	unsigned short ret = 0;
+
+	/* move to bank 2 */
+	m_nic_bfc (CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs (CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* write address to MIREGADR */
+	m_nic_write (CTL_REG_MIREGADR, addr);
+
+	/* set MICMD.MIIRD */
+	m_nic_write (CTL_REG_MICMD, ENC_MICMD_MIIRD);
+
+	/* taken from the Linux driver */
+	/* move to bank 3 */
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* poll MISTAT.BUSY bit until operation is complete */
+	while ((m_nic_read (CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		static int cnt = 0;
+
+		if (cnt++ >= 1000) {
+			/* GJ - this seems extremely dangerous! */
+			/* printf("#"); */
+			cnt = 0;
+		}
+	}
+
+	/* taken from the Linux driver */
+	/* move to bank 2 */
+	m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* clear MICMD.MIIRD */
+	m_nic_write (CTL_REG_MICMD, 0);
+
+	ret = (m_nic_read (CTL_REG_MIRDH) << 8);
+	ret |= (m_nic_read (CTL_REG_MIRDL) & 0xFF);
+
+	return ret;
+}
+
+/*****************************************************************************
+ *
+ * Taken from the Linux driver.
+ * Description:
+ * Write PHY registers.
+ *
+ * NOTE! This function will change to Bank 3.
+ *
+ * Params:
+ * [in] addr address of the register to write to
+ * [in] data to be written
+ *
+ * Returns:
+ *    None
+ */
+static void phyWrite(unsigned char addr, unsigned short data)
+{
+	/* move to bank 2 */
+	m_nic_bfc(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* write address to MIREGADR */
+	m_nic_write(CTL_REG_MIREGADR, addr);
+
+	m_nic_write(CTL_REG_MIWRL, data & 0xff);
+	m_nic_write(CTL_REG_MIWRH, data >> 8);
+
+	/* move to bank 3 */
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL0);
+	m_nic_bfs(CTL_REG_ECON1, ENC_ECON1_BSEL1);
+
+	/* poll MISTAT.BUSY bit until operation is complete */
+	while((m_nic_read(CTL_REG_MISTAT) & ENC_MISTAT_BUSY) != 0) {
+		static int cnt = 0;
+
+		if(cnt++ >= 1000) {
+			cnt = 0;
+		}
+	}
+}
+
+#endif /* CONFIG_ENC28J60 */
diff --git a/drivers/fsl_i2c.c b/drivers/fsl_i2c.c
index ebae5af..22485ea 100644
--- a/drivers/fsl_i2c.c
+++ b/drivers/fsl_i2c.c
@@ -69,9 +69,10 @@
 	dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET);
 
 	writeb(0, &dev->cr);			/* stop I2C controller */
+	udelay(5);				/* let it shutdown in peace */
 	writeb(0x3F, &dev->fdr);		/* set bus speed */
 	writeb(0x3F, &dev->dfsrr);		/* set default filter */
-	writeb(slaveadd, &dev->adr);		/* write slave address */
+	writeb(slaveadd << 1, &dev->adr);	/* write slave address */
 	writeb(0x0, &dev->sr);			/* clear status register */
 	writeb(I2C_CR_MEN, &dev->cr);		/* start I2C controller */
 #endif	/* CFG_I2C2_OFFSET */
diff --git a/drivers/fsl_pci_init.c b/drivers/fsl_pci_init.c
new file mode 100644
index 0000000..1084dc6
--- /dev/null
+++ b/drivers/fsl_pci_init.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * Version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_FSL_PCI_INIT
+
+/*
+ * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
+ *
+ * Initialize controller and call the common driver/pci pci_hose_scan to
+ * scan for bridges and devices.
+ *
+ * Hose fields which need to be pre-initialized by board specific code:
+ *   regions[]
+ *   first_busno
+ *
+ * Fields updated:
+ *   last_busno
+ */
+
+#include <pci.h>
+#include <asm/immap_fsl_pci.h>
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+				pci_dev_t dev, int sub_bus);
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+				pci_dev_t dev, int sub_bus);
+
+void pciauto_config_init(struct pci_controller *hose);
+void
+fsl_pci_init(struct pci_controller *hose)
+{
+	u16 temp16;
+	u32 temp32;
+	int busno = hose->first_busno;
+	int enabled;
+	u16 ltssm;
+	u8 temp8;
+	int r;
+	int bridge;
+	volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) hose->cfg_addr;
+	pci_dev_t dev = PCI_BDF(busno,0,0);
+
+	/* Initialize ATMU registers based on hose regions and flags */
+	volatile pot_t *po=&pci->pot[1];	/* skip 0 */
+	volatile pit_t *pi=&pci->pit[0];	/* ranges from: 3 to 1 */
+
+#ifdef DEBUG
+	int neg_link_w;
+#endif
+
+	for (r=0; r<hose->region_count; r++) {
+		if (hose->regions[r].flags & PCI_REGION_MEMORY) { /* inbound */
+			pi->pitar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
+			pi->piwbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
+			pi->piwbear = 0;
+			pi->piwar = PIWAR_EN | PIWAR_PF | PIWAR_LOCAL |
+				PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP |
+				(__ilog2(hose->regions[r].size) - 1);
+			pi++;
+		} else { /* Outbound */
+			po->powbar = (hose->regions[r].phys_start >> 12) & 0x000fffff;
+			po->potar = (hose->regions[r].bus_start >> 12) & 0x000fffff;
+			po->potear = 0;
+			if (hose->regions[r].flags & PCI_REGION_IO)
+				po->powar = POWAR_EN | POWAR_IO_READ | POWAR_IO_WRITE |
+					(__ilog2(hose->regions[r].size) - 1);
+			else
+				po->powar = POWAR_EN | POWAR_MEM_READ | POWAR_MEM_WRITE |
+					(__ilog2(hose->regions[r].size) - 1);
+			po++;
+		}
+	}
+
+	pci_register_hose(hose);
+	pciauto_config_init(hose);	/* grab pci_{mem,prefetch,io} */
+	hose->current_busno = hose->first_busno;
+
+	pci->pedr = 0xffffffff;		/* Clear any errors */
+	pci->peer = ~0x20140;		/* Enable All Error Interupts except
+					 * - Master abort (pci)
+					 * - Master PERR (pci)
+					 * - ICCA (PCIe)
+					 */
+	pci_hose_read_config_dword (hose, dev, PCI_DCR, &temp32);
+	temp32 |= 0xf000e;		/* set URR, FER, NFER (but not CER) */
+	pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32);
+
+	pci_hose_read_config_byte (hose, dev, PCI_HEADER_TYPE, &temp8);
+	bridge = temp8 & PCI_HEADER_TYPE_BRIDGE; /* Bridge, such as pcie */
+
+	if ( bridge ) {
+
+		pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+		enabled = ltssm >= PCI_LTSSM_L0;
+
+		if (!enabled) {
+			debug("....PCIE link error.  Skipping scan."
+			      "LTSSM=0x%02x\n", ltssm);
+			hose->last_busno = hose->first_busno;
+			return;
+		}
+
+		pci->pme_msg_det = 0xffffffff;
+		pci->pme_msg_int_en = 0xffffffff;
+#ifdef DEBUG
+		pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16);
+		neg_link_w = (temp16 & 0x3f0 ) >> 4;
+		printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n",
+		      ltssm, neg_link_w);
+#endif
+		hose->current_busno++; /* Start scan with secondary */
+		pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+
+	}
+
+	/* Call setup to allocate PCSRBAR window */
+	pciauto_setup_device(hose, dev, 1, hose->pci_mem,
+			     hose->pci_prefetch, hose->pci_io);
+#ifndef CONFIG_PCI_NOSCAN
+	printf ("               Scanning PCI bus %02x\n", hose->current_busno);
+	hose->last_busno = pci_hose_scan_bus(hose,hose->current_busno);
+
+	if ( bridge ) { /* update limit regs and subordinate busno */
+		pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
+	}
+#else
+	hose->last_busno = hose->current_busno;
+#endif
+
+	/* Clear all error indications */
+
+	pci->pme_msg_det = 0xffffffff;
+	pci->pedr = 0xffffffff;
+
+	pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16);
+	if (temp16) {
+		pci_hose_write_config_word(hose, dev,
+					PCI_DSR, 0xffff);
+	}
+
+	pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
+	if (temp16) {
+		pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
+	}
+}
+
+#endif /* CONFIG_FSL_PCI */
diff --git a/drivers/inca-ip_sw.c b/drivers/inca-ip_sw.c
index ab22b4d..e4aaed6 100644
--- a/drivers/inca-ip_sw.c
+++ b/drivers/inca-ip_sw.c
@@ -26,8 +26,8 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
-	&& defined(CONFIG_INCA_IP_SWITCH)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_INCA_IP_SWITCH)
 
 #include <malloc.h>
 #include <net.h>
diff --git a/drivers/isp116x-hcd.c b/drivers/isp116x-hcd.c
new file mode 100644
index 0000000..8e2bc7a
--- /dev/null
+++ b/drivers/isp116x-hcd.c
@@ -0,0 +1,1413 @@
+/*
+ * ISP116x HCD (Host Controller Driver) for u-boot.
+ *
+ * Copyright (C) 2006-2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2006-2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Derived in part from the SL811 HCD driver "u-boot/drivers/sl811_usb.c"
+ * (original copyright message follows):
+ *
+ *    (C) Copyright 2004
+ *    Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ *    This code is based on linux driver for sl811hs chip, source at
+ *    drivers/usb/host/sl811.c:
+ *
+ *    SL811 Host Controller Interface driver for USB.
+ *
+ *    Copyright (c) 2003/06, Courage Co., Ltd.
+ *
+ *    Based on:
+ *         1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap,
+ *           Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber,
+ *           Adam Richter, Gregory P. Smith;
+ *         2.Original SL811 driver (hc_sl811.o) by Pei Liu <pbl@cypress.com>
+ *         3.Rewrited as sl811.o by Yin Aihua <yinah:couragetech.com.cn>
+ *
+ *    [[GNU/GPL disclaimer]]
+ *
+ * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c"
+ * (original copyright message follows):
+ *
+ *    URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
+ *
+ *    (C) Copyright 2003
+ *    Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ *    [[GNU/GPL disclaimer]]
+ *
+ *    Note: Part of this code has been derived from linux
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_ISP116X_HCD
+#include <asm/io.h>
+#include <usb.h>
+#include <malloc.h>
+#include <linux/list.h>
+
+/*
+ * ISP116x chips require certain delays between accesses to its
+ * registers. The following timing options exist.
+ *
+ * 1. Configure your memory controller (the best)
+ * 2. Use ndelay (easiest, poorest). For that, enable the following macro.
+ *
+ * Value is in microseconds.
+ */
+#ifdef ISP116X_HCD_USE_UDELAY
+#define UDELAY		1
+#endif
+
+/*
+ * On some (slowly?) machines an extra delay after data packing into
+ * controller's FIFOs is required, * otherwise you may get the following
+ * error:
+ *
+ *   uboot> usb start
+ *   (Re)start USB...
+ *   USB:   scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT
+ *   isp116x: isp116x_submit_job: ****** FIFO not ready! ******
+ *
+ *         USB device not responding, giving up (status=4)
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         isp116x: isp116x_submit_job: ****** FIFO not empty! ******
+ *         3 USB Device(s) found
+ *                scanning bus for storage devices... 0 Storage Device(s) found
+ *
+ * Value is in milliseconds.
+ */
+#ifdef ISP116X_HCD_USE_EXTRA_DELAY
+#define EXTRA_DELAY	2
+#endif
+
+/*
+ * Enable the following defines if you wish enable debugging messages.
+ */
+#undef DEBUG			/* enable debugging messages */
+#undef TRACE			/* enable tracing code */
+#undef VERBOSE			/* verbose debugging messages */
+
+#include "isp116x.h"
+
+#define DRIVER_VERSION	"08 Jan 2007"
+static const char hcd_name[] = "isp116x-hcd";
+
+struct isp116x isp116x_dev;
+struct isp116x_platform_data isp116x_board;
+int got_rhsc = 0;		/* root hub status change */
+struct usb_device *devgone;	/* device which was disconnected */
+int rh_devnum = 0;		/* address of Root Hub endpoint */
+
+/* ------------------------------------------------------------------------- */
+
+#define ALIGN(x,a)	(((x)+(a)-1UL)&~((a)-1UL))
+#define min_t(type,x,y)	\
+	({ type __x = (x); type __y = (y); __x < __y ? __x : __y; })
+
+/* ------------------------------------------------------------------------- */
+
+static int isp116x_reset(struct isp116x *isp116x);
+
+/* --- Debugging functions ------------------------------------------------- */
+
+#define isp116x_show_reg(d, r) {				\
+	if ((r) < 0x20) {					\
+		DBG("%-12s[%02x]: %08x", #r,			\
+			r, isp116x_read_reg32(d, r));		\
+	} else {						\
+		DBG("%-12s[%02x]:     %04x", #r,		\
+			r, isp116x_read_reg16(d, r));  		\
+	}							\
+}
+
+#define isp116x_show_regs(d) {					\
+	isp116x_show_reg(d, HCREVISION);			\
+	isp116x_show_reg(d, HCCONTROL);				\
+	isp116x_show_reg(d, HCCMDSTAT);				\
+	isp116x_show_reg(d, HCINTSTAT);				\
+	isp116x_show_reg(d, HCINTENB);				\
+	isp116x_show_reg(d, HCFMINTVL);				\
+	isp116x_show_reg(d, HCFMREM);				\
+	isp116x_show_reg(d, HCFMNUM);				\
+	isp116x_show_reg(d, HCLSTHRESH);			\
+	isp116x_show_reg(d, HCRHDESCA);				\
+	isp116x_show_reg(d, HCRHDESCB);				\
+	isp116x_show_reg(d, HCRHSTATUS);			\
+	isp116x_show_reg(d, HCRHPORT1);				\
+	isp116x_show_reg(d, HCRHPORT2);				\
+	isp116x_show_reg(d, HCHWCFG);				\
+	isp116x_show_reg(d, HCDMACFG);				\
+	isp116x_show_reg(d, HCXFERCTR);				\
+	isp116x_show_reg(d, HCuPINT);				\
+	isp116x_show_reg(d, HCuPINTENB);			\
+	isp116x_show_reg(d, HCCHIPID);				\
+	isp116x_show_reg(d, HCSCRATCH);				\
+	isp116x_show_reg(d, HCITLBUFLEN);			\
+	isp116x_show_reg(d, HCATLBUFLEN);			\
+	isp116x_show_reg(d, HCBUFSTAT);				\
+	isp116x_show_reg(d, HCRDITL0LEN);			\
+	isp116x_show_reg(d, HCRDITL1LEN);			\
+}
+
+#if defined(TRACE)
+
+static int isp116x_get_current_frame_number(struct usb_device *usb_dev)
+{
+	struct isp116x *isp116x = &isp116x_dev;
+
+	return isp116x_read_reg32(isp116x, HCFMNUM);
+}
+
+static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		     int len, char *str)
+{
+#if defined(VERBOSE)
+	int i;
+#endif
+
+	DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx",
+	    str,
+	    isp116x_get_current_frame_number(dev),
+	    usb_pipedevice(pipe),
+	    usb_pipeendpoint(pipe),
+	    usb_pipeout(pipe) ? 'O' : 'I',
+	    usb_pipetype(pipe) < 2 ?
+	    (usb_pipeint(pipe) ?
+	     "INTR" : "ISOC") :
+	    (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status);
+#if defined(VERBOSE)
+	if (len > 0 && buffer) {
+		printf(__FILE__ ": data(%d):", len);
+		for (i = 0; i < 16 && i < len; i++)
+			printf(" %02x", ((__u8 *) buffer)[i]);
+		printf("%s\n", i < len ? "..." : "");
+	}
+#endif
+}
+
+#define PTD_DIR_STR(ptd)  ({char __c;		\
+	switch(PTD_GET_DIR(ptd)){		\
+	case 0:  __c = 's'; break;		\
+	case 1:  __c = 'o'; break;		\
+	default: __c = 'i'; break;		\
+	}; __c;})
+
+/*
+  Dump PTD info. The code documents the format
+  perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+#if defined(VERBOSE)
+	int k;
+#endif
+
+	DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x",
+	    PTD_GET_CC(ptd),
+	    PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+	    PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+	    PTD_GET_TOGGLE(ptd),
+	    PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+#if defined(VERBOSE)
+	printf("isp116x: %s: PTD(byte): ", __FUNCTION__);
+	for (k = 0; k < sizeof(struct ptd); ++k)
+		printf("%02x ", ((u8 *) ptd)[k]);
+	printf("\n");
+#endif
+}
+
+static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type)
+{
+#if defined(VERBOSE)
+	int k;
+
+	if (type == 0 /* 0ut data */ ) {
+		printf("isp116x: %s: out data: ", __FUNCTION__);
+		for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+			printf("%02x ", ((u8 *) buf)[k]);
+		printf("\n");
+	}
+	if (type == 1 /* 1n data */ ) {
+		printf("isp116x: %s: in data: ", __FUNCTION__);
+		for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+			printf("%02x ", ((u8 *) buf)[k]);
+		printf("\n");
+	}
+
+	if (PTD_GET_LAST(ptd))
+		DBG("--- last PTD ---");
+#endif
+}
+
+#else
+
+#define dump_msg(dev, pipe, buffer, len, str)			do { } while (0)
+#define dump_pkt(dev, pipe, buffer, len, setup, str, small)	do {} while (0)
+
+#define dump_ptd(ptd)			do {} while (0)
+#define dump_ptd_data(ptd, buf, type)	do {} while (0)
+
+#endif
+
+/* --- Virtual Root Hub ---------------------------------------------------- */
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] = {
+	0x12,			/*  __u8  bLength; */
+	0x01,			/*  __u8  bDescriptorType; Device */
+	0x10,			/*  __u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,			/*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  bDeviceSubClass; */
+	0x00,			/*  __u8  bDeviceProtocol; */
+	0x08,			/*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x00,			/*  __u16 idVendor; */
+	0x00,
+	0x00,			/*  __u16 idProduct; */
+	0x00,
+	0x00,			/*  __u16 bcdDevice; */
+	0x00,
+	0x00,			/*  __u8  iManufacturer; */
+	0x01,			/*  __u8  iProduct; */
+	0x00,			/*  __u8  iSerialNumber; */
+	0x01			/*  __u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] = {
+	0x09,			/*  __u8  bLength; */
+	0x02,			/*  __u8  bDescriptorType; Configuration */
+	0x19,			/*  __u16 wTotalLength; */
+	0x00,
+	0x01,			/*  __u8  bNumInterfaces; */
+	0x01,			/*  __u8  bConfigurationValue; */
+	0x00,			/*  __u8  iConfiguration; */
+	0x40,			/*  __u8  bmAttributes;
+				   Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,			/*  __u8  MaxPower; */
+
+	/* interface */
+	0x09,			/*  __u8  if_bLength; */
+	0x04,			/*  __u8  if_bDescriptorType; Interface */
+	0x00,			/*  __u8  if_bInterfaceNumber; */
+	0x00,			/*  __u8  if_bAlternateSetting; */
+	0x01,			/*  __u8  if_bNumEndpoints; */
+	0x09,			/*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,			/*  __u8  if_bInterfaceSubClass; */
+	0x00,			/*  __u8  if_bInterfaceProtocol; */
+	0x00,			/*  __u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,			/*  __u8  ep_bLength; */
+	0x05,			/*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,			/*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,			/*  __u8  ep_bmAttributes; Interrupt */
+	0x00,			/*  __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x02,
+	0xff			/*  __u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] = {
+	0x04,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	0x09,			/*  __u8  lang ID */
+	0x04,			/*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] = {
+	0x22,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	'I',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'S',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'P',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'1',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'1',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'6',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'x',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'R',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	't',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'u',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+	'b',			/*  __u8  Unicode */
+	0,			/*  __u8  Unicode */
+};
+
+/*
+ * Hub class-specific descriptor is constructed dynamically
+ */
+
+/* --- Virtual root hub management functions ------------------------------- */
+
+static int rh_check_port_status(struct isp116x *isp116x)
+{
+	u32 temp, ndp, i;
+	int res;
+
+	res = -1;
+	temp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+	ndp = (temp & RH_A_NDP);
+	for (i = 0; i < ndp; i++) {
+		temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i);
+		/* check for a device disconnect */
+		if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+		     (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) {
+			res = i;
+			break;
+		}
+	}
+	return res;
+}
+
+/* --- HC management functions --------------------------------------------- */
+
+/* Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+	u8 *dp = (u8 *) buf;
+	u16 *dp2 = (u16 *) buf;
+	u16 w;
+	int quot = len % 4;
+
+	if ((unsigned long)dp2 & 1) {
+		/* not aligned */
+		for (; len > 1; len -= 2) {
+			w = *dp++;
+			w |= *dp++ << 8;
+			isp116x_raw_write_data16(isp116x, w);
+		}
+		if (len)
+			isp116x_write_data16(isp116x, (u16) * dp);
+	} else {
+		/* aligned */
+		for (; len > 1; len -= 2)
+			isp116x_raw_write_data16(isp116x, *dp2++);
+		if (len)
+			isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+	}
+	if (quot == 1 || quot == 2)
+		isp116x_raw_write_data16(isp116x, 0);
+}
+
+/* Read len bytes from fifo and then read till 32-bit boundary
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+	u8 *dp = (u8 *) buf;
+	u16 *dp2 = (u16 *) buf;
+	u16 w;
+	int quot = len % 4;
+
+	if ((unsigned long)dp2 & 1) {
+		/* not aligned */
+		for (; len > 1; len -= 2) {
+			w = isp116x_raw_read_data16(isp116x);
+			*dp++ = w & 0xff;
+			*dp++ = (w >> 8) & 0xff;
+		}
+		if (len)
+			*dp = 0xff & isp116x_read_data16(isp116x);
+	} else {
+		/* aligned */
+		for (; len > 1; len -= 2)
+			*dp2++ = isp116x_raw_read_data16(isp116x);
+		if (len)
+			*(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+	}
+	if (quot == 1 || quot == 2)
+		isp116x_raw_read_data16(isp116x);
+}
+
+/* Write PTD's and data for scheduled transfers into the fifo ram.
+ * Fifo must be empty and ready */
+static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+		      unsigned long pipe, struct ptd *ptd, int n, void *data,
+		      int len)
+{
+	int buflen = n * sizeof(struct ptd) + len;
+	int i, done;
+
+	DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+	isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+	isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+	isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+
+	done = 0;
+	for (i = 0; i < n; i++) {
+		DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+		dump_ptd(&ptd[i]);
+		isp116x_write_data16(isp116x, ptd[i].count);
+		isp116x_write_data16(isp116x, ptd[i].mps);
+		isp116x_write_data16(isp116x, ptd[i].len);
+		isp116x_write_data16(isp116x, ptd[i].faddr);
+
+		dump_ptd_data(&ptd[i], (__u8 *) data + done, 0);
+		write_ptddata_to_fifo(isp116x,
+				      (__u8 *) data + done,
+				      PTD_GET_LEN(&ptd[i]));
+
+		done += PTD_GET_LEN(&ptd[i]);
+	}
+}
+
+/* Read the processed PTD's and data from fifo ram back to URBs' buffers.
+ * Fifo must be full and done */
+static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev,
+		       unsigned long pipe, struct ptd *ptd, int n, void *data,
+		       int len)
+{
+	int buflen = n * sizeof(struct ptd) + len;
+	int i, done, cc, ret;
+
+	isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+	isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+	isp116x_write_addr(isp116x, HCATLPORT);
+
+	ret = TD_CC_NOERROR;
+	done = 0;
+	for (i = 0; i < n; i++) {
+		DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i]));
+
+		ptd[i].count = isp116x_read_data16(isp116x);
+		ptd[i].mps = isp116x_read_data16(isp116x);
+		ptd[i].len = isp116x_read_data16(isp116x);
+		ptd[i].faddr = isp116x_read_data16(isp116x);
+		dump_ptd(&ptd[i]);
+
+		read_ptddata_from_fifo(isp116x,
+				       (__u8 *) data + done,
+				       PTD_GET_LEN(&ptd[i]));
+		dump_ptd_data(&ptd[i], (__u8 *) data + done, 1);
+
+		done += PTD_GET_LEN(&ptd[i]);
+
+		cc = PTD_GET_CC(&ptd[i]);
+		if (cc == TD_DATAUNDERRUN) {	/* underrun is no error... */
+			DBG("allowed data underrun");
+			cc = TD_CC_NOERROR;
+		}
+		if (cc != TD_CC_NOERROR && ret == TD_CC_NOERROR)
+			ret = cc;
+	}
+
+	DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen);
+
+	return ret;
+}
+
+/* Interrupt handling
+ */
+static int isp116x_interrupt(struct isp116x *isp116x)
+{
+	u16 irqstat;
+	u32 intstat;
+	int ret = 0;
+
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+	irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+	isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+	DBG(">>>>>> irqstat %x <<<<<<", irqstat);
+
+	if (irqstat & HCuPINT_ATL) {
+		DBG(">>>>>> HCuPINT_ATL <<<<<<");
+		udelay(500);
+		ret = 1;
+	}
+
+	if (irqstat & HCuPINT_OPR) {
+		intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+		isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+		DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat);
+
+		if (intstat & HCINT_UE) {
+			ERR("unrecoverable error, controller disabled");
+
+			/* FIXME: be optimistic, hope that bug won't repeat
+			 * often. Make some non-interrupt context restart the
+			 * controller. Count and limit the retries though;
+			 * either hardware or software errors can go forever...
+			 */
+			isp116x_reset(isp116x);
+			ret = -1;
+			return -1;
+		}
+
+		if (intstat & HCINT_RHSC) {
+			got_rhsc = 1;
+			ret = 1;
+			/* When root hub or any of its ports is going
+			   to come out of suspend, it may take more
+			   than 10ms for status bits to stabilize. */
+			wait_ms(20);
+		}
+
+		if (intstat & HCINT_SO) {
+			ERR("schedule overrun");
+			ret = -1;
+		}
+
+		irqstat &= ~HCuPINT_OPR;
+	}
+
+	return ret;
+}
+
+#define PTD_NUM			64	/* it should be enougth... */
+struct ptd ptd[PTD_NUM];
+static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe)
+{
+	return min(PTD_NUM * usb_maxpacket(dev, pipe), PTD_NUM * 16);
+}
+
+/* Do an USB transfer
+ */
+static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe,
+			      int dir, void *buffer, int len)
+{
+	struct isp116x *isp116x = &isp116x_dev;
+	int type = usb_pipetype(pipe);
+	int epnum = usb_pipeendpoint(pipe);
+	int max = usb_maxpacket(dev, pipe);
+	int dir_out = usb_pipeout(pipe);
+	int speed_low = usb_pipeslow(pipe);
+	int i, done, stat, timeout, cc;
+	int retries = 10;
+
+	DBG("------------------------------------------------");
+	dump_msg(dev, pipe, buffer, len, "SUBMIT");
+	DBG("------------------------------------------------");
+
+	if (isp116x->disabled) {
+		ERR("EPIPE");
+		dev->status = USB_ST_CRC_ERR;
+		return -1;
+	}
+
+	/* device pulled? Shortcut the action. */
+	if (devgone == dev) {
+		ERR("ENODEV");
+		dev->status = USB_ST_CRC_ERR;
+		return USB_ST_CRC_ERR;
+	}
+
+	if (!max) {
+		ERR("pipesize for pipe %lx is zero", pipe);
+		dev->status = USB_ST_CRC_ERR;
+		return -1;
+	}
+
+	if (type == PIPE_ISOCHRONOUS) {
+		ERR("isochronous transfers not supported");
+		dev->status = USB_ST_CRC_ERR;
+		return -1;
+	}
+
+	/* FIFO not empty? */
+	if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) {
+		ERR("****** FIFO not empty! ******");
+		dev->status = USB_ST_BUF_ERR;
+		return -1;
+	}
+
+      retry:
+	isp116x_write_reg32(isp116x, HCINTSTAT, 0xff);
+
+	/* Prepare the PTD data */
+	done = 0;
+	i = 0;
+	do {
+		ptd[i].count = PTD_CC_MSK | PTD_ACTIVE_MSK |
+		    PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out));
+		ptd[i].mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum);
+		ptd[i].len = PTD_LEN(max > len - done ? len - done : max) |
+		    PTD_DIR(dir);
+		ptd[i].faddr = PTD_FA(usb_pipedevice(pipe));
+
+		usb_dotoggle(dev, epnum, dir_out);
+		done += PTD_GET_LEN(&ptd[i]);
+		i++;
+		if (i >= PTD_NUM) {
+			ERR("****** Cannot pack buffer! ******");
+			dev->status = USB_ST_BUF_ERR;
+			return -1;
+		}
+	} while (done < len);
+	ptd[i - 1].mps |= PTD_LAST_MSK;
+
+	/* Pack data into FIFO ram */
+	pack_fifo(isp116x, dev, pipe, ptd, i, buffer, len);
+#ifdef EXTRA_DELAY
+	wait_ms(EXTRA_DELAY);
+#endif
+
+	/* Start the data transfer */
+
+	/* Allow more time for a BULK device to react - some are slow */
+	if (usb_pipetype(pipe) == PIPE_BULK)
+		timeout = 5000;
+	else
+		timeout = 100;
+
+	/* Wait for it to complete */
+	for (;;) {
+		/* Check whether the controller is done */
+		stat = isp116x_interrupt(isp116x);
+
+		if (stat < 0) {
+			dev->status = USB_ST_CRC_ERR;
+			break;
+		}
+		if (stat > 0)
+			break;
+
+		/* Check the timeout */
+		if (--timeout)
+			udelay(1);
+		else {
+			ERR("CTL:TIMEOUT ");
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+	}
+
+	/* We got an Root Hub Status Change interrupt */
+	if (got_rhsc) {
+		isp116x_show_regs(isp116x);
+
+		got_rhsc = 0;
+
+		/* Abuse timeout */
+		timeout = rh_check_port_status(isp116x);
+		if (timeout >= 0) {
+			/*
+			 * FIXME! NOTE! AAAARGH!
+			 * This is potentially dangerous because it assumes
+			 * that only one device is ever plugged in!
+			 */
+			devgone = dev;
+		}
+	}
+
+	/* Ok, now we can read transfer status */
+
+	/* FIFO not ready? */
+	if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) {
+		ERR("****** FIFO not ready! ******");
+		dev->status = USB_ST_BUF_ERR;
+		return -1;
+	}
+
+	/* Unpack data from FIFO ram */
+	cc = unpack_fifo(isp116x, dev, pipe, ptd, i, buffer, len);
+
+	/* Mmm... sometime we get 0x0f as cc which is a non sense!
+	 * Just retry the transfer...
+	 */
+	if (cc == 0x0f && retries-- > 0) {
+		usb_dotoggle(dev, epnum, dir_out);
+		goto retry;
+	}
+
+	if (cc != TD_CC_NOERROR) {
+		DBG("****** completition code error %x ******", cc);
+		switch (cc) {
+		case TD_CC_BITSTUFFING:
+			dev->status = USB_ST_BIT_ERR;
+			break;
+		case TD_CC_STALL:
+			dev->status = USB_ST_STALLED;
+			break;
+		case TD_BUFFEROVERRUN:
+		case TD_BUFFERUNDERRUN:
+			dev->status = USB_ST_BUF_ERR;
+			break;
+		default:
+			dev->status = USB_ST_CRC_ERR;
+		}
+		return -cc;
+	}
+
+	dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)");
+
+	dev->status = 0;
+	return done;
+}
+
+/* Adapted from au1x00_usb_ohci.c
+ */
+static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+				 void *buffer, int transfer_len,
+				 struct devrequest *cmd)
+{
+	struct isp116x *isp116x = &isp116x_dev;
+	u32 tmp = 0;
+
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	u32 datab[4];
+	u8 *data_buf = (u8 *) datab;
+	u16 bmRType_bReq;
+	u16 wValue;
+	u16 wIndex;
+	u16 wLength;
+
+	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+		INFO("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+	wValue = swap_16(cmd->value);
+	wIndex = swap_16(cmd->index);
+	wLength = swap_16(cmd->length);
+
+	DBG("--- HUB ----------------------------------------");
+	DBG("submit rh urb, req=%x val=%#x index=%#x len=%d",
+	    bmRType_bReq, wValue, wIndex, wLength);
+	dump_msg(dev, pipe, buffer, transfer_len, "RH");
+	DBG("------------------------------------------------");
+
+	switch (bmRType_bReq) {
+	case RH_GET_STATUS:
+		DBG("RH_GET_STATUS");
+
+		*(__u16 *) data_buf = swap_16(1);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_INTERFACE:
+		DBG("RH_GET_STATUS | RH_INTERFACE");
+
+		*(__u16 *) data_buf = swap_16(0);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_ENDPOINT:
+		DBG("RH_GET_STATUS | RH_ENDPOINT");
+
+		*(__u16 *) data_buf = swap_16(0);
+		len = 2;
+		break;
+
+	case RH_GET_STATUS | RH_CLASS:
+		DBG("RH_GET_STATUS | RH_CLASS");
+
+		tmp = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+		*(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE));
+		len = 4;
+		break;
+
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+		DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS");
+
+		tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1);
+		*(__u32 *) data_buf = swap_32(tmp);
+		isp116x_show_regs(isp116x);
+		len = 4;
+		break;
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		DBG("RH_CLEAR_FEATURE | RH_ENDPOINT");
+
+		switch (wValue) {
+		case RH_ENDPOINT_STALL:
+			DBG("C_HUB_ENDPOINT_STALL");
+			len = 0;
+			break;
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		DBG("RH_CLEAR_FEATURE | RH_CLASS");
+
+		switch (wValue) {
+		case RH_C_HUB_LOCAL_POWER:
+			DBG("C_HUB_LOCAL_POWER");
+			len = 0;
+			break;
+
+		case RH_C_HUB_OVER_CURRENT:
+			DBG("C_HUB_OVER_CURRENT");
+			isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+			len = 0;
+			break;
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS");
+
+		switch (wValue) {
+		case RH_PORT_ENABLE:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_CCS);
+			len = 0;
+			break;
+
+		case RH_PORT_SUSPEND:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_POCI);
+			len = 0;
+			break;
+
+		case RH_PORT_POWER:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_LSDA);
+			len = 0;
+			break;
+
+		case RH_C_PORT_CONNECTION:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_CSC);
+			len = 0;
+			break;
+
+		case RH_C_PORT_ENABLE:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PESC);
+			len = 0;
+			break;
+
+		case RH_C_PORT_SUSPEND:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PSSC);
+			len = 0;
+			break;
+
+		case RH_C_PORT_OVER_CURRENT:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_POCI);
+			len = 0;
+			break;
+
+		case RH_C_PORT_RESET:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PRSC);
+			len = 0;
+			break;
+
+		default:
+			ERR("invalid wValue");
+			stat = USB_ST_STALLED;
+		}
+
+		isp116x_show_regs(isp116x);
+
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS");
+
+		switch (wValue) {
+		case RH_PORT_SUSPEND:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PSS);
+			len = 0;
+			break;
+
+		case RH_PORT_RESET:
+			/* Spin until any current reset finishes */
+			while (1) {
+				tmp =
+				    isp116x_read_reg32(isp116x,
+						       HCRHPORT1 + wIndex - 1);
+				if (!(tmp & RH_PS_PRS))
+					break;
+				wait_ms(1);
+			}
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PRS);
+			wait_ms(10);
+
+			len = 0;
+			break;
+
+		case RH_PORT_POWER:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PPS);
+			len = 0;
+			break;
+
+		case RH_PORT_ENABLE:
+			isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1,
+					    RH_PS_PES);
+			len = 0;
+			break;
+
+		default:
+			ERR("invalid wValue");
+			stat = USB_ST_STALLED;
+		}
+
+		isp116x_show_regs(isp116x);
+
+		break;
+
+	case RH_SET_ADDRESS:
+		DBG("RH_SET_ADDRESS");
+
+		rh_devnum = wValue;
+		len = 0;
+		break;
+
+	case RH_GET_DESCRIPTOR:
+		DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength);
+
+		switch (wValue) {
+		case (USB_DT_DEVICE << 8):	/* device descriptor */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_dev_des),
+						wLength));
+			data_buf = root_hub_dev_des;
+			break;
+
+		case (USB_DT_CONFIG << 8):	/* configuration descriptor */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_config_des),
+						wLength));
+			data_buf = root_hub_config_des;
+			break;
+
+		case ((USB_DT_STRING << 8) | 0x00):	/* string 0 descriptors */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_str_index0),
+						wLength));
+			data_buf = root_hub_str_index0;
+			break;
+
+		case ((USB_DT_STRING << 8) | 0x01):	/* string 1 descriptors */
+			len = min_t(unsigned int,
+				    leni, min_t(unsigned int,
+						sizeof(root_hub_str_index1),
+						wLength));
+			data_buf = root_hub_str_index1;
+			break;
+
+		default:
+			ERR("invalid wValue");
+			stat = USB_ST_STALLED;
+		}
+
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+		DBG("RH_GET_DESCRIPTOR | RH_CLASS");
+
+		tmp = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+		data_buf[0] = 0x09;	/* min length; */
+		data_buf[1] = 0x29;
+		data_buf[2] = tmp & RH_A_NDP;
+		data_buf[3] = 0;
+		if (tmp & RH_A_PSM)	/* per-port power switching? */
+			data_buf[3] |= 0x01;
+		if (tmp & RH_A_NOCP)	/* no overcurrent reporting? */
+			data_buf[3] |= 0x10;
+		else if (tmp & RH_A_OCPM)	/* per-port overcurrent rep? */
+			data_buf[3] |= 0x08;
+
+		/* Corresponds to data_buf[4-7] */
+		datab[1] = 0;
+		data_buf[5] = (tmp & RH_A_POTPGT) >> 24;
+
+		tmp = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+		data_buf[7] = tmp & RH_B_DR;
+		if (data_buf[2] < 7)
+			data_buf[8] = 0xff;
+		else {
+			data_buf[0] += 2;
+			data_buf[8] = (tmp & RH_B_DR) >> 8;
+			data_buf[10] = data_buf[9] = 0xff;
+		}
+
+		len = min_t(unsigned int, leni,
+			    min_t(unsigned int, data_buf[0], wLength));
+		break;
+
+	case RH_GET_CONFIGURATION:
+		DBG("RH_GET_CONFIGURATION");
+
+		*(__u8 *) data_buf = 0x01;
+		len = 1;
+		break;
+
+	case RH_SET_CONFIGURATION:
+		DBG("RH_SET_CONFIGURATION");
+
+		isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC);
+		len = 0;
+		break;
+
+	default:
+		ERR("*** *** *** unsupported root hub command *** *** ***");
+		stat = USB_ST_STALLED;
+	}
+
+	len = min_t(int, len, leni);
+	if (buffer != data_buf)
+		memcpy(buffer, data_buf, len);
+
+	dev->act_len = len;
+	dev->status = stat;
+	DBG("dev act_len %d, status %d", dev->act_len, dev->status);
+
+	dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)");
+
+	return stat;
+}
+
+/* --- Transfer functions -------------------------------------------------- */
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		   int len, int interval)
+{
+	DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d",
+	    dev, pipe, buffer, len, interval);
+
+	return -1;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		       int len, struct devrequest *setup)
+{
+	int devnum = usb_pipedevice(pipe);
+	int epnum = usb_pipeendpoint(pipe);
+	int max = max_transfer_len(dev, pipe);
+	int dir_in = usb_pipein(pipe);
+	int done, ret;
+
+	/* Control message is for the HUB? */
+	if (devnum == rh_devnum)
+		return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup);
+
+	/* Ok, no HUB message so send the message to the device */
+
+	/* Setup phase */
+	DBG("--- SETUP PHASE --------------------------------");
+	usb_settoggle(dev, epnum, 1, 0);
+	ret = isp116x_submit_job(dev, pipe,
+				 PTD_DIR_SETUP,
+				 setup, sizeof(struct devrequest));
+	if (ret < 0) {
+		DBG("control setup phase error (ret = %d", ret);
+		return -1;
+	}
+
+	/* Data phase */
+	DBG("--- DATA PHASE ---------------------------------");
+	done = 0;
+	usb_settoggle(dev, epnum, !dir_in, 1);
+	while (done < len) {
+		ret = isp116x_submit_job(dev, pipe,
+					 dir_in ? PTD_DIR_IN : PTD_DIR_OUT,
+					 (__u8 *) buffer + done,
+					 max > len - done ? len - done : max);
+		if (ret < 0) {
+			DBG("control data phase error (ret = %d)", ret);
+			return -1;
+		}
+		done += ret;
+
+		if (dir_in && ret < max)	/* short packet */
+			break;
+	}
+
+	/* Status phase */
+	DBG("--- STATUS PHASE -------------------------------");
+	usb_settoggle(dev, epnum, !dir_in, 1);
+	ret = isp116x_submit_job(dev, pipe,
+				 !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0);
+	if (ret < 0) {
+		DBG("control status phase error (ret = %d", ret);
+		return -1;
+	}
+
+	dev->act_len = done;
+
+	dump_msg(dev, pipe, buffer, len, "DEV(ret)");
+
+	return done;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		    int len)
+{
+	int dir_out = usb_pipeout(pipe);
+	int max = max_transfer_len(dev, pipe);
+	int done, ret;
+
+	DBG("--- BULK ---------------------------------------");
+	DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d",
+	    usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out);
+
+	done = 0;
+	while (done < len) {
+		ret = isp116x_submit_job(dev, pipe,
+					 !dir_out ? PTD_DIR_IN : PTD_DIR_OUT,
+					 (__u8 *) buffer + done,
+					 max > len - done ? len - done : max);
+		if (ret < 0) {
+			DBG("error on bulk message (ret = %d)", ret);
+			return -1;
+		}
+
+		done += ret;
+
+		if (!dir_out && ret < max)	/* short packet */
+			break;
+	}
+
+	dev->act_len = done;
+
+	return 0;
+}
+
+/* --- Basic functions ----------------------------------------------------- */
+
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+	int retries = 15;
+	int ret = 0;
+
+	DBG("");
+
+	isp116x->disabled = 1;
+
+	isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+	isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+	while (--retries) {
+		/* It usually resets within 1 ms */
+		wait_ms(1);
+		if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+			break;
+	}
+	if (!retries) {
+		ERR("software reset timeout");
+		ret = -1;
+	}
+	return ret;
+}
+
+static int isp116x_reset(struct isp116x *isp116x)
+{
+	unsigned long t;
+	u16 clkrdy = 0;
+	int ret, timeout = 15 /* ms */ ;
+
+	DBG("");
+
+	ret = isp116x_sw_reset(isp116x);
+	if (ret)
+		return ret;
+
+	for (t = 0; t < timeout; t++) {
+		clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+		if (clkrdy)
+			break;
+		wait_ms(1);
+	}
+	if (!clkrdy) {
+		ERR("clock not ready after %dms", timeout);
+		/* After sw_reset the clock won't report to be ready, if
+		   H_WAKEUP pin is high. */
+		ERR("please make sure that the H_WAKEUP pin is pulled low!");
+		ret = -1;
+	}
+	return ret;
+}
+
+static void isp116x_stop(struct isp116x *isp116x)
+{
+	u32 val;
+
+	DBG("");
+
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+	/* Switch off ports' power, some devices don't come up
+	   after next 'start' without this */
+	val = isp116x_read_reg32(isp116x, HCRHDESCA);
+	val &= ~(RH_A_NPS | RH_A_PSM);
+	isp116x_write_reg32(isp116x, HCRHDESCA, val);
+	isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+
+	isp116x_sw_reset(isp116x);
+}
+
+/*
+ *  Configure the chip. The chip must be successfully reset by now.
+ */
+static int isp116x_start(struct isp116x *isp116x)
+{
+	struct isp116x_platform_data *board = isp116x->board;
+	u32 val;
+
+	DBG("");
+
+	/* Clear interrupt status and disable all interrupt sources */
+	isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+	isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+	isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+	isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+	/* Hardware configuration */
+	val = HCHWCFG_DBWIDTH(1);
+	if (board->sel15Kres)
+		val |= HCHWCFG_15KRSEL;
+	/* Remote wakeup won't work without working clock */
+	if (board->remote_wakeup_enable)
+		val |= HCHWCFG_CLKNOTSTOP;
+	if (board->oc_enable)
+		val |= HCHWCFG_ANALOG_OC;
+	isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+	/* --- Root hub configuration */
+	val = (25 << 24) & RH_A_POTPGT;
+	/* AN10003_1.pdf recommends RH_A_NPS (no power switching) to
+	   be always set. Yet, instead, we request individual port
+	   power switching. */
+	val |= RH_A_PSM;
+	/* Report overcurrent per port */
+	val |= RH_A_OCPM;
+	isp116x_write_reg32(isp116x, HCRHDESCA, val);
+	isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+	val = RH_B_PPCM;
+	isp116x_write_reg32(isp116x, HCRHDESCB, val);
+	isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+	val = 0;
+	if (board->remote_wakeup_enable)
+		val |= RH_HS_DRWE;
+	isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+	isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+	isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+	/* Go operational */
+	val = HCCONTROL_USB_OPER;
+	if (board->remote_wakeup_enable)
+		val |= HCCONTROL_RWE;
+	isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+	/* Disable ports to avoid race in device enumeration */
+	isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+	isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+	isp116x_show_regs(isp116x);
+
+	isp116x->disabled = 0;
+
+	return 0;
+}
+
+/* --- Init functions ------------------------------------------------------ */
+
+int isp116x_check_id(struct isp116x *isp116x)
+{
+	int val;
+
+	val = isp116x_read_reg16(isp116x, HCCHIPID);
+	if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+		ERR("invalid chip ID %04x", val);
+		return -1;
+	}
+
+	return 0;
+}
+
+int usb_lowlevel_init(void)
+{
+	struct isp116x *isp116x = &isp116x_dev;
+
+	DBG("");
+
+	/* Init device registers addr */
+	isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR;
+	isp116x->data_reg = (u16 *) ISP116X_HCD_DATA;
+
+	/* Setup specific board settings */
+#ifdef ISP116X_HCD_SEL15kRES
+	isp116x_board.sel15Kres = 1;
+#endif
+#ifdef ISP116X_HCD_OC_ENABLE
+	isp116x_board.oc_enable = 1;
+#endif
+#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE
+	isp116x_board.remote_wakeup_enable = 1;
+#endif
+	isp116x->board = &isp116x_board;
+
+	/* Try to get ISP116x silicon chip ID */
+	if (isp116x_check_id(isp116x) < 0)
+		return -1;
+
+	isp116x->disabled = 1;
+	isp116x->sleeping = 0;
+
+	isp116x_reset(isp116x);
+	isp116x_start(isp116x);
+
+	return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+	struct isp116x *isp116x = &isp116x_dev;
+
+	DBG("");
+
+	if (!isp116x->disabled)
+		isp116x_stop(isp116x);
+
+	return 0;
+}
+
+#endif				/* CONFIG_USB_ISP116X_HCD */
diff --git a/drivers/isp116x.h b/drivers/isp116x.h
new file mode 100644
index 0000000..a3ce3b5
--- /dev/null
+++ b/drivers/isp116x.h
@@ -0,0 +1,489 @@
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef DEBUG
+#define DBG(fmt, args...)	\
+		printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#else
+#define DBG(fmt, args...)	do {} while (0)
+#endif
+
+#ifdef VERBOSE
+#    define VDBG		DBG
+#else
+#    define VDBG(fmt, args...)	do {} while (0)
+#endif
+
+#define ERR(fmt, args...)	\
+		printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define WARN(fmt, args...)	\
+		printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args)
+#define INFO(fmt, args...)	\
+		printf("isp116x: " fmt "\n" , ## args)
+
+/* ------------------------------------------------------------------------- */
+
+/* us of 1ms frame */
+#define  MAX_LOAD_LIMIT		850
+
+/* Full speed: max # of bytes to transfer for a single urb
+   at a time must be < 1024 && must be multiple of 64.
+   832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED	832
+
+/* Low speed: there is no reason to schedule in very big
+   chunks; often the requested long transfers are for
+   string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED	64
+
+/* Bytetime (us), a rough indication of how much time it
+   would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED	1
+#define BYTE_TIME_LOWSPEED	20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE	4096
+#define ISP116x_ITL_BUFSIZE	0
+#define ISP116x_ATL_BUFSIZE	((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET	0x80
+
+/* --- ISP116x registers/bits ---------------------------------------------- */
+
+#define	HCREVISION	0x00
+#define	HCCONTROL	0x01
+#define		HCCONTROL_HCFS	(3 << 6)	/* host controller
+						   functional state */
+#define		HCCONTROL_USB_RESET	(0 << 6)
+#define		HCCONTROL_USB_RESUME	(1 << 6)
+#define		HCCONTROL_USB_OPER	(2 << 6)
+#define		HCCONTROL_USB_SUSPEND	(3 << 6)
+#define		HCCONTROL_RWC	(1 << 9)	/* remote wakeup connected */
+#define		HCCONTROL_RWE	(1 << 10)	/* remote wakeup enable */
+#define	HCCMDSTAT	0x02
+#define		HCCMDSTAT_HCR	(1 << 0)	/* host controller reset */
+#define		HCCMDSTAT_SOC	(3 << 16)	/* scheduling overrun count */
+#define	HCINTSTAT	0x03
+#define		HCINT_SO	(1 << 0)	/* scheduling overrun */
+#define		HCINT_WDH	(1 << 1)	/* writeback of done_head */
+#define		HCINT_SF	(1 << 2)	/* start frame */
+#define		HCINT_RD	(1 << 3)	/* resume detect */
+#define		HCINT_UE	(1 << 4)	/* unrecoverable error */
+#define		HCINT_FNO	(1 << 5)	/* frame number overflow */
+#define		HCINT_RHSC	(1 << 6)	/* root hub status change */
+#define		HCINT_OC	(1 << 30)	/* ownership change */
+#define		HCINT_MIE	(1 << 31)	/* master interrupt enable */
+#define	HCINTENB	0x04
+#define	HCINTDIS	0x05
+#define	HCFMINTVL	0x0d
+#define	HCFMREM		0x0e
+#define	HCFMNUM		0x0f
+#define	HCLSTHRESH	0x11
+#define	HCRHDESCA	0x12
+#define		RH_A_NDP	(0x3 << 0)	/* # downstream ports */
+#define		RH_A_PSM	(1 << 8)	/* power switching mode */
+#define		RH_A_NPS	(1 << 9)	/* no power switching */
+#define		RH_A_DT		(1 << 10)	/* device type (mbz) */
+#define		RH_A_OCPM	(1 << 11)	/* overcurrent protection
+						   mode */
+#define		RH_A_NOCP	(1 << 12)	/* no overcurrent protection */
+#define		RH_A_POTPGT	(0xff << 24)	/* power on -> power good
+						   time */
+#define	HCRHDESCB	0x13
+#define		RH_B_DR		(0xffff << 0)	/* device removable flags */
+#define		RH_B_PPCM	(0xffff << 16)	/* port power control mask */
+#define	HCRHSTATUS	0x14
+#define		RH_HS_LPS	(1 << 0)	/* local power status */
+#define		RH_HS_OCI	(1 << 1)	/* over current indicator */
+#define		RH_HS_DRWE	(1 << 15)	/* device remote wakeup
+						   enable */
+#define		RH_HS_LPSC	(1 << 16)	/* local power status change */
+#define		RH_HS_OCIC	(1 << 17)	/* over current indicator
+						   change */
+#define		RH_HS_CRWE	(1 << 31)	/* clear remote wakeup
+						   enable */
+#define	HCRHPORT1	0x15
+#define		RH_PS_CCS	(1 << 0)	/* current connect status */
+#define		RH_PS_PES	(1 << 1)	/* port enable status */
+#define		RH_PS_PSS	(1 << 2)	/* port suspend status */
+#define		RH_PS_POCI	(1 << 3)	/* port over current
+						   indicator */
+#define		RH_PS_PRS	(1 << 4)	/* port reset status */
+#define		RH_PS_PPS	(1 << 8)	/* port power status */
+#define		RH_PS_LSDA	(1 << 9)	/* low speed device attached */
+#define		RH_PS_CSC	(1 << 16)	/* connect status change */
+#define		RH_PS_PESC	(1 << 17)	/* port enable status change */
+#define		RH_PS_PSSC	(1 << 18)	/* port suspend status
+						   change */
+#define		RH_PS_OCIC	(1 << 19)	/* over current indicator
+						   change */
+#define		RH_PS_PRSC	(1 << 20)	/* port reset status change */
+#define		HCRHPORT_CLRMASK	(0x1f << 16)
+#define	HCRHPORT2	0x16
+#define	HCHWCFG		0x20
+#define		HCHWCFG_15KRSEL		(1 << 12)
+#define		HCHWCFG_CLKNOTSTOP	(1 << 11)
+#define		HCHWCFG_ANALOG_OC	(1 << 10)
+#define		HCHWCFG_DACK_MODE	(1 << 8)
+#define		HCHWCFG_EOT_POL		(1 << 7)
+#define		HCHWCFG_DACK_POL	(1 << 6)
+#define		HCHWCFG_DREQ_POL	(1 << 5)
+#define		HCHWCFG_DBWIDTH_MASK	(0x03 << 3)
+#define		HCHWCFG_DBWIDTH(n)	(((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define		HCHWCFG_INT_POL		(1 << 2)
+#define		HCHWCFG_INT_TRIGGER	(1 << 1)
+#define		HCHWCFG_INT_ENABLE	(1 << 0)
+#define	HCDMACFG	0x21
+#define		HCDMACFG_BURST_LEN_MASK	(0x03 << 5)
+#define		HCDMACFG_BURST_LEN(n)	(((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define		HCDMACFG_BURST_LEN_1	HCDMACFG_BURST_LEN(0)
+#define		HCDMACFG_BURST_LEN_4	HCDMACFG_BURST_LEN(1)
+#define		HCDMACFG_BURST_LEN_8	HCDMACFG_BURST_LEN(2)
+#define		HCDMACFG_DMA_ENABLE	(1 << 4)
+#define		HCDMACFG_BUF_TYPE_MASK	(0x07 << 1)
+#define		HCDMACFG_CTR_SEL	(1 << 2)
+#define		HCDMACFG_ITLATL_SEL	(1 << 1)
+#define		HCDMACFG_DMA_RW_SELECT	(1 << 0)
+#define	HCXFERCTR	0x22
+#define	HCuPINT		0x24
+#define		HCuPINT_SOF		(1 << 0)
+#define		HCuPINT_ATL		(1 << 1)
+#define		HCuPINT_AIIEOT		(1 << 2)
+#define		HCuPINT_OPR		(1 << 4)
+#define		HCuPINT_SUSP		(1 << 5)
+#define		HCuPINT_CLKRDY		(1 << 6)
+#define	HCuPINTENB	0x25
+#define	HCCHIPID	0x27
+#define		HCCHIPID_MASK		0xff00
+#define		HCCHIPID_MAGIC		0x6100
+#define	HCSCRATCH	0x28
+#define	HCSWRES		0x29
+#define		HCSWRES_MAGIC		0x00f6
+#define	HCITLBUFLEN	0x2a
+#define	HCATLBUFLEN	0x2b
+#define	HCBUFSTAT	0x2c
+#define		HCBUFSTAT_ITL0_FULL	(1 << 0)
+#define		HCBUFSTAT_ITL1_FULL	(1 << 1)
+#define		HCBUFSTAT_ATL_FULL	(1 << 2)
+#define		HCBUFSTAT_ITL0_DONE	(1 << 3)
+#define		HCBUFSTAT_ITL1_DONE	(1 << 4)
+#define		HCBUFSTAT_ATL_DONE	(1 << 5)
+#define	HCRDITL0LEN	0x2d
+#define	HCRDITL1LEN	0x2e
+#define	HCITLPORT	0x40
+#define	HCATLPORT	0x41
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p)	(((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v)		(((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p)	(((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v)		(((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p)	(((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v)		(((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p)		(((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v)		(((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p)		(((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v)		(((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p)		(((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v)		(((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p)		(((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v)		(((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p)		(((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v)		(((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p)		(((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v)		(((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p)		(((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v)		(((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p)		(((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v)		(((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p)		(((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v)		(((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p)		(((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v)		(((v) << 7) & PTD_FMT_MSK)
+
+/*  Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+    /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+    /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED     0x0F
+
+/* ------------------------------------------------------------------------- */
+
+#define	LOG2_PERIODIC_SIZE	5	/* arbitrary; this matches OHCI */
+#define	PERIODIC_SIZE		(1 << LOG2_PERIODIC_SIZE)
+
+/* Philips transfer descriptor */
+struct ptd {
+	u16 count;
+#define	PTD_COUNT_MSK	(0x3ff << 0)
+#define	PTD_TOGGLE_MSK	(1 << 10)
+#define	PTD_ACTIVE_MSK	(1 << 11)
+#define	PTD_CC_MSK	(0xf << 12)
+	u16 mps;
+#define	PTD_MPS_MSK	(0x3ff << 0)
+#define	PTD_SPD_MSK	(1 << 10)
+#define	PTD_LAST_MSK	(1 << 11)
+#define	PTD_EP_MSK	(0xf << 12)
+	u16 len;
+#define	PTD_LEN_MSK	(0x3ff << 0)
+#define	PTD_DIR_MSK	(3 << 10)
+#define	PTD_DIR_SETUP	(0)
+#define	PTD_DIR_OUT	(1)
+#define	PTD_DIR_IN	(2)
+#define	PTD_B5_5_MSK	(1 << 13)
+	u16 faddr;
+#define	PTD_FA_MSK	(0x7f << 0)
+#define	PTD_FMT_MSK	(1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+struct isp116x_ep {
+	struct usb_device *udev;
+	struct ptd ptd;
+
+	u8 maxpacket;
+	u8 epnum;
+	u8 nextpid;
+
+	u16 length;		/* of current packet */
+	unsigned char *data;	/* to databuf */
+
+	u16 error_count;
+};
+
+/* URB struct */
+#define N_URB_TD		48
+#define URB_DEL			1
+typedef struct {
+	struct isp116x_ep *ed;
+	void *transfer_buffer;	/* (in) associated data buffer */
+	int actual_length;	/* (return) actual transfer length */
+	unsigned long pipe;	/* (in) pipe information */
+#if 0
+	int state;
+#endif
+} urb_priv_t;
+
+struct isp116x_platform_data {
+	/* Enable internal resistors on downstream ports */
+	unsigned sel15Kres:1;
+	/* On-chip overcurrent detection */
+	unsigned oc_enable:1;
+	/* Enable wakeup by devices on usb bus (e.g. wakeup
+	   by attachment/detachment or by device activity
+	   such as moving a mouse). When chosen, this option
+	   prevents stopping internal clock, increasing
+	   thereby power consumption in suspended state. */
+	unsigned remote_wakeup_enable:1;
+};
+
+struct isp116x {
+	u16 *addr_reg;
+	u16 *data_reg;
+
+	struct isp116x_platform_data *board;
+
+	struct dentry *dentry;
+	unsigned long stat1, stat2, stat4, stat8, stat16;
+
+	/* Status flags */
+	unsigned disabled:1;
+	unsigned sleeping:1;
+
+	/* Root hub registers */
+	u32 rhdesca;
+	u32 rhdescb;
+	u32 rhstatus;
+	u32 rhport[2];
+
+	/* Schedule for the current frame */
+	struct isp116x_ep *atl_active;
+	int atl_buflen;
+	int atl_bufshrt;
+	int atl_last_dir;
+	int atl_finishing;
+};
+
+/* ------------------------------------------------- */
+
+/* Inter-io delay (ns). The chip is picky about access timings; it
+ * expects at least:
+ * 150ns delay between consecutive accesses to DATA_REG,
+ * 300ns delay between access to ADDR_REG and DATA_REG
+ * OE, WE MUST NOT be changed during these intervals
+ */
+#if defined(UDELAY)
+#define	isp116x_delay(h,d)	udelay(d)
+#else
+#define	isp116x_delay(h,d)	do {} while (0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+	writew(reg & 0xff, isp116x->addr_reg);
+	isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+	writew(val, isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+	__raw_writew(val, isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+	u16 val;
+
+	val = readw(isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+	return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+	u16 val;
+
+	val = __raw_readw(isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+	return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+	writew(val & 0xffff, isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+	writew(val >> 16, isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+	u32 val;
+
+	val = (u32) readw(isp116x->data_reg);
+	isp116x_delay(isp116x, UDELAY);
+	val |= ((u32) readw(isp116x->data_reg)) << 16;
+	isp116x_delay(isp116x, UDELAY);
+	return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+   we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+	isp116x_write_addr(isp116x, reg);
+	return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+	isp116x_write_addr(isp116x, reg);
+	return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+				unsigned val)
+{
+	isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+	isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+				unsigned val)
+{
+	isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+	isp116x_write_data32(isp116x, (u32) val);
+}
+
+/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */
+
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS          0x0500
+#define RH_GET_DESCRIPTOR       0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION    0x0880
+#define RH_SET_CONFIGURATION    0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
diff --git a/drivers/lan91c96.c b/drivers/lan91c96.c
index a50c5f0..ecdcbd9 100644
--- a/drivers/lan91c96.c
+++ b/drivers/lan91c96.c
@@ -65,7 +65,7 @@
 
 #ifdef CONFIG_DRIVER_LAN91C96
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_CMD_NET)
 
 /*------------------------------------------------------------------------
  *
diff --git a/drivers/macb.c b/drivers/macb.c
index 186ab19..95cdc49 100644
--- a/drivers/macb.c
+++ b/drivers/macb.c
@@ -17,7 +17,8 @@
  */
 #include <common.h>
 
-#if defined(CONFIG_MACB) && (CONFIG_COMMANDS & (CFG_CMD_NET | CFG_CMD_MII))
+#if defined(CONFIG_MACB) \
+	&& (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII))
 
 /*
  * The u-boot networking stack is a little weird.  It seems like the
@@ -51,6 +52,8 @@
 
 #include "macb.h"
 
+#define barrier() asm volatile("" ::: "memory")
+
 #define CFG_MACB_RX_BUFFER_SIZE		4096
 #define CFG_MACB_RX_RING_SIZE		(CFG_MACB_RX_BUFFER_SIZE / 128)
 #define CFG_MACB_TX_RING_SIZE		16
@@ -163,7 +166,7 @@
 	return MACB_BFEXT(DATA, frame);
 }
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_CMD_NET)
 
 static int macb_send(struct eth_device *netdev, volatile void *packet,
 		     int length)
@@ -185,31 +188,31 @@
 
 	macb->tx_ring[tx_head].ctrl = ctrl;
 	macb->tx_ring[tx_head].addr = paddr;
+	barrier();
 	macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
 
 	/*
 	 * I guess this is necessary because the networking core may
 	 * re-use the transmit buffer as soon as we return...
 	 */
-	i = 0;
-	while (!(macb->tx_ring[tx_head].ctrl & TXBUF_USED)) {
-		if (i > CFG_MACB_TX_TIMEOUT) {
-			printf("%s: TX timeout\n", netdev->name);
+	for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
+		barrier();
+		ctrl = macb->tx_ring[tx_head].ctrl;
+		if (ctrl & TXBUF_USED)
 			break;
-		}
 		udelay(1);
-		i++;
 	}
 
 	dma_unmap_single(packet, length, paddr);
 
 	if (i <= CFG_MACB_TX_TIMEOUT) {
-		ctrl = macb->tx_ring[tx_head].ctrl;
 		if (ctrl & TXBUF_UNDERRUN)
 			printf("%s: TX underrun\n", netdev->name);
 		if (ctrl & TXBUF_EXHAUSTED)
 			printf("%s: TX buffers exhausted in mid frame\n",
 			       netdev->name);
+	} else {
+		printf("%s: TX timeout\n", netdev->name);
 	}
 
 	/* No one cares anyway */
@@ -234,6 +237,7 @@
 		i++;
 	}
 
+	barrier();
 	macb->rx_tail = new_tail;
 }
 
@@ -283,11 +287,38 @@
 				rx_tail = 0;
 			}
 		}
+		barrier();
 	}
 
 	return 0;
 }
 
+static void macb_phy_reset(struct macb_device *macb)
+{
+	struct eth_device *netdev = &macb->netdev;
+	int i;
+	u16 status, adv;
+
+	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+	macb_mdio_write(macb, MII_ADVERTISE, adv);
+	printf("%s: Starting autonegotiation...\n", netdev->name);
+	macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+					 | BMCR_ANRESTART));
+
+	for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+		status = macb_mdio_read(macb, MII_BMSR);
+		if (status & BMSR_ANEGCOMPLETE)
+			break;
+		udelay(100);
+	}
+
+	if (status & BMSR_ANEGCOMPLETE)
+		printf("%s: Autonegotiation complete\n", netdev->name);
+	else
+		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+		       netdev->name, status);
+}
+
 static int macb_phy_init(struct macb_device *macb)
 {
 	struct eth_device *netdev = &macb->netdev;
@@ -303,36 +334,16 @@
 		return 0;
 	}
 
-	adv = ADVERTISE_CSMA | ADVERTISE_ALL;
-	macb_mdio_write(macb, MII_ADVERTISE, adv);
-	printf("%s: Starting autonegotiation...\n", netdev->name);
-	macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
-					 | BMCR_ANRESTART));
-
-#if 0
-	for (i = 0; i < 9; i++)
-		printf("mii%d: 0x%04x\n", i, macb_mdio_read(macb, i));
-#endif
-
-	for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
-		status = macb_mdio_read(macb, MII_BMSR);
-		if (status & BMSR_ANEGCOMPLETE)
-			break;
-		udelay(100);
-	}
-
-	if (status & BMSR_ANEGCOMPLETE)
-		printf("%s: Autonegotiation complete\n", netdev->name);
-	else
-		printf("%s: Autonegotiation timed out (status=0x%04x)\n",
-		       netdev->name, status);
-
+	status = macb_mdio_read(macb, MII_BMSR);
 	if (!(status & BMSR_LSTATUS)) {
+		/* Try to re-negotiate if we don't have link already. */
+		macb_phy_reset(macb);
+
 		for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
-			udelay(100);
 			status = macb_mdio_read(macb, MII_BMSR);
 			if (status & BMSR_LSTATUS)
 				break;
+			udelay(100);
 		}
 	}
 
@@ -341,6 +352,7 @@
 		       netdev->name, status);
 		return 0;
 	} else {
+		adv = macb_mdio_read(macb, MII_ADVERTISE);
 		lpa = macb_mdio_read(macb, MII_LPA);
 		media = mii_nway_result(lpa & adv);
 		speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
@@ -492,9 +504,9 @@
 	return 0;
 }
 
-#endif /* (CONFIG_COMMANDS & CFG_CMD_NET) */
+#endif
 
-#if (CONFIG_COMMANDS & CFG_CMD_MII)
+#if defined(CONFIG_CMD_MII)
 
 int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
 {
@@ -570,6 +582,6 @@
 	return 0;
 }
 
-#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) */
+#endif
 
 #endif /* CONFIG_MACB */
diff --git a/drivers/mpc8xx_pcmcia.c b/drivers/mpc8xx_pcmcia.c
index 399a719..8a34cd3 100644
--- a/drivers/mpc8xx_pcmcia.c
+++ b/drivers/mpc8xx_pcmcia.c
@@ -6,11 +6,11 @@
 
 #undef	CONFIG_PCMCIA
 
-#if	(CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 #define	CONFIG_PCMCIA
 #endif
 
-#if	(CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
 #define	CONFIG_PCMCIA
 #endif
 
@@ -23,7 +23,7 @@
 extern int pcmcia_hardware_enable (int slot);
 extern int pcmcia_voltage_set(int slot, int vcc, int vpp);
 
-#if	(CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 extern int pcmcia_hardware_disable(int slot);
 #endif
 
@@ -189,7 +189,7 @@
 	return rc;
 }
 
-#if	(CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 int pcmcia_off (void)
 {
 	int i;
@@ -221,7 +221,7 @@
 	pcmcia_hardware_disable(_slot_);
 	return 0;
 }
-#endif	/* CFG_CMD_PCMCIA */
+#endif
 
 
 static u_int m8xx_get_graycode(u_int size)
diff --git a/drivers/nand/nand.c b/drivers/nand/nand.c
index 9fef71d..27b5792 100644
--- a/drivers/nand/nand.c
+++ b/drivers/nand/nand.c
@@ -23,7 +23,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include <nand.h>
 
diff --git a/drivers/nand/nand_base.c b/drivers/nand/nand_base.c
index c6fee18..151f535 100644
--- a/drivers/nand/nand_base.c
+++ b/drivers/nand/nand_base.c
@@ -72,7 +72,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include <malloc.h>
 #include <watchdog.h>
diff --git a/drivers/nand/nand_bbt.c b/drivers/nand/nand_bbt.c
index aaa9400..19a9bc2 100644
--- a/drivers/nand/nand_bbt.c
+++ b/drivers/nand/nand_bbt.c
@@ -54,7 +54,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include <malloc.h>
 #include <linux/mtd/compat.h>
diff --git a/drivers/nand/nand_ecc.c b/drivers/nand/nand_ecc.c
index 90274e6..4c532b0 100644
--- a/drivers/nand/nand_ecc.c
+++ b/drivers/nand/nand_ecc.c
@@ -37,7 +37,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include<linux/mtd/mtd.h>
 
@@ -197,4 +197,4 @@
 	return -1;
 }
 
-#endif	/* CONFIG_COMMANDS & CFG_CMD_NAND */
+#endif
diff --git a/drivers/nand/nand_ids.c b/drivers/nand/nand_ids.c
index 8b58736..075cae6 100644
--- a/drivers/nand/nand_ids.c
+++ b/drivers/nand/nand_ids.c
@@ -13,7 +13,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include <linux/mtd/nand.h>
 
diff --git a/drivers/nand/nand_util.c b/drivers/nand/nand_util.c
index 10bf036..cf05043 100644
--- a/drivers/nand/nand_util.c
+++ b/drivers/nand/nand_util.c
@@ -32,11 +32,12 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY)
 
 #include <command.h>
 #include <watchdog.h>
 #include <malloc.h>
+#include <div64.h>
 
 #include <nand.h>
 #include <jffs2/jffs2.h>
@@ -208,10 +209,10 @@
 		}
 
 		if (!opts->quiet) {
-			int percent = (int)
-				((unsigned long long)
+			unsigned long long n =(unsigned long long)
 				 (erase.addr+meminfo->erasesize-opts->offset)
-				 * 100 / erase_length);
+				 * 100;
+			int percent = (int)do_div(n, erase_length);
 
 			/* output progress message only at whole percent
 			 * steps to reduce the number of messages printed
@@ -475,10 +476,9 @@
 		imglen -= readlen;
 
 		if (!opts->quiet) {
-			int percent = (int)
-				((unsigned long long)
-				 (opts->length-imglen) * 100
-				 / opts->length);
+			unsigned long long n = (unsigned long long)
+				 (opts->length-imglen) * 100;
+			int percent = (int)do_div(n, opts->length);
 			/* output progress message only at whole percent
 			 * steps to reduce the number of messages printed
 			 * on (slow) serial consoles
@@ -651,10 +651,9 @@
 		}
 
 		if (!opts->quiet) {
-			int percent = (int)
-				((unsigned long long)
-				 (opts->length-imglen) * 100
-				 / opts->length);
+			unsigned long long n = (unsigned long long)
+				 (opts->length-imglen) * 100;
+			int percent = (int)do_div(n ,opts->length);
 			/* output progress message only at whole percent
 			 * steps to reduce the number of messages printed
 			 * on (slow) serial consoles
@@ -859,4 +858,4 @@
 	return ret;
 }
 
-#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */
+#endif
diff --git a/drivers/nand_legacy/nand_legacy.c b/drivers/nand_legacy/nand_legacy.c
index 458046d..49d2ebb 100644
--- a/drivers/nand_legacy/nand_legacy.c
+++ b/drivers/nand_legacy/nand_legacy.c
@@ -15,14 +15,7 @@
 #include <asm/io.h>
 #include <watchdog.h>
 
-#ifdef CONFIG_SHOW_BOOT_PROGRESS
-# include <status_led.h>
-# define SHOW_BOOT_PROGRESS(arg)	show_boot_progress(arg)
-#else
-# define SHOW_BOOT_PROGRESS(arg)
-#endif
-
-#if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY)
+#if defined(CONFIG_CMD_NAND) && defined(CFG_NAND_LEGACY)
 
 #include <linux/mtd/nand_legacy.h>
 #include <linux/mtd/nand_ids.h>
@@ -1616,4 +1609,4 @@
 }
 #endif /* CONFIG_JFFS2_NAND */
 
-#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && defined(CFG_NAND_LEGACY) */
+#endif
diff --git a/drivers/natsemi.c b/drivers/natsemi.c
index b009db6..075d6c5 100644
--- a/drivers/natsemi.c
+++ b/drivers/natsemi.c
@@ -56,8 +56,8 @@
 #include <asm/io.h>
 #include <pci.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
-	defined(CONFIG_NATSEMI)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_NATSEMI)
 
 /* defines */
 #define EEPROM_SIZE 0xb /*12 16-bit chunks, or 24 bytes*/
diff --git a/drivers/netarm_eth.c b/drivers/netarm_eth.c
index 89b3a83..a99ee5d 100644
--- a/drivers/netarm_eth.c
+++ b/drivers/netarm_eth.c
@@ -30,7 +30,7 @@
 #include <asm/arch/netarm_registers.h>
 
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_CMD_NET)
 
 static int na_mii_poll_busy (void);
 
diff --git a/drivers/ns8382x.c b/drivers/ns8382x.c
index 976f86a..f8b143a 100644
--- a/drivers/ns8382x.c
+++ b/drivers/ns8382x.c
@@ -56,8 +56,8 @@
 #include <asm/io.h>
 #include <pci.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
-	defined(CONFIG_NS8382X)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_NS8382X)
 
 /* defines */
 #define DSIZE     0x00000FFF
diff --git a/drivers/pci.c b/drivers/pci.c
index 050582f..4158919 100644
--- a/drivers/pci.c
+++ b/drivers/pci.c
@@ -490,10 +490,16 @@
 
 int pci_hose_scan(struct pci_controller *hose)
 {
+	/* Start scan at current_busno.
+	 * PCIe will start scan at first_busno+1.
+	 */
+	/* For legacy support, ensure current>=first */
+	if (hose->first_busno > hose->current_busno)
+		hose->current_busno = hose->first_busno;
 #ifdef CONFIG_PCI_PNP
 	pciauto_config_init(hose);
 #endif
-	return pci_hose_scan_bus(hose, hose->first_busno);
+	return pci_hose_scan_bus(hose, hose->current_busno);
 }
 
 void pci_init(void)
diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c
index f170c2d..2378553 100644
--- a/drivers/pci_auto.c
+++ b/drivers/pci_auto.c
@@ -65,7 +65,7 @@
 
 	res->bus_lower = addr + size;
 
-	DEBUGF("address=0x%lx", addr);
+	DEBUGF("address=0x%lx bus_lower=%x", addr, res->bus_lower);
 
 	*bar = addr;
 	return 0;
@@ -94,7 +94,7 @@
 	pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
 	cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER;
 
-	for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) {
+	for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) {
 		/* Tickle the BAR and get the response */
 		pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
 		pci_hose_read_config_dword(hose, dev, bar, &bar_response);
@@ -154,7 +154,7 @@
 	pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
 }
 
-static void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
 					 pci_dev_t dev, int sub_bus)
 {
 	struct pci_region *pci_mem = hose->pci_mem;
@@ -165,8 +165,10 @@
 	pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
 
 	/* Configure bus number registers */
-	pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS, PCI_BUS(dev));
-	pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS, sub_bus);
+	pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS,
+				   PCI_BUS(dev) - hose->first_busno);
+	pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS,
+				   sub_bus - hose->first_busno);
 	pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff);
 
 	if (pci_mem) {
@@ -211,7 +213,7 @@
 	pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
 }
 
-static void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
 					  pci_dev_t dev, int sub_bus)
 {
 	struct pci_region *pci_mem = hose->pci_mem;
@@ -219,7 +221,8 @@
 	struct pci_region *pci_io = hose->pci_io;
 
 	/* Configure bus number registers */
-	pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, sub_bus);
+	pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
+				   sub_bus - hose->first_busno);
 
 	if (pci_mem) {
 		/* Round memory allocator to 1MB boundary */
@@ -282,25 +285,36 @@
 	if (hose->pci_mem) {
 		pciauto_region_init(hose->pci_mem);
 
-		DEBUGF("PCI Autoconfig: Memory region: [%lx-%lx]\n",
+		DEBUGF("PCI Autoconfig: Bus Memory region: [%lx-%lx],\n"
+		       "\t\tPhysical Memory [%x-%x]\n",
 		    hose->pci_mem->bus_start,
-		    hose->pci_mem->bus_start + hose->pci_mem->size - 1);
+		    hose->pci_mem->bus_start + hose->pci_mem->size - 1,
+		    hose->pci_mem->phys_start,
+		    hose->pci_mem->phys_start + hose->pci_mem->size - 1);
 	}
 
 	if (hose->pci_prefetch) {
 		pciauto_region_init(hose->pci_prefetch);
 
-		DEBUGF("PCI Autoconfig: Prefetchable Memory region: [%lx-%lx]\n",
+		DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [%lx-%lx],\n"
+		       "\t\tPhysical Memory [%x-%x]\n",
 		    hose->pci_prefetch->bus_start,
-		    hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1);
+		    hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1,
+		    hose->pci_prefetch->phys_start,
+		    hose->pci_prefetch->phys_start +
+				hose->pci_prefetch->size - 1);
 	}
 
 	if (hose->pci_io) {
 		pciauto_region_init(hose->pci_io);
 
-		DEBUGF("PCI Autoconfig: I/O region: [%lx-%lx]\n",
+		DEBUGF("PCI Autoconfig: Bus I/O region: [%lx-%lx],\n"
+		       "\t\tPhysical Memory: [%x-%x]\n",
 		    hose->pci_io->bus_start,
-		    hose->pci_io->bus_start + hose->pci_io->size - 1);
+		    hose->pci_io->bus_start + hose->pci_io->size - 1,
+		    hose->pci_io->phys_start,
+		    hose->pci_io->phys_start + hose->pci_io->size - 1);
+
 	}
 }
 
@@ -317,6 +331,12 @@
 	pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
 
 	switch(class) {
+	case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+		DEBUGF("PCI AutoConfig: Found PowerPC device\n");
+		pciauto_setup_device(hose, dev, 6, hose->pci_mem,
+				     hose->pci_prefetch, hose->pci_io);
+		break;
+
 	case PCI_CLASS_BRIDGE_PCI:
 		hose->current_busno++;
 		pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
diff --git a/drivers/pci_indirect.c b/drivers/pci_indirect.c
index d7be081..a8220fb 100644
--- a/drivers/pci_indirect.c
+++ b/drivers/pci_indirect.c
@@ -45,7 +45,7 @@
 	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	 \
 	return 0;    					 		 \
 }
-#elif defined(CONFIG_E500)
+#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
 #define INDIRECT_PCI_OP(rw, size, type, op, mask)                        \
 static int                                                               \
 indirect_##rw##_config_##size(struct pci_controller *hose,               \
@@ -55,7 +55,7 @@
 	b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev);		 \
 	b = b - hose->first_busno;					 \
 	dev = PCI_BDF(b, d, f);						 \
-	*(hose->cfg_addr) = dev | (offset & 0xfc) | 0x80000000;          \
+	*(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
 	sync();                                                          \
 	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);       \
 	return 0;                                                        \
diff --git a/drivers/pcnet.c b/drivers/pcnet.c
index da9ac7f..2af0e8f 100644
--- a/drivers/pcnet.c
+++ b/drivers/pcnet.c
@@ -45,8 +45,8 @@
 #define PCNET_DEBUG2(fmt,args...)
 #endif
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
-    && defined(CONFIG_PCNET)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_PCNET)
 
 #if !defined(CONF_PCNET_79C973) && defined(CONF_PCNET_79C975)
 #error "Macro for PCnet chip version is not defined!"
diff --git a/drivers/plb2800_eth.c b/drivers/plb2800_eth.c
index 4c683d7..0ae5d80 100644
--- a/drivers/plb2800_eth.c
+++ b/drivers/plb2800_eth.c
@@ -25,8 +25,8 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
-	&& defined(CONFIG_PLB2800_ETHER)
+#if defined(CONFIG_CMD_NET) \
+	&& defined(CONFIG_NET_MULTI) && defined(CONFIG_PLB2800_ETHER)
 
 #include <malloc.h>
 #include <net.h>
diff --git a/drivers/pxa_pcmcia.c b/drivers/pxa_pcmcia.c
index d9d38bb..6020e46 100644
--- a/drivers/pxa_pcmcia.c
+++ b/drivers/pxa_pcmcia.c
@@ -85,7 +85,7 @@
 	return rc;
 }
 
-#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 int pcmcia_off (void)
 {
 	return 0;
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 5f20962..0f5232a 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -98,7 +98,7 @@
 	out_be32(&p->sdaqmr, 0);
 
 	/* Allocate 2KB temporary buffer for sdma */
-	sdma_buffer_base = qe_muram_alloc(2048, 64);
+	sdma_buffer_base = qe_muram_alloc(2048, 4096);
 	out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
 
 	/* Clear sdma status */
diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h
index 0bcd0a9..400b1a6 100644
--- a/drivers/qe/qe.h
+++ b/drivers/qe/qe.h
@@ -29,7 +29,7 @@
 #define QE_NUM_OF_BRGS	16
 #define UCC_MAX_NUM	8
 
-#define QE_DATAONLY_BASE	(uint)(128)
+#define QE_DATAONLY_BASE	0
 #define QE_DATAONLY_SIZE	(QE_MURAM_SIZE - QE_DATAONLY_BASE)
 
 /* QE threads SNUM
diff --git a/drivers/rpx_pcmcia.c b/drivers/rpx_pcmcia.c
index 2a0a9e0..c7c425b 100644
--- a/drivers/rpx_pcmcia.c
+++ b/drivers/rpx_pcmcia.c
@@ -9,11 +9,11 @@
 
 #undef	CONFIG_PCMCIA
 
-#if	CONFIG_COMMANDS & CFG_CMD_PCMCIA
+#if defined(CONFIG_CMD_PCMCIA)
 #define	CONFIG_PCMCIA
 #endif
 
-#if	(CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
 #define	CONFIG_PCMCIA
 #endif
 
@@ -62,12 +62,12 @@
 	return 0;	/* No hardware to enable */
 }
 
-#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 static int pcmcia_hardware_disable(int slot)
 {
 	return 0;	/* No hardware to disable */
 }
-#endif	/* CONFIG_COMMANDS & CFG_CMD_PCMCIA */
+#endif
 
 
 #endif	/* CONFIG_PCMCIA && (CONFIG_RPXCLASSIC || CONFIG_RPXLITE) */
diff --git a/drivers/rtl8019.c b/drivers/rtl8019.c
index 62b9245..409a69f 100644
--- a/drivers/rtl8019.c
+++ b/drivers/rtl8019.c
@@ -34,7 +34,7 @@
 
 #ifdef CONFIG_DRIVER_RTL8019
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_CMD_NET)
 
 
 /* packet page register access functions */
diff --git a/drivers/rtl8139.c b/drivers/rtl8139.c
index afe1a4f..9045523 100644
--- a/drivers/rtl8139.c
+++ b/drivers/rtl8139.c
@@ -77,7 +77,7 @@
 #include <asm/io.h>
 #include <pci.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
 	defined(CONFIG_RTL8139)
 
 #define TICKS_PER_SEC	CFG_HZ
@@ -535,4 +535,4 @@
 		udelay (100); /* wait 100us */
 	}
 }
-#endif	/* CFG_CMD_NET && CONFIG_NET_MULTI && CONFIG_RTL8139 */
+#endif
diff --git a/drivers/rtl8169.c b/drivers/rtl8169.c
index 3393ba8..63ea2cc 100644
--- a/drivers/rtl8169.c
+++ b/drivers/rtl8169.c
@@ -55,7 +55,7 @@
 #include <asm/io.h>
 #include <pci.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
 	defined(CONFIG_RTL8169)
 
 #undef DEBUG_RTL8169
diff --git a/drivers/sk98lin/uboot_drv.c b/drivers/sk98lin/uboot_drv.c
index 263dac8..d02cd1b 100644
--- a/drivers/sk98lin/uboot_drv.c
+++ b/drivers/sk98lin/uboot_drv.c
@@ -25,7 +25,7 @@
 
 #include <common.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
 	defined(CONFIG_SK98)
 
 #include "h/skdrv1st.h"
diff --git a/drivers/sym53c8xx.c b/drivers/sym53c8xx.c
index ae10f80..29eeccd 100644
--- a/drivers/sym53c8xx.c
+++ b/drivers/sym53c8xx.c
@@ -51,7 +51,7 @@
 #define PRINTF(fmt,args...)
 #endif
 
-#if (CONFIG_COMMANDS & CFG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
+#if defined(CONFIG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
 
 #undef SCSI_SINGLE_STEP
 /*
@@ -787,7 +787,7 @@
 	scsi_write_byte(DMODE,0x00);
 #endif
 }
-#endif /* (CONFIG_COMMANDS & CFG_CMD_SCSI) */
+#endif
 
 
 #endif /* CONFIG_SCSI_SYM53C8XX */
diff --git a/drivers/ti_pci1410a.c b/drivers/ti_pci1410a.c
index d5297b5..208ca50 100644
--- a/drivers/ti_pci1410a.c
+++ b/drivers/ti_pci1410a.c
@@ -64,7 +64,7 @@
 
 #include <pcmcia.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) && defined(CONFIG_IDE_TI_CARDBUS)
+#if defined(CONFIG_CMD_PCMCIA) && defined(CONFIG_IDE_TI_CARDBUS)
 
 int pcmcia_on(int ide_base_bus);
 
diff --git a/drivers/tigon3.c b/drivers/tigon3.c
index 91e22eb..5f6a4ec 100644
--- a/drivers/tigon3.c
+++ b/drivers/tigon3.c
@@ -12,7 +12,7 @@
 /******************************************************************************/
 #include <common.h>
 #include <asm/types.h>
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_NET_MULTI) && \
+#if defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI) && \
 	defined(CONFIG_TIGON3)
 #ifdef CONFIG_BMW
 #include <mpc824x.h>
@@ -5695,4 +5695,5 @@
 	}
 	return LM_STATUS_SUCCESS;
 }
-#endif				/* CFG_CMD_NET, !CONFIG_NET_MULTI, CONFIG_TIGON3 */
+
+#endif
diff --git a/drivers/tqm8xx_pcmcia.c b/drivers/tqm8xx_pcmcia.c
index a0f53cd..132c7a5 100644
--- a/drivers/tqm8xx_pcmcia.c
+++ b/drivers/tqm8xx_pcmcia.c
@@ -10,11 +10,11 @@
 
 #undef	CONFIG_PCMCIA
 
-#if	(CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 #define	CONFIG_PCMCIA
 #endif
 
-#if	(CONFIG_COMMANDS & CFG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
+#if defined(CONFIG_CMD_IDE) && defined(CONFIG_IDE_8xx_PCCARD)
 #define	CONFIG_PCMCIA
 #endif
 
@@ -241,7 +241,7 @@
 }
 
 
-#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA)
+#if defined(CONFIG_CMD_PCMCIA)
 int pcmcia_hardware_disable(int slot)
 {
 	u_long reg;
@@ -263,7 +263,7 @@
 
 	return (0);
 }
-#endif	/* CFG_CMD_PCMCIA */
+#endif
 
 int pcmcia_voltage_set(int slot, int vcc, int vpp)
 {
diff --git a/drivers/tsec.c b/drivers/tsec.c
index b418773..c011123 100644
--- a/drivers/tsec.c
+++ b/drivers/tsec.c
@@ -65,33 +65,33 @@
  *   FEC_PHYIDX
  */
 static struct tsec_info_struct tsec_info[] = {
-#if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)
-#if defined(CONFIG_MPC8544DS)
+#if defined(CONFIG_TSEC1)
+#if defined(CONFIG_MPC8544DS) || defined(CONFIG_MPC8641HPCN)
 	{TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
 #else
 	{TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},
 #endif
-#elif defined(CONFIG_MPC86XX_TSEC1)
-	{TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},
 #else
 	{0, 0, 0},
 #endif
-#if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2)
-	{TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
-#elif defined(CONFIG_MPC86XX_TSEC2)
+#if defined(CONFIG_TSEC2)
+#if defined(CONFIG_MPC8641HPCN)
 	{TSEC2_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC2_PHYIDX},
 #else
+	{TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},
+#endif
+#else
 	{0, 0, 0},
 #endif
 #ifdef CONFIG_MPC85XX_FEC
 	{FEC_PHY_ADDR, 0, FEC_PHYIDX},
 #else
-#if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) || defined(CONFIG_MPC86XX_TSEC3)
+#if defined(CONFIG_TSEC3)
 	{TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX},
 #else
 	{0, 0, 0},
 #endif
-#if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4) || defined(CONFIG_MPC86XX_TSEC4)
+#if defined(CONFIG_TSEC4)
 	{TSEC4_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC4_PHYIDX},
 #else
 	{0, 0, 0},
@@ -178,7 +178,7 @@
 	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET;
 	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);
 
-#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
 	&& !defined(BITBANGMII)
 	miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write);
 #endif
@@ -298,9 +298,9 @@
 	volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR);
 
 	/* Assign a Physical address to the TBI */
-	regs->tbipa = TBIPA_VALUE;
+	regs->tbipa = CFG_TBIPA_VALUE;
 	regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);
-	regs->tbipa = TBIPA_VALUE;
+	regs->tbipa = CFG_TBIPA_VALUE;
 	asm("sync");
 
 	/* Reset MII (due to new addresses) */
@@ -900,6 +900,39 @@
 		phy_run_commands(priv, priv->phyinfo->shutdown);
 }
 
+struct phy_info phy_info_M88E1149S = {
+	0x1410ca,
+	"Marvell 88E1149S",
+	4,
+	(struct phy_cmd[]){     /* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{0x1d, 0x1f, NULL},
+		{0x1e, 0x200c, NULL},
+		{0x1d, 0x5, NULL},
+		{0x1e, 0x0, NULL},
+		{0x1e, 0x100, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){     /* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_88E1011_PHY_STATUS, miim_read,
+		 &mii_parse_88E1011_psr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]){     /* shutdown */
+		{miim_end,}
+	},
+};
+
 /* The 5411 id is 0x206070, the 5421 is 0x2060e0 */
 struct phy_info phy_info_BCM5461S = {
 	0x02060c1,	/* 5461 ID */
@@ -928,6 +961,33 @@
 	},
 };
 
+struct phy_info phy_info_BCM5464S = {
+	0x02060b1,	/* 5464 ID */
+	"Broadcom BCM5464S",
+	0, /* not clear to me what minor revisions we can shift away */
+	(struct phy_cmd[]) { /* config */
+		/* Reset and configure the PHY */
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
+		{MIIM_ANAR, MIIM_ANAR_INIT, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* startup */
+		/* Status is read once to clear old link state */
+		{MIIM_STATUS, miim_read, NULL},
+		/* Auto-negotiate */
+		{MIIM_STATUS, miim_read, &mii_parse_sr},
+		/* Read the status */
+		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
+		{miim_end,}
+	},
+	(struct phy_cmd[]) { /* shutdown */
+		{miim_end,}
+	},
+};
+
 struct phy_info phy_info_M88E1011S = {
 	0x01410c6,
 	"Marvell 88E1011S",
@@ -968,11 +1028,6 @@
 	(struct phy_cmd[]){	/* config */
 			   /* Reset and configure the PHY */
 			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
-			   {0x1d, 0x1f, NULL},
-			   {0x1e, 0x200c, NULL},
-			   {0x1d, 0x5, NULL},
-			   {0x1e, 0x0, NULL},
-			   {0x1e, 0x100, NULL},
 			   {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */
 			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
 			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
@@ -1012,14 +1067,16 @@
 	"Marvell 88E1145",
 	4,
 	(struct phy_cmd[]){	/* config */
+			   /* Reset the PHY */
+			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+
 			   /* Errata E0, E1 */
 			   {29, 0x001b, NULL},
 			   {30, 0x418f, NULL},
 			   {29, 0x0016, NULL},
 			   {30, 0xa2da, NULL},
 
-			   /* Reset and configure the PHY */
-			   {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL},
+			   /* Configure the PHY */
 			   {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL},
 			   {MIIM_ANAR, MIIM_ANAR_INIT, NULL},
 			   {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO,
@@ -1292,9 +1349,11 @@
 	&phy_info_cis8204,
 	&phy_info_cis8201,
 	&phy_info_BCM5461S,
+	&phy_info_BCM5464S,
 	&phy_info_M88E1011S,
 	&phy_info_M88E1111S,
 	&phy_info_M88E1145,
+	&phy_info_M88E1149S,
 	&phy_info_dm9161,
 	&phy_info_lxt971,
 	&phy_info_VSC8244,
@@ -1325,8 +1384,10 @@
 	/* loop through all the known PHY types, and find one that */
 	/* matches the ID we read from the PHY. */
 	for (i = 0; phy_info[i]; i++) {
-		if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift))
+		if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) {
 			theInfo = phy_info[i];
+			break;
+		}
 	}
 
 	if (theInfo == NULL) {
@@ -1417,7 +1478,7 @@
 	relocated = 1;
 }
 
-#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) \
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
 	&& !defined(BITBANGMII)
 
 struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
@@ -1476,7 +1537,6 @@
 	return 0;
 }
 
-#endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
-		&& !defined(BITBANGMII) */
+#endif
 
 #endif /* CONFIG_TSEC_ENET */
diff --git a/drivers/tsec.h b/drivers/tsec.h
index 7bf3dee..2f0092a 100644
--- a/drivers/tsec.h
+++ b/drivers/tsec.h
@@ -70,7 +70,9 @@
 #define miim_end -2
 #define miim_read -1
 
-#define TBIPA_VALUE		0x1f
+#ifndef CFG_TBIPA_VALUE
+    #define CFG_TBIPA_VALUE	0x1f
+#endif
 #define MIIMCFG_INIT_VALUE	0x00000003
 #define MIIMCFG_RESET		0x80000000
 
diff --git a/drivers/tsi108_eth.c b/drivers/tsi108_eth.c
index 47341be..524e9da 100644
--- a/drivers/tsi108_eth.c
+++ b/drivers/tsi108_eth.c
@@ -27,7 +27,7 @@
 
 #include <config.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) \
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) \
 	&& defined(CONFIG_TSI108_ETH)
 
 #if !defined(CONFIG_TSI108_ETH_NUM_PORTS) || (CONFIG_TSI108_ETH_NUM_PORTS > 2)
diff --git a/drivers/tsi108_i2c.c b/drivers/tsi108_i2c.c
index eb52cb6..3a3b75c 100644
--- a/drivers/tsi108_i2c.c
+++ b/drivers/tsi108_i2c.c
@@ -28,7 +28,7 @@
 #ifdef CONFIG_TSI108_I2C
 #include <tsi108.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_I2C)
+#if defined(CONFIG_CMD_I2C)
 
 #define I2C_DELAY	100000
 #undef  DEBUG_I2C
@@ -279,5 +279,5 @@
 	return i2c_read (chip, 0, 1, (char *)&tmp, 1);
 }
 
-#endif	/* (CONFIG_COMMANDS & CFG_CMD_I2C) */
+#endif
 #endif /* CONFIG_TSI108_I2C */
diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c
new file mode 100644
index 0000000..f0a37b2
--- /dev/null
+++ b/drivers/usb_ohci.c
@@ -0,0 +1,1918 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus.
+ *
+ * Interrupt support is added. Now, it has been tested
+ * on ULI1575 chip and works well with USB keyboard.
+ *
+ * (C) Copyright 2007
+ * Zhang Wei, Freescale Semiconductor, Inc. <wei.zhang@freescale.com>
+ *
+ * (C) Copyright 2003
+ * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
+ * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
+ * ebenard@eukrea.com - based on s3c24x0's driver
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+/*
+ * IMPORTANT NOTES
+ * 1 - Read doc/README.generic_usb_ohci
+ * 2 - this driver is intended for use with USB Mass Storage Devices
+ *     (BBB) and USB keyboard. There is NO support for Isochronous pipes!
+ * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
+ *     to activate workaround for bug #41 or this driver will NOT work!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI_NEW
+
+#include <asm/byteorder.h>
+
+#if defined(CONFIG_PCI_OHCI)
+# include <pci.h>
+#endif
+
+#include <malloc.h>
+#include <usb.h>
+#include "usb_ohci.h"
+
+#if defined(CONFIG_ARM920T) || \
+    defined(CONFIG_S3C2400) || \
+    defined(CONFIG_S3C2410) || \
+    defined(CONFIG_440EP) || \
+    defined(CONFIG_PCI_OHCI) || \
+    defined(CONFIG_MPC5200)
+# define OHCI_USE_NPS		/* force NoPowerSwitching mode */
+#endif
+
+#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
+
+/* For initializing controller (mask in an HCFS mode too) */
+#define OHCI_CONTROL_INIT \
+	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+
+/*
+ * e.g. PCI controllers need this
+ */
+#ifdef CFG_OHCI_SWAP_REG_ACCESS
+# define readl(a) __swap_32(*((vu_long *)(a)))
+# define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a))
+#else
+# define readl(a) (*((vu_long *)(a)))
+# define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a))
+#endif /* CFG_OHCI_SWAP_REG_ACCESS */
+
+#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+
+#ifdef CONFIG_PCI_OHCI
+static struct pci_device_id ohci_pci_ids[] = {
+	{0x10b9, 0x5237},	/* ULI1575 PCI OHCI module ids */
+	/* Please add supported PCI OHCI controller ids here */
+	{0, 0}
+};
+#endif
+
+#ifdef DEBUG
+#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
+#else
+#define dbg(format, arg...) do {} while(0)
+#endif /* DEBUG */
+#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
+#undef SHOW_INFO
+#ifdef SHOW_INFO
+#define info(format, arg...) printf("INFO: " format "\n", ## arg)
+#else
+#define info(format, arg...) do {} while(0)
+#endif
+
+#ifdef CFG_OHCI_BE_CONTROLLER
+# define m16_swap(x) cpu_to_be16(x)
+# define m32_swap(x) cpu_to_be32(x)
+#else
+# define m16_swap(x) cpu_to_le16(x)
+# define m32_swap(x) cpu_to_le32(x)
+#endif /* CFG_OHCI_BE_CONTROLLER */
+
+/* global ohci_t */
+static ohci_t gohci;
+/* this must be aligned to a 256 byte boundary */
+struct ohci_hcca ghcca[1];
+/* a pointer to the aligned storage */
+struct ohci_hcca *phcca;
+/* this allocates EDs for all possible endpoints */
+struct ohci_device ohci_dev;
+/* RHSC flag */
+int got_rhsc;
+/* device which was disconnected */
+struct usb_device *devgone;
+
+/*-------------------------------------------------------------------------*/
+
+/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
+ * The erratum (#4) description is incorrect.  AMD's workaround waits
+ * till some bits (mostly reserved) are clear; ok for all revs.
+ */
+#define OHCI_QUIRK_AMD756 0xabcd
+#define read_roothub(hc, register, mask) ({ \
+	u32 temp = readl (&hc->regs->roothub.register); \
+	if (hc->flags & OHCI_QUIRK_AMD756) \
+		while (temp & mask) \
+			temp = readl (&hc->regs->roothub.register); \
+	temp; })
+
+static u32 roothub_a (struct ohci *hc)
+	{ return read_roothub (hc, a, 0xfc0fe000); }
+static inline u32 roothub_b (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.b); }
+static inline u32 roothub_status (struct ohci *hc)
+	{ return readl (&hc->regs->roothub.status); }
+static u32 roothub_portstatus (struct ohci *hc, int i)
+	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
+
+/* forward declaration */
+static int hc_interrupt (void);
+static void
+td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
+
+/*-------------------------------------------------------------------------*
+ * URB support functions
+ *-------------------------------------------------------------------------*/
+
+/* free HCD-private data associated with this URB */
+
+static void urb_free_priv (urb_priv_t * urb)
+{
+	int		i;
+	int		last;
+	struct td	* td;
+
+	last = urb->length - 1;
+	if (last >= 0) {
+		for (i = 0; i <= last; i++) {
+			td = urb->td[i];
+			if (td) {
+				td->usb_dev = NULL;
+				urb->td[i] = NULL;
+			}
+		}
+	}
+	free(urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+static int sohci_get_current_frame_number (struct usb_device * dev);
+
+/* debug| print the main components of an URB
+ * small: 0) header + data packets 1) just header */
+
+static void pkt_print (urb_priv_t *purb, struct usb_device * dev,
+	unsigned long pipe, void * buffer,
+	int transfer_len, struct devrequest * setup, char * str, int small)
+{
+	dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
+			str,
+			sohci_get_current_frame_number (dev),
+			usb_pipedevice (pipe),
+			usb_pipeendpoint (pipe),
+			usb_pipeout (pipe)? 'O': 'I',
+			usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
+				(usb_pipecontrol (pipe)? "CTRL": "BULK"),
+			(purb ? purb->actual_length : 0),
+			transfer_len, dev->status);
+#ifdef	OHCI_VERBOSE_DEBUG
+	if (!small) {
+		int i, len;
+
+		if (usb_pipecontrol (pipe)) {
+			printf (__FILE__ ": cmd(8):");
+			for (i = 0; i < 8 ; i++)
+				printf (" %02x", ((__u8 *) setup) [i]);
+			printf ("\n");
+		}
+		if (transfer_len > 0 && buffer) {
+			printf (__FILE__ ": data(%d/%d):",
+				(purb ? purb->actual_length : 0),
+				transfer_len);
+			len = usb_pipeout (pipe)?
+					transfer_len:
+					(purb ? purb->actual_length : 0);
+			for (i = 0; i < 16 && i < len; i++)
+				printf (" %02x", ((__u8 *) buffer) [i]);
+			printf ("%s\n", i < len? "...": "");
+		}
+	}
+#endif
+}
+
+/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
+void ep_print_int_eds (ohci_t *ohci, char * str) {
+	int i, j;
+	 __u32 * ed_p;
+	for (i= 0; i < 32; i++) {
+		j = 5;
+		ed_p = &(ohci->hcca->int_table [i]);
+		if (*ed_p == 0)
+		    continue;
+		printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
+		while (*ed_p != 0 && j--) {
+			ed_t *ed = (ed_t *)m32_swap(ed_p);
+			printf (" ed: %4x;", ed->hwINFO);
+			ed_p = &ed->hwNextED;
+		}
+		printf ("\n");
+	}
+}
+
+static void ohci_dump_intr_mask (char *label, __u32 mask)
+{
+	dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
+		label,
+		mask,
+		(mask & OHCI_INTR_MIE) ? " MIE" : "",
+		(mask & OHCI_INTR_OC) ? " OC" : "",
+		(mask & OHCI_INTR_RHSC) ? " RHSC" : "",
+		(mask & OHCI_INTR_FNO) ? " FNO" : "",
+		(mask & OHCI_INTR_UE) ? " UE" : "",
+		(mask & OHCI_INTR_RD) ? " RD" : "",
+		(mask & OHCI_INTR_SF) ? " SF" : "",
+		(mask & OHCI_INTR_WDH) ? " WDH" : "",
+		(mask & OHCI_INTR_SO) ? " SO" : ""
+		);
+}
+
+static void maybe_print_eds (char *label, __u32 value)
+{
+	ed_t *edp = (ed_t *)value;
+
+	if (value) {
+		dbg ("%s %08x", label, value);
+		dbg ("%08x", edp->hwINFO);
+		dbg ("%08x", edp->hwTailP);
+		dbg ("%08x", edp->hwHeadP);
+		dbg ("%08x", edp->hwNextED);
+	}
+}
+
+static char * hcfs2string (int state)
+{
+	switch (state) {
+		case OHCI_USB_RESET:	return "reset";
+		case OHCI_USB_RESUME:	return "resume";
+		case OHCI_USB_OPER:	return "operational";
+		case OHCI_USB_SUSPEND:	return "suspend";
+	}
+	return "?";
+}
+
+/* dump control and status registers */
+static void ohci_dump_status (ohci_t *controller)
+{
+	struct ohci_regs	*regs = controller->regs;
+	__u32			temp;
+
+	temp = readl (&regs->revision) & 0xff;
+	if (temp != 0x10)
+		dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
+
+	temp = readl (&regs->control);
+	dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
+		(temp & OHCI_CTRL_RWE) ? " RWE" : "",
+		(temp & OHCI_CTRL_RWC) ? " RWC" : "",
+		(temp & OHCI_CTRL_IR) ? " IR" : "",
+		hcfs2string (temp & OHCI_CTRL_HCFS),
+		(temp & OHCI_CTRL_BLE) ? " BLE" : "",
+		(temp & OHCI_CTRL_CLE) ? " CLE" : "",
+		(temp & OHCI_CTRL_IE) ? " IE" : "",
+		(temp & OHCI_CTRL_PLE) ? " PLE" : "",
+		temp & OHCI_CTRL_CBSR
+		);
+
+	temp = readl (&regs->cmdstatus);
+	dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
+		(temp & OHCI_SOC) >> 16,
+		(temp & OHCI_OCR) ? " OCR" : "",
+		(temp & OHCI_BLF) ? " BLF" : "",
+		(temp & OHCI_CLF) ? " CLF" : "",
+		(temp & OHCI_HCR) ? " HCR" : ""
+		);
+
+	ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
+	ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
+
+	maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
+
+	maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
+	maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
+
+	maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
+	maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
+
+	maybe_print_eds ("donehead", readl (&regs->donehead));
+}
+
+static void ohci_dump_roothub (ohci_t *controller, int verbose)
+{
+	__u32			temp, ndp, i;
+
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+	ndp = (ndp == 2) ? 1:0;
+#endif
+	if (verbose) {
+		dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
+			((temp & RH_A_POTPGT) >> 24) & 0xff,
+			(temp & RH_A_NOCP) ? " NOCP" : "",
+			(temp & RH_A_OCPM) ? " OCPM" : "",
+			(temp & RH_A_DT) ? " DT" : "",
+			(temp & RH_A_NPS) ? " NPS" : "",
+			(temp & RH_A_PSM) ? " PSM" : "",
+			ndp
+			);
+		temp = roothub_b (controller);
+		dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
+			temp,
+			(temp & RH_B_PPCM) >> 16,
+			(temp & RH_B_DR)
+			);
+		temp = roothub_status (controller);
+		dbg ("roothub.status: %08x%s%s%s%s%s%s",
+			temp,
+			(temp & RH_HS_CRWE) ? " CRWE" : "",
+			(temp & RH_HS_OCIC) ? " OCIC" : "",
+			(temp & RH_HS_LPSC) ? " LPSC" : "",
+			(temp & RH_HS_DRWE) ? " DRWE" : "",
+			(temp & RH_HS_OCI) ? " OCI" : "",
+			(temp & RH_HS_LPS) ? " LPS" : ""
+			);
+	}
+
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
+			i,
+			temp,
+			(temp & RH_PS_PRSC) ? " PRSC" : "",
+			(temp & RH_PS_OCIC) ? " OCIC" : "",
+			(temp & RH_PS_PSSC) ? " PSSC" : "",
+			(temp & RH_PS_PESC) ? " PESC" : "",
+			(temp & RH_PS_CSC) ? " CSC" : "",
+
+			(temp & RH_PS_LSDA) ? " LSDA" : "",
+			(temp & RH_PS_PPS) ? " PPS" : "",
+			(temp & RH_PS_PRS) ? " PRS" : "",
+			(temp & RH_PS_POCI) ? " POCI" : "",
+			(temp & RH_PS_PSS) ? " PSS" : "",
+
+			(temp & RH_PS_PES) ? " PES" : "",
+			(temp & RH_PS_CCS) ? " CCS" : ""
+			);
+	}
+}
+
+static void ohci_dump (ohci_t *controller, int verbose)
+{
+	dbg ("OHCI controller usb-%s state", controller->slot_name);
+
+	/* dumps some of the state we know about */
+	ohci_dump_status (controller);
+	if (verbose)
+		ep_print_int_eds (controller, "hcca");
+	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	ohci_dump_roothub (controller, 1);
+
+#endif /* DEBUG */
+
+/*-------------------------------------------------------------------------*
+ * Interface functions (URB)
+ *-------------------------------------------------------------------------*/
+
+/* get a transfer request */
+
+int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
+{
+	ohci_t *ohci;
+	ed_t * ed;
+	urb_priv_t *purb_priv = urb;
+	int i, size = 0;
+	struct usb_device *dev = urb->dev;
+	unsigned long pipe = urb->pipe;
+	void *buffer = urb->transfer_buffer;
+	int transfer_len = urb->transfer_buffer_length;
+	int interval = urb->interval;
+
+	ohci = &gohci;
+
+	/* when controller's hung, permit only roothub cleanup attempts
+	 * such as powering down ports */
+	if (ohci->disabled) {
+		err("sohci_submit_job: EPIPE");
+		return -1;
+	}
+
+	/* we're about to begin a new transaction here so mark the URB unfinished */
+	urb->finished = 0;
+
+	/* every endpoint has a ed, locate and fill it */
+	if (!(ed = ep_add_ed (dev, pipe, interval, 1))) {
+		err("sohci_submit_job: ENOMEM");
+		return -1;
+	}
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (usb_pipetype (pipe)) {
+		case PIPE_BULK: /* one TD for every 4096 Byte */
+			size = (transfer_len - 1) / 4096 + 1;
+			break;
+		case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
+			size = (transfer_len == 0)? 2:
+						(transfer_len - 1) / 4096 + 3;
+			break;
+		case PIPE_INTERRUPT: /* 1 TD */
+			size = 1;
+			break;
+	}
+
+	ed->purb = urb;
+
+	if (size >= (N_URB_TD - 1)) {
+		err("need %d TDs, only have %d", size, N_URB_TD);
+		return -1;
+	}
+	purb_priv->pipe = pipe;
+
+	/* fill the private part of the URB */
+	purb_priv->length = size;
+	purb_priv->ed = ed;
+	purb_priv->actual_length = 0;
+
+	/* allocate the TDs */
+	/* note that td[0] was allocated in ep_add_ed */
+	for (i = 0; i < size; i++) {
+		purb_priv->td[i] = td_alloc (dev);
+		if (!purb_priv->td[i]) {
+			purb_priv->length = i;
+			urb_free_priv (purb_priv);
+			err("sohci_submit_job: ENOMEM");
+			return -1;
+		}
+	}
+
+	if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
+		urb_free_priv (purb_priv);
+		err("sohci_submit_job: EINVAL");
+		return -1;
+	}
+
+	/* link the ed into a chain if is not already */
+	if (ed->state != ED_OPER)
+		ep_link (ohci, ed);
+
+	/* fill the TDs and link it to the ed */
+	td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
+
+	return 0;
+}
+
+static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
+{
+	struct ohci_regs *regs = hc->regs;
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_INTERRUPT:
+		/* implicitly requeued */
+		if (urb->dev->irq_handle &&
+				(urb->dev->irq_act_len = urb->actual_length)) {
+			writel (OHCI_INTR_WDH, &regs->intrenable);
+			readl (&regs->intrenable); /* PCI posting flush */
+			urb->dev->irq_handle(urb->dev);
+			writel (OHCI_INTR_WDH, &regs->intrdisable);
+			readl (&regs->intrdisable); /* PCI posting flush */
+		}
+		urb->actual_length = 0;
+		td_submit_job (
+				urb->dev,
+				urb->pipe,
+				urb->transfer_buffer,
+				urb->transfer_buffer_length,
+				NULL,
+				urb,
+				urb->interval);
+		break;
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+/* tell us the current USB frame number */
+
+static int sohci_get_current_frame_number (struct usb_device *usb_dev)
+{
+	ohci_t *ohci = &gohci;
+
+	return m16_swap (ohci->hcca->frame_no);
+}
+#endif
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* search for the right branch to insert an interrupt ed into the int tree
+ * do some load ballancing;
+ * returns the branch and
+ * sets the interval to interval = 2^integer (ld (interval)) */
+
+static int ep_int_ballance (ohci_t * ohci, int interval, int load)
+{
+	int i, branch = 0;
+
+	/* search for the least loaded interrupt endpoint
+	 * branch of all 32 branches
+	 */
+	for (i = 0; i < 32; i++)
+		if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i])
+			branch = i;
+
+	branch = branch % interval;
+	for (i = branch; i < 32; i += interval)
+		ohci->ohci_int_load [i] += load;
+
+	return branch;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*  2^int( ld (inter)) */
+
+static int ep_2_n_interval (int inter)
+{
+	int i;
+	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++);
+	return 1 << i;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the int tree is a binary tree
+ * in order to process it sequentially the indexes of the branches have to be mapped
+ * the mapping reverses the bits of a word of num_bits length */
+
+static int ep_rev (int num_bits, int word)
+{
+	int i, wout = 0;
+
+	for (i = 0; i < num_bits; i++)
+		wout |= (((word >> i) & 1) << (num_bits - i - 1));
+	return wout;
+}
+
+/*-------------------------------------------------------------------------*
+ * ED handling functions
+ *-------------------------------------------------------------------------*/
+
+/* link an ed into one of the HC chains */
+
+static int ep_link (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+	int int_branch;
+	int i;
+	int inter;
+	int interval;
+	int load;
+	__u32 * ed_p;
+
+	ed->state = ED_OPER;
+	ed->int_interval = 0;
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		ed->hwNextED = 0;
+		if (ohci->ed_controltail == NULL) {
+			writel (ed, &ohci->regs->ed_controlhead);
+		} else {
+			ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_controltail;
+		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_CLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_controltail = edi;
+		break;
+
+	case PIPE_BULK:
+		ed->hwNextED = 0;
+		if (ohci->ed_bulktail == NULL) {
+			writel (ed, &ohci->regs->ed_bulkhead);
+		} else {
+			ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed);
+		}
+		ed->ed_prev = ohci->ed_bulktail;
+		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
+			ohci->hc_control |= OHCI_CTRL_BLE;
+			writel (ohci->hc_control, &ohci->regs->control);
+		}
+		ohci->ed_bulktail = edi;
+		break;
+
+	case PIPE_INTERRUPT:
+		load = ed->int_load;
+		interval = ep_2_n_interval (ed->int_period);
+		ed->int_interval = interval;
+		int_branch = ep_int_ballance (ohci, interval, load);
+		ed->int_branch = int_branch;
+
+		for (i = 0; i < ep_rev (6, interval); i += inter) {
+			inter = 1;
+			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]);
+				(*ed_p != 0) && (((ed_t *)ed_p)->int_interval >= interval);
+				ed_p = &(((ed_t *)ed_p)->hwNextED))
+					inter = ep_rev (6, ((ed_t *)ed_p)->int_interval);
+			ed->hwNextED = *ed_p;
+			*ed_p = m32_swap(ed);
+		}
+		break;
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed,
+		unsigned index, unsigned period)
+{
+	for (; index < NUM_INTS; index += period) {
+		__u32	*ed_p = &ohci->hcca->int_table [index];
+
+		/* ED might have been unlinked through another path */
+		while (*ed_p != 0) {
+			if (((struct ed *)m32_swap (ed_p)) == ed) {
+				*ed_p = ed->hwNextED;
+				break;
+			}
+			ed_p = & (((struct ed *)m32_swap (ed_p))->hwNextED);
+		}
+	}
+}
+
+/* unlink an ed from one of the HC chains.
+ * just the link to the ed is unlinked.
+ * the link from the ed still points to another operational ed or 0
+ * so the HC can eventually finish the processing of the unlinked ed */
+
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
+{
+	volatile ed_t *ed = edi;
+	int i;
+
+	ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
+
+	switch (ed->type) {
+	case PIPE_CONTROL:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_CLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_controltail == ed) {
+			ohci->ed_controltail = ed->ed_prev;
+		} else {
+			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_BULK:
+		if (ed->ed_prev == NULL) {
+			if (!ed->hwNextED) {
+				ohci->hc_control &= ~OHCI_CTRL_BLE;
+				writel (ohci->hc_control, &ohci->regs->control);
+			}
+			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+		} else {
+			ed->ed_prev->hwNextED = ed->hwNextED;
+		}
+		if (ohci->ed_bulktail == ed) {
+			ohci->ed_bulktail = ed->ed_prev;
+		} else {
+			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		periodic_unlink (ohci, ed, 0, 1);
+		for (i = ed->int_branch; i < 32; i += ed->int_interval)
+		    ohci->ohci_int_load[i] -= ed->int_load;
+		break;
+	}
+	ed->state = ED_UNLINK;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* add/reinit an endpoint; this should be done once at the
+ * usb_set_configuration command, but the USB stack is a little bit
+ * stateless so we do it at every transaction if the state of the ed
+ * is ED_NEW then a dummy td is added and the state is changed to
+ * ED_UNLINK in all other cases the state is left unchanged the ed
+ * info fields are setted anyway even though most of them should not
+ * change
+ */
+static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe,
+		int interval, int load)
+{
+	td_t *td;
+	ed_t *ed_ret;
+	volatile ed_t *ed;
+
+	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
+			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+
+	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
+		err("ep_add_ed: pending delete");
+		/* pending delete request */
+		return NULL;
+	}
+
+	if (ed->state == ED_NEW) {
+		ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
+		/* dummy td; end of td list for ed */
+		td = td_alloc (usb_dev);
+		ed->hwTailP = m32_swap ((unsigned long)td);
+		ed->hwHeadP = ed->hwTailP;
+		ed->state = ED_UNLINK;
+		ed->type = usb_pipetype (pipe);
+		ohci_dev.ed_cnt++;
+	}
+
+	ed->hwINFO = m32_swap (usb_pipedevice (pipe)
+			| usb_pipeendpoint (pipe) << 7
+			| (usb_pipeisoc (pipe)? 0x8000: 0)
+			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
+			| usb_pipeslow (pipe) << 13
+			| usb_maxpacket (usb_dev, pipe) << 16);
+
+	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
+		ed->int_period = interval;
+		ed->int_load = load;
+	}
+
+	return ed_ret;
+}
+
+/*-------------------------------------------------------------------------*
+ * TD handling functions
+ *-------------------------------------------------------------------------*/
+
+/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
+
+static void td_fill (ohci_t *ohci, unsigned int info,
+	void *data, int len,
+	struct usb_device *dev, int index, urb_priv_t *urb_priv)
+{
+	volatile td_t  *td, *td_pt;
+#ifdef OHCI_FILL_TRACE
+	int i;
+#endif
+
+	if (index > urb_priv->length) {
+		err("index > length");
+		return;
+	}
+	/* use this td as the next dummy */
+	td_pt = urb_priv->td [index];
+	td_pt->hwNextTD = 0;
+
+	/* fill the old dummy TD */
+	td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
+
+	td->ed = urb_priv->ed;
+	td->next_dl_td = NULL;
+	td->index = index;
+	td->data = (__u32)data;
+#ifdef OHCI_FILL_TRACE
+	if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
+		for (i = 0; i < len; i++)
+		printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
+		printf("\n");
+	}
+#endif
+	if (!len)
+		data = 0;
+
+	td->hwINFO = m32_swap (info);
+	td->hwCBP = m32_swap ((unsigned long)data);
+	if (data)
+		td->hwBE = m32_swap ((unsigned long)(data + len - 1));
+	else
+		td->hwBE = 0;
+	td->hwNextTD = m32_swap ((unsigned long)td_pt);
+
+	/* append to queue */
+	td->ed->hwTailP = td->hwNextTD;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* prepare all TDs of a transfer */
+
+static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
+	int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
+{
+	ohci_t *ohci = &gohci;
+	int data_len = transfer_len;
+	void *data;
+	int cnt = 0;
+	__u32 info = 0;
+	unsigned int toggle = 0;
+
+	/* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
+	if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
+		toggle = TD_T_TOGGLE;
+	} else {
+		toggle = TD_T_DATA0;
+		usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
+	}
+	urb->td_cnt = 0;
+	if (data_len)
+		data = buffer;
+	else
+		data = 0;
+
+	switch (usb_pipetype (pipe)) {
+	case PIPE_BULK:
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
+		while(data_len > 4096) {
+			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
+			data += 4096; data_len -= 4096; cnt++;
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
+		td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
+		cnt++;
+
+		if (!ohci->sleeping)
+			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+		break;
+
+	case PIPE_CONTROL:
+		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
+		td_fill (ohci, info, setup, 8, dev, cnt++, urb);
+		if (data_len > 0) {
+			info = usb_pipeout (pipe)?
+				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
+			/* NOTE:  mishandles transfers >8K, some >4K */
+			td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+		}
+		info = usb_pipeout (pipe)?
+			TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
+		td_fill (ohci, info, data, 0, dev, cnt++, urb);
+		if (!ohci->sleeping)
+			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+		break;
+
+	case PIPE_INTERRUPT:
+		info = usb_pipeout (urb->pipe)?
+			TD_CC | TD_DP_OUT | toggle:
+			TD_CC | TD_R | TD_DP_IN | toggle;
+		td_fill (ohci, info, data, data_len, dev, cnt++, urb);
+		break;
+	}
+	if (urb->length != cnt)
+		dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
+}
+
+/*-------------------------------------------------------------------------*
+ * Done List handling functions
+ *-------------------------------------------------------------------------*/
+
+/* calculate the transfer length and update the urb */
+
+static void dl_transfer_length(td_t * td)
+{
+	__u32 tdINFO, tdBE, tdCBP;
+	urb_priv_t *lurb_priv = td->ed->purb;
+
+	tdINFO = m32_swap (td->hwINFO);
+	tdBE   = m32_swap (td->hwBE);
+	tdCBP  = m32_swap (td->hwCBP);
+
+	if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
+	    ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
+		if (tdBE != 0) {
+			if (td->hwCBP == 0)
+				lurb_priv->actual_length += tdBE - td->data + 1;
+			else
+				lurb_priv->actual_length += tdCBP - td->data;
+		}
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+
+static td_t * dl_reverse_done_list (ohci_t *ohci)
+{
+	__u32 td_list_hc;
+	td_t *td_rev = NULL;
+	td_t *td_list = NULL;
+	urb_priv_t *lurb_priv = NULL;
+
+	td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
+	ohci->hcca->done_head = 0;
+
+	while (td_list_hc) {
+		td_list = (td_t *)td_list_hc;
+
+		if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
+			lurb_priv = td_list->ed->purb;
+			dbg(" USB-error/status: %x : %p",
+					TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & m32_swap (0x1)) {
+				if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
+					td_list->ed->hwHeadP =
+						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
+									(td_list->ed->hwHeadP & m32_swap (0x2));
+					lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
+				} else
+					td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
+			}
+#ifdef CONFIG_MPC5200
+			td_list->hwNextTD = 0;
+#endif
+		}
+
+		td_list->next_dl_td = td_rev;
+		td_rev = td_list;
+		td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
+	}
+	return td_list;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* td done list */
+static int dl_done_list (ohci_t *ohci, td_t *td_list)
+{
+	td_t *td_list_next = NULL;
+	ed_t *ed;
+	int cc = 0;
+	int stat = 0;
+	/* urb_t *urb; */
+	urb_priv_t *lurb_priv;
+	__u32 tdINFO, edHeadP, edTailP;
+
+	while (td_list) {
+		td_list_next = td_list->next_dl_td;
+
+		tdINFO = m32_swap (td_list->hwINFO);
+
+		ed = td_list->ed;
+		lurb_priv = ed->purb;
+
+		dl_transfer_length(td_list);
+
+		/* error code of transfer */
+		cc = TD_CC_GET (tdINFO);
+		if (cc != 0) {
+			dbg("ConditionCode %#x", cc);
+			stat = cc_to_error[cc];
+		}
+
+		/* see if this done list makes for all TD's of current URB,
+		 * and mark the URB finished if so */
+		if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+#if 1
+			if ((ed->state & (ED_OPER | ED_UNLINK)) &&
+			    (lurb_priv->state != URB_DEL))
+#else
+			if ((ed->state & (ED_OPER | ED_UNLINK)))
+#endif
+				lurb_priv->finished = sohci_return_job(ohci,
+						lurb_priv);
+			else
+				dbg("dl_done_list: strange.., ED state %x, ed->state\n");
+		} else
+			dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
+				lurb_priv->length);
+		if (ed->state != ED_NEW &&
+			  (usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) {
+			edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
+			edTailP = m32_swap (ed->hwTailP);
+
+			/* unlink eds if they are not busy */
+			if ((edHeadP == edTailP) && (ed->state == ED_OPER))
+				ep_unlink (ohci, ed);
+		}
+
+		td_list = td_list_next;
+	}
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+	0x12,	    /*	__u8  bLength; */
+	0x01,	    /*	__u8  bDescriptorType; Device */
+	0x10,	    /*	__u16 bcdUSB; v1.1 */
+	0x01,
+	0x09,	    /*	__u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  bDeviceSubClass; */
+	0x00,	    /*	__u8  bDeviceProtocol; */
+	0x08,	    /*	__u8  bMaxPacketSize0; 8 Bytes */
+	0x00,	    /*	__u16 idVendor; */
+	0x00,
+	0x00,	    /*	__u16 idProduct; */
+	0x00,
+	0x00,	    /*	__u16 bcdDevice; */
+	0x00,
+	0x00,	    /*	__u8  iManufacturer; */
+	0x01,	    /*	__u8  iProduct; */
+	0x00,	    /*	__u8  iSerialNumber; */
+	0x01	    /*	__u8  bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+	0x09,	    /*	__u8  bLength; */
+	0x02,	    /*	__u8  bDescriptorType; Configuration */
+	0x19,	    /*	__u16 wTotalLength; */
+	0x00,
+	0x01,	    /*	__u8  bNumInterfaces; */
+	0x01,	    /*	__u8  bConfigurationValue; */
+	0x00,	    /*	__u8  iConfiguration; */
+	0x40,	    /*	__u8  bmAttributes;
+		 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+	0x00,	    /*	__u8  MaxPower; */
+
+	/* interface */
+	0x09,	    /*	__u8  if_bLength; */
+	0x04,	    /*	__u8  if_bDescriptorType; Interface */
+	0x00,	    /*	__u8  if_bInterfaceNumber; */
+	0x00,	    /*	__u8  if_bAlternateSetting; */
+	0x01,	    /*	__u8  if_bNumEndpoints; */
+	0x09,	    /*	__u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,	    /*	__u8  if_bInterfaceSubClass; */
+	0x00,	    /*	__u8  if_bInterfaceProtocol; */
+	0x00,	    /*	__u8  if_iInterface; */
+
+	/* endpoint */
+	0x07,	    /*	__u8  ep_bLength; */
+	0x05,	    /*	__u8  ep_bDescriptorType; Endpoint */
+	0x81,	    /*	__u8  ep_bEndpointAddress; IN Endpoint 1 */
+	0x03,	    /*	__u8  ep_bmAttributes; Interrupt */
+	0x02,	    /*	__u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+	0x00,
+	0xff	    /*	__u8  ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+	0x04,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	0x09,			/*  __u8  lang ID */
+	0x04,			/*  __u8  lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+	28,			/*  __u8  bLength; */
+	0x03,			/*  __u8  bDescriptorType; String-descriptor */
+	'O',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'C',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'I',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'R',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'o',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	't',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	' ',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'H',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'u',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+	'b',			/*  __u8  Unicode */
+	0,				/*  __u8  Unicode */
+};
+
+/* Hub class-specific descriptor is constructed dynamically */
+
+/*-------------------------------------------------------------------------*/
+
+#define OK(x)			len = (x); break
+#ifdef DEBUG
+#define WR_RH_STAT(x)		{info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
+#define WR_RH_PORTSTAT(x)	{info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
+#else
+#define WR_RH_STAT(x)		writel((x), &gohci.regs->roothub.status)
+#define WR_RH_PORTSTAT(x)	writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
+#endif
+#define RD_RH_STAT		roothub_status(&gohci)
+#define RD_RH_PORTSTAT		roothub_portstatus(&gohci,wIndex-1)
+
+/* request to virtual root hub */
+
+int rh_check_port_status(ohci_t *controller)
+{
+	__u32 temp, ndp, i;
+	int res;
+
+	res = -1;
+	temp = roothub_a (controller);
+	ndp = (temp & RH_A_NDP);
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+	ndp = (ndp == 2) ? 1:0;
+#endif
+	for (i = 0; i < ndp; i++) {
+		temp = roothub_portstatus (controller, i);
+		/* check for a device disconnect */
+		if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
+			(RH_PS_PESC | RH_PS_CSC)) &&
+			((temp & RH_PS_CCS) == 0)) {
+			res = i;
+			break;
+		}
+	}
+	return res;
+}
+
+static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+		void *buffer, int transfer_len, struct devrequest *cmd)
+{
+	void * data = buffer;
+	int leni = transfer_len;
+	int len = 0;
+	int stat = 0;
+	__u32 datab[4];
+	__u8 *data_buf = (__u8 *)datab;
+	__u16 bmRType_bReq;
+	__u16 wValue;
+	__u16 wIndex;
+	__u16 wLength;
+
+#ifdef DEBUG
+pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
+#else
+	wait_ms(1);
+#endif
+	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+		info("Root-Hub submit IRQ: NOT implemented");
+		return 0;
+	}
+
+	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
+	wValue	      = cpu_to_le16 (cmd->value);
+	wIndex	      = cpu_to_le16 (cmd->index);
+	wLength	      = cpu_to_le16 (cmd->length);
+
+	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
+		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
+
+	switch (bmRType_bReq) {
+	/* Request Destination:
+	   without flags: Device,
+	   RH_INTERFACE: interface,
+	   RH_ENDPOINT: endpoint,
+	   RH_CLASS means HUB here,
+	   RH_OTHER | RH_CLASS	almost ever means HUB_PORT here
+	*/
+
+	case RH_GET_STATUS:
+			*(__u16 *) data_buf = cpu_to_le16 (1); OK (2);
+	case RH_GET_STATUS | RH_INTERFACE:
+			*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+	case RH_GET_STATUS | RH_ENDPOINT:
+			*(__u16 *) data_buf = cpu_to_le16 (0); OK (2);
+	case RH_GET_STATUS | RH_CLASS:
+			*(__u32 *) data_buf = cpu_to_le32 (
+				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
+			OK (4);
+	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+			*(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
+
+	case RH_CLEAR_FEATURE | RH_ENDPOINT:
+		switch (wValue) {
+			case (RH_ENDPOINT_STALL): OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_CLASS:
+		switch (wValue) {
+			case RH_C_HUB_LOCAL_POWER:
+				OK(0);
+			case (RH_C_HUB_OVER_CURRENT):
+					WR_RH_STAT(RH_HS_OCIC); OK (0);
+		}
+		break;
+
+	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
+			case (RH_C_PORT_CONNECTION):
+					WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
+			case (RH_C_PORT_ENABLE):
+					WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
+			case (RH_C_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
+			case (RH_C_PORT_OVER_CURRENT):
+					WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
+			case (RH_C_PORT_RESET):
+					WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
+		}
+		break;
+
+	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+		switch (wValue) {
+			case (RH_PORT_SUSPEND):
+					WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
+			case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PRS);
+					OK (0);
+			case (RH_PORT_POWER):
+					WR_RH_PORTSTAT (RH_PS_PPS );
+					wait_ms(100);
+					OK (0);
+			case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
+					if (RD_RH_PORTSTAT & RH_PS_CCS)
+					    WR_RH_PORTSTAT (RH_PS_PES );
+					OK (0);
+		}
+		break;
+
+	case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
+
+	case RH_GET_DESCRIPTOR:
+		switch ((wValue & 0xff00) >> 8) {
+			case (0x01): /* device descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_dev_des),
+					      wLength));
+				data_buf = root_hub_dev_des; OK(len);
+			case (0x02): /* configuration descriptor */
+				len = min_t(unsigned int,
+					  leni,
+					  min_t(unsigned int,
+					      sizeof (root_hub_config_des),
+					      wLength));
+				data_buf = root_hub_config_des; OK(len);
+			case (0x03): /* string descriptors */
+				if(wValue==0x0300) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index0),
+						      wLength));
+					data_buf = root_hub_str_index0;
+					OK(len);
+				}
+				if(wValue==0x0301) {
+					len = min_t(unsigned int,
+						  leni,
+						  min_t(unsigned int,
+						      sizeof (root_hub_str_index1),
+						      wLength));
+					data_buf = root_hub_str_index1;
+					OK(len);
+			}
+			default:
+				stat = USB_ST_STALLED;
+		}
+		break;
+
+	case RH_GET_DESCRIPTOR | RH_CLASS:
+	{
+		__u32 temp = roothub_a (&gohci);
+
+		data_buf [0] = 9;		/* min length; */
+		data_buf [1] = 0x29;
+		data_buf [2] = temp & RH_A_NDP;
+#ifdef CONFIG_AT91C_PQFP_UHPBUG
+		data_buf [2] = (data_buf [2] == 2) ? 1:0;
+#endif
+		data_buf [3] = 0;
+		if (temp & RH_A_PSM)	/* per-port power switching? */
+			data_buf [3] |= 0x1;
+		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+			data_buf [3] |= 0x10;
+		else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+			data_buf [3] |= 0x8;
+
+		/* corresponds to data_buf[4-7] */
+		datab [1] = 0;
+		data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		temp = roothub_b (&gohci);
+		data_buf [7] = temp & RH_B_DR;
+		if (data_buf [2] < 7) {
+			data_buf [8] = 0xff;
+		} else {
+			data_buf [0] += 2;
+			data_buf [8] = (temp & RH_B_DR) >> 8;
+			data_buf [10] = data_buf [9] = 0xff;
+		}
+
+		len = min_t(unsigned int, leni,
+			    min_t(unsigned int, data_buf [0], wLength));
+		OK (len);
+	}
+
+	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK (1);
+
+	case RH_SET_CONFIGURATION:	WR_RH_STAT (0x10000); OK (0);
+
+	default:
+		dbg ("unsupported root hub command");
+		stat = USB_ST_STALLED;
+	}
+
+#ifdef	DEBUG
+	ohci_dump_roothub (&gohci, 1);
+#else
+	wait_ms(1);
+#endif
+
+	len = min_t(int, len, leni);
+	if (data != data_buf)
+	    memcpy (data, data_buf, len);
+	dev->act_len = len;
+	dev->status = stat;
+
+#ifdef DEBUG
+	pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
+#else
+	wait_ms(1);
+#endif
+
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* common code for handling submit messages - used for all but root hub */
+/* accesses. */
+int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup, int interval)
+{
+	int stat = 0;
+	int maxsize = usb_maxpacket(dev, pipe);
+	int timeout;
+	urb_priv_t *urb;
+
+	urb = malloc(sizeof(urb_priv_t));
+	memset(urb, 0, sizeof(urb_priv_t));
+
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->transfer_buffer = buffer;
+	urb->transfer_buffer_length = transfer_len;
+	urb->interval = interval;
+
+	/* device pulled? Shortcut the action. */
+	if (devgone == dev) {
+		dev->status = USB_ST_CRC_ERR;
+		return 0;
+	}
+
+#ifdef DEBUG
+	urb->actual_length = 0;
+	pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+	wait_ms(1);
+#endif
+	if (!maxsize) {
+		err("submit_common_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+
+	if (sohci_submit_job(urb, setup) < 0) {
+		err("sohci_submit_job failed");
+		return -1;
+	}
+
+#if 0
+	wait_ms(10);
+	/* ohci_dump_status(&gohci); */
+#endif
+
+	/* allow more time for a BULK device to react - some are slow */
+#define BULK_TO	 5000	/* timeout in milliseconds */
+	if (usb_pipetype (pipe) == PIPE_BULK)
+		timeout = BULK_TO;
+	else
+		timeout = 100;
+
+	/* wait for it to complete */
+	for (;;) {
+		/* check whether the controller is done */
+		stat = hc_interrupt();
+		if (stat < 0) {
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+
+		/* NOTE: since we are not interrupt driven in U-Boot and always
+		 * handle only one URB at a time, we cannot assume the
+		 * transaction finished on the first successful return from
+		 * hc_interrupt().. unless the flag for current URB is set,
+		 * meaning that all TD's to/from device got actually
+		 * transferred and processed. If the current URB is not
+		 * finished we need to re-iterate this loop so as
+		 * hc_interrupt() gets called again as there needs to be some
+		 * more TD's to process still */
+		if ((stat >= 0) && (stat != 0xff) && (urb->finished)) {
+			/* 0xff is returned for an SF-interrupt */
+			break;
+		}
+
+		if (--timeout) {
+			wait_ms(1);
+			if (!urb->finished)
+				dbg("\%");
+
+		} else {
+			err("CTL:TIMEOUT ");
+			dbg("submit_common_msg: TO status %x\n", stat);
+			urb->finished = 1;
+			stat = USB_ST_CRC_ERR;
+			break;
+		}
+	}
+
+	dev->status = stat;
+	dev->act_len = transfer_len;
+
+#ifdef DEBUG
+	pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
+#else
+	wait_ms(1);
+#endif
+
+	/* free TDs in urb_priv */
+	if (usb_pipetype (pipe) != PIPE_INTERRUPT)
+		urb_free_priv (urb);
+	return 0;
+}
+
+/* submit routines called from usb.c */
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len)
+{
+	info("submit_bulk_msg");
+	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, struct devrequest *setup)
+{
+	int maxsize = usb_maxpacket(dev, pipe);
+
+	info("submit_control_msg");
+#ifdef DEBUG
+	pkt_print(NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
+#else
+	wait_ms(1);
+#endif
+	if (!maxsize) {
+		err("submit_control_message: pipesize for pipe %lx is zero",
+			pipe);
+		return -1;
+	}
+	if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
+		gohci.rh.dev = dev;
+		/* root hub - redirect */
+		return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
+			setup);
+	}
+
+	return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+		int transfer_len, int interval)
+{
+	info("submit_int_msg");
+	return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
+			interval);
+}
+
+/*-------------------------------------------------------------------------*
+ * HC functions
+ *-------------------------------------------------------------------------*/
+
+/* reset the HC and BUS */
+
+static int hc_reset (ohci_t *ohci)
+{
+	int timeout = 30;
+	int smm_timeout = 50; /* 0,5 sec */
+
+	dbg("%s\n", __FUNCTION__);
+
+	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
+		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
+		info("USB HC TakeOver from SMM");
+		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+			wait_ms (10);
+			if (--smm_timeout == 0) {
+				err("USB HC TakeOver failed!");
+				return -1;
+			}
+		}
+	}
+
+	/* Disable HC interrupts */
+	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
+		ohci->slot_name,
+		readl(&ohci->regs->control));
+
+	/* Reset USB (needed by some controllers) */
+	ohci->hc_control = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* HC Reset requires max 10 us delay */
+	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+		if (--timeout == 0) {
+			err("USB HC reset timed out!");
+			return -1;
+		}
+		udelay (1);
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Start an OHCI controller, set the BUS operational
+ * enable interrupts
+ * connect the virtual root hub */
+
+static int hc_start (ohci_t * ohci)
+{
+	__u32 mask;
+	unsigned int fminterval;
+
+	ohci->disabled = 1;
+
+	/* Tell the controller where the control and bulk lists are
+	 * The lists are empty now. */
+
+	writel (0, &ohci->regs->ed_controlhead);
+	writel (0, &ohci->regs->ed_bulkhead);
+
+	writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+
+	fminterval = 0x2edf;
+	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
+	fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
+	writel (fminterval, &ohci->regs->fminterval);
+	writel (0x628, &ohci->regs->lsthresh);
+
+	/* start controller operations */
+	ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+	ohci->disabled = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
+
+	/* disable all interrupts */
+	mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
+			OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
+			OHCI_INTR_OC | OHCI_INTR_MIE);
+	writel (mask, &ohci->regs->intrdisable);
+	/* clear all interrupts */
+	mask &= ~OHCI_INTR_MIE;
+	writel (mask, &ohci->regs->intrstatus);
+	/* Choose the interrupts we care about now  - but w/o MIE */
+	mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	writel (mask, &ohci->regs->intrenable);
+
+#ifdef	OHCI_USE_NPS
+	/* required for AMD-756 and some Mac platforms */
+	writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
+		&ohci->regs->roothub.a);
+	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+#endif	/* OHCI_USE_NPS */
+
+#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
+	/* POTPGT delay is bits 24-31, in 2 ms units. */
+	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+
+	/* connect the virtual root hub */
+	ohci->rh.devnum = 0;
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Poll USB interrupt. */
+void usb_event_poll(void)
+{
+	hc_interrupt();
+}
+
+/* an interrupt happens */
+
+static int hc_interrupt (void)
+{
+	ohci_t *ohci = &gohci;
+	struct ohci_regs *regs = ohci->regs;
+	int ints;
+	int stat = -1;
+
+	if ((ohci->hcca->done_head != 0) &&
+	    !(m32_swap (ohci->hcca->done_head) & 0x01)) {
+		ints =  OHCI_INTR_WDH;
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->slot_name);
+		return -1;
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+		dbg("hc_interrupt: returning..\n");
+		return 0xff;
+	}
+
+	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+	if (ints & OHCI_INTR_RHSC) {
+		got_rhsc = 1;
+		stat = 0xff;
+	}
+
+	if (ints & OHCI_INTR_UE) {
+		ohci->disabled++;
+		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+			ohci->slot_name);
+		/* e.g. due to PCI Master/Target Abort */
+
+#ifdef	DEBUG
+		ohci_dump (ohci, 1);
+#else
+	wait_ms(1);
+#endif
+		/* FIXME: be optimistic, hope that bug won't repeat often. */
+		/* Make some non-interrupt context restart the controller. */
+		/* Count and limit the retries though; either hardware or */
+		/* software errors can go forever... */
+		hc_reset (ohci);
+		return -1;
+	}
+
+	if (ints & OHCI_INTR_WDH) {
+		wait_ms(1);
+		writel (OHCI_INTR_WDH, &regs->intrdisable);
+		(void)readl (&regs->intrdisable); /* flush */
+		stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+		writel (OHCI_INTR_WDH, &regs->intrenable);
+		(void)readl (&regs->intrdisable); /* flush */
+	}
+
+	if (ints & OHCI_INTR_SO) {
+		dbg("USB Schedule overrun\n");
+		writel (OHCI_INTR_SO, &regs->intrenable);
+		stat = -1;
+	}
+
+	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
+	if (ints & OHCI_INTR_SF) {
+		unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
+		wait_ms(1);
+		writel (OHCI_INTR_SF, &regs->intrdisable);
+		if (ohci->ed_rm_list[frame] != NULL)
+			writel (OHCI_INTR_SF, &regs->intrenable);
+		stat = 0xff;
+	}
+
+	writel (ints, &regs->intrstatus);
+	return stat;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/* De-allocate all resources.. */
+
+static void hc_release_ohci (ohci_t *ohci)
+{
+	dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+
+	if (!ohci->disabled)
+		hc_reset (ohci);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * low level initalisation routine, called from usb.c
+ */
+static char ohci_inited = 0;
+
+int usb_lowlevel_init(void)
+{
+#ifdef CONFIG_PCI_OHCI
+	pci_dev_t pdev;
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+	/* cpu dependant init */
+	if(usb_cpu_init())
+		return -1;
+#endif
+
+#ifdef CFG_USB_OHCI_BOARD_INIT
+	/*  board dependant init */
+	if(usb_board_init())
+		return -1;
+#endif
+	memset (&gohci, 0, sizeof (ohci_t));
+
+	/* align the storage */
+	if ((__u32)&ghcca[0] & 0xff) {
+		err("HCCA not aligned!!");
+		return -1;
+	}
+	phcca = &ghcca[0];
+	info("aligned ghcca %p", phcca);
+	memset(&ohci_dev, 0, sizeof(struct ohci_device));
+	if ((__u32)&ohci_dev.ed[0] & 0x7) {
+		err("EDs not aligned!!");
+		return -1;
+	}
+	memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
+	if ((__u32)gtd & 0x7) {
+		err("TDs not aligned!!");
+		return -1;
+	}
+	ptd = gtd;
+	gohci.hcca = phcca;
+	memset (phcca, 0, sizeof (struct ohci_hcca));
+
+	gohci.disabled = 1;
+	gohci.sleeping = 0;
+	gohci.irq = -1;
+#ifdef CONFIG_PCI_OHCI
+	pdev = pci_find_devices(ohci_pci_ids, 0);
+
+	if (pdev != -1) {
+		u16 vid, did;
+		u32 base;
+		pci_read_config_word(pdev, PCI_VENDOR_ID, &vid);
+		pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
+		printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n",
+				vid, did, (pdev >> 16) & 0xff,
+				(pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
+		pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base);
+		printf("OHCI regs address 0x%08x\n", base);
+		gohci.regs = (struct ohci_regs *)base;
+	} else
+		return -1;
+#else
+	gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE;
+#endif
+
+	gohci.flags = 0;
+	gohci.slot_name = CFG_USB_OHCI_SLOT_NAME;
+
+	if (hc_reset (&gohci) < 0) {
+		hc_release_ohci (&gohci);
+		err ("can't reset usb-%s", gohci.slot_name);
+#ifdef CFG_USB_OHCI_BOARD_INIT
+		/* board dependant cleanup */
+		usb_board_init_fail();
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+		/* cpu dependant cleanup */
+		usb_cpu_init_fail();
+#endif
+		return -1;
+	}
+
+	/* FIXME this is a second HC reset; why?? */
+	/* writel(gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
+	   wait_ms(10); */
+	if (hc_start (&gohci) < 0) {
+		err ("can't start usb-%s", gohci.slot_name);
+		hc_release_ohci (&gohci);
+		/* Initialization failed */
+#ifdef CFG_USB_OHCI_BOARD_INIT
+		/* board dependant cleanup */
+		usb_board_stop();
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+		/* cpu dependant cleanup */
+		usb_cpu_stop();
+#endif
+		return -1;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (&gohci, 1);
+#else
+	wait_ms(1);
+#endif
+	ohci_inited = 1;
+	return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+	/* this gets called really early - before the controller has */
+	/* even been initialized! */
+	if (!ohci_inited)
+		return 0;
+	/* TODO release any interrupts, etc. */
+	/* call hc_release_ohci() here ? */
+	hc_reset (&gohci);
+
+#ifdef CFG_USB_OHCI_BOARD_INIT
+	/* board dependant cleanup */
+	if(usb_board_stop())
+		return -1;
+#endif
+
+#ifdef CFG_USB_OHCI_CPU_INIT
+	/* cpu dependant cleanup */
+	if(usb_cpu_stop())
+		return -1;
+#endif
+
+	return 0;
+}
+#endif /* CONFIG_USB_OHCI_NEW */
diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h
new file mode 100644
index 0000000..380cb4c
--- /dev/null
+++ b/drivers/usb_ohci.h
@@ -0,0 +1,445 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * usb-ohci.h
+ */
+
+/* functions for doing board or CPU specific setup/cleanup */
+extern int usb_board_init(void);
+extern int usb_board_stop(void);
+extern int usb_board_init_fail(void);
+
+extern int usb_cpu_init(void);
+extern int usb_cpu_stop(void);
+extern int usb_cpu_init_fail(void);
+
+
+static int cc_to_error[16] = {
+
+/* mapping of the OHCI CC status to error codes */
+	/* No  Error  */	       0,
+	/* CRC Error  */	       USB_ST_CRC_ERR,
+	/* Bit Stuff  */	       USB_ST_BIT_ERR,
+	/* Data Togg  */	       USB_ST_CRC_ERR,
+	/* Stall      */	       USB_ST_STALLED,
+	/* DevNotResp */	       -1,
+	/* PIDCheck   */	       USB_ST_BIT_ERR,
+	/* UnExpPID   */	       USB_ST_BIT_ERR,
+	/* DataOver   */	       USB_ST_BUF_ERR,
+	/* DataUnder  */	       USB_ST_BUF_ERR,
+	/* reservd    */	       -1,
+	/* reservd    */	       -1,
+	/* BufferOver */	       USB_ST_BUF_ERR,
+	/* BuffUnder  */	       USB_ST_BUF_ERR,
+	/* Not Access */	       -1,
+	/* Not Access */	       -1
+};
+
+/* ED States */
+
+#define ED_NEW		0x00
+#define ED_UNLINK	0x01
+#define ED_OPER		0x02
+#define ED_DEL		0x04
+#define ED_URB_DEL	0x08
+
+/* usb_ohci_ed */
+struct ed {
+	__u32 hwINFO;
+	__u32 hwTailP;
+	__u32 hwHeadP;
+	__u32 hwNextED;
+
+	struct ed *ed_prev;
+	__u8 int_period;
+	__u8 int_branch;
+	__u8 int_load;
+	__u8 int_interval;
+	__u8 state;
+	__u8 type;
+	__u16 last_iso;
+	struct ed *ed_rm_list;
+
+	struct usb_device *usb_dev;
+	void *purb;
+	__u32 unused[2];
+} __attribute((aligned(16)));
+typedef struct ed ed_t;
+
+
+/* TD info field */
+#define TD_CC	    0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
+#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_EC	    0x0C000000
+#define TD_T	    0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R	    0x00040000
+#define TD_DI	    0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP	    0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+#define TD_ISO	    0x00010000
+#define TD_DEL	    0x00020000
+
+/* CC Codes */
+#define TD_CC_NOERROR	   0x00
+#define TD_CC_CRC	   0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL	   0x04
+#define TD_DEVNOTRESP	   0x05
+#define TD_PIDCHECKFAIL	   0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN	   0x08
+#define TD_DATAUNDERRUN	   0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED	   0x0F
+
+
+#define MAXPSW 1
+
+struct td {
+	__u32 hwINFO;
+	__u32 hwCBP;		/* Current Buffer Pointer */
+	__u32 hwNextTD;		/* Next TD Pointer */
+	__u32 hwBE;		/* Memory Buffer End Pointer */
+
+/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */
+	__u16 hwPSW[MAXPSW];
+/* #endif */
+	__u8 unused;
+	__u8 index;
+	struct ed *ed;
+	struct td *next_dl_td;
+	struct usb_device *usb_dev;
+	int transfer_len;
+	__u32 data;
+
+	__u32 unused2[2];
+} __attribute((aligned(32)));
+typedef struct td td_t;
+
+#define OHCI_ED_SKIP	(1 << 14)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
+#if defined(CONFIG_MPC5200)
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u16	frame_no;		/* current frame number */
+#else
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+#endif
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+
+/*
+ * Maximum number of root hub ports.
+ */
+#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS
+# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!"
+#endif
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.	You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* OHCI CONTROL AND STATUS REGISTER MASKS */
+
+/*
+ * HcControl (control) register masks
+ */
+#define OHCI_CTRL_CBSR	(3 << 0)	/* control/bulk service ratio */
+#define OHCI_CTRL_PLE	(1 << 2)	/* periodic list enable */
+#define OHCI_CTRL_IE	(1 << 3)	/* isochronous enable */
+#define OHCI_CTRL_CLE	(1 << 4)	/* control list enable */
+#define OHCI_CTRL_BLE	(1 << 5)	/* bulk list enable */
+#define OHCI_CTRL_HCFS	(3 << 6)	/* host controller functional state */
+#define OHCI_CTRL_IR	(1 << 8)	/* interrupt routing */
+#define OHCI_CTRL_RWC	(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_RWE	(1 << 10)	/* remote wakeup enable */
+
+/* pre-shifted values for HCFS */
+#	define OHCI_USB_RESET	(0 << 6)
+#	define OHCI_USB_RESUME	(1 << 6)
+#	define OHCI_USB_OPER	(2 << 6)
+#	define OHCI_USB_SUSPEND (3 << 6)
+
+/*
+ * HcCommandStatus (cmdstatus) register masks
+ */
+#define OHCI_HCR	(1 << 0)	/* host controller reset */
+#define OHCI_CLF	(1 << 1)	/* control list filled */
+#define OHCI_BLF	(1 << 2)	/* bulk list filled */
+#define OHCI_OCR	(1 << 3)	/* ownership change request */
+#define OHCI_SOC	(3 << 16)	/* scheduling overrun count */
+
+/*
+ * masks used with interrupt registers:
+ * HcInterruptStatus (intrstatus)
+ * HcInterruptEnable (intrenable)
+ * HcInterruptDisable (intrdisable)
+ */
+#define OHCI_INTR_SO	(1 << 0)	/* scheduling overrun */
+#define OHCI_INTR_WDH	(1 << 1)	/* writeback of done_head */
+#define OHCI_INTR_SF	(1 << 2)	/* start frame */
+#define OHCI_INTR_RD	(1 << 3)	/* resume detect */
+#define OHCI_INTR_UE	(1 << 4)	/* unrecoverable error */
+#define OHCI_INTR_FNO	(1 << 5)	/* frame number overflow */
+#define OHCI_INTR_RHSC	(1 << 6)	/* root hub status change */
+#define OHCI_INTR_OC	(1 << 30)	/* ownership change */
+#define OHCI_INTR_MIE	(1 << 31)	/* master interrupt enable */
+
+
+/* Virtual Root HUB */
+struct virt_root_hub {
+	int devnum; /* Address of Root Hub endpoint */
+	void *dev;  /* was urb */
+	void *int_addr;
+	int send;
+	int interval;
+};
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
+
+/* destination of request */
+#define RH_INTERFACE		   0x01
+#define RH_ENDPOINT		   0x02
+#define RH_OTHER		   0x03
+
+#define RH_CLASS		   0x20
+#define RH_VENDOR		   0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS		0x0080
+#define RH_CLEAR_FEATURE	0x0100
+#define RH_SET_FEATURE		0x0300
+#define RH_SET_ADDRESS		0x0500
+#define RH_GET_DESCRIPTOR	0x0680
+#define RH_SET_DESCRIPTOR	0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE		0x0280
+#define RH_GET_INTERFACE	0x0A80
+#define RH_SET_INTERFACE	0x0B00
+#define RH_SYNC_FRAME		0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP		0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION	   0x00
+#define RH_PORT_ENABLE		   0x01
+#define RH_PORT_SUSPEND		   0x02
+#define RH_PORT_OVER_CURRENT	   0x03
+#define RH_PORT_RESET		   0x04
+#define RH_PORT_POWER		   0x08
+#define RH_PORT_LOW_SPEED	   0x09
+
+#define RH_C_PORT_CONNECTION	   0x10
+#define RH_C_PORT_ENABLE	   0x11
+#define RH_C_PORT_SUSPEND	   0x12
+#define RH_C_PORT_OVER_CURRENT	   0x13
+#define RH_C_PORT_RESET		   0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER	   0x00
+#define RH_C_HUB_OVER_CURRENT	   0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP	   0x00
+#define RH_ENDPOINT_STALL	   0x01
+
+#define RH_ACK			   0x01
+#define RH_REQ_ERR		   -1
+#define RH_NACK			   0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS	     0x00000001		/* current connect status */
+#define RH_PS_PES	     0x00000002		/* port enable status*/
+#define RH_PS_PSS	     0x00000004		/* port suspend status */
+#define RH_PS_POCI	     0x00000008		/* port over current indicator */
+#define RH_PS_PRS	     0x00000010		/* port reset status */
+#define RH_PS_PPS	     0x00000100		/* port power status */
+#define RH_PS_LSDA	     0x00000200		/* low speed device attached */
+#define RH_PS_CSC	     0x00010000		/* connect status change */
+#define RH_PS_PESC	     0x00020000		/* port enable status change */
+#define RH_PS_PSSC	     0x00040000		/* port suspend status change */
+#define RH_PS_OCIC	     0x00080000		/* over current indicator change */
+#define RH_PS_PRSC	     0x00100000		/* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS	     0x00000001		/* local power status */
+#define RH_HS_OCI	     0x00000002		/* over current indicator */
+#define RH_HS_DRWE	     0x00008000		/* device remote wakeup enable */
+#define RH_HS_LPSC	     0x00010000		/* local power status change */
+#define RH_HS_OCIC	     0x00020000		/* over current indicator change */
+#define RH_HS_CRWE	     0x80000000		/* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR		0x0000ffff		/* device removable flags */
+#define RH_B_PPCM	0xffff0000		/* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP	(0xff << 0)		/* number of downstream ports */
+#define RH_A_PSM	(1 << 8)		/* power switching mode */
+#define RH_A_NPS	(1 << 9)		/* no power switching */
+#define RH_A_DT		(1 << 10)		/* device type (mbz) */
+#define RH_A_OCPM	(1 << 11)		/* over current protection mode */
+#define RH_A_NOCP	(1 << 12)		/* no over current protection */
+#define RH_A_POTPGT	(0xff << 24)		/* power on to power good time */
+
+/* urb */
+#define N_URB_TD 48
+typedef struct
+{
+	ed_t *ed;
+	__u16 length;	/* number of tds associated with this request */
+	__u16 td_cnt;	/* number of tds already serviced */
+	struct usb_device *dev;
+	int   state;
+	unsigned long pipe;
+	void *transfer_buffer;
+	int transfer_buffer_length;
+	int interval;
+	int actual_length;
+	int finished;
+	td_t *td[N_URB_TD];	/* list pointer to all corresponding TDs associated with this request */
+} urb_priv_t;
+#define URB_DEL 1
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+typedef struct ohci {
+	struct ohci_hcca *hcca;		/* hcca */
+	/*dma_addr_t hcca_dma;*/
+
+	int irq;
+	int disabled;			/* e.g. got a UE, we're hung */
+	int sleeping;
+	unsigned long flags;		/* for HC bugs */
+
+	struct ohci_regs *regs; /* OHCI controller's memory */
+
+	int ohci_int_load[32];	 /* load of the 32 Interrupt Chains (for load balancing)*/
+	ed_t *ed_rm_list[2];	 /* lists of all endpoints to be removed */
+	ed_t *ed_bulktail;	 /* last endpoint of bulk list */
+	ed_t *ed_controltail;	 /* last endpoint of control list */
+	int intrstatus;
+	__u32 hc_control;		/* copy of the hc control reg */
+	struct usb_device *dev[32];
+	struct virt_root_hub rh;
+
+	const char	*slot_name;
+} ohci_t;
+
+#define NUM_EDS 8		/* num of preallocated endpoint descriptors */
+
+struct ohci_device {
+	ed_t	ed[NUM_EDS];
+	int ed_cnt;
+};
+
+/* hcd */
+/* endpoint */
+static int ep_link(ohci_t * ohci, ed_t * ed);
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
+static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe,
+		int interval, int load);
+
+/*-------------------------------------------------------------------------*/
+
+/* we need more TDs than EDs */
+#define NUM_TD 64
+
+/* +1 so we can align the storage */
+td_t gtd[NUM_TD+1];
+/* pointers to aligned storage */
+td_t *ptd;
+
+/* TDs ... */
+static inline struct td *
+td_alloc (struct usb_device *usb_dev)
+{
+	int i;
+	struct td	*td;
+
+	td = NULL;
+	for (i = 0; i < NUM_TD; i++)
+	{
+		if (ptd[i].usb_dev == NULL)
+		{
+			td = &ptd[i];
+			td->usb_dev = usb_dev;
+			break;
+		}
+	}
+
+	return td;
+}
+
+static inline void
+ed_free (struct ed *ed)
+{
+	ed->usb_dev = NULL;
+}
diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c
index 260befe..1e44f32 100644
--- a/drivers/usbdcore_ep0.c
+++ b/drivers/usbdcore_ep0.c
@@ -2,6 +2,9 @@
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
  *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, deckard@CodeHermit.ie
+ *
  * Based on
  * linux/drivers/usbd/ep0.c
  *
@@ -39,11 +42,17 @@
  * function driver. This may need to change.
  *
  * XXX
+ *
+ * As alluded to above, a simple callback cdc_recv_setup has been implemented
+ * in the usb_device data structure to facilicate passing
+ * Common Device Class packets to a function driver.
+ *
+ * XXX
  */
 
 #include <common.h>
 
-#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE)
+#if defined(CONFIG_USB_DEVICE)
 #include "usbdcore.h"
 
 #if 0
@@ -69,7 +78,7 @@
 	char *cp;
 
 	urb->actual_length = 2;
-	cp = urb->buffer;
+	cp = (char*)urb->buffer;
 	cp[0] = cp[1] = 0;
 
 	switch (requesttype) {
@@ -115,7 +124,7 @@
  *
  * Copy configuration data to urb transfer buffer if there is room for it.
  */
-static void copy_config (struct urb *urb, void *data, int max_length,
+void copy_config (struct urb *urb, void *data, int max_length,
 			 int max_buf)
 {
 	int available;
@@ -128,10 +137,7 @@
 		dbg_ep0 (1, "data is NULL");
 		return;
 	}
-	if (!(length = *(unsigned char *) data)) {
-		dbg_ep0 (1, "length is zero");
-		return;
-	}
+	length = max_length;
 
 	if (length > max_length) {
 		dbg_ep0 (1, "length: %d >= max_length: %d", length,
@@ -192,7 +198,7 @@
 
 	/* setup tx urb */
 	urb->actual_length = 0;
-	cp = urb->buffer;
+	cp = (char*)urb->buffer;
 
 	dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type));
 
@@ -200,7 +206,6 @@
 	case USB_DESCRIPTOR_TYPE_DEVICE:
 		{
 			struct usb_device_descriptor *device_descriptor;
-
 			if (!
 			    (device_descriptor =
 			     usbd_device_device_descriptor (device, port))) {
@@ -214,20 +219,16 @@
 			/* correct the correct control endpoint 0 max packet size into the descriptor */
 			device_descriptor =
 				(struct usb_device_descriptor *) urb->buffer;
-			device_descriptor->bMaxPacketSize0 =
-				urb->device->bus->maxpacketsize;
 
 		}
-		/*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */
+		dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length);
 		break;
 
 	case USB_DESCRIPTOR_TYPE_CONFIGURATION:
 		{
-			int bNumInterface;
 			struct usb_configuration_descriptor
 				*configuration_descriptor;
 			struct usb_device_descriptor *device_descriptor;
-
 			if (!
 			    (device_descriptor =
 			     usbd_device_device_descriptor (device, port))) {
@@ -251,130 +252,35 @@
 					 index);
 				return -1;
 			}
+			dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength));
 			copy_config (urb, configuration_descriptor,
-				     sizeof (struct
-					     usb_configuration_descriptor),
+
+					cpu_to_le16(configuration_descriptor->wTotalLength),
 				     max);
-
-
-			/* iterate across interfaces for specified configuration */
-			dbg_ep0 (0, "bNumInterfaces: %d",
-				 configuration_descriptor->bNumInterfaces);
-			for (bNumInterface = 0;
-			     bNumInterface <
-			     configuration_descriptor->bNumInterfaces;
-			     bNumInterface++) {
-
-				int bAlternateSetting;
-				struct usb_interface_instance
-					*interface_instance;
-
-				dbg_ep0 (3, "[%d] bNumInterfaces: %d",
-					 bNumInterface,
-					 configuration_descriptor->bNumInterfaces);
-
-				if (! (interface_instance = usbd_device_interface_instance (device,
-								     port, index, bNumInterface)))
-				{
-					dbg_ep0 (3, "[%d] interface_instance NULL",
-						 bNumInterface);
-					return -1;
-				}
-				/* iterate across interface alternates */
-				for (bAlternateSetting = 0;
-				     bAlternateSetting < interface_instance->alternates;
-				     bAlternateSetting++) {
-					/*int class; */
-					int bNumEndpoint;
-					struct usb_interface_descriptor *interface_descriptor;
-
-					struct usb_alternate_instance *alternate_instance;
-
-					dbg_ep0 (3, "[%d:%d] alternates: %d",
-						 bNumInterface,
-						 bAlternateSetting,
-						 interface_instance->alternates);
-
-					if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) {
-						dbg_ep0 (3, "[%d] alternate_instance NULL",
-							 bNumInterface);
-						return -1;
-					}
-					/* copy descriptor for this interface */
-					copy_config (urb, alternate_instance->interface_descriptor,
-						     sizeof (struct usb_interface_descriptor),
-						     max);
-
-					/*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */
-					/*        alternate_instance->classes, alternate_instance->endpoints); */
-
-					/* iterate across classes for this alternate interface */
-#if 0
-					for (class = 0;
-					     class < alternate_instance->classes;
-					     class++) {
-						struct usb_class_descriptor *class_descriptor;
-						/*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */
-						/*        class, alternate_instance->classes); */
-						if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) {
-							dbg_ep0 (3, "[%d] class NULL",
-								 class);
-							return -1;
-						}
-						/* copy descriptor for this class */
-						copy_config (urb, class_descriptor,
-							sizeof (struct usb_class_descriptor),
-							max);
-					}
-#endif
-
-					/* iterate across endpoints for this alternate interface */
-					interface_descriptor = alternate_instance->interface_descriptor;
-					for (bNumEndpoint = 0;
-					     bNumEndpoint < alternate_instance->endpoints;
-					     bNumEndpoint++) {
-						struct usb_endpoint_descriptor *endpoint_descriptor;
-						dbg_ep0 (3, "[%d:%d:%d] endpoint: %d",
-							 bNumInterface,
-							 bAlternateSetting,
-							 bNumEndpoint,
-							 interface_descriptor->
-							 bNumEndpoints);
-						if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) {
-							dbg_ep0 (3, "[%d] endpoint NULL",
-								 bNumEndpoint);
-							return -1;
-						}
-						/* copy descriptor for this endpoint */
-						copy_config (urb, endpoint_descriptor,
-							     sizeof (struct usb_endpoint_descriptor),
-							     max);
-					}
-				}
-			}
-			dbg_ep0 (3, "lengths: %d %d",
-				 le16_to_cpu (configuration_descriptor->wTotalLength),
-				 urb->actual_length);
 		}
+
 		break;
 
 	case USB_DESCRIPTOR_TYPE_STRING:
 		{
 			struct usb_string_descriptor *string_descriptor;
-
 			if (!(string_descriptor = usbd_get_string (index))) {
+				serial_printf("Invalid string index %d\n", index);
 				return -1;
 			}
-			/*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */
+			dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength);
 			copy_config (urb, string_descriptor, string_descriptor->bLength, max);
 		}
 		break;
 	case USB_DESCRIPTOR_TYPE_INTERFACE:
+	serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n");
 		return -1;
 	case USB_DESCRIPTOR_TYPE_ENDPOINT:
+		serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n");
 		return -1;
 	case USB_DESCRIPTOR_TYPE_HID:
 		{
+			serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n");
 			return -1;	/* unsupported at this time */
 #if 0
 			int bNumInterface =
@@ -403,6 +309,7 @@
 		break;
 	case USB_DESCRIPTOR_TYPE_REPORT:
 		{
+			serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n");
 			return -1;	/* unsupported at this time */
 #if 0
 			int bNumInterface =
@@ -434,12 +341,19 @@
 #endif
 		}
 		break;
+	case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+		{
+			/* If a USB device supports both a full speed and low speed operation
+			 * we must send a Device_Qualifier descriptor here
+			 */
+			return -1;
+		}
 	default:
 		return -1;
 	}
 
 
-	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d",
+	dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d",
 		 urb->buffer, urb->buffer_length, urb->actual_length,
 		 device->bus->endpoint_array[0].tx_packetSize);
 /*
@@ -495,6 +409,12 @@
 
 	/* handle USB Standard Request (c.f. USB Spec table 9-2) */
 	if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) {
+		if(device->device_state <= STATE_CONFIGURED){
+			/*	Attempt to handle a CDC specific request if we are
+			 *	in the configured state.
+			 */
+			return device->cdc_recv_setup(request,urb);
+		}
 		dbg_ep0 (1, "non standard request: %x",
 			 request->bmRequestType & USB_REQ_TYPE_MASK);
 		return -1;	/* Stall here */
@@ -567,6 +487,7 @@
 						   le16_to_cpu (request->wValue) & 0xff);
 
 		case USB_REQ_GET_CONFIGURATION:
+			serial_printf("get config %d\n", device->configuration);
 			return ep0_get_one (device, urb,
 					    device->configuration);
 
@@ -642,7 +563,6 @@
 			/*dbg_ep0(2, "address: %d %d %d", */
 			/*        request->wValue, le16_to_cpu(request->wValue), device->address); */
 
-			serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n");
 			return 0;
 
 		case USB_REQ_SET_DESCRIPTOR:	/* XXX should we support this? */
@@ -653,9 +573,10 @@
 			/* c.f. 9.4.7 - the top half of wValue is reserved */
 			/* */
 			if ((device->configuration =
-			     le16_to_cpu (request->wValue) & 0x7f) != 0) {
+				le16_to_cpu (request->wValue) & 0xFF80) != 0) {
 				/* c.f. 9.4.7 - zero is the default or addressed state, in our case this */
 				/* is the same is configuration zero */
+				serial_printf("error setting dev->config to zero!\n");
 				device->configuration = 0;	/* TBR - ?????? */
 			}
 			/* reset interface and alternate settings */
diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c
new file mode 100644
index 0000000..e87284b
--- /dev/null
+++ b/drivers/usbdcore_mpc8xx.c
@@ -0,0 +1,1400 @@
+/*
+ * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit
+ * bodonoghue@CodeHermit.ie
+ *
+ * References
+ * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+/*
+ * Notes :
+ * 1.	#define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX
+ *		packet to force the USB re-transmit protocol.
+ *
+ * 2.	#define __DEBUG_UDC__ to switch on debug tracing to serial console
+ *	be careful that tracing doesn't create Hiesen-bugs with respect to
+ *	response timeouts to control requests.
+ *
+ * 3.	This driver should be able to support any higher level driver that
+ *	that wants to do either of the two standard UDC implementations
+ *	Control-Bulk-Interrupt or  Bulk-IN/Bulk-Out standards. Hence
+ *	gserial and cdc_acm should work with this code.
+ *
+ * 4.	NAK events never actually get raised at all, the documentation
+ *	is just wrong !
+ *
+ * 5.	For some reason, cbd_datlen is *always* +2 the value it should be.
+ *	this means that having an RX cbd of 16 bytes is not possible, since
+ *	the same size is reported for 14 bytes received as 16 bytes received
+ *	until we can find out why this happens, RX cbds must be limited to 8
+ *	bytes. TODO: check errata for this behaviour.
+ *
+ * 6.	Right now this code doesn't support properly powering up with the USB
+ *	cable attached to the USB host my development board the Adder87x doesn't
+ *	have a pull-up fitted to allow this, so it is necessary to power the
+ *	board and *then* attached the USB cable to the host. However somebody
+ *	with a different design in their board may be able to keep the cable
+ *	constantly connected and simply enable/disable a pull-up  re
+ *	figure 31.1 in MPC885RM.pdf instead of having to power up the board and
+ *	then attach the cable !
+ *
+ */
+#include <common.h>
+#include <config.h>
+
+#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE)
+#include <commproc.h>
+#include "usbdcore.h"
+#include "usbdcore_mpc8xx.h"
+#include "usbdcore_ep0.h"
+
+#define ERR(fmt, args...)\
+	serial_printf("ERROR : [%s] %s:%d: "fmt,\
+				__FILE__,__FUNCTION__,__LINE__, ##args)
+#ifdef __DEBUG_UDC__
+#define DBG(fmt,args...)\
+		serial_printf("[%s] %s:%d: "fmt,\
+				__FILE__,__FUNCTION__,__LINE__, ##args)
+#else
+#define DBG(fmt,args...)
+#endif
+
+/* Static Data */
+#ifdef __SIMULATE_ERROR__
+static char err_poison_test = 0;
+#endif
+static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS];
+static u32 address_base = STATE_NOT_READY;
+static mpc8xx_udc_state_t udc_state = 0;
+static struct usb_device_instance *udc_device = 0;
+static volatile usb_epb_t *endpoints[MAX_ENDPOINTS];
+static volatile cbd_t *tx_cbd[TX_RING_SIZE];
+static volatile cbd_t *rx_cbd[RX_RING_SIZE];
+static volatile immap_t *immr = 0;
+static volatile cpm8xx_t *cp = 0;
+static volatile usb_pram_t *usb_paramp = 0;
+static volatile usb_t *usbp = 0;
+static int rx_ct = 0;
+static int tx_ct = 0;
+
+/* Static Function Declarations */
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+					    usb_device_state_t final);
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+					      usb_device_state_t final);
+static void mpc8xx_udc_stall (unsigned int ep);
+static void mpc8xx_udc_flush_tx_fifo (int epid);
+static void mpc8xx_udc_flush_rx_fifo (void);
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
+				struct urb *tx_urb);
+static void mpc8xx_udc_dump_request (struct usb_device_request *request);
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+				   volatile cpm8xx_t * cp);
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi);
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_cbd_init (void);
+static void mpc8xx_udc_endpoint_init (void);
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size);
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment);
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp);
+static void mpc8xx_udc_set_nak (unsigned int ep);
+static short mpc8xx_udc_handle_txerr (void);
+static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid);
+
+/******************************************************************************
+			       Global Linkage
+ *****************************************************************************/
+
+/* udc_init
+ *
+ * Do initial bus gluing
+ */
+int udc_init (void)
+{
+	/* Init various pointers */
+	immr = (immap_t *) CFG_IMMR;
+	cp = (cpm8xx_t *) & (immr->im_cpm);
+	usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]);
+	usbp = (usb_t *) & (cp->cp_scc[0]);
+
+	memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS));
+
+	udc_device = 0;
+	udc_state = STATE_NOT_READY;
+
+	usbp->usmod = 0x00;
+	usbp->uscom = 0;
+
+	/* Set USB Frame #0, Respond at Address & Get a clock source  */
+	usbp->usaddr = 0x00;
+	mpc8xx_udc_clock_init (immr, cp);
+
+	/* PA15, PA14 as perhiperal USBRXD and USBOE */
+	immr->im_ioport.iop_padir &= ~0x0003;
+	immr->im_ioport.iop_papar |= 0x0003;
+
+	/* PC11/PC10 as peripheral USBRXP USBRXN */
+	immr->im_ioport.iop_pcso |= 0x0030;
+
+	/* PC7/PC6 as perhiperal USBTXP and USBTXN */
+	immr->im_ioport.iop_pcdir |= 0x0300;
+	immr->im_ioport.iop_pcpar |= 0x0300;
+
+	/* Set the base address */
+	address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE);
+
+	/* Initialise endpoints and circular buffers */
+	mpc8xx_udc_endpoint_init ();
+	mpc8xx_udc_cbd_init ();
+
+	/* Assign allocated Dual Port Endpoint descriptors */
+	usb_paramp->ep0ptr = (u32) endpoints[0];
+	usb_paramp->ep1ptr = (u32) endpoints[1];
+	usb_paramp->ep2ptr = (u32) endpoints[2];
+	usb_paramp->ep3ptr = (u32) endpoints[3];
+	usb_paramp->frame_n = 0;
+
+	DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n",
+	     usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr,
+	     usb_paramp->ep3ptr);
+
+	return 0;
+}
+
+/* udc_irq
+ *
+ * Poll for whatever events may have occured
+ */
+void udc_irq (void)
+{
+	int epid = 0;
+	volatile cbd_t *rx_cbdp = 0;
+	volatile cbd_t *rx_cbdp_base = 0;
+
+	if (udc_state != STATE_READY) {
+		return;
+	}
+
+	if (usbp->usber & USB_E_BSY) {
+		/* This shouldn't happen. If it does then it's a bug ! */
+		usbp->usber |= USB_E_BSY;
+		mpc8xx_udc_flush_rx_fifo ();
+	}
+
+	/* Scan all RX/Bidirectional Endpoints for RX data. */
+	for (epid = 0; epid < MAX_ENDPOINTS; epid++) {
+		if (!ep_ref[epid].prx) {
+			continue;
+		}
+		rx_cbdp = rx_cbdp_base = ep_ref[epid].prx;
+
+		do {
+			if (!(rx_cbdp->cbd_sc & RX_BD_E)) {
+
+				if (rx_cbdp->cbd_sc & 0x1F) {
+					/* Corrupt data discard it.
+					 * Controller has NAK'd this packet.
+					 */
+					mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+				} else {
+					if (!epid) {
+						mpc8xx_udc_ep0_rx (rx_cbdp);
+
+					} else {
+						/* Process data */
+						mpc8xx_udc_set_nak (epid);
+						mpc8xx_udc_epn_rx (epid, rx_cbdp);
+						mpc8xx_udc_clear_rxbd (rx_cbdp);
+					}
+				}
+
+				/* Advance RX CBD pointer */
+				mpc8xx_udc_advance_rx (&rx_cbdp, epid);
+				ep_ref[epid].prx = rx_cbdp;
+			} else {
+				/* Advance RX CBD pointer */
+				mpc8xx_udc_advance_rx (&rx_cbdp, epid);
+			}
+
+		} while (rx_cbdp != rx_cbdp_base);
+	}
+
+	/* Handle TX events as appropiate, the correct place to do this is
+	 * in a tx routine. Perhaps TX on epn was pre-empted by ep0
+	 */
+
+	if (usbp->usber & USB_E_TXB) {
+		usbp->usber |= USB_E_TXB;
+	}
+
+	if (usbp->usber & (USB_TX_ERRMASK)) {
+		mpc8xx_udc_handle_txerr ();
+	}
+
+	/* Switch to the default state, respond at the default address */
+	if (usbp->usber & USB_E_RESET) {
+		usbp->usber |= USB_E_RESET;
+		usbp->usaddr = 0x00;
+		udc_device->device_state = STATE_DEFAULT;
+	}
+
+	/* if(usbp->usber&USB_E_IDLE){
+	   We could suspend here !
+	   usbp->usber|=USB_E_IDLE;
+	   DBG("idle state change\n");
+	   }
+	   if(usbp->usbs){
+	   We could resume here when IDLE is deasserted !
+	   Not worth doing, so long as we are self powered though.
+	   }
+	*/
+
+	return;
+}
+
+/* udc_endpoint_write
+ *
+ * Write some data to an endpoint
+ */
+int udc_endpoint_write (struct usb_endpoint_instance *epi)
+{
+	int ep = 0;
+	short epid = 1, unnak = 0, ret = 0;
+
+	if (udc_state != STATE_READY) {
+		ERR ("invalid udc_state != STATE_READY!\n");
+		return -1;
+	}
+
+	if (!udc_device || !epi) {
+		return -1;
+	}
+
+	if (udc_device->device_state != STATE_CONFIGURED) {
+		return -1;
+	}
+
+	ep = epi->endpoint_address & 0x03;
+	if (ep >= MAX_ENDPOINTS) {
+		return -1;
+	}
+
+	/* Set NAK for all RX endpoints during TX */
+	for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
+
+		/* Don't set NAK on DATA IN/CONTROL endpoints */
+		if (ep_ref[epid].sc & USB_DIR_IN) {
+			continue;
+		}
+
+		if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) {
+			unnak |= 1 << epid;
+		}
+
+		mpc8xx_udc_set_nak (epid);
+	}
+
+	mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep],
+			    epi->tx_urb);
+	ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]);
+
+	/* Remove temporary NAK */
+	for (epid = 1; epid < MAX_ENDPOINTS; epid++) {
+		if (unnak & (1 << epid)) {
+			udc_unset_nak (epid);
+		}
+	}
+
+	return ret;
+}
+
+/* mpc8xx_udc_assign_urb
+ *
+ * Associate a given urb to an endpoint TX or RX transmit/receive buffers
+ */
+static int mpc8xx_udc_assign_urb (int ep, char direction)
+{
+	struct usb_endpoint_instance *epi = 0;
+
+	if (ep >= MAX_ENDPOINTS) {
+		goto err;
+	}
+	epi = &udc_device->bus->endpoint_array[ep];
+	if (!epi) {
+		goto err;
+	}
+
+	if (!ep_ref[ep].urb) {
+		ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array);
+		if (!ep_ref[ep].urb) {
+			goto err;
+		}
+	} else {
+		ep_ref[ep].urb->actual_length = 0;
+	}
+
+	switch (direction) {
+	case USB_DIR_IN:
+		epi->tx_urb = ep_ref[ep].urb;
+		break;
+	case USB_DIR_OUT:
+		epi->rcv_urb = ep_ref[ep].urb;
+		break;
+	default:
+		goto err;
+	}
+	return 0;
+
+      err:
+	udc_state = STATE_ERROR;
+	return -1;
+}
+
+/* udc_setup_ep
+ *
+ * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram
+ * Isochronous endpoints aren't yet supported!
+ */
+void udc_setup_ep (struct usb_device_instance *device, unsigned int ep,
+		   struct usb_endpoint_instance *epi)
+{
+	uchar direction = 0;
+	int ep_attrib = 0;
+
+	if (epi && (ep < MAX_ENDPOINTS)) {
+
+		if (ep == 0) {
+			if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL
+			    || epi->tx_attributes !=
+			    USB_ENDPOINT_XFER_CONTROL) {
+
+				/* ep0 must be a control endpoint */
+				udc_state = STATE_ERROR;
+				return;
+
+			}
+			if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+				mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize,
+						       epi->rcv_packetSize);
+			}
+			usbp->usep[ep] = 0x0000;
+			return;
+		}
+
+		if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK)
+		    == USB_DIR_IN) {
+
+			direction = 1;
+			ep_attrib = epi->tx_attributes;
+			epi->rcv_packetSize = 0;
+			ep_ref[ep].sc |= USB_DIR_IN;
+		} else {
+
+			direction = 0;
+			ep_attrib = epi->rcv_attributes;
+			epi->tx_packetSize = 0;
+			ep_ref[ep].sc &= ~USB_DIR_IN;
+		}
+
+		if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address
+					   & USB_ENDPOINT_DIR_MASK)) {
+			return;
+		}
+
+		switch (ep_attrib) {
+		case USB_ENDPOINT_XFER_CONTROL:
+			if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+				mpc8xx_udc_cbd_attach (ep,
+						       epi->tx_packetSize,
+						       epi->rcv_packetSize);
+			}
+			usbp->usep[ep] = ep << 12;
+			epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb;
+
+			break;
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			if (!(ep_ref[ep].sc & EP_ATTACHED)) {
+				if (direction) {
+					mpc8xx_udc_cbd_attach (ep,
+							       epi->tx_packetSize,
+							       0);
+				} else {
+					mpc8xx_udc_cbd_attach (ep,
+							       0,
+							       epi->rcv_packetSize);
+				}
+			}
+			usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8);
+
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+		default:
+			serial_printf ("Error endpoint attrib %d>3\n", ep_attrib);
+			udc_state = STATE_ERROR;
+			break;
+		}
+	}
+
+}
+
+/* udc_connect
+ *
+ * Move state, switch on the USB
+ */
+void udc_connect (void)
+{
+	/* Enable pull-up resistor on D+
+	 * TODO: fit a pull-up resistor to drive SE0 for > 2.5us
+	 */
+
+	if (udc_state != STATE_ERROR) {
+		udc_state = STATE_READY;
+		usbp->usmod |= USMOD_EN;
+	}
+}
+
+/* udc_disconnect
+ *
+ * Disconnect is not used but, is included for completeness
+ */
+void udc_disconnect (void)
+{
+	/* Disable pull-up resistor on D-
+	 * TODO: fix a pullup resistor to control this
+	 */
+
+	if (udc_state != STATE_ERROR) {
+		udc_state = STATE_NOT_READY;
+	}
+	usbp->usmod &= ~USMOD_EN;
+}
+
+/* udc_enable
+ *
+ * Grab an EP0 URB, register interest in a subset of USB events
+ */
+void udc_enable (struct usb_device_instance *device)
+{
+	if (udc_state == STATE_ERROR) {
+		return;
+	}
+
+	udc_device = device;
+
+	if (!ep_ref[0].urb) {
+		ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array);
+	}
+
+	/* Register interest in all events except SOF, enable transceiver */
+	usbp->usber = 0x03FF;
+	usbp->usbmr = 0x02F7;
+
+	return;
+}
+
+/* udc_disable
+ *
+ * disable the currently hooked device
+ */
+void udc_disable (void)
+{
+	int i = 0;
+
+	if (udc_state == STATE_ERROR) {
+		DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n");
+		return;
+	}
+
+	udc_device = 0;
+
+	for (; i < MAX_ENDPOINTS; i++) {
+		if (ep_ref[i].urb) {
+			usbd_dealloc_urb (ep_ref[i].urb);
+			ep_ref[i].urb = 0;
+		}
+	}
+
+	usbp->usbmr = 0x00;
+	usbp->usmod = ~USMOD_EN;
+	udc_state = STATE_NOT_READY;
+}
+
+/* udc_startup_events
+ *
+ * Enable the specified device
+ */
+void udc_startup_events (struct usb_device_instance *device)
+{
+	udc_enable (device);
+	if (udc_state == STATE_READY) {
+		usbd_device_event_irq (device, DEVICE_CREATE, 0);
+	}
+}
+
+/* udc_set_nak
+ *
+ * Allow upper layers to signal lower layers should not accept more RX data
+ *
+ */
+void udc_set_nak (int epid)
+{
+	if (epid) {
+		mpc8xx_udc_set_nak (epid);
+	}
+}
+
+/* udc_unset_nak
+ *
+ * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint.
+ * Switch off NAKing on this endpoint to accept more data output from host.
+ *
+ */
+void udc_unset_nak (int epid)
+{
+	if (epid > MAX_ENDPOINTS) {
+		return;
+	}
+
+	if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) {
+		usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK);
+		__asm__ ("eieio");
+	}
+}
+
+/******************************************************************************
+			      Static Linkage
+******************************************************************************/
+
+/* udc_state_transition_up
+ * udc_state_transition_down
+ *
+ * Helper functions to implement device state changes.	The device states and
+ * the events that transition between them are:
+ *
+ *				STATE_ATTACHED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_HUB_CONFIGURED			DEVICE_HUB_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_POWERED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_RESET				DEVICE_POWER_INTERRUPTION
+ *				||	/\
+ *				\/	||
+ *				STATE_DEFAULT
+ *				||	/\
+ *				\/	||
+ *	DEVICE_ADDRESS_ASSIGNED			DEVICE_RESET
+ *				||	/\
+ *				\/	||
+ *				STATE_ADDRESSED
+ *				||	/\
+ *				\/	||
+ *	DEVICE_CONFIGURED			DEVICE_DE_CONFIGURED
+ *				||	/\
+ *				\/	||
+ *				STATE_CONFIGURED
+ *
+ * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED
+ * to STATE_CONFIGURED) from the specified initial state to the specified final
+ * state, passing through each intermediate state on the way.  If the initial
+ * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then
+ * no state transitions will take place.
+ *
+ * udc_state_transition_down transitions down (in the direction from
+ * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the
+ * specified final state, passing through each intermediate state on the way.
+ * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final
+ * state, then no state transitions will take place.
+ *
+ */
+
+static void mpc8xx_udc_state_transition_up (usb_device_state_t initial,
+					    usb_device_state_t final)
+{
+	if (initial < final) {
+		switch (initial) {
+		case STATE_ATTACHED:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_HUB_CONFIGURED, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_ADDRESS_ASSIGNED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq (udc_device, DEVICE_CONFIGURED,
+					       0);
+		case STATE_CONFIGURED:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void mpc8xx_udc_state_transition_down (usb_device_state_t initial,
+					      usb_device_state_t final)
+{
+	if (initial > final) {
+		switch (initial) {
+		case STATE_CONFIGURED:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_DE_CONFIGURED, 0);
+			if (final == STATE_ADDRESSED)
+				break;
+		case STATE_ADDRESSED:
+			usbd_device_event_irq (udc_device, DEVICE_RESET, 0);
+			if (final == STATE_DEFAULT)
+				break;
+		case STATE_DEFAULT:
+			usbd_device_event_irq (udc_device,
+					       DEVICE_POWER_INTERRUPTION, 0);
+			if (final == STATE_POWERED)
+				break;
+		case STATE_POWERED:
+			usbd_device_event_irq (udc_device, DEVICE_HUB_RESET,
+					       0);
+		case STATE_ATTACHED:
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/* mpc8xx_udc_stall
+ *
+ * Force returning of STALL tokens on the given endpoint. Protocol or function
+ * STALL conditions are permissable here
+ */
+static void mpc8xx_udc_stall (unsigned int ep)
+{
+	usbp->usep[ep] |= STALL_BITMASK;
+}
+
+/* mpc8xx_udc_set_nak
+ *
+ * Force returning of NAK responses for the given endpoint as a kind of very
+ * simple flow control
+ */
+static void mpc8xx_udc_set_nak (unsigned int ep)
+{
+	usbp->usep[ep] |= NAK_BITMASK;
+	__asm__ ("eieio");
+}
+
+/* mpc8xx_udc_handle_txerr
+ *
+ * Handle errors relevant to TX. Return a status code to allow calling
+ * indicative of what if anything happened
+ */
+static short mpc8xx_udc_handle_txerr ()
+{
+	short ep = 0, ret = 0;
+
+	for (; ep < TX_RING_SIZE; ep++) {
+		if (usbp->usber & (0x10 << ep)) {
+
+			/* Timeout or underrun */
+			if (tx_cbd[ep]->cbd_sc & 0x06) {
+				ret = 1;
+				mpc8xx_udc_flush_tx_fifo (ep);
+
+			} else {
+				if (usbp->usep[ep] & STALL_BITMASK) {
+					if (!ep) {
+						usbp->usep[ep] &= ~STALL_BITMASK;
+					}
+				}	/* else NAK */
+			}
+			usbp->usber |= (0x10 << ep);
+		}
+	}
+	return ret;
+}
+
+/* mpc8xx_udc_advance_rx
+ *
+ * Advance cbd rx
+ */
+static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid)
+{
+	if ((*rx_cbdp)->cbd_sc & RX_BD_W) {
+		*rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CFG_IMMR);
+
+	} else {
+		(*rx_cbdp)++;
+	}
+}
+
+
+/* mpc8xx_udc_flush_tx_fifo
+ *
+ * Flush a given TX fifo. Assumes one tx cbd per endpoint
+ */
+static void mpc8xx_udc_flush_tx_fifo (int epid)
+{
+	volatile cbd_t *tx_cbdp = 0;
+
+	if (epid > MAX_ENDPOINTS) {
+		return;
+	}
+
+	/* TX stop */
+	immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01);
+	__asm__ ("eieio");
+	while (immr->im_cpm.cp_cpcr & 0x01);
+
+	usbp->uscom = 0x40 | 0;
+
+	/* reset ring */
+	tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CFG_IMMR);
+	tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W);
+
+
+	endpoints[epid]->tptr = endpoints[epid]->tbase;
+	endpoints[epid]->tstate = 0x00;
+	endpoints[epid]->tbcnt = 0x00;
+
+	/* TX start */
+	immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01);
+	__asm__ ("eieio");
+	while (immr->im_cpm.cp_cpcr & 0x01);
+
+	return;
+}
+
+/* mpc8xx_udc_flush_rx_fifo
+ *
+ * For the sake of completeness of the namespace, it seems like
+ * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo();
+ * If RX_BD_E is true => a driver bug either here or in an upper layer
+ * not polling frequently enough. If RX_BD_E is true we have told the host
+ * we have accepted data but, the CPM found it had no-where to put that data
+ * which needless to say would be a bad thing.
+ */
+static void mpc8xx_udc_flush_rx_fifo ()
+{
+	int i = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
+			ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n",
+			     rx_cbd[i], rx_cbd[i]->cbd_datlen,
+			     rx_cbd[i]->cbd_sc);
+
+		}
+	}
+	ERR ("BUG : Input over-run\n");
+}
+
+/* mpc8xx_udc_clear_rxbd
+ *
+ * Release control of RX CBD to CP.
+ */
+static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp)
+{
+	rx_cbdp->cbd_datlen = 0x0000;
+	rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I));
+	__asm__ ("eieio");
+}
+
+/* mpc8xx_udc_tx_irq
+ *
+ * Parse for tx timeout, control RX or USB reset/busy conditions
+ * Return -1 on timeout, -2 on fatal error, else return zero
+ */
+static int mpc8xx_udc_tx_irq (int ep)
+{
+	int i = 0;
+
+	if (usbp->usber & (USB_TX_ERRMASK)) {
+		if (mpc8xx_udc_handle_txerr ()) {
+			/* Timeout, controlling function must retry send */
+			return -1;
+		}
+	}
+
+	if (usbp->usber & (USB_E_RESET | USB_E_BSY)) {
+		/* Fatal, abandon TX transaction */
+		return -2;
+	}
+
+	if (usbp->usber & USB_E_RXB) {
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) {
+				if ((rx_cbd[i] == ep_ref[0].prx) || ep) {
+					return -2;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+/* mpc8xx_udc_ep_tx
+ *
+ * Transmit in a re-entrant fashion outbound USB packets.
+ * Implement retry/timeout mechanism described in USB specification
+ * Toggle DATA0/DATA1 pids as necessary
+ * Introduces non-standard tx_retry. The USB standard has no scope for slave
+ * devices to give up TX, however tx_retry stops us getting stuck in an endless
+ * TX loop.
+ */
+static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi)
+{
+	struct urb *urb = epi->tx_urb;
+	volatile cbd_t *tx_cbdp = 0;
+	unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0;
+	int ret = 0;
+
+	if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) {
+		return -1;
+	}
+
+	ep = epi->endpoint_address & 0x03;
+	tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR);
+
+	if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) {
+		mpc8xx_udc_flush_tx_fifo (ep);
+		usbp->usber |= USB_E_TXB;
+	};
+
+	while (tx_retry++ < 100) {
+		ret = mpc8xx_udc_tx_irq (ep);
+		if (ret == -1) {
+			/* ignore timeout here */
+		} else if (ret == -2) {
+			/* Abandon TX */
+			mpc8xx_udc_flush_tx_fifo (ep);
+			return -1;
+		}
+
+		tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR);
+		while (tx_cbdp->cbd_sc & TX_BD_R) {
+		};
+		tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W);
+
+		pkt_len = urb->actual_length - epi->sent;
+
+		if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) {
+			pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT);
+		}
+
+		for (x = 0; x < pkt_len; x++) {
+			*((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) =
+				urb->buffer[epi->sent + x];
+		}
+		tx_cbdp->cbd_datlen = pkt_len;
+		tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid);
+		__asm__ ("eieio");
+
+#ifdef __SIMULATE_ERROR__
+		if (++err_poison_test == 2) {
+			err_poison_test = 0;
+			tx_cbdp->cbd_sc &= ~TX_BD_TC;
+		}
+#endif
+
+		usbp->uscom = (USCOM_STR | ep);
+
+		while (!(usbp->usber & USB_E_TXB)) {
+			ret = mpc8xx_udc_tx_irq (ep);
+			if (ret == -1) {
+				/* TX timeout */
+				break;
+			} else if (ret == -2) {
+				if (usbp->usber & USB_E_TXB) {
+					usbp->usber |= USB_E_TXB;
+				}
+				mpc8xx_udc_flush_tx_fifo (ep);
+				return -1;
+			}
+		};
+
+		if (usbp->usber & USB_E_TXB) {
+			usbp->usber |= USB_E_TXB;
+		}
+
+		/* ACK must be present <= 18bit times from TX */
+		if (ret == -1) {
+			continue;
+		}
+
+		/* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */
+		epi->sent += pkt_len;
+		epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize);
+		TOGGLE_TX_PID (ep_ref[ep].pid);
+
+		if (epi->sent >= epi->tx_urb->actual_length) {
+
+			epi->tx_urb->actual_length = 0;
+			epi->sent = 0;
+
+			if (ep_ref[ep].sc & EP_SEND_ZLP) {
+				ep_ref[ep].sc &= ~EP_SEND_ZLP;
+			} else {
+				return 0;
+			}
+		}
+	}
+
+	ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent,
+	     epi->tx_urb->actual_length);
+
+	return -1;
+}
+
+/* mpc8xx_udc_dump_request
+ *
+ * Dump a control request to console
+ */
+static void mpc8xx_udc_dump_request (struct usb_device_request *request)
+{
+	DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x "
+	     "wIndex:%04x wLength:%04x ?\n",
+	     request->bmRequestType,
+	     request->bRequest,
+	     request->wValue, request->wIndex, request->wLength);
+
+	return;
+}
+
+/* mpc8xx_udc_ep0_rx_setup
+ *
+ * Decode received ep0 SETUP packet. return non-zero on error
+ */
+static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp)
+{
+	unsigned int x = 0;
+	struct urb *purb = ep_ref[0].urb;
+	struct usb_endpoint_instance *epi =
+		&udc_device->bus->endpoint_array[0];
+
+	for (; x < rx_cbdp->cbd_datlen; x++) {
+		*(((unsigned char *) &ep_ref[0].urb->device_request) + x) =
+			*((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
+	}
+
+	mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+	if (ep0_recv_setup (purb)) {
+		mpc8xx_udc_dump_request (&purb->device_request);
+		return -1;
+	}
+
+	if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK)
+	    == USB_REQ_HOST2DEVICE) {
+
+		switch (purb->device_request.bRequest) {
+		case USB_REQ_SET_ADDRESS:
+			/* Send the Status OUT ZLP */
+			ep_ref[0].pid = TX_BD_PID_DATA1;
+			purb->actual_length = 0;
+			mpc8xx_udc_init_tx (epi, purb);
+			mpc8xx_udc_ep_tx (epi);
+
+			/* Move to the addressed state */
+			usbp->usaddr = udc_device->address;
+			mpc8xx_udc_state_transition_up (udc_device->device_state,
+							STATE_ADDRESSED);
+			return 0;
+
+		case USB_REQ_SET_CONFIGURATION:
+			if (!purb->device_request.wValue) {
+				/* Respond at default address */
+				usbp->usaddr = 0x00;
+				mpc8xx_udc_state_transition_down (udc_device->device_state,
+								  STATE_ADDRESSED);
+			} else {
+				/* TODO: Support multiple configurations */
+				mpc8xx_udc_state_transition_up (udc_device->device_state,
+								STATE_CONFIGURED);
+				for (x = 1; x < MAX_ENDPOINTS; x++) {
+					if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK)
+					    == USB_DIR_IN) {
+						ep_ref[x].pid = TX_BD_PID_DATA0;
+					} else {
+						ep_ref[x].pid = RX_BD_PID_DATA0;
+					}
+					/* Set configuration must unstall endpoints */
+					usbp->usep[x] &= ~STALL_BITMASK;
+				}
+			}
+			break;
+		default:
+			/* CDC/Vendor specific */
+			break;
+		}
+
+		/* Send ZLP as ACK in Status OUT phase */
+		ep_ref[0].pid = TX_BD_PID_DATA1;
+		purb->actual_length = 0;
+		mpc8xx_udc_init_tx (epi, purb);
+		mpc8xx_udc_ep_tx (epi);
+
+	} else {
+
+		if (purb->actual_length) {
+			ep_ref[0].pid = TX_BD_PID_DATA1;
+			mpc8xx_udc_init_tx (epi, purb);
+
+			if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) {
+				ep_ref[0].sc |= EP_SEND_ZLP;
+			}
+
+			if (purb->device_request.wValue ==
+			    USB_DESCRIPTOR_TYPE_DEVICE) {
+				if (le16_to_cpu (purb->device_request.wLength)
+				    > purb->actual_length) {
+					/* Send EP0_MAX_PACKET_SIZE bytes
+					 * unless correct size requested.
+					 */
+					if (purb->actual_length > epi->tx_packetSize) {
+						purb->actual_length = epi->tx_packetSize;
+					}
+				}
+			}
+			mpc8xx_udc_ep_tx (epi);
+
+		} else {
+			/* Corrupt SETUP packet? */
+			ERR ("Zero length data or SETUP with DATA-IN phase ?\n");
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/* mpc8xx_udc_init_tx
+ *
+ * Setup some basic parameters for a TX transaction
+ */
+static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi,
+				struct urb *tx_urb)
+{
+	epi->sent = 0;
+	epi->last = 0;
+	epi->tx_urb = tx_urb;
+}
+
+/* mpc8xx_udc_ep0_rx
+ *
+ * Receive ep0/control USB data. Parse and possibly send a response.
+ */
+static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp)
+{
+	if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) {
+
+		/* Unconditionally accept SETUP packets */
+		if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) {
+			mpc8xx_udc_stall (0);
+		}
+
+	} else {
+
+		mpc8xx_udc_clear_rxbd (rx_cbdp);
+
+		if ((rx_cbdp->cbd_datlen - 2)) {
+			/* SETUP with a DATA phase
+			 * outside of SETUP packet.
+			 * Reply with STALL.
+			 */
+			mpc8xx_udc_stall (0);
+		}
+	}
+}
+
+/* mpc8xx_udc_epn_rx
+ *
+ * Receive some data from cbd into USB system urb data abstraction
+ * Upper layers should NAK if there is insufficient RX data space
+ */
+static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp)
+{
+	struct usb_endpoint_instance *epi = 0;
+	struct urb *urb = 0;
+	unsigned int x = 0;
+
+	if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) {
+		return 0;
+	}
+
+	/* USB 2.0 PDF section 8.6.4
+	 * Discard data with invalid PID it is a resend.
+	 */
+	if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) {
+		return 1;
+	}
+	TOGGLE_RX_PID (ep_ref[epid].pid);
+
+	epi = &udc_device->bus->endpoint_array[epid];
+	urb = epi->rcv_urb;
+
+	for (; x < (rx_cbdp->cbd_datlen - 2); x++) {
+		*((unsigned char *) (urb->buffer + urb->actual_length + x)) =
+			*((unsigned char *) (rx_cbdp->cbd_bufaddr + x));
+	}
+
+	if (x) {
+		usbd_rcv_complete (epi, x, 0);
+		if (ep_ref[epid].urb->status == RECV_ERROR) {
+			DBG ("RX error unset NAK\n");
+			udc_unset_nak (epid);
+		}
+	}
+	return x;
+}
+
+/* mpc8xx_udc_clock_init
+ *
+ * Obtain a clock reference for Full Speed Signaling
+ */
+static void mpc8xx_udc_clock_init (volatile immap_t * immr,
+				   volatile cpm8xx_t * cp)
+{
+
+#if defined(CFG_USB_EXTC_CLK)
+
+	/* This has been tested with a 48MHz crystal on CLK6 */
+	switch (CFG_USB_EXTC_CLK) {
+	case 1:
+		immr->im_ioport.iop_papar |= 0x0100;
+		immr->im_ioport.iop_padir &= ~0x0100;
+		cp->cp_sicr |= 0x24;
+		break;
+	case 2:
+		immr->im_ioport.iop_papar |= 0x0200;
+		immr->im_ioport.iop_padir &= ~0x0200;
+		cp->cp_sicr |= 0x2D;
+		break;
+	case 3:
+		immr->im_ioport.iop_papar |= 0x0400;
+		immr->im_ioport.iop_padir &= ~0x0400;
+		cp->cp_sicr |= 0x36;
+		break;
+	case 4:
+		immr->im_ioport.iop_papar |= 0x0800;
+		immr->im_ioport.iop_padir &= ~0x0800;
+		cp->cp_sicr |= 0x3F;
+		break;
+	default:
+		udc_state = STATE_ERROR;
+		break;
+	}
+
+#elif defined(CFG_USB_BRGCLK)
+
+	/* This has been tested with brgclk == 50MHz */
+	DECLARE_GLOBAL_DATA_PTR;
+	int divisor = 0;
+
+	if (gd->cpu_clk < 48000000L) {
+		ERR ("brgclk is too slow for full-speed USB!\n");
+		udc_state = STATE_ERROR;
+		return;
+	}
+
+	/* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz)
+	 * but, can /probably/ live with close-ish alternative rates.
+	 */
+	divisor = (gd->cpu_clk / 48000000L) - 1;
+	cp->cp_sicr &= ~0x0000003F;
+
+	switch (CFG_USB_BRGCLK) {
+	case 1:
+		cp->cp_brgc1 |= (divisor | CPM_BRG_EN);
+		cp->cp_sicr &= ~0x2F;
+		break;
+	case 2:
+		cp->cp_brgc2 |= (divisor | CPM_BRG_EN);
+		cp->cp_sicr |= 0x00000009;
+		break;
+	case 3:
+		cp->cp_brgc3 |= (divisor | CPM_BRG_EN);
+		cp->cp_sicr |= 0x00000012;
+		break;
+	case 4:
+		cp->cp_brgc4 = (divisor | CPM_BRG_EN);
+		cp->cp_sicr |= 0x0000001B;
+		break;
+	default:
+		udc_state = STATE_ERROR;
+		break;
+	}
+
+#else
+#error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined"
+#endif
+
+}
+
+/* mpc8xx_udc_cbd_attach
+ *
+ * attach a cbd to and endpoint
+ */
+static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size)
+{
+
+	if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) {
+		udc_state = STATE_ERROR;
+		return;
+	}
+
+	if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT ||
+	    (!tx_size && !rx_size)) {
+		udc_state = STATE_ERROR;
+		return;
+	}
+
+	/* Attach CBD to appropiate Parameter RAM Endpoint data structure */
+	if (rx_size) {
+		endpoints[ep]->rbase = (u32) rx_cbd[rx_ct];
+		endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+		rx_ct++;
+
+		if (!ep) {
+
+			endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+			rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+			rx_ct++;
+
+		} else {
+			rx_ct += 2;
+			endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct];
+			rx_cbd[rx_ct]->cbd_sc |= RX_BD_W;
+			rx_ct++;
+		}
+
+		/* Where we expect to RX data on this endpoint */
+		ep_ref[ep].prx = rx_cbd[rx_ct - 1];
+	} else {
+
+		ep_ref[ep].prx = 0;
+		endpoints[ep]->rbase = 0;
+		endpoints[ep]->rbptr = 0;
+	}
+
+	if (tx_size) {
+		endpoints[ep]->tbase = (u32) tx_cbd[tx_ct];
+		endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct];
+		tx_ct++;
+	} else {
+		endpoints[ep]->tbase = 0;
+		endpoints[ep]->tbptr = 0;
+	}
+
+	endpoints[ep]->tstate = 0;
+	endpoints[ep]->tbcnt = 0;
+	endpoints[ep]->mrblr = EP_MAX_PKT;
+	endpoints[ep]->rfcr = 0x18;
+	endpoints[ep]->tfcr = 0x18;
+	ep_ref[ep].sc |= EP_ATTACHED;
+
+	DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n",
+		ep, endpoints[ep]->rbase, endpoints[ep]->rbptr,
+		endpoints[ep]->tbase, endpoints[ep]->tbptr,
+		ep_ref[ep].prx);
+
+	return;
+}
+
+/* mpc8xx_udc_cbd_init
+ *
+ * Allocate space for a cbd and allocate TX/RX data space
+ */
+static void mpc8xx_udc_cbd_init (void)
+{
+	int i = 0;
+
+	for (; i < TX_RING_SIZE; i++) {
+		tx_cbd[i] = (cbd_t *)
+			mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
+	}
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_cbd[i] = (cbd_t *)
+			mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int));
+	}
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tx_cbd[i]->cbd_bufaddr =
+			mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
+
+		tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W);
+		tx_cbd[i]->cbd_datlen = 0x0000;
+	}
+
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		rx_cbd[i]->cbd_bufaddr =
+			mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int));
+		rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E);
+		rx_cbd[i]->cbd_datlen = 0x0000;
+
+	}
+
+	return;
+}
+
+/* mpc8xx_udc_endpoint_init
+ *
+ * Attach an endpoint to some dpram
+ */
+static void mpc8xx_udc_endpoint_init (void)
+{
+	int i = 0;
+
+	for (; i < MAX_ENDPOINTS; i++) {
+		endpoints[i] = (usb_epb_t *)
+			mpc8xx_udc_alloc (sizeof (usb_epb_t), 32);
+	}
+}
+
+/* mpc8xx_udc_alloc
+ *
+ * Grab the address of some dpram
+ */
+static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment)
+{
+	u32 retaddr = address_base;
+
+	while (retaddr % alignment) {
+		retaddr++;
+	}
+	address_base += data_size;
+
+	return retaddr;
+}
+
+#endif /* CONFIG_MPC885_FAMILY && CONFIG_USB_DEVICE) */
diff --git a/drivers/usbdcore_omap1510.c b/drivers/usbdcore_omap1510.c
index 1d54a63..84bb936 100644
--- a/drivers/usbdcore_omap1510.c
+++ b/drivers/usbdcore_omap1510.c
@@ -1517,4 +1517,31 @@
 	udc_enable (device);
 }
 
+/**
+ * udc_irq - do pseudo interrupts
+ */
+void udc_irq(void)
+{
+	/* Loop while we have interrupts.
+	 * If we don't do this, the input chain
+	 * polling delay is likely to miss
+	 * host requests.
+	 */
+	while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
+		/* Handle any new IRQs */
+		omap1510_udc_irq ();
+		omap1510_udc_noniso_irq ();
+	}
+}
+
+/* Flow control */
+void udc_set_nak(int epid)
+{
+	/* TODO: implement this functionality in omap1510 */
+}
+
+void udc_unset_nak (int epid)
+{
+	/* TODO: implement this functionality in omap1510 */
+}
 #endif
diff --git a/drivers/usbtty.c b/drivers/usbtty.c
index ce4a12e..a3b5013 100644
--- a/drivers/usbtty.c
+++ b/drivers/usbtty.c
@@ -2,6 +2,9 @@
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
  *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -25,20 +28,42 @@
 #include <circbuf.h>
 #include <devices.h>
 #include "usbtty.h"
+#include "usb_cdc_acm.h"
+#include "usbdescriptors.h"
+#include <config.h>		/* If defined, override Linux identifiers with
+			   	 * vendor specific ones */
 
 #if 0
-#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#define TTYDBG(fmt,args...)\
+	serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
 #else
 #define TTYDBG(fmt,args...) do{}while(0)
 #endif
 
-#if 0
-#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args)
+#if 1
+#define TTYERR(fmt,args...)\
+	serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\
+	__LINE__,##args)
 #else
 #define TTYERR(fmt,args...) do{}while(0)
 #endif
 
 /*
+ * Defines
+ */
+#define NUM_CONFIGS    1
+#define MAX_INTERFACES 2
+#define NUM_ENDPOINTS  3
+#define ACM_TX_ENDPOINT 3
+#define ACM_RX_ENDPOINT 2
+#define GSERIAL_TX_ENDPOINT 2
+#define GSERIAL_RX_ENDPOINT 1
+#define NUM_ACM_INTERFACES 2
+#define NUM_GSERIAL_INTERFACES 1
+#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface"
+#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface"
+
+/*
  * Buffers to hold input and output data
  */
 #define USBTTY_BUFFER_SIZE 256
@@ -50,157 +75,336 @@
  * Instance variables
  */
 static device_t usbttydev;
-static struct usb_device_instance	 device_instance[1];
-static struct usb_bus_instance		 bus_instance[1];
+static struct usb_device_instance device_instance[1];
+static struct usb_bus_instance bus_instance[1];
 static struct usb_configuration_instance config_instance[NUM_CONFIGS];
-static struct usb_interface_instance	 interface_instance[NUM_INTERFACES];
-static struct usb_alternate_instance	 alternate_instance[NUM_INTERFACES];
-static struct usb_endpoint_instance	 endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */
-
-/*
- * Static allocation of urbs
- */
-#define RECV_ENDPOINT 1
-#define TX_ENDPOINT 2
+static struct usb_interface_instance interface_instance[MAX_INTERFACES];
+static struct usb_alternate_instance alternate_instance[MAX_INTERFACES];
+/* one extra for control endpoint */
+static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1];
 
 /*
  * Global flag
  */
 int usbtty_configured_flag = 0;
 
-
 /*
  * Serial number
  */
 static char serial_number[16];
 
+
 /*
- * Descriptors
+ * Descriptors, Strings, Local variables.
  */
+
+/* defined and used by usbdcore_ep0.c */
+extern struct usb_string_descriptor **usb_strings;
+
+/* Indicies, References */
+static unsigned short rx_endpoint = 0;
+static unsigned short tx_endpoint = 0;
+static unsigned short interface_count = 0;
+static struct usb_string_descriptor *usbtty_string_table[STR_COUNT];
+
+/* USB Descriptor Strings */
 static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4};
 static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)];
 static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)];
 static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)];
 static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)];
-static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)];
+static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
+static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)];
 
-static struct usb_string_descriptor *usbtty_string_table[] = {
-  (struct usb_string_descriptor*)wstrLang,
-  (struct usb_string_descriptor*)wstrManufacturer,
-  (struct usb_string_descriptor*)wstrProduct,
-  (struct usb_string_descriptor*)wstrSerial,
-  (struct usb_string_descriptor*)wstrConfiguration,
-  (struct usb_string_descriptor*)wstrInterface
-};
-extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */
-
+/* Standard USB Data Structures */
+static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES];
+static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS];
+static struct usb_configuration_descriptor	*configuration_descriptor = 0;
 static struct usb_device_descriptor device_descriptor = {
-  bLength:	      sizeof(struct usb_device_descriptor),
-  bDescriptorType:    USB_DT_DEVICE,
-  bcdUSB:	      USB_BCD_VERSION,
-  bDeviceClass:	      USBTTY_DEVICE_CLASS,
-  bDeviceSubClass:    USBTTY_DEVICE_SUBCLASS,
-  bDeviceProtocol:    USBTTY_DEVICE_PROTOCOL,
-  bMaxPacketSize0:    EP0_MAX_PACKET_SIZE,
-  idVendor:	      CONFIG_USBD_VENDORID,
-  idProduct:	      CONFIG_USBD_PRODUCTID,
-  bcdDevice:	      USBTTY_BCD_DEVICE,
-  iManufacturer:      STR_MANUFACTURER,
-  iProduct:	      STR_PRODUCT,
-  iSerialNumber:      STR_SERIAL,
-  bNumConfigurations: NUM_CONFIGS
-  };
-static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = {
-  {
-    bLength:		 sizeof(struct usb_configuration_descriptor),
-    bDescriptorType:	 USB_DT_CONFIG,
-    wTotalLength:	 (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) +
-			 (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) +
-			 (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS),
-    bNumInterfaces:	 NUM_INTERFACES,
-    bConfigurationValue: 1,
-    iConfiguration:	 STR_CONFIG,
-    bmAttributes:	 BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED,
-    bMaxPower:		 USBTTY_MAXPOWER
-  },
+	.bLength = sizeof(struct usb_device_descriptor),
+	.bDescriptorType =	USB_DT_DEVICE,
+	.bcdUSB = 		cpu_to_le16(USB_BCD_VERSION),
+	.bDeviceSubClass =	0x00,
+	.bDeviceProtocol =	0x00,
+	.bMaxPacketSize0 =	EP0_MAX_PACKET_SIZE,
+	.idVendor =		cpu_to_le16(CONFIG_USBD_VENDORID),
+	.bcdDevice =		cpu_to_le16(USBTTY_BCD_DEVICE),
+	.iManufacturer =	STR_MANUFACTURER,
+	.iProduct =		STR_PRODUCT,
+	.iSerialNumber =	STR_SERIAL,
+	.bNumConfigurations =	NUM_CONFIGS
 };
-static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = {
-  {
-    bLength:		 sizeof(struct usb_interface_descriptor),
-    bDescriptorType:	 USB_DT_INTERFACE,
-    bInterfaceNumber:	 0,
-    bAlternateSetting:	 0,
-    bNumEndpoints:	 NUM_ENDPOINTS,
-    bInterfaceClass:	 USBTTY_INTERFACE_CLASS,
-    bInterfaceSubClass:	 USBTTY_INTERFACE_SUBCLASS,
-    bInterfaceProtocol:	 USBTTY_INTERFACE_PROTOCOL,
-    iInterface:		 STR_INTERFACE
-  },
+
+
+/*
+ * Static CDC ACM specific descriptors
+ */
+
+struct acm_config_desc {
+	struct usb_configuration_descriptor configuration_desc;
+
+	/* Master Interface */
+	struct usb_interface_descriptor interface_desc;
+
+	struct usb_class_header_function_descriptor usb_class_header;
+	struct usb_class_call_management_descriptor usb_class_call_mgt;
+	struct usb_class_abstract_control_descriptor usb_class_acm;
+	struct usb_class_union_function_descriptor usb_class_union;
+	struct usb_endpoint_descriptor notification_endpoint;
+
+	/* Slave Interface */
+	struct usb_interface_descriptor data_class_interface;
+	struct usb_endpoint_descriptor
+		data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed));
+} __attribute__((packed));
+
+static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = {
+	{
+		.configuration_desc ={
+			.bLength =
+				sizeof(struct usb_configuration_descriptor),
+    			.bDescriptorType = USB_DT_CONFIG,
+			.wTotalLength =
+				cpu_to_le16(sizeof(struct acm_config_desc)),
+	    		.bNumInterfaces = NUM_ACM_INTERFACES,
+    			.bConfigurationValue = 1,
+			.iConfiguration = STR_CONFIG,
+			.bmAttributes =
+				BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+			.bMaxPower = USBTTY_MAXPOWER
+		},
+		/* Interface 1 */
+		.interface_desc = {
+			.bLength  = sizeof(struct usb_interface_descriptor),
+			.bDescriptorType = USB_DT_INTERFACE,
+			.bInterfaceNumber = 0,
+			.bAlternateSetting = 0,
+			.bNumEndpoints = 0x01,
+			.bInterfaceClass =
+				COMMUNICATIONS_INTERFACE_CLASS_CONTROL,
+			.bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS,
+			.bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL,
+			.iInterface = STR_CTRL_INTERFACE,
+		},
+		.usb_class_header = {
+			.bFunctionLength	=
+				sizeof(struct usb_class_header_function_descriptor),
+			.bDescriptorType	= CS_INTERFACE,
+			.bDescriptorSubtype	= USB_ST_HEADER,
+			.bcdCDC	= cpu_to_le16(110),
+		},
+		.usb_class_call_mgt = {
+			.bFunctionLength	=
+				sizeof(struct usb_class_call_management_descriptor),
+			.bDescriptorType	= CS_INTERFACE,
+			.bDescriptorSubtype	= USB_ST_CMF,
+			.bmCapabilities		= 0x00,
+			.bDataInterface		= 0x01,
+		},
+		.usb_class_acm = {
+			.bFunctionLength	=
+				sizeof(struct usb_class_abstract_control_descriptor),
+			.bDescriptorType	= CS_INTERFACE,
+			.bDescriptorSubtype	= USB_ST_ACMF,
+			.bmCapabilities		= 0x00,
+		},
+		.usb_class_union = {
+			.bFunctionLength	=
+				sizeof(struct usb_class_union_function_descriptor),
+			.bDescriptorType	= CS_INTERFACE,
+			.bDescriptorSubtype	= USB_ST_UF,
+			.bMasterInterface	= 0x00,
+			.bSlaveInterface0	= 0x01,
+		},
+		.notification_endpoint = {
+			.bLength =
+				sizeof(struct usb_endpoint_descriptor),
+			.bDescriptorType	= USB_DT_ENDPOINT,
+			.bEndpointAddress	= 0x01 | USB_DIR_IN,
+			.bmAttributes		= USB_ENDPOINT_XFER_INT,
+			.wMaxPacketSize
+				= cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+			.bInterval		= 0xFF,
+		},
+
+		/* Interface 2 */
+		.data_class_interface = {
+			.bLength		=
+				sizeof(struct usb_interface_descriptor),
+			.bDescriptorType	= USB_DT_INTERFACE,
+			.bInterfaceNumber	= 0x01,
+			.bAlternateSetting	= 0x00,
+			.bNumEndpoints		= 0x02,
+			.bInterfaceClass	=
+				COMMUNICATIONS_INTERFACE_CLASS_DATA,
+			.bInterfaceSubClass	= DATA_INTERFACE_SUBCLASS_NONE,
+			.bInterfaceProtocol	= DATA_INTERFACE_PROTOCOL_NONE,
+			.iInterface		= STR_DATA_INTERFACE,
+		},
+		.data_endpoints = {
+			{
+				.bLength		=
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType	= USB_DT_ENDPOINT,
+				.bEndpointAddress	= 0x02 | USB_DIR_OUT,
+				.bmAttributes		=
+					USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize		=
+					cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+				.bInterval		= 0xFF,
+			},
+			{
+				.bLength		=
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType	= USB_DT_ENDPOINT,
+				.bEndpointAddress	= 0x03 | USB_DIR_IN,
+				.bmAttributes		=
+					USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize		=
+					cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE),
+				.bInterval		= 0xFF,
+			},
+		},
+	},
 };
-static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = {
-  {
-    bLength:		 sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:	 USB_DT_ENDPOINT,
-    bEndpointAddress:	 CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT,
-    bmAttributes:	 USB_ENDPOINT_XFER_BULK,
-    wMaxPacketSize:	 CONFIG_USBD_SERIAL_OUT_PKTSIZE,
-    bInterval:		 0
-  },
-  {
-    bLength:		 sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:	 USB_DT_ENDPOINT,
-    bEndpointAddress:	 CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN,
-    bmAttributes:	 USB_ENDPOINT_XFER_BULK,
-    wMaxPacketSize:	 CONFIG_USBD_SERIAL_IN_PKTSIZE,
-    bInterval:		 0
-  },
-  {
-    bLength:		 sizeof(struct usb_endpoint_descriptor),
-    bDescriptorType:	 USB_DT_ENDPOINT,
-    bEndpointAddress:	 CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN,
-    bmAttributes:	 USB_ENDPOINT_XFER_INT,
-    wMaxPacketSize:	 CONFIG_USBD_SERIAL_INT_PKTSIZE,
-    bInterval:		 0
-  },
+
+static struct rs232_emu rs232_desc={
+		.dter 		=  	115200,
+	   	.stop_bits	=	0x00,
+	   	.parity		=	0x00,
+		.data_bits	=	0x08
 };
-static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = {
-  &(ep_descriptors[0]),
-  &(ep_descriptors[1]),
-  &(ep_descriptors[2]),
+
+
+/*
+ * Static Generic Serial specific data
+ */
+
+
+struct gserial_config_desc {
+
+	struct usb_configuration_descriptor configuration_desc;
+	struct usb_interface_descriptor
+		interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed));
+	struct usb_endpoint_descriptor
+		data_endpoints[NUM_ENDPOINTS] __attribute__((packed));
+
+} __attribute__((packed));
+
+static struct gserial_config_desc
+gserial_configuration_descriptors[NUM_CONFIGS] ={
+	{
+		.configuration_desc ={
+			.bLength = sizeof(struct usb_configuration_descriptor),
+			.bDescriptorType = USB_DT_CONFIG,
+			.wTotalLength =
+				cpu_to_le16(sizeof(struct gserial_config_desc)),
+			.bNumInterfaces = NUM_GSERIAL_INTERFACES,
+			.bConfigurationValue = 1,
+			.iConfiguration = STR_CONFIG,
+			.bmAttributes =
+				BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED,
+			.bMaxPower = USBTTY_MAXPOWER
+		},
+		.interface_desc = {
+			{
+				.bLength  =
+					sizeof(struct usb_interface_descriptor),
+				.bDescriptorType = USB_DT_INTERFACE,
+				.bInterfaceNumber = 0,
+				.bAlternateSetting = 0,
+				.bNumEndpoints = NUM_ENDPOINTS,
+				.bInterfaceClass =
+					COMMUNICATIONS_INTERFACE_CLASS_VENDOR,
+				.bInterfaceSubClass =
+					COMMUNICATIONS_NO_SUBCLASS,
+				.bInterfaceProtocol =
+					COMMUNICATIONS_NO_PROTOCOL,
+				.iInterface = STR_DATA_INTERFACE
+			},
+  		},
+		.data_endpoints  = {
+			{
+				.bLength =
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType =	USB_DT_ENDPOINT,
+				.bEndpointAddress =	0x01 | USB_DIR_OUT,
+				.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize =
+					cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE),
+				.bInterval=		0xFF,
+			},
+			{
+				.bLength =
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType =	USB_DT_ENDPOINT,
+				.bEndpointAddress =	0x02 | USB_DIR_IN,
+				.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+				.wMaxPacketSize =
+					cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE),
+				.bInterval = 		0xFF,
+			},
+			{
+				.bLength =
+					sizeof(struct usb_endpoint_descriptor),
+				.bDescriptorType =	USB_DT_ENDPOINT,
+				.bEndpointAddress =	0x03 | USB_DIR_IN,
+				.bmAttributes =		USB_ENDPOINT_XFER_INT,
+    				.wMaxPacketSize =
+					cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE),
+				.bInterval =		0xFF,
+			},
+		},
+	},
 };
 
+/*
+ * Static Function Prototypes
+ */
+
+static void usbtty_init_strings (void);
+static void usbtty_init_instances (void);
+static void usbtty_init_endpoints (void);
+static void usbtty_init_terminal_type(short type);
+static void usbtty_event_handler (struct usb_device_instance *device,
+				usb_device_event_t event, int data);
+static int usbtty_cdc_setup(struct usb_device_request *request,
+				struct urb *urb);
+static int usbtty_configured (void);
+static int write_buffer (circbuf_t * buf);
+static int fill_buffer (circbuf_t * buf);
+
+void usbtty_poll (void);
+
 /* utility function for converting char* to wide string used by USB */
 static void str2wide (char *str, u16 * wide)
 {
 	int i;
-
-	for (i = 0; i < strlen (str) && str[i]; i++)
-		wide[i] = (u16) str[i];
+	for (i = 0; i < strlen (str) && str[i]; i++){
+		#if defined(__LITTLE_ENDIAN)
+			wide[i] = (u16) str[i];
+		#elif defined(__BIG_ENDIAN)
+			wide[i] = ((u16)(str[i])<<8);
+		#else
+			#error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined"
+		#endif
+	}
 }
 
 /*
- * Prototypes
- */
-static void usbtty_init_strings (void);
-static void usbtty_init_instances (void);
-static void usbtty_init_endpoints (void);
-
-static void usbtty_event_handler (struct usb_device_instance *device,
-				  usb_device_event_t event, int data);
-static int usbtty_configured (void);
-
-static int write_buffer (circbuf_t * buf);
-static int fill_buffer (circbuf_t * buf);
-
-void usbtty_poll (void);
-static void pretend_interrupts (void);
-
-
-/*
  * Test whether a character is in the RX buffer
  */
+
 int usbtty_tstc (void)
 {
+	struct usb_endpoint_instance *endpoint =
+		&endpoint_instance[rx_endpoint];
+
+	/* If no input data exists, allow more RX to be accepted */
+	if(usbtty_input.size <= 0){
+		udc_unset_nak(endpoint->endpoint_address&0x03);
+	}
+
 	usbtty_poll ();
 	return (usbtty_input.size > 0);
 }
@@ -210,15 +414,21 @@
  * otherwise. When the function is succesfull, the character read is
  * written into its argument c.
  */
+
 int usbtty_getc (void)
 {
 	char c;
+	struct usb_endpoint_instance *endpoint =
+		&endpoint_instance[rx_endpoint];
 
 	while (usbtty_input.size <= 0) {
+		udc_unset_nak(endpoint->endpoint_address&0x03);
 		usbtty_poll ();
 	}
 
 	buf_pop (&usbtty_input, &c, 1);
+	udc_set_nak(endpoint->endpoint_address&0x03);
+
 	return c;
 }
 
@@ -238,7 +448,6 @@
 	}
 }
 
-
 /* usbtty_puts() helper function for finding the next '\n' in a string */
 static int next_nl_pos (const char *s)
 {
@@ -252,8 +461,9 @@
 }
 
 /*
- * Output a string to the usb client port.
+ * Output a string to the usb client port - implementing flow control
  */
+
 static void __usbtty_puts (const char *str, int len)
 {
 	int maxlen = usbtty_output.totalsize;
@@ -261,22 +471,19 @@
 
 	/* break str into chunks < buffer size, if needed */
 	while (len > 0) {
+		usbtty_poll ();
+
 		space = maxlen - usbtty_output.size;
-
 		/* Empty buffer here, if needed, to ensure space... */
-		if (space <= 0) {
+		if (space) {
 			write_buffer (&usbtty_output);
-			space = maxlen - usbtty_output.size;
-			if (space <= 0) {
-				space = len;	/* allow old data to be overwritten. */
-			}
+
+			n = MIN (space, MIN (len, maxlen));
+			buf_push (&usbtty_output, str, n);
+
+			str += n;
+			len -= n;
 		}
-
-		n = MIN (space, MIN (len, maxlen));
-		buf_push (&usbtty_output, str, n);
-
-		str += n;
-		len -= n;
 	}
 }
 
@@ -313,8 +520,10 @@
 {
 	int rc;
 	char * sn;
+	char * tt;
 	int snlen;
 
+	/* Ger seiral number */
 	if (!(sn = getenv("serial#"))) {
 		sn = "000000000000";
 	}
@@ -327,6 +536,14 @@
 	memcpy (serial_number, sn, snlen);
 	serial_number[snlen] = '\0';
 
+	/* Decide on which type of UDC device to be.
+	 */
+
+	if(!(tt = getenv("usbtty"))) {
+		tt = "generic";
+	}
+	usbtty_init_terminal_type(strcmp(tt,"cdc_acm"));
+
 	/* prepare buffers... */
 	buf_init (&usbtty_input, USBTTY_BUFFER_SIZE);
 	buf_init (&usbtty_output, USBTTY_BUFFER_SIZE);
@@ -337,7 +554,7 @@
 	usbtty_init_strings ();
 	usbtty_init_instances ();
 
-	udc_startup_events (device_instance);	/* Enable our device, initialize udc pointers */
+	udc_startup_events (device_instance);/* Enable dev, init udc pointers */
 	udc_connect ();		/* Enable pullup for host detection */
 
 	usbtty_init_endpoints ();
@@ -362,30 +579,48 @@
 {
 	struct usb_string_descriptor *string;
 
+	usbtty_string_table[STR_LANG] =
+		(struct usb_string_descriptor*)wstrLang;
+
 	string = (struct usb_string_descriptor *) wstrManufacturer;
-	string->bLength = sizeof (wstrManufacturer);
+	string->bLength = sizeof(wstrManufacturer);
 	string->bDescriptorType = USB_DT_STRING;
 	str2wide (CONFIG_USBD_MANUFACTURER, string->wData);
+	usbtty_string_table[STR_MANUFACTURER]=string;
+
 
 	string = (struct usb_string_descriptor *) wstrProduct;
-	string->bLength = sizeof (wstrProduct);
+	string->bLength = sizeof(wstrProduct);
 	string->bDescriptorType = USB_DT_STRING;
 	str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData);
+	usbtty_string_table[STR_PRODUCT]=string;
+
 
 	string = (struct usb_string_descriptor *) wstrSerial;
-	string->bLength = 2 + 2*strlen(serial_number);
+	string->bLength = sizeof(serial_number);
 	string->bDescriptorType = USB_DT_STRING;
 	str2wide (serial_number, string->wData);
+	usbtty_string_table[STR_SERIAL]=string;
+
 
 	string = (struct usb_string_descriptor *) wstrConfiguration;
-	string->bLength = sizeof (wstrConfiguration);
+	string->bLength = sizeof(wstrConfiguration);
 	string->bDescriptorType = USB_DT_STRING;
 	str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData);
+	usbtty_string_table[STR_CONFIG]=string;
 
-	string = (struct usb_string_descriptor *) wstrInterface;
-	string->bLength = sizeof (wstrInterface);
+
+	string = (struct usb_string_descriptor *) wstrDataInterface;
+	string->bLength = sizeof(wstrDataInterface);
 	string->bDescriptorType = USB_DT_STRING;
-	str2wide (CONFIG_USBD_INTERFACE_STR, string->wData);
+	str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData);
+	usbtty_string_table[STR_DATA_INTERFACE]=string;
+
+	string = (struct usb_string_descriptor *) wstrCtrlInterface;
+	string->bLength = sizeof(wstrCtrlInterface);
+	string->bDescriptorType = USB_DT_STRING;
+	str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData);
+	usbtty_string_table[STR_CTRL_INTERFACE]=string;
 
 	/* Now, initialize the string table for ep0 handling */
 	usb_strings = usbtty_string_table;
@@ -400,6 +635,7 @@
 	device_instance->device_state = STATE_INIT;
 	device_instance->device_descriptor = &device_descriptor;
 	device_instance->event = usbtty_event_handler;
+	device_instance->cdc_recv_setup = usbtty_cdc_setup;
 	device_instance->bus = bus_instance;
 	device_instance->configurations = NUM_CONFIGS;
 	device_instance->configuration_instance_array = config_instance;
@@ -415,8 +651,8 @@
 	/* configuration instance */
 	memset (config_instance, 0,
 		sizeof (struct usb_configuration_instance));
-	config_instance->interfaces = NUM_INTERFACES;
-	config_instance->configuration_descriptor = config_descriptors;
+	config_instance->interfaces = interface_count;
+	config_instance->configuration_descriptor = configuration_descriptor;
 	config_instance->interface_instance_array = interface_instance;
 
 	/* interface instance */
@@ -447,17 +683,22 @@
 			sizeof (struct usb_endpoint_instance));
 
 		endpoint_instance[i].endpoint_address =
-			ep_descriptors[i - 1].bEndpointAddress;
+			ep_descriptor_ptrs[i - 1]->bEndpointAddress;
+
+		endpoint_instance[i].rcv_attributes =
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
 
 		endpoint_instance[i].rcv_packetSize =
-			ep_descriptors[i - 1].wMaxPacketSize;
-		endpoint_instance[i].rcv_attributes =
-			ep_descriptors[i - 1].bmAttributes;
+			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
+		endpoint_instance[i].tx_attributes =
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
 
 		endpoint_instance[i].tx_packetSize =
-			ep_descriptors[i - 1].wMaxPacketSize;
+			le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize);
+
 		endpoint_instance[i].tx_attributes =
-			ep_descriptors[i - 1].bmAttributes;
+			ep_descriptor_ptrs[i - 1]->bmAttributes;
 
 		urb_link_init (&endpoint_instance[i].rcv);
 		urb_link_init (&endpoint_instance[i].rdy);
@@ -480,13 +721,79 @@
 	int i;
 
 	bus_instance->max_endpoints = NUM_ENDPOINTS + 1;
-	for (i = 0; i <= NUM_ENDPOINTS; i++) {
+	for (i = 1; i <= NUM_ENDPOINTS; i++) {
 		udc_setup_ep (device_instance, i, &endpoint_instance[i]);
 	}
 }
 
+/* usbtty_init_terminal_type
+ *
+ * Do some late binding for our device type.
+ */
+static void usbtty_init_terminal_type(short type)
+{
+	switch(type){
+		/* CDC ACM */
+		case 0:
+			/* Assign endpoint descriptors */
+			ep_descriptor_ptrs[0] =
+				&acm_configuration_descriptors[0].notification_endpoint;
+			ep_descriptor_ptrs[1] =
+				&acm_configuration_descriptors[0].data_endpoints[0];
+			ep_descriptor_ptrs[2] =
+				&acm_configuration_descriptors[0].data_endpoints[1];
 
-/*********************************************************************************/
+			/* Enumerate Device Descriptor */
+			device_descriptor.bDeviceClass =
+				COMMUNICATIONS_DEVICE_CLASS;
+			device_descriptor.idProduct =
+				cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM);
+
+			/* Assign endpoint indices */
+			tx_endpoint = ACM_TX_ENDPOINT;
+			rx_endpoint = ACM_RX_ENDPOINT;
+
+			/* Configuration Descriptor */
+			configuration_descriptor =
+				(struct usb_configuration_descriptor*)
+				&acm_configuration_descriptors;
+
+			/* Interface count */
+			interface_count = NUM_ACM_INTERFACES;
+		break;
+
+		/* BULK IN/OUT & Default */
+		case 1:
+		default:
+			/* Assign endpoint descriptors */
+			ep_descriptor_ptrs[0] =
+				&gserial_configuration_descriptors[0].data_endpoints[0];
+			ep_descriptor_ptrs[1] =
+				&gserial_configuration_descriptors[0].data_endpoints[1];
+			ep_descriptor_ptrs[2] =
+				&gserial_configuration_descriptors[0].data_endpoints[2];
+
+			/* Enumerate Device Descriptor */
+			device_descriptor.bDeviceClass = 0xFF;
+			device_descriptor.idProduct =
+				cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL);
+
+			/* Assign endpoint indices */
+			tx_endpoint = GSERIAL_TX_ENDPOINT;
+			rx_endpoint = GSERIAL_RX_ENDPOINT;
+
+			/* Configuration Descriptor */
+			configuration_descriptor =
+				(struct usb_configuration_descriptor*)
+				&gserial_configuration_descriptors;
+
+			/* Interface count */
+			interface_count = NUM_GSERIAL_INTERFACES;
+		break;
+	}
+}
+
+/******************************************************************************/
 
 static struct urb *next_urb (struct usb_device_instance *device,
 			     struct usb_endpoint_instance *endpoint)
@@ -526,27 +833,39 @@
 		return 0;
 	}
 
-	if (buf->size) {
+	struct usb_endpoint_instance *endpoint =
+			&endpoint_instance[tx_endpoint];
+	struct urb *current_urb = NULL;
 
-		struct usb_endpoint_instance *endpoint =
-			&endpoint_instance[TX_ENDPOINT];
-		struct urb *current_urb = NULL;
+	current_urb = next_urb (device_instance, endpoint);
+	/* TX data still exists - send it now
+	 */
+	if(endpoint->sent < current_urb->actual_length){
+		if(udc_endpoint_write (endpoint)){
+			/* Write pre-empted by RX */
+			return -1;
+		}
+	}
+
+	if (buf->size) {
 		char *dest;
 
 		int space_avail;
 		int popnum, popped;
 		int total = 0;
 
-		/* Break buffer into urb sized pieces, and link each to the endpoint */
+		/* Break buffer into urb sized pieces,
+		 * and link each to the endpoint
+		 */
 		while (buf->size > 0) {
-			current_urb = next_urb (device_instance, endpoint);
+
 			if (!current_urb) {
 				TTYERR ("current_urb is NULL, buf->size %d\n",
 					buf->size);
 				return total;
 			}
 
-			dest = current_urb->buffer +
+			dest = (char*)current_urb->buffer +
 				current_urb->actual_length;
 
 			space_avail =
@@ -562,14 +881,19 @@
 			current_urb->actual_length += popped;
 			total += popped;
 
-			/* If endpoint->last == 0, then transfers have not started on this endpoint */
+			/* If endpoint->last == 0, then transfers have
+			 * not started on this endpoint
+			 */
 			if (endpoint->last == 0) {
-				udc_endpoint_write (endpoint);
+				if(udc_endpoint_write (endpoint)){
+					/* Write pre-empted by RX */
+					return -1;
+				}
 			}
 
-		}		/* end while */
+		}/* end while */
 		return total;
-	}			/* end if tx_urb */
+	}
 
 	return 0;
 }
@@ -577,18 +901,22 @@
 static int fill_buffer (circbuf_t * buf)
 {
 	struct usb_endpoint_instance *endpoint =
-		&endpoint_instance[RECV_ENDPOINT];
+		&endpoint_instance[rx_endpoint];
 
 	if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) {
-		unsigned int nb = endpoint->rcv_urb->actual_length;
+		unsigned int nb = 0;
 		char *src = (char *) endpoint->rcv_urb->buffer;
+		unsigned int rx_avail = buf->totalsize - buf->size;
 
-		buf_push (buf, src, nb);
-		endpoint->rcv_urb->actual_length = 0;
+		if(rx_avail >= endpoint->rcv_urb->actual_length){
 
+			nb = endpoint->rcv_urb->actual_length;
+			buf_push (buf, src, nb);
+			endpoint->rcv_urb->actual_length = 0;
+
+		}
 		return nb;
 	}
-
 	return 0;
 }
 
@@ -597,7 +925,7 @@
 	return usbtty_configured_flag;
 }
 
-/*********************************************************************************/
+/******************************************************************************/
 
 static void usbtty_event_handler (struct usb_device_instance *device,
 				  usb_device_event_t event, int data)
@@ -619,8 +947,34 @@
 	}
 }
 
-/*********************************************************************************/
+/******************************************************************************/
 
+int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb)
+{
+	switch (request->bRequest){
+
+	   	case ACM_SET_CONTROL_LINE_STATE:	/* Implies DTE ready */
+			break;
+	   	case ACM_SEND_ENCAPSULATED_COMMAND :	/* Required */
+			break;
+		case ACM_SET_LINE_ENCODING :		/* DTE stop/parity bits
+							 * per character */
+			break;
+	   	case ACM_GET_ENCAPSULATED_RESPONSE :	/* request response */
+			break;
+		case ACM_GET_LINE_ENCODING :		/* request DTE rate,
+							 * stop/parity bits */
+			memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc));
+			urb->actual_length = sizeof(rs232_desc);
+
+			break;
+	 	default:
+			return 1;
+	}
+	return 0;
+}
+
+/******************************************************************************/
 
 /*
  * Since interrupt handling has not yet been implemented, we use this function
@@ -630,36 +984,29 @@
 void usbtty_poll (void)
 {
 	/* New interrupts? */
-	pretend_interrupts ();
+	udc_irq();
 
-	/* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */
+	/* Write any output data to host buffer
+	 * (do this before checking interrupts to avoid missing one)
+	 */
 	if (usbtty_configured ()) {
 		write_buffer (&usbtty_output);
 	}
 
 	/* New interrupts? */
-	pretend_interrupts ();
+	udc_irq();
 
-	/* Check for new data from host.. (do this after checking interrupts to get latest data) */
+	/* Check for new data from host..
+	 * (do this after checking interrupts to get latest data)
+	 */
 	if (usbtty_configured ()) {
 		fill_buffer (&usbtty_input);
 	}
 
 	/* New interrupts? */
-	pretend_interrupts ();
+	udc_irq();
+
 }
 
-static void pretend_interrupts (void)
-{
-	/* Loop while we have interrupts.
-	 * If we don't do this, the input chain
-	 * polling delay is likely to miss
-	 * host requests.
-	 */
-	while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) {
-		/* Handle any new IRQs */
-		omap1510_udc_irq ();
-		omap1510_udc_noniso_irq ();
-	}
-}
+
 #endif
diff --git a/drivers/usbtty.h b/drivers/usbtty.h
index 79c2fe5..8154e30 100644
--- a/drivers/usbtty.h
+++ b/drivers/usbtty.h
@@ -2,6 +2,9 @@
  * (C) Copyright 2003
  * Gerry Hamel, geh@ti.com, Texas Instruments
  *
+ * (C) Copyright 2006
+ * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
+ *
  * 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
@@ -21,44 +24,47 @@
 #ifndef __USB_TTY_H__
 #define __USB_TTY_H__
 
-
 #include "usbdcore.h"
+#if defined(CONFIG_PPC)
+#include "usbdcore_mpc8xx.h"
+#elif defined(CONFIG_ARM)
 #include "usbdcore_omap1510.h"
+#endif
 
+#include <version_autogenerated.h>
 
-#define NUM_CONFIGS    1
-#define NUM_INTERFACES 1
-#define NUM_ENDPOINTS  3
+/* If no VendorID/ProductID is defined in config.h, pretend to be Linux
+ * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
 
-#define EP0_MAX_PACKET_SIZE 64
+#define CONFIG_USBD_VENDORID 0x0525 	/* Linux/NetChip */
+#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6	/* gserial */
+#define CONFIG_USBD_PRODUCTID_CDCACM  0xa4a7	/* CDC ACM */
+#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
+#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
+
 
 #define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
-#define CONFIG_USBD_INTERFACE_STR     "Simple Serial Data Interface - Bulk Mode"
 
-
-#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2
-#define CONFIG_USBD_SERIAL_OUT_PKTSIZE	64
-#define CONFIG_USBD_SERIAL_IN_ENDPOINT	1
-#define CONFIG_USBD_SERIAL_IN_PKTSIZE	64
-#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5
-#define CONFIG_USBD_SERIAL_INT_PKTSIZE	16
-
+#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
+#define CONFIG_USBD_SERIAL_OUT_PKTSIZE	UDC_OUT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_IN_ENDPOINT	UDC_IN_ENDPOINT
+#define CONFIG_USBD_SERIAL_IN_PKTSIZE	UDC_IN_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
+#define CONFIG_USBD_SERIAL_INT_PKTSIZE	UDC_INT_PACKET_SIZE
+#define CONFIG_USBD_SERIAL_BULK_PKTSIZE	UDC_BULK_PACKET_SIZE
 
 #define USBTTY_DEVICE_CLASS	COMMUNICATIONS_DEVICE_CLASS
-#define USBTTY_DEVICE_SUBCLASS	COMMUNICATIONS_NO_SUBCLASS
-#define USBTTY_DEVICE_PROTOCOL	COMMUNICATIONS_NO_PROTOCOL
 
-#define USBTTY_INTERFACE_CLASS	   0xFF /* Vendor Specific */
-#define USBTTY_INTERFACE_SUBCLASS  0x02
-#define USBTTY_INTERFACE_PROTOCOL  0x01
+#define USBTTY_BCD_DEVICE 	0x00
+#define USBTTY_MAXPOWER	  	0x00
 
-#define USBTTY_BCD_DEVICE 0x0
-#define USBTTY_MAXPOWER	  0x0
-
-#define STR_MANUFACTURER 1
-#define STR_PRODUCT	 2
-#define STR_SERIAL	 3
-#define STR_CONFIG	 4
-#define STR_INTERFACE	 5
+#define STR_LANG		0x00
+#define STR_MANUFACTURER	0x01
+#define STR_PRODUCT		0x02
+#define STR_SERIAL		0x03
+#define STR_CONFIG		0x04
+#define STR_DATA_INTERFACE	0x05
+#define STR_CTRL_INTERFACE	0x06
+#define STR_COUNT		0x07
 
 #endif