/**************************************************************************\ $Header: o:\src/RCS/MGA.C 1.10 94/03/02 04:46:47 jyharbec Exp $ $Log: MGA.C $ * Revision 1.10 94/03/02 04:46:47 jyharbec * Modification for PCI to default to board 0. * * Revision 1.9 94/02/28 04:04:36 jyharbec * Code for 5-6-5 driver; * Setting cursor colors for ViewPoint. * * Revision 1.8 94/01/05 12:03:32 jyharbec * New service IOCTL_VIDEO_MTX_QUERY_HW_DATA. * * Revision 1.7 93/12/20 11:42:36 jyharbec * Modified S3 to MGA in debug message text. * * Revision 1.6 93/11/04 04:50:04 dlee * Modified for Alpha. * * Revision 1.5 93/10/15 11:30:00 jyharbec * Added service IOCTL_VIDEO_MTX_QUERY_BOARD_ID. * * Revision 1.4 93/10/06 05:39:59 jyharbec * Modifications required to update MGA.INF file to current version. * * Revision 1.3 93/09/23 11:42:49 jyharbec * Modification to IOCTL_VIDEO_MTX_QUERY_RAMDAC_INFO to include Overscan. * * Revision 1.2 93/09/01 13:29:07 jyharbec * Take into account DISPTYPE_UNUSABLE from HwModeData structures. * * Revision 1.1 93/08/27 12:37:09 jyharbec * Initial revision * \**************************************************************************/ /****************************************************************************\ * MODULE: MGA.C * * DESCRIPTION: This module contains the code that implements the MGA miniport * driver. [Based on S3.C (Mar 1,1993) from Windows-NT DDK] * * Copyright (c) 1990-1992 Microsoft Corporation * Copyright (c) 1993 Matrox Electronic Systems Ltd. * * History: * 23AUG93 - Added check for micro-channel adapter in FindAdapter * \****************************************************************************/ #include "switches.h" #include #include "bind.h" #include "sxci.h" #include "mga.h" #include "defbind.h" #include "mga_nt.h" // // New entry points added for NT 5.0. // #if (_WIN32_WINNT >= 500) // // Routine to set a desired DPMS power management state. // VP_STATUS MgaSetPower50( PMGA_DEVICE_EXTENSION phwDeviceExtension, ULONG HwDeviceId, PVIDEO_POWER_MANAGEMENT pVideoPowerMgmt ); // // Routine to retrieve possible DPMS power management states. // VP_STATUS MgaGetPower50( PMGA_DEVICE_EXTENSION phwDeviceExtension, ULONG HwDeviceId, PVIDEO_POWER_MANAGEMENT pVideoPowerMgmt ); // // Routine to retrieve the Enhanced Display ID structure via DDC // ULONG MgaGetVideoChildDescriptor( PVOID HwDeviceExtension, PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, PVIDEO_CHILD_TYPE pChildType, PVOID pvChildDescriptor, PULONG pHwId, PULONG pUnused ); #endif // _WIN32_WINNT >= 500 // From MTXINIT.C; it should be in some header file. #define BOARD_MGA_RESERVED 0x07 VIDEO_MODE_INFORMATION CommonVideoModeInformation = { sizeof(VIDEO_MODE_INFORMATION), // Size of the mode informtion structure 0, // *Mode index used in setting the mode 1280, // *X Resolution, in pixels 1024, // *Y Resolution, in pixels 1024, // *Screen stride 1, // Number of video memory planes 8, // *Number of bits per plane 1, // Screen Frequency, in Hertz 330, // Horizontal size of screen in millimeters 240, // Vertical size of screen in millimeters 8, // Number Red pixels in DAC 8, // Number Green pixels in DAC 8, // Number Blue pixels in DAC 0x00000000, // *Mask for Red Pixels in non-palette modes 0x00000000, // *Mask for Green Pixels in non-palette modes 0x00000000, // *Mask for Blue Pixels in non-palette modes 0, // *Mode description flags. 1280, // *Video Memory Bitmap Width 1024 // *Video Memory Bitmap Height }; #if NB_BOARD_MAX > 7 #error Error! Modify MultiModes array! #endif UCHAR MgaBusType[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // Nb of modes supported by 1, 2, 3, 4, 5, 6, 7 boards. USHORT MultiModes[] = { 0, 1, 2, 2, 3, 2, 4, 2 }; USHORT SingleWidths[] = { 640, 768, 800, 1024, 1152, 1280, 1600, 0xffff}; USHORT SingleHeights[]= { 480, 576, 600, 768, 882, 1024, 1200, 0xffff}; // MGA communication access ranges. VIDEO_ACCESS_RANGE MgaDriverCommonAccessRange[] = { // {0x00000400, 0x00000000, 0x000000AB, 0, 0, 1}, // BIOS Communication Area {0x000003B4, 0x00000000, 0x00000002, 1, 0, 1}, // 0 Titan VGA & CRTC {0x000003BA, 0x00000000, 0x00000001, 1, 0, 1}, // 1 {0x000003C0, 0x00000000, 0x00000010, 1, 0, 1}, // 2 {0x000003D4, 0x00000000, 0x00000008, 1, 0, 1}, // 3 {0x000003DE, 0x00000000, 0x00000002, 1, 0, 1}, // 4 #if USE_SETUP_VGA {0x000046E8, 0x00000000, 0x00000002, 1, 0, 1}, // 5 {0x00000410, 0x00000000, 0x00000001, 0, 0, 1}, // 6 {0x00000449, 0x00000000, 0x0000001e, 0, 0, 1}, // 7 {0x00000484, 0x00000000, 0x00000007, 0, 0, 1}, // 8 {0x000004A8, 0x00000000, 0x00000004, 0, 0, 1}, // 9 {0x000A0000, 0x00000000, 0x00010000, 0, 0, 1} // 10 //{0x000B8000, 0x00000000, 0x00008000, 0, 0, 1} // 11 #else {0x000046E8, 0x00000000, 0x00000002, 1, 0, 1} // 5 #endif }; // MGA windows access ranges. VIDEO_ACCESS_RANGE MgaDriverAccessRange[] = { {0x000C8000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 0 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 0 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 1 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 1 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 2 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 2 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 3 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 3 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 4 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 4 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 5 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0}, // Config space 5 {0x00000000, 0x00000000, 0x00004000, 0, 0, 0}, // Command window 6 {0x0000C000, 0x00000000, 0x00000100, 1, 0, 0} // Config space 6 }; #if (!USE_VP_GET_ACCESS_RANGES) VIDEO_ACCESS_RANGE MgaDriverSupplAccessRange[] = { {0x00000CF8, 0x00000000, 0x00000008, 1, 0, 1} //{0x000E0000, 0x00000000, 0x00020000, 1, 0, 1} }; #endif #define NUM_MGA_COMMON_ACCESS_RANGES \ (sizeof(MgaDriverCommonAccessRange) / sizeof(VIDEO_ACCESS_RANGE)) #define NUM_MGA_ACCESS_RANGES \ (sizeof(MgaDriverAccessRange) / sizeof(VIDEO_ACCESS_RANGE)) #if (!USE_VP_GET_ACCESS_RANGES) #define NUM_MGA_SUPPL_ACCESS_RANGES \ (sizeof(MgaDriverSupplAccessRange) / sizeof(VIDEO_ACCESS_RANGE)) #else #define NUM_MGA_SUPPL_ACCESS_RANGES 0 #endif #define NUM_ALL_ACCESS_RANGES \ (NUM_MGA_COMMON_ACCESS_RANGES + NUM_MGA_ACCESS_RANGES + NUM_MGA_SUPPL_ACCESS_RANGES) INTERFACE_TYPE NtInterfaceType; HwData *pMgaBoardData; ULONG ulNewInfoSize; PUCHAR pucNewInfo; PUCHAR pMgaBiosVl; extern PVOID pMgaDeviceExtension; extern word mtxVideoMode; extern byte NbBoard; extern dword MgaSel; extern PVOID pMgaBaseAddr; extern HwData Hw[NB_BOARD_MAX+1]; extern byte iBoard; extern char *mgainf; extern char DefaultVidset[]; extern dword ProductMGA[NB_BOARD_MAX]; // Board number conversion macro. // In the user-mode drivers, boards are numbered sequentially starting from 0 // at the upper left corner and going from left to right and then top to // bottom. In the miniport driver, we might want to start from the lower // left corner. #if 1 // Same numbering convention as the user-mode driver. #define CONVERT_BOARD_NUMBER(n) n = n #else // Starting from lower left instead of upper left corner. #define CONVERT_BOARD_NUMBER(n) n = ((pCurMulti->MulArrayHeight - 1) * \ pCurMulti->MulArrayWidth) - n + \ 2*(n % pCurMulti->MulArrayWidth) #endif // Function Prototypes // // Functions that start with 'Mga' are entry points for the OS port driver. #ifdef MGA_WINNT35 BOOLEAN MgaResetHw( PVOID HwDeviceExtension, ULONG Columns, ULONG Rows ); #endif VP_STATUS MgaFindAdapter( PVOID HwDeviceExtension, PVOID HwContext, PWSTR ArgumentString, PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again ); BOOLEAN MgaInitialize( PVOID HwDeviceExtension ); BOOLEAN MgaStartIO( PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket ); VP_STATUS MgaInitModeList( PMGA_DEVICE_EXTENSION MgaDeviceExtension); VP_STATUS MgaSetColorLookup( PMGA_DEVICE_EXTENSION MgaDeviceExtension, PVIDEO_CLUT ClutBuffer, ULONG ClutBufferSize ); VOID MgaSetCursorColour( PMGA_DEVICE_EXTENSION MgaDeviceExtension, ULONG ulFgColour, ULONG ulBgColour); // For WinNT 3.5 // Code NOT to be made pageable: // SetVgaEn(); // setVgaMode(); // restoreVga(); // checkCursorEn(); // mtxCheckVgaEn(); // mtxMapVLBSpace(); // mtxUnMapVLBSpace(); // mtxIsVLB(); // isPciBus(); // wideToIsa(); // blankEcran(); // delay_us(); // _inp(); (macro) // _outp(); (macro) // rdDubicDReg(); // rdDubicIReg(); // rdDacReg(); // rdTitanReg(); // mgaReadDWORD(); (macro) // mgaReadBYTE(); (macro) // wrDubicDReg(); // wrDubicIReg(); // wrDacReg(); // wrTitanReg(); // mgaWriteBYTE(); (macro) // mgaWriteDWORD(); (macro) // Data NOT to be made pageable: // Hw (in mtxinit.c) // pMgaBaseAddr (in mtxinit.c) // iBoard (in mtxinit.c) // mtxVideoMode (in mtxinit.c) // pMgaDeviceExtension (in mtxinit.c) // isVLBFlag (in mtxvideo.c) // cursorStat (in mtxvideo.c) // saveBitOperation (in mtxvideo.c) #if defined(ALLOC_PRAGMA) #pragma alloc_text(PAGE,DriverEntry) #pragma alloc_text(PAGE,MgaFindAdapter) #pragma alloc_text(PAGE,MgaInitialize) #pragma alloc_text(PAGE,MgaStartIO) #pragma alloc_text(PAGE,MgaInitModeList) //#pragma alloc_text(PAGE,MgaSetColorLookup) #pragma alloc_text(PAGE,MgaSetCursorColour) #if (_WIN32_WINNT >= 500) #pragma alloc_text(PAGE_COM, MgaSetPower50) #pragma alloc_text(PAGE_COM, MgaGetPower50) #pragma alloc_text(PAGE_COM, MgaGetVideoChildDescriptor) #endif // _WIN32_WINNT >= 500 #endif //#if defined(ALLOC_PRAGMA) // #pragma data_seg("PAGE") //#endif // External function prototypes extern volatile byte _Far *setmgasel(dword MgaSel, dword phyadr, dword limit); bool MapBoard(void); char *adjustDefaultVidset(); PVOID AllocateSystemMemory(ULONG NumberOfBytes); char *mtxConvertMgaInf( char * ); void SetVgaEn(); char *selectMgaInfoBoard(); #if USE_SETUP_VGA void setupVga(void); void restoreVga(); #endif /****************************************************************************\ * ULONG * DriverEntry ( * PVOID Context1, * PVOID Context2) * * DESCRIPTION: * Installable driver initialization entry point. * This entry point is called directly by the I/O system. * * ARGUMENTS: * Context1 - First context value passed by the operating system. This is * the value with which the miniport driver calls VideoPortInitialize(). * * Context2 - Second context value passed by the operating system. This is * the value with which the miniport driver calls VideoPortInitialize(). * * RETURNS: * Status from VideoPortInitialize() * \****************************************************************************/ ULONG DriverEntry ( PVOID Context1, PVOID Context2 ) { VIDEO_HW_INITIALIZATION_DATA hwInitData; ULONG isaStatus, eisaStatus, microChannelStatus, pciStatus, minStatus; ULONG i, j; HwData TempHw; VideoDebugPrint((1, "MGA.SYS!DriverEntry\n")); //DbgBreakPoint(); // Zero out structure. VideoPortZeroMemory(&hwInitData, sizeof(VIDEO_HW_INITIALIZATION_DATA)) ; // Specify sizes of structure and extension. hwInitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA); // Set entry points. hwInitData.HwFindAdapter = MgaFindAdapter; hwInitData.HwInitialize = MgaInitialize; //hwInitData.HwInterrupt = NULL; hwInitData.HwStartIO = MgaStartIO; #ifdef MGA_WINNT35 hwInitData.HwResetHw = MgaResetHw; //hwInitData.HwTimer = NULL; #endif #if (_WIN32_WINNT >= 500) // // Set new entry points added for NT 5.0. // hwInitData.HwSetPowerState = MgaSetPower50; hwInitData.HwGetPowerState = MgaGetPower50; hwInitData.HwGetVideoChildDescriptor = MgaGetVideoChildDescriptor; #endif // _WIN32_WINNT >= 500 // // Determine the size we require for the device extension. // hwInitData.HwDeviceExtensionSize = sizeof(MGA_DEVICE_EXTENSION); // Always start with parameters for device0 in this case. //hwInitData.StartingDeviceNumber = 0; // This device only supports the internal bus type. So return the status // value directly to the operating system. // I think that each VPInitialize call will itself call MgaFindAdapter, // provided that the specified AdapterInterfaceType makes sense for the // hardware. MgaFindAdapter will call MapBoard. We can't be sure that // the last call to MapBoard will find all the boards, so we'll have to // accumulate the boards found, making sure that we don't record the // same board twice. //#if (defined(MGA_WINNT35) && defined(MGA_ALPHA)) NbBoard = 0; //#endif hwInitData.AdapterInterfaceType = PCIBus; pciStatus = VideoPortInitialize(Context1, Context2, &hwInitData, NULL); hwInitData.AdapterInterfaceType = Isa; isaStatus = VideoPortInitialize(Context1, Context2, &hwInitData, NULL); hwInitData.AdapterInterfaceType = Eisa; eisaStatus = VideoPortInitialize(Context1, Context2, &hwInitData, NULL); hwInitData.AdapterInterfaceType = MicroChannel; microChannelStatus = VideoPortInitialize(Context1, Context2, &hwInitData, NULL); // We should have found all our boards at this point. We want to // reorder the Hw array so that the PCI boards are the first ones. // The MgaBusType array was initialized to MGA_BUS_INVALID. for (i = 0; i < NbBoard; i++) { // The only possibilities are MGA_BUS_PCI and MGA_BUS_ISA. if (MgaBusType[i] == MGA_BUS_ISA) { // We found an ISA board. Look for a PCI board. for (j = i+1; j < NbBoard; j++) { if (MgaBusType[j] == MGA_BUS_PCI) { // We found a PCI board, exchange them. TempHw = Hw[j]; Hw[j] = Hw[i]; Hw[i] = TempHw; MgaBusType[i] = MGA_BUS_PCI; MgaBusType[j] = MGA_BUS_ISA; MgaDriverAccessRange[i*2].RangeStart.LowPart = Hw[i].MapAddress; MgaDriverAccessRange[i*2+1].RangeStart.LowPart = Hw[i].ConfigSpace; MgaDriverAccessRange[j*2].RangeStart.LowPart = Hw[j].MapAddress; MgaDriverAccessRange[j*2+1].RangeStart.LowPart = Hw[j].ConfigSpace; break; } } } } // Return the smallest of isaStatus, eisaStatus, pciStatus, and // microChannelStatus. minStatus = (isaStatus < eisaStatus) ? isaStatus : eisaStatus; if (microChannelStatus < minStatus) minStatus = microChannelStatus; if (pciStatus < minStatus) minStatus = pciStatus; return(minStatus); } // end DriverEntry() #ifdef MGA_WINNT35 /****************************************************************************\ * VOID * MgaResetHw(VOID) * * DESCRIPTION: * * This function is called when the machine needs to bugchecks (go back * to the blue screen). * * This function should reset the video adapter to a character mode, * or at least to a state from which an int 10 can reset the card to * a character mode. * * This routine CAN NOT call int10. * It can only call Read\Write Port\Register functions from the port driver. * * The function must also be completely in non-paged pool since the IO\MM * subsystems may have crashed. * * ARGUMENTS: * * HwDeviceExtension - Supplies the miniport driver's adapter storage. * * Columns - Number of columns in the requested mode. * * Rows - Number of rows in the requested mode. * * RETURN VALUE: * * The return value determines if the mode was completely programmed (TRUE) * or if an int10 should be done by the HAL to complete the modeset (FALSE). * \****************************************************************************/ BOOLEAN MgaResetHw( PVOID HwDeviceExtension, ULONG Columns, ULONG Rows ) { PMGA_DEVICE_EXTENSION MgaDeviceExtension; VideoDebugPrint((1, "MGA.SYS!MgaResetHw\n")); // There is nothing to be done to reset the board if the one that // went into hi-res was not VGA-enabled to start with. However it // will look nicer if we clear the screen. If the board was VGA- // enabled, we put it back into text mode, or as near as we can get. pMgaDeviceExtension = MgaDeviceExtension = (PMGA_DEVICE_EXTENSION)HwDeviceExtension; pMgaBaseAddr = MgaDeviceExtension->KernelModeMappedBaseAddress[0]; // Make the cursor disappear. mtxCursorEnable(0); if (Hw[0].VGAEnable) { SetVgaEn(); #if USE_SETUP_VGA setupVga(); restoreVga(); #endif mtxVideoMode = mtxPASSTHRU; } // Let the caller execute the Int10. return(FALSE); } #endif /****************************************************************************\ * FIND_ADAPTER_STATUS * MgaFindAdapter( * PVOID HwDeviceExtension, * PVOID HwContext, * PWSTR ArgumentString, * PVIDEO_PORT_CONFIG_INFO ConfigInfo, * PUCHAR Again * ) * * DESCRIPTION: * * This routine is called to determine if the adapter for this driver * is present in the system. * If it is present, the function fills out some information describing * the adapter. * * ARGUMENTS: * * HwDeviceExtension - Supplies the miniport driver's adapter storage. This * storage is initialized to zero before this call. * * HwContext - Supplies the context value which was passed to * VideoPortInitialize(). Must be NULL for PnP drivers. * * ArgumentString - Suuplies a NULL terminated ASCII string. This string * originates from the user. * * ConfigInfo - Returns the configuration information structure which is * filled by the miniport driver. This structure is initialized with * any knwon configuration information (such as SystemIoBusNumber) by * the port driver. Where possible, drivers should have one set of * defaults which do not require any supplied configuration information. * * Again - Indicates if the miniport driver wants the port driver to call * its VIDEO_HW_FIND_ADAPTER function again with a new device extension * and the same config info. This is used by the miniport drivers which * can search for several adapters on a bus. * * RETURN VALUE: * * This routine must return: * * VP_RETURN_FOUND - Indicates a host adapter was found and the * configuration information was successfully determined. * * VP_RETURN_ERROR - Indicates a host adapter was found but there was an * error obtaining the configuration information. If possible an error * should be logged. * * VP_RETURN_BAD_CONFIG - Indicates the supplied configuration was invalid. * * VP_RETURN_NOT_FOUND - Indicates no host adapter was found for the * supplied configuration information. * \****************************************************************************/ VP_STATUS MgaFindAdapter( PVOID HwDeviceExtension, PVOID HwContext, PWSTR ArgumentString, PVIDEO_PORT_CONFIG_INFO ConfigInfo, PUCHAR Again ) { PMGA_DEVICE_EXTENSION MgaDeviceExtension; VIDEO_ACCESS_RANGE AllAccessRanges[NUM_ALL_ACCESS_RANGES+1]; VP_STATUS status; ULONG i, j, SetBiosVl; //ULONG PreNbBoards; VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter\n")); // Make sure the size of the structure is at least as large as what we // are expecting (check version of the config info structure). if (ConfigInfo->Length < sizeof(VIDEO_PORT_CONFIG_INFO)) { return ERROR_INVALID_PARAMETER; } pMgaDeviceExtension = MgaDeviceExtension = HwDeviceExtension; // Set some global variable saying which bus we'll be exploring. NtInterfaceType = ConfigInfo->AdapterInterfaceType; // Get access ranges for our I/O. // Check to see if there is a hardware resource conflict. // Register all we'll need for now, unless we already did it. for (i = 0; i < NUM_MGA_COMMON_ACCESS_RANGES; i++) { AllAccessRanges[i] = MgaDriverCommonAccessRange[i]; } #if (!USE_VP_GET_ACCESS_RANGES) for (i = 0; i < NUM_MGA_SUPPL_ACCESS_RANGES; i++) { AllAccessRanges[i + NUM_MGA_COMMON_ACCESS_RANGES] = MgaDriverSupplAccessRange[i]; } #endif status = VideoPortVerifyAccessRanges(MgaDeviceExtension, (ULONG)(NUM_MGA_COMMON_ACCESS_RANGES + NUM_MGA_SUPPL_ACCESS_RANGES), AllAccessRanges); if (status != NO_ERROR) { VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter: Access Range conflict\n")); return status; } for (i=0; i < NUM_MGA_COMMON_ACCESS_RANGES; i++) { if ((MgaDeviceExtension->MappedAddress[i] = VideoPortGetDeviceBase( MgaDeviceExtension, MgaDriverCommonAccessRange[i].RangeStart, MgaDriverCommonAccessRange[i].RangeLength, MgaDriverCommonAccessRange[i].RangeInIoSpace)) == NULL) { VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter failed to map port addresses\n")); return(ERROR_INVALID_PARAMETER); } } // Search for MGA boards installed in the system. // On x86, the first call to MapBoard should have found all the boards. if (NbBoard != 0) { return(ERROR_DEV_NOT_EXIST); } if (!MapBoard()) { VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter failed MapBoard\n")); return(ERROR_DEV_NOT_EXIST); } //PreNbBoards = (ULONG)NbBoard; ////if (!MapBoard()) //if (!MapBoard() || (PreNbBoards == (ULONG)NbBoard)) //{ // VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter failed MapBoard\n")); // return(ERROR_DEV_NOT_EXIST); //} SetBiosVl = 0; // Fill out RangeStart portion of VIDEO_ACCESS_RANGE structure // with the mapping of the MGA boards found. for (i = 0; i < (ULONG)NbBoard; i++) { MgaDriverAccessRange[i*2].RangeStart.LowPart = Hw[i].MapAddress; if (Hw[i].MapAddress == 0xAC000) { // Make sure that this is shareable. MgaDriverAccessRange[i*2].RangeShareable = 1; // We'll also need access to 4 pages for BIOS_VL. SetBiosVl = 1; } MgaDriverAccessRange[i*2+1].RangeStart.LowPart = Hw[i].ConfigSpace; if (Hw[i].ConfigSpace == 0) { // This board doesn't require access to config space. MgaDriverAccessRange[i*2+1].RangeLength = 0; MgaDriverAccessRange[i*2+1].RangeInIoSpace = 0; } // Also make sure that the pHwMode field is set to 0. Hw[i].pHwMode = NULL; } // Register all we'll need. j = NUM_MGA_SUPPL_ACCESS_RANGES + NUM_MGA_COMMON_ACCESS_RANGES; for (i = 0; i < (ULONG)NbBoard*2; i++) { if (MgaDriverAccessRange[i].RangeStart.LowPart != 0) { AllAccessRanges[j] = MgaDriverAccessRange[i]; j++; } } if (SetBiosVl == 1) { // Add one more range. AllAccessRanges[j] = MgaDriverAccessRange[0]; AllAccessRanges[j].RangeStart.LowPart = 0xc0000; AllAccessRanges[j].RangeShareable = 1; j++; pMgaBiosVl = (PUCHAR)setmgasel(MgaSel, 0xc0000, 4); } //status = VideoPortVerifyAccessRanges(MgaDeviceExtension, // (ULONG) (NbBoard + // NUM_MGA_SUPPL_ACCESS_RANGES + // NUM_MGA_COMMON_ACCESS_RANGES), // AllAccessRanges); //if (status != NO_ERROR) //{ // VideoDebugPrint((1, "MGA.SYS!MgaFindAdapter: Access Range conflict\n")); // return status; //} VideoPortVerifyAccessRanges(MgaDeviceExtension, j, AllAccessRanges); // Special limitation: // The user-mode driver used by Microsoft doesn't allow for multiple // boards, so we'll make certain that only one board is considered here: NbBoard = 1; // Intel and Alpha both support VideoPortInt10. MgaDeviceExtension->bUsingInt10 = TRUE; // Clear out the Emulator entries and the state size since this driver // is not VGA compatible and does not support them. ConfigInfo->NumEmulatorAccessEntries = 0; ConfigInfo->EmulatorAccessEntries = NULL; ConfigInfo->EmulatorAccessEntriesContext = 0; // BUGBUG: Andrea, why do I have to do this. Faking out a VGA. if (!(MgaDeviceExtension->bUsingInt10)) { ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x00000000; ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000; ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00000000; } else { // !!! This should be removed or looked into some more. // These values are set to the same values as a VGA to try and // work around some memory mapping issues in the port driver. ConfigInfo->VdmPhysicalVideoMemoryAddress.LowPart = 0x000A0000; ConfigInfo->VdmPhysicalVideoMemoryAddress.HighPart = 0x00000000; ConfigInfo->VdmPhysicalVideoMemoryLength = 0x00020000; } ConfigInfo->HardwareStateSize = 0; // Let's try to build a list of modes right here. We'll use the // default vidset for now, but we may change our mind later and // build a different list. iBoard = 0; mgainf = adjustDefaultVidset(); // Call the service. MgaInitModeList(MgaDeviceExtension); // If an error occurred, pMgaDeviceExtension->NumberOfSuperModes will // be zero; otherwise, it will be the appropriate number of modes. // Indicate we do not wish to be called over *Again = 0; // Indicate a successful completion status. return NO_ERROR; } // end MgaFindAdapter() /****************************************************************************\ * BOOLEAN * MgaInitialize( * PVOID HwDeviceExtension * ) * * * DESCRIPTION: * * This routine does one time initialization of the device. * * ARGUMENTS: * * HwDeviceExtension - Supplies a pointer to the miniport's device extension. * * RETURN VALUE: * * Always returns TRUE since this routine can never fail. * \****************************************************************************/ BOOLEAN MgaInitialize( PVOID HwDeviceExtension ) { UNREFERENCED_PARAMETER(HwDeviceExtension); VideoDebugPrint((1, "MGA.SYS!MgaInitialize\n")); // We would like to do some work here, but we have to wait until we get // the contents of the MGA.INF file. Since MGA.INF has to be opened by // the user-mode driver, this work will be done by a special // INITIALIZE_MGA service of MgaStartIO. // Some day, we might want to write an application that will update the // registry instead of a file. We would then be able to do our work here. return (TRUE); } // end MgaInitialize() /****************************************************************************\ * BOOLEAN * MgaStartIO( * PVOID HwDeviceExtension, * PVIDEO_REQUEST_PACKET RequestPacket * ) * * Routine Description: * * This routine is the main execution routine for the miniport driver. It * acceptss a Video Request Packet, performs the request, and then returns * with the appropriate status. * * Arguments: * * HwDeviceExtension - Supplies a pointer to the miniport's device * extension. * * RequestPacket - Pointer to the video request packet. This structure * contains all the parameters passed to the VideoIoControl function. * * Return Value: * \****************************************************************************/ BOOLEAN MgaStartIO( PVOID HwDeviceExtension, PVIDEO_REQUEST_PACKET RequestPacket ) { PMGA_DEVICE_EXTENSION MgaDeviceExtension = HwDeviceExtension; PVIDEO_MODE_INFORMATION modeInformation; PVIDEO_MEMORY_INFORMATION memoryInformation; PVIDEO_CLUT pclutBuffer; PVIDEO_PUBLIC_ACCESS_RANGES publicAccessRanges; PRAMDAC_INFO pVideoPointerAttributes; HwModeData *pMgaDispMode; OffScrData *pMgaOffScreenData; MULTI_MODE *pCurMulti; PWSTR pwszChip, pwszDAC, pwszAdapterString; PUCHAR pucInBuffer, pucOutBuffer; PVOID pCurBaseAddr; VIDEO_CLUT clutBufferOne; VP_STATUS status; ULONG ZoomFactor; ULONG i, n; ULONG ulWindowLength, ulSizeOfBuffer; ULONG CurrentResNbBoards, ModeInit; ULONG cbChip, cbDAC, cbAdapterString, AdapterMemorySize; USHORT j; USHORT MaxWidth, MaxHeight, usTemp; UCHAR iCurBoard; UCHAR ucTemp; //DbgBreakPoint(); VideoDebugPrint((1, "MGA.SYS!MgaStartIO\n")); pMgaDeviceExtension = MgaDeviceExtension; // Switch on the IoContolCode in the RequestPacket. It indicates which // function must be performed by the driver. switch (RequestPacket->IoControlCode) { /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_INITIALIZE_MGA | | This will normally be the first call made to MgaStartIO. We do | here what we should have done in MgaInitialize, but couldn't. | We first determine if we'll be using the default vidset or the | contents of some MGA.INF file. If the file is an older version, | we will send back a non-zero FileInfoSize, so that the user-mode | driver can call us with MTX_GET_UPDATED_INF to get an updated | version. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_INITIALIZE_MGA: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_INITIALIZE_MGA\n")); //DbgBreakPoint(); #if 1 status = NO_ERROR; pucInBuffer = (PUCHAR)(RequestPacket->InputBuffer); ulSizeOfBuffer = RequestPacket->InputBufferLength; ulNewInfoSize = 0; iBoard = 0; mgainf = adjustDefaultVidset(); pucNewInfo = mgainf; *(PULONG)(RequestPacket->OutputBuffer) = ulNewInfoSize; RequestPacket->StatusBlock->Information = sizeof(ULONG); break; #else status = NO_ERROR; pucInBuffer = (PUCHAR)(RequestPacket->InputBuffer); ulSizeOfBuffer = RequestPacket->InputBufferLength; // We may have to update the current MGA.INF file later. // For now, assume that we won't. If the call to mtxConvertMgaInf // is required and successful, this will be changed. ulNewInfoSize = 0; iBoard = 0; // Check to see if we are to use the default vidset. if ((pucInBuffer == NULL) || (ulSizeOfBuffer == 0)) { // The user-mode driver tells us to use the default. mgainf = adjustDefaultVidset(); } else { // The user-mode driver sends us the actual file contents. if ( ((header *)pucInBuffer)->Revision != (short)VERSION_NUMBER) { // The file is an older version, convert it to current format. // The returned value can be DefaultVidset, NULL, or a pointer // to a character buffer allocated by the conversion routine. if ( !(mgainf = mtxConvertMgaInf(pucInBuffer)) || (mgainf == DefaultVidset) ) { // The returned value was NULL or DefaultVidset. mgainf = adjustDefaultVidset(); } } else { // The file is in the current format. // Allocate memory for the input buffer. mgainf = (PUCHAR)AllocateSystemMemory(ulSizeOfBuffer); if (mgainf == NULL) { // The memory allocation failed, use the default set. mgainf = adjustDefaultVidset(); } else { // The memory allocation was successful, copy the buffer. VideoPortMoveMemory(mgainf, pucInBuffer, ulSizeOfBuffer); } } // At this point, mgainf points to DefaultVidset or to the // MGA.INF information, in the current version format. if (mgainf != DefaultVidset) { // We are not looking at the default vidset. if ((selectMgaInfoBoard() == NULL) || (strncmp(mgainf, "Matrox MGA Setup file", 21) != 0)) { // The MGA.INF file is incomplete or corrupted. VideoDebugPrint((1, "MGA.SYS!MgaStartIO - Incomplete MGA.INF file, using default\n")); // Either memory was allocated for the input buffer, or // memory was allocated by mtxConvertMgaInf. Free it. VideoPortReleaseBuffer(pMgaDeviceExtension, mgainf); // Make sure that we won't try to update MGA.INF. ulNewInfoSize = 0; // And use the default set. mgainf = adjustDefaultVidset(); } } } // At this point, mgainf points to DefaultVidset or to the // validated MGA.INF information, in the current version format. // Record the mgainf value, in case we need it later. pucNewInfo = mgainf; // Set the length of the file to be updated. *(PULONG)(RequestPacket->OutputBuffer) = ulNewInfoSize; // And don't forget to set this to the appropriate length! RequestPacket->StatusBlock->Information = sizeof(ULONG); break; // end MTX_INITIALIZE_MGA #endif // #if 0 /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_INIT_MODE_LIST | | This will normally be the second or third call made to MgaStartIO. | We call mtxCheckHwAll() and we fill in our MgaDeviceExtension | structure with mode information for each board we found. From | this, we build a series of MULTI_MODE structures describing each | 'super-mode', starting at MgaDeviceExtension->pSuperModes, and | we set the total number of supported modes in | MgaDeviceExtension->NumberOfSuperModes. | | The miniport driver builds a default list of modes (using the | default vidset) at HwFindAdapter time. The default list will | be discarded when the user-mode driver calls INIT_MODE_LIST | explicitly. When the BASEVIDEO driver calls QUERY_NUM_AVAIL_MODES | without first calling INIT_MODE_LIST, the default list will be | used. \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_INIT_MODE_LIST: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_INIT_MODE_LIST\n")); //DbgBreakPoint(); status = MgaInitModeList(MgaDeviceExtension); break; // end MTX_INIT_MODE_LIST /*------------------------------------------------------------------*\ | Special service: MTX_GET_UPDATED_INF | | This service will be called if a non-zero file size was returned | by MTX_INITIALIZE_MGA. It will return the updated MGA.INF | contents to the user-mode driver. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_GET_UPDATED_INF: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_GET_UPDATED_INF\n")); //DbgBreakPoint(); if (ulNewInfoSize == 0) { status = NO_ERROR; break; } pucOutBuffer = (PUCHAR)(RequestPacket->OutputBuffer); ulSizeOfBuffer = RequestPacket->OutputBufferLength; if (ulSizeOfBuffer < ulNewInfoSize) { // Not enough room reserved for the file contents. status = ERROR_INSUFFICIENT_BUFFER; } else { // We should be able to copy our data. VideoPortMoveMemory(pucOutBuffer, pucNewInfo, ulNewInfoSize); // And don't forget to set this to the appropriate length! RequestPacket->StatusBlock->Information = ulNewInfoSize; status = NO_ERROR; } break; // end MTX_GET_UPDATED_INF /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES | | The MGA user-mode drivers will call this very early in their | initialization sequence, probably right after MTX_INITIALIZE_MGA. | This will return the number of video modes supported by the | adapter by filling out a VIDEO_NUM_MODES structure. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - QUERY_NUM_AVAIL_MODES\n")); //DbgBreakPoint(); // Find out the size of the data to be put in the the buffer and // return that in the status information (whether or not the // information is there). // If the buffer passed in is not large enough return an appropriate // error code. if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(VIDEO_NUM_MODES))) { status = ERROR_INSUFFICIENT_BUFFER; } else { if (MgaDeviceExtension->NumberOfSuperModes == 0) { // No modes are listed so far, try to make up the list. iBoard = 0; if (mgainf == NULL) { // No vidset yet, use the default one. mgainf = adjustDefaultVidset(); } // Call the service. MgaInitModeList(MgaDeviceExtension); // If an error occurred, NumberOfSuperModes will be zero; // otherwise, it will be the appropriate number of modes. } ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)->NumModes = MgaDeviceExtension->NumberOfSuperModes; ((PVIDEO_NUM_MODES)RequestPacket->OutputBuffer)-> ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION); status = NO_ERROR; } break; // end QUERY_NUM_AVAIL_MODES /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_QUERY_AVAIL_MODES | | The MGA user-mode drivers will call this very early in their | initialization sequence, just after QUERY_NUM_AVAIL_MODES. | This will return return information about each video mode | supported by the adapter (including modes that require more than | one board if more than one are present) by filling out an array | of VIDEO_MODE_INFORMATION structures. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_QUERY_AVAIL_MODES: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - QUERY_AVAIL_MODES\n")); //DbgBreakPoint(); if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = MgaDeviceExtension->NumberOfSuperModes * sizeof(VIDEO_MODE_INFORMATION)) ) { status = ERROR_INSUFFICIENT_BUFFER; } else { modeInformation = RequestPacket->OutputBuffer; // Fill in a VIDEO_MODE_INFORMATION struc for each available mode. pCurMulti = MgaDeviceExtension->pSuperModes; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } for (i = 0; i < MgaDeviceExtension->NumberOfSuperModes; i++) { // Fill in common values that apply to all modes modeInformation[i] = CommonVideoModeInformation; // Fill in mode specific informations modeInformation[i].ModeIndex = pCurMulti->MulModeNumber; modeInformation[i].VisScreenWidth = pCurMulti->MulWidth; modeInformation[i].VisScreenHeight= pCurMulti->MulHeight; modeInformation[i].ScreenStride = pCurMulti->MulWidth * pCurMulti->MulPixWidth / 8; modeInformation[i].BitsPerPlane = pCurMulti->MulPixWidth; modeInformation[i].Frequency = pCurMulti->MulRefreshRate; // XMillimeter and YMillimeter will be modified by the user- // mode driver. // If we're in TrueColor mode, then set RGB masks if ((modeInformation[i].BitsPerPlane == 32) || (modeInformation[i].BitsPerPlane == 24)) { // This makes 32 bpp look like 24 to the display driver modeInformation[i].BitsPerPlane = 24; modeInformation[i].RedMask = 0x00FF0000; modeInformation[i].GreenMask = 0x0000FF00; modeInformation[i].BlueMask = 0x000000FF; modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS; } else if (modeInformation[i].BitsPerPlane == 16) { modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS; if (pCurMulti->MulHwModes[0]->DispType & DISPTYPE_M565) { modeInformation[i].RedMask = 0x0000F800; modeInformation[i].GreenMask = 0x000007E0; modeInformation[i].BlueMask = 0x0000001F; } else { modeInformation[i].RedMask = 0x00007C00; modeInformation[i].GreenMask = 0x000003E0; modeInformation[i].BlueMask = 0x0000001F; modeInformation[i].AttributeFlags |= VIDEO_MODE_555; modeInformation[i].BitsPerPlane = 15; } } else { modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS | VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE; } if (pCurMulti->MulHwModes[0]->ZBuffer) { // This is a 3D mode. modeInformation[i].AttributeFlags |= VIDEO_MODE_3D; } // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For each of them... for (n = 0; n < CurrentResNbBoards; n++) { // Point to the mode information structure. pMgaDispMode = pCurMulti->MulHwModes[n]; // For now, don't disclose whether we're interlaced. //if (pMgaDispMode->DispType & TYPE_INTERLACED) //{ // modeInformation[i].AttributeFlags |= // VIDEO_MODE_INTERLACED; //} // Figure out the width and height of the video memory bitmap MaxWidth = pMgaDispMode->DispWidth; MaxHeight = pMgaDispMode->DispHeight; pMgaOffScreenData = pMgaDispMode->pOffScr; for (j = 0; j < pMgaDispMode->NumOffScr; j++) { if ((usTemp=(pMgaOffScreenData[j].XStart + pMgaOffScreenData[j].Width)) > MaxWidth) MaxWidth=usTemp; if ((usTemp=(pMgaOffScreenData[j].YStart + pMgaOffScreenData[j].Height)) > MaxHeight) MaxHeight=usTemp; } modeInformation[i].VideoMemoryBitmapWidth = MaxWidth; modeInformation[i].VideoMemoryBitmapHeight= MaxHeight; } pCurMulti++; } status = NO_ERROR; } break; // end QUERY_AVAIL_MODES /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_SET_CURRENT_MODE | | The MGA user-mode drivers will probably call this service right | after QUERY_AVAIL_MODES. This will set the adapter to the mode | specified by VIDEO_MODE. If more than one board are involved | in the mode, each one will be set to the appropriate mode. We | want to take care not to re-program the mode already current. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_SET_CURRENT_MODE: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - SET_CURRENT_MODE\n")); //DbgBreakPoint(); ModeInit = *(ULONG *)(RequestPacket->InputBuffer); if (MgaDeviceExtension->SuperModeNumber == ModeInit) { // The requested mode is already the current mode status = NO_ERROR; break; } // Save the current board, because this service will modify it. iCurBoard = iBoard; pCurBaseAddr = pMgaBaseAddr; // Check to see if we have a valid ModeNumber. if (ModeInit >= MgaDeviceExtension->NumberOfSuperModes) { // If the mode number is invalid, choose the first one. ModeInit = 0; } MgaDeviceExtension->SuperModeNumber = ModeInit; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } #if DBG VideoDebugPrint((1, "MGA.SYS!MgaStartIO - Requested mode: %u\n", ModeInit)); VideoDebugPrint((1, "ModeNumber Width Height PW X Y n mo pHwMode\n")); VideoDebugPrint((1, "0x%08x % 6d % 6d % 3d % 3d % 3d\n", pCurMulti->MulModeNumber, pCurMulti->MulWidth, pCurMulti->MulHeight, pCurMulti->MulPixWidth, pCurMulti->MulArrayWidth, pCurMulti->MulArrayHeight)); j = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; for (n = 0; n < j; n++) { VideoDebugPrint((1, " %d %02x 0x%08x\n", pCurMulti->MulBoardNb[n], pCurMulti->MulBoardMode[n], pCurMulti->MulHwModes[n])); } //DbgBreakPoint(); #endif // Use info for the first board to set a few Registry values. iBoard = pCurMulti->MulBoardNb[0]; switch((Hw[iBoard].ProductRev >> 4) & 0x0000000f) { case TITAN_CHIP: pwszChip = L"MGA (A2681700)"; cbChip = sizeof(L"MGA (A2681700)"); break; case ATLAS_CHIP: pwszChip = L"MGA (A2681701)"; cbChip = sizeof(L"MGA (A2681701)"); break; case ATHENA_CHIP: pwszChip = L"MGA (A2681702)"; cbChip = sizeof(L"MGA (A2681702)"); break; default: pwszChip = L"MGA (Unspecified)"; cbChip = sizeof(L"MGA (Unspecified)"); break; } switch(Hw[iBoard].DacType) { case BT482: pwszDAC = L"Brooktree Bt482"; cbDAC = sizeof(L"Brooktree Bt482"); break; case BT485: pwszDAC = L"Brooktree Bt485"; cbDAC = sizeof(L"Brooktree Bt485"); break; case PX2085: pwszDAC = L"Cirrus Logic PX2085"; cbDAC = sizeof(L"Cirrus Logic PX2085"); break; case VIEWPOINT: pwszDAC = L"TI TVP3020"; cbDAC = sizeof(L"TI TVP3020"); break; case TVP3026: pwszDAC = L"TI TVP3026"; cbDAC = sizeof(L"TI TVP3026"); break; default: pwszDAC = L"Unknown"; cbDAC = sizeof(L"Unknown"); break; } AdapterMemorySize = Hw[iBoard].VramAvail + Hw[iBoard].DramAvail; if ((Hw[iBoard].ProductType & 0x0f) == BOARD_MGA_RESERVED) { MgaDeviceExtension->BoardId = TYPE_QVISION_PCI; // This is a Compaq board. if (Hw[iBoard].DacType == PX2085) { pwszAdapterString = L"QVision 2000"; cbAdapterString = sizeof(L"QVision 2000"); } else if (Hw[iBoard].DacType == TVP3026) { pwszAdapterString = L"QVision 2000+"; cbAdapterString = sizeof(L"QVision 2000+"); } else { MgaDeviceExtension->BoardId = TYPE_QVISION_ISA; pwszAdapterString = L"Compaq Unknown"; cbAdapterString = sizeof(L"Compaq Unknown"); } } else { MgaDeviceExtension->BoardId = TYPE_MATROX; switch(Hw[iBoard].ProductType >> 16) { case MGA_ULTIMA: pwszAdapterString = L"Ultima"; cbAdapterString = sizeof(L"Ultima"); break; case MGA_ULTIMA_VAFC: pwszAdapterString = L"Ultima VAFC"; cbAdapterString = sizeof(L"Ultima VAFC"); break; case MGA_ULTIMA_PLUS: pwszAdapterString = L"Ultima Plus"; cbAdapterString = sizeof(L"Ultima Plus"); break; case MGA_ULTIMA_PLUS_200: pwszAdapterString = L"Ultima Plus 200"; cbAdapterString = sizeof(L"Ultima Plus 200"); break; case MGA_IMPRESSION_PLUS: pwszAdapterString = L"Impression Plus"; cbAdapterString = sizeof(L"Impression Plus"); break; case MGA_IMPRESSION_PLUS_200: pwszAdapterString = L"Impression Plus 200"; cbAdapterString = sizeof(L"Impression Plus 200"); break; case MGA_IMPRESSION: pwszAdapterString = L"Impression"; cbAdapterString = sizeof(L"Impression"); break; case MGA_IMPRESSION_PRO: pwszAdapterString = L"Impression PRO"; cbAdapterString = sizeof(L"Impression PRO"); break; case MGA_IMPRESSION_LTE: pwszAdapterString = L"Impression Lite"; cbAdapterString = sizeof(L"Impression Lite"); break; default: pwszAdapterString = L"Unknown"; cbAdapterString = sizeof(L"Unknown"); break; } } VideoPortSetRegistryParameters(MgaDeviceExtension, L"HardwareInformation.ChipType", pwszChip, cbChip); VideoPortSetRegistryParameters(MgaDeviceExtension, L"HardwareInformation.DacType", pwszDAC, cbDAC); VideoPortSetRegistryParameters(MgaDeviceExtension, L"HardwareInformation.MemorySize", &AdapterMemorySize, sizeof(ULONG)); VideoPortSetRegistryParameters(MgaDeviceExtension, L"HardwareInformation.AdapterString", pwszAdapterString, cbAdapterString); // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For each of them... for (n = 0; n < CurrentResNbBoards; n++) { // Point to the mode information structure. pMgaDispMode = pCurMulti->MulHwModes[n]; // Make the board current. iBoard = pCurMulti->MulBoardNb[n]; pMgaBaseAddr = MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard]; // If the board is mapped at 0x000AC000, we must set the // MAP SEL 1 bit of the VGA MISC register to have the TITAN // mapped. if (Hw[iBoard].MapAddress == 0x000AC000) { // Select VGA MISC register (Index 6) VideoPortWritePortUchar(TITAN_GCTL_ADDR_PORT, (UCHAR) 6); ucTemp = VideoPortReadPortUchar(TITAN_GCTL_DATA_PORT) | 0x08; VideoPortWritePortUchar(TITAN_GCTL_DATA_PORT, ucTemp); } // Reset all Titan host registers VideoPortWriteRegisterUlong((PULONG)((PUCHAR)pMgaBaseAddr + TITAN_OFFSET + TITAN_RST), 1); VideoPortStallExecution(2000); VideoPortWriteRegisterUlong((PULONG)((PUCHAR)pMgaBaseAddr + TITAN_OFFSET + TITAN_RST), 0); // Set the graphics mode from the available hardware modes. mtxSelectHwMode(pMgaDispMode); // Select the display mode. // Pass the frequency in the last byte of the ZOOM factor ZoomFactor = (pCurMulti->MulRefreshRate << 24) | ZOOM_X1; mtxSetDisplayMode(pMgaDispMode, ZoomFactor); // Set the cursor colors to white and black. MgaSetCursorColour(MgaDeviceExtension, 0xFFFFFF, 0x000000); // Set the MCtlWtSt register. VideoPortWriteRegisterUlong((PULONG)((PUCHAR)pMgaBaseAddr + TITAN_OFFSET + TITAN_MCTLWTST), (ULONG)MCTLWTST_STD); } // Restore the current board to what it used to be. iBoard = iCurBoard; pMgaBaseAddr = pCurBaseAddr; // At this point, the RAMDAC should be okay, but it looks // like it's not quite ready to accept data, particularly // on VL boards. Adding a delay seems to fix things. VideoPortStallExecution(100); // Microseconds status = NO_ERROR; break; // end SET_CURRENT_MODE /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_BOARD_ARRAY | | The MGA user-mode drivers will probably call this service after | the mode has been set by SET_CURRENT_MODE. The user-mode drivers | have to know how the boards are arrayed to make up the display | surface, so that they know which board to address when writing | to a specific (x, y) position. The miniport driver knows this, | since it has just set the mode. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_BOARD_ARRAY: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_BOARD_ARRAY\n")); //DbgBreakPoint(); // If the buffer passed in is not large enough return an appropriate // error code. if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(SIZEL))) { status = ERROR_INSUFFICIENT_BUFFER; } else { if(MgaDeviceExtension->SuperModeNumber == 0xFFFFFFFF) { // No mode has been selected yet, so we don't know... status = ERROR_DEV_NOT_EXIST; } else { ModeInit = MgaDeviceExtension->SuperModeNumber; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } ((SIZEL*)RequestPacket->OutputBuffer)->cx = pCurMulti->MulArrayWidth; ((SIZEL*)RequestPacket->OutputBuffer)->cy = pCurMulti->MulArrayHeight; status = NO_ERROR; } } break; // end MTX_QUERY_BOARD_ARRAY /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_MAKE_BOARD_CURRENT | | The MGA user-mode drivers will call this service whenever a | miniport operation need be executed on a particular board, as | opposed to every single board involved in the current mode. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_MAKE_BOARD_CURRENT: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_MAKE_BOARD_CURRENT\n")); //DbgBreakPoint(); n = *(ULONG *)(RequestPacket->InputBuffer); // Check to see if we have a valid board number. i = MgaDeviceExtension->SuperModeNumber; if (i == 0xFFFFFFFF) { status = ERROR_DEV_NOT_EXIST; break; } pCurMulti = &MgaDeviceExtension->pSuperModes[i]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } if (n >= (ULONG)(pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight)) { status = ERROR_DEV_NOT_EXIST; } else { // Make the board current. CONVERT_BOARD_NUMBER(n); iBoard = pCurMulti->MulBoardNb[n]; pMgaBaseAddr = MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard]; status = NO_ERROR; } break; // end MTX_MAKE_BOARD_CURRENT /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_BOARD_ID | | This service returns the board type information to the user-mode | driver. A call to MTX_MAKE_BOARD_CURRENT must have been made | previously to set which board is to be queried. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_BOARD_ID: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_BOARD_ID\n")); //DbgBreakPoint(); if (RequestPacket->OutputBufferLength < sizeof(ULONG)) { // Not enough room reserved for the board ID. status = ERROR_INSUFFICIENT_BUFFER; } else { *((PULONG)(RequestPacket->OutputBuffer)) = ProductMGA[iBoard]; // And don't forget to set this to the appropriate length! RequestPacket->StatusBlock->Information = sizeof(ULONG); status = NO_ERROR; } break; // end MTX_QUERY_BOARD_ID /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_HW_DATA | | This service returns hardware information about the current | board by filling out a HW_DATA structure. A call to | MTX_MAKE_BOARD_CURRENT must have been made previously to set | which board is to be queried. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_HW_DATA: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_HW_DATA\n")); //DbgBreakPoint(); // Check if we have a sufficient output buffer if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(HW_DATA))) { status = ERROR_INSUFFICIENT_BUFFER; } else { register PHW_DATA pUserModeHwData; register HwData *pMiniportHwData; pUserModeHwData = RequestPacket->OutputBuffer; pMiniportHwData = &Hw[iBoard]; pUserModeHwData->MapAddress = pMiniportHwData->MapAddress; pUserModeHwData->ProductType = pMiniportHwData->ProductType; pUserModeHwData->ProductRev = pMiniportHwData->ProductRev; pUserModeHwData->ShellRev = pMiniportHwData->ShellRev; pUserModeHwData->BindingRev = pMiniportHwData->BindingRev; pUserModeHwData->VGAEnable = pMiniportHwData->VGAEnable; pUserModeHwData->Sync = pMiniportHwData->Sync; pUserModeHwData->Device8_16 = pMiniportHwData->Device8_16; pUserModeHwData->PortCfg = pMiniportHwData->PortCfg; pUserModeHwData->PortIRQ = pMiniportHwData->PortIRQ; pUserModeHwData->MouseMap = pMiniportHwData->MouseMap; pUserModeHwData->MouseIRate = pMiniportHwData->MouseIRate; pUserModeHwData->DacType = pMiniportHwData->DacType; pUserModeHwData->cursorInfo.MaxWidth = pMiniportHwData->cursorInfo.MaxWidth; pUserModeHwData->cursorInfo.MaxHeight = pMiniportHwData->cursorInfo.MaxHeight; pUserModeHwData->cursorInfo.MaxDepth = pMiniportHwData->cursorInfo.MaxDepth; pUserModeHwData->cursorInfo.MaxColors = pMiniportHwData->cursorInfo.MaxColors; pUserModeHwData->cursorInfo.CurWidth = pMiniportHwData->cursorInfo.CurWidth; pUserModeHwData->cursorInfo.CurHeight = pMiniportHwData->cursorInfo.CurHeight; pUserModeHwData->cursorInfo.cHotSX = pMiniportHwData->cursorInfo.cHotSX; pUserModeHwData->cursorInfo.cHotSY = pMiniportHwData->cursorInfo.cHotSY; pUserModeHwData->cursorInfo.HotSX = pMiniportHwData->cursorInfo.HotSX; pUserModeHwData->cursorInfo.HotSY = pMiniportHwData->cursorInfo.HotSY; pUserModeHwData->VramAvail = pMiniportHwData->VramAvail; pUserModeHwData->DramAvail = pMiniportHwData->DramAvail; pUserModeHwData->CurrentOverScanX = pMiniportHwData->CurrentOverScanX; pUserModeHwData->CurrentOverScanY = pMiniportHwData->CurrentOverScanY; pUserModeHwData->YDstOrg = pMiniportHwData->YDstOrg; status = NO_ERROR; } break; // end MTX_QUERY_HW_DATA /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_NUM_OFFSCREEN_BLOCKS | | This service returns the number of offscreen memory areas | available for the requested super-mode. A call to | MTX_MAKE_BOARD_CURRENT must have been made previously to set | which board is to be queried. | | Input: A pointer to a VIDEO_MODE_INFORMATION structure, as | returned by a QUERY_AVAIL_MODES request. | | Output: A pointer to a VIDEO_NUM_OFFSCREEN_BLOCKS structure, as | defined below. | | The calling routine will have allocated the memory for the | VIDEO_NUM_OFFSCREEN_BLOCKS structure. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_NUM_OFFSCREEN_BLOCKS: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_NUM_OFFSCREEN_BLOCKS\n")); //DbgBreakPoint(); // Verify that input & output buffers are the correct sizes if ( (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(VIDEO_NUM_OFFSCREEN_BLOCKS))) || (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE_INFORMATION)) ) { status = ERROR_INSUFFICIENT_BUFFER; } else { PVIDEO_NUM_OFFSCREEN_BLOCKS pVideoNumOffscreenBlocks = RequestPacket->OutputBuffer; // Get the super-mode number the user-mode driver is asking about. modeInformation = RequestPacket->InputBuffer; ModeInit = modeInformation->ModeIndex; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Look for the current board. i = 0; while ((i < NB_BOARD_MAX) && (pCurMulti->MulBoardNb[i] != iBoard)) i++; // Point to the appropriate hw mode. pMgaDispMode = pCurMulti->MulHwModes[i]; // Fill out NumBlocks. pVideoNumOffscreenBlocks->NumBlocks = pMgaDispMode->NumOffScr; // Fill out OffScreenBlockLength. pVideoNumOffscreenBlocks->OffscreenBlockLength = sizeof(OFFSCREEN_BLOCK); status = NO_ERROR; } break; // end MTX_QUERY_NUM_OFFSCREEN_BLOCKS /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_OFFSCREEN_BLOCKS | | This service returns a description of each offscreen memory area | available for the requested super-mode. A call to | MTX_MAKE_BOARD_CURRENT must have been made previously to set | which board is to be queried. | | Input: A pointer to a VIDEO_MODE_INFORMATION structure, as | returned by a QUERY_AVAIL_MODES request. | | Output: A pointer to the first of a series of OFFSCREEN_BLOCK | structures, as defined below. | | The calling routine will have allocated the memory for the | OFFSCREEN_BLOCK structures. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_OFFSCREEN_BLOCKS: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_OFFSCREEN_BLOCKS\n")); //DbgBreakPoint(); // Verify that the input buffer is the correct size. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE_INFORMATION)) { status = ERROR_INSUFFICIENT_BUFFER; } else { UCHAR NumOffScrBlocks; OffScrData *pOffScrDataArray; POFFSCREEN_BLOCK pOffscreenBlockArray = RequestPacket->OutputBuffer; // Get the super-mode number the user-mode driver is asking about. modeInformation = RequestPacket->InputBuffer; ModeInit = modeInformation->ModeIndex; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Look for the current board. i = 0; while ((i < NB_BOARD_MAX) && (pCurMulti->MulBoardNb[i] != iBoard)) i++; // Point to the appropriate hw mode. pMgaDispMode = pCurMulti->MulHwModes[i]; NumOffScrBlocks = pMgaDispMode->NumOffScr; // Verify that the output buffer is the correct size. if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = NumOffScrBlocks * sizeof(OFFSCREEN_BLOCK))) { status = ERROR_INSUFFICIENT_BUFFER; } else { // Fill the OFFSCREEN_BLOCK structures pOffScrDataArray = pMgaDispMode->pOffScr; for (i = 0; i < NumOffScrBlocks; i++) { pOffscreenBlockArray[i].Type =pOffScrDataArray[i].Type; pOffscreenBlockArray[i].XStart=pOffScrDataArray[i].XStart; pOffscreenBlockArray[i].YStart=pOffScrDataArray[i].YStart; pOffscreenBlockArray[i].Width =pOffScrDataArray[i].Width; pOffscreenBlockArray[i].Height=pOffScrDataArray[i].Height; pOffscreenBlockArray[i].SafePlanes = pOffScrDataArray[i].SafePlanes; pOffscreenBlockArray[i].ZOffset = pOffScrDataArray[i].ZXStart; } status = NO_ERROR; } } break; // end MTX_QUERY_OFFSCREEN_BLOCKS /*------------------------------------------------------------------*\ | Special service: IOCTL_VIDEO_MTX_QUERY_RAMDAC_INFO | | This service returns information about the type and capabilities | of the installed ramdac by filling out a RAMDAC_INFO structure. | A call to MTX_MAKE_BOARD_CURRENT must have been made previously | to set which board is to be queried. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MTX_QUERY_RAMDAC_INFO: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MTX_QUERY_RAMDAC_INFO\n")); //DbgBreakPoint(); // Check if we have a sufficient output buffer if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(RAMDAC_INFO))) { status = ERROR_INSUFFICIENT_BUFFER; } else { pVideoPointerAttributes=RequestPacket->OutputBuffer; pVideoPointerAttributes->Flags = RAMDAC_NONE; pVideoPointerAttributes->OverScanX = Hw[iBoard].CurrentOverScanX; pVideoPointerAttributes->OverScanY = Hw[iBoard].CurrentOverScanY; if (Hw[iBoard].DacType == DacTypeBT482) { pVideoPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER | RAMDAC_BT482; pVideoPointerAttributes->Width = 32; pVideoPointerAttributes->Height = 32; } if (Hw[iBoard].DacType == DacTypeBT485) { pVideoPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER | RAMDAC_BT485; pVideoPointerAttributes->Width = 64; pVideoPointerAttributes->Height = 64; } if (Hw[iBoard].DacType == DacTypePX2085) { pVideoPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER | RAMDAC_PX2085; pVideoPointerAttributes->Width = 64; pVideoPointerAttributes->Height = 64; } if (Hw[iBoard].DacType == DacTypeVIEWPOINT) { pVideoPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER | RAMDAC_VIEWPOINT; pVideoPointerAttributes->Width = 64; pVideoPointerAttributes->Height = 64; } if (Hw[iBoard].DacType == DacTypeTVP3026) { pVideoPointerAttributes->Flags = VIDEO_MODE_MONO_POINTER | RAMDAC_TVP3026; pVideoPointerAttributes->Width = 64; pVideoPointerAttributes->Height = 64; } status = NO_ERROR; } break; // end MTX_QUERY_RAMDAC_INFO /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES | | This service will return the address ranges used by the user-mode | drivers to program the video hardware directly, by filling out | a VIDEO_PUBLIC_ACCESS_RANGES structure. A call to | MTX_MAKE_BOARD_CURRENT must have been made previously to set | which board is to be accessed. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_QUERY_PUBLIC_ACCESS_RANGES: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - QUERY_PUBLIC_ACCESS_RANGES\n")); //DbgBreakPoint(); // Make sure the output buffer is big enough. if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(VIDEO_PUBLIC_ACCESS_RANGES))) { status = ERROR_INSUFFICIENT_BUFFER; } else { // Fill out the VIDEO_PUBLIC_ACCESS_RANGES buffer. publicAccessRanges = RequestPacket->OutputBuffer; ulWindowLength = MgaDriverAccessRange[iBoard*2].RangeLength; publicAccessRanges->InIoSpace = MgaDriverAccessRange[iBoard*2].RangeInIoSpace; publicAccessRanges->MappedInIoSpace = MgaDriverAccessRange[iBoard*2].RangeInIoSpace; publicAccessRanges->VirtualAddress = (PVOID) NULL; // Any virtual address status = VideoPortMapMemory( MgaDeviceExtension, MgaDriverAccessRange[iBoard*2].RangeStart, &ulWindowLength, &(publicAccessRanges->InIoSpace), &(publicAccessRanges->VirtualAddress) ); MgaDeviceExtension->UserModeMappedBaseAddress[iBoard] = publicAccessRanges->VirtualAddress; } break; // end QUERY_PUBLIC_ACCESS_RANGES /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_SET_COLOR_REGISTERS | | This service sets the adapter's color registers to the specified | RGB values. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_SET_COLOR_REGISTERS: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - SET_COLOR_REGISTERS\n")); //DbgBreakPoint(); if ((ModeInit = MgaDeviceExtension->SuperModeNumber) == 0xFFFFFFFF) { status = ERROR_DEV_NOT_EXIST; break; } pclutBuffer = RequestPacket->InputBuffer; // Save the current board, because this service will modify it. iCurBoard = iBoard; pCurBaseAddr = pMgaBaseAddr; status = NO_ERROR; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For each of them... for (n = 0; n < CurrentResNbBoards; n++) { // Point to the mode information structure. pMgaDispMode = pCurMulti->MulHwModes[n]; // Make the board current. iBoard = pCurMulti->MulBoardNb[n]; pMgaBaseAddr = MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard]; status |= MgaSetColorLookup(MgaDeviceExtension, (PVIDEO_CLUT) RequestPacket->InputBuffer, RequestPacket->InputBufferLength); } // Restore the current board to what it used to be. iBoard = iCurBoard; pMgaBaseAddr = pCurBaseAddr; break; // end SET_COLOR_REGISTERS /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES | | This service will release the address ranges used by the user-mode | drivers to program the video hardware. In the S3 code, and in | the DDK reference, it is said that the input buffer should | contain an array of VIDEO_PUBLIC_ACCESS_RANGES to be released. | However, I did not get anything in the input buffer when I traced | through the code. Instead, I have observed that SET_CURRENT_MODE | had been called, so that there is a current valid mode. We will | simply free the access ranges not required by the current mode. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_FREE_PUBLIC_ACCESS_RANGES: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - FREE_PUBLIC_ACCESS_RANGES\n")); //DbgBreakPoint(); // Make sure the input buffer is big enough. if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) { // The input buffer is not large enough. // Assume all will be right. status = NO_ERROR; ModeInit = MgaDeviceExtension->SuperModeNumber; if(ModeInit == 0xFFFFFFFF) { // No mode has been selected yet, so we'll free everything. // For every board... for (i = 0; i< NbBoard; i++) { if (MgaDeviceExtension->UserModeMappedBaseAddress[i]) { // This board has a non-null user-mode base address. // Fill out the VIDEO_PUBLIC_ACCESS_RANGES buffer. publicAccessRanges=RequestPacket->OutputBuffer; publicAccessRanges->InIoSpace = 0; // Not in I/O space publicAccessRanges->MappedInIoSpace = 0; // Not in I/O space publicAccessRanges->VirtualAddress = MgaDeviceExtension->UserModeMappedBaseAddress[i]; status |= VideoPortUnmapMemory( MgaDeviceExtension, publicAccessRanges->VirtualAddress, 0); // Reset the user-mode base address. MgaDeviceExtension->UserModeMappedBaseAddress[i] = 0; } } } else { // We know our current mode. // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For every board... for (i = 0; i< NbBoard; i++) { // Check whether it's used by the current mode. n = 0; while ((n < CurrentResNbBoards) && (pCurMulti->MulBoardNb[n] != i)) n++; if ((n == CurrentResNbBoards) && (MgaDeviceExtension->UserModeMappedBaseAddress[i])) { // We went through the list, the board is not in use, // and the board has a non-null user-mode base address. // Fill out the VIDEO_PUBLIC_ACCESS_RANGES buffer. publicAccessRanges=RequestPacket->OutputBuffer; publicAccessRanges->InIoSpace = 0; // Not in I/O space publicAccessRanges->MappedInIoSpace = 0; // Not in I/O space publicAccessRanges->VirtualAddress = MgaDeviceExtension->UserModeMappedBaseAddress[i]; status |= VideoPortUnmapMemory( MgaDeviceExtension, publicAccessRanges->VirtualAddress, 0); // Reset the user-mode base address. MgaDeviceExtension->UserModeMappedBaseAddress[i] = 0; } } } } else { // The input buffer is large enough, use it. status = VideoPortUnmapMemory(MgaDeviceExtension, ((PVIDEO_MEMORY) (RequestPacket->InputBuffer))-> RequestedVirtualAddress, 0); } break; // end FREE_PUBLIC_ACCESS_RANGES /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_MAP_VIDEO_MEMORY | | This service maps the frame buffer and VRAM into the virtual | address space of the requestor. For now, we'll just return NULL | addresses and lengths. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_MAP_VIDEO_MEMORY: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - MAP_VIDEO_MEMORY\n")); //DbgBreakPoint(); if ( (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION))) || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) { status = ERROR_INSUFFICIENT_BUFFER; } else { memoryInformation = RequestPacket->OutputBuffer; memoryInformation->VideoRamBase = 0; memoryInformation->VideoRamLength = 0; memoryInformation->FrameBufferBase = 0; memoryInformation->FrameBufferLength = 0; status = NO_ERROR; } break; // end MAP_VIDEO_MEMORY /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_UNMAP_VIDEO_MEMORY | | This service releases mapping of the frame buffer and VRAM from | the virtual address space of the requestor. For now, we'll just | do nothing. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - UNMAP_VIDEO_MEMORY\n")); //DbgBreakPoint(); if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) { status = ERROR_INSUFFICIENT_BUFFER; } else { status = NO_ERROR; } break; /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_QUERY_CURRENT_MODE | | This service returns information about the current video mode | by filling out a VIDEO_MODE_INFORMATION structure. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_QUERY_CURRENT_MODE: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - QUERY_CURRENT_MODE\n")); //DbgBreakPoint(); if (RequestPacket->OutputBufferLength < (RequestPacket->StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION)) ) { status = ERROR_INSUFFICIENT_BUFFER; } else { modeInformation = RequestPacket->OutputBuffer; // Fill in a VIDEO_MODE_INFORMATION struc for the mode indicated // by MgaDeviceExtension->SuperModeNumber i = MgaDeviceExtension->SuperModeNumber; if (i == 0xFFFFFFFF) { status = ERROR_DEV_NOT_EXIST; break; } pCurMulti = &MgaDeviceExtension->pSuperModes[i]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Fill in common values that apply to all modes. *modeInformation=CommonVideoModeInformation; // Fill in mode specific informations. modeInformation->ModeIndex = pCurMulti->MulModeNumber; modeInformation->VisScreenWidth = pCurMulti->MulWidth; modeInformation->VisScreenHeight= pCurMulti->MulHeight; modeInformation->ScreenStride = pCurMulti->MulWidth * pCurMulti->MulPixWidth / 8; modeInformation->BitsPerPlane = pCurMulti->MulPixWidth; modeInformation->Frequency = pCurMulti->MulRefreshRate; // If we're in TrueColor mode, then set RGB masks if ((modeInformation[i].BitsPerPlane == 32) || (modeInformation[i].BitsPerPlane == 24)) { modeInformation[i].RedMask = 0x00FF0000; modeInformation[i].GreenMask = 0x0000FF00; modeInformation[i].BlueMask = 0x000000FF; modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS; } else if (modeInformation[i].BitsPerPlane == 16) { modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS; if (pCurMulti->MulHwModes[0]->DispType & DISPTYPE_M565) { modeInformation[i].RedMask = 0x0000F800; modeInformation[i].GreenMask = 0x000007E0; modeInformation[i].BlueMask = 0x0000001F; } else { modeInformation[i].RedMask = 0x00007C00; modeInformation[i].GreenMask = 0x000003E0; modeInformation[i].BlueMask = 0x0000001F; modeInformation[i].AttributeFlags |= VIDEO_MODE_555; modeInformation[i].BitsPerPlane = 15; } } else { modeInformation[i].AttributeFlags = VIDEO_MODE_COLOR | VIDEO_MODE_GRAPHICS | VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE; } if (pCurMulti->MulHwModes[0]->ZBuffer) { // This is a 3D mode. modeInformation[i].AttributeFlags |= VIDEO_MODE_3D; } // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For each of them... for (n = 0; n < CurrentResNbBoards; n++) { // Point to the mode information structure. pMgaDispMode = pCurMulti->MulHwModes[n]; // For now, don't disclose whether we're interlaced. //if (pMgaDispMode->DispType & TYPE_INTERLACED) //{ // modeInformation[i].AttributeFlags |= // VIDEO_MODE_INTERLACED; //} // Figure out the width and height of the video memory bitmap MaxWidth = pMgaDispMode->DispWidth; MaxHeight = pMgaDispMode->DispHeight; pMgaOffScreenData = pMgaDispMode->pOffScr; for (j = 0; j < pMgaDispMode->NumOffScr; j++) { if ((usTemp=(pMgaOffScreenData[j].XStart + pMgaOffScreenData[j].Width)) > MaxWidth) MaxWidth=usTemp; if ((usTemp=(pMgaOffScreenData[j].YStart + pMgaOffScreenData[j].Height)) > MaxHeight) MaxHeight=usTemp; } modeInformation[i].VideoMemoryBitmapWidth = MaxWidth; modeInformation[i].VideoMemoryBitmapHeight= MaxHeight; } status = NO_ERROR; } break; // end QUERY_CURRENT_MODE /*------------------------------------------------------------------*\ | Required service: IOCTL_VIDEO_RESET_DEVICE | | This service resets the video hardware to the default mode, to | which it was initialized at system boot. | \*------------------------------------------------------------------*/ case IOCTL_VIDEO_RESET_DEVICE: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - RESET_DEVICE\n")); //DbgBreakPoint(); if ((ModeInit = MgaDeviceExtension->SuperModeNumber) == 0xFFFFFFFF) { // RESET has been done already. status = NO_ERROR; break; } // Save the current board, because this service will modify it. iCurBoard = iBoard; pCurBaseAddr = pMgaBaseAddr; // Point to the appropriate MULTI_MODE structure. pCurMulti = &MgaDeviceExtension->pSuperModes[ModeInit]; if (pCurMulti == NULL) { status = ERROR_DEV_NOT_EXIST; break; } // Number of boards involved in the current super-mode. CurrentResNbBoards = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; // For each of them... for (n = 0; n < CurrentResNbBoards; n++) { // Point to the mode information structure. pMgaDispMode = pCurMulti->MulHwModes[n]; // Make the board current. iBoard = pCurMulti->MulBoardNb[n]; pMgaBaseAddr = MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard]; // Disable the hardware cursor. mtxCursorEnable(0); if(Hw[iBoard].VGAEnable) { // This board is VGA-enabled, reset it to VGA. mtxSetVideoMode(mtxPASSTHRU); } else { // This board is not VGA-enabled. // Just clear the screen, it will look nicer. clutBufferOne.NumEntries = 1; clutBufferOne.LookupTable[0].RgbLong = 0; for (j = 0; j <= VIDEO_MAX_COLOR_REGISTER; j++) { clutBufferOne.FirstEntry = j; MgaSetColorLookup(MgaDeviceExtension, &clutBufferOne, sizeof(VIDEO_CLUT)); } // Make the cursor disappear. // MgaSetCursorColour(MgaDeviceExtension, 0, 0); } } // Signal that no mode is currently selected. MgaDeviceExtension->SuperModeNumber = 0xFFFFFFFF; if (MgaDeviceExtension->pSuperModes != (PMULTI_MODE) NULL) { // Free our allocated memory. VideoPortReleaseBuffer(pMgaDeviceExtension, MgaDeviceExtension->pSuperModes); MgaDeviceExtension->pSuperModes = (PMULTI_MODE) NULL; } MgaDeviceExtension->NumberOfSuperModes = 0; // Memory might have been allocated for mgainf. if (mgainf != DefaultVidset) { VideoPortReleaseBuffer(pMgaDeviceExtension, mgainf); // And use the default set. mgainf = adjustDefaultVidset(); } // Restore the current board to what it used to be. iBoard = iCurBoard; pMgaBaseAddr = pCurBaseAddr; status = NO_ERROR; break; // end IOCTL_VIDEO_RESET_DEVICE #if 0 case IOCTL_VIDEO_SAVE_HARDWARE_STATE: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - SAVE_HARDWARE_STATE\n")); status = ERROR_INVALID_FUNCTION; break; case IOCTL_VIDEO_RESTORE_HARDWARE_STATE: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - RESTORE_HARDWARE_STATE\n")); status = ERROR_INVALID_FUNCTION; break; case IOCTL_VIDEO_ENABLE_VDM: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - ENABLE_VDM\n")); status = ERROR_INVALID_FUNCTION; break; #endif /*------------------------------------------------------------------*\ | If we get here, an invalid IoControlCode was specified. \*------------------------------------------------------------------*/ default: VideoDebugPrint((1, "MGA.SYS!MgaStartIO - Invalid service\n")); status = ERROR_INVALID_FUNCTION; break; } RequestPacket->StatusBlock->Status = status; return TRUE; } // end MgaStartIO() /*--------------------------------------------------------------------------*\ | VP_STATUS | MgaInitModeList( | PMGA_DEVICE_EXTENSION MgaDeviceExtension) | | Routine Description: | | This routine builds the list of modes available for the detected boards. | | Arguments: | | HwDeviceExtension - Pointer to the miniport driver's device extension. | | Return Value: | | NO_ERROR, ERROR_DEV_NOT_EXIST, or ERROR_NOT_ENOUGH_MEMORY. | \*--------------------------------------------------------------------------*/ VP_STATUS MgaInitModeList( PMGA_DEVICE_EXTENSION MgaDeviceExtension) { HwModeData *pMgaDispMode, *pMgaModeData, *pCurrentMgaModeData; HwModeData *Mga2dMode[16], *Mga3dMode[16]; MULTI_MODE *pCurMulti; PULONG pulModeFlags; ULONG ulNb2DRefreshRates, ulNb3DRefreshRates, ulNbRefreshRates; ULONG VGABoard, VGABoardBit, ModePixDepth, ulModeListOffset, NbSuperModes, ResTag, ModeInit; ULONG CurrentResFlags, CurrentFlag, CurrentResWidth, CurrentResHeight, CurrentRefreshRate, CurrentResNbBoards, CurrentResNbBoards3D, CurrentPixWidth; ULONG i, k, m, n, ir, ja, i2d, i3d; VP_STATUS status; USHORT j; USHORT us2DRefreshRates, us3DRefreshRates, usRefreshRates; UCHAR ValidBoard[NB_BOARD_MAX]; UCHAR ucTestFlags, ucRefreshBit; UCHAR ucMask; BOOLEAN bSupported2dMode, bSupported3dMode; // Assume we won't have any problem. status = NO_ERROR; // Check whether we've already built a mode list. MgaDeviceExtension // is assumed to have been zeroed out when it was first given us. if (MgaDeviceExtension->NumberOfSuperModes != 0) { if (MgaDeviceExtension->pSuperModes != (PMULTI_MODE) NULL) { // Free our allocated memory. VideoPortReleaseBuffer(pMgaDeviceExtension, MgaDeviceExtension->pSuperModes); MgaDeviceExtension->pSuperModes = (PMULTI_MODE) NULL; } // Memory might have been allocated for mgainf. It's all right, // we'll want to use the current mgainf. } // Just in case we leave early... MgaDeviceExtension->NumberOfSuperModes = 0; // Get information on all the MGA boards currently installed in the // system. if ((pMgaBoardData = mtxCheckHwAll()) == NULL) { // mtxCheckHwAll should always return success, since MapBoard has // already been executed. // BUGBUG - if it never occurs, then this code isn't needed. // a better answer would be to code an ASSERT() and // write code that would handle the failure anyways VideoDebugPrint((1, "MGA.SYS!MGAStartIO failed mtxCheckHwAll\n")); status = ERROR_DEV_NOT_EXIST; return(status); } else { // There may be several MGA boards installed. Look at all of // them, and map their physical addresses into kernel space. // While we're at it, find out if any of our boards is VGA enabled. VGABoard = (ULONG)-1; VGABoardBit = 0; // No mode has been selected yet, so make this invalid. MgaDeviceExtension->SuperModeNumber = 0xFFFFFFFF; MgaDeviceExtension->pSuperModes = (PMULTI_MODE) NULL; // We don't care whether the mode is interlaced or not, because // the only modes that we'll get will be selected according to // the monitor capabilities through the mga.inf file. ucMask = (UCHAR)(~DISPTYPE_INTERLACED); // pMgaBoardData is really the address of Hw[0]. for (i = 0; i < NbBoard; i++) { MgaDeviceExtension->NumberOfModes[i] = 0; MgaDeviceExtension->NumberOfValidModes[i] = 0; MgaDeviceExtension->ModeFlags2D[i] = 0; MgaDeviceExtension->ModeFlags3D[i] = 0; // Make it clean: initialize the ModeList to an invalid mode. for (j = 0; j < 64; j++) { MgaDeviceExtension->ModeList[i][j] = 0xFF; } if (mtxSelectHw(&Hw[i]) == mtxFAIL) { // mtxSelectHw should always return success, since // MapBoard has already been executed. // BUGBUG - if it never occurs, then this code isn't needed. // a better answer would be to code an ASSERT() and // write code that would handle the failure anyways VideoDebugPrint((1, "MGA.SYS!MGAStartIO failed mtxSelectHw for board %d\n", i)); MgaDeviceExtension->KernelModeMappedBaseAddress[i] = (PVOID)0xffffffff; continue; } // MGA board i has been selected. //VideoDebugPrint((1, "MGA.SYS!MGAStartIO mapped board %d at 0x%x\n", i, pMgaBaseAddr)); //DbgPrint("MGA.SYS!MGAStartIO mapped board %d at 0x%x\n", i, pMgaBaseAddr); MgaDeviceExtension->KernelModeMappedBaseAddress[i] = pMgaBaseAddr; if (Hw[i].VGAEnable) { VGABoard = i; VGABoardBit = 1 << i; } // Set up the test flags. TITAN always supports // double-buffering, while Atlas and Athena use different // modes. if ((Hw[i].ProductRev & 0x000000F0) == 0) { // This is TITAN. ucTestFlags = DISPTYPE_DB; } else { // This is not TITAN. ucTestFlags = 0; } // Get information on all the hardware modes available for // the current MGA board. if ((pMgaModeData = mtxGetHwModes()) == NULL) { // This case never occurs. // BUGBUG - if it never occurs, then this code isn't needed. // a better answer would be to code an ASSERT() and // write code that would handle the failure anyways VideoDebugPrint((1, "MGA.SYS!MGAStartIO failed mtxGetHwModes for board %d\n", i)); continue; } // Store it in the DeviceExtension structure. MgaDeviceExtension->pMgaHwModes[i] = pMgaModeData; // Modes we may want to support: // // 2D modes ------------------------------------------------- // 8bpp, LUT // DispType = 14, ZBuffer = 0, PixWidth = 8 (Titan) // DispType = 4, ZBuffer = 0, PixWidth = 8 (others) // 16bpp, 565 // DispType = 8, ZBuffer = 0, PixWidth = 16 // 24bpp // DispType = 0, ZBuffer = 0, PixWidth = 24 (Storm only) // 32bpp // DispType = 10, ZBuffer = 0, PixWidth = 32 (Titan) // DispType = 0, ZBuffer = 0, PixWidth = 32 (others) // // 3D modes ------------------------------------------------- // 8bpp, no LUT // DispType = 10, ZBuffer = 1, PixWidth = 8 // 16bpp, 555 // DispType = 10, ZBuffer = 1, PixWidth = 16 (Mga or Storm) // OR // 16bpp, 565 // DispType = 18, ZBuffer = 1, PixWidth = 16 (Storm only) // 24bpp // DispType = 10, ZBuffer = 1, PixWidth = 24 (Storm only) // 32bpp // DispType = 10, ZBuffer = 1, PixWidth = 32 // Calculate the number of available modes for this board. // *IMPORTANT* We assume the last entry in the HwMode // array has DispWidth equal to -1. // NEW! // We do not want to support 16bpp modes here. We'll // support 5-5-5 modes, but the trick is that some of // them will be 3D modes, and the other ones will be 2D. // We have to examine the list for these. i2d = 0; i3d = 0; for (pCurrentMgaModeData = pMgaModeData; pCurrentMgaModeData->DispWidth != (word)-1; pCurrentMgaModeData++) { if (pCurrentMgaModeData->PixWidth == 16) { if (pCurrentMgaModeData->ZBuffer) { // 16bpp, Z buffer. if ((pCurrentMgaModeData->DispType & ucMask) == DISPTYPE_DB) { Mga3dMode[i3d] = pCurrentMgaModeData; i3d++; } } else { // 16bpp, no Z buffer. if ((pCurrentMgaModeData->DispType & ucMask) == ucTestFlags) { Mga2dMode[i2d] = pCurrentMgaModeData; i2d++; } } } } for (m = 0; m < i2d; m++) { // Examine one of the 2D modes. bSupported2dMode = TRUE; pCurrentMgaModeData = Mga2dMode[m]; CurrentResWidth = pCurrentMgaModeData->DispWidth; CurrentResHeight = pCurrentMgaModeData->DispHeight; // Look for a similar 3D mode. for (k = 0; k < i3d; k++) { pCurrentMgaModeData = Mga3dMode[k]; if ((pCurrentMgaModeData->DispWidth == CurrentResWidth ) && (pCurrentMgaModeData->DispHeight== CurrentResHeight)) { // The current 2D mode is simlar to a 3D mode, // we want to reject this 2D mode. bSupported2dMode = FALSE; break; } } if (bSupported2dMode == TRUE) { // We want to keep this one, so remove it from the // checklist. Mga2dMode[m] = 0; } } for (pCurrentMgaModeData = pMgaModeData; pCurrentMgaModeData->DispWidth != (word)-1; pCurrentMgaModeData++) { // Update the total number of modes supported. MgaDeviceExtension->NumberOfModes[i]++; for (m = 0; m < i2d; m++) { if (pCurrentMgaModeData == Mga2dMode[m]) { // This one is on our black list, reject it. goto IML_END_OF_LOOP; } } // Assume this mode won't be supported. bSupported2dMode = FALSE; bSupported3dMode = FALSE; // Update the number of valid modes supported. ModePixDepth = pCurrentMgaModeData->PixWidth; switch (ModePixDepth) { case 8: if (pCurrentMgaModeData->ZBuffer) { // 8bpp, Z buffer. // We don't support any of these. } else { // 8bpp, no Z buffer. if ((pCurrentMgaModeData->DispType & ucMask) == (ucTestFlags | DISPTYPE_LUT)) { bSupported2dMode = TRUE; } } break; case 16:if (pCurrentMgaModeData->ZBuffer) { // 16bpp, Z buffer. if ((pCurrentMgaModeData->DispType & ucMask) == DISPTYPE_DB) { bSupported3dMode = TRUE; } } else { // 16bpp, no Z buffer. //if ((pCurrentMgaModeData->DispType & ucMask) == // DISPTYPE_M565) if ((pCurrentMgaModeData->DispType & ucMask) == ucTestFlags) { bSupported2dMode = TRUE; } } break; case 24:if (pCurrentMgaModeData->ZBuffer) { // 24bpp, Z buffer. // We don't support any of these. } else { // 24bpp, no Z buffer. // We don't support any of these. } break; case 32:if (pCurrentMgaModeData->ZBuffer) { // 32bpp, Z buffer. // We don't support any of these. } else { // 32bpp, no Z buffer. if ((pCurrentMgaModeData->DispType & ucMask) == ucTestFlags) { bSupported2dMode = TRUE; } } break; default: break; } if ((bSupported2dMode == FALSE) && (bSupported3dMode == FALSE)) { // We don't support this mode, get out. continue; } if (bSupported2dMode) ulModeListOffset = 0; else ulModeListOffset = 32; // We can do something with the current mode. switch(pCurrentMgaModeData->DispWidth) { case 640: ResTag = BIT_640; break; case 768: ResTag = BIT_768; break; case 800: ResTag = BIT_800; break; case 1024: ResTag = BIT_1024; break; case 1152: ResTag = BIT_1152; break; case 1280: ResTag = BIT_1280; break; case 1600: ResTag = BIT_1600; break; default: ResTag = BIT_INVALID; } // Record the HW mode to be used for this mode. // ModePixDepth is either 8, 16, 24, or 32. if (ResTag != BIT_INVALID) { // We know this hardware mode is correct. Now find // out how many refresh rates this mode supports. usRefreshRates = mtxGetRefreshRates(pCurrentMgaModeData); for (j = 0; j < 16; j++) { if (usRefreshRates & (1 << j)) { MgaDeviceExtension->NumberOfValidModes[i]++; } } MgaDeviceExtension-> ModeList[i][ResTag+ModePixDepth+ulModeListOffset-8] = (UCHAR)(MgaDeviceExtension->NumberOfModes[i] - 1); MgaDeviceExtension-> ModeFreqs[i][ResTag+ModePixDepth+ulModeListOffset-8] = usRefreshRates; } // Make up the resolution tag from the bit field. ResTag = 1 << ResTag; // Shift the resolution tag into its pixel-depth field. ResTag <<= (ModePixDepth - 8); // Record the resolution/pixel-depth flag. if (bSupported2dMode) MgaDeviceExtension->ModeFlags2D[i] |= ResTag; else MgaDeviceExtension->ModeFlags3D[i] |= ResTag; IML_END_OF_LOOP: ; } } // We have recorded information for each of our boards in the // MgaDeviceExtension structure. For each board, we have set: // // NumberOfModes[n] The number of available modes // NumberOfValidModes[n] The number of modes supported by the // user-mode drivers // ModeFlags2D[n] The bit flags describing the supported // 2D modes // ModeFlags3D[n] The bit flags describing the supported // 3D modes // KernelModeMappedBaseAddress[n] // The board's registers window mapping, // returned when VideoPortGetDeviceBase // is called with Hw[n].MapAddress // pMgaHwModes[n] The pointer to an array of HwModeData // structures describing available modes // ModeList[n][64] A list of hardware modes corresponding // to the ModeFlags bits // //DbgBreakPoint(); #if DBG // Display it so that we can see if it makes sense... VideoDebugPrint((1, "# NbModes NbValid ModeFlg2D ModeFlg3D BaseAddr pHwModes ModeList\n")); for (i = 0; i < NbBoard; i++) { VideoDebugPrint((1, "%d % 7d % 7d 0x%08x 0x%08x 0x%08x\n",i, MgaDeviceExtension->NumberOfModes[i], MgaDeviceExtension->NumberOfValidModes[i], MgaDeviceExtension->ModeFlags2D[i], MgaDeviceExtension->ModeFlags3D[i], MgaDeviceExtension->KernelModeMappedBaseAddress[i], MgaDeviceExtension->pMgaHwModes[i])); for (j = 0; j < 64; j+=8) { VideoDebugPrint((1, " %02x %02x %02x %02x %02x %02x %02x %02x\n", MgaDeviceExtension->ModeList[i][j], MgaDeviceExtension->ModeList[i][j+1], MgaDeviceExtension->ModeList[i][j+2], MgaDeviceExtension->ModeList[i][j+3], MgaDeviceExtension->ModeList[i][j+4], MgaDeviceExtension->ModeList[i][j+5], MgaDeviceExtension->ModeList[i][j+6], MgaDeviceExtension->ModeList[i][j+7])); } } #endif // #if DBG // Now for the fun part: find out the resolutions and // combinations of resolutions that we can support. // First, run through the ModeFlags to determine how many modes // we can make up from the single-board modes. // For each bit in our ModeFlags... NbSuperModes = 0; for (i = 0; i < 32; i++) { // Find out which boards, if any, support this mode. CurrentResNbBoards = 0; CurrentResNbBoards3D = 0; for (n = 0; n < (ULONG)NbBoard; n++) { ulNb2DRefreshRates = 0; ulNb3DRefreshRates = 0; us2DRefreshRates = MgaDeviceExtension->ModeFreqs[n][i]; us3DRefreshRates = MgaDeviceExtension->ModeFreqs[n][i+32]; for (j = 0; j < 16; j++) { if (us2DRefreshRates & (1 << j)) { ulNb2DRefreshRates++; } if (us3DRefreshRates & (1 << j)) { ulNb3DRefreshRates++; } } if ((MgaDeviceExtension->ModeFlags2D[n] >> i) & 1) { // The mode is supported by the current board. CurrentResNbBoards++; NbSuperModes += (ulNb2DRefreshRates * MultiModes[CurrentResNbBoards]); } if ((MgaDeviceExtension->ModeFlags3D[n] >> i) & 1) { // The mode is supported by the current board. CurrentResNbBoards3D++; NbSuperModes += (ulNb3DRefreshRates * MultiModes[CurrentResNbBoards3D]); } } } if (NbSuperModes == 0) { // We did not find any mode! status = ERROR_DEV_NOT_EXIST; return(status); } // Now, allocate some memory to hold the new structures. MgaDeviceExtension->pSuperModes = pCurMulti = (MULTI_MODE*) AllocateSystemMemory(NbSuperModes*sizeof(MULTI_MODE)); if (pCurMulti == NULL) { // The memory allocation failed. We won't be able to use // our supermode list, so we'll fall back on the single- // board code. NbSuperModes = 0; status = ERROR_NOT_ENOUGH_MEMORY; return(status); } // And we're ready to go! ModeInit = 0x00000000; pulModeFlags = &MgaDeviceExtension->ModeFlags2D[0]; ulModeListOffset = 0; MTX_INIT_MODE_LIST_LOOP: // For each bit in our ModeFlags... for (i = 0; i < 32; i++) { // Find out which boards, if any, support this // resolution/pixel-depth. CurrentResNbBoards = 0; CurrentResFlags = 0; k = 0; for (n = 0; n < (ULONG)NbBoard; n++) { CurrentFlag = (pulModeFlags[n] >> i) & 1; CurrentResNbBoards += CurrentFlag; if (CurrentFlag) { // This one is valid. usRefreshRates = MgaDeviceExtension-> ModeFreqs[n][i+ulModeListOffset]; CurrentResFlags |= (1 << n); ValidBoard[k++] = (UCHAR)n; } } // Nothing to do if no boards support this combination. if (CurrentResNbBoards == 0) continue; // At least one board supports this resolution/pixel-depth. CurrentResWidth = (ULONG)SingleWidths[i%8]; CurrentResHeight = (ULONG)SingleHeights[i%8]; CurrentPixWidth = (i/8 + 1)*8; ulNbRefreshRates = 0; for (j = 0; j < 16; j++) { if (usRefreshRates & (1 << j)) { ulNbRefreshRates++; } } ucRefreshBit = 0; for (ir = 0; ir < ulNbRefreshRates; ir++) { while ((usRefreshRates & 1) == 0) { usRefreshRates >>= 1; ucRefreshBit++; } CurrentRefreshRate = (ULONG)ConvBitToFreq(ucRefreshBit); usRefreshRates >>= 1; ucRefreshBit++; // Set the 1x1 display. pCurMulti->MulArrayWidth = 1; pCurMulti->MulArrayHeight = 1; pCurMulti->MulWidth = CurrentResWidth; pCurMulti->MulHeight = CurrentResHeight; pCurMulti->MulPixWidth = CurrentPixWidth; pCurMulti->MulRefreshRate = CurrentRefreshRate; // For 1x1, select the VGA-enabled board, if possible. if (CurrentResFlags & VGABoardBit) { // The VGA-enabled board supports this resolution. pCurMulti->MulBoardNb[0] = (UCHAR)VGABoard; } else { // Otherwise, pick board 0. pCurMulti->MulBoardNb[0] = ValidBoard[0]; } n = pCurMulti->MulBoardNb[0]; pCurMulti->MulBoardMode[0] = MgaDeviceExtension->ModeList[n] [i+ulModeListOffset]; // Record a pointer to the HwModeData structure. pMgaDispMode = MgaDeviceExtension->pMgaHwModes[n]; pCurMulti->MulHwModes[0] = &pMgaDispMode[pCurMulti->MulBoardMode[0]]; pCurMulti->MulModeNumber = ModeInit++; pCurMulti++; if (CurrentResNbBoards == 1) continue; // At least two boards support this resolution/pixel-depth. // For each number of boards up to the maximum... for (k = 2; k <= CurrentResNbBoards; k++) { // For each integer up to the maximum... for (m = 1; m <= CurrentResNbBoards; m++) { if ((k % m) == 0) { // We can get a (k/m, m) desktop. pCurMulti->MulArrayHeight = (USHORT)m; pCurMulti->MulHeight = m*CurrentResHeight; pCurMulti->MulArrayWidth = (USHORT)(k/m); pCurMulti->MulWidth = pCurMulti->MulArrayWidth * CurrentResWidth; pCurMulti->MulPixWidth = CurrentPixWidth; pCurMulti->MulRefreshRate = CurrentRefreshRate; // Select the boards we'll be using. // Select the VGA-enabled board as the first // board, if possible. Except for that, we // won't try to place the boards in any // consistent way for now. if (CurrentResFlags & VGABoardBit) { // The VGA-enabled board supports this mode. pCurMulti->MulBoardNb[0] = (UCHAR)VGABoard; ja = 0; for (j = 1; j < k; j++) { if (ValidBoard[ja] == VGABoard) ja++; pCurMulti->MulBoardNb[j] = ValidBoard[ja]; ja++; } } else { // The VGA-enabled board won't be involved. for (j = 0; j < k; j++) { pCurMulti->MulBoardNb[j] = ValidBoard[j]; } } // For each board... for (j = 0; j < k; j++) { // Record the hardware mode the board // would use. n = pCurMulti->MulBoardNb[j]; pCurMulti->MulBoardMode[j] = MgaDeviceExtension->ModeList[n] [i+ulModeListOffset]; // Record a ptr to the HwModeData structure. pMgaDispMode = MgaDeviceExtension->pMgaHwModes[n]; pCurMulti->MulHwModes[j] = &pMgaDispMode[pCurMulti->MulBoardMode[j]]; } pCurMulti->MulModeNumber = ModeInit++; pCurMulti++; } // If it's a valid desktop... } // For each integer up to the maximum... } // For each number of boards up to the maximum... } // For the number of Refresh... } // For each bit in our ModeFlags... if (pulModeFlags == &MgaDeviceExtension->ModeFlags2D[0]) { // We just looked at the 2D modes, now look at the 3D modes. pulModeFlags = &MgaDeviceExtension->ModeFlags3D[0]; ulModeListOffset = 32; goto MTX_INIT_MODE_LIST_LOOP; } MgaDeviceExtension->NumberOfSuperModes = NbSuperModes; // At this point, we have a table of 'super-modes' (which includes // all the regular modes also). All the modes in this table are // supported, and each of them is unique. MgaDeviceExtension-> // pSuperModes points to the start of the mode list. Each entry // in the list holds: // // MulModeNumber A unique mode Id // MulWidth The total width for this mode // MulHeight The total height for this mode // MulPixWidth The pixel depth for this mode // MulArrayWidth The number of boards arrayed along X // MulArrayHeight The number of boards arrayed along Y // MulBoardNb[n] The board numbers of the required boards // MulBoardMode[n] The mode required from each board // *MulHwModes[n] The pointers to the required HwModeData // // Moreover, MgaDeviceExtension->NumberOfSuperModes holds the // number of entries in the list. //DbgBreakPoint(); #if DBG // Now display our results... VideoDebugPrint((1, "ModeNumber Width Height PW X Y n mo pHwMode\n")); pCurMulti = MgaDeviceExtension->pSuperModes; for (i = 0; i < NbSuperModes; i++) { VideoDebugPrint((1, "0x%08x % 6d % 6d % 3d % 3d % 3d\n", pCurMulti->MulModeNumber, pCurMulti->MulWidth, pCurMulti->MulHeight, pCurMulti->MulPixWidth, pCurMulti->MulArrayWidth, pCurMulti->MulArrayHeight)); j = pCurMulti->MulArrayWidth * pCurMulti->MulArrayHeight; for (n = 0; n < j; n++) { VideoDebugPrint((1, " %d %02x 0x%08x\n", pCurMulti->MulBoardNb[n], pCurMulti->MulBoardMode[n], pCurMulti->MulHwModes[n])); } pCurMulti++; } #endif // #if DBG } return(status); } /*--------------------------------------------------------------------------*\ | VP_STATUS | MgaSetColorLookup( | PMGA_DEVICE_EXTENSION MgaDeviceExtension, | PVIDEO_CLUT ClutBuffer, | ULONG ClutBufferSize | ) | | Routine Description: | | This routine sets a specified portion of the color lookup table settings. | | Arguments: | | HwDeviceExtension - Pointer to the miniport driver's device extension. | | ClutBufferSize - Length of the input buffer supplied by the user. | | ClutBuffer - Pointer to the structure containing the color lookup table. | | Return Value: | | None. | \*--------------------------------------------------------------------------*/ VP_STATUS MgaSetColorLookup( PMGA_DEVICE_EXTENSION MgaDeviceExtension, PVIDEO_CLUT ClutBuffer, ULONG ClutBufferSize ) { ULONG ulVal; PUCHAR pucPaletteDataReg, pucPaletteWriteReg; LONG i, m, n, lNumEntries; // DbgBreakPoint(); // Check if the size of the data in the input buffer is large enough. if ( (ClutBufferSize < sizeof(VIDEO_CLUT) - sizeof(ULONG)) || (ClutBufferSize < sizeof(VIDEO_CLUT) + (sizeof(ULONG) * (ClutBuffer->NumEntries - 1)) ) ) { return ERROR_INSUFFICIENT_BUFFER; } // Check to see if the parameters are valid. if ( (ClutBuffer->NumEntries == 0) || (ClutBuffer->FirstEntry > VIDEO_MAX_COLOR_REGISTER) || (ClutBuffer->FirstEntry + ClutBuffer->NumEntries > VIDEO_MAX_COLOR_REGISTER + 1) ) { return ERROR_INVALID_PARAMETER; } pucPaletteDataReg = (PUCHAR)MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard] + PALETTE_DATA; pucPaletteWriteReg= (PUCHAR)MgaDeviceExtension->KernelModeMappedBaseAddress[iBoard] + PALETTE_RAM_WRITE; // Set CLUT registers directly on the hardware. VideoPortWriteRegisterUchar(pucPaletteWriteReg, (UCHAR)ClutBuffer->FirstEntry); n = 0; m = (LONG)ClutBuffer->NumEntries; if (pMgaBoardData[iBoard].DacType == DacTypeTVP3026) { // TVP3026 cursor is very touchy. #define TVP3026_PAL_BATCH_SIZE 64 m = TVP3026_PAL_BATCH_SIZE; lNumEntries = (LONG)ClutBuffer->NumEntries; while ((lNumEntries -= 64) > 0) { // Wait for VSYNC. do { ulVal = VideoPortReadRegisterUlong((PULONG) ((PUCHAR)pMgaBaseAddr + TITAN_OFFSET + TITAN_STATUS)); } while (!(ulVal & TITAN_VSYNCSTS_M)); for (i = n; i < m; i++) { VideoPortWriteRegisterUchar(pucPaletteDataReg, (UCHAR) ClutBuffer->LookupTable[i].RgbArray.Red); VideoPortWriteRegisterUchar(pucPaletteDataReg, (UCHAR) ClutBuffer->LookupTable[i].RgbArray.Green); VideoPortWriteRegisterUchar(pucPaletteDataReg, (UCHAR) ClutBuffer->LookupTable[i].RgbArray.Blue); } n += TVP3026_PAL_BATCH_SIZE; m += TVP3026_PAL_BATCH_SIZE; } m += lNumEntries; // Wait for VSYNC. do { ulVal = VideoPortReadRegisterUlong((PULONG) ((PUCHAR)pMgaBaseAddr + TITAN_OFFSET + TITAN_STATUS)); } while (!(ulVal & TITAN_VSYNCSTS_M)); } for (i = n; i < m; i++) { VideoPortWriteRegisterUchar(pucPaletteDataReg, ((UCHAR) ClutBuffer->LookupTable[i].RgbArray.Red)); VideoPortWriteRegisterUchar(pucPaletteDataReg, ((UCHAR) ClutBuffer->LookupTable[i].RgbArray.Green)); VideoPortWriteRegisterUchar(pucPaletteDataReg, ((UCHAR) ClutBuffer->LookupTable[i].RgbArray.Blue)); } return NO_ERROR; } // end MgaSetColorLookup() VOID MgaSetCursorColour( PMGA_DEVICE_EXTENSION MgaDeviceExtension, ULONG ulFgColour, ULONG ulBgColour) { PUCHAR pucCursorDataReg, pucCursorWriteReg; PUCHAR pucCmdRegA, pucPixRdMaskReg; UCHAR ucOldCmdRegA, ucOldRdMask; VideoDebugPrint((1, "MGA.SYS!MgaSetCursorColour\n")); // DbgBreakPoint(); switch(pMgaBoardData[iBoard].DacType) { case DacTypeBT485: case DacTypePX2085: // Set cursor colour for Bt485. pucCursorDataReg = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT485_COL_OVL; pucCursorWriteReg= (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT485_WADR_OVL; VideoPortWriteRegisterUchar(pucCursorWriteReg, 1); // Set Background Colour VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>16 & 0xFF)); // Set Foreground Colour VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>16 & 0xFF)); break; case DacTypeBT482: // Set cursor colour for Bt482. pucCursorDataReg = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_COL_OVL; pucCmdRegA = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_CMD_REGA; pucPixRdMaskReg = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_PIX_RD_MSK; ucOldCmdRegA = VideoPortReadRegisterUchar(pucCmdRegA); VideoPortWriteRegisterUchar(pucCmdRegA, (UCHAR) (ucOldCmdRegA | BT482_EXT_REG_EN)); VideoPortWriteRegisterUchar((PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_WADR_PAL, BT482_CUR_REG); ucOldRdMask = VideoPortReadRegisterUchar(pucPixRdMaskReg); VideoPortWriteRegisterUchar(pucPixRdMaskReg, 0); VideoPortWriteRegisterUchar((PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_WADR_OVL, 0x11); // Set Colour 1 VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>16 & 0xFF)); // Set Colour 2 VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>16 & 0xFF)); // Restore old read mask and command register values VideoPortWriteRegisterUchar((PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + BT482_WADR_PAL, BT482_CUR_REG); VideoPortWriteRegisterUchar(pucPixRdMaskReg, ucOldRdMask); VideoPortWriteRegisterUchar(pucCmdRegA, ucOldCmdRegA); break; case DacTypeVIEWPOINT: // Set cursor colour for ViewPoint pucCursorDataReg = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + VPOINT_DATA; pucCursorWriteReg= (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + VPOINT_INDEX; // Set Background Colour VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL0_RED); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL0_GREEN); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL0_BLUE); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>16 & 0xFF)); // Set Foreground Colour VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL1_RED); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL1_GREEN); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorWriteReg,VPOINT_CUR_COL1_BLUE); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>16 & 0xFF)); break; case DacTypeTVP3026: // Set cursor colour for TVP3026 pucCursorDataReg = (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + TVP3026_CUR_COL_DATA; pucCursorWriteReg= (PUCHAR)MgaDeviceExtension-> KernelModeMappedBaseAddress[iBoard] + RAMDAC_OFFSET + TVP3026_CUR_COL_ADDR; // Set Background Colour VideoPortWriteRegisterUchar(pucCursorWriteReg,1); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulBgColour>>16 & 0xFF)); // Set Foreground Colour VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>8 & 0xFF)); VideoPortWriteRegisterUchar(pucCursorDataReg, (UCHAR)(ulFgColour>>16 & 0xFF)); break; default: break; } } #if (_WIN32_WINNT >= 500) // // Routine to set a desired DPMS power management state. // VP_STATUS MgaSetPower50( PMGA_DEVICE_EXTENSION phwDeviceExtension, ULONG HwDeviceId, PVIDEO_POWER_MANAGEMENT pVideoPowerMgmt ) { if ((pVideoPowerMgmt->PowerState == VideoPowerOn) || (pVideoPowerMgmt->PowerState == VideoPowerHibernate)) { return NO_ERROR; } else { return ERROR_INVALID_FUNCTION; } } // // Routine to retrieve possible DPMS power management states. // VP_STATUS MgaGetPower50( PMGA_DEVICE_EXTENSION phwDeviceExtension, ULONG HwDeviceId, PVIDEO_POWER_MANAGEMENT pVideoPowerMgmt ) { if ((pVideoPowerMgmt->PowerState == VideoPowerOn) || (pVideoPowerMgmt->PowerState == VideoPowerHibernate)) { return NO_ERROR; } else { return ERROR_INVALID_FUNCTION; } } // // Routine to retrieve the Enhanced Display ID structure via DDC // ULONG MgaGetVideoChildDescriptor( PVOID HwDeviceExtension, PVIDEO_CHILD_ENUM_INFO ChildEnumInfo, PVIDEO_CHILD_TYPE pChildType, PVOID pvChildDescriptor, PULONG pHwId, PULONG pUnused ) { PMGA_DEVICE_EXTENSION pHwDeviceExtension = HwDeviceExtension; ULONG Status; ASSERT(pHwDeviceExtension != NULL && pMoreChildren != NULL); VideoDebugPrint((2, "mga.SYS mgaGetVideoChildDescriptor: *** Entry point ***\n")); // // Determine if the graphics adapter in the system supports // DDC2 (our miniport only supports DDC2, not DDC1). This has // the side effect (assuming both monitor and card support // DDC2) of switching the monitor from DDC1 mode (repeated // "blind" broadcast of EDID clocked by the vertical sync // signal) to DDC2 mode (query/response not using any of the // normal video lines - can transfer information rapidly // without first disrupting the screen by switching into // a pseudo-mode with a high vertical sync frequency). // // Since we must support hot-plugging of monitors, and our // routine to obtain the EDID structure via DDC2 assumes that // the monitor is in DDC2 mode, we must make this test each // time this entry point is called. // switch (ChildEnumInfo->ChildIndex) { case 0: // // Case 0 is used to enumerate devices found by the ACPI firmware. // // Since we do not support ACPI devices yet, we must return failure. // Status = ERROR_NO_MORE_DEVICES; break; case 1: // // We do not support monitor enumeration // Status = ERROR_NO_MORE_DEVICES; break; case DISPLAY_ADAPTER_HW_ID: { PUSHORT pPnpDeviceDescription = NULL; ULONG stringSize = sizeof(L"*PNPXXXX"); // // Special ID to handle return legacy PnP IDs for root enumerated // devices. // *pChildType = VideoChip; *pHwId = DISPLAY_ADAPTER_HW_ID; // // Figure out which card type and set pPnpDeviceDescription at // associated string. // if (pHwDeviceExtension->BoardId == TYPE_QVISION_PCI) pPnpDeviceDescription = L"*PNP0919"; else pPnpDeviceDescription = L"*PNP0918"; // // Now just copy the string into memory provided. // if (pPnpDeviceDescription) memcpy(pvChildDescriptor, pPnpDeviceDescription, stringSize); Status = ERROR_MORE_DATA; break; } default: Status = ERROR_NO_MORE_DEVICES; break; } return Status; } #endif // _WIN32_WINNT >= 500