Index: error_msg.c
===================================================================
--- error_msg.c	(revision 0)
+++ error_msg.c	(revision 0)
@@ -0,0 +1,30 @@
+#include <windows.h>
+#include <stdio.h>
+#include "error_msg.h"
+
+VOID display_error_message(DWORD error_number)
+{
+	
+    LPVOID lpMsgBuf;
+    if (!FormatMessage( 
+		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+        FORMAT_MESSAGE_FROM_SYSTEM | 
+		FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+		error_number,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+		(LPTSTR) &lpMsgBuf,
+        0,
+		NULL ))
+    {
+	// Handle the error.
+	return;
+    }
+
+    // Display the string.
+    printf("Error! %s\n", (LPCTSTR)lpMsgBuf );
+
+    // Free the buffer.
+    LocalFree( lpMsgBuf );
+}
+
Index: flash.h
===================================================================
--- flash.h	(revision 670)
+++ flash.h	(working copy)
@@ -30,7 +30,11 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <stdio.h>
+#ifdef __MINGW32_VERSION
+#include "libpci/pci.h"
+#else
 #include <pci/pci.h>
+#endif
 
 /* for iopl and outb under Solaris */
 #if defined (__sun) && (defined(__i386) || defined(__amd64))
Index: error_msg.h
===================================================================
--- error_msg.h	(revision 0)
+++ error_msg.h	(revision 0)
@@ -0,0 +1,11 @@
+#ifndef __ERROR_MSG_H__
+#define __ERROR_MSG_H__
+
+/*
+ * Note: Error number can be found easily with GetLastError() function
+ */
+
+void display_error_message(unsigned long error_number);
+
+#endif //__ERROR_MSG_H__
+
Index: driver/winflashrom.h
===================================================================
--- driver/winflashrom.h	(revision 0)
+++ driver/winflashrom.h	(revision 0)
@@ -0,0 +1,83 @@
+#ifndef __WINFLASHROM_H__
+#define __WINFLASHROM_H__
+
+#include <ntddk.h>
+#include "../interfaces.h"
+
+//  Debugging macros
+
+#if DBG
+#define WINFLASHROM_KDPRINT(_x_) \
+                DbgPrint("WINFLASHROM.SYS: ");\
+                DbgPrint _x_;
+#else
+
+#define WINFLASHROM_KDPRINT(_x_)
+
+#endif
+
+
+
+#define WINFLASHROM_DEVICE_NAME_U     L"\\Device\\winflashrom"
+#define WINFLASHROM_DOS_DEVICE_NAME_U L"\\DosDevices\\winflashrom"
+
+
+typedef struct _MMIO_RING_0_MAP{
+    PVOID  sysAddrBase;	    	// start of system virtual address of the mapped physical address range 
+    ULONG64 phyAddrStart;    	// start of physical address of the mapped MMIO
+    ULONG  size;		// size of the mapped physical address range 
+    PVOID  usermodeAddrBase; 	// pointer to the usermode virtual address where this range is mapped
+    PMDL pMdl;		    	// Memory Descriptor List for the memory mapped I/O range to be mapped
+}MMIO_RING_0_MAP, *PMMIO_RING_0_MAP;
+
+typedef struct _DEVICE_EXTENSION{
+    MMIO_RING_0_MAP mapZone[MAX_MAPPED_MMIO];   
+}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef enum {false = 0, true = 1} bool;
+
+NTSTATUS
+DriverEntry(
+    IN PDRIVER_OBJECT  DriverObject,
+    IN PUNICODE_STRING registryPath
+);
+
+NTSTATUS
+DispatchCreate(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+    );
+
+NTSTATUS
+DispatchClose(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+    );
+
+VOID
+DispatchUnload(
+    IN PDRIVER_OBJECT DriverObject
+    );
+
+NTSTATUS
+DispatchRead(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+);
+
+
+NTSTATUS
+DispatchWrite(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+);
+
+NTSTATUS
+DispatchIoControl(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp
+);
+
+#endif //__WINFLASHROM_H__
+
+
Index: driver/sources
===================================================================
--- driver/sources	(revision 0)
+++ driver/sources	(revision 0)
@@ -0,0 +1,17 @@
+TARGETNAME=winflashrom
+TARGETPATH=.
+TARGETTYPE=DRIVER
+
+#
+# The  WinXP DDK has introduced the DDK_TARGET_OS environemnt variable
+# for conditional compilation.  The test here is designed to make this
+# sources file portable to the standalone Win 2K DDK environment.  Note,
+# however, that the required csq.h and csq.lib are not present in that
+# environment.
+#
+!if "$(DDK_TARGET_OS)"!="WinXP"
+C_DEFINES=$(C_DEFINES) -DW2K=1
+TARGETLIBS=$(DDK_LIB_PATH)\csq.lib
+!endif
+
+SOURCES=winflashrom.c
Index: driver/winflashrom.c
===================================================================
--- driver/winflashrom.c	(revision 0)
+++ driver/winflashrom.c	(revision 0)
@@ -0,0 +1,899 @@
+/*! \file
+ 
+Module Name:	winflashrom.c
+
+Abstract:   Main file of winflashrom device driver 
+
+Author:	    Darmawan Salihun 
+
+Environment:	Kernel mode
+
+Revision History:
+    
+    - (June 2007) BIOS Probing device driver Modified to work with winflashrom
+    - (July 29th) MMIO mapping limited to low 1MB and 4GB-20MB to 4GB physical address range
+*/
+
+#include "winflashrom.h"
+#include <devioctl.h>
+#include "../interfaces.h"
+
+static const ULONG _1MB = 0x100000;
+static const ULONG64 _4GB = 0x100000000 ;
+static const ULONG _4GB_min_20MB = (0x100000000 - (20*0x100000)); 
+
+
+NTSTATUS DriverEntry( IN PDRIVER_OBJECT  DriverObject, IN PUNICODE_STRING RegistryPath )
+/*!
+
+\brief 	Installable driver initialization entry point.
+    	This entry point is called directly by the I/O system.
+
+
+\param	DriverObject - pointer to the driver object
+
+\param 	RegistryPath - pointer to a unicode string representing the path,
+                   to driver-specific key in the registry.
+
+\retval    STATUS_SUCCESS if successful,
+\retval    STATUS_UNSUCCESSFUL otherwise
+
+*/
+{
+    NTSTATUS            status = STATUS_SUCCESS;
+    UNICODE_STRING      unicodeDeviceName;   
+    UNICODE_STRING      unicodeDosDeviceName;  
+    PDEVICE_OBJECT      deviceObject;
+    PDEVICE_EXTENSION	pDevExt;
+    ULONG		i;
+    
+    UNREFERENCED_PARAMETER (RegistryPath);
+
+    WINFLASHROM_KDPRINT(("DriverEntry Enter \n"));
+
+    DriverObject->DriverUnload = DispatchUnload;    
+
+    DriverObject->MajorFunction[IRP_MJ_CREATE]= DispatchCreate;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
+    DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead; 
+    DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoControl;
+
+   
+    (void) RtlInitUnicodeString(&unicodeDeviceName, WINFLASHROM_DEVICE_NAME_U);
+
+    status = IoCreateDevice(
+                DriverObject,
+                sizeof(DEVICE_EXTENSION),
+                &unicodeDeviceName,
+                FILE_DEVICE_UNKNOWN,
+                0,
+                (BOOLEAN) FALSE,
+                &deviceObject
+                );
+
+    if (!NT_SUCCESS(status))
+    {
+        return status;
+    }
+
+    WINFLASHROM_KDPRINT(("DeviceObject %p\n", deviceObject));
+
+    //
+    // Set the flag signifying that we will do direct I/O. This causes NT
+    // to lock the user buffer into memory when it's accessed
+    //
+    deviceObject->Flags |= DO_DIRECT_IO;
+
+    
+    //
+    // Allocate and initialize a Unicode String containing the Win32 name
+    // for our device.
+    //
+    (void)RtlInitUnicodeString( &unicodeDosDeviceName, WINFLASHROM_DOS_DEVICE_NAME_U );
+
+
+    status = IoCreateSymbolicLink(  (PUNICODE_STRING) &unicodeDosDeviceName,
+				    (PUNICODE_STRING) &unicodeDeviceName );
+
+    if (!NT_SUCCESS(status))
+    {
+        IoDeleteDevice(deviceObject);
+        return status;
+    }
+
+    //
+    // Initialize device extension
+    //
+    pDevExt = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
+    for(i = 0; i < MAX_MAPPED_MMIO; i++) 
+    {
+	pDevExt->mapZone[i].sysAddrBase = NULL;
+	pDevExt->mapZone[i].phyAddrStart = _4GB; // Note: _4GB is considered invalid phyAddrStart
+	pDevExt->mapZone[i].size = 0;
+	pDevExt->mapZone[i].usermodeAddrBase = NULL;
+	pDevExt->mapZone[i].pMdl = NULL;
+    }    
+    
+    WINFLASHROM_KDPRINT(("DriverEntry Exit = %x\n", status));
+
+    return status;
+}
+
+
+NTSTATUS DispatchCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
+/*!
+\brief
+   Process the create IRPs sent to this device.
+   This routine does nothing but signalling 
+   successful IRP handling.
+
+\param 	DeviceObject - pointer to a device object.
+\param	Irp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    NTSTATUS             status = STATUS_SUCCESS;
+
+    WINFLASHROM_KDPRINT(("DispatchCreate Enter\n"));
+
+    // 
+    // The dispatch routine for IRP_MJ_CREATE is called when a 
+    // file object associated with the device is created. 
+    // This is typically because of a call to CreateFile() in 
+    // a user-mode program or because another driver is 
+    // layering itself over a this driver. A driver is 
+    // required to supply a dispatch routine for IRP_MJ_CREATE.
+    //
+    WINFLASHROM_KDPRINT(("IRP_MJ_CREATE\n"));
+    Irp->IoStatus.Information = 0;
+    
+    //
+    // Save Status for return and complete Irp
+    //
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    WINFLASHROM_KDPRINT((" DispatchCreate Exit = %x\n", status));
+
+    return status;
+}
+
+
+NTSTATUS ReadPortByte(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_READ_PORT_BYTE code. 
+    This routine reads a byte from the designated port, 
+    and returns the value to usermode application 
+    through pointer to the locked-down usermode buffer 
+    in the IRP.
+
+
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_BYTE* pUsermodeMem =  (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem ;// build user-mode memory pointer register	
+	    mov dx,[ebx].port8	    ;// fetch input port addr
+	    in  al,dx		    ;// read the byte from the device
+	    mov [ebx].value8, al   ;// write probing result directly to user-mode memory
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+NTSTATUS ReadPortWord(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_READ_PORT_WORD code. 
+    This routine reads a word from the designated port, 
+    and returns the value to usermode application 
+    through pointer to the locked-down usermode buffer 
+    in the IRP.
+
+\param 	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_WORD* pUsermodeMem =  (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem	;// build user-mode memory pointer register	
+	    mov dx, [ebx].port16	;// fetch input port addr
+	    in  ax, dx			;// read the bytes from the device
+	    mov [ebx].value16, ax	;// write probing result directly to user-mode memory
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+NTSTATUS ReadPortLong(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_READ_PORT_LONG code. 
+    This routine reads a DWORD from the designated port, 
+    and returns the value to usermode application 
+    through pointer to the locked-down usermode buffer 
+    in the IRP.
+
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_LONG* pUsermodeMem =  (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem	;// build user-mode memory pointer register	
+	    mov dx, [ebx].port32	;// fetch input port addr
+	    in  eax, dx			;// read the bytes from the device
+	    mov [ebx].value32, eax	;// write probing result directly to user-mode memory
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+NTSTATUS WritePortByte(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_WRITE_PORT_BYTE code. 
+    This routine writes a byte to the designated port. 
+    The value of the byte and the port address are obtained  
+    through pointer to the locked-down buffer in the IRP.
+
+\param 	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+--*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_BYTE* pUsermodeMem =  (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem	;// build user-mode memory pointer register	
+	    mov dx, [ebx].port8	;// fetch input port addr
+    	    mov al, [ebx].value8	;// read the value to be written directly from user-mode memory
+	    out dx, al			;// write the byte to the device
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+NTSTATUS WritePortWord(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_WRITE_PORT_WORD code. 
+    This routine writes a word to the designated port. 
+    The value of the word and the port address are obtained  
+    through pointer to the locked-down buffer in the IRP.
+
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_WORD* pUsermodeMem =  (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem	;// build user-mode memory pointer register	
+	    mov dx, [ebx].port16	;// fetch input port addr
+    	    mov ax, [ebx].value16	;// read the value to be written directly from user-mode memory
+	    out dx, ax			;// write the bytes to the device
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+NTSTATUS WritePortLong(PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_WRITE_PORT_LONG code. 
+    This routine writes a dword to the designated port. 
+    The value of the dword and the port address are obtained  
+    through pointer to the locked-down buffer in the IRP.
+
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+--*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    IO_LONG* pUsermodeMem =  (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    if( NULL != pUsermodeMem) {
+        __asm
+	{
+	    pushad		    ;// save all register contents
+
+	    mov ebx, pUsermodeMem	;// build user-mode memory pointer register	
+	    mov dx, [ebx].port32	;// fetch input port addr
+    	    mov eax, [ebx].value32	;// read the value to be written directly from user-mode memory
+	    out dx, eax			;// write the bytes to the device
+
+	    popad		    ;// restore all saved register value
+	}
+	
+    } else {
+	status = STATUS_INVALID_USER_BUFFER;
+    }
+
+    return status;
+}
+
+
+bool VerifyMmioAddressRange(ULONG64 phyAddrStart, ULONG size, PDEVICE_EXTENSION pDevExt)
+/*!
+\brief
+   Verify whether the memory-mapped I/O address range 
+   requested by the user mode application lies within 
+   the "correct" address range that this driver will handle.
+
+   This verification is needed to prevent user mode 
+   application from mapping dangerous memory-mapped I/O 
+   address range to user mode application
+
+\param	phyAddrStart - starting physical address of the MMIO range to be mapped
+\param	size - the size of the MMIO range to be mapped
+\param	pDevExt - pointer to the DEVICE_EXTENSION of this driver
+
+\retval false if the MMIO range contains "incorrect" address range
+\retval true if the MMIO range doesn't contain "incorrect" address range
+*/
+{
+  int i;	
+  ULONG64 bottom, top ;
+
+  WINFLASHROM_KDPRINT(("phyAddrStart = 0x%X \n", phyAddrStart));
+  WINFLASHROM_KDPRINT(("size = 0x%X \n", size));
+    
+  /* First, check whether the MMIO range lies in the low 1MB range __or__ 
+   * whether the MMIO range lies between the 4GB-20MB and 4GB limit 
+   */
+
+  if((phyAddrStart > _1MB ) && ((phyAddrStart + size) < _4GB_min_20MB)) {
+  	return false;
+
+  } else if (phyAddrStart > _4GB) {
+	return false;
+  }
+  
+  /* Now, check whether part or all of the requested physical address range 
+   * has been mapped previously by the application that open access to this driver. 
+   */ 
+  
+    for(i = 0; i < MAX_MAPPED_MMIO; i++)
+    {
+	if( pDevExt->mapZone[i].phyAddrStart != _4GB)
+	{
+      	  bottom = pDevExt->mapZone[i].phyAddrStart;
+	  top = pDevExt->mapZone[i].phyAddrStart + pDevExt->mapZone[i].size;
+      
+	  WINFLASHROM_KDPRINT(("pDevExt->mapZone[%u].phyAddrStart = 0x%X \n", i, pDevExt->mapZone[i].phyAddrStart));
+	  WINFLASHROM_KDPRINT(("pDevExt->mapZone[%u].size = 0x%X \n", i, pDevExt->mapZone[i].size));
+          	  
+	  if( (phyAddrStart < bottom ) && ((phyAddrStart + size) > bottom) ){ // enclosing or intersection in lower limit of mapZone[i]
+	   	return false;
+		
+	  } else if ((phyAddrStart > bottom) && ((phyAddrStart + size) < top )) { // enclosed by mapZone[i]
+	   	return false;
+		
+	  } else if ((phyAddrStart < top) && ((phyAddrStart + size) > top )) {  // enclosing or intersection in upper limit of mapZone[i]
+		return false;			  
+	  }    
+   	}	
+	
+    }	    
+
+    return true;
+}
+
+
+
+NTSTATUS MapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_MAP_MMIO code. 
+    This routine maps a physical address range 
+    to the usermode application address space. 
+
+    This function can only map the area 
+    below the 4GB limit.
+
+\param	pDO - pointer to the device object of this driver.
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval NT Status code
+*/
+{
+    PDEVICE_EXTENSION pDevExt;
+    PHYSICAL_ADDRESS phyAddr;
+    MMIO_MAP* pUsermodeMem;
+    ULONG   i, free_idx;
+	    
+    pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
+
+    //
+    // Check for free mapZone in the device extension.
+    // If none is free, return an error code.
+    //
+    for(i = 0; i < MAX_MAPPED_MMIO; i++)
+    {
+	if( pDevExt->mapZone[i].sysAddrBase == NULL )
+	{
+	    free_idx = i;
+	    break;
+	}	
+    }	    
+    
+    if( i == MAX_MAPPED_MMIO )
+    {
+	return STATUS_UNSUCCESSFUL;
+    }
+    
+    //
+    // We have obtained a free mapZone, check whether the requested address range  
+    // is valid and map the MMIO if it's valid
+    //    
+    pUsermodeMem =  (MMIO_MAP*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+    if( NULL == pUsermodeMem) {
+	return STATUS_INVALID_USER_BUFFER;
+    } 
+   
+    if( false == VerifyMmioAddressRange(pUsermodeMem->phy_addr_start, pUsermodeMem->size, pDevExt)){
+	return STATUS_UNSUCCESSFUL;
+    }
+	
+    
+    phyAddr.HighPart = 0;
+    phyAddr.LowPart = pUsermodeMem->phy_addr_start;
+
+    pDevExt->mapZone[free_idx].sysAddrBase = MmMapIoSpace( phyAddr, pUsermodeMem->size, MmNonCached);
+    if(NULL == pDevExt->mapZone[free_idx].sysAddrBase) {
+	return STATUS_BUFFER_TOO_SMALL;
+    
+    } else {
+	pDevExt->mapZone[free_idx].phyAddrStart = pUsermodeMem->phy_addr_start;
+    }
+	    
+    
+    pDevExt->mapZone[free_idx].pMdl = IoAllocateMdl(pDevExt->mapZone[free_idx].sysAddrBase, 
+						    pUsermodeMem->size, FALSE, FALSE, NULL);
+    if(NULL == pDevExt->mapZone[free_idx].pMdl) 	    
+    {
+	MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase, pUsermodeMem->size);
+	pDevExt->mapZone[free_idx].sysAddrBase = NULL;
+	pDevExt->mapZone[free_idx].phyAddrStart =  _4GB;
+	return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    pDevExt->mapZone[free_idx].size = pUsermodeMem->size;
+
+    //
+    // Map the system virtual address to usermode virtual address
+    // 
+    MmBuildMdlForNonPagedPool(pDevExt->mapZone[free_idx].pMdl);
+    pDevExt->mapZone[free_idx].usermodeAddrBase = MmMapLockedPagesSpecifyCache(	pDevExt->mapZone[free_idx].pMdl, 
+										UserMode, MmNonCached, 
+										NULL, FALSE,  
+										NormalPagePriority);
+    if(NULL ==  pDevExt->mapZone[free_idx].usermodeAddrBase)
+    {
+	IoFreeMdl(pDevExt->mapZone[free_idx].pMdl);
+	MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase, pDevExt->mapZone[free_idx].size);
+	pDevExt->mapZone[free_idx].sysAddrBase = NULL;
+	pDevExt->mapZone[free_idx].phyAddrStart =  _4GB;
+	pDevExt->mapZone[free_idx].size = 0;
+	return STATUS_BUFFER_TOO_SMALL;
+    } 
+
+    // copy the resulting usermode virtual address to IRP "buffer"
+    pUsermodeMem->usermode_virt_addr = pDevExt->mapZone[free_idx].usermodeAddrBase;
+    
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS CleanupMmioMapping(PDEVICE_EXTENSION pDevExt, ULONG i)
+/*!
+\brief
+    This routine cleanup the mapping of a MMIO range 
+    and resources it consumes.
+    
+
+\param	pDevExt - pointer to the device extension of the driver
+\param	i - index of the mapZone to cleanup
+
+\retval	NT Status code
+*/
+{
+    if( NULL != pDevExt->mapZone[i].usermodeAddrBase )
+    {
+	MmUnmapLockedPages( pDevExt->mapZone[i].usermodeAddrBase, 
+			    pDevExt->mapZone[i].pMdl); 
+	pDevExt->mapZone[i].usermodeAddrBase = NULL;
+    }
+	    
+    if( NULL != pDevExt->mapZone[i].pMdl )
+    {
+	IoFreeMdl(pDevExt->mapZone[i].pMdl); 
+	pDevExt->mapZone[i].pMdl = NULL;
+    }
+	
+    if( NULL != pDevExt->mapZone[i].sysAddrBase )
+    {
+        MmUnmapIoSpace(	pDevExt->mapZone[i].sysAddrBase, 
+			pDevExt->mapZone[i].size); 
+        pDevExt->mapZone[i].sysAddrBase = NULL;
+	pDevExt->mapZone[i].phyAddrStart = _4GB;
+	pDevExt->mapZone[i].size = 0;
+    } 
+
+    return STATUS_SUCCESS; 
+}
+
+	
+NTSTATUS UnmapMmio(PDEVICE_OBJECT pDO, PIRP pIrp)
+/*!
+\brief
+    Process the IRPs with IOCTL_UNMAP_MMIO code. 
+    This routine unmaps a previously mapped physical 
+    address range.
+
+    This function can only unmap the area 
+    below the 4-GB limit.
+
+
+\param	pDO - pointer to the device object of this driver.
+\param	pIrp - pointer to an I/O Request Packet.
+
+\retval	NT Status code
+*/
+{
+    PDEVICE_EXTENSION pDevExt;
+    MMIO_MAP* pMmioMap;
+    ULONG i;
+    
+    // 
+    // Unmap the requested zone from the system address space 
+    // and update the device extension data
+    // 
+    pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
+    pMmioMap = (MMIO_MAP*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
+
+    for(i = 0 ; i < MAX_MAPPED_MMIO; i++)
+    {
+	if(pDevExt->mapZone[i].usermodeAddrBase == pMmioMap->usermode_virt_addr)
+	{
+	    CleanupMmioMapping(pDevExt, i);
+	    break;
+	}
+    }
+    
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DispatchIoControl( IN PDEVICE_OBJECT pDO, IN PIRP pIrp )
+/*!
+\brief
+    Io control code dispatch routine
+           
+\param	pDO - pointer to a device object.
+\param	pIrp  - pointer to current Irp
+  
+\retval	NT status code.
+*/
+{
+    NTSTATUS status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pIrp);
+	
+    switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
+    {
+	case IOCTL_READ_PORT_BYTE:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) {	
+		    status = ReadPortByte(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_READ_PORT_WORD:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) {	
+		    status = ReadPortWord(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_READ_PORT_LONG:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) {	
+		    status = ReadPortLong(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_WRITE_PORT_BYTE:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) {	
+		    status = WritePortByte(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_WRITE_PORT_WORD:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) {	
+		    status = WritePortWord(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_WRITE_PORT_LONG:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) {	
+		    status = WritePortLong(pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+
+	case IOCTL_MAP_MMIO:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(MMIO_MAP)) {	
+		    status = MapMmio(pDO, pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+	    
+	case IOCTL_UNMAP_MMIO:
+	    {
+		if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(MMIO_MAP)) {	
+		    status = UnmapMmio(pDO, pIrp);
+				
+		} else {
+		    status = STATUS_BUFFER_TOO_SMALL;
+		}
+	    }break;
+	    
+	default:	    
+	    {
+		status = STATUS_INVALID_DEVICE_REQUEST;
+	    }break;
+    }
+    
+    //
+    // complete the I/O request and return appropriate values
+    //
+    pIrp->IoStatus.Status = status;
+    
+    // Set number of bytes to copy back to user-mode
+    if(status == STATUS_SUCCESS)
+    {
+	pIrp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
+    }
+    else
+    {
+	pIrp->IoStatus.Information = 0;
+    }
+    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
+
+    return status;
+}
+
+
+NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDO, IN PIRP pIrp )
+/*!
+\brief
+    Read dispatch routine
+
+    This function does nothing. It's merely a place holder	 
+    to satisfy the need of the user mode code to open the driver 
+    with a GENERIC_READ parameter.
+ 
+\param	pDO - pointer to a device object.
+\param	pIrp  - pointer to current Irp
+  
+\retval	NT status code.
+*/
+{
+    // Just complete the I/O request right away
+    pIrp->IoStatus.Status = STATUS_SUCCESS;
+    pIrp->IoStatus.Information = 0;
+    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DispatchWrite( IN PDEVICE_OBJECT pDO, IN PIRP pIrp )
+/*!
+\brief
+    Write dispatch routine
+
+    This function does nothing. It's merely a place holder	 
+    to satisfy the need of the user mode code to open the driver 
+    with a GENERIC_WRITE parameter.
+    
+\param	pDO - pointer to a device object.
+\param	pIrp  - pointer to current Irp
+  
+\retval	NT status code.
+*/
+{
+    // Just complete the I/O request right away
+    pIrp->IoStatus.Status = STATUS_SUCCESS;
+    pIrp->IoStatus.Information = 0;
+    IoCompleteRequest( pIrp, IO_NO_INCREMENT );
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
+/*!
+\brief
+   Process the close IRPs sent to this device.
+
+   This function clean-up the mapped MMIO ranges that 
+   haven't been cleaned-up by a "buggy" usermode application.
+
+\param	DeviceObject - pointer to a device object.
+\param	Irp - pointer to an I/O Request Packet.
+
+\retval NT Status code
+*/
+{
+    PDEVICE_EXTENSION pDevExt;
+    ULONG	i;
+    NTSTATUS	status = STATUS_SUCCESS;
+    
+    WINFLASHROM_KDPRINT(("DispatchClose Enter\n"));
+
+    pDevExt = DeviceObject->DeviceExtension ;
+    
+    //
+    // Clean-up the mapped MMIO space in case the usermode
+    // application forget to call UnmapMmio for some MMIO zone.
+    // This is to guard against some buggy usermode application.
+    //
+    for(i = 0; i < MAX_MAPPED_MMIO; i++)
+    {
+	if(pDevExt->mapZone[i].sysAddrBase != NULL)
+	{
+	    CleanupMmioMapping(pDevExt, i);
+	}
+    }
+    
+    //
+    // The IRP_MJ_CLOSE dispatch routine is called when a file object
+    // opened on the driver is being removed from the system; that is,
+    // all file object handles have been closed and the reference count
+    // of the file object is down to 0. 
+    //
+    WINFLASHROM_KDPRINT(("IRP_MJ_CLOSE\n"));
+    Irp->IoStatus.Information = 0;
+
+    //
+    // Save Status for return and complete Irp
+    //
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    WINFLASHROM_KDPRINT((" DispatchClose Exit = %x\n", status));
+
+    return status;
+}
+
+
+VOID DispatchUnload( IN PDRIVER_OBJECT DriverObject )
+/*!
+\brief
+    Free all the allocated resources, etc.
+
+\param	DriverObject - pointer to a driver object.
+
+\retval	VOID
+*/
+{
+    PDEVICE_OBJECT  deviceObject = DriverObject->DeviceObject;
+    UNICODE_STRING  uniWin32NameString;
+
+    WINFLASHROM_KDPRINT(("DispatchUnload Enter\n"));
+
+    //
+    // Create counted string version of our Win32 device name.
+    //
+
+    RtlInitUnicodeString( &uniWin32NameString, WINFLASHROM_DOS_DEVICE_NAME_U );
+
+    IoDeleteSymbolicLink( &uniWin32NameString );
+
+    ASSERT(!deviceObject->AttachedDevice);
+    
+    IoDeleteDevice( deviceObject );
+ 
+    WINFLASHROM_KDPRINT(("DispatchUnload Exit\n"));
+    return;
+}
+
+
Index: physmap.c
===================================================================
--- physmap.c	(revision 670)
+++ physmap.c	(working copy)
@@ -24,6 +24,27 @@
 #include <errno.h>
 #include "flash.h"
 
+
+#ifdef __MINGW32_VERSION
+#define MEM_DEV "DirectIO"
+#include "direct_io.h"
+int getpagesize(void)
+{
+	return 4096;
+}
+
+void *sys_physmap(unsigned long phys_addr, size_t len)
+{
+	return map_physical_addr_range(phys_addr, len);
+}
+
+void physunmap(void *virt_addr, size_t len)
+{
+	unmap_physical_addr_range(virt_addr, len);
+}
+
+
+#else
 #ifdef __DARWIN__
 #include <DirectIO/darwinio.h>
 
@@ -77,6 +98,7 @@
 	munmap(virt_addr, len);
 }
 #endif
+#endif
 
 void *physmap(const char *descr, unsigned long phys_addr, size_t len)
 {
Index: libpci/i386-ports.c
===================================================================
--- libpci/i386-ports.c	(revision 0)
+++ libpci/i386-ports.c	(revision 0)
@@ -0,0 +1,222 @@
+/*
+ *	$Id: i386-ports.c,v 1.3 2002/03/30 15:39:25 mj Exp $
+ *
+ *	The PCI Library -- Direct Configuration access via i386 Ports
+ *
+ *	Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+
+#include "../direct_io.h"
+#include "internal.h"
+
+/*
+ * Before we decide to use direct hardware access mechanisms, we try to do some
+ * trivial checks to ensure it at least _seems_ to be working -- we just test
+ * whether bus 00 contains a host bridge (this is similar to checking
+ * techniques used in XFree86, but ours should be more reliable since we
+ * attempt to make use of direct access hints provided by the PCI BIOS).
+ *
+ * This should be close to trivial, but it isn't, because there are buggy
+ * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
+ */
+
+static int
+intel_sanity_check(struct pci_access *a, struct pci_methods *m)
+{
+  struct pci_dev d;
+
+  a->debug("...sanity check \n");
+  d.bus = 0;
+  d.func = 0;
+  for(d.dev = 0; d.dev < 32; d.dev++)
+    {
+      u16 class, vendor;
+      if ( (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
+	  (class == (PCI_CLASS_BRIDGE_HOST) || class == (PCI_CLASS_DISPLAY_VGA))) ||
+	  (m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
+	  (vendor == (PCI_VENDOR_ID_INTEL) || vendor == (PCI_VENDOR_ID_COMPAQ))) )
+	{
+	  a->debug("...outside the Asylum at 0/%02x/0 \n", d.dev);
+	  return 1;
+	}
+    }
+  a->debug("...insane\n");
+  return 0;
+}
+
+/*
+ *	Configuration type 1
+ */
+
+#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
+
+static int
+conf1_detect(struct pci_access *a)
+{
+  unsigned int tmp;
+  int res = 0;
+
+  outb (0x01, 0xCFB);
+  tmp = inl (0xCF8);
+  outl (0x80000000, 0xCF8);
+  if (inl (0xCF8) == 0x80000000)
+    res = 1;
+  outl (tmp, 0xCF8);
+  if (res)
+    res = intel_sanity_check(a, &pm_intel_conf1);
+  return res;
+}
+
+static int
+conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  u16 addr = 0xcfc + (pos&3);
+  outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+  switch (len)
+    {
+    case 1:
+      buf[0] = inb(addr);
+      break;
+    case 2:
+      ((u16 *) buf)[0] = (inw(addr));
+      break;
+    case 4:
+      ((u32 *) buf)[0] = (inl(addr));
+      break;
+    default:
+      return pci_generic_block_read(d, pos, buf, len);
+    }
+  return 1;
+}
+
+static int
+conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  u16 addr = 0xcfc + (pos&3);
+  outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+
+  switch (len)
+    {
+    case 1:
+      outb(buf[0], addr);
+      break;
+    case 2:
+      outw((((u16 *) buf)[0]), addr);
+      break;
+    case 4:
+      outl((((u32 *) buf)[0]), addr);
+      break;
+    default:
+      return pci_generic_block_write(d, pos, buf, len);
+    }
+  return 1;
+}
+
+/*
+ *	Configuration type 2. Obsolete and brain-damaged, but existing.
+ */
+
+static int
+conf2_detect(struct pci_access *a)
+{
+  /* This is ugly and tends to produce false positives. Beware. */
+
+  outb(0x00, 0xCFB);
+  outb(0x00, 0xCF8);
+  outb(0x00, 0xCFA);
+  if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
+    return intel_sanity_check(a, &pm_intel_conf2);
+  else
+    return 0;
+}
+
+static int
+conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  u16 addr = 0xc000 | (d->dev << 8) | pos;
+
+  if (d->dev >= 16)
+    /* conf2 supports only 16 devices per bus */
+    return 0;
+  outb((d->func << 1) | 0xf0, 0xcf8);
+  outb((u8)d->bus, 0xcfa);
+  switch (len)
+    {
+    case 1:
+      buf[0] = inb(addr);
+      break;
+    case 2:
+      ((u16 *) buf)[0] = (inw(addr));
+      break;
+    case 4:
+      ((u32 *) buf)[0] = (inl(addr));
+      break;
+    default:
+      outb(0, 0xcf8);
+      return pci_generic_block_read(d, pos, buf, len);
+    }
+  outb(0, 0xcf8);
+  return 1;
+}
+
+static int
+conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  u16 addr = 0xc000 | (d->dev << 8) | pos;
+
+  if (d->dev >= 16)
+    d->access->error("conf2_write: only first 16 devices exist.");
+  outb((d->func << 1) | 0xf0, 0xcf8);
+  outb((u8)d->bus, 0xcfa);
+  switch (len)
+    {
+    case 1:
+      outb(buf[0], addr);
+      break;
+    case 2:
+      outw((* (u16 *) buf), addr);
+      break;
+    case 4:
+      outl((* (u32 *) buf), addr);
+      break;
+    default:
+      outb(0, 0xcf8);
+      return pci_generic_block_write(d, pos, buf, len);
+    }
+  outb(0, 0xcf8);
+  return 1;
+}
+
+
+struct pci_methods pm_intel_conf1 = {
+  "Intel-conf1",
+  NULL,					/* config */
+  conf1_detect,
+  NULL,
+  NULL,
+  pci_generic_scan,
+  pci_generic_fill_info,
+  conf1_read,
+  conf1_write,
+  NULL,					/* init_dev */
+  NULL					/* cleanup_dev */
+};
+
+struct pci_methods pm_intel_conf2 = {
+  "Intel-conf2",
+  NULL,					/* config */
+  conf2_detect,
+  NULL,
+  NULL,
+  pci_generic_scan,
+  pci_generic_fill_info,
+  conf2_read,
+  conf2_write,
+  NULL,					/* init_dev */
+  NULL					/* cleanup_dev */
+};
Index: libpci/pci.h
===================================================================
--- libpci/pci.h	(revision 0)
+++ libpci/pci.h	(revision 0)
@@ -0,0 +1,135 @@
+/*
+ *	$Id: pci.h,v 1.12 2003/01/04 11:04:39 mj Exp $
+ *
+ *	The PCI Library
+ *
+ *	Copyright (c) 1997--2002 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _PCI_LIB_H
+#define _PCI_LIB_H
+
+#include "header.h"
+
+/*
+ *	Types
+ */
+
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef unsigned short word;
+typedef unsigned short u16;
+typedef unsigned long u32;
+
+typedef unsigned long pciaddr_t;
+
+/*
+ *	PCI Access Structure
+ */
+
+struct pci_methods;
+
+enum pci_access_type {
+  /* Known access methods, remember to update access.c as well */
+  PCI_ACCESS_WINDOWS_HAL,		/* Windows Hardware Abstraction Layer */
+  PCI_ACCESS_I386_TYPE1,		/* i386 ports, type 1 (params: none) */
+  PCI_ACCESS_I386_TYPE2,		/* i386 ports, type 2 (params: none) */
+  PCI_ACCESS_MAX
+};
+
+struct pci_access {
+  /* Options you can change: */
+  unsigned int method;			/* Access method */
+  char *method_params[PCI_ACCESS_MAX];	/* Parameters for the methods */
+  int buscentric;			/* Bus-centric view of the world */
+
+  /* Functions you can override: */
+  void (*error)(char *msg, ...);	/* Write error message and quit */
+  void (*warning)(char *msg, ...);	/* Write a warning message */
+  void (*debug)(char *msg, ...);	/* Write a debugging message */
+
+  struct pci_dev *devices;		/* Devices found on this bus */
+
+  /* Fields used internally: */
+  struct pci_methods *methods;
+};
+
+/* Initialize PCI access */
+struct pci_access *pci_alloc(void);
+void pci_init(struct pci_access *);
+void pci_cleanup(struct pci_access *);
+
+/* Scanning of devices */
+void pci_scan_bus(struct pci_access *acc);
+struct pci_dev *pci_get_dev(struct pci_access *acc, word bus, byte dev, byte func); /* Raw access to specified device */
+void pci_free_dev(struct pci_dev *);
+
+/*
+ *	Devices
+ */
+
+struct pci_dev {
+  struct pci_dev *next;			/* Next device in the chain */
+  word bus;				/* Higher byte can select host bridges */
+  byte dev, func;			/* Device and function */
+
+  /* These fields are set by pci_fill_info() */
+  int known_fields;			/* Set of info fields already known */
+  word vendor_id, device_id;		/* Identity of the device */
+  int irq;				/* IRQ number */
+  pciaddr_t base_addr[6];		/* Base addresses */
+  pciaddr_t size[6];			/* Region sizes */
+  pciaddr_t rom_base_addr;		/* Expansion ROM base address */
+  pciaddr_t rom_size;			/* Expansion ROM size */
+
+  /* Fields used internally: */
+  struct pci_access *access;
+  struct pci_methods *methods;
+  int hdrtype;				/* Direct methods: header type */
+  void *aux;				/* Auxillary data */
+};
+
+#define PCI_ADDR_IO_MASK (~(pciaddr_t) 0x3)
+#define PCI_ADDR_MEM_MASK (~(pciaddr_t) 0xf)
+
+byte pci_read_byte(struct pci_dev *, int pos); /* Access to configuration space */
+word pci_read_word(struct pci_dev *, int pos);
+u32  pci_read_long(struct pci_dev *, int pos);
+int pci_read_block(struct pci_dev *, int pos, byte *buf, int len);
+int pci_write_byte(struct pci_dev *, int pos, byte data);
+int pci_write_word(struct pci_dev *, int pos, word data);
+int pci_write_long(struct pci_dev *, int pos, u32 data);
+int pci_write_block(struct pci_dev *, int pos, byte *buf, int len);
+
+int pci_fill_info(struct pci_dev *, int flags); /* Fill in device information */
+
+#define PCI_FILL_IDENT		1
+#define PCI_FILL_IRQ		2
+#define PCI_FILL_BASES		4
+#define PCI_FILL_ROM_BASE	8
+#define PCI_FILL_SIZES		16
+#define PCI_FILL_RESCAN		0x10000
+
+
+/*
+ *	Filters
+ */
+
+struct pci_filter {
+  int bus, slot, func;			/* -1 = ANY */
+  int vendor, device;
+};
+
+void pci_filter_init(struct pci_access *, struct pci_filter *);
+int pci_filter_match(struct pci_filter *, struct pci_dev *);
+
+#define PCI_LOOKUP_VENDOR 1
+#define PCI_LOOKUP_DEVICE 2
+#define PCI_LOOKUP_CLASS 4
+#define PCI_LOOKUP_SUBSYSTEM 8
+#define PCI_LOOKUP_PROGIF 16
+#define PCI_LOOKUP_NUMERIC 0x10000
+
+#endif
Index: libpci/access.c
===================================================================
--- libpci/access.c	(revision 0)
+++ libpci/access.c	(revision 0)
@@ -0,0 +1,282 @@
+/*
+ *	$Id: access.c,v 1.10 2003/01/04 11:04:39 mj Exp $
+ *
+ *	The PCI Library -- User Access
+ *
+ *	Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "internal.h"
+
+static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
+  &pm_intel_conf1,
+  &pm_intel_conf2,
+};
+
+struct pci_access *
+pci_alloc(void)
+{
+  struct pci_access *a = malloc(sizeof(struct pci_access));
+  int i;
+
+  memset(a, 0, sizeof(*a));
+  for(i=0; i<PCI_ACCESS_MAX; i++)
+    if (pci_methods[i] && pci_methods[i]->config)
+      pci_methods[i]->config(a);
+  return a;
+}
+
+void *
+pci_malloc(struct pci_access *a, int size)
+{
+  void *x = malloc(size);
+
+  if (!x)
+    a->error("Out of memory (allocation of %d bytes failed)", size);
+  return x;
+}
+
+void
+pci_mfree(void *x)
+{
+  if (x)
+    free(x);
+}
+
+static void
+pci_generic_error(char *msg, ...)
+{
+  va_list args;
+
+  va_start(args, msg);
+  fputs("pcilib: ", stderr);
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+  exit(1);
+}
+
+static void
+pci_generic_warn(char *msg, ...)
+{
+  va_list args;
+
+  va_start(args, msg);
+  fputs("pcilib: ", stderr);
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+}
+
+static void
+pci_generic_debug(char *msg, ...)
+{
+  va_list args;
+
+  va_start(args, msg);
+  vfprintf(stdout, msg, args);
+  va_end(args);
+}
+
+
+void
+pci_init(struct pci_access *a)
+{
+  if (!a->error)
+    a->error = pci_generic_error;
+  if (!a->warning)
+    a->warning = pci_generic_warn;
+  if (!a->debug)
+    a->debug = pci_generic_debug;
+
+  if (a->method)
+    {
+      if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
+	a->error("This access method is not supported.\n");
+      a->methods = pci_methods[a->method];
+    }
+  else
+    {
+      unsigned int i;
+      for(i=0; i<PCI_ACCESS_MAX; i++)
+	if (pci_methods[i])
+	  {
+	    a->debug("Trying method %d...\n", i);
+	    if (pci_methods[i]->detect(a))
+	      {
+		a->debug("...OK\n");
+		a->methods = pci_methods[i];
+		a->method = i;
+		break;
+	      }
+	    a->debug("...No.\n");
+	  }
+      if (!a->methods)
+	a->error("Cannot find any working access method.");
+    }
+  a->debug("Decided to use %s\n", a->methods->name);
+
+  if( NULL != a->methods->init )
+  {
+    a->methods->init(a); //this is the bug, we don't need iopl3 init in windows
+  }
+}
+
+void
+pci_cleanup(struct pci_access *a)
+{
+  struct pci_dev *d, *e;
+
+  for(d=a->devices; d; d=e)
+  {
+      e = d->next;
+      pci_free_dev(d);
+  }
+  
+  if (a->methods)
+  {
+    if( a->methods->cleanup != NULL )
+    {  a->methods->cleanup(a); } //this is the bug, we don't need iopl3 cleanup in windows
+  }
+  
+  pci_mfree(a);
+}
+
+void
+pci_scan_bus(struct pci_access *a)
+{
+  a->methods->scan(a);
+}
+
+struct pci_dev *
+pci_alloc_dev(struct pci_access *a)
+{
+  struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
+
+  memset(d, 0, sizeof(*d));
+  d->access = a;
+  d->methods = a->methods;
+  if (d->methods->init_dev)
+    d->methods->init_dev(d);
+  return d;
+}
+
+int
+pci_link_dev(struct pci_access *a, struct pci_dev *d)
+{
+  d->next = a->devices;
+  a->devices = d;
+
+  return 1;
+}
+
+struct pci_dev *
+pci_get_dev(struct pci_access *a, word bus, byte dev, byte func)
+{
+  struct pci_dev *d = pci_alloc_dev(a);
+
+  d->bus = bus;
+  d->dev = dev;
+  d->func = func;
+  return d;
+}
+
+void pci_free_dev(struct pci_dev *d)
+{
+  if (d->methods->cleanup_dev)
+    d->methods->cleanup_dev(d);
+  pci_mfree(d);
+}
+
+static void
+pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+  if (pos & (len-1))
+    d->access->error("Unaligned read: pos=%02x, len=%d", pos, len);
+  else if (!d->methods->read(d, pos, buf, len))
+    memset(buf, 0xff, len);
+}
+
+byte
+pci_read_byte(struct pci_dev *d, int pos)
+{
+  byte buf;
+  pci_read_data(d, &buf, pos, 1);
+  return buf;
+}
+
+word
+pci_read_word(struct pci_dev *d, int pos)
+{
+  word buf;
+  pci_read_data(d, &buf, pos, 2);
+  return buf;
+}
+
+u32
+pci_read_long(struct pci_dev *d, int pos)
+{
+  u32 buf;
+  pci_read_data(d, &buf, pos, 4);
+  return buf;
+}
+
+int
+pci_read_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  return d->methods->read(d, pos, buf, len);
+}
+
+static int
+pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
+{
+  if (pos & (len-1))
+    d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
+  return d->methods->write(d, pos, buf, len);
+}
+
+int
+pci_write_byte(struct pci_dev *d, int pos, byte data)
+{
+  return pci_write_data(d, &data, pos, 1);
+}
+
+int
+pci_write_word(struct pci_dev *d, int pos, word data)
+{
+  word buf = data;
+  return pci_write_data(d, &buf, pos, 2);
+}
+
+int
+pci_write_long(struct pci_dev *d, int pos, u32 data)
+{
+  u32 buf = data;
+  return pci_write_data(d, &buf, pos, 4);
+}
+
+int
+pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  return d->methods->write(d, pos, buf, len);
+}
+
+int
+pci_fill_info(struct pci_dev *d, int flags)
+{
+  if (flags & PCI_FILL_RESCAN)
+    {
+      flags &= ~PCI_FILL_RESCAN;
+      d->known_fields = 0;
+    }
+  if (flags & ~d->known_fields)
+    d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
+  return d->known_fields;
+}
+
+
Index: libpci/internal.h
===================================================================
--- libpci/internal.h	(revision 0)
+++ libpci/internal.h	(revision 0)
@@ -0,0 +1,39 @@
+/*
+ *	$Id: internal.h,v 1.7 2002/12/26 19:28:33 mj Exp $
+ *
+ *	The PCI Library -- Internal Include File
+ *
+ *	Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "pci.h"
+
+struct pci_methods {
+  char *name;
+  void (*config)(struct pci_access *);
+  int (*detect)(struct pci_access *);
+  void (*init)(struct pci_access *);
+  void (*cleanup)(struct pci_access *);
+  void (*scan)(struct pci_access *);
+  int (*fill_info)(struct pci_dev *, int flags);
+  int (*read)(struct pci_dev *, int pos, byte *buf, int len);
+  int (*write)(struct pci_dev *, int pos, byte *buf, int len);
+  void (*init_dev)(struct pci_dev *);
+  void (*cleanup_dev)(struct pci_dev *);
+};
+
+void pci_generic_scan_bus(struct pci_access *, byte *busmap, word bus);
+void pci_generic_scan(struct pci_access *);
+int pci_generic_fill_info(struct pci_dev *, int flags);
+int pci_generic_block_read(struct pci_dev *, int pos, byte *buf, int len);
+int pci_generic_block_write(struct pci_dev *, int pos, byte *buf, int len);
+
+void *pci_malloc(struct pci_access *, int);
+void pci_mfree(void *);
+
+struct pci_dev *pci_alloc_dev(struct pci_access *);
+int pci_link_dev(struct pci_access *, struct pci_dev *);
+
+extern struct pci_methods pm_intel_conf1, pm_intel_conf2;
Index: libpci/filter.c
===================================================================
--- libpci/filter.c	(revision 0)
+++ libpci/filter.c	(revision 0)
@@ -0,0 +1,97 @@
+/*
+ *	$Id: filter.c,v 1.3 2002/03/30 15:39:25 mj Exp $
+ *
+ *	Linux PCI Library -- Device Filtering
+ *
+ *	Copyright (c) 1998--2002 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+
+void
+pci_filter_init(struct pci_access * a, struct pci_filter *f)
+{
+  f->bus = f->slot = f->func = -1;
+  f->vendor = f->device = -1;
+}
+
+
+/* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */
+
+char *
+pci_filter_parse_slot(struct pci_filter *f, char *str)
+{
+  char *colon = strrchr(str, ':');
+  char *dot = strchr((colon ? colon + 1 : str), '.');
+  char *mid = str;
+  char *e, *bus, *colon2;
+
+  if (colon)
+    {
+      *colon++ = 0;
+      mid = colon;
+      colon2 = strchr(str, ':');
+      if (colon2)
+	{
+	  *colon2++ = 0;
+	  bus = colon2;
+	  if (str[0] && strcmp(str, "*"))
+	    {
+	      long int x = strtol(str, &e, 16);
+	      if ((e && *e) || (x < 0 || x > 0xffff))
+		return "Invalid domain number";
+	      // f->domain = x;
+	    }
+	}
+      else
+	bus = str;
+      if (bus[0] && strcmp(bus, "*"))
+	{
+	  long int x = strtol(bus, &e, 16);
+	  if ((e && *e) || (x < 0 || x > 0xff))
+	    return "Invalid bus number";
+	  f->bus = x;
+	}
+    }
+  if (dot)
+    *dot++ = 0;
+  if (mid[0] && strcmp(mid, "*"))
+    {
+      long int x = strtol(mid, &e, 16);
+      if ((e && *e) || (x < 0 || x > 0x1f))
+	return "Invalid slot number";
+      f->slot = x;
+    }
+  if (dot && dot[0] && strcmp(dot, "*"))
+    {
+      long int x = strtol(dot, &e, 16);
+      if ((e && *e) || (x < 0 || x > 7))
+	return "Invalid function number";
+      f->func = x;
+    }
+  return NULL;
+}
+
+
+
+int
+pci_filter_match(struct pci_filter *f, struct pci_dev *d)
+{
+  if ((f->bus >= 0 && f->bus != d->bus) ||
+      (f->slot >= 0 && f->slot != d->dev) ||
+      (f->func >= 0 && f->func != d->func))
+    return 0;
+  if (f->device >= 0 || f->vendor >= 0)
+    {
+      pci_fill_info(d, PCI_FILL_IDENT);
+      if ((f->device >= 0 && f->device != d->device_id) ||
+	  (f->vendor >= 0 && f->vendor != d->vendor_id))
+	return 0;
+    }
+  return 1;
+}
Index: libpci/generic.c
===================================================================
--- libpci/generic.c	(revision 0)
+++ libpci/generic.c	(revision 0)
@@ -0,0 +1,214 @@
+/*
+ *	$Id: generic.c,v 1.8 2002/12/27 19:01:51 mj Exp $
+ *
+ *	The PCI Library -- Generic Direct Access Functions
+ *
+ *	Copyright (c) 1997--2000 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <string.h>
+
+#include "internal.h"
+
+void
+pci_generic_scan_bus(struct pci_access *a, byte *busmap, word bus)
+{
+  int multi, ht;
+  u32 vd;
+  u8 dev;
+  struct pci_dev *d;
+
+  struct pci_dev *t = pci_alloc_dev(a);
+
+  a->debug("Scanning bus %02x for devices...\n", bus);
+  if (busmap[bus])
+    {
+      a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
+      return;
+    }
+  busmap[bus] = 1;
+  t->bus = bus;
+  for(dev=0; dev<32; dev++)
+    {
+      t->dev = dev;
+      multi = 0;
+      for(t->func=0; !t->func || (multi && t->func<8); t->func++)
+	{
+	  vd = pci_read_long(t, PCI_VENDOR_ID);
+
+	  if (!vd || vd == 0xffffffff)
+	    continue;
+	  ht = pci_read_byte(t, PCI_HEADER_TYPE);
+	  if (!t->func)
+	    multi = ht & 0x80;
+	  ht &= 0x7f;
+	  d = pci_alloc_dev(a);
+	  d->bus = t->bus;
+	  d->dev = t->dev;
+	  d->func = t->func;
+	  d->vendor_id = (word)(vd & 0xffff);
+	  d->device_id = (word)(vd >> 16U);
+	  d->known_fields = PCI_FILL_IDENT;
+	  d->hdrtype = ht;
+	  pci_link_dev(a, d);
+	  switch (ht)
+	    {
+	    case PCI_HEADER_TYPE_NORMAL:
+	      break;
+	    case PCI_HEADER_TYPE_BRIDGE:
+	    case PCI_HEADER_TYPE_CARDBUS:
+	      pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS));
+	      break;
+	    default:
+	      a->debug("Device %02x:%02x.%d has unknown header type %02x.\n", d->bus, d->dev, d->func, ht);
+	    }
+	}
+    }
+}
+
+void
+pci_generic_scan(struct pci_access *a)
+{
+  byte busmap[256];
+
+  memset(busmap, 0, sizeof(busmap));
+  pci_generic_scan_bus(a, busmap, 0);
+}
+
+int
+pci_generic_fill_info(struct pci_dev *d, int flags)
+{
+  struct pci_access *a = d->access;
+
+  if (flags & PCI_FILL_IDENT)
+    {
+      d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
+      d->device_id = pci_read_word(d, PCI_DEVICE_ID);
+    }
+  if (flags & PCI_FILL_IRQ)
+    d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
+  if (flags & PCI_FILL_BASES)
+    {
+      int cnt = 0, i;
+      memset(d->base_addr, 0,  sizeof(d->base_addr));
+      switch (d->hdrtype)
+	{
+	case PCI_HEADER_TYPE_NORMAL:
+	  cnt = 6;
+	  break;
+	case PCI_HEADER_TYPE_BRIDGE:
+	  cnt = 2;
+	  break;
+	case PCI_HEADER_TYPE_CARDBUS:
+	  cnt = 1;
+	  break;
+	}
+      if (cnt)
+	{
+	  u16 cmd = pci_read_word(d, PCI_COMMAND);
+	  for(i=0; i<cnt; i++)
+	    {
+	      u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
+	      if (!x || x == (u32) ~0)
+		continue;
+	      d->base_addr[i] = x;
+	      if (x & PCI_BASE_ADDRESS_SPACE_IO)
+		{
+		  if (!a->buscentric && !(cmd & PCI_COMMAND_IO))
+		    d->base_addr[i] = 0;
+		}
+	      else if (a->buscentric || (cmd & PCI_COMMAND_MEMORY))
+		{
+		  if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+		    {
+		      if (i >= cnt-1)
+			a->warning("%02x:%02x.%d: Invalid 64-bit address seen.", d->bus, d->dev, d->func);
+		      else
+			{
+			  u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
+#ifdef HAVE_64BIT_ADDRESS
+			  d->base_addr[i-1] |= ((pciaddr_t) y) << 32;
+#else
+			  if (y)
+			    {
+			      a->warning("%02x:%02x.%d 64-bit device address ignored.", d->bus, d->dev, d->func);
+			      d->base_addr[i-1] = 0;
+			    }
+#endif
+			}
+		    }
+		}
+	      else
+		d->base_addr[i] = 0;
+	    }
+	}
+    }
+  if (flags & PCI_FILL_ROM_BASE)
+    {
+      int reg = 0;
+      d->rom_base_addr = 0;
+      switch (d->hdrtype)
+	{
+	case PCI_HEADER_TYPE_NORMAL:
+	  reg = PCI_ROM_ADDRESS;
+	  break;
+	case PCI_HEADER_TYPE_BRIDGE:
+	  reg = PCI_ROM_ADDRESS1;
+	  break;
+	}
+      if (reg)
+	{
+	  u32 a = pci_read_long(d, reg);
+	  if (a & PCI_ROM_ADDRESS_ENABLE)
+	    d->rom_base_addr = a;
+	}
+    }
+  return flags & ~PCI_FILL_SIZES;
+}
+
+static int
+pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
+		 int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
+{
+  if ((pos & 1) && len >= 1)
+    {
+      if (!r(d, pos, buf, 1))
+	return 0;
+      pos++; buf++; len--;
+    }
+  if ((pos & 3) && len >= 2)
+    {
+      if (!r(d, pos, buf, 2))
+	return 0;
+      pos += 2; buf += 2; len -= 2;
+    }
+  while (len >= 4)
+    {
+      if (!r(d, pos, buf, 4))
+	return 0;
+      pos += 4; buf += 4; len -= 4;
+    }
+  if (len >= 2)
+    {
+      if (!r(d, pos, buf, 2))
+	return 0;
+      pos += 2; buf += 2; len -= 2;
+    }
+  if (len && !r(d, pos, buf, 1))
+    return 0;
+  return 1;
+}
+
+int
+pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
+}
+
+int
+pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+  return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
+}
Index: libpci/Makefile
===================================================================
--- libpci/Makefile	(revision 0)
+++ libpci/Makefile	(revision 0)
@@ -0,0 +1,27 @@
+#
+# Makefile for temporary PCI library 
+# 
+# by Darmawan Salihun <darmawan.salihun@gmail.com>
+#
+
+
+LIBRARY = libpci.a
+
+AR 	= ar
+CC      = gcc
+STRIP	= strip
+CFLAGS  = -O2 -g -Wall -Werror
+STRIP_ARGS = -s
+
+OBJS = access.o filter.o generic.o i386-ports.o 
+
+all: $(LIBRARY)
+
+$(LIBRARY): $(OBJS)
+	$(AR) -r $(LIBRARY) $(OBJS)
+
+clean:
+	rm -f *.o *~ *.a
+
+.PHONY: all clean
+
Index: libpci/header.h
===================================================================
--- libpci/header.h	(revision 0)
+++ libpci/header.h	(revision 0)
@@ -0,0 +1,421 @@
+/*
+ *	$Id: header.h,v 1.9 2002/12/26 20:24:50 mj Exp $
+ *
+ *	The PCI Library -- PCI Header Structure (extracted from <linux/pci.h>)
+ *
+ *	Copyright (c) 1997--2002 Martin Mares <mj@ucw.cz>
+ *
+ *	Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID		0x00	/* 16 bits */
+#define PCI_DEVICE_ID		0x02	/* 16 bits */
+#define PCI_COMMAND		0x04	/* 16 bits */
+#define  PCI_COMMAND_IO		0x1	/* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY	0x2	/* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER	0x4	/* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL	0x8	/* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE	0x10	/* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20	/* Enable palette snooping */
+#define  PCI_COMMAND_PARITY	0x40	/* Enable parity checking */
+#define  PCI_COMMAND_WAIT 	0x80	/* Enable address/data stepping */
+#define  PCI_COMMAND_SERR	0x100	/* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK	0x200	/* Enable back-to-back writes */
+
+#define PCI_STATUS		0x06	/* 16 bits */
+#define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */
+#define  PCI_STATUS_66MHZ	0x20	/* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK	0x80	/* Accept fast-back to back */
+#define  PCI_STATUS_PARITY	0x100	/* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK	0x600	/* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST	0x000	
+#define  PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define  PCI_STATUS_DEVSEL_SLOW 0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION	0x08	/* High 24 bits are class, low 8
+					   revision */
+#define PCI_REVISION_ID         0x08    /* Revision ID */
+#define PCI_CLASS_PROG          0x09    /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE        0x0a    /* Device class */
+
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
+#define PCI_HEADER_TYPE		0x0e	/* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL	0
+#define  PCI_HEADER_TYPE_BRIDGE 1
+#define  PCI_HEADER_TYPE_CARDBUS 2
+
+#define PCI_BIST		0x0f	/* 8 bits */
+#define PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of 
+ * 0xffffffff to the register, and reading it back.  Only 
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#define PCI_BASE_ADDRESS_1	0x14	/* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2	0x18	/* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3	0x1c	/* 32 bits */
+#define PCI_BASE_ADDRESS_4	0x20	/* 32 bits */
+#define PCI_BASE_ADDRESS_5	0x24	/* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE	0x01	/* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO 0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH	0x08	/* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK	(~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK	(~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS		0x28
+#define PCI_SUBSYSTEM_VENDOR_ID	0x2c
+#define PCI_SUBSYSTEM_ID	0x2e  
+#define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE	0x01
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST	0x34	/* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE	0x3c	/* 8 bits */
+#define PCI_INTERRUPT_PIN	0x3d	/* 8 bits */
+#define PCI_MIN_GNT		0x3e	/* 8 bits */
+#define PCI_MAX_LAT		0x3f	/* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS		0x18	/* Primary bus number */
+#define PCI_SECONDARY_BUS	0x19	/* Secondary bus number */
+#define PCI_SUBORDINATE_BUS	0x1a	/* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER	0x1b	/* Latency timer for secondary interface */
+#define PCI_IO_BASE		0x1c	/* I/O range behind the bridge */
+#define PCI_IO_LIMIT		0x1d
+#define  PCI_IO_RANGE_TYPE_MASK	0x0f	/* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16	0x00
+#define  PCI_IO_RANGE_TYPE_32	0x01
+#define  PCI_IO_RANGE_MASK	~0x0f
+#define PCI_SEC_STATUS		0x1e	/* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE		0x20	/* Memory range behind */
+#define PCI_MEMORY_LIMIT	0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0f
+#define  PCI_MEMORY_RANGE_MASK	~0x0f
+#define PCI_PREF_MEMORY_BASE	0x24	/* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT	0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0f
+#define  PCI_PREF_RANGE_TYPE_32	0x00
+#define  PCI_PREF_RANGE_TYPE_64	0x01
+#define  PCI_PREF_RANGE_MASK	~0x0f
+#define PCI_PREF_BASE_UPPER32	0x28	/* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32	0x2c
+#define PCI_IO_BASE_UPPER16	0x30	/* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16	0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1	0x38	/* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL	0x3e
+#define  PCI_BRIDGE_CTL_PARITY	0x01	/* Enable parity detection on secondary interface */
+#define  PCI_BRIDGE_CTL_SERR	0x02	/* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_NO_ISA	0x04	/* Disable bridging of ISA ports */
+#define  PCI_BRIDGE_CTL_VGA	0x08	/* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT 0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET 0x40	/* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK 0x80	/* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+/* 0x14-0x15 reserved */
+#define PCI_CB_SEC_STATUS	0x16	/* Secondary status */
+#define PCI_CB_PRIMARY_BUS	0x18	/* PCI bus number */
+#define PCI_CB_CARD_BUS		0x19	/* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS	0x1a	/* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER	0x1b	/* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0	0x1c
+#define PCI_CB_MEMORY_LIMIT_0	0x20
+#define PCI_CB_MEMORY_BASE_1	0x24
+#define PCI_CB_MEMORY_LIMIT_1	0x28
+#define PCI_CB_IO_BASE_0	0x2c
+#define PCI_CB_IO_BASE_0_HI	0x2e
+#define PCI_CB_IO_LIMIT_0	0x30
+#define PCI_CB_IO_LIMIT_0_HI	0x32
+#define PCI_CB_IO_BASE_1	0x34
+#define PCI_CB_IO_BASE_1_HI	0x36
+#define PCI_CB_IO_LIMIT_1	0x38
+#define PCI_CB_IO_LIMIT_1_HI	0x3a
+#define  PCI_CB_IO_RANGE_MASK	~0x03
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL	0x3e
+#define  PCI_CB_BRIDGE_CTL_PARITY	0x01	/* Similar to standard bridge control register */
+#define  PCI_CB_BRIDGE_CTL_SERR		0x02
+#define  PCI_CB_BRIDGE_CTL_ISA		0x04
+#define  PCI_CB_BRIDGE_CTL_VGA		0x08
+#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT	0x20
+#define  PCI_CB_BRIDGE_CTL_CB_RESET	0x40	/* CardBus reset */
+#define  PCI_CB_BRIDGE_CTL_16BIT_INT	0x80	/* Enable interrupt for 16-bit cards */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100	/* Prefetch enable for both memory regions */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define  PCI_CB_BRIDGE_CTL_POST_WRITES	0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40
+#define PCI_CB_SUBSYSTEM_ID	0x42
+#define PCI_CB_LEGACY_MODE_BASE	0x44	/* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID		0	/* Capability ID */
+#define  PCI_CAP_ID_PM		0x01	/* Power Management */
+#define  PCI_CAP_ID_AGP		0x02	/* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD		0x03	/* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID	0x04	/* Slot Identification */
+#define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
+#define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX        0x07    /* PCI-X */
+#define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
+#define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF		4
+
+/* Power Management Registers */
+
+#define  PCI_PM_CAP_VER_MASK	0x0007	/* Version (2=PM1.1) */
+#define  PCI_PM_CAP_PME_CLOCK	0x0008	/* Clock required for PME generation */
+#define  PCI_PM_CAP_DSI		0x0020	/* Device specific initialization required */
+#define  PCI_PM_CAP_AUX_C_MASK	0x01c0	/* Maximum aux current required in D3cold */
+#define  PCI_PM_CAP_D1		0x0200	/* D1 power state support */
+#define  PCI_PM_CAP_D2		0x0400	/* D2 power state support */
+#define  PCI_PM_CAP_PME_D0	0x0800	/* PME can be asserted from D0 */
+#define  PCI_PM_CAP_PME_D1	0x1000	/* PME can be asserted from D1 */
+#define  PCI_PM_CAP_PME_D2	0x2000	/* PME can be asserted from D2 */
+#define  PCI_PM_CAP_PME_D3_HOT	0x4000	/* PME can be asserted from D3hot */
+#define  PCI_PM_CAP_PME_D3_COLD	0x8000	/* PME can be asserted from D3cold */
+#define PCI_PM_CTRL		4	/* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK	0x0003	/* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_PME_ENABLE	0x0100	/* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK	0x1e00	/* PM table data index */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK	0x6000	/* PM table data scaling factor */
+#define  PCI_PM_CTRL_PME_STATUS	0x8000	/* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS	6	/* PPB support extensions */
+#define  PCI_PM_PPB_B2_B3	0x40	/* If bridge enters D3hot, bus enters: 0=B3, 1=B2 */
+#define  PCI_PM_BPCC_ENABLE	0x80	/* Secondary bus is power managed */
+#define PCI_PM_DATA_REGISTER	7	/* PM table contents read here */
+#define PCI_PM_SIZEOF		8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION		2	/* BCD version number */
+#define PCI_AGP_RFU		3	/* Rest of capability flags */
+#define PCI_AGP_STATUS		4	/* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK	0xff000000	/* Maximum number of requests - 1 */
+#define  PCI_AGP_STATUS_ISOCH	0x10000	/* Isochronous transactions supported */
+#define  PCI_AGP_STATUS_ARQSZ_MASK	0xe000	/* log2(optimum async req size in bytes) - 4 */
+#define  PCI_AGP_STATUS_CAL_MASK	0x1c00	/* Calibration cycle timing */
+#define  PCI_AGP_STATUS_SBA	0x0200	/* Sideband addressing supported */
+#define  PCI_AGP_STATUS_ITA_COH	0x0100	/* In-aperture accesses always coherent */
+#define  PCI_AGP_STATUS_GART64	0x0080	/* 64-bit GART entries supported */
+#define  PCI_AGP_STATUS_HTRANS	0x0040	/* If 0, core logic can xlate host CPU accesses thru aperture */
+#define  PCI_AGP_STATUS_64BIT	0x0020	/* 64-bit addressing cycles supported */
+#define  PCI_AGP_STATUS_FW	0x0010	/* Fast write transfers supported */
+#define  PCI_AGP_STATUS_AGP3	0x0008	/* AGP3 mode supported */
+#define  PCI_AGP_STATUS_RATE4	0x0004	/* 4x transfer rate supported (RFU in AGP3 mode) */
+#define  PCI_AGP_STATUS_RATE2	0x0002	/* 2x transfer rate supported (8x in AGP3 mode) */
+#define  PCI_AGP_STATUS_RATE1	0x0001	/* 1x transfer rate supported (4x in AGP3 mode) */
+#define PCI_AGP_COMMAND		8	/* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
+#define  PCI_AGP_COMMAND_ARQSZ_MASK	0xe000	/* log2(optimum async req size in bytes) - 4 */
+#define  PCI_AGP_COMMAND_CAL_MASK	0x1c00	/* Calibration cycle timing */
+#define  PCI_AGP_COMMAND_SBA	0x0200	/* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP	0x0100	/* Allow processing of AGP transactions */
+#define  PCI_AGP_COMMAND_GART64	0x0080	/* 64-bit GART entries enabled */
+#define  PCI_AGP_COMMAND_64BIT	0x0020 	/* Allow generation of 64-bit addr cycles */
+#define  PCI_AGP_COMMAND_FW	0x0010 	/* Enable FW transfers */
+#define  PCI_AGP_COMMAND_RATE4	0x0004	/* Use 4x rate (RFU in AGP3 mode) */
+#define  PCI_AGP_COMMAND_RATE2	0x0002	/* Use 2x rate (8x in AGP3 mode) */
+#define  PCI_AGP_COMMAND_RATE1	0x0001	/* Use 1x rate (4x in AGP3 mode) */
+#define PCI_AGP_SIZEOF		12
+
+/* Slot Identification */
+
+#define PCI_SID_ESR		2	/* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS	0x1f	/* Number of expansion slots available */
+#define  PCI_SID_ESR_FIC	0x20	/* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR	3	/* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS		2	/* Various flags */
+#define  PCI_MSI_FLAGS_64BIT	0x80	/* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE	0x70	/* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK	0x0e	/* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE	0x01	/* MSI feature enabled */
+#define PCI_MSI_RFU		3	/* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO	4	/* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI	8	/* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32		8	/* 16 bits of data for 32-bit devices */
+#define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
+
+/* PCI-X */
+#define PCI_PCIX_COMMAND                                                2 /* Command register offset */
+#define PCI_PCIX_COMMAND_DPERE                                     0x0001 /* Data Parity Error Recover Enable */
+#define PCI_PCIX_COMMAND_ERO                                       0x0002 /* Enable Relaxed Ordering */
+#define PCI_PCIX_COMMAND_MAX_MEM_READ_BYTE_COUNT                   0x000c /* Maximum Memory Read Byte Count */
+#define PCI_PCIX_COMMAND_MAX_OUTSTANDING_SPLIT_TRANS               0x0070  
+#define PCI_PCIX_COMMAND_RESERVED                                   0xf80
+#define PCI_PCIX_STATUS                                                 4 /* Status register offset */
+#define PCI_PCIX_STATUS_FUNCTION                               0x00000007
+#define PCI_PCIX_STATUS_DEVICE                                 0x000000f8
+#define PCI_PCIX_STATUS_BUS                                    0x0000ff00
+#define PCI_PCIX_STATUS_64BIT                                  0x00010000
+#define PCI_PCIX_STATUS_133MHZ                                 0x00020000
+#define PCI_PCIX_STATUS_SC_DISCARDED                           0x00040000 /* Split Completion Discarded */
+#define PCI_PCIX_STATUS_UNEXPECTED_SC                          0x00080000 /* Unexpected Split Completion */
+#define PCI_PCIX_STATUS_DEVICE_COMPLEXITY                      0x00100000 /* 0 = simple device, 1 = bridge device */
+#define PCI_PCIX_STATUS_DESIGNED_MAX_MEM_READ_BYTE_COUNT       0x00600000 /* 0 = 512 bytes, 1 = 1024, 2 = 2048, 3 = 4096 */
+#define PCI_PCIX_STATUS_DESIGNED_MAX_OUTSTANDING_SPLIT_TRANS   0x03800000
+#define PCI_PCIX_STATUS_DESIGNED_MAX_CUMULATIVE_READ_SIZE      0x1c000000
+#define PCI_PCIX_STATUS_RCVD_SC_ERR_MESS                       0x20000000 /* Received Split Completion Error Message */
+#define PCI_PCIX_STATUS_RESERVED                               0xc0000000
+#define PCI_PCIX_SIZEOF		4
+
+/* PCI-X Bridges */
+#define PCI_PCIX_BRIDGE_SEC_STATUS                                      2 /* Secondary bus status register offset */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_64BIT                           0x0001
+#define PCI_PCIX_BRIDGE_SEC_STATUS_133MHZ                          0x0002
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SC_DISCARDED                    0x0004 /* Split Completion Discarded on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_UNEXPECTED_SC                   0x0008 /* Unexpected Split Completion on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SC_OVERRUN                      0x0010 /* Split Completion Overrun on secondary bus */
+#define PCI_PCIX_BRIDGE_SEC_STATUS_SPLIT_REQUEST_DELAYED           0x0020
+#define PCI_PCIX_BRIDGE_SEC_STATUS_CLOCK_FREQ                      0x01c0
+#define PCI_PCIX_BRIDGE_SEC_STATUS_RESERVED                        0xfe00
+#define PCI_PCIX_BRIDGE_STATUS                                          4 /* Primary bus status register offset */
+#define PCI_PCIX_BRIDGE_STATUS_FUNCTION                        0x00000007
+#define PCI_PCIX_BRIDGE_STATUS_DEVICE                          0x000000f8
+#define PCI_PCIX_BRIDGE_STATUS_BUS                             0x0000ff00
+#define PCI_PCIX_BRIDGE_STATUS_64BIT                           0x00010000
+#define PCI_PCIX_BRIDGE_STATUS_133MHZ                          0x00020000
+#define PCI_PCIX_BRIDGE_STATUS_SC_DISCARDED                    0x00040000 /* Split Completion Discarded */
+#define PCI_PCIX_BRIDGE_STATUS_UNEXPECTED_SC                   0x00080000 /* Unexpected Split Completion */
+#define PCI_PCIX_BRIDGE_STATUS_SC_OVERRUN                      0x00100000 /* Split Completion Overrun */
+#define PCI_PCIX_BRIDGE_STATUS_SPLIT_REQUEST_DELAYED           0x00200000
+#define PCI_PCIX_BRIDGE_STATUS_RESERVED                        0xffc00000
+#define PCI_PCIX_BRIDGE_UPSTREAM_SPLIT_TRANS_CTRL                       8 /* Upstream Split Transaction Register offset */
+#define PCI_PCIX_BRIDGE_DOWNSTREAM_SPLIT_TRANS_CTRL                    12 /* Downstream Split Transaction Register offset */
+#define PCI_PCIX_BRIDGE_STR_CAPACITY                           0x0000ffff
+#define PCI_PCIX_BRIDGE_STR_COMMITMENT_LIMIT                   0xffff0000
+#define PCI_PCIX_BRIDGE_SIZEOF 12
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices.  The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ *	7:3 = slot
+ *	2:0 = function
+ */
+#define PCI_DEVFN(slot,func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn)		(((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)		((devfn) & 0x07)
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED		0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
+
+#define PCI_BASE_CLASS_STORAGE		0x01
+#define PCI_CLASS_STORAGE_SCSI		0x0100
+#define PCI_CLASS_STORAGE_IDE		0x0101
+#define PCI_CLASS_STORAGE_FLOPPY	0x0102
+#define PCI_CLASS_STORAGE_IPI		0x0103
+#define PCI_CLASS_STORAGE_RAID		0x0104
+#define PCI_CLASS_STORAGE_OTHER		0x0180
+
+#define PCI_BASE_CLASS_NETWORK		0x02
+#define PCI_CLASS_NETWORK_ETHERNET	0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
+#define PCI_CLASS_NETWORK_FDDI		0x0202
+#define PCI_CLASS_NETWORK_ATM		0x0203
+#define PCI_CLASS_NETWORK_OTHER		0x0280
+
+#define PCI_BASE_CLASS_DISPLAY		0x03
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_CLASS_DISPLAY_XGA		0x0301
+#define PCI_CLASS_DISPLAY_OTHER		0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA	0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
+#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
+
+#define PCI_BASE_CLASS_MEMORY		0x05
+#define  PCI_CLASS_MEMORY_RAM		0x0500
+#define  PCI_CLASS_MEMORY_FLASH		0x0501
+#define  PCI_CLASS_MEMORY_OTHER		0x0580
+
+#define PCI_BASE_CLASS_BRIDGE		0x06
+#define  PCI_CLASS_BRIDGE_HOST		0x0600
+#define  PCI_CLASS_BRIDGE_ISA		0x0601
+#define  PCI_CLASS_BRIDGE_EISA		0x0602
+#define  PCI_CLASS_BRIDGE_MC		0x0603
+#define  PCI_CLASS_BRIDGE_PCI		0x0604
+#define  PCI_CLASS_BRIDGE_PCMCIA	0x0605
+#define  PCI_CLASS_BRIDGE_NUBUS		0x0606
+#define  PCI_CLASS_BRIDGE_CARDBUS	0x0607
+#define  PCI_CLASS_BRIDGE_OTHER		0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION	0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
+
+#define PCI_BASE_CLASS_SYSTEM		0x08
+#define PCI_CLASS_SYSTEM_PIC		0x0800
+#define PCI_CLASS_SYSTEM_DMA		0x0801
+#define PCI_CLASS_SYSTEM_TIMER		0x0802
+#define PCI_CLASS_SYSTEM_RTC		0x0803
+#define PCI_CLASS_SYSTEM_OTHER		0x0880
+
+#define PCI_BASE_CLASS_INPUT		0x09
+#define PCI_CLASS_INPUT_KEYBOARD	0x0900
+#define PCI_CLASS_INPUT_PEN		0x0901
+#define PCI_CLASS_INPUT_MOUSE		0x0902
+#define PCI_CLASS_INPUT_OTHER		0x0980
+
+#define PCI_BASE_CLASS_DOCKING		0x0a
+#define PCI_CLASS_DOCKING_GENERIC	0x0a00
+#define PCI_CLASS_DOCKING_OTHER		0x0a01
+
+#define PCI_BASE_CLASS_PROCESSOR	0x0b
+#define PCI_CLASS_PROCESSOR_386		0x0b00
+#define PCI_CLASS_PROCESSOR_486		0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
+#define PCI_CLASS_PROCESSOR_CO		0x0b40
+
+#define PCI_BASE_CLASS_SERIAL		0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_ACCESS		0x0c01
+#define PCI_CLASS_SERIAL_SSA		0x0c02
+#define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_FIBER		0x0c04
+
+#define PCI_CLASS_OTHERS		0xff
+
+/* Several ID's we need in the library */
+
+#define PCI_VENDOR_ID_INTEL		0x8086
+#define PCI_VENDOR_ID_COMPAQ		0x0e11
Index: sst49lfxxxc.c
===================================================================
--- sst49lfxxxc.c	(revision 670)
+++ sst49lfxxxc.c	(working copy)
@@ -19,9 +19,6 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/mman.h>
 #include <stdlib.h>
 #include "flash.h"
 
Index: interfaces.h
===================================================================
--- interfaces.h	(revision 0)
+++ interfaces.h	(revision 0)
@@ -0,0 +1,81 @@
+/*
+ *  This is the interface file that connects the user mode application and the kernel mode driver
+ *
+ *  NOTE:
+ *  -----
+ *  - You __have__ to put #include <winioctl.h> prior to including this file in your user mode application
+ *  - You probably need to put #include <devioctl.h> prior to including this file in your kernel mode driver 
+ *  These includes are needed for the CTL_CODE macro to work.
+ */
+
+#ifndef __INTERFACES_H__
+#define __INTERFACES_H__
+
+#define IOCTL_READ_PORT_BYTE	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0801, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+#define IOCTL_READ_PORT_WORD	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0802, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+#define IOCTL_READ_PORT_LONG	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0803, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+
+#define IOCTL_WRITE_PORT_BYTE	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0804, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+#define IOCTL_WRITE_PORT_WORD	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0805, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+#define IOCTL_WRITE_PORT_LONG	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0806, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+
+#define IOCTL_MAP_MMIO		CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0809, METHOD_IN_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+#define IOCTL_UNMAP_MMIO	CTL_CODE(FILE_DEVICE_UNKNOWN, 0x080A, METHOD_OUT_DIRECT, FILE_READ_DATA | FILE_WRITE_DATA)
+
+
+#ifdef __GNUC__ // are we using GCC to compile this code?
+#define PACK_STRUC __attribute__((packed))
+#else
+#define PACK_STRUC 
+#endif 
+
+
+enum {
+    MAX_MAPPED_MMIO = 256 // maximum number of mapped memory-mapped I/O zones
+};
+
+#ifdef _MSC_VER // are we using MSVC to compile this code?
+#pragma pack (push, 1)
+#endif
+
+struct _IO_BYTE {
+    unsigned short port8;
+    unsigned char value8;
+}PACK_STRUC; 
+typedef struct _IO_BYTE IO_BYTE;
+
+struct _IO_WORD {
+    unsigned short port16; 
+    unsigned short value16;
+}PACK_STRUC;
+typedef struct _IO_WORD IO_WORD;
+
+struct _IO_LONG {
+    unsigned short port32;
+    unsigned long value32;
+}PACK_STRUC;
+typedef struct _IO_LONG IO_LONG; 
+
+struct _MMIO_MAP {
+    unsigned long phy_addr_start; // start address in physical address space to be mapped
+    unsigned long size; // size of the physical address space to map
+    void * usermode_virt_addr; // starting virtual address of the MMIO as seen from user mode
+}PACK_STRUC;
+typedef struct _MMIO_MAP MMIO_MAP;
+
+struct _PCI_ADDRESS {
+	unsigned long bus;
+	unsigned long device;
+	unsigned long function;
+	unsigned long value;
+	unsigned char offset;
+	unsigned char length; // length of the value to be written/read in bytes
+}PACK_STRUC;
+typedef struct _PCI_ADDRESS PCI_ADDRESS;
+
+#ifdef _MSC_VER // are we using MSVC to compile this code?
+#pragma pack (pop)
+#endif
+
+
+#endif //__INTERFACES_H__
Index: Makefile
===================================================================
--- Makefile	(revision 670)
+++ Makefile	(working copy)
@@ -19,13 +19,13 @@
 
 PROGRAM = flashrom
 
-CC      ?= gcc
+CC      = gcc
 STRIP   = strip
 INSTALL = install
 DIFF    = diff
 PREFIX  ?= /usr/local
 MANDIR  ?= $(PREFIX)/share/man
-CFLAGS  ?= -Os -Wall -Werror
+CFLAGS  ?= -Os -Wall 
 EXPORTDIR ?= .
 
 OS_ARCH	= $(shell uname)
@@ -41,17 +41,28 @@
 LDFLAGS += -L/usr/local/lib
 endif
 
-LIBS += -lpci -lz
-
 OBJS = chipset_enable.o board_enable.o udelay.o jedec.o stm50flw0x0x.o \
 	sst28sf040.o am29f040b.o mx29f002.o m29f400bt.o pm29f002.o \
 	w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \
 	sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o physmap.o \
 	flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \
 	ichspi.o w39v040c.o sb600spi.o wbsio_spi.o m29f002.o internal.o \
-	dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o serprog.o \
+	dummyflasher.o pcidev.o nic3com.o satasii.o ft2232_spi.o \
 	print.o
 
+ifeq ($(OS), Windows_NT)
+RC = windres
+LIBS += libpci/libpci.a
+OBJS += direct_io.o error_msg.o
+RESOURCES = flashrom.rc
+RESOURCE_OBJ = windows.o
+OBJS += $(RESOURCE_OBJ)
+else
+LIBS += -lpci -lz
+OBJS += serprog.o
+endif
+
+
 all: pciutils features dep $(PROGRAM)
 
 # Set the flashrom version string from the highest revision number
@@ -76,6 +87,11 @@
 # stored files, they can be handled here as well.
 TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root")
 
+
+ifeq ($(OS), Windows_NT)
+$(RESOURCE_OBJ): $(RESOURCES)
+	$(RC) -o $(RESOURCE_OBJ) $(RESOURCES)
+endif
 %.o: %.c .features
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $<
 
@@ -100,6 +116,7 @@
 		rm -f .test.c .test; exit 1)
 	@rm -f .test.c .test
 
+ifneq ($(OS), Windows_NT)
 pciutils: compiler
 	@printf "Checking for pciutils and zlib... "
 	@$(shell ( echo "#include <pci/pci.h>";		   \
@@ -112,6 +129,10 @@
 		echo "See README for more information."; echo;		\
 		rm -f .test.c .test; exit 1)
 	@rm -f .test.c .test
+else
+pciutils:
+	$(MAKE) -C libpci
+endif
 
 .features: features
 
Index: flashrom.rc
===================================================================
--- flashrom.rc	(revision 0)
+++ flashrom.rc	(revision 0)
@@ -0,0 +1,6 @@
+/////////////////////////////////////////////////////////////////////////
+//  winflashrom resource file
+//  28 June 2007 Darmawan Salihun
+//
+
+WINFLASHROMDRV	DRIVER	DISCARDABLE	"driver/i386/winflashrom.sys"	
Index: direct_io.c
===================================================================
--- direct_io.c	(revision 0)
+++ direct_io.c	(revision 0)
@@ -0,0 +1,654 @@
+#include <windows.h>
+#include <winioctl.h>
+#include <stdio.h>
+
+#include "interfaces.h" // Must be included after winioctl.h
+#include "direct_io.h"
+#include "error_msg.h"
+
+#define DRIVER_NAME       "winflashrom"
+
+//
+// verbosity of messages
+//
+#define VEBOSE_DEBUG_MESSAGE
+#undef VEBOSE_DEBUG_MESSAGE
+
+//
+// Globals
+//
+static HANDLE h_device = INVALID_HANDLE_VALUE;
+static UCHAR driver_path[MAX_PATH];
+
+//
+// Function implementation
+//
+
+static BOOLEAN setup_driver_name( PUCHAR driver_path )
+{
+    HANDLE file_handle;
+    unsigned long err_no;
+    unsigned long driver_path_len = 0;
+
+    //
+    // Get the current directory.
+    //
+    driver_path_len = GetCurrentDirectory(MAX_PATH, driver_path );
+
+    if (!driver_path_len) {
+	err_no = GetLastError();	    
+        printf("GetCurrentDirectory failed!  Error = %d \n",(int) err_no);
+				display_error_message(err_no);
+
+        return FALSE;
+    }
+
+    //
+    // Setup path name to driver file.
+    //
+
+    strcat(driver_path, "\\");
+    strcat(driver_path, DRIVER_NAME);
+    strcat(driver_path, ".sys");
+
+    //
+    // Insure driver file is in the specified directory.
+    //
+
+    if ((file_handle = CreateFile(driver_path,
+                                 GENERIC_READ | GENERIC_WRITE,
+                                 0,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL
+                                 )) == INVALID_HANDLE_VALUE) {
+
+
+        printf("Driver: BIOS_PROBE.SYS is not in the system directory. \n");
+
+        //
+        // Indicate failure.
+        //
+
+        return FALSE;
+    }
+
+    //
+    // Close open file handle.
+    //
+
+    if (file_handle) {
+
+        CloseHandle(file_handle);
+    }
+
+    //
+    // Indicate success.
+    //
+
+    return TRUE;
+
+
+}   // setup_driver_name
+
+
+static BOOL extract_driver(char *sz_driver, char *sz_out)
+/*++
+Routine Description:
+	find, load and extract the driver from resource
+
+Arguments: 
+	sz_driver = resource name or number
+	sz_out    = output filename
+    
+Return Value:
+	FALSE = function fails
+	TRUE = function succeds
+--*/
+
+{
+	HRSRC h_res;
+	HGLOBAL h_sys;
+	LPVOID p_sys;
+	HANDLE h_file;
+	unsigned long dw_size, dw_wri;
+
+	// find and load resources, return false if failed
+	if(!(h_res = FindResource(NULL, sz_driver, TEXT("DRIVER"))))
+		return FALSE;
+
+	if(!(h_sys = LoadResource(0, h_res)))
+		return FALSE;
+
+	dw_size = SizeofResource(0, h_res);
+	p_sys = LockResource(h_sys);
+
+	// create the driver file to the choosen path
+	if((h_file = CreateFile(sz_out, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE)
+		return FALSE;
+
+	// write the driver and and close the file handle
+	if(!WriteFile(h_file, p_sys, dw_size, &dw_wri, 0))
+	{
+		CloseHandle(h_file);
+	 	return FALSE;
+	}
+	
+	CloseHandle(h_file);
+	return TRUE;
+}
+
+
+static BOOL activate_driver(char *sz_serv, char *sz_path, BOOL activate)
+/*++
+Routine Description:
+	register, run, stop and unregister driver
+
+Arguments: 
+	sz_serv   = driver service name
+	sz_path   = path to driver
+	activate = register/unregisterNone
+    
+Return Value:
+	0 = function fails
+	1 = function succeds
+--*/
+{
+	BOOL b_stat;
+	SC_HANDLE h_sc, h_sr;
+	SERVICE_STATUS srv_stat;
+
+	b_stat = FALSE;
+	
+	h_sc = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
+	if(!h_sc) 
+	{
+	    printf("Error: failed to open service control manager\n");
+	    return FALSE;
+	}
+
+	if(activate)
+	{
+	    // start debug		
+ 	    printf("creating new service... \n");
+	    // end debug
+	    
+	    h_sr = CreateService(h_sc, sz_serv, sz_serv, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, 
+				SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, sz_path, 
+				NULL, NULL, NULL, NULL, NULL);
+		
+	    if(!h_sr) 
+	    {
+	    	// start debug		
+ 	    	printf("invalid service handle... \n");
+	    	// end debug
+		    
+		if(GetLastError() == ERROR_SERVICE_EXISTS)
+		{
+		    h_sr = OpenService(h_sc, sz_serv, SERVICE_ALL_ACCESS);
+		    
+		    if(!h_sr)
+		    {
+			printf("Error: failed to open access to the service (service already exists)\n");
+			    
+			CloseServiceHandle(h_sc);
+			return FALSE;
+		    }
+
+		    printf("Error: service already exist!\n");
+		}   
+		else
+		{
+		    // start debug
+		    printf("CreateService failed. But, not because of service exists :(\n");
+		    // end debug
+		    
+		    CloseServiceHandle(h_sc);
+		    return FALSE;
+		}
+	    }
+	    else
+	    {
+		if(StartService(h_sr, 0, NULL) == 0) 
+		{
+		    if(ERROR_SERVICE_ALREADY_RUNNING != GetLastError())
+		    {    
+                        CloseServiceHandle(h_sc);
+                        CloseServiceHandle(h_sr);
+                        return FALSE;
+		    }
+		} 
+		else 
+		{
+		    b_stat = TRUE;
+		}
+	    }
+	}
+	else
+	{
+		if(!(h_sr = OpenService(h_sc, sz_serv, SERVICE_ALL_ACCESS)))
+			b_stat = FALSE;
+		else
+			b_stat = (ControlService(h_sr, SERVICE_CONTROL_STOP, &srv_stat) == 0) ? FALSE : TRUE;
+
+		// unregister the driver
+		b_stat = (DeleteService(h_sr) == 0) ? FALSE : TRUE;
+	}
+
+	// close the service handle
+	if(h_sr) CloseServiceHandle(h_sr);
+	if(h_sc) CloseServiceHandle(h_sc);
+	return b_stat;
+}
+
+
+int init_driver()
+/*++
+Routine Description:
+	Initialize the driver interface
+
+Arguments: None
+    
+Return Value:
+    0 if error
+    1 if succeeded
+--*/
+{
+	unsigned long err_no;
+
+	// 
+    // Extract the driver binary from the resource in the executable
+    // 
+    if (extract_driver(TEXT("WINFLASHROMDRV"), "winflashrom.sys") == TRUE) {
+		printf("The driver has been extracted\n");
+		
+    } else {
+		display_error_message(GetLastError());
+		printf("Exiting..\n");
+		return 0;
+    }
+    
+    
+    //
+    // Setup full path to driver name.
+    //
+    if (!setup_driver_name(driver_path)) {
+		printf("Error: failed to setup driver name \n");
+        return 0;
+    }
+
+
+    //
+    // Try to activate the driver 
+    //
+    if(activate_driver(DRIVER_NAME, driver_path, TRUE) == TRUE) {
+		printf("The driver is registered and activated\n"); 
+    } else {
+		printf("Error: unable to register and activate the driver\n");
+		DeleteFile(driver_path);
+		return 0;		
+    }
+
+    //
+    // Try to open the newly installed driver.
+    //
+        
+    h_device = CreateFile( "\\\\.\\winflashrom",
+                GENERIC_READ | GENERIC_WRITE,
+                0,
+                NULL,
+                OPEN_EXISTING,
+                FILE_ATTRIBUTE_NORMAL,
+                NULL);
+
+    if ( h_device == INVALID_HANDLE_VALUE ){
+        err_no = GetLastError();	
+		printf ( "Error: CreateFile Failed : %d\n", (int) err_no );
+		display_error_message(err_no);
+
+		// cleanup resurces created and used up to now
+		activate_driver(DRIVER_NAME, driver_path, FALSE);
+		DeleteFile(driver_path);
+	
+        return 0;
+    }
+
+	return 1;
+}
+
+
+void cleanup_driver()
+{
+    //
+    // Close the access to the exported device interface in user-mode
+    //
+	if(h_device != INVALID_HANDLE_VALUE) {
+		CloseHandle(h_device); 
+	}
+
+    //
+    // Unload the driver.  Ignore any errors.
+    //
+    if(activate_driver(DRIVER_NAME, driver_path, FALSE) == TRUE) {
+		printf("The driver stopped and unloaded\n"); 
+    } else {
+		printf("Error: failed to stop and unload the driver\n");
+    }
+
+    //
+    // Delete the driver file
+    // 
+    DeleteFile(driver_path);
+}
+
+
+
+unsigned char inb(unsigned short port)
+{
+    IO_BYTE ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port8 = port; // port address to read from
+    
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(inl) Error: the driver handle is invalid!\n");
+	return -1;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_READ_PORT_BYTE,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+	return -1;
+    }
+
+#ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_READ_PORT_BYTE) : %d\n", 
+	    bytes_returned);
+#endif //VEBOSE_DEBUG_MESSAGE
+
+    return ioBuf.value8;
+}
+
+
+void outb(unsigned char value, unsigned short port)
+{
+    IO_BYTE ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port8 = port; // port address to write to
+    ioBuf.value8 = value; 
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(outw) Error: the driver handle is invalid!\n");
+	return;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_WRITE_PORT_BYTE,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+    }
+    
+ #ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_WRITE_PORT_BYTE) : %d\n", 
+	    bytes_returned);
+ #endif //VEBOSE_DEBUG_MESSAGE
+}
+
+
+unsigned short inw(unsigned short port)
+{
+    IO_WORD ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port16 = port; // port address to read from
+    
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(inl) Error: the driver handle is invalid!\n");
+	return -1;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_READ_PORT_WORD,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+	return -1;
+    }
+
+#ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_READ_PORT_WORD) : %d\n", 
+	    bytes_returned);
+#endif //VEBOSE_DEBUG_MESSAGE
+
+    return ioBuf.value16;
+}
+
+
+void outw(unsigned short value, unsigned short port)
+{
+    IO_WORD ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port16 = port; // port address to write to
+    ioBuf.value16 = value; 
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(outw) Error: the driver handle is invalid!\n");
+	return;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_WRITE_PORT_WORD,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+    }
+
+#ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_WRITE_PORT_WORD) : %d\n", 
+	    bytes_returned);
+#endif //VEBOSE_DEBUG_MESSAGE
+}
+
+
+unsigned long inl(unsigned short port)
+{
+    IO_LONG ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port32 = port; // port address to read from
+    
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(inl) Error: the driver handle is invalid!\n");
+	return -1;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_READ_PORT_LONG,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+	return -1;
+    }
+
+	 #ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_READ_PORT_LONG) : %d\n", 
+	    bytes_returned);
+	 #endif //VEBOSE_DEBUG_MESSAGE
+
+    return ioBuf.value32;
+}
+
+
+void outl(unsigned long value, unsigned short port)
+{
+    IO_LONG ioBuf;
+    unsigned long bytes_returned;
+    
+    ioBuf.port32 = port; // port address to write to
+    ioBuf.value32 = value; 
+
+    if( INVALID_HANDLE_VALUE == h_device) {
+	printf("(outl) Error: the driver handle is invalid!\n");
+	return;
+    }
+    
+    if( FALSE == DeviceIoControl( h_device, 
+				 IOCTL_WRITE_PORT_LONG,
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &ioBuf,
+				 sizeof(ioBuf),
+				 &bytes_returned,
+				 NULL))
+    {
+	display_error_message(GetLastError());
+    }
+
+ #ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_WRITE_PORT_LONG) : %d\n", 
+	    bytes_returned);
+ #endif //VEBOSE_DEBUG_MESSAGE
+}
+
+
+void* map_physical_addr_range( unsigned long phy_addr_start, unsigned long size )
+/*++
+Routine Description:
+	Maps an MMIO range.
+
+Arguments:
+    phy_addr_start -  The start of physical address to be mapped.
+	size - The size of the MMIO range to map, in bytes.
+
+Return Value:
+    NULL - on error
+	pointer to the virtual address of the mapped MMIO range - on success
+
+Note:
+	-	The pointer returned from this function is in the context of the 
+	    usermode application that use this function.
+	-	You must call unmap_physical_addr_range when you are done with the  
+		mapped physical memory/MMIO range that you obtain with this function.
+--*/
+{
+	MMIO_MAP mmio_map;
+	unsigned long bytes_returned;
+
+	if( INVALID_HANDLE_VALUE == h_device) {
+		printf("(map_physical_addr_range) Error: the driver handle is invalid!\n");
+		return 0; // error
+    }
+    
+	mmio_map.phy_addr_start = phy_addr_start;
+	mmio_map.size = size;
+
+    if( FALSE == DeviceIoControl( h_device, 
+					IOCTL_MAP_MMIO,
+					&mmio_map,
+					sizeof(mmio_map),
+					&mmio_map,
+					sizeof(mmio_map),
+					&bytes_returned,
+					NULL))
+    {
+		display_error_message(GetLastError());
+		return NULL; // error
+    }
+
+ #ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_MAP_BIOS_CHIP) : %d\n", 
+	    bytes_returned);
+ #endif //VEBOSE_DEBUG_MESSAGE
+
+    return mmio_map.usermode_virt_addr; 
+}	
+
+
+int unmap_physical_addr_range( void* virt_addr_start, unsigned long size )
+/*++
+Routine Description:
+	Unmaps a previously mapped MMIO range.
+
+Arguments:
+    virt_addr_start - The start address of the mapped physical address.
+	                This parameter _must_ _be_ in the context of the 
+					currently executing application. It must be a 
+					pointer returned from a previous call to 
+					map_physical_addr_range function.
+	size - The size of the mapped MMIO range in bytes.
+
+Return Value:
+    0 - on error
+	1 - on success
+
+Note:
+	This function must be called when you are done with a 
+	mapped physical memory/MMIO range.
+--*/
+{
+	MMIO_MAP mmio_map;
+	unsigned long bytes_returned;
+
+	if( INVALID_HANDLE_VALUE == h_device) {
+		printf("(unmap_physical_addr_range) Error: the driver handle is invalid!\n");
+		return 0; // error
+    	}
+    
+	mmio_map.usermode_virt_addr = virt_addr_start;
+	mmio_map.size = size;
+
+    if( FALSE == DeviceIoControl( h_device, 
+					IOCTL_UNMAP_MMIO,
+					&mmio_map,
+					sizeof(mmio_map),
+					&mmio_map,
+					sizeof(mmio_map),
+					&bytes_returned,
+					NULL))
+    {
+		display_error_message(GetLastError());
+		return 0; // error
+    }
+
+ #ifdef VEBOSE_DEBUG_MESSAGE
+    printf("number of bytes returned from kernel (IOCTL_UNMAP_BIOS_CHIP) : %d\n", 
+	    bytes_returned);
+ #endif //VEBOSE_DEBUG_MESSAGE
+
+	return 1; // success
+}
+
Index: chipset_enable.c
===================================================================
--- chipset_enable.c	(revision 670)
+++ chipset_enable.c	(working copy)
@@ -29,7 +29,11 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#ifdef __MINGW32_VERSION
+#include "direct_io.h"
+#else
 #include <sys/mman.h>
