Works now in OS9, OSX, and with MacsBug !

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff --git a/QemuVGADriver/QemuVGADriver.mcp.xml b/QemuVGADriver/QemuVGADriver.mcp.xml
index 71c86c5..f4f930e 100644
--- a/QemuVGADriver/QemuVGADriver.mcp.xml
+++ b/QemuVGADriver/QemuVGADriver.mcp.xml
Binary files differ
diff --git a/QemuVGADriver/src/DriverDoDriverIO.c b/QemuVGADriver/src/DriverDoDriverIO.c
old mode 100644
new mode 100755
index 38f861a..d72fd9c
--- a/QemuVGADriver/src/DriverDoDriverIO.c
+++ b/QemuVGADriver/src/DriverDoDriverIO.c
@@ -25,7 +25,7 @@
 	| (0 * kDriverIsLoadedUponDiscovery)	/* Loader runtime options */
 	| (1 * kDriverIsOpenedUponLoad)		/* Opened when loaded */
 	| (1 * kDriverIsUnderExpertControl)	/* I/O expert handles loads/opens */
-	| (01 * kDriverIsConcurrent)		/* concurrent */
+	| (0 * kDriverIsConcurrent)		/* concurrent */
 	| (0 * kDriverQueuesIOPB),		/* Internally queued */
 	QEMU_PCI_VIDEO_PNAME,			/* Str31 driverName (OpenDriver param) */
 	0, 0, 0, 0, 0, 0, 0, 0,			/* UInt32 driverDescReserved[8] */
@@ -42,8 +42,6 @@
 	1, 0, 0, 0
 };
 
-#pragma internal on
-
 /*
  * All driver-global information is in a structure defined in NCRDriverPrivate.
  * Note that "modern" drivers do not have access to their dce. In native Power PC
@@ -77,8 +75,6 @@
  * If it returns busy status, the driver promises to call IOCommandIsComplete when
  * the transaction has completed.
  */
-#pragma internal off
-
 OSStatus
 DoDriverIO( AddressSpaceID addressSpaceID, IOCommandID ioCommandID, IOCommandContents ioCommandContents,
 	    IOCommandCode ioCommandCode, IOCommandKind ioCommandKind )
@@ -90,8 +86,8 @@
 	 * or immediate. Read, Write, Control, and Status may be immediate,
 	 * synchronous, or asynchronous.
 	 */
-	
-	Trace(DoDriverIO);
+
+	lprintf("DoDriverIO cmdCode=%d\n", ioCommandCode);
 
 	switch( ioCommandCode ) {
 	case kInitializeCommand:			/* Always immediate */
@@ -119,7 +115,6 @@
 					   (CntrlParam*)ioCommandContents.pb );
 		break;
 	case kStatusCommand:
-		/* lprintf("kStatusCommand\n");	*/
 		status = DriverStatusCmd( ioCommandID, ioCommandKind, 
 					  (CntrlParam *)ioCommandContents.pb );
 		break;
@@ -138,6 +133,8 @@
 		status = paramErr;
 		break;
 	}
+	lprintf("Completing with status=%d (kind: %x)\n", status, ioCommandKind);
+
 	/*
 	 * Force a valid result for immediate commands -- they must return a valid
 	 * status to the Driver Manager: returning kIOBusyStatus would be a bug..
@@ -166,8 +163,6 @@
 	return status;
 }
 
-#pragma internal on
-
 /*
  * DriverInitializeCmd
  *
@@ -180,6 +175,11 @@
 		
 	Trace(DriverInitializeCmd);
 
+	lprintf("** First call:\n");
+	lprintf("   DoDriverIO       @ %p\n", DoDriverIO);
+	lprintf("   DriverStatusCmd  @ %p\n", DriverStatusCmd);
+	lprintf("   DriverControlCmd @ %p\n", DriverControlCmd);
+	
 	GLOBAL.refNum = driverInitInfoPtr->refNum;
 	GLOBAL.openCount = 0;
 	GLOBAL.inInterrupt = false;
@@ -217,6 +217,7 @@
 			GLOBAL.boardRegAddress, GLOBAL.boardRegMappedSize);
 
 
+	lprintf("Enabling memory space..\n");
 	status = EnablePCIMemorySpace(&GLOBAL.deviceEntry);
 	if (status != noErr) {
 		lprintf("EnablePCIMemorySpace returned %d\n", status);
@@ -224,7 +225,9 @@
 	}
 
 	status = QemuVga_Init();
-
+	if (status != noErr)
+		goto bail;
+	
 bail:
 	DBG(lprintf("Driver init result: %d\n", status));
 	
@@ -330,12 +333,11 @@
 	
 	switch( pb->csCode ) {
 	case cscReset:			// Old obsolete call..return a 'controlErr'
-		status = controlErr;
+		return controlErr;
 		break;
 			
 	case cscKillIO:			// Old obsolete call..do nothing
-		status = controlErr;
-		break;
+		return noErr;
 
 	case cscSetMode:
 		status = GraphicsCoreSetMode((VDPageInfo *) genericPtr);
@@ -368,8 +370,7 @@
 		break;
 			
 	case cscSetDefaultMode:
-		status = controlErr;
-		break;
+		return controlErr;
 		
 	case cscSwitchMode:
 		status = GraphicsCoreSwitchMode((VDSwitchInfoRec *) genericPtr);
@@ -394,11 +395,10 @@
 		status = GraphicsCoreSetPowerState((VDPowerStateRec *) genericPtr);
 		break;	
 	default:
-		status = controlErr;
 		break;
 	}
-	if( status )
-		status = controlErr;
+	if (status)
+		status = paramErr;
 
 	return status;
 }
@@ -425,7 +425,7 @@
 	genericPtr = (void *) *((UInt32 *) &(pb->csParam[0]));
 
 	Trace(DriverStatusCmd);
-	
+	lprintf("csCode=%d\n", pb->csCode);
 	switch( pb->csCode ) {
 	case cscGetMode:
 		status = GraphicsCoreGetMode((VDPageInfo *) genericPtr);
@@ -510,13 +510,15 @@
 	case cscGetPowerState:
 		status = GraphicsCoreGetPowerState((VDPowerStateRec *) genericPtr);
 		break;
-		
-	default:
-		status = statusErr;
+	case cscGetClutBehavior:
+		*(VDClutBehaviorPtr)genericPtr = kSetClutAtSetEntries;
+		status = noErr;
 		break;
+	default:
+		return statusErr;
 	}
-	if( status )
-		status = statusErr;
+	if (status)
+		status = paramErr;
 
 	return status;
 }
diff --git a/QemuVGADriver/src/DriverGestaltHandler.c b/QemuVGADriver/src/DriverGestaltHandler.c
old mode 100644
new mode 100755
index ca37874..84189e0
--- a/QemuVGADriver/src/DriverGestaltHandler.c
+++ b/QemuVGADriver/src/DriverGestaltHandler.c
@@ -16,6 +16,11 @@
 	PB.driverGestaltResponse = 0;
 	status = noErr;
 
+	lprintf("DriverGestalt, selector=%c%c%c%c\n",
+		PB.driverGestaltSelector >> 24,
+		(PB.driverGestaltSelector >> 16) & 0xff,
+		(PB.driverGestaltSelector >>  8) & 0xff,
+		(PB.driverGestaltSelector      ) & 0xff);	
 	switch( PB.driverGestaltSelector ) {
 	case kdgSync:
 		PB.driverGestaltResponse = FALSE;	/* We handle asynchronous I/O */
