1127 lines
32 KiB
C
1127 lines
32 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
clddc2b.c
|
|
|
|
Abstract:
|
|
|
|
This module checks for a DDC monitor, and returns the
|
|
established Timings value from the EDID if found.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
* plc3 10-23-95 VESA DDC2B support.
|
|
*
|
|
* sge01 09-25-96 Non DDC Moniotr table support
|
|
*
|
|
* sge02 10-14-96 Detailed timing calculation in EDID
|
|
*
|
|
* sge03 12-05-96 Only check active pixel clock in detailed timing.
|
|
*
|
|
--*/
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <dderror.h>
|
|
#include <devioctl.h>
|
|
#include <miniport.h>
|
|
|
|
#include <ntddvdeo.h>
|
|
#include <video.h>
|
|
#include "cirrus.h"
|
|
|
|
#define ERROR 0
|
|
|
|
#define OFF 0
|
|
#define ON 1
|
|
|
|
#define SDA_BIT 2
|
|
#define SCL_BIT 1
|
|
#define SCL_BIT_ON 1
|
|
#define SCL_BIT_OFF 0
|
|
|
|
#define DELAY_COUNT 255
|
|
|
|
UCHAR WaitCount ;
|
|
UCHAR Err ;
|
|
|
|
VOID ReadVESATiming(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID EnableDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN IsDDC2(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID DisableDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID StartDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID StopDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID ProcessDDC2(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN ReadSDA(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN ReadSCL(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN ReadBit(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN ReadByte(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID SetSCL(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR status
|
|
);
|
|
|
|
VOID SetData(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN SetClock(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID WaitVerticalRetrace(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR count
|
|
);
|
|
|
|
VOID WaitDelay(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VOID ClearData(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN SendByte(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR data
|
|
);
|
|
|
|
BOOLEAN SendDDCCommand(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
BOOLEAN
|
|
CheckDDC2BMonitor(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
ULONG i
|
|
);
|
|
|
|
ULONG
|
|
CalculateMaxinumTiming(
|
|
);
|
|
|
|
VOID ProcessNonDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
);
|
|
|
|
VP_STATUS
|
|
CirrusNonDDCRegistryCallback(
|
|
PVOID HwDeviceExtension,
|
|
PVOID Context,
|
|
PWSTR ValueName,
|
|
PVOID ValueData,
|
|
ULONG ValueLength
|
|
);
|
|
|
|
#if defined(ALLOC_PRAGMA)
|
|
#pragma alloc_text (PAGE,ReadVESATiming)
|
|
#pragma alloc_text (PAGE,EnableDDC)
|
|
#pragma alloc_text (PAGE,IsDDC2)
|
|
#pragma alloc_text (PAGE,DisableDDC)
|
|
#pragma alloc_text (PAGE,StartDDC)
|
|
#pragma alloc_text (PAGE,StopDDC)
|
|
#pragma alloc_text (PAGE,ProcessDDC2)
|
|
#pragma alloc_text (PAGE,ReadSDA)
|
|
#pragma alloc_text (PAGE,ReadSCL)
|
|
#pragma alloc_text (PAGE,ReadBit)
|
|
#pragma alloc_text (PAGE,ReadByte)
|
|
#pragma alloc_text (PAGE,SetSCL)
|
|
#pragma alloc_text (PAGE,SetData)
|
|
#pragma alloc_text (PAGE,SetClock)
|
|
#pragma alloc_text (PAGE,WaitVerticalRetrace)
|
|
#pragma alloc_text (PAGE,WaitDelay)
|
|
#pragma alloc_text (PAGE,ClearData)
|
|
#pragma alloc_text (PAGE,SendByte)
|
|
#pragma alloc_text (PAGE,SendDDCCommand)
|
|
#pragma alloc_text (PAGE,CheckDDC2BMonitor)
|
|
#pragma alloc_text (PAGE,CalculateMaxinumTiming)
|
|
#pragma alloc_text (PAGE,ProcessNonDDC)
|
|
#pragma alloc_text (PAGE,CirrusNonDDCRegistryCallback)
|
|
#endif
|
|
|
|
UCHAR EDIDBuffer[128] ;
|
|
UCHAR EDIDTiming_I ;
|
|
UCHAR EDIDTiming_II ;
|
|
UCHAR EDIDTiming_III ;
|
|
UCHAR DDC2BFlag ;
|
|
UCHAR NonDDCTable ;
|
|
ULONG ulEDIDMaxTiming ;
|
|
|
|
UCHAR SDAValue ;
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID EnableDDC (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSR08 ;
|
|
UCHAR WaitCount = 2 ;
|
|
|
|
VideoDebugPrint((1, "CLDDC2B!EnableDDC\n"));
|
|
|
|
VideoPortWritePortUchar (HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
|
|
0x08) ;
|
|
|
|
ReadSR08 = VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT) ;
|
|
// Enable DDC2B Configuration
|
|
ReadSR08 |= 0x43 ;
|
|
|
|
VideoPortWritePortUchar (HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ReadSR08) ;
|
|
|
|
WaitVerticalRetrace (HwDeviceExtension, WaitCount) ;
|
|
|
|
} /*----- EnableDDC -----*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID DisableDDC (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSEQADDR, ReadSEQDATA ;
|
|
UCHAR DDCStatus ;
|
|
|
|
VideoDebugPrint((1, "CLDDC2B!DisableDDC\n"));
|
|
|
|
if ((DDCStatus = SendDDCCommand ( HwDeviceExtension )) == 1)
|
|
goto DDC_ERROR ;
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar ( HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT ) ;
|
|
// Disable DDC2B Configuration
|
|
ReadSEQDATA &= 0xBC ;
|
|
|
|
// o 3c5 ReadSEQDATA
|
|
VideoPortWritePortUchar ( HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ReadSEQDATA ) ;
|
|
|
|
DDC_ERROR:
|
|
return ;
|
|
|
|
} /*------- DisableDDC -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID ProcessDDC2 (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR DDCStatus, i ;
|
|
UCHAR checksum, header ;
|
|
|
|
VideoDebugPrint((1, "CLDDC2B!ProcessDDC2\n"));
|
|
|
|
DDC2BFlag = 0 ;
|
|
|
|
if ((DDCStatus = SendDDCCommand ( HwDeviceExtension )) == 1) {
|
|
VideoDebugPrint((0, "CLDDC2B!ProcessDDC2: Infinite wait state ...\n"));
|
|
goto PROCESSDDC_EXIT ;
|
|
}
|
|
|
|
for (i = 0; i < 128; i++) {
|
|
EDIDBuffer[i] = ReadByte (HwDeviceExtension) ;
|
|
if (Err) {
|
|
VideoDebugPrint((0, "CLDDC2B!ProcessDDC2: Infinite wait state ...\n"));
|
|
goto PROCESSDDC_EXIT ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check EDID table 8-byte header
|
|
// The correct first 8 bytes of EDID table is 0x00, 0xFF, 0xFF, 0xFF,
|
|
// 0xFF, 0xFF, 0xFF, 0x00
|
|
//
|
|
|
|
if ((EDIDBuffer[0] != 0) ||
|
|
(EDIDBuffer[7] != 0)) {
|
|
VideoDebugPrint((1, "CLDDC2B: Invalid EDID header table\n"));
|
|
StopDDC (HwDeviceExtension) ;
|
|
return ;
|
|
}
|
|
for (i = 1; i < 7; i++) {
|
|
if (EDIDBuffer[i] != 0xFF) {
|
|
VideoDebugPrint((1, "CLDDC2B: Invalid EDID header table\n"));
|
|
StopDDC (HwDeviceExtension) ;
|
|
return ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate checksum of 128-byte EDID table.
|
|
//
|
|
checksum = 0x00 ;
|
|
|
|
for (i = 0; i < 128; i++) {
|
|
checksum += EDIDBuffer[i] ;
|
|
}
|
|
|
|
VideoDebugPrint((1, "CLDDC2B: EDID Table check sum = %d\n", checksum));
|
|
|
|
//
|
|
// EDID table checksum must be zero.
|
|
//
|
|
if (checksum) {
|
|
VideoDebugPrint((1, "CLDDC2B: Invalid checksum of EDID table\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Set DDC2B Flag and find timing values.
|
|
//
|
|
DDC2BFlag = 1 ;
|
|
EDIDTiming_I = EDIDBuffer[35] ;
|
|
EDIDTiming_II = EDIDBuffer[36] ;
|
|
EDIDTiming_III = EDIDBuffer[37] ;
|
|
ulEDIDMaxTiming= CalculateMaxinumTiming();
|
|
VideoDebugPrint((1, "CLDDC2B: DDC2B is supported\n"));
|
|
}
|
|
|
|
PROCESSDDC_EXIT:
|
|
StopDDC (HwDeviceExtension) ;
|
|
return ;
|
|
|
|
} /*------- ProcessDDC2 -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID StartDDC (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
|
|
VideoDebugPrint((1, "DDC2B!StartDDC\n"));
|
|
|
|
SetSCL (HwDeviceExtension, ON) ;
|
|
ClearData (HwDeviceExtension) ;
|
|
SetSCL (HwDeviceExtension, OFF) ;
|
|
|
|
} /*------- StartDDC -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID StopDDC (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
|
|
VideoDebugPrint((1, "DDC2B!StopDDC\n"));
|
|
|
|
SetSCL (HwDeviceExtension, ON) ;
|
|
SetData (HwDeviceExtension) ;
|
|
|
|
} /*------- StopDDC -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN ReadSCL (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSEQDATA, status ;
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar ( HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT ) ;
|
|
|
|
// Read SR08.B2
|
|
ReadSEQDATA = ( (ReadSEQDATA) & 0x04 ) >> 2 ;
|
|
|
|
return (ReadSEQDATA) ;
|
|
|
|
} /*------- ReadSCL -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID SetSCL(
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR status
|
|
)
|
|
{
|
|
UCHAR ReadSEQADDR, ReadSEQDATA ;
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT) ;
|
|
|
|
ReadSEQDATA = ( ( ReadSEQDATA & 0xFE ) | status ) ;
|
|
|
|
// o 3c5 ReadSEQDATA
|
|
VideoPortWritePortUchar (HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ReadSEQDATA) ;
|
|
|
|
WaitDelay (HwDeviceExtension) ;
|
|
|
|
} /*------- SetSCL -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN ReadSDA (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSEQADDR, ReadSEQDATA ;
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT) ;
|
|
|
|
ReadSEQDATA = ( ReadSEQDATA & 0x80 ) >> 7 ;
|
|
|
|
return ( ReadSEQDATA ) ;
|
|
|
|
} /*------- ReadSDA -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID ClearData
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSEQADDR, ReadSEQDATA ;
|
|
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT) ;
|
|
|
|
ReadSEQDATA &= 0xFD ;
|
|
|
|
// o 3c5 ReadSEQDATA
|
|
VideoPortWritePortUchar (HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ReadSEQDATA) ;
|
|
|
|
WaitDelay (HwDeviceExtension) ;
|
|
|
|
} /*------- ClearData -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID SetData
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ReadSEQADDR, ReadSEQDATA ;
|
|
|
|
// i 3c5 ReadSEQDATA
|
|
ReadSEQDATA = VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
SEQ_DATA_PORT) ;
|
|
|
|
ReadSEQDATA |= 0x02 ;
|
|
|
|
// o 3c5 ReadSEQDATA
|
|
VideoPortWritePortUchar (HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
|
|
ReadSEQDATA) ;
|
|
|
|
WaitDelay (HwDeviceExtension) ;
|
|
|
|
} /*------- SetData -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN SetClock
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
ULONG i ;
|
|
UCHAR status ;
|
|
|
|
SetSCL (HwDeviceExtension, ON) ;
|
|
|
|
for (i = 0; i < DELAY_COUNT; i++)
|
|
status = ReadSCL (HwDeviceExtension) ;
|
|
|
|
SetSCL (HwDeviceExtension, OFF) ;
|
|
|
|
if (!status)
|
|
VideoDebugPrint((0, "DDC2B!SetClock: Infinite wait state ...\n"));
|
|
|
|
if (status == 1)
|
|
return ( FALSE ) ; // retuern 0 -> OK
|
|
else
|
|
return ( TRUE ) ; // retuern 1 -> Infinite wait state
|
|
|
|
|
|
} /*------- SetClock -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN ReadBit
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
USHORT i ;
|
|
UCHAR bit ;
|
|
|
|
SetSCL (HwDeviceExtension, ON) ;
|
|
for (i = 0; i < DELAY_COUNT; i++)
|
|
ReadSCL (HwDeviceExtension) ;
|
|
|
|
bit = ReadSDA (HwDeviceExtension) ;
|
|
|
|
SetSCL (HwDeviceExtension, OFF) ;
|
|
|
|
return ( bit ) ;
|
|
|
|
} /*------- ReadBit -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN ReadByte
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
|
|
UCHAR ReadByteValue, bit, i ;
|
|
|
|
SetData ( HwDeviceExtension ) ;
|
|
|
|
ReadByteValue = 0 ;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
ReadByteValue <<= 1 ;
|
|
bit = ReadBit ( HwDeviceExtension ) ;
|
|
ReadByteValue |= bit ;
|
|
}
|
|
|
|
if ((bit & 0x02) != 0) {
|
|
SetData ( HwDeviceExtension ) ;
|
|
} else {
|
|
ClearData ( HwDeviceExtension ) ;
|
|
}
|
|
|
|
SetClock ( HwDeviceExtension ) ;
|
|
|
|
SetData ( HwDeviceExtension ) ;
|
|
|
|
return (ReadByteValue) ;
|
|
|
|
} /*----- ReadByte -----*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN SendByte (
|
|
/*-------------------------------------------------------------------------*/
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR data
|
|
)
|
|
{
|
|
UCHAR i ;
|
|
|
|
UCHAR Mask[8] = { 0x80, 0x40, 0x20, 0x10,
|
|
0x08, 0x04, 0x02, 0x01 } ;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (data & Mask[i]) {
|
|
SetData ( HwDeviceExtension ) ;
|
|
} else {
|
|
ClearData ( HwDeviceExtension ) ;
|
|
}
|
|
Err = SetClock ( HwDeviceExtension ) ;
|
|
}
|
|
|
|
if (Err) {
|
|
SetSCL ( HwDeviceExtension, OFF ) ;
|
|
ClearData (HwDeviceExtension) ;
|
|
} else {
|
|
SetData ( HwDeviceExtension ) ;
|
|
SetSCL ( HwDeviceExtension, ON ) ;
|
|
ReadBit ( HwDeviceExtension ) ; // Discard acknowledge bit
|
|
}
|
|
|
|
return (Err) ;
|
|
|
|
} /*------- SendByte -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN IsDDC2
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR DDCStatus, SCLStatus ;
|
|
|
|
VideoDebugPrint((1, "DDC2B!IsDDC2\n"));
|
|
|
|
SetSCL (HwDeviceExtension, OFF) ;
|
|
SCLStatus = ReadSCL(HwDeviceExtension) ;
|
|
if (SCLStatus != 0) {
|
|
return ( FALSE ) ;
|
|
}
|
|
|
|
SetSCL (HwDeviceExtension, ON) ;
|
|
SCLStatus = ReadSCL (HwDeviceExtension) ;
|
|
if (SCLStatus != 1) {
|
|
return ( FALSE ) ;
|
|
}
|
|
|
|
return ( TRUE ) ;
|
|
|
|
} /*------- IsDDC2 -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
BOOLEAN SendDDCCommand
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR ClockStatus ;
|
|
|
|
VideoDebugPrint((1, "DDC2B!SendDDCCommand\n"));
|
|
|
|
StartDDC ( HwDeviceExtension ) ;
|
|
|
|
ClockStatus = SendByte ( HwDeviceExtension, 0xA0 ) ;
|
|
if (ClockStatus)
|
|
VideoDebugPrint((0, "DDC2B!SendDDCCommand: Infinite wait state ...\n"));
|
|
|
|
ClockStatus = SendByte ( HwDeviceExtension, 0x00 ) ;
|
|
if (ClockStatus)
|
|
VideoDebugPrint((0, "DDC2B!SendDDCCommand: Infinite wait state ...\n"));
|
|
|
|
StopDDC ( HwDeviceExtension ) ;
|
|
|
|
|
|
StartDDC ( HwDeviceExtension ) ;
|
|
|
|
ClockStatus = SendByte ( HwDeviceExtension, 0xA1 ) ;
|
|
if (ClockStatus)
|
|
VideoDebugPrint((0, "DDC2B!SendDDCCommand: Infinite wait state ...\n"));
|
|
|
|
SetData ( HwDeviceExtension ) ;
|
|
|
|
return (ClockStatus) ;
|
|
|
|
} /*------- SendDDCCommand -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID WaitDelay
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
PUCHAR InStatPort ;
|
|
|
|
//
|
|
// Set up port addresses for color/mono
|
|
//
|
|
if (VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
MISC_OUTPUT_REG_READ_PORT) & 0x01) {
|
|
InStatPort = HwDeviceExtension->IOAddress + INPUT_STATUS_1_COLOR ;
|
|
} else {
|
|
InStatPort = HwDeviceExtension->IOAddress + INPUT_STATUS_1_MONO ;
|
|
}
|
|
|
|
while ((VideoPortReadPortUchar (InStatPort) & 0x01) != 0) ;
|
|
while ((VideoPortReadPortUchar (InStatPort) & 0x01) == 0) ;
|
|
while ((VideoPortReadPortUchar (InStatPort) & 0x01) != 0) ;
|
|
|
|
} /*------- wait_delay -------*/
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID WaitVerticalRetrace
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
UCHAR waitcount
|
|
)
|
|
{
|
|
PUCHAR InStatPort ;
|
|
ULONG i ;
|
|
|
|
//
|
|
// Set up port addresses for color/mono
|
|
//
|
|
if (VideoPortReadPortUchar (HwDeviceExtension->IOAddress +
|
|
MISC_OUTPUT_REG_READ_PORT) & 0x01) {
|
|
InStatPort = INPUT_STATUS_1_COLOR + HwDeviceExtension->IOAddress;
|
|
} else {
|
|
InStatPort = INPUT_STATUS_1_MONO + HwDeviceExtension->IOAddress;
|
|
}
|
|
|
|
for (i = 0; i < waitcount; i++)
|
|
{
|
|
while ((VideoPortReadPortUchar (InStatPort) & 0x08) != 0) ;
|
|
while ((VideoPortReadPortUchar (InStatPort) & 0x08) == 0) ;
|
|
}
|
|
|
|
} /*------- WaitVerticalRetrace -------*/
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
VOID ReadVESATiming
|
|
/*-------------------------------------------------------------------------*/
|
|
(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
UCHAR status ;
|
|
|
|
VideoDebugPrint((1, "DDC2B!ReadVESATiming\n"));
|
|
#if 1 // NonDDC #sge
|
|
//
|
|
// clear flag.
|
|
//
|
|
NonDDCTable = 0;
|
|
DDC2BFlag = 0;
|
|
#endif
|
|
EnableDDC (HwDeviceExtension) ;
|
|
|
|
if ((status = IsDDC2 (HwDeviceExtension)) != 0x00) {
|
|
ProcessDDC2 (HwDeviceExtension) ;
|
|
}
|
|
#if 1 // NonDDC #sge
|
|
if(!DDC2BFlag)
|
|
ProcessNonDDC(HwDeviceExtension);
|
|
#endif
|
|
|
|
DisableDDC (HwDeviceExtension) ;
|
|
|
|
return ;
|
|
|
|
} /*----- ReadVESATiming -----*/
|
|
|
|
BOOLEAN
|
|
CheckDDC2BMonitor(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension,
|
|
ULONG i
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Determines if refresh rate support according to DDC2B standard.
|
|
|
|
Arguments:
|
|
HwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG ulCurrTiming ;
|
|
#if 1 // NonDDC #sge
|
|
if (!DDC2BFlag && !NonDDCTable)
|
|
return TRUE ;
|
|
#else
|
|
if (!DDC2BFlag)
|
|
return TRUE ;
|
|
#endif
|
|
|
|
VideoDebugPrint((4, "CheckDDC2B\n"));
|
|
VideoDebugPrint((4, "refresh rate = %ld\n", ModesVGA[i].Frequency));
|
|
VideoDebugPrint((4, "hres = %d\n", ModesVGA[i].hres));
|
|
VideoDebugPrint((4, "vres = %d\n", ModesVGA[i].vres));
|
|
|
|
ulCurrTiming = ModesVGA[i].Frequency *
|
|
ModesVGA[i].hres *
|
|
ModesVGA[i].vres ;
|
|
|
|
VideoDebugPrint((4, "ulCurrTiming = %d\n", ulCurrTiming)) ;
|
|
|
|
VideoDebugPrint((4, "ulEDIDMaxTiming = %d\n", ulEDIDMaxTiming)) ;
|
|
|
|
if ( ulCurrTiming > ulEDIDMaxTiming )
|
|
return FALSE ;
|
|
else
|
|
return TRUE ;
|
|
|
|
} // end of CheckDDC2bMonitor
|
|
|
|
|
|
ULONG
|
|
CalculateMaxinumTiming(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Determines maximum allowablt VESA timing value.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG current_timing_value ;
|
|
ULONG freq ;
|
|
SHORT i ;
|
|
USHORT usHzActive, usHzBlanking, usVtActive, usVtBlanking;
|
|
ULONG maximum_allowable_timing_value = ulEDIDMaxTiming;
|
|
|
|
VideoDebugPrint((1, "CLDDC2B: CalculateMaxinumTiming\n")) ;
|
|
|
|
//
|
|
// Calculate established timing values
|
|
//
|
|
/* 720 * 400 * 70 = 20160000 */
|
|
if ( EDIDTiming_I & 0x80 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 720 * 400 * 70\n")) ;
|
|
if (maximum_allowable_timing_value < ((ULONG) 20160000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 20160000) ;
|
|
}
|
|
}
|
|
|
|
/* 720 * 400 * 88 = 25344000 */
|
|
if ( EDIDTiming_I & 0x40 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 720 * 400 * 88\n")) ;
|
|
if (maximum_allowable_timing_value < ((ULONG) 25344000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 25344000) ;
|
|
}
|
|
}
|
|
|
|
/* 640 * 480 * 60 = 18432000 */
|
|
if ( EDIDTiming_I & 0x20 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * 60\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 18432000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 18432000) ;
|
|
}
|
|
}
|
|
|
|
/* 640 * 480 * 67 = 20582400 */
|
|
if ( EDIDTiming_I & 0x10 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * 67\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 20582400)) {
|
|
maximum_allowable_timing_value = ((ULONG) 20582400) ;
|
|
}
|
|
}
|
|
|
|
/* 640 * 480 * 72 = 22118400 */
|
|
if ( EDIDTiming_I & 0x08 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * 72\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 22118400)) {
|
|
maximum_allowable_timing_value = ((ULONG) 22118400) ;
|
|
}
|
|
}
|
|
|
|
/* 640 * 480 * 75 = 23040000 */
|
|
if ( EDIDTiming_I & 0x04 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 23040000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 23040000) ;
|
|
}
|
|
}
|
|
|
|
/* 800 * 600 * 56 = 26880000 */
|
|
if ( EDIDTiming_I & 0x02 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 800 * 600 * 56\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 26880000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 26880000) ;
|
|
}
|
|
}
|
|
|
|
/* 800 * 600 * 60 = 28800000 */
|
|
if ( EDIDTiming_I & 0x01 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 800 * 600 * 60\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 28800000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 28800000) ;
|
|
}
|
|
}
|
|
|
|
/* 800 * 600 * 72 = 34560000 */
|
|
if ( EDIDTiming_II & 0x80 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 800 * 600 * 72\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 34560000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 34560000) ;
|
|
}
|
|
}
|
|
|
|
/* 800 * 600 * 75 = 36000000 */
|
|
if ( EDIDTiming_II & 0x40 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 800 * 600 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 36000000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 36000000) ;
|
|
}
|
|
}
|
|
|
|
/* 832 * 624 * 75 = 38937600 */
|
|
if ( EDIDTiming_II & 0x20 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 832 * 624 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 38937600)) {
|
|
maximum_allowable_timing_value = ((ULONG) 38937600) ;
|
|
}
|
|
}
|
|
|
|
/* 1024 * 768 * 43 = 33816576 */
|
|
if ( EDIDTiming_II & 0x10 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1024 * 768 * 43\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 33816576)) {
|
|
maximum_allowable_timing_value = ((ULONG) 33816576) ;
|
|
}
|
|
}
|
|
|
|
/* 1024 * 768 * 60 = 47185920 */
|
|
if ( EDIDTiming_II & 0x08 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1024 * 768 * 60\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 47185920)) {
|
|
maximum_allowable_timing_value = ((ULONG) 47185920) ;
|
|
}
|
|
}
|
|
|
|
/* 1024 * 768 * 70 = 55050240 */
|
|
if ( EDIDTiming_II & 0x04 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1024 * 768 * 70\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 55050240)) {
|
|
maximum_allowable_timing_value = ((ULONG) 55050240) ;
|
|
}
|
|
}
|
|
|
|
/* 1024 * 768 * 75 = 58982400 */
|
|
if ( EDIDTiming_II & 0x02 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1024 * 768 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 58982400)) {
|
|
maximum_allowable_timing_value = ((ULONG) 58982400) ;
|
|
}
|
|
}
|
|
|
|
/* 1280 * 1024 * 75 = 98304000 */
|
|
if ( EDIDTiming_II & 0x01 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1280 * 1024 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 98304000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 98304000) ;
|
|
}
|
|
}
|
|
|
|
/* 1152 * 870 * 75 = 75168000 */
|
|
if ( EDIDTiming_III & 0x80 ) {
|
|
VideoDebugPrint((1, "CLDDC2B: 1152 * 870 * 75\n"));
|
|
if (maximum_allowable_timing_value < ((ULONG) 75168000)) {
|
|
maximum_allowable_timing_value = ((ULONG) 75168000) ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate standard timing values
|
|
//
|
|
|
|
for ( i = 0x26 ; i <= 0x35 ; i+=2 ) {
|
|
current_timing_value = 0L ;
|
|
freq = ( EDIDBuffer[i+1] & 0x3F ) + 60 ;
|
|
switch ( EDIDBuffer[i] ) {
|
|
case 0x31 : // 640 * 480 = 307200
|
|
current_timing_value = ((ULONG) freq) * 307200 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * %d\n", freq));
|
|
break ;
|
|
case 0x3B : // 720 * 400 = 288000
|
|
current_timing_value = ((ULONG) freq) * 288000 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 640 * 480 * %d\n", freq));
|
|
break ;
|
|
case 0x45 : // 800 * 600 = 480000
|
|
current_timing_value = ((ULONG) freq) * 480000 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 800 * 600 * %d\n", freq));
|
|
break ;
|
|
case 0x61 : // 1024 * 768 = 786432
|
|
current_timing_value = ((ULONG) freq) * 786432 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 1024 * 768 * %d\n", freq));
|
|
break ;
|
|
case 0x71 : // 1152 * 870 = 1002240
|
|
current_timing_value = ((ULONG) freq) * 1002240 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 1152 * 870 * %d\n", freq));
|
|
break ;
|
|
case 0x81 : // 1280 * 1024 = 1310720
|
|
current_timing_value = ((ULONG) freq) * 1310720 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 1280 * 1024 * %d\n", freq));
|
|
break ;
|
|
case 0xA9 : // 1600 * 1200 = 1920000
|
|
current_timing_value = ((ULONG) freq) * 1920000 ;
|
|
VideoDebugPrint((1, "CLDDC2B: 1600 * 1200 * %d\n", freq));
|
|
break ;
|
|
default :
|
|
;
|
|
}
|
|
|
|
if (maximum_allowable_timing_value < current_timing_value)
|
|
maximum_allowable_timing_value = current_timing_value ;
|
|
|
|
}
|
|
|
|
// sge02
|
|
//
|
|
// Calculate detailed timing values
|
|
//
|
|
|
|
for ( i = 0x36 ; i <= 0x7D; i+=18 )
|
|
{
|
|
current_timing_value = EDIDBuffer[i] ;
|
|
current_timing_value += EDIDBuffer[i+1] * 256;
|
|
//
|
|
// Validation.
|
|
//
|
|
// sge03
|
|
if (current_timing_value <= 0x0101 )
|
|
continue;
|
|
current_timing_value *= 10000;
|
|
//
|
|
// Calculate Horizontal Active and Blanking
|
|
//
|
|
usHzActive = (EDIDBuffer[i+4] & 0xf0);
|
|
usHzActive <<= 4;
|
|
usHzActive |= EDIDBuffer[i+2];
|
|
usHzBlanking = (EDIDBuffer[i+4] & 0x0f);
|
|
usHzBlanking <<= 8;
|
|
usHzBlanking |= EDIDBuffer[i+3];
|
|
//
|
|
// Calculate Vertical Active and Blanking
|
|
//
|
|
usVtActive = (EDIDBuffer[i+7] & 0xf0);
|
|
usVtActive <<= 4;
|
|
usVtActive |= EDIDBuffer[i+5];
|
|
usVtBlanking = (EDIDBuffer[i+7] & 0x0f);
|
|
usVtBlanking <<= 8;
|
|
usVtBlanking |= EDIDBuffer[i+6];
|
|
|
|
current_timing_value = (current_timing_value + usHzActive + usHzBlanking - 1) / (usHzActive + usHzBlanking);
|
|
current_timing_value = (current_timing_value + usVtActive + usVtBlanking - 1) / (usVtActive + usVtBlanking);
|
|
current_timing_value *= usHzActive;
|
|
current_timing_value *= usVtActive;
|
|
|
|
if (maximum_allowable_timing_value < current_timing_value)
|
|
maximum_allowable_timing_value = current_timing_value ;
|
|
|
|
}
|
|
|
|
return (maximum_allowable_timing_value);
|
|
|
|
} // end of CalculateMaxinumTiming
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
// Read NonDDC Table from Registry and Set NonDDCTable Flag.
|
|
//
|
|
// Input:
|
|
// HwDeviceExtension - Pointer to the miniport driver's device extension.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
VOID ProcessNonDDC(
|
|
PHW_DEVICE_EXTENSION HwDeviceExtension
|
|
)
|
|
{
|
|
ULONG i ;
|
|
|
|
VideoDebugPrint((1, "NonDDC!ProcessNonDDC\n"));
|
|
|
|
NonDDCTable = 0 ;
|
|
|
|
if (NO_ERROR == VideoPortGetRegistryParameters(HwDeviceExtension,
|
|
L"NonDDCMonitor.Data",
|
|
FALSE,
|
|
CirrusNonDDCRegistryCallback,
|
|
NULL))
|
|
{
|
|
//
|
|
// We got the table
|
|
//
|
|
//
|
|
// Check EDID table 8-byte header
|
|
// The correct first 8 bytes of EDID table is 0x00, 0xFF, 0xFF, 0xFF,
|
|
// 0xFF, 0xFF, 0xFF, 0x00
|
|
//
|
|
|
|
if ((EDIDBuffer[0] != 0) ||
|
|
(EDIDBuffer[7] != 0))
|
|
{
|
|
VideoDebugPrint((1, "CLNonDDC: Invalid EDID header table\n"));
|
|
return ;
|
|
}
|
|
for (i = 1; i < 7; i++)
|
|
{
|
|
if (EDIDBuffer[i] != 0xFF)
|
|
{
|
|
VideoDebugPrint((1, "CLNonDDC: Invalid EDID header table\n"));
|
|
return ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set NonDDCTable Flag and find timing values.
|
|
//
|
|
NonDDCTable = 1 ;
|
|
EDIDTiming_I = EDIDBuffer[35] ;
|
|
EDIDTiming_II = EDIDBuffer[36] ;
|
|
EDIDTiming_III = EDIDBuffer[37] ;
|
|
ulEDIDMaxTiming= CalculateMaxinumTiming();
|
|
VideoDebugPrint((1, "NonDDC: NonDDC is supported\n"));
|
|
}
|
|
} // end of ProcessNonDDC
|