+#endif
 #include <fcntl.h>
 #include "flash.h"
 
@@ -968,7 +972,7 @@
 	}
 
 	/* 4. Clean up */
-	munmap(mmcr, getpagesize());
+	physunmap(mmcr, getpagesize());
 	return 0;
 }
 
Index: sb600spi.c
===================================================================
--- sb600spi.c	(revision 670)
+++ sb600spi.c	(working copy)
@@ -21,7 +21,7 @@
  */
 
 #include <string.h>
-#include <sys/mman.h>
+//#include <sys/mman.h>
 #include "flash.h"
 #include "spi.h"
 
Index: direct_io.h
===================================================================
--- direct_io.h	(revision 0)
+++ direct_io.h	(revision 0)
@@ -0,0 +1,28 @@
+#ifndef __DIRECT_IO_H__
+#define __DIRECT_IO_H__
+
+int init_driver(); // returns 0 on error, 1 on success
+void cleanup_driver(); // must be called after done using the driver
+
+void* map_physical_addr_range( unsigned long phy_addr_start, 
+						 unsigned long size ); // returns NULL on error, valid pointer on success
+int unmap_physical_addr_range( void* virt_addr_start, 
+		        unsigned long size ); // must be called after done with the mapped physical memory
+
+unsigned long hal_pci_read_offset( unsigned long  bus, unsigned long  device,
+		                   unsigned long  function, unsigned long  offset, 
+				   unsigned char length);
+
+void hal_pci_write_offset( unsigned long  bus, unsigned long  device, 
+			   unsigned long  function, unsigned long  offset, 
+			   unsigned long value, unsigned char length );
+
+void outb(unsigned char value, unsigned short port);
+void outw(unsigned short value, unsigned short port);
+void outl(unsigned long value, unsigned short port);
+
+unsigned char inb(unsigned short port);
+unsigned short inw(unsigned short port);
+unsigned long inl(unsigned short port);
+
+#endif //__DIRECT_IO_H__
Index: flashrom.c
===================================================================
--- flashrom.c	(revision 670)
+++ flashrom.c	(working copy)
@@ -131,6 +131,8 @@
 		.chip_writen		= fallback_chip_writen,
 		.delay			= internal_delay,
 	},