diff --git a/QemuVGADriver/src/DriverQDCalls.c b/QemuVGADriver/src/DriverQDCalls.c
old mode 100644
new mode 100755
index 2383643..f33a76e
--- a/QemuVGADriver/src/DriverQDCalls.c
+++ b/QemuVGADriver/src/DriverQDCalls.c
@@ -3,10 +3,60 @@
 #include "DriverQDCalls.h"
 #include "QemuVga.h"
 
-static OSStatus		GraphicsCoreDoSetEntries(VDSetEntryRecord *entryRecord, Boolean directDevice, UInt32 start, UInt32 stop, Boolean useValue);
+#define MAX_DEPTH_MODE	kDepthMode3
+
+static UInt8 DepthToDepthMode(UInt8 depth)
+{
+	switch (depth) {
+	case 8:
+		return kDepthMode1;
+	case 15:
+	case 16:
+		return kDepthMode2;
+	case 24:
+	case 32:
+		return kDepthMode3;
+	default:
+		return kDepthMode1;
+	}
+}
+
+static UInt8 DepthModeToDepth(UInt8 mode)
+{
+	switch (mode) {
+	case kDepthMode1:
+		return 32;
+	case kDepthMode2:
+		return 15;
+	case kDepthMode3:
+		return 32;
+	default:
+		return 8;
+	}
+}
 
 /************************ Color Table Stuff ****************************/
 
+static OSStatus
+GraphicsCoreDoSetEntries(VDSetEntryRecord *entryRecord, Boolean directDevice, UInt32 start, UInt32 stop, Boolean useValue)
+{
+	UInt32 i;
+	
+	CHECK_OPEN( controlErr );
+	if (GLOBAL.depth != 8)
+		return controlErr;
+	if (NULL == entryRecord->csTable)
+		return controlErr;
+	
+	/* Note that stop value is included in the range */
+	for(i=start;i<=stop;i++) {
+		UInt32	colorIndex = useValue ? entryRecord->csTable[i].value : i;
+		QemuVga_SetColorEntry(colorIndex, &entryRecord->csTable[i].rgb);
+	}
+	
+	return noErr;
+}
+
 OSStatus
 GraphicsCoreSetEntries(VDSetEntryRecord *entryRecord)
 {
@@ -32,29 +82,6 @@
 }
 
 OSStatus
