diff options
Diffstat (limited to 'QemuVGADriver/src')
-rw-r--r-- | QemuVGADriver/src/DriverDoDriverIO.c | 603 | ||||
-rw-r--r-- | QemuVGADriver/src/DriverGestaltHandler.c | 45 | ||||
-rw-r--r-- | QemuVGADriver/src/DriverQDCalls.c | 629 | ||||
-rw-r--r-- | QemuVGADriver/src/DriverQDCalls.h | 42 | ||||
-rw-r--r-- | QemuVGADriver/src/QemuVga.c | 267 | ||||
-rw-r--r-- | QemuVGADriver/src/QemuVga.h | 54 | ||||
-rw-r--r-- | QemuVGADriver/src/VideoDriver.exp | 2 | ||||
-rw-r--r-- | QemuVGADriver/src/VideoDriverPrivate.h | 79 | ||||
-rw-r--r-- | QemuVGADriver/src/VideoDriverPrototypes.h | 105 |
9 files changed, 1826 insertions, 0 deletions
diff --git a/QemuVGADriver/src/DriverDoDriverIO.c b/QemuVGADriver/src/DriverDoDriverIO.c new file mode 100644 index 0000000..38f861a --- /dev/null +++ b/QemuVGADriver/src/DriverDoDriverIO.c @@ -0,0 +1,603 @@ +/* Simple PCI video driver for use with Mac-On-Linux emulator + * + * Basically, this driver forward Apple video driver calls to + * the emulator via a fake HW (and later, a "sc" based API). +*/ + +#include "VideoDriverPrivate.h" +#include "VideoDriverPrototypes.h" +#include "DriverQDCalls.h" +#include "QemuVga.h" + +DriverDescription TheDriverDescription = { + /* + * Signature info + */ + kTheDescriptionSignature, /* OSType driverDescSignature */ + kInitialDriverDescriptor, /* DriverDescVersion driverDescVersion */ + QEMU_PCI_VIDEO_NAME, + 0x01, 0x01, + 0, 0, + /* + * DriverOSRuntime driverOSRuntimeInfo + */ + 0 /* RuntimeOptions driverRuntime */ + | (0 * kDriverIsLoadedUponDiscovery) /* Loader runtime options */ + | (1 * kDriverIsOpenedUponLoad) /* Opened when loaded */ + | (1 * kDriverIsUnderExpertControl) /* I/O expert handles loads/opens */ + | (01 * 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] */ + /* + * DriverOSService Information. This section contains a vector count followed by + * a vector of structures, each defining a driver service. + */ + 1, /* ServiceCount nServices */ + /* + * DriverServiceInfo service[0] + */ + kServiceCategoryNdrvDriver, /* OSType serviceCategory */ + kNdrvTypeIsVideo, /* OSType serviceType */ + 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 + * environments, the global world is created by the Code Fragment Manager (hmm, + * perhaps it is created by CFMInitialize). + */ +DriverGlobal gDriverGlobal; + +/* + * DoDriverIO + * + * In the new driver environment, DoDriverIO performs all driver + * functions. It is called with the following parameters: + * IOCommandID A unique reference for this driver request. In + * the emulated environment, this will be the ParamBlkPtr + * passed in from the Device Manager. + * + * IOCommandContents A union structure that contains information for the + * specific request. For the emulated environment, this + * will contain the following: + * Initialize Driver RefNum and the name registry id for this driver. + * Finalize Driver RefNum and the name registry id for this driver. + * Others The ParamBlkPtr + * + * IOCommandCode A switch value that specifies the required function. + * + * IOCommandKind A bit-mask indicating Synchronous, Asynchronous, and Immediate + * + * For Synchronous and Immediate commands, DoDriverIO returns the final status to + * the Device Manager. For Asynchronous commands, DoDriverIO may return kIOBusyStatus. + * 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 ) +{ + OSStatus status; + + /* + * Note: Initialize, Open, KillIO, Close, and Finalize are either synchronous + * or immediate. Read, Write, Control, and Status may be immediate, + * synchronous, or asynchronous. + */ + + Trace(DoDriverIO); + + switch( ioCommandCode ) { + case kInitializeCommand: /* Always immediate */ + status = DriverInitializeCmd(addressSpaceID, ioCommandContents.initialInfo); + CheckStatus(status, "Initialize failed"); + break; + case kFinalizeCommand: /* Always immediate */ + status = DriverFinalizeCmd(ioCommandContents.finalInfo); + break; + case kSupersededCommand: + status = DriverSupersededCmd(ioCommandContents.supersededInfo, FALSE); + break; + case kReplaceCommand: /* replace an old driver */ + status = DriverReplaceCmd(addressSpaceID, ioCommandContents.replaceInfo); + break; + case kOpenCommand: /* Always immediate */ + status = DriverOpenCmd(addressSpaceID, ioCommandContents.pb); + break; + case kCloseCommand: /* Always immediate */ + status = DriverCloseCmd(ioCommandContents.pb); + break; + case kControlCommand: + /* lprintf("kControlCommand\n"); */ + status = DriverControlCmd( addressSpaceID, ioCommandID, ioCommandKind, + (CntrlParam*)ioCommandContents.pb ); + break; + case kStatusCommand: + /* lprintf("kStatusCommand\n"); */ + status = DriverStatusCmd( ioCommandID, ioCommandKind, + (CntrlParam *)ioCommandContents.pb ); + break; + case kReadCommand: + status = DriverReadCmd( addressSpaceID, ioCommandID, ioCommandKind, + ioCommandContents.pb ); + break; + case kWriteCommand: + status = DriverWriteCmd( addressSpaceID, ioCommandID, ioCommandKind, + ioCommandContents.pb); + break; + case kKillIOCommand: /* Always immediate */ + status = DriverKillIOCmd(ioCommandContents.pb); + break; + default: + status = paramErr; + break; + } + /* + * Force a valid result for immediate commands -- they must return a valid + * status to the Driver Manager: returning kIOBusyStatus would be a bug.. + * Non-immediate commands return a status from the lower-level routine. If the + * status is kIOBusyStatus, we just return -- an asynchronous I/O completion + * routine will eventually complete the request. If it's some other status, the + * lower-level routine has completed a non-immediate task, so we call + * IOCommandIsComplete and return its (presumably noErr) status. + */ + if( (ioCommandKind & kImmediateIOCommandKind) != 0 ) { + ; /* Immediate commands return the operation status */ + } + else if (status == ioInProgress) { + /* + * An asynchronous operation is in progress. The driver handler promises + * to call IOCommandIsComplete when the operation concludes. + */ + status = noErr; + } else { + /* + * Normal command that completed synchronously. Dequeue the user's + * parameter block. + */ + status = (OSStatus)IOCommandIsComplete(ioCommandID, (OSErr)status); + } + return status; +} + +#pragma internal on + +/* + * DriverInitializeCmd + * + * The New Driver Manager calls this when the driver is first opened. + */ +OSStatus +DriverInitializeCmd( AddressSpaceID addressSpaceID, DriverInitInfoPtr driverInitInfoPtr ) +{ + OSStatus status; + + Trace(DriverInitializeCmd); + + GLOBAL.refNum = driverInitInfoPtr->refNum; + GLOBAL.openCount = 0; + GLOBAL.inInterrupt = false; + GLOBAL.hasTimer = false; + + RegistryEntryIDInit( &GLOBAL.deviceEntry ); + status = RegistryEntryIDCopy( &driverInitInfoPtr->deviceEntry, &GLOBAL.deviceEntry ); + if( status != noErr ) + return status; + + GLOBAL.isOpen = false; + GLOBAL.qdInterruptsEnable = false; + GLOBAL.qdVBLInterrupt = NULL; + + GLOBAL.boardFBAddress = GetDeviceBARAddress(&GLOBAL.deviceEntry, + QEMU_PCI_VIDEO_BASE_REG, + &GLOBAL.boardFBMappedSize, + NULL); + if (GLOBAL.boardFBAddress == NULL) { + status = paramErr; + goto bail; + } + lprintf("boardFBAddress %08lX boardFBMappedSize %08lX\n", + GLOBAL.boardFBAddress, GLOBAL.boardFBMappedSize); + + GLOBAL.boardRegAddress = GetDeviceBARAddress(&GLOBAL.deviceEntry, + QEMU_PCI_VIDEO_MMIO_REG, + &GLOBAL.boardRegMappedSize, + NULL); + if (GLOBAL.boardRegAddress == NULL) { + status = paramErr; + goto bail; + } + lprintf("boardRegAddress %08lX boardRegMappedSize %08lX\n", + GLOBAL.boardRegAddress, GLOBAL.boardRegMappedSize); + + + status = EnablePCIMemorySpace(&GLOBAL.deviceEntry); + if (status != noErr) { + lprintf("EnablePCIMemorySpace returned %d\n", status); + goto bail; + } + + status = QemuVga_Init(); + +bail: + DBG(lprintf("Driver init result: %d\n", status)); + + return status; +} + +/* + * DriverReplaceCmd + * + * We are replacing an existing driver -- or are completing an initialization sequence. + * Retrieve any state information from the Name Registry (we have none), install + * our interrupt handlers, and activate the device. + * + * We don't use the calledFromInitialize parameter, but it's here so that a driver can + * distinguish between initialization (fetch only the NVRAM parameter) and replacement + * (fetch state information that may be left-over from the previous incantation). + */ +OSStatus +DriverReplaceCmd( AddressSpaceID addressSpaceID, DriverReplaceInfoPtr driverReplaceInfoPtr ) +{ + OSStatus status; + + Trace(DriverReplaceCmd); + + GLOBAL.refNum = driverReplaceInfoPtr->refNum; + GLOBAL.deviceEntry = driverReplaceInfoPtr->deviceEntry; + + status = DriverInitializeCmd(addressSpaceID, driverReplaceInfoPtr); + + return status; +} + +/* + * DriverFinalizeCmd + * + * Process a DoDriverIO finalize command. + */ +OSStatus +DriverFinalizeCmd( DriverFinalInfoPtr driverFinalInfoPtr ) +{ + Trace(DriverFinializeCmd); + (void) DriverSupersededCmd((DriverSupersededInfoPtr) driverFinalInfoPtr, TRUE); + return noErr; +} + +/* + * DriverSupersededCmd + * + * We are shutting down, or being replaced by a later driver. Wait for all I/O to + * complete and store volatile state in the Name Registry whree it will be retrieved + * by our replacement. + */ +OSStatus +DriverSupersededCmd( DriverSupersededInfoPtr driverSupersededInfoPtr, Boolean calledFromFinalize ) +{ + Trace(DriverSupersededCmd); + + /* + * This duplicates DriverKillIOCmd, the correct algorithm would wait for + * concurrent I/O to complete. Hmm, what about "infinite wait" I/O, such + * as would be posted by a modem server or socket listener? Note that + * this section needs to be extended to handle all pending requests. + * + * It's safe to call CompleteThisRequest, as that routine uses an atomic + * operation that allows it to be called when no request is pending without + * any possible problems. Since it's a secondary interrupt handler, we + * need to call it through the Driver Services Library. + * + * Warning: GLOBAL.perRequestDataPtr will be NULL if initialization fails + * and the Driver Manager tries to terminate us. When we permit concurrent + * requests, this will loop on all per-request records. + */ + + QemuVga_Exit(); + + RegistryEntryIDDispose( &GLOBAL.deviceEntry ); + + return noErr; +} + +/* + * DriverControlCmd + * + * Process a PBControl command. + */ +OSStatus +DriverControlCmd( AddressSpaceID addressSpaceID, IOCommandID ioCommandID, + IOCommandKind ioCommandKind, CntrlParam *pb ) +{ + OSStatus status; + void *genericPtr; + + /* The 'csParam' field of the 'CntrlParam' stucture is defined as 'short csParam[11]'. This is + * meant for 'operation defined parameters.' For the graphics driver, only the first 4 bytes are + * used. They are used as a pointer to another structure. + * To help code readability, the pointer will be extracted as a generic 'void *' and then cast as + * appropriate. + */ + + genericPtr = (void *) *((UInt32 *) &(pb->csParam[0])); + + Trace(DriverControlCmd); + + switch( pb->csCode ) { + case cscReset: // Old obsolete call..return a 'controlErr' + status = controlErr; + break; + + case cscKillIO: // Old obsolete call..do nothing + status = controlErr; + break; + + case cscSetMode: + status = GraphicsCoreSetMode((VDPageInfo *) genericPtr); + break; + + case cscSetEntries: + status = GraphicsCoreSetEntries((VDSetEntryRecord *) genericPtr); + // if ((status == noErr)&&(GLOBAL.qdDeskServiceCreated)&&(ioCommandKind == kSynchronousIOCommandKind)) + // VSLWaitOnInterruptService(GLOBAL.qdVBLInterrupt, 1000); + break; + + case cscSetGamma: + status = GraphicsCoreSetGamma((VDGammaRecord *) genericPtr); + break; + + case cscGrayPage: + status = GraphicsCoreGrayPage((VDPageInfo *) genericPtr); + break; + + case cscSetGray: + status = GraphicsCoreSetGray((VDGrayRecord *) genericPtr); + break; + + case cscSetInterrupt: + status = GraphicsCoreSetInterrupt((VDFlagRecord *) genericPtr); + break; + + case cscDirectSetEntries: + status = GraphicsCoreDirectSetEntries((VDSetEntryRecord *) genericPtr); + break; + + case cscSetDefaultMode: + status = controlErr; + break; + + case cscSwitchMode: + status = GraphicsCoreSwitchMode((VDSwitchInfoRec *) genericPtr); + break; + + case cscSetSync: + status = GraphicsCoreSetSync((VDSyncInfoRec *) genericPtr); + break; + + case cscSavePreferredConfiguration: + status = GraphicsCoreSetPreferredConfiguration((VDSwitchInfoRec *) genericPtr); + break; + + case cscSetHardwareCursor: + status = GraphicsCoreSetHardwareCursor((VDSetHardwareCursorRec *) genericPtr); + break; + + case cscDrawHardwareCursor: + status = GraphicsCoreDrawHardwareCursor((VDDrawHardwareCursorRec *) genericPtr); + break; + case cscSetPowerState: + status = GraphicsCoreSetPowerState((VDPowerStateRec *) genericPtr); + break; + default: + status = controlErr; + break; + } + if( status ) + status = controlErr; + + return status; +} + +/* + * DriverStatusCmd + * + * Process a PBStatus command. We support the driver gestalt call and our private + * debugging commands. + */ +OSStatus +DriverStatusCmd( IOCommandID ioCommandID, IOCommandKind ioCommandKind, CntrlParam *pb ) +{ + OSStatus status; + void *genericPtr; + + /* The 'csParam' field of the 'CntrlParam' stucture is defined as 'short csParam[11]'. This is + * meant for 'operation defined parameters.' For the graphics driver, only the first 4 bytes are + * used. They are used as a pointer to another structure. + * To help code readability, the pointer will be extracted as a generic 'void *' and then cast as + * appropriate. + */ + + genericPtr = (void *) *((UInt32 *) &(pb->csParam[0])); + + Trace(DriverStatusCmd); + + switch( pb->csCode ) { + case cscGetMode: + status = GraphicsCoreGetMode((VDPageInfo *) genericPtr); + break; + + case cscGetEntries: + status = GraphicsCoreGetEntries((VDSetEntryRecord *) genericPtr); + break; + + case cscGetPages: + status = GraphicsCoreGetPages((VDPageInfo *) genericPtr); + break; + + case cscGetBaseAddr: + status = GraphicsCoreGetBaseAddress((VDPageInfo *) genericPtr); + break; + + case cscGetGray: + status = GraphicsCoreGetGray((VDGrayRecord *) genericPtr); + break; + + case cscGetInterrupt: + status = GraphicsCoreGetInterrupt((VDFlagRecord *) genericPtr); + break; + + case cscGetGamma: + status = GraphicsCoreGetGamma((VDGammaRecord *) genericPtr); + break; + + case cscGetDefaultMode: + status = statusErr; + break; + + case cscGetCurMode: + status = GraphicsCoreGetCurrentMode((VDSwitchInfoRec *) genericPtr); + break; + + case cscGetSync: + status = GraphicsCoreGetSync((VDSyncInfoRec *) genericPtr); + break; + + case cscGetConnection: + status = GraphicsCoreGetConnection((VDDisplayConnectInfoRec *) genericPtr); + break; + + case cscGetModeTiming: + status = GraphicsCoreGetModeTiming((VDTimingInfoRec *) genericPtr); + break; + + case cscGetPreferredConfiguration: + status = GraphicsCoreGetPreferredConfiguration((VDSwitchInfoRec *) genericPtr); + break; + + case cscGetNextResolution: + status = GraphicsCoreGetNextResolution((VDResolutionInfoRec *) genericPtr); + break; + + case cscGetVideoParameters: + status = GraphicsCoreGetVideoParams((VDVideoParametersInfoRec *) genericPtr); + break; + + case cscGetGammaInfoList: + status = GraphicsCoreGetGammaInfoList((VDGetGammaListRec *) genericPtr); + break; + + case cscRetrieveGammaTable: + status = GraphicsCoreRetrieveGammaTable((VDRetrieveGammaRec *) genericPtr); + break; + + case cscSupportsHardwareCursor: + status = GraphicsCoreSupportsHardwareCursor((VDSupportsHardwareCursorRec *) genericPtr); + break; + + case cscGetHardwareCursorDrawState: + status = GraphicsCoreGetHardwareCursorDrawState((VDHardwareCursorDrawStateRec *) genericPtr); + break; + + case kDriverGestaltCode: + status = DriverGestaltHandler(pb); + break; + + case cscGetPowerState: + status = GraphicsCoreGetPowerState((VDPowerStateRec *) genericPtr); + break; + + default: + status = statusErr; + break; + } + if( status ) + status = statusErr; + + return status; +} + +/* + * DriverKillIOCmd stops all I/O for this chip. It's a big hammer, use it wisely. + * This will need revision when we support concurrent I/O as we must stop all + * pending requests. + */ +OSStatus +DriverKillIOCmd( ParmBlkPtr pb ) +{ +#define REQUEST (GLOBAL.perRequestData) + + Trace(DriverKillIOCmd); + return noErr; +#undef REQUEST +} + +/* + * DriverReadCmd + * + * The caller passes the data buffer and buffer length in the IOParam record and + * a pointer to a SCSI NCRSCSIParam in the ioMisc field. + */ +OSStatus +DriverReadCmd( AddressSpaceID addressSpaceID, IOCommandID ioCommandID, + IOCommandKind ioCommandKind, ParmBlkPtr pb ) +{ + Trace(DriverReadCmd); + return paramErr; +} + + +/* + * DriverWriteCmd + * + * The caller passes the data buffer and buffer length in the IOParam record and + * a pointer to a SCSI NCRSCSIParam in the ioMisc field. + */ +OSStatus +DriverWriteCmd( AddressSpaceID addressSpaceID, IOCommandID ioCommandID, + IOCommandKind ioCommandKind, ParmBlkPtr pb ) +{ + Trace(DriverWriteCmd); + return paramErr; +} + +/* + * DriverCloseCmd does nothing.. + */ +OSStatus +DriverCloseCmd( ParmBlkPtr pb ) +{ + Trace(DriverCloseCmd); + + if( !GLOBAL.openCount ) + return notOpenErr; + + GLOBAL.openCount--; + + if (!GLOBAL.openCount) + QemuVga_Close(); + + return noErr; +} + +/* + * DriverOpenCmd does nothing: remember that many applications will open a device, but + * never close it.. + */ +OSStatus +DriverOpenCmd( AddressSpaceID addressSpaceID, ParmBlkPtr pb ) +{ + Trace(DriverOpenCmd); + + GLOBAL.openCount++; + if (GLOBAL.openCount == 1) + QemuVga_Open(); + + return noErr; +} + + diff --git a/QemuVGADriver/src/DriverGestaltHandler.c b/QemuVGADriver/src/DriverGestaltHandler.c new file mode 100644 index 0000000..ca37874 --- /dev/null +++ b/QemuVGADriver/src/DriverGestaltHandler.c @@ -0,0 +1,45 @@ +#include "VideoDriverPrivate.h" +#include "VideoDriverPrototypes.h" + +/* + * Called on PBStatus, csCode = 43 + */ +OSStatus +DriverGestaltHandler( CntrlParam *pb ) +{ +#define PB (*((DriverGestaltParam *) pb)) +#define OPTIONS (TheDriverDescription.driverOSRuntimeInfo) + + OSStatus status; + Trace(DriverGestaltHandler); + + PB.driverGestaltResponse = 0; + status = noErr; + + switch( PB.driverGestaltSelector ) { + case kdgSync: + PB.driverGestaltResponse = FALSE; /* We handle asynchronous I/O */ + break; + case kdgVersion: + PB.driverGestaltResponse = + *((UInt32 *) &TheDriverDescription.driverType.version); + break; + case kdgDeviceType: + PB.driverGestaltResponse = 'QEMU'; + break; + case kdgInterface: + PB.driverGestaltResponse = 'pci '; + break; + case kdgSupportsSwitching: /* Support Power up/down switching? */ + PB.driverGestaltResponse = FALSE; /* Not supported yet */ + break; + case kdgSupportsPowerCtl: /* TRUE if in high-power mode */ + PB.driverGestaltResponse = FALSE; /* Power-switching is not supported */ + break; + default: + status = statusErr; + break; + } + return status; +#undef PB +} diff --git a/QemuVGADriver/src/DriverQDCalls.c b/QemuVGADriver/src/DriverQDCalls.c new file mode 100644 index 0000000..2383643 --- /dev/null +++ b/QemuVGADriver/src/DriverQDCalls.c @@ -0,0 +1,629 @@ +#include "VideoDriverPrivate.h" +#include "VideoDriverPrototypes.h" +#include "DriverQDCalls.h" +#include "QemuVga.h" + +static OSStatus GraphicsCoreDoSetEntries(VDSetEntryRecord *entryRecord, Boolean directDevice, UInt32 start, UInt32 stop, Boolean useValue); + +/************************ Color Table Stuff ****************************/ + +OSStatus +GraphicsCoreSetEntries(VDSetEntryRecord *entryRecord) +{ + Boolean useValue = (entryRecord->csStart < 0); + UInt32 start = useValue ? 0UL : (UInt32)entryRecord->csStart; + UInt32 stop = start + entryRecord->csCount; + + Trace(GraphicsCoreSetEntries); + + return GraphicsCoreDoSetEntries(entryRecord, false, start, stop, useValue); +} + +OSStatus +GraphicsCoreDirectSetEntries(VDSetEntryRecord *entryRecord) +{ + Boolean useValue = (entryRecord->csStart < 0); + UInt32 start = useValue ? 0 : entryRecord->csStart; + UInt32 stop = start + entryRecord->csCount; + + Trace(GraphicsCoreDirectSetEntries); + + return GraphicsCoreDoSetEntries(entryRecord, true, start, stop, useValue); +} + +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); + UInt32 start = useValue ? 0UL : (UInt32)entryRecord->csStart; + UInt32 stop = start + entryRecord->csCount; + UInt32 i; + + Trace(GraphicsCoreGetEntries); + + 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); + } + + return noErr; +} + +/************************ Gamma ****************************/ + +OSStatus +GraphicsCoreSetGamma(VDGammaRecord *gammaRec) +{ + CHECK_OPEN( controlErr ); + + return noErr; +} + +OSStatus +GraphicsCoreGetGammaInfoList(VDGetGammaListRec *gammaList) +{ + Trace(GraphicsCoreGammaInfoList); + + return statusErr; +} + +OSStatus +GraphicsCoreRetrieveGammaTable(VDRetrieveGammaRec *gammaRec) +{ + Trace(GraphicsCoreRetrieveGammaTable); + + return statusErr; +} + +OSStatus +GraphicsCoreGetGamma(VDGammaRecord *gammaRecord) +{ + CHECK_OPEN( statusErr ); + + Trace(GraphicsCoreGetGamma); + + gammaRecord->csGTable = NULL; + + return noErr; +} + + +/************************ Gray pages ****************************/ + +OSStatus +GraphicsCoreGrayPage(VDPageInfo *pageInfo) +{ + CHECK_OPEN( controlErr ); + + Trace(GraphicsCoreGrayPage); + + if (pageInfo->csPage != 0) + return paramErr; + + return noErr; +} + +OSStatus +GraphicsCoreSetGray(VDGrayRecord *grayRecord) +{ + CHECK_OPEN( controlErr ); + + Trace(GraphicsCoreSetGray); + + GLOBAL.qdLuminanceMapping = grayRecord->csMode; + return noErr; +} + + +OSStatus +GraphicsCoreGetPages(VDPageInfo *pageInfo) +{ +/* DepthMode mode; */ + CHECK_OPEN( statusErr ); + + Trace(GraphicsCoreGetPages); + + pageInfo->csPage = 1; + return noErr; +} + + +OSStatus +GraphicsCoreGetGray(VDGrayRecord *grayRecord) +{ + CHECK_OPEN( statusErr ); + + Trace(GraphicsCoreGetGray); + + grayRecord->csMode = (GLOBAL.qdLuminanceMapping); + + return noErr; +} + +/************************ Hardware Cursor ****************************/ + +OSStatus +GraphicsCoreSupportsHardwareCursor(VDSupportsHardwareCursorRec *hwCursRec) +{ + CHECK_OPEN( statusErr ); + + Trace(GraphicsCoreSupportsHardwareCursor); + + hwCursRec->csReserved1 = 0; + hwCursRec->csReserved2 = 0; + + hwCursRec->csSupportsHardwareCursor = false; + + return noErr; +} + +OSStatus +GraphicsCoreSetHardwareCursor(VDSetHardwareCursorRec *setHwCursRec) +{ + Trace(GraphicsCoreSetHardwareCursor); + + return controlErr; +} + +OSStatus +GraphicsCoreDrawHardwareCursor(VDDrawHardwareCursorRec *drawHwCursRec) +{ + Trace(GraphicsCoreDrawHardwareCursor); + + return controlErr; +} + +OSStatus +GraphicsCoreGetHardwareCursorDrawState(VDHardwareCursorDrawStateRec *hwCursDStateRec) +{ + Trace(GraphicsCoreGetHardwareCursorDrawState); + + return statusErr; +} + +/************************ Misc ****************************/ + +OSStatus +GraphicsCoreSetInterrupt(VDFlagRecord *flagRecord) +{ + CHECK_OPEN( controlErr ); + + Trace(GraphicsCoreSetInterrupt); + + if (!flagRecord->csMode) + QemuVga_EnableInterrupts(); + else + QemuVga_DisableInterrupts(); + + return noErr; +} + +OSStatus +GraphicsCoreGetInterrupt(VDFlagRecord *flagRecord) +{ + Trace(GraphicsCoreGetInterrupt); + + CHECK_OPEN( statusErr ); + + flagRecord->csMode = !GLOBAL.qdInterruptsEnable; + 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; +} + +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; +} + +OSStatus +GraphicsCoreSetPowerState(VDPowerStateRec *powerStateRec) +{ + 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; +} + +OSStatus +GraphicsCoreGetPowerState(VDPowerStateRec *powerStateRec) +{ + Trace(GraphicsCoreGetPowerState); + + CHECK_OPEN( statusErr ); + + powerStateRec->powerState = MOLVideoPowerState; + powerStateRec->powerFlags = 0; + return noErr; +} + +OSStatus +GraphicsCoreSetPreferredConfiguration(VDSwitchInfoRec *switchInfo) +{ + Trace(GraphicsCoreSetPreferredConfiguration); + + CHECK_OPEN( controlErr ); + + 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) +{ + Trace(GraphicsCoreGetPreferredConfiguration); + + CHECK_OPEN( statusErr ); + + switchInfo->csMode = DepthToDepthMode(GLOBAL.bootDepth); + switchInfo->csData = GLOBAL.bootMode + 1; /* Modes are 1 based */ + switchInfo->csPage = 0; + switchInfo->csBaseAddr = FB_START; + + return noErr; +} + +// €***************** Misc status calls *********************/ + +OSStatus +GraphicsCoreGetBaseAddress(VDPageInfo *pageInfo) +{ + Trace(GraphicsCoreGetBaseAddress); + + CHECK_OPEN( statusErr ); + + if (pageInfo->csPage != 0) + return paramErr; + + pageInfo->csBaseAddr = FB_START; + return noErr; +} + +OSStatus +GraphicsCoreGetConnection(VDDisplayConnectInfoRec *connectInfo) +{ + Trace(GraphicsCoreGetConnection); + + CHECK_OPEN( statusErr ); + + connectInfo->csDisplayType = kVGAConnect; + connectInfo->csConnectTaggedType = 0; + connectInfo->csConnectTaggedData = 0; + + connectInfo->csConnectFlags = + (1 << kTaggingInfoNonStandard) | (1 << kUncertainConnection); + + connectInfo->csDisplayComponent = 0; + + return noErr; +} + +OSStatus +GraphicsCoreGetMode(VDPageInfo *pageInfo) +{ + Trace(GraphicsCoreGetMode); + + CHECK_OPEN( statusErr ); + + //lprintf("GetMode\n"); + pageInfo->csMode = DepthToDepthMode(GLOBAL.depth); + pageInfo->csPage = 0; + pageInfo->csBaseAddr = FB_START; + + return noErr; +} + +OSStatus +GraphicsCoreGetCurrentMode(VDSwitchInfoRec *switchInfo) +{ + Trace(GraphicsCoreGetCurrentMode); + + CHECK_OPEN( statusErr ); + + //lprintf("GetCurrentMode\n"); + switchInfo->csMode = DepthToDepthMode(GLOBAL.depth); + switchInfo->csData = GLOBAL.curMode + 1; + switchInfo->csPage = 0; + switchInfo->csBaseAddr = FB_START; + + return noErr; +} + +/********************** Video mode *****************************/ + +OSStatus +GraphicsCoreGetModeTiming(VDTimingInfoRec *timingInfo) +{ + Trace(GraphicsCoreGetModeTiming); + + CHECK_OPEN( statusErr ); + + if (timingInfo->csTimingMode < 1 || timingInfo->csTimingMode > GLOBAL.numModes ) + return paramErr; + + timingInfo->csTimingFlags = + (1 << kModeValid) | (1 << kModeDefault) | (1 <<kModeSafe); + + timingInfo->csTimingFormat = kDeclROMtables; + timingInfo->csTimingData = timingVESA_640x480_60hz; + + return noErr; +} + + +OSStatus +GraphicsCoreSetMode(VDPageInfo *pageInfo) +{ + Trace(GraphicsCoreSetMode); + + CHECK_OPEN(controlErr); + + if (pageInfo->csPage != 0) + return paramErr; + + QemuVga_SetMode(GLOBAL.curMode, DepthModeToDepth(pageInfo->csMode)); + pageInfo->csBaseAddr = FB_START; + + return noErr; +} + + +OSStatus +GraphicsCoreSwitchMode(VDSwitchInfoRec *switchInfo) +{ + UInt32 newMode, newDepth; + + 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)) + return controlErr; + } + switchInfo->csBaseAddr = FB_START; + + return noErr; +} + +OSStatus +GraphicsCoreGetNextResolution(VDResolutionInfoRec *resInfo) +{ + UInt32 width, height; + int id = resInfo->csPreviousDisplayModeID; + + Trace(GraphicsCoreGetNextResolution); + + CHECK_OPEN(statusErr); + + if (id == kDisplayModeIDFindFirstResolution) + id = 0; + else if (id == kDisplayModeIDCurrent) + id = GLOBAL.curMode; + id++; + + if (id == GLOBAL.numModes + 1) { + resInfo->csDisplayModeID = kDisplayModeIDNoMoreResolutions; + return noErr; + } + if (id < 1 || id > GLOBAL.numModes) + return paramErr; + + if (QemuVga_GetModeInfo(id - 1, &width, &height)) + return paramErr; + + resInfo->csDisplayModeID = id; + resInfo->csHorizontalPixels = width; + resInfo->csVerticalLines = height; + resInfo->csRefreshRate = 60; + resInfo->csMaxDepthMode = kDepthMode3; /* XXX Calculate if it fits ! */ + + return noErr; +} + +// Looks quite a bit hard-coded, isn't it ? +OSStatus +GraphicsCoreGetVideoParams(VDVideoParametersInfoRec *videoParams) +{ + UInt32 width, height, depth; + 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 (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); + + (videoParams->csVPBlockPtr)->vpBaseOffset = 0; // For us, it's always 0 + (videoParams->csVPBlockPtr)->vpBounds.top = 0; // Always 0 + (videoParams->csVPBlockPtr)->vpBounds.left = 0; // Always 0 + (videoParams->csVPBlockPtr)->vpVersion = 0; // Always 0 + (videoParams->csVPBlockPtr)->vpPackType = 0; // Always 0 + (videoParams->csVPBlockPtr)->vpPackSize = 0; // Always 0 + (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); + + switch (depth) { + case 8: + videoParams->csDeviceType = clutType; + (videoParams->csVPBlockPtr)->vpPixelType = 0; + (videoParams->csVPBlockPtr)->vpPixelSize = 8; + (videoParams->csVPBlockPtr)->vpCmpCount = 1; + (videoParams->csVPBlockPtr)->vpCmpSize = 8; + (videoParams->csVPBlockPtr)->vpPlaneBytes = 0; + break; + case 15: + case 16: + videoParams->csDeviceType = directType; + (videoParams->csVPBlockPtr)->vpPixelType = 16; + (videoParams->csVPBlockPtr)->vpPixelSize = 16; + (videoParams->csVPBlockPtr)->vpCmpCount = 3; + (videoParams->csVPBlockPtr)->vpCmpSize = 5; + (videoParams->csVPBlockPtr)->vpPlaneBytes = 0; + break; + case 32: + videoParams->csDeviceType = directType; + (videoParams->csVPBlockPtr)->vpPixelType = 16; + (videoParams->csVPBlockPtr)->vpPixelSize = 32; + (videoParams->csVPBlockPtr)->vpCmpCount = 3; + (videoParams->csVPBlockPtr)->vpCmpSize = 8; + (videoParams->csVPBlockPtr)->vpPlaneBytes = 0; + break; + default: + err = paramErr; + break; + } + + return err; +} diff --git a/QemuVGADriver/src/DriverQDCalls.h b/QemuVGADriver/src/DriverQDCalls.h new file mode 100644 index 0000000..cca4d28 --- /dev/null +++ b/QemuVGADriver/src/DriverQDCalls.h @@ -0,0 +1,42 @@ +#ifndef _DRIVER_QD_CALLS_H__ +#define _DRIVER_QD_CALLS_H__ + +// ###ĘCONTROL ROUTINES ### + +OSStatus GraphicsCoreSetMode(VDPageInfo *pageInfo); +OSStatus GraphicsCoreSetEntries(VDSetEntryRecord *entryRecord); +OSStatus GraphicsCoreSetGamma(VDGammaRecord *gammaRec); +OSStatus GraphicsCoreGrayPage(VDPageInfo *pageInfo); +OSStatus GraphicsCoreSetGray(VDGrayRecord *grayRecord); +OSStatus GraphicsCoreSetInterrupt(VDFlagRecord *flagRecord); +OSStatus GraphicsCoreDirectSetEntries(VDSetEntryRecord *entryRecord); +OSStatus GraphicsCoreSwitchMode(VDSwitchInfoRec *switchInfo); +OSStatus GraphicsCoreSetSync(VDSyncInfoRec *syncInfo); +OSStatus GraphicsCoreSetPreferredConfiguration(VDSwitchInfoRec *switchInfo); +OSStatus GraphicsCoreSetHardwareCursor(VDSetHardwareCursorRec *setHwCursRec); +OSStatus GraphicsCoreDrawHardwareCursor(VDDrawHardwareCursorRec *drawHwCursRec); +OSStatus GraphicsCoreSetPowerState(VDPowerStateRec * powerStateRec); + +// ### STATUS ROUTINES ### + +OSStatus GraphicsCoreGetMode(VDPageInfo *pageInfo); +OSStatus GraphicsCoreGetEntries(VDSetEntryRecord *entryRecord); +OSStatus GraphicsCoreGetPages(VDPageInfo *pageInfo); +OSStatus GraphicsCoreGetBaseAddress(VDPageInfo *pageInfo); +OSStatus GraphicsCoreGetGray(VDGrayRecord *grayRecord); +OSStatus GraphicsCoreGetInterrupt(VDFlagRecord *flagRecord); +OSStatus GraphicsCoreGetGamma(VDGammaRecord *gammaRecord); +OSStatus GraphicsCoreGetCurrentMode(VDSwitchInfoRec *switchInfo); +OSStatus GraphicsCoreGetSync(VDSyncInfoRec *syncInfo); +OSStatus GraphicsCoreGetConnection(VDDisplayConnectInfoRec *connectInfo); +OSStatus GraphicsCoreGetModeTiming(VDTimingInfoRec *timingInfo); +OSStatus GraphicsCoreGetPreferredConfiguration(VDSwitchInfoRec *switchInfo); +OSStatus GraphicsCoreGetNextResolution(VDResolutionInfoRec *resInfo); +OSStatus GraphicsCoreGetVideoParams(VDVideoParametersInfoRec *videoParams); +OSStatus GraphicsCoreGetGammaInfoList(VDGetGammaListRec *gammaList); +OSStatus GraphicsCoreRetrieveGammaTable(VDRetrieveGammaRec *gammaRec); +OSStatus GraphicsCoreSupportsHardwareCursor(VDSupportsHardwareCursorRec *hwCursRec); +OSStatus GraphicsCoreGetHardwareCursorDrawState(VDHardwareCursorDrawStateRec *hwCursDStateRec); +OSStatus GraphicsCoreGetPowerState(VDPowerStateRec * powerStateRec); + +#endif /* DRIVER_QD_CALLS */ diff --git a/QemuVGADriver/src/QemuVga.c b/QemuVGADriver/src/QemuVga.c new file mode 100644 index 0000000..8c996a7 --- /dev/null +++ b/QemuVGADriver/src/QemuVga.c @@ -0,0 +1,267 @@ +#include "VideoDriverPrivate.h" +#include "VideoDriverPrototypes.h" +#include "DriverQDCalls.h" +#include "QemuVga.h" + +/* List of supported modes */ +struct vMode { + UInt32 width; + UInt32 height; +}; + +static struct vMode vModes[] = { + { 640, 480 }, + { 800, 600 }, + { 1024, 768 }, + { 1280, 1024 }, + { 1600, 1200 }, + { 1920, 1080 }, + { 1920, 1200 }, + { 0,0 } +}; + +static void VgaWriteB(UInt16 port, UInt8 val) +{ + UInt8 *ptr; + + ptr = (UInt8 *)((UInt32)GLOBAL.boardRegAddress + port + 0x400 - 0x3c0); + *ptr = val; + SynchronizeIO(); +} + +static UInt8 VgaReadB(UInt16 port) +{ + UInt8 *ptr, val; + + ptr = (UInt8 *)((UInt32)GLOBAL.boardRegAddress + port + 0x400 - 0x3c0); + val = *ptr; + SynchronizeIO(); + return val; +} + +static void DispiWriteW(UInt16 reg, UInt16 val) +{ + UInt16 *ptr; + + ptr = (UInt16 *)((UInt32)GLOBAL.boardRegAddress + (reg << 1) + 0x500); + *ptr = EndianSwap16Bit(val); + SynchronizeIO(); +} + +static UInt16 DispiReadW(UInt16 reg) +{ + UInt16 *ptr, val; + + ptr = (UInt16 *)((UInt32)GLOBAL.boardRegAddress + (reg << 1) + 0x500); + val = EndianSwap16Bit(*ptr); + SynchronizeIO(); + return val; +} + +static void ExtWriteL(UInt16 reg, UInt32 val) +{ + UInt32 *ptr; + + ptr = (UInt32 *)((UInt32)GLOBAL.boardRegAddress + (reg << 2) + 0x600); + *ptr = EndianSwap32Bit(val); + SynchronizeIO(); +} + +static UInt32 ExtReadL(UInt32 reg) +{ + UInt32 *ptr, val; + + ptr = (UInt32 *)((UInt32)GLOBAL.boardRegAddress + (reg << 2) + 0x600); + val = EndianSwap32Bit(*ptr); + SynchronizeIO(); + return val; +} + +OSStatus QemuVga_Init(void) +{ + UInt16 id, i; + UInt32 mem, width, height, depth; + + id = DispiReadW(VBE_DISPI_INDEX_ID); + mem = DispiReadW(VBE_DISPI_INDEX_VIDEO_MEMORY_64K); + mem <<= 16; + lprintf("DISPI_ID=%04x VMEM=%d Mb\n", id, mem >> 20); + if ((id & 0xfff0) != VBE_DISPI_ID0) { + lprintf("Unsupported ID !\n"); + return controlErr; + } + if (mem > GLOBAL.boardFBMappedSize) + mem = GLOBAL.boardFBMappedSize; + GLOBAL.vramSize = mem; + + // XXX Add endian control regs + + width = DispiReadW(VBE_DISPI_INDEX_XRES); + height = DispiReadW(VBE_DISPI_INDEX_YRES); + depth = DispiReadW(VBE_DISPI_INDEX_BPP); + lprintf("Current setting: %dx%dx%d\n", width, height, depth); + + GLOBAL.depth = GLOBAL.bootDepth = depth; + for (i = 0; vModes[i].width; i++) { + if (width == vModes[i].width && height == vModes[i].height) + break; + } + if (!vModes[i].width) { + lprintf("Not found in list ! using default.\n"); + i = 0; + } + GLOBAL.curMode = GLOBAL.bootMode = i; + GLOBAL.numModes = sizeof(vModes) / sizeof(struct vMode) - 1; + + 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; + + /* Create VBL if timer works */ + if (GLOBAL.hasTimer && !GLOBAL.qdVBLInterrupt) + 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; +} + +OSStatus QemuVga_Close(void) +{ + lprintf("Closing Driver...\n"); + + GLOBAL.isOpen = false; + + QemuVga_DisableInterrupts(); + if (GLOBAL.qdVBLInterrupt) + VSLDisposeInterruptService( GLOBAL.qdVBLInterrupt ); + GLOBAL.qdVBLInterrupt = NULL; + + return noErr; +} + +OSStatus QemuVga_Exit(void) +{ + QemuVga_Close(); + + return noErr; +} + +void QemuVga_EnableInterrupts(void) +{ + GLOBAL.qdInterruptsEnable = true; + if (GLOBAL.hasTimer) + ScheduleVBLTimer(); +} + +void QemuVga_DisableInterrupts(void) +{ + AbsoluteTime remaining; + + GLOBAL.qdInterruptsEnable = false; + if (GLOBAL.hasTimer) + CancelTimer(GLOBAL.VBLTimerID, &remaining); +} + +OSStatus QemuVga_SetColorEntry(UInt32 index, RGBColor *color) +{ + //lprintf("SetColorEntry %d, %x %x %x\n", index, color->red, color->green, color->blue); + VgaWriteB(0x3c8, index); + VgaWriteB(0x3c9, color->red >> 8); + VgaWriteB(0x3c9, color->green >> 8); + VgaWriteB(0x3c9, color->blue >> 8); + return noErr; +} + +OSStatus QemuVga_GetColorEntry(UInt32 index, RGBColor *color) +{ + UInt32 r,g,b; + + VgaWriteB(0x3c7, index); + r = VgaReadB(0x3c9); + g = VgaReadB(0x3c9); + b = VgaReadB(0x3c9); + color->red = (r << 8) | r; + color->green = (g << 8) | g; + color->blue = (b << 8) | b; + + return noErr; +} + +OSStatus QemuVga_GetModeInfo(UInt32 index, UInt32 *width, UInt32 *height) +{ + if (index >= GLOBAL.numModes) + return paramErr; + if (width) + *width = vModes[index].width; + if (height) + *height = vModes[index].height; + return noErr; +} + + +OSStatus QemuVga_SetMode(UInt32 mode, UInt32 depth) +{ + UInt32 width, height; + + if (mode >= GLOBAL.numModes) + return paramErr; + width = vModes[mode].width; + height = vModes[mode].height; + + lprintf("Set Mode: %dx%dx%d\n", width, height, depth); + + DispiWriteW(VBE_DISPI_INDEX_ENABLE, 0); + DispiWriteW(VBE_DISPI_INDEX_BPP, depth); + DispiWriteW(VBE_DISPI_INDEX_XRES, width); + 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_X_OFFSET, 0); + DispiWriteW(VBE_DISPI_INDEX_Y_OFFSET, 0); + DispiWriteW(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED | VBE_DISPI_8BIT_DAC); + GLOBAL.curMode = mode; + GLOBAL.depth = depth; + + return noErr; +} diff --git a/QemuVGADriver/src/QemuVga.h b/QemuVGADriver/src/QemuVga.h new file mode 100644 index 0000000..e401ef3 --- /dev/null +++ b/QemuVGADriver/src/QemuVga.h @@ -0,0 +1,54 @@ +#ifndef __QEMU_VGA_H__ +#define __QEMU_VGA_H__ + +/* --- Qemu/Bochs special registers --- */ + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +/* --- Internal APIs */ + +extern OSStatus QemuVga_Init(); +extern OSStatus QemuVga_Exit(); + +extern OSStatus QemuVga_Open(); +extern OSStatus QemuVga_Close(); + +extern void QemuVga_EnableInterrupts(void); +extern void QemuVga_DisableInterrupts(void); + +extern OSStatus QemuVga_SetDepth(UInt32 bpp); + +extern OSStatus QemuVga_SetColorEntry(UInt32 index, RGBColor *color); +extern OSStatus QemuVga_GetColorEntry(UInt32 index, RGBColor *color); + +extern OSStatus QemuVga_GetModeInfo(UInt32 index, UInt32 *width, UInt32 *height); +extern OSStatus QemuVga_SetMode(UInt32 modeIndex, UInt32 depth); + +#endif diff --git a/QemuVGADriver/src/VideoDriver.exp b/QemuVGADriver/src/VideoDriver.exp new file mode 100644 index 0000000..0a102ee --- /dev/null +++ b/QemuVGADriver/src/VideoDriver.exp @@ -0,0 +1,2 @@ +TheDriverDescription +DoDriverIO diff --git a/QemuVGADriver/src/VideoDriverPrivate.h b/QemuVGADriver/src/VideoDriverPrivate.h new file mode 100644 index 0000000..cd4cdba --- /dev/null +++ b/QemuVGADriver/src/VideoDriverPrivate.h @@ -0,0 +1,79 @@ +#ifndef __VideoDriverPrivate_H__ +#define __VideoDriverPrivate_H__ + +#pragma internal off + +#include <VideoServices.h> +#include <Video.h> +#include <Displays.h> +#include <DriverGestalt.h> +#include <DriverServices.h> +#include <PCI.h> + +#pragma internal on + +#ifndef FALSE +#define TRUE 1 +#define FALSE 0 +#endif + +#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_BASE_REG 0x10 +#define QEMU_PCI_VIDEO_MMIO_REG 0x18 + +#define kDriverGlobalsPropertyName "GLOBALS" +#define kDriverFailTextPropertyName "FAILURE" +#define kDriverFailCodePropertyName "FAIL-CODE" + + +/* + * Our global storage is defined by this structure. This is not a requirement of the + * driver environment, but it collects globals into a coherent structure for debugging. + */ +struct DriverGlobal { + DriverRefNum refNum; /* Driver refNum for PB... */ + RegEntryID deviceEntry; /* Name Registry Entry ID */ + LogicalAddress boardFBAddress; + ByteCount boardFBMappedSize; + LogicalAddress boardRegAddress; + ByteCount boardRegMappedSize; + + volatile Boolean inInterrupt; + + /* Common globals */ + UInt32 openCount; + + /* Frame buffer configuration */ + Boolean qdInterruptsEnable; /* Enable VBLs for qd */ + Boolean qdLuminanceMapping; + + Boolean hasTimer; + InterruptServiceIDType qdVBLInterrupt; + TimerID VBLTimerID; + + Boolean isOpen; + + UInt32 vramSize; + UInt32 depth; + UInt32 bootDepth; + UInt32 bootMode; + UInt32 curMode; + UInt32 numModes; +}; +typedef struct DriverGlobal DriverGlobal, *DriverGlobalPtr; + +/* + * Globals and functions + */ +extern DriverGlobal gDriverGlobal; /* All interesting globals */ +#define GLOBAL (gDriverGlobal) /* GLOBAL.field for references */ +extern DriverDescription TheDriverDescription; /* Exported to the universe */ + +#define FB_START ((char*)GLOBAL.boardFBAddress) +#define CHECK_OPEN( error ) if( !GLOBAL.isOpen ) return (error) + +#endif diff --git a/QemuVGADriver/src/VideoDriverPrototypes.h b/QemuVGADriver/src/VideoDriverPrototypes.h new file mode 100644 index 0000000..b4d6c6f --- /dev/null +++ b/QemuVGADriver/src/VideoDriverPrototypes.h @@ -0,0 +1,105 @@ +#ifndef __VideoDriverPrototypes_H__ +#define __VideoDriverPrototypes_H__ + +#include <PCI.h> +#include "logger.h" + +/* + * The Driver Manager calls DoDriverIO to perform I/O. + */ +#pragma internal off + +OSStatus +DoDriverIO( AddressSpaceID addressSpaceID, + IOCommandID ioCommandID, + IOCommandContents ioCommandContents, + IOCommandCode ioCommandCode, + IOCommandKind ioCommandKind); + +#pragma internal on + +#include "MacDriverUtils.h" + +/* + * Prototypes for the specific driver handlers. These do real work. + */ +OSStatus +DriverInitializeCmd( AddressSpaceID addressSpaceID, + DriverInitInfoPtr driverInitInfoPtr); + +OSStatus +DriverFinalizeCmd( DriverFinalInfoPtr driverFinalInfoPtr); + +OSStatus +DriverSupersededCmd( DriverSupersededInfoPtr driverSupersededInfoPtr, + Boolean calledFromFinalize); + +OSStatus +DriverReplaceCmd( AddressSpaceID addressSpaceID, + DriverReplaceInfoPtr driverReplaceInfoPtr); + +OSStatus +DriverOpenCmd( AddressSpaceID addressSpaceID, + ParmBlkPtr pb); + +OSStatus +DriverCloseCmd( ParmBlkPtr pb); + +OSStatus +DriverControlCmd( AddressSpaceID addressSpaceID, + IOCommandID ioCommandID, + IOCommandKind ioCommandKind, + CntrlParam *pb); + +OSStatus +DriverStatusCmd( IOCommandID ioCommandID, + IOCommandKind ioCommandKind, + CntrlParam *pb); + +OSStatus +DriverKillIOCmd( ParmBlkPtr pb); + +OSStatus +DriverReadCmd( + AddressSpaceID addressSpaceID, + IOCommandID ioCommandID, + IOCommandKind ioCommandKind, + ParmBlkPtr pb); + +OSStatus +DriverWriteCmd( AddressSpaceID addressSpaceID, + IOCommandID ioCommandID, + IOCommandKind ioCommandKind, + ParmBlkPtr pb); + +/* .___________________________________________________________________________________. + | Driver Gestalt handler -- called from the PBStatus handler. | + .___________________________________________________________________________________. + */ +OSStatus +DriverGestaltHandler( CntrlParam* pb); + + +#pragma internal on + +/* .___________________________________________________________________________________. + | Utitlity function to clear a block of memory. | + .___________________________________________________________________________________. + */ +#ifndef CLEAR +#define CLEAR(what) BlockZero((char*)&what, sizeof what) +#endif + +/* + * This uses the ANSI-C string concatenate and "stringize" operations. + */ +#define Trace(what) lprintf("Trace: %s\n", #what) + +#if 0 +static void +CheckStatus( OSStatus value, + char* message) +{} +#endif + +#endif
\ No newline at end of file |