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.

404 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. edid.c
  5. Abstract:
  6. This is the NT Video port Display Data Channel (DDC) code. It contains the
  7. implementations for the EDID industry standard Extended Display
  8. Identification Data manipulations.
  9. Author:
  10. Bruce McQuistan (brucemc) 23-Sept-1996
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. Based on VESA EDID Specification Version 2, April 9th, 1996
  15. Revision History:
  16. 7/3/97 - brucemc. fixed some detailed timing decoding macros.
  17. 4/14/98 - brucemc. added support for version 3 (revision date 11/13/97).
  18. --*/
  19. #include "videoprt.h"
  20. #include "pedid.h"
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE,EdidCheckSum)
  23. #pragma alloc_text(PAGE,pVideoPortIsValidEDID)
  24. #pragma alloc_text(PAGE,pVideoPortGetEDIDId)
  25. #endif
  26. BOOLEAN
  27. EdidCheckSum(
  28. IN PCHAR pBlob,
  29. IN ULONG BlobSize
  30. )
  31. {
  32. CHAR chk=0;
  33. ULONG i;
  34. for (i=0; i<BlobSize; i++)
  35. chk = (CHAR)(chk + ((CHAR*)pBlob)[i]);
  36. if (chk != 0)
  37. {
  38. pVideoDebugPrint((0, " ***** invalid EDID chksum at %x\n", pBlob));
  39. return FALSE;
  40. }
  41. return TRUE;
  42. }
  43. VOID
  44. pVideoPortGetEDIDId(
  45. PVOID pEdid,
  46. PWCHAR pwChar
  47. )
  48. {
  49. WCHAR _hex[] = L"0123456789ABCDEF";
  50. PUCHAR pTmp;
  51. if ((((UNALIGNED ULONG*)pEdid)[0] == 0xFFFFFF00) &&
  52. (((UNALIGNED ULONG*)pEdid)[1] == 0x00FFFFFF))
  53. pTmp = &(((PEDID_V1)pEdid)->UC_OemIdentification[0]);
  54. else
  55. pTmp = &(((PEDID_V2)pEdid)->UC_Header[1]);
  56. pwChar[0] = 0x40 + ((pTmp[0] >> 2) & 0x1F);
  57. pwChar[1] = 0x40 + (((pTmp[0] << 3)|(pTmp[1] >> 5)) & 0x1F);
  58. pwChar[2] = 0x40 + (pTmp[1] & 0x1F) ;
  59. pwChar[3] = _hex[(pTmp[3] & 0xF0) >> 4];
  60. pwChar[4] = _hex[(pTmp[3] & 0x0F)];
  61. pwChar[5] = _hex[(pTmp[2] & 0xF0) >> 4];
  62. pwChar[6] = _hex[(pTmp[2] & 0x0F)];
  63. pwChar[7] = 0;
  64. }
  65. PVOID
  66. pVideoPortGetMonitordescription(
  67. PVOID pEdid)
  68. {
  69. PWSTR pStr = NULL;
  70. return NULL;
  71. }
  72. BOOLEAN
  73. pVideoPortIsValidEDID(
  74. PVOID pEdid
  75. )
  76. {
  77. CHAR chk=0;
  78. UCHAR versionNumber, revisionNumber;
  79. ULONG i;
  80. ASSERT(pEdid);
  81. //
  82. // Version 1 EDID checking
  83. //
  84. if ((((UNALIGNED ULONG*)pEdid)[0] == 0xFFFFFF00) &&
  85. (((UNALIGNED ULONG*)pEdid)[1] == 0x00FFFFFF))
  86. {
  87. pVideoDebugPrint((1, " ***** Valid EDID1 header at %x\n", pEdid));
  88. return EdidCheckSum(pEdid, 128);
  89. }
  90. //
  91. // EDID V2 support
  92. //
  93. versionNumber = ((PEDID_V2) pEdid)->UC_Header[0];
  94. versionNumber >>= 4;
  95. revisionNumber = ((PEDID_V2) pEdid)->UC_Header[0];
  96. revisionNumber &= 7;
  97. //
  98. // Note that the versionNumber cannot be 1 because then it would
  99. // have to be of the form above.
  100. //
  101. if (versionNumber != 2)
  102. {
  103. pVideoDebugPrint((1, " ***** invalid EDID2 header at %x\n", &((PEDID_V2) pEdid)->UC_Header[0]));
  104. return FALSE;
  105. }
  106. return EdidCheckSum(pEdid, 256);
  107. }
  108. BOOLEAN
  109. VideoPortIsMonitorDescriptor(
  110. IN PEDID_V1 Edid,
  111. IN ULONG BlockNumber
  112. )
  113. /*++
  114. Routine Description:
  115. Determines the Block is a VESA DDC compliant MonitorDescriptor.
  116. Arguments:
  117. Edid - pointer to an EDID
  118. BlockNumber - number indicating which block to query (1-4).
  119. Return Value:
  120. TRUE if the block is a VESA DDC compliant MonitorDescriptor.
  121. FALSE if the block is not a VESA DDC compliant MonitorDescriptor
  122. STATUS_INVALID_PARAMETER if the BlockNumber is invalid.
  123. --*/
  124. {
  125. PMONITOR_DESCRIPTION pMonitorDesc;
  126. switch(BlockNumber) {
  127. default:
  128. pVideoDebugPrint((0, "Bogus DescriptorNumber\n"));
  129. return FALSE;
  130. case 1:
  131. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL1(Edid);
  132. break;
  133. case 2:
  134. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL2(Edid);
  135. break;
  136. case 3:
  137. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL3(Edid);
  138. break;
  139. case 4:
  140. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL4(Edid);
  141. break;
  142. }
  143. if ((pMonitorDesc->Flag1[0] == 0) && (pMonitorDesc->Flag1[1] == 0)) {
  144. return TRUE;
  145. }
  146. pVideoDebugPrint((1, " Not a monitordescriptor\n"));
  147. return FALSE;
  148. }
  149. NTSTATUS
  150. pVideoPortGetMonitorInfo(
  151. IN PMONITOR_DESCRIPTION MonitorDesc,
  152. OUT UCHAR Ascii[64]
  153. )
  154. /*++
  155. Routine Description:
  156. Helper routine for decoding a VESA DDC compliant Monitor Description (Detailed Timing).
  157. Arguments:
  158. MonitorDesc - Pointer to a MONITOR_DESCRIPTION extracted from the EDID.
  159. Ascii - Buffer to be filled in.
  160. Return Value:
  161. STATUS_SUCCESS if successful
  162. STATUS_INVALID_PARAMETER if there's nothing to decode.
  163. --*/
  164. {
  165. PUCHAR pRanges = GET_MONITOR_RANGE_LIMITS(MonitorDesc);
  166. ULONG index;
  167. if (IS_MONITOR_DATA_SN(MonitorDesc) ||
  168. IS_MONITOR_DATA_STRING(MonitorDesc) ||
  169. IS_MONITOR_DATA_NAME(MonitorDesc) ) {
  170. //
  171. // find the things length. It ends in 0xa.
  172. //
  173. RtlCopyMemory(Ascii, pRanges, 13);
  174. for (index = 0; index < 13; ++index) {
  175. if (Ascii[index] == 0x0a) {
  176. Ascii[index] = (UCHAR)NULL;
  177. break;
  178. }
  179. }
  180. Ascii[index] = (UCHAR)NULL;
  181. return STATUS_SUCCESS;
  182. }
  183. return STATUS_INVALID_PARAMETER;
  184. }
  185. NTSTATUS
  186. VideoPortGetEdidMonitorDescription(
  187. IN PEDID_V1 Edid,
  188. IN ULONG DescriptorNumber,
  189. OUT UCHAR Ascii[64]
  190. )
  191. /*++
  192. Routine Description:
  193. Extracts VESA DDC compliant Monitor Descriptor indexed by DescriptorNumber and
  194. decodes it into the REGISTRY_MONITOR_DESCRIPTOR passed in by user.
  195. Arguments:
  196. Edid - Pointer to the a copy of the EDID from the monitors ROM.
  197. DescriptorNumber - a ULONG enumerating which Detailed Descriptor to decode.
  198. Ascii - Buffer to be filled in.
  199. Return Value:
  200. STATUS_SUCCESS or STATUS_INVALID_PARAMETER.
  201. --*/
  202. {
  203. NTSTATUS retval;
  204. PMONITOR_DESCRIPTION pMonitorDesc;
  205. switch(DescriptorNumber) {
  206. default:
  207. pVideoDebugPrint((0, "Bogus DescriptorNumber\n"));
  208. return STATUS_INVALID_PARAMETER;
  209. case 1:
  210. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL1(Edid);
  211. break;
  212. case 2:
  213. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL2(Edid);
  214. break;
  215. case 3:
  216. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL3(Edid);
  217. break;
  218. case 4:
  219. pMonitorDesc = (PMONITOR_DESCRIPTION)GET_EDID_PDETAIL4(Edid);
  220. break;
  221. }
  222. retval = pVideoPortGetMonitorInfo(pMonitorDesc, Ascii);
  223. return retval;
  224. }
  225. ULONG
  226. pVideoPortGetEdidOemID(
  227. IN PVOID pEdid,
  228. OUT PUCHAR pBuffer
  229. )
  230. {
  231. ULONG count, versionNumber, revisionNumber, totalLength = 0;
  232. if ((((UNALIGNED ULONG*)pEdid)[0] == 0xFFFFFF00) &&
  233. (((UNALIGNED ULONG*)pEdid)[1] == 0x00FFFFFF)) {
  234. PEDID_V1 pEdidV1 = (PEDID_V1)pEdid;
  235. for (count = 1; count < 5; ++count) {
  236. if (VideoPortIsMonitorDescriptor(pEdidV1, count)) {
  237. if (STATUS_SUCCESS ==
  238. VideoPortGetEdidMonitorDescription(pEdidV1,
  239. count,
  240. &(pBuffer[totalLength]))) {
  241. totalLength += strlen(&(pBuffer[totalLength]));
  242. pBuffer[totalLength] = '_';
  243. }
  244. }
  245. //
  246. // NULL terminate it.
  247. //
  248. pBuffer[totalLength] = (UCHAR) NULL;
  249. }
  250. return totalLength;
  251. }
  252. //
  253. // EDID V2 support
  254. //
  255. versionNumber = ((PEDID_V2) pEdid)->UC_Header[0];
  256. versionNumber >>= 4;
  257. revisionNumber = ((PEDID_V2) pEdid)->UC_Header[0];
  258. revisionNumber &= 7;
  259. //
  260. // Note that the versionNumber cannot be 1 because then it would
  261. // have to be of the form above.
  262. //
  263. if (versionNumber != 2) {
  264. pVideoDebugPrint((1, " ***** invalid EDID2 header at %x\n", &((PEDID_V2) pEdid)->UC_Header[0]));
  265. return 0;
  266. } else {
  267. PEDID_V2 pEdidV2 = (PEDID_V2)pEdid;
  268. //
  269. // This string has ascii code 0x9 delineating the
  270. // manufacturers name and terminating with 0xa. Replace these
  271. // with '_' and NULL respectively.
  272. //
  273. memcpy(pBuffer, pEdidV2->UC_OemIdentification, 32);
  274. for(count = 0; count < 32; ++count) {
  275. if (pBuffer[count] == 0x9) {
  276. pBuffer[count] = '_';
  277. continue;
  278. }
  279. if (pBuffer[count] == 0xa)
  280. break;
  281. }
  282. pBuffer[count] = (UCHAR)NULL;
  283. }
  284. return (count + 1);
  285. }