-GraphicsCoreDoSetEntries(VDSetEntryRecord *entryRecord, Boolean directDevice, UInt32 start, UInt32 stop, Boolean useValue)
-{
-	UInt32 i;
-	
-	CHECK_OPEN( controlErr );
-	if (GLOBAL.depth != 8)
-		return controlErr;
-	if (NULL == entryRecord->csTable)
-		return controlErr;
-//	if (directDevice != (VMODE.depth != 8))
-//		return controlErr;
-	
-	/* Note that stop value is included in the range */
-	for(i=start;i<=stop;i++) {
-		UInt32	tabIndex = i-start;
-		UInt32	colorIndex = useValue ? entryRecord->csTable[tabIndex].value : tabIndex;
-		QemuVga_SetColorEntry(colorIndex, &entryRecord->csTable[tabIndex].rgb);
-	}
-	
-	return noErr;
-}
-
-OSStatus
 GraphicsCoreGetEntries(VDSetEntryRecord *entryRecord)
 {
 	Boolean useValue	= (entryRecord->csStart < 0);
@@ -64,10 +91,11 @@
 	
 	Trace(GraphicsCoreGetEntries);
 
+	if (GLOBAL.depth != 8)
+		return controlErr;
 	for(i=start;i<=stop;i++) {
-		UInt32	tabIndex = i-start;
-		UInt32	colorIndex = useValue ? entryRecord->csTable[tabIndex].value : tabIndex;
-		QemuVga_GetColorEntry(colorIndex, &entryRecord->csTable[tabIndex].rgb);
+		UInt32	colorIndex = useValue ? entryRecord->csTable[i].value : i;
+		QemuVga_GetColorEntry(colorIndex, &entryRecord->csTable[i].rgb);
 	}
 
 	return noErr;
@@ -117,13 +145,17 @@
 OSStatus
 GraphicsCoreGrayPage(VDPageInfo *pageInfo)
 {
+	UInt32 pageCount;
+
 	CHECK_OPEN( controlErr );
 		
 	Trace(GraphicsCoreGrayPage);
 
-	if (pageInfo->csPage != 0)
+	QemuVga_GetModePages(GLOBAL.curMode, GLOBAL.depth, NULL, &pageCount);
+	if (pageInfo->csPage >= pageCount)
 		return paramErr;
-		
+	
+	/* XXX Make it gray ! */
 	return noErr;
 }
 			
@@ -142,12 +174,16 @@
 OSStatus
 GraphicsCoreGetPages(VDPageInfo *pageInfo)
 {
-/*	DepthMode mode; */
+	UInt32 pageCount, depth;
+
 	CHECK_OPEN( statusErr );
 
 	Trace(GraphicsCoreGetPages);
 
-	pageInfo->csPage = 1;
+	depth = DepthModeToDepth(pageInfo->csMode);
+	QemuVga_GetModePages(GLOBAL.curMode, depth, NULL, &pageCount);
+	pageInfo->csPage = pageCount;
+
 	return noErr;
 }
 
@@ -233,79 +269,22 @@
 	return noErr;
 }
 
-/* assume initial state is always "power-on" */
-// XXX FIXME
-static unsigned long MOLVideoPowerState = kAVPowerOn;
-
 OSStatus
 GraphicsCoreSetSync(VDSyncInfoRec *syncInfo)
 {
-	unsigned char syncmask;
-	unsigned long newpowermode;
-
 	Trace(GraphicsCoreSetSync);
 
 	CHECK_OPEN( controlErr );
 
-	syncmask = (!syncInfo->csFlags)? kDPMSSyncMask: syncInfo->csFlags;
-	if (!(syncmask & kDPMSSyncMask)) /* nothing to do */
-		return noErr;
-	switch (syncInfo->csMode & syncmask) {
-	case kDPMSSyncOn:
-		newpowermode = kAVPowerOn;
-		break;
-	case kDPMSSyncStandby:
-		newpowermode = kAVPowerStandby;
-		break;
-	case kDPMSSyncSuspend:
-		newpowermode = kAVPowerSuspend;
-		break;
-	case kDPMSSyncOff:
-		newpowermode = kAVPowerOff;
-		break;
-	default:
-		return paramErr;
-	}
-	if (newpowermode != MOLVideoPowerState) {
-		//OSI_SetVPowerState(newpowermode);
-		MOLVideoPowerState = newpowermode;
-	}
-
-	return noErr;
+	return paramErr;
 }
 
 OSStatus
 GraphicsCoreGetSync(VDSyncInfoRec *syncInfo)
 {
-	CHECK_OPEN( statusErr );
-		
 	Trace(GraphicsCoreGetSync);
 
-	if (syncInfo->csMode == 0xff) {
-		/* report back the capability */
-		syncInfo->csMode = 0 | ( 1 << kDisableHorizontalSyncBit)
-							 | ( 1 << kDisableVerticalSyncBit)
-							 | ( 1 << kDisableCompositeSyncBit);
-	} else if (syncInfo->csMode == 0) {
-		/* current sync mode */
-		switch (MOLVideoPowerState) {
-		case kAVPowerOn:
-			syncInfo->csMode = kDPMSSyncOn;
-			break;
-		case kAVPowerStandby:
-			syncInfo->csMode = kDPMSSyncStandby;
-			break;
-		case kAVPowerSuspend:
-			syncInfo->csMode = kDPMSSyncSuspend;
-			break;
-		case kAVPowerOff:
-			syncInfo->csMode = kDPMSSyncOff;
-			break;
-		}
-	} else /* not defined ? */
-		return paramErr;
-
-	return noErr;
+	return paramErr;
 }
 
 OSStatus
@@ -313,18 +292,7 @@
 {
 	Trace(GraphicsCoreSetPowerState);
 
-	CHECK_OPEN( controlErr );
-
-	if (powerStateRec->powerState > kAVPowerOn)
-		return paramErr;
-		
-	if (MOLVideoPowerState != powerStateRec->powerState) {
-		//OSI_SetVPowerState(powerStateRec->powerState);
-		MOLVideoPowerState = powerStateRec->powerState;
-	}
-	powerStateRec->powerFlags = 0;
-
-	return noErr;
+	return paramErr;
 }
 
 OSStatus
