OBJ += drvutil_video.o drvutil_disk.o
OBJ += messages.o modules.o syscalls.o system.o
OBJ += threads.o mutex.o semaphore.o workqueue.o events.o rwlock.o
-OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o
+OBJ += drv/zero-one.o drv/proc.o drv/fifo.o drv/iocache.o drv/pci.o drv/vpci.o
OBJ += drv/vterm.o drv/vterm_font.o drv/vterm_vt100.o drv/vterm_output.o drv/vterm_input.o drv/vterm_termbuf.o
OBJ += binary.o bin/elf.o bin/pe.o
OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/dir.o vfs/io.o vfs/mount.o
A_OBJ = start.ao main.o lib.o lib.ao time.o pci.o debug.o
A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+A_OBJ += vpci_$(PLATFORM).o
#main.c: Makefile.BuildNum.$(ARCH)
. += gUsertextPhysStart + _kernel_base - _usertext_vbase;
/DISCARD/ : { *(.ARM.extab.init .ARM.exidx.init) }
- .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ .ARM.extab : AT( ADDR(.ARM.extab) - _kernel_base)
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ }
PROVIDE_HIDDEN ( __exidx_start = . );
- .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ .ARM.exidx : AT( ADDR(.ARM.exidx) - _kernel_base)
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ }
PROVIDE_HIDDEN ( __exidx_end = . );
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
- .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ .eh_frame_hdr : AT( ADDR(.eh_frame_hdr) - _kernel_base) {
+ *(.eh_frame_hdr)
+ }
+ .eh_frame : AT( ADDR(.eh_frame) - _kernel_base) ONLY_IF_RO
+ {
+ KEEP (*(.eh_frame))
+ }
+ .gcc_except_table : AT( ADDR(.gcc_except_table) - _kernel_base) ONLY_IF_RO
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ }
/* 0x4000 (4 pages) alignment needed for root table */
. = ALIGN(0x4000);
--- /dev/null
+/*
+ * Acess2 Kernel ARMv7 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci_tegra2.c
+ * - Tegra2 VPCI Definitions
+ */
+#include <virtual_pci.h>
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+tVPCI_Device gaVPCI_Devices[] = {
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5000000,0,0,0,0,0},
+ .IRQ = 0*32+20,
+ },
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5004000,0,0,0,0,0},
+ .IRQ = 0*32+21,
+ },
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5008000,0,0,0,0,0},
+ .IRQ = 4*32+1,
+ }
+};
+int giVPCI_DeviceCount = sizeof(gaVPCI_Devices)/sizeof(gaVPCI_Devices[0]);
+
A_OBJ = start.ao main.o mboot.o lib.o desctab.ao errors.o irq.o
A_OBJ += mm_phys.o mm_virt.o
A_OBJ += proc.o proc.ao time.o vm8086.o
-A_OBJ += kpanic.o pci.o
+A_OBJ += kpanic.o pci.o vpci.o
gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
// Adjust Multiboot structure address
- mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+ mbInfo = (void*)( (tVAddr)MbInfoPtr + KERNEL_BASE );
nPMemMapEnts = Multiboot_LoadMemoryMap(mbInfo, KERNEL_BASE, pmemmap, MAX_PMEMMAP_ENTS,
KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_BASE);
* mboot.c
* - Multiboot Support
*/
-#define DEBUG 0
+#define DEBUG 1
#include <acess.h>
#include <mboot.h>
ENTER("pMBInfo pMapOffset pMap iMapSize PKStart PKEnd",
MBInfo, MapOffset, Map, MapSize, KStart, KEnd);
- // Build up memory map
- nPMemMapEnts = 0;
- while( ent < last && nPMemMapEnts < MapSize )
+ // Check that the memory map is present
+ if( MBInfo->Flags & (1 << 6) )
{
- tPMemMapEnt *nent = &Map[nPMemMapEnts];
- nent->Start = ent->Base;
- nent->Length = ent->Length;
- switch(ent->Type)
+ // Build up memory map
+ nPMemMapEnts = 0;
+ while( ent < last && nPMemMapEnts < MapSize )
{
- case 1:
- nent->Type = PMEMTYPE_FREE;
- break;
- default:
- nent->Type = PMEMTYPE_RESERVED;
- break;
+ tPMemMapEnt *nent = &Map[nPMemMapEnts];
+ if( !MM_GetPhysAddr(ent) )
+ Log_KernelPanic("MBoot", "MBoot Map entry %i addres bad (%p)",
+ nPMemMapEnts, ent);
+
+ nent->Start = ent->Base;
+ nent->Length = ent->Length;
+ switch(ent->Type)
+ {
+ case 1:
+ nent->Type = PMEMTYPE_FREE;
+ break;
+ default:
+ nent->Type = PMEMTYPE_RESERVED;
+ break;
+ }
+ nent->NUMADomain = 0;
+
+ nPMemMapEnts ++;
+ ent = (void*)( (tVAddr)ent + ent->Size + 4 );
}
- nent->NUMADomain = 0;
-
- nPMemMapEnts ++;
- ent = (void*)( (tVAddr)ent + ent->Size + 4 );
+ }
+ else if( MBInfo->Flags & (1 << 0) )
+ {
+ Log_Warning("MBoot", "No memory map passed, using mem_lower and mem_upper");
+ nPMemMapEnts = 2;
+ Map[0].Start = 0;
+ Map[0].Length = MBInfo->LowMem * 1024;
+ Map[0].Type = PMEMTYPE_FREE;
+ Map[0].NUMADomain = 0;
+
+ Map[1].Start = 0x100000;
+ Map[1].Length = MBInfo->HighMem * 1024;
+ Map[1].Type = PMEMTYPE_FREE;
+ Map[1].NUMADomain = 0;
+ }
+ else
+ {
+ Log_KernelPanic("MBoot", "Multiboot didn't pass memory information");
}
// Ensure it's valid
KStart, KEnd - KStart
);
- // Replace modules with PMEMTYPE_USED
- nPMemMapEnts = PMemMap_MarkRangeUsed(Map, nPMemMapEnts, MapSize,
- MBInfo->Modules, MBInfo->ModuleCount*sizeof(tMBoot_Module)
- );
- tMBoot_Module *mods = (void*)( (tVAddr)MBInfo->Modules + MapOffset);
- for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+ PMemMap_DumpBlocks(Map, nPMemMapEnts);
+
+ // Check if boot modules were passed
+ if( MBInfo->Flags & (1 << 3) )
{
- nPMemMapEnts = PMemMap_MarkRangeUsed(
- Map, nPMemMapEnts, MapSize,
- mods->Start, mods->End - mods->Start
+ // Replace modules with PMEMTYPE_USED
+ nPMemMapEnts = PMemMap_MarkRangeUsed(Map, nPMemMapEnts, MapSize,
+ MBInfo->Modules, MBInfo->ModuleCount*sizeof(tMBoot_Module)
);
+ LOG("MBInfo->Modules = %x", MBInfo->Modules);
+ tMBoot_Module *mods = (void*)( (tVAddr)MBInfo->Modules + MapOffset);
+ for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+ {
+ LOG("&mods[%i] = %p", i, &mods[i]);
+ LOG("mods[i] = {0x%x -> 0x%x}", mods[i].Start, mods[i].End);
+ nPMemMapEnts = PMemMap_MarkRangeUsed(
+ Map, nPMemMapEnts, MapSize,
+ mods[i].Start, mods[i].End - mods[i].Start
+ );
+ }
}
-
+
// Debug - Output map
PMemMap_DumpBlocks(Map, nPMemMapEnts);
tBootModule *Multiboot_LoadModules(tMBoot_Info *MBInfo, tVAddr MapOffset, int *ModuleCount)
{
+ if( !(MBInfo->Flags & (1 << 3)) ) {
+ *ModuleCount = 0;
+ Log_Log("Arch", "No multiboot module information passed");
+ return NULL;
+ }
+
tMBoot_Module *mods = (void*)( MBInfo->Modules + MapOffset );
*ModuleCount = MBInfo->ModuleCount;
tBootModule *ret = malloc( MBInfo->ModuleCount * sizeof(*ret) );
--- /dev/null
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === GLOBALS ===
+ int giVPCI_DeviceCount = 0;
+tVPCI_Device gaVPCI_Devices[0];
+
/*\r
- * AcessOS/AcessBasic v0.1\r
- * PCI Bus Driver\r
+ * Acess2 Kernel\r
+ * - By John Hodge (thePowersGang)\r
+ * \r
+ * drv/pci.c\r
+ * - PCI Enumeration and Arbitration\r
*/\r
#define DEBUG 0\r
#include <acess.h>\r
#include <fs_devfs.h>\r
#include <drv_pci.h>\r
#include <drv_pci_int.h>\r
+#include <virtual_pci.h>\r
\r
#define USE_PORT_BITMAP 0\r
#define LIST_DEVICES 1\r
+#define PCI_MAX_BUSSES 8\r
\r
// === STRUCTURES ===\r
typedef struct sPCIDevice\r
// === GLOBALS ===\r
MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
int giPCI_BusCount = 1;\r
+Uint8 gaPCI_BusNumbers[PCI_MAX_BUSSES];\r
int giPCI_InodeHandle = -1;\r
int giPCI_DeviceCount = 0;\r
tPCIDevice *gPCI_Devices = NULL;\r
#endif \r
\r
// Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
+ giPCI_DeviceCount = 0;\r
+ giPCI_BusCount = 1;\r
+ gaPCI_BusNumbers[0] = 0;\r
for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
{\r
- ret = PCI_ScanBus(bus, 0);\r
+ ret = PCI_ScanBus(gaPCI_BusNumbers[bus], 0);\r
if(ret != MODULE_ERR_OK) return ret;\r
}\r
- \r
+ // TODO: PCIe\r
+ // - Add VPCI Devices\r
+ giPCI_DeviceCount += giVPCI_DeviceCount;\r
+ \r
if(giPCI_DeviceCount == 0) {\r
Log_Notice("PCI", "No devices were found");\r
return MODULE_ERR_NOTNEEDED;\r
// Rescan, filling the PCI device array\r
for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
{\r
- PCI_ScanBus(bus, 1);\r
+ PCI_ScanBus(gaPCI_BusNumbers[bus], 1);\r
+ }\r
+ // Insert VPCI Devices\r
+ for( int i = 0; i < giVPCI_DeviceCount; i ++ )\r
+ {\r
+ tPCIDevice *devinfo = &gPCI_Devices[giPCI_DeviceCount];\r
+ \r
+ devinfo->bus = -1;\r
+ devinfo->slot = i;\r
+ devinfo->fcn = 0;\r
+ devinfo->vendor = gaVPCI_Devices[i].Vendor;\r
+ devinfo->device = gaVPCI_Devices[i].Device;\r
+ devinfo->revision = gaVPCI_Devices[i].Class & 0xFF;\r
+ devinfo->class = gaVPCI_Devices[i].Class >> 8;\r
+ snprintf(devinfo->Name, sizeof(devinfo->Name), "%02x.%02x:%x", 0xFF, i, 0);\r
+\r
+ for(int j = 0; j < 256/4; j ++ )\r
+ devinfo->ConfigCache[i] = VPCI_Read(&gaVPCI_Devices[i], j*4, 4);\r
+\r
+ memset(&devinfo->Node, 0, sizeof(devinfo->Node));\r
+ devinfo->Node.Inode = giPCI_DeviceCount;\r
+ devinfo->Node.Size = 256;\r
+ devinfo->Node.NumACLs = 1;\r
+ devinfo->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
+ devinfo->Node.Type = &gPCI_DevNodeType;\r
+\r
+ giPCI_DeviceCount ++;\r
}\r
\r
// Complete Driver Structure\r
if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))\r
continue;\r
\r
- if(devInfo.class == PCI_OC_PCIBRIDGE)\r
- {\r
- #if LIST_DEVICES\r
- if( !bFill )\r
- Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
- BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
- #endif\r
- //TODO: Handle PCI-PCI Bridges\r
- //PCI_ScanBus(devInfo.???, bFill);\r
- giPCI_BusCount ++;\r
- }\r
- else\r
- {\r
- #if LIST_DEVICES\r
- if( !bFill )\r
- Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x Rev %i",\r
- BusID, dev, fcn, devInfo.class,\r
- devInfo.vendor, devInfo.device, devInfo.revision);\r
- #endif\r
- }\r
+ #if LIST_DEVICES\r
+ if( !bFill )\r
+ Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x Rev %i",\r
+ BusID, dev, fcn, devInfo.class,\r
+ devInfo.vendor, devInfo.device, devInfo.revision);\r
+ #endif\r
\r
if( bFill ) {\r
devInfo.Node.Inode = giPCI_DeviceCount;\r
}\r
giPCI_DeviceCount ++;\r
\r
- // If bit 23 of (soemthing) is set, there are sub-functions\r
+ switch(devInfo.ConfigCache[3] & 0x007F0000)\r
+ {\r
+ case 0x00: // Normal device\r
+ break;\r
+ case 0x01: // PCI-PCI Bridge\r
+ {\r
+ // TODO: Add to list of busses?\r
+ Uint8 sec = (devInfo.ConfigCache[6] & 0x0000FF00) >> 8;\r
+ #if LIST_DEVICES\r
+ if( !bFill ) {\r
+ Uint8 pri = (devInfo.ConfigCache[6] & 0x000000FF) >> 0;\r
+ Log_Log("PCI", "- PCI-PCI Bridge %02x=>%02x", pri, sec);\r
+ }\r
+ #endif\r
+ gaPCI_BusNumbers[giPCI_BusCount++] = sec;\r
+ }\r
+ break;\r
+ case 0x02: // PCI-CardBus Bridge\r
+ break;\r
+ }\r
+\r
+ // If bit 8 of the Header Type register is set, there are sub-functions\r
if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
break;\r
}\r
*/\r
tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)\r
{\r
- int bus,slot,fcn;\r
int i;\r
- // Validate Filename (Pointer and length)\r
- if(!filename || strlen(filename) != 7)\r
- return NULL;\r
- // Check for spacers\r
- if(filename[2] != '.' || filename[5] != ':')\r
- return NULL;\r
- \r
- // Get Information\r
- if(filename[0] < '0' || filename[0] > '9') return NULL;\r
- bus = (filename[0] - '0')*10;\r
- if(filename[1] < '0' || filename[1] > '9') return NULL;\r
- bus += filename[1] - '0';\r
- if(filename[3] < '0' || filename[3] > '9') return NULL;\r
- slot = (filename[3] - '0')*10;\r
- if(filename[4] < '0' || filename[4] > '9') return NULL;\r
- slot += filename[4] - '0';\r
- if(filename[6] < '0' || filename[6] > '9') return NULL;\r
- fcn = filename[6] - '0';\r
\r
// Find Match\r
for(i=0;i<giPCI_DeviceCount;i++)\r
{\r
- if(gPCI_Devices[i].bus != bus) continue;\r
- if(gPCI_Devices[i].slot != slot) continue;\r
- if(gPCI_Devices[i].fcn != fcn) continue;\r
- \r
- return &gPCI_Devices[i].Node;\r
+ int cmp = strcmp(gPCI_Devices[i].Name, filename);\r
+ if( cmp > 0 ) // Sorted list\r
+ break;\r
+ if( cmp == 0 )\r
+ return &gPCI_Devices[i].Node;\r
}\r
\r
// Error Return\r
if( Offset & (Size - 1) ) return 0;\r
\r
dev = &gPCI_Devices[ID];\r
+ // Detect VPCI devices\r
+ if( dev->bus == -1 ) {\r
+ return VPCI_Read(&gaVPCI_Devices[dev->slot], Offset, Size);\r
+ }\r
+\r
addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
\r
dword = PCI_CfgReadDWord(addr);\r
tPCIDevice *dev;\r
Uint32 dword, addr;\r
int shift;\r
+\r
if( ID < 0 || ID >= giPCI_DeviceCount ) return ;\r
if( Offset < 0 || Offset > 256 ) return ;\r
- \r
+\r
dev = &gPCI_Devices[ID];\r
+\r
+ // Detect VPCI devices\r
+ if( dev->bus == -1 ) {\r
+ VPCI_Write(&gaVPCI_Devices[dev->slot], Offset, Size, Value);\r
+ return ;\r
+ }\r
+\r
addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
\r
if(Size != 4)\r
vendor_dev = PCI_CfgReadDWord( addr );\r
if((vendor_dev & 0xFFFF) == 0xFFFF) // Invalid Device\r
return 0;\r
+ \r
+ info->bus = bus;\r
+ info->slot = slot;\r
+ info->fcn = fcn;\r
\r
+ // Read configuration\r
info->ConfigCache[0] = vendor_dev;\r
for( i = 1, addr += 4; i < 256/4; i ++, addr += 4 )\r
{\r
info->ConfigCache[i] = PCI_CfgReadDWord(addr);\r
} \r
\r
- info->bus = bus;\r
- info->slot = slot;\r
- info->fcn = fcn;\r
info->vendor = vendor_dev & 0xFFFF;\r
info->device = vendor_dev >> 16;\r
tmp = info->ConfigCache[2];\r
// #endif\r
\r
// Make node name\r
- info->Name[0] = '0' + bus/10;\r
- info->Name[1] = '0' + bus%10;\r
- info->Name[2] = '.';\r
- info->Name[3] = '0' + slot/10;\r
- info->Name[4] = '0' + slot%10;\r
- info->Name[5] = ':';\r
- info->Name[6] = '0' + fcn;\r
- info->Name[7] = '\0';\r
+ snprintf(info->Name, 8, "%02x.%02x:%x", bus, slot, fcn);\r
\r
// Create VFS Node\r
memset( &info->Node, 0, sizeof(tVFS_Node) );\r
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === CODE ===
+Uint32 VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size)
+{
+ Uint32 tmp_dword = 0;
+
+ if( Size > 4 || Size == 3 || Size == 0 )
+ return 0;
+ if( Offset & (Size - 1) )
+ return 0;
+
+ switch( Offset >> 2 )
+ {
+ case 0: // Vendor[0:15], Device[16:31]
+ tmp_dword = (Dev->Vendor) | (Dev->Device << 16);
+ break;
+ case 2: // Class Code
+ tmp_dword = Dev->Class;
+ break;
+ // 1: Command[0:15], Status[16:31]
+ // 3: Cache Line Size, Latency Timer, Header Type, BIST
+ // 4-9: BARs
+ // 10: Unused (Cardbus CIS Pointer)
+ // 11: Subsystem Vendor ID, Subsystem ID
+ // 12: Expansion ROM Address
+ // 13: Capabilities[0:8], Reserved[9:31]
+ // 14: Reserved
+ // 15: Interrupt Line, Interrupt Pin, Min Grant, Max Latency
+ default:
+ tmp_dword = Dev->Read(Dev->Ptr, Offset >> 2);
+ break;
+ }
+
+ tmp_dword >>= 8*(Offset & 3);
+ switch(Size)
+ {
+ case 4: break;
+ case 2: tmp_dword &= 0xFFFF; break;
+ case 1: tmp_dword &= 0xFF;
+ }
+
+ return tmp_dword;
+}
+
+void VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data)
+{
+ Uint32 tmp_dword;
+ if( Size > 4 || Size == 3 || Size == 0 )
+ return ;
+ if( Offset & (Size - 1) )
+ return ;
+
+ switch(Offset >> 2)
+ {
+ case 0: // Vendor / Device IDs
+ case 2: // Class Code
+ // READ ONLY
+ return ;
+ }
+
+ tmp_dword = Dev->Read(Dev->Ptr, Offset>>2);
+ switch(Size)
+ {
+ case 4: tmp_dword = 0; break;
+ case 2:
+ tmp_dword &= ~(0xFFFF << ((Offset&2)*16));
+ Data |= 0xFFFF;
+ break;
+ case 1:
+ tmp_dword &= ~(0xFF << ((Offset&3)*8));
+ Data |= 0xFF;
+ break;
+ }
+ tmp_dword |= Data << ((Offset&3)*8);
+ Dev->Write(Dev->Ptr, Offset>>2, tmp_dword);
+}
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * virtual_pci.h
+ * - Virtual PCI bus definitions
+ */
+#ifndef _VIRTUAL_PCI_H_
+#define _VIRTUAL_PCI_H_
+#include <acess.h>
+
+typedef struct sVPCI_Device tVPCI_Device;
+
+struct sVPCI_Device
+{
+ void *Ptr;
+
+ // Vendor/Device is defined at runtime as 0x0ACE:0x[ARCH][ARCH][IDX][IDX]
+ Uint16 Vendor;
+ Uint16 Device;
+ // Class code (Class, Subclass, Programming Interface, Revision)
+ Uint32 Class;
+
+ Uint32 BARs[6];
+ Uint8 IRQ;
+
+ /**
+ * \param Ptr Value in sVPCI_Device.Ptr
+ * \param Data Data to write to the specified address
+ */
+ void (*Write)(void *Ptr, Uint8 DWord, Uint32 Data);
+ Uint32 (*Read)(void *Ptr, Uint8 DWord);
+};
+
+extern int giVPCI_DeviceCount;
+extern tVPCI_Device gaVPCI_Devices[];
+
+extern Uint32 VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size);
+extern void VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data);
+#endif
+