+#ifndef __MINGW32_VERSION
+	/* the serprog driver has not been ported to windows yet */
 	{
 		.init			= serprog_init,
 		.shutdown		= serprog_shutdown,
@@ -146,6 +148,7 @@
 		.chip_writen		= fallback_chip_writen,
 		.delay			= serprog_delay,
 	},
+#endif
 
 	{},
 };
@@ -661,10 +664,12 @@
 				programmer = PROGRAMMER_FT2232SPI;
 				if (optarg[9] == '=')
 					ft2232spi_param = strdup(optarg + 10);
+#ifndef __MINGW32_VERSION
 			} else if (strncmp(optarg, "serprog", 7) == 0) {
 				programmer = PROGRAMMER_SERPROG;
 				if (optarg[7] == '=')
 					serprog_param = strdup(optarg + 8);
+#endif
 			} else {
 				printf("Error: Unknown programmer.\n");
 				exit(1);
Index: internal.c
===================================================================
--- internal.c	(revision 670)
+++ internal.c	(working copy)
@@ -27,6 +27,9 @@
 #include <errno.h>
 #include "flash.h"
 
+#if defined(__MINGW32_VERSION)
+#include "direct_io.h"
+#endif
 #if defined(__FreeBSD__) || defined(__DragonFly__)
 int io_fd;
 #endif
@@ -82,10 +85,18 @@
 
 void get_io_perms(void)
 {
+#ifdef __MINGW32_VERSION
+	if(init_driver() == 0) {
+		fprintf(stderr, "ERROR: Could not get I/O privileges.\n");
+		exit(1);
+	}
+	atexit(cleanup_driver);
+#else
 #if defined (__sun) && (defined(__i386) || defined(__amd64))
 	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
 #elif defined(__FreeBSD__) || defined (__DragonFly__)
 	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
+
 #else
 	if (iopl(3) != 0) {
 #endif
@@ -93,6 +104,7 @@
 			"You need to be root.\n", strerror(errno));
 		exit(1);
 	}
+#endif
 }
 
 int internal_init(void)