@@ -332,11 +300,7 @@
 {
 	Trace(GraphicsCoreGetPowerState);
 
-	CHECK_OPEN( statusErr );
-		
-	powerStateRec->powerState = MOLVideoPowerState;
-	powerStateRec->powerFlags = 0;
-	return noErr;
+	return paramErr;
 }
 		
 OSStatus
@@ -349,30 +313,6 @@
 	return noErr;
 }
 
-static UInt8 DepthToDepthMode(UInt8 depth)
-{
-	switch (depth) {
-	case 8:
-		return kDepthMode1;
-	case 15:
-	case 16:
-		return kDepthMode2;
-	default:
-		return kDepthMode3;
-	}
-}
-
-static UInt8 DepthModeToDepth(UInt8 mode)
-{
-	switch (mode) {
-	case kDepthMode1:
-		return 8;
-	case kDepthMode2:
-		return 15;
-	default:
-		return 32;
-	}
-}
 
 OSStatus
 GraphicsCoreGetPreferredConfiguration(VDSwitchInfoRec *switchInfo)
@@ -394,14 +334,18 @@
 OSStatus
 GraphicsCoreGetBaseAddress(VDPageInfo *pageInfo)
 {
+	UInt32 pageCount, pageSize;
+
 	Trace(GraphicsCoreGetBaseAddress);
 
 	CHECK_OPEN( statusErr );
 
-	if (pageInfo->csPage != 0)
+	QemuVga_GetModePages(GLOBAL.curMode, GLOBAL.depth, &pageSize, &pageCount);
+	if (pageInfo->csPage >= pageCount)
 		return paramErr;
 		
-	pageInfo->csBaseAddr = FB_START;
+	pageInfo->csBaseAddr = FB_START + pageInfo->csPage * pageSize;
+
 	return noErr;
 }
 			
@@ -431,11 +375,10 @@
 
 	CHECK_OPEN( statusErr );
 	
-	//lprintf("GetMode\n");
 	pageInfo->csMode		= DepthToDepthMode(GLOBAL.depth);
-	pageInfo->csPage		= 0;
-	pageInfo->csBaseAddr	= FB_START;
-	
+	pageInfo->csPage		= GLOBAL.curPage;
+	pageInfo->csBaseAddr	= GLOBAL.curBaseAddress;
+
 	return noErr;
 }
 
@@ -449,8 +392,8 @@
 	//lprintf("GetCurrentMode\n");
 	switchInfo->csMode		= DepthToDepthMode(GLOBAL.depth);
 	switchInfo->csData		= GLOBAL.curMode + 1;
-	switchInfo->csPage		= 0;
-	switchInfo->csBaseAddr	= FB_START;
+	switchInfo->csPage		= GLOBAL.curPage;
+	switchInfo->csBaseAddr	= GLOBAL.curBaseAddress;
 
 	return noErr;
 }
@@ -480,15 +423,25 @@
 OSStatus
 GraphicsCoreSetMode(VDPageInfo *pageInfo)
 {
+	UInt32 newDepth, newPage, pageCount;
+
 	Trace(GraphicsCoreSetMode);
 
 	CHECK_OPEN(controlErr);
 
-	if (pageInfo->csPage != 0)
+	newDepth = DepthModeToDepth(pageInfo->csMode);
+	newPage = pageInfo->csPage;
+	QemuVga_GetModePages(GLOBAL.curMode, newDepth, NULL, &pageCount);
+
+	lprintf("Requested depth=%d page=%d\n", newDepth, newPage);
+	if (pageInfo->csPage >= pageCount)
 		return paramErr;
 	
-	QemuVga_SetMode(GLOBAL.curMode, DepthModeToDepth(pageInfo->csMode));
-	pageInfo->csBaseAddr = FB_START;
+	if (newDepth != GLOBAL.depth || newPage != GLOBAL.curPage)
+		QemuVga_SetMode(GLOBAL.curMode, newDepth, newPage);
+	
+	pageInfo->csBaseAddr = GLOBAL.curBaseAddress;
+	lprintf("Returning BA: %lx\n", pageInfo->csBaseAddr);
 
 	return noErr;
 }			
@@ -497,23 +450,26 @@
 OSStatus
 GraphicsCoreSwitchMode(VDSwitchInfoRec *switchInfo)
 {
-	UInt32 newMode, newDepth;
+	UInt32 newMode, newDepth, newPage, pageCount;
 
 	Trace(GraphicsCoreSwitchMode);
 
 	CHECK_OPEN(controlErr);
-
-	if (switchInfo->csPage != 0)
-		return paramErr;
 	
 	newMode = switchInfo->csData - 1;
 	newDepth = DepthModeToDepth(switchInfo->csMode);
-	
-	if (newMode != GLOBAL.curMode || newDepth != GLOBAL.depth) {
-		if (QemuVga_SetMode(newMode, newDepth))
+	newPage = switchInfo->csPage;
+	QemuVga_GetModePages(GLOBAL.curMode, newDepth, NULL, &pageCount);
+
+	if (newPage >= pageCount)
+		return paramErr;
+
+	if (newMode != GLOBAL.curMode || newDepth != GLOBAL.depth ||
+	    newPage != GLOBAL.curPage) {
+		if (QemuVga_SetMode(newMode, newDepth, newPage))
 			return controlErr;
 	}
-	switchInfo->csBaseAddr = FB_START;
+	switchInfo->csBaseAddr = GLOBAL.curBaseAddress;
 
 	return noErr;
 }
@@ -548,7 +504,7 @@
 	resInfo->csHorizontalPixels	= width;
 	resInfo->csVerticalLines	= height;
 	resInfo->csRefreshRate		= 60;
-	resInfo->csMaxDepthMode		= kDepthMode3; /* XXX Calculate if it fits ! */
+	resInfo->csMaxDepthMode		= MAX_DEPTH_MODE; /* XXX Calculate if it fits ! */
 
 	return noErr;
 }
