Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
6.1 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ddc.c
  5. Abstract:
  6. This module contains the code that support DDC querying..
  7. Environment:
  8. Kernel mode
  9. Revision History:
  10. --*/
  11. #include <dderror.h>
  12. #include <devioctl.h>
  13. #include <miniport.h>
  14. #include <ntddvdeo.h>
  15. #include <video.h>
  16. #include <cirrus.h>
  17. VOID WriteClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
  18. VOID WriteDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
  19. BOOLEAN ReadClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension);
  20. BOOLEAN ReadDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension);
  21. VOID WaitForVsyncActive(PHW_DEVICE_EXTENSION HwDeviceExtension);
  22. /****************************************************************
  23. ; DDC register
  24. ;
  25. ; Controls the individual toggling of bits in Sr8 to produce
  26. ; clock and data pulses.
  27. ;
  28. ; Sr8 is defined as follows:
  29. ;
  30. ; 7 ... 2 1 0 SCW = CLK Write
  31. ; |---|---|---|---|---| SDW = DATA Write
  32. ; |SDR ...|SCR|SDW|SCW| SCR = CLK Read
  33. ; --------------------- SDR = DATA Read
  34. ;
  35. ;****************************************************************/
  36. #define DDC_PORT (HwDeviceExtension->IOAddress + SEQ_DATA_PORT)
  37. #define STATUS_PORT (HwDeviceExtension->IOAddress + INPUT_STATUS_1_COLOR)
  38. #define VSYNC_ACTIVE 0x08
  39. VOID WriteClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
  40. {
  41. UCHAR ucPortData;
  42. //
  43. // read the current value and reset the clock line.
  44. //
  45. ucPortData = (VideoPortReadPortUchar(DDC_PORT) & 0xFE) | ucData;
  46. VideoPortWritePortUchar(DDC_PORT, ucPortData);
  47. }
  48. VOID WriteDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
  49. {
  50. UCHAR ucPortData;
  51. //
  52. // read the current value and reset the data line.
  53. //
  54. ucPortData = (VideoPortReadPortUchar(DDC_PORT) & 0xFD) | (ucData << 1);
  55. VideoPortWritePortUchar(DDC_PORT, ucPortData);
  56. }
  57. BOOLEAN ReadClockLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
  58. {
  59. UCHAR uc;
  60. uc = VideoPortReadPortUchar(DDC_PORT);
  61. //VideoDebugPrint((0, "Read = 0x%x\n", uc));
  62. return ((VideoPortReadPortUchar(DDC_PORT) & 0x04) >> 2);
  63. }
  64. BOOLEAN ReadDataLine(PHW_DEVICE_EXTENSION HwDeviceExtension)
  65. {
  66. UCHAR uc;
  67. uc = VideoPortReadPortUchar(DDC_PORT);
  68. //VideoDebugPrint((0, "Read = 0x%x\n", uc));
  69. return ((VideoPortReadPortUchar(DDC_PORT) & 0x80) >> 7);
  70. }
  71. VOID WaitForVsyncActive(PHW_DEVICE_EXTENSION HwDeviceExtension)
  72. {
  73. while ((VideoPortReadPortUchar(STATUS_PORT) & VSYNC_ACTIVE) != 0);
  74. while ((VideoPortReadPortUchar(STATUS_PORT) & VSYNC_ACTIVE) == 0);
  75. }
  76. BOOLEAN
  77. GetDdcInformation(
  78. PHW_DEVICE_EXTENSION HwDeviceExtension,
  79. PUCHAR QueryBuffer,
  80. ULONG BufferSize)
  81. /*++
  82. Routine Description:
  83. Reads the basic EDID structure from the monitor using DDC2.
  84. Arguments:
  85. HwDeviceExtension - Points to per-adapter device extension.
  86. QueryBuffer - Buffer where information will be stored.
  87. BufferSize - Size of the buffer to fill.
  88. Return Value:
  89. Whether the call succeeded or not.
  90. --*/
  91. {
  92. UCHAR ucData;
  93. BOOLEAN bRet = FALSE;
  94. I2C_FNC_TABLE i2c;
  95. ULONG i;
  96. UCHAR OldSeqIdx;
  97. UCHAR ucSr6;
  98. UCHAR ucSr8;
  99. // workaround for Cirrus HW problem (part 1/2)
  100. static UCHAR onceQueryBuffer [512]; // EDID length is expected to be 128 or 256 bytes
  101. static UCHAR onceReadAttempt = FALSE;
  102. static UCHAR onceReturnedValue;
  103. if (onceReadAttempt) {
  104. VideoDebugPrint((1, "CIRRUS: ONCE READ => returning previously obtained data\n"));
  105. memcpy (QueryBuffer, onceQueryBuffer, BufferSize);
  106. return onceReturnedValue;
  107. }
  108. // end of the workaround (part 1/2)
  109. OldSeqIdx = VideoPortReadPortUchar(HwDeviceExtension->IOAddress
  110. + SEQ_ADDRESS_PORT);
  111. //
  112. // Make sure the extension registers are unlocked.
  113. //
  114. VideoPortWritePortUchar(
  115. HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
  116. 0x6);
  117. ucSr6 = VideoPortReadPortUchar(
  118. HwDeviceExtension->IOAddress + SEQ_DATA_PORT);
  119. VideoPortWritePortUchar(
  120. HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
  121. 0x12);
  122. VideoPortWritePortUchar(
  123. HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
  124. 0x08);
  125. ucSr8 = VideoPortReadPortUchar(
  126. HwDeviceExtension->IOAddress + SEQ_DATA_PORT);
  127. VideoPortWritePortUchar(
  128. HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
  129. (UCHAR)(ucSr8 | 0x40));
  130. i2c.WriteClockLine = WriteClockLine;
  131. i2c.WriteDataLine = WriteDataLine;
  132. i2c.ReadClockLine = ReadClockLine;
  133. i2c.ReadDataLine = ReadDataLine;
  134. i2c.WaitVsync = WaitForVsyncActive;
  135. i2c.Size = sizeof(I2C_FNC_TABLE);
  136. // 5430/5440 has a problem doing DDC unless we wait for vsync first.
  137. if (HwDeviceExtension->ChipType == CL543x && HwDeviceExtension->ChipRevision == CL5430_ID)
  138. {
  139. WaitForVsyncActive(HwDeviceExtension);
  140. }
  141. bRet = VideoPortDDCMonitorHelper(HwDeviceExtension,
  142. &i2c,
  143. QueryBuffer,
  144. BufferSize);
  145. VideoPortWritePortUchar(
  146. HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
  147. 0x08);
  148. VideoPortWritePortUchar(
  149. HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
  150. ucSr8);
  151. VideoPortWritePortUchar(
  152. HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
  153. 0x6);
  154. VideoPortWritePortUchar(
  155. HwDeviceExtension->IOAddress + SEQ_DATA_PORT,
  156. ucSr6);
  157. VideoPortWritePortUchar(
  158. HwDeviceExtension->IOAddress + SEQ_ADDRESS_PORT,
  159. OldSeqIdx);
  160. // workaround for Cirrus HW problem (part 2/2)
  161. onceReadAttempt = TRUE;
  162. onceReturnedValue = bRet;
  163. VideoDebugPrint((1, "CIRRUS: first EDID reading attempt "));
  164. if (onceReturnedValue)
  165. VideoDebugPrint((1, "succeeded"));
  166. else
  167. VideoDebugPrint((1, "failed"));
  168. VideoDebugPrint((1, " - the result saved\n"));
  169. memcpy (onceQueryBuffer, QueryBuffer, BufferSize);
  170. // end of the workaround (part 1/2)
  171. return bRet;
  172. }