Index: ichspi.c
===================================================================
--- ichspi.c	(revision 670)
+++ ichspi.c	(working copy)
@@ -33,7 +33,7 @@
  */
 
 #include <string.h>
-#include <sys/mman.h>
+// #include <sys/mman.h>
 #include "flash.h"
 #include "spi.h"
 
Index: cbtable.c
===================================================================
--- cbtable.c	(revision 670)
+++ cbtable.c	(working copy)
@@ -26,7 +26,6 @@
 #include <sys/types.h>
 #include <string.h>
 #include <errno.h>
-#include <sys/mman.h>
 #include "flash.h"
 #include "coreboot_tables.h"
 
@@ -180,7 +179,7 @@
 	}
 }
 
-#define BYTES_TO_MAP (1024*1024)
+#define BYTES_TO_MAP (64*1024)
 int coreboot_init(void)
 {
 	uint8_t *table_area;
@@ -208,8 +207,9 @@
 			start = forward->forward;
 			start &= ~(getpagesize() - 1);
 			physunmap(table_area, BYTES_TO_MAP);
-			table_area = physmap("high tables", start, BYTES_TO_MAP);
-			lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+			//table_area = physmap("high tables", start, BYTES_TO_MAP);
+			//lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+			lb_table=NULL;
 		}
 	}
 