@@ -557,29 +513,26 @@
 OSStatus
 GraphicsCoreGetVideoParams(VDVideoParametersInfoRec *videoParams)
 {
-	UInt32 width, height, depth;
+	UInt32 width, height, depth, rowBytes, pageCount;
 	OSStatus err = noErr;
 	
 	Trace(GraphicsCoreGetVideoParams);
 
 	CHECK_OPEN(statusErr);
-
-	//lprintf("GetVideoParams(ID=%d, depthMode=%d)\n",
-	//	videoParams->csDisplayModeID,
-	//	videoParams->csDepthMode);
  		
 	if (videoParams->csDisplayModeID < 1 || videoParams->csDisplayModeID > GLOBAL.numModes)
 		return paramErr;
-
+	if (videoParams->csDepthMode > MAX_DEPTH_MODE)
+		return paramErr;
 	if (QemuVga_GetModeInfo(videoParams->csDisplayModeID - 1, &width, &height))
 		return paramErr;
-
-	videoParams->csPageCount	= 1;
 	
 	depth = DepthModeToDepth(videoParams->csDepthMode);
-
-	//lprintf(" -> width=%d, height=%d, depth=%d\n", width, height, depth);
+	QemuVga_GetModePages(videoParams->csDisplayModeID - 1, depth, NULL, &pageCount);
+	videoParams->csPageCount = pageCount;
+	lprintf("Video Params says %d pages\n", pageCount);
 	
+	rowBytes = width * ((depth + 7) / 8);
 	(videoParams->csVPBlockPtr)->vpBaseOffset 		= 0;			// For us, it's always 0
 	(videoParams->csVPBlockPtr)->vpBounds.top 		= 0;			// Always 0
 	(videoParams->csVPBlockPtr)->vpBounds.left 		= 0;			// Always 0
@@ -589,10 +542,9 @@
 	(videoParams->csVPBlockPtr)->vpHRes 			= 0x00480000;	// Hard coded to 72 dpi
 	(videoParams->csVPBlockPtr)->vpVRes 			= 0x00480000;	// Hard coded to 72 dpi
 	(videoParams->csVPBlockPtr)->vpPlaneBytes 		= 0;			// Always 0
-
 	(videoParams->csVPBlockPtr)->vpBounds.bottom	= height;
 	(videoParams->csVPBlockPtr)->vpBounds.right		= width;
-	(videoParams->csVPBlockPtr)->vpRowBytes			= width * ((depth + 7) / 8);
+	(videoParams->csVPBlockPtr)->vpRowBytes			= rowBytes;
 
 	switch (depth) {
 	case 8:
diff --git a/QemuVGADriver/src/QemuVga.c b/QemuVGADriver/src/QemuVga.c
index 8c996a7..a208ae0 100644
--- a/QemuVGADriver/src/QemuVga.c
+++ b/QemuVGADriver/src/QemuVga.c
@@ -2,6 +2,7 @@
 #include "VideoDriverPrototypes.h"
 #include "DriverQDCalls.h"
 #include "QemuVga.h"
+#include <Timer.h>
 
 /* List of supported modes */
 struct vMode {
@@ -77,11 +78,82 @@
 	return val;
 }
 
+static OSStatus VBLTimerProc(void *p1, void *p2);
+
+#ifndef USE_DSL_TIMER
+static TMTask gLegacyTimer;
+
+static pascal void legacyTimerCB(TMTaskPtr *inTask)
+{
+	VBLTimerProc(NULL, NULL);
+}
+
+static const RoutineDescriptor	gLegacyTimerDesc	= BUILD_ROUTINE_DESCRIPTOR(uppTimerProcInfo, legacyTimerCB);
+static const TimerUPP			gLegacyTimerProc	= (TimerUPP) &gLegacyTimerDesc;
+static int gTimerInstalled;
+
+static OSStatus ScheduleVBLTimer(void)
+{
+	if (!gTimerInstalled) {
+		BlockZero(&gLegacyTimer, sizeof(gLegacyTimer));
+		gLegacyTimer.tmAddr = gLegacyTimerProc;
+		gLegacyTimer.qLink = (QElemPtr)'eada';
+		InsXTime((QElemPtr)&gLegacyTimer);
+		gTimerInstalled = true;
+	}
+	PrimeTime((QElemPtr)&gLegacyTimer, TIMER_DURATION);
+	return noErr;
+}
+
+#else
+
+static OSStatus ScheduleVBLTimer(void)
+{
+	AbsoluteTime target = AddDurationToAbsolute(TIMER_DURATION, UpTime());
+	return SetInterruptTimer(&target, VBLTimerProc, NULL, &GLOBAL.VBLTimerID);
+}
+
+#endif
+
+static OSStatus VBLTimerProc(void *p1, void *p2)
+{
+	static UInt32 VBcnt;
+
+	GLOBAL.inInterrupt = 1;
+
+	/* This can be called before the service is ready */
+	if (GLOBAL.qdVBLInterrupt && GLOBAL.qdInterruptsEnable)
+		VSLDoInterruptService(GLOBAL.qdVBLInterrupt);
+	
+	/* Reschedule */
+	ScheduleVBLTimer();
+
+	GLOBAL.inInterrupt = 0;
+}
+
+#ifdef USE_PCI_IRQ
+static InterruptMemberNumber PCIInterruptHandler(InterruptSetMember ISTmember,
+												 void *refCon, UInt32 theIntCount)
+{
+	UInt32 reg;
+	
+	reg = ExtReadL(2);
+	if (!(reg & 1))
+		return kIsrIsNotComplete;
+	if (GLOBAL.qdVBLInterrupt && GLOBAL.qdInterruptsEnable)
+		VSLDoInterruptService(GLOBAL.qdVBLInterrupt);
+	ExtWriteL(2, 3);
+	return kIsrIsComplete;
+}
+#endif
+
+
 OSStatus QemuVga_Init(void)
 {
 	UInt16 id, i;
 	UInt32 mem, width, height, depth;
 
+	lprintf("First MMIO read...\n");
 	id = DispiReadW(VBE_DISPI_INDEX_ID);
 	mem = DispiReadW(VBE_DISPI_INDEX_VIDEO_MEMORY_64K);
 	mem <<= 16;
@@ -110,58 +182,51 @@
 		lprintf("Not found in list ! using default.\n");
 		i = 0;
 	}
-	GLOBAL.curMode = GLOBAL.bootMode = i;
+	GLOBAL.bootMode = i;
 	GLOBAL.numModes = sizeof(vModes) / sizeof(struct vMode) - 1;
 
+	QemuVga_SetMode(GLOBAL.bootMode, depth, 0);
+
+#ifdef USE_PCI_IRQ
+	if (SetupPCIInterrupt(&GLOBAL.deviceEntry, &GLOBAL.irqInfo,
+					   	  PCIInterruptHandler, NULL) == noErr)
+		GLOBAL.hasPCIInterrupt = true;
+	else
+#else
+	GLOBAL.hasPCIInterrupt = false;
+#endif
 	return noErr;
 }
 
-static OSStatus VBLTimerProc(void *p1, void *p2);
-
-static OSStatus ScheduleVBLTimer(void)
-{
-    /* XXX HACK: Run timer at 20Hz */
-	AbsoluteTime target = AddDurationToAbsolute(50, UpTime());
-	
-	return SetInterruptTimer(&target, VBLTimerProc, NULL, &GLOBAL.VBLTimerID);
-}
-
-static OSStatus VBLTimerProc(void *p1, void *p2)
-{
-	GLOBAL.inInterrupt = 1;
-
-	/* This can be called before the service is ready */
-	if (GLOBAL.qdVBLInterrupt && GLOBAL.qdInterruptsEnable)
-		VSLDoInterruptService(GLOBAL.qdVBLInterrupt);
-	
-	/* Reschedule */
-	ScheduleVBLTimer();
-
-	GLOBAL.inInterrupt = 0;
-}
-
 OSStatus QemuVga_Open(void)
 {
 	lprintf("QemuVga v1.00\n");
 
 	GLOBAL.isOpen = true;
 
-	/* Schedule the timer now if timers are supported. They aren't on OS X
-	 * in which case we must not create the VSL service, otherwise OS X will expect
-	 * a VBL and fail to update the cursor when not getting one.
-	 */
-	GLOBAL.hasTimer = (ScheduleVBLTimer() == noErr);
-	GLOBAL.qdInterruptsEnable = GLOBAL.hasTimer;
+	if (GLOBAL.hasPCIInterrupt) {
+		QemuVga_EnableInterrupts();
+		lprintf("VBL registered using PCI interrupts\n");	
+	} else {
+		/* Schedule the timer now if timers are supported. They aren't on OS X
+		 * in which case we must not create the VSL service, otherwise OS X will expect
+		 * a VBL and fail to update the cursor when not getting one.
+	 	*/
+		lprintf("Testing using timer to simulate VBL..\n");	
+		GLOBAL.hasTimer = (ScheduleVBLTimer() == noErr);
+		GLOBAL.qdInterruptsEnable = GLOBAL.hasTimer;
 
-	/* Create VBL if timer works */
-	if (GLOBAL.hasTimer && !GLOBAL.qdVBLInterrupt)
+		if (GLOBAL.hasTimer)
+			lprintf("Using timer to simulate VBL.\n");	
+		else
+			lprintf("No timer service (OS X ?), VBL not registered.\n");	
+
+	}
+
+	/* Create VBL if we have a PCI interrupt or timer works */
+	if (GLOBAL.hasPCIInterrupt || GLOBAL.hasTimer)
 		VSLNewInterruptService(&GLOBAL.deviceEntry, kVBLInterruptServiceType, &GLOBAL.qdVBLInterrupt);
 	
-	if (GLOBAL.hasTimer)
-		lprintf("Using timer to simulate VBL.\n");	
-	else
-		lprintf("No timer service (OS X ?), VBL not registered.\n");	
-
 	return noErr;
 }
 
@@ -190,7 +255,11 @@
 {
 	GLOBAL.qdInterruptsEnable = true;
 	if (GLOBAL.hasTimer)
-		ScheduleVBLTimer();	
+		ScheduleVBLTimer();
+	else if (GLOBAL.hasPCIInterrupt) {
+		GLOBAL.irqInfo.enableFunction(GLOBAL.irqInfo.interruptSetMember, GLOBAL.irqInfo.refCon);
+		ExtWriteL(2, 3);
+	}
 }
 
 void QemuVga_DisableInterrupts(void)
@@ -200,6 +269,10 @@
 	GLOBAL.qdInterruptsEnable = false;
 	if (GLOBAL.hasTimer)
 		CancelTimer(GLOBAL.VBLTimerID, &remaining);
+	else if (GLOBAL.hasPCIInterrupt) {
+		ExtWriteL(2, 1);
+		GLOBAL.irqInfo.disableFunction(GLOBAL.irqInfo.interruptSetMember, GLOBAL.irqInfo.refCon);
+	}
 }
 
 OSStatus QemuVga_SetColorEntry(UInt32 index, RGBColor *color)
@@ -238,17 +311,41 @@
 	return noErr;
 }
 
+OSStatus QemuVga_GetModePages(UInt32 index, UInt32 depth,
+							  UInt32 *pageSize, UInt32 *pageCount)
+{
+	UInt32 width, height, pBytes;
 
-OSStatus QemuVga_SetMode(UInt32 mode, UInt32 depth)
+	if (index >= GLOBAL.numModes)
+		return paramErr;
+	width = vModes[index].width;
+	height = vModes[index].height;
+	pBytes = width * ((depth + 7) / 8) * height;
+	if (pageSize)
+		*pageSize = pBytes;
+	if (pageCount) {
+		if (pBytes <= (GLOBAL.boardFBMappedSize / 2))
+			*pageCount = 2;
+		else
+			*pageCount = 1;
+	}
+	return noErr;
+}
+
+OSStatus QemuVga_SetMode(UInt32 mode, UInt32 depth, UInt32 page)
 {
 	UInt32 width, height;
+	UInt32 pageSize, numPages;
 
 	if (mode >= GLOBAL.numModes)
 		return paramErr;
+	
 	width = vModes[mode].width;
 	height = vModes[mode].height;
-
-	lprintf("Set Mode: %dx%dx%d\n", width, height, depth);
+	QemuVga_GetModePages(mode, depth, &pageSize, &numPages);
+	lprintf("Set Mode: %dx%dx%d has %d pages\n", width, height, depth, numPages);
+	if (page >= numPages)
+		return paramErr;
 
 	DispiWriteW(VBE_DISPI_INDEX_ENABLE,      0);
 	DispiWriteW(VBE_DISPI_INDEX_BPP,         depth);
@@ -256,12 +353,14 @@
 	DispiWriteW(VBE_DISPI_INDEX_YRES,        height);
 	DispiWriteW(VBE_DISPI_INDEX_BANK,        0);
 	DispiWriteW(VBE_DISPI_INDEX_VIRT_WIDTH,  width);
-	DispiWriteW(VBE_DISPI_INDEX_VIRT_HEIGHT, height);
+	DispiWriteW(VBE_DISPI_INDEX_VIRT_HEIGHT, height * numPages);
 	DispiWriteW(VBE_DISPI_INDEX_X_OFFSET,    0);
-	DispiWriteW(VBE_DISPI_INDEX_Y_OFFSET,    0);
+	DispiWriteW(VBE_DISPI_INDEX_Y_OFFSET,    height * page);
 	DispiWriteW(VBE_DISPI_INDEX_ENABLE,      VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED | VBE_DISPI_8BIT_DAC);	
 	GLOBAL.curMode = mode;
 	GLOBAL.depth = depth;
+	GLOBAL.curPage = page;
+	GLOBAL.curBaseAddress = FB_START + page * pageSize;
 	
 	return noErr;
 }
diff --git a/QemuVGADriver/src/QemuVga.h b/QemuVGADriver/src/QemuVga.h
old mode 100644
new mode 100755
index e401ef3..d7bf053
--- a/QemuVGADriver/src/QemuVga.h
+++ b/QemuVGADriver/src/QemuVga.h
@@ -1,6 +1,19 @@
 #ifndef __QEMU_VGA_H__
 #define __QEMU_VGA_H__
 
+/* This must be enabled for the MacOS X version of the timer otherwise
+ * we don't know if the call failed and don't back off to non-VBL ops
+ */
+#define USE_DSL_TIMER
+
+/* Pseudo VBL timer duration in ms */
+#define TIMER_DURATION	30
+
+/* Enable use of the PCI IRQ as VBL using non-upstream QEMU VGA
+ * extensions
+ */
+#undef USE_PCI_IRQ
+
 /* --- Qemu/Bochs special registers --- */
 
 #define VBE_DISPI_IOPORT_INDEX           0x01CE
@@ -48,7 +61,9 @@
 extern OSStatus	QemuVga_SetColorEntry(UInt32 index, RGBColor *color);
 extern OSStatus	QemuVga_GetColorEntry(UInt32 index, RGBColor *color);
 
+extern OSStatus QemuVga_GetModePages(UInt32 index, UInt32 depth,
+									 UInt32 *pageSize, UInt32 *pageCount);
 extern OSStatus QemuVga_GetModeInfo(UInt32 index, UInt32 *width, UInt32 *height);
-extern OSStatus QemuVga_SetMode(UInt32 modeIndex, UInt32 depth);
+extern OSStatus QemuVga_SetMode(UInt32 modeIndex, UInt32 depth, UInt32 page);
 
 #endif
diff --git a/QemuVGADriver/src/VideoDriverPrivate.h b/QemuVGADriver/src/VideoDriverPrivate.h
old mode 100644
new mode 100755
index cd4cdba..65c161c
--- a/QemuVGADriver/src/VideoDriverPrivate.h
+++ b/QemuVGADriver/src/VideoDriverPrivate.h
@@ -10,7 +10,7 @@
 #include <DriverServices.h>
 #include <PCI.h>
 
-#pragma internal on
+#include "MacDriverUtils.h"
 
 #ifndef FALSE
 #define TRUE	1
@@ -19,8 +19,8 @@
 
 #define QEMU_PCI_VIDEO_VENDOR_ID		0x1234
 #define QEMU_PCI_VIDEO_DEVICE_ID		0x1111
-#define QEMU_PCI_VIDEO_NAME				"\pQemuVgaVideo"
-#define QEMU_PCI_VIDEO_PNAME			"\p.QemuVgaVideo"
+#define QEMU_PCI_VIDEO_NAME				"\pQEMU,VGA"
+#define QEMU_PCI_VIDEO_PNAME			"\p.Display_Video_QemuVGA"
 
 #define QEMU_PCI_VIDEO_BASE_REG			0x10
 #define QEMU_PCI_VIDEO_MMIO_REG			0x18
@@ -51,6 +51,9 @@
 	Boolean				qdInterruptsEnable;	/* Enable VBLs for qd */
 	Boolean				qdLuminanceMapping;
 
+	Boolean				hasPCIInterrupt;
+	IRQInfo				irqInfo;
+
 	Boolean				hasTimer;
 	InterruptServiceIDType	qdVBLInterrupt;
 	TimerID				VBLTimerID;
@@ -63,6 +66,8 @@
 	UInt32				bootMode;
 	UInt32				curMode;
 	UInt32				numModes;
+	UInt32				curPage;
+	LogicalAddress		curBaseAddress;
 };
 typedef struct DriverGlobal DriverGlobal, *DriverGlobalPtr;
 
diff --git a/QemuVGADriver/src/VideoDriverPrototypes.h b/QemuVGADriver/src/VideoDriverPrototypes.h
old mode 100644
new mode 100755
index b4d6c6f..682671a
--- a/QemuVGADriver/src/VideoDriverPrototypes.h
+++ b/QemuVGADriver/src/VideoDriverPrototypes.h
@@ -7,7 +7,6 @@
 /*
  * The Driver Manager calls DoDriverIO to perform I/O.
  */
-#pragma internal off
 
 OSStatus
 DoDriverIO(	AddressSpaceID			addressSpaceID,
@@ -16,8 +15,6 @@
 		IOCommandCode			ioCommandCode,
 		IOCommandKind			ioCommandKind);
 
-#pragma internal on
-
 #include "MacDriverUtils.h"
 
 /*
@@ -80,8 +77,6 @@
 DriverGestaltHandler(	CntrlParam*			pb);
 
 
-#pragma internal on
-
 /*	.___________________________________________________________________________________.
   	| Utitlity function to clear a block of memory.										|
 	.___________________________________________________________________________________.
diff --git a/builds/qemu_vga.ndrv b/builds/qemu_vga.ndrv
index 0b1549d..930e9c2 100644
--- a/builds/qemu_vga.ndrv
+++ b/builds/qemu_vga.ndrv
Binary files differ
diff --git a/builds/qemu_vga_debugosi.ndrv b/builds/qemu_vga_debugosi.ndrv
index 148add7..3b86f5a 100644
--- a/builds/qemu_vga_debugosi.ndrv
+++ b/builds/qemu_vga_debugosi.ndrv
Binary files differ
diff --git a/shared/MacDriverUtils.c b/shared/MacDriverUtils.c
index 19d323a..3537dad 100644
--- a/shared/MacDriverUtils.c
+++ b/shared/MacDriverUtils.c
Binary files differ
diff --git a/shared/MacDriverUtils.h b/shared/MacDriverUtils.h
index a9ad4c2..d93429a 100644
--- a/shared/MacDriverUtils.h
+++ b/shared/MacDriverUtils.h
Binary files differ
diff --git a/shared/vsprintf.c b/shared/vsprintf.c
old mode 100644
new mode 100755
index 0df7b34..b8eae5c
--- a/shared/vsprintf.c
+++ b/shared/vsprintf.c
@@ -326,7 +326,9 @@
 	vsprintf(buf, fmt, args);
 	va_end(args);
 
-	OSI_PutC( '+' );
+	OSI_PutC( '*' );
+	OSI_PutC( '*' );
+	OSI_PutC( '*' );
 	OSI_PutC( ' ' );
 	for( p=buf; *p; p++ )
 		OSI_PutC( *p );