Leaked source code of windows server 2003
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.

1637 lines
41 KiB

  1. //***************************************************************************
  2. // Module Name: s3ddc.c
  3. //
  4. // Description: This module checks for a DDC monitor, and returns the
  5. // 128 bytes of EDID table if found.
  6. //
  7. // Notes: The routine, DdcSetupRefresh, keeps track of resolution
  8. // changes in the registry. On a resolution change,
  9. // DdcSetupRefresh will select the optimal refresh rate. If
  10. // there is NOT any change in the resolution, the user can
  11. // select any refresh rate, as long as the monitor and
  12. // driver can support it.
  13. //
  14. // Copyright (c) 1996 S3, Inc.
  15. //
  16. //***************************************************************************
  17. //@@BEGIN_S3MSINTERNAL
  18. //
  19. // Revision History:
  20. //
  21. // $Log: Q:/SOFTDEV/VCS/NT/MINIPORT/s3ddc.c_v $
  22. //
  23. // Rev 1.13 04 Feb 1997 23:40:52 kkarnos
  24. //Added BEGIN/END S3MSINTERNAL blocks.
  25. //
  26. // Rev 1.12 30 Jan 1997 14:56:24 bryhti
  27. //Fixed the refresh frequency calculation in the Detailed Timing section
  28. //of DdcMaxRefresh - was causing problems in NT 3.51.
  29. //
  30. // Rev 1.11 30 Jan 1997 09:47:36 bryhti
  31. //Fixed the "for" loop count for Standard Timings in DdcMaxRefresh.
  32. //
  33. // Rev 1.10 16 Jan 1997 09:21:28 bryhti
  34. //Added CheckDDCType routine to return monitor DDC type.
  35. //
  36. // Rev 1.9 11 Dec 1996 10:24:38 kkarnos
  37. //
  38. //Fix Set_VSYNC.
  39. //
  40. // Rev 1.8 10 Dec 1996 16:45:42 kkarnos
  41. //Just added a comment to explain the source of some odd 764 code (EKL input)
  42. //
  43. // Rev 1.7 10 Dec 1996 16:37:08 kkarnos
  44. //Use register and register bit defines. Correct assignment of SET VSYNC bit
  45. //
  46. // Rev 1.6 02 Dec 1996 07:46:16 bryhti
  47. //
  48. //Moved GetDdcInformation () prototype to S3.H. Added code to
  49. //DdcMaxRefresh () to also check the Detailed Timing Descriptions.
  50. //
  51. // Rev 1.5 13 Nov 1996 10:14:08 bryhti
  52. //Major cleanup/rewrite to get DDC1 and DDC2 support on M65. Also got DDC1
  53. //support working on 765.
  54. //
  55. // Rev 1.4 02 Oct 1996 13:56:42 elau
  56. //765 and new chips support DDC; the newer chip must have a serial port at FF20
  57. //
  58. // Rev 1.3 22 Aug 1996 11:44:40 elau
  59. //Change int to ULONG to remove warning
  60. //
  61. // Rev 1.2 18 Aug 1996 16:30:42 elau
  62. //Use HW default setting for DDC if supports
  63. //
  64. // Rev 1.1 24 Jul 1996 15:37:42 elau
  65. //DDC support for 764
  66. //
  67. // Rev 1.0 12 Jul 1996 11:52:36 elau
  68. //Initial revision.
  69. //
  70. //@@END_S3MSINTERNAL
  71. //***************************************************************************
  72. #include "s3.h"
  73. #include "cmdcnst.h"
  74. #include "s3ddc.h"
  75. #define MMFF20 (PVOID) ((ULONG)(HwDeviceExtension->MmIoBase) + SERIAL_PORT_MM)
  76. #define NO_FLAGS 0
  77. #define VERIFY_CHECKSUM 1
  78. //
  79. // Function Prototypes
  80. //
  81. VOID I2C_Out (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
  82. VOID I2C_Setup (PHW_DEVICE_EXTENSION HwDeviceExtension);
  83. VOID I2C_StartService (PHW_DEVICE_EXTENSION HwDeviceExtension);
  84. VOID I2C_StopService (PHW_DEVICE_EXTENSION HwDeviceExtension);
  85. VOID I2C_BitWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
  86. VOID I2C_AckWrite (PHW_DEVICE_EXTENSION HwDeviceExtension);
  87. VOID I2C_NackWrite (PHW_DEVICE_EXTENSION HwDeviceExtension);
  88. UCHAR I2C_ByteWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData);
  89. UCHAR I2C_BitRead (PHW_DEVICE_EXTENSION HwDeviceExtension);
  90. UCHAR I2C_ByteRead (PHW_DEVICE_EXTENSION HwDeviceExtension);
  91. UCHAR I2C_Data_Request (PHW_DEVICE_EXTENSION, UCHAR, long, long, UCHAR *);
  92. VOID Wait_For_Active (PHW_DEVICE_EXTENSION HwDeviceExtension);
  93. VOID Set_Vsync (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucFlag);
  94. VOID Provide_Fake_VSYNC (PHW_DEVICE_EXTENSION HwDeviceExtension);
  95. UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension);
  96. VOID Disable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension);
  97. VOID Enable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension);
  98. UCHAR Read_EDID_Bit (PHW_DEVICE_EXTENSION HwDeviceExtension);
  99. UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension);
  100. UCHAR Sync_EDID_Header (PHW_DEVICE_EXTENSION HwDeviceExtension);
  101. UCHAR EDID_Buffer_Xfer (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer);
  102. UCHAR Check_DDC1_Monitor (PHW_DEVICE_EXTENSION HwDeviceExtension);
  103. UCHAR Configure_Chip_DDC_Caps (PHW_DEVICE_EXTENSION HwDeviceExtension);
  104. UCHAR GetDdcInformation (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer);
  105. /****************************************************************
  106. ; I2C_Out
  107. ;
  108. ; Controls the individual toggling of bits in MMFF20 to produce
  109. ; clock and data pulses, and in the end provides a delay.
  110. ;
  111. ; MMIO FF20h is defined as follows:
  112. ;
  113. ; ... 3 2 1 0 SCW = CLK Write
  114. ; --------|---|---|---|---| SDW = DATA Write
  115. ; ...|SDR|SCR|SDW|SCW| SCR = CLK Read
  116. ; ------------------------- SDR = DATA Read
  117. ;
  118. ; Input:
  119. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  120. ; UCHAR ucData
  121. ; Bit 7:2 = 0
  122. ; Bit 1 = SDA
  123. ; Bit 0 = SCL
  124. ; Output:
  125. ;
  126. ;****************************************************************/
  127. VOID I2C_Out (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
  128. {
  129. UCHAR ucPortData;
  130. unsigned int uCount;
  131. //
  132. // read the current value, clear the clock and data bits, and add
  133. // the new clock and data values
  134. //
  135. ucPortData = (VideoPortReadRegisterUchar (MMFF20) & 0xFC) | ucData;
  136. VideoPortWriteRegisterUchar (MMFF20, ucPortData);
  137. //
  138. // if we set the clock high, wait for target to set clock high
  139. //
  140. if (ucData & 0x01)
  141. {
  142. uCount = 2000;
  143. do
  144. {
  145. --uCount;
  146. ucPortData = VideoPortReadRegisterUchar (MMFF20) & 0x04;
  147. } while ( !ucPortData && uCount );
  148. }
  149. VideoPortStallExecution(5);
  150. }
  151. /****************************************************************
  152. ; I2C_Setup
  153. ;
  154. ; Allow one very long low clock pulse so that monitor has time
  155. ; to switch to DDC2 mode.
  156. ;
  157. ; Input:
  158. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  159. ;
  160. ; Output:
  161. ;
  162. ;****************************************************************/
  163. VOID I2C_Setup (PHW_DEVICE_EXTENSION HwDeviceExtension)
  164. {
  165. //
  166. // CLK=low, DATA=high
  167. //
  168. I2C_Out (HwDeviceExtension, 0x02);
  169. Wait_For_Active (HwDeviceExtension);
  170. Wait_For_Active (HwDeviceExtension);
  171. //
  172. // CLK=high, DATA=high
  173. //
  174. I2C_Out (HwDeviceExtension, 0x03);
  175. Wait_For_Active (HwDeviceExtension);
  176. Wait_For_Active (HwDeviceExtension);
  177. }
  178. /****************************************************************
  179. ; I2C_StartService
  180. ;
  181. ; Provide start sequence for talking to I2C bus.
  182. ;
  183. ; Input:
  184. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  185. ;
  186. ; Output:
  187. ;
  188. ;****************************************************************/
  189. VOID I2C_StartService (PHW_DEVICE_EXTENSION HwDeviceExtension)
  190. {
  191. //
  192. // CLK=low, DATA=high
  193. //
  194. I2C_Out (HwDeviceExtension, 0x02);
  195. //
  196. // CLK=high, DATA=high
  197. //
  198. I2C_Out (HwDeviceExtension, 0x03);
  199. //
  200. // CLK=high, DATA=low
  201. //
  202. I2C_Out (HwDeviceExtension, 0x01);
  203. //
  204. // CLK=low, DATA=low
  205. //
  206. I2C_Out (HwDeviceExtension, 0x00);
  207. }
  208. /****************************************************************
  209. ; I2C_StopService
  210. ;
  211. ; Provide stop sequence to the I2C bus.
  212. ;
  213. ; Input:
  214. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  215. ;
  216. ; Output:
  217. ;
  218. ;***************************************************************/
  219. VOID I2C_StopService (PHW_DEVICE_EXTENSION HwDeviceExtension)
  220. {
  221. //
  222. // CLK=low, DATA=low
  223. //
  224. I2C_Out (HwDeviceExtension, 0x00);
  225. //
  226. // CLK=high, DATA=low
  227. //
  228. I2C_Out (HwDeviceExtension, 0x01);
  229. //
  230. // CLK=high, DATA=high
  231. //
  232. I2C_Out (HwDeviceExtension, 0x03);
  233. //
  234. // CLK=low, DATA=high
  235. //
  236. I2C_Out (HwDeviceExtension, 0x02);
  237. }
  238. /****************************************************************
  239. ; I2C_BitWrite
  240. ;
  241. ; Writes one SDA bit to the I2C bus.
  242. ;
  243. ; Input:
  244. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  245. ; Bit 1 of ucData = Bit to be written.
  246. ;
  247. ; Output:
  248. ;
  249. ;***************************************************************/
  250. VOID I2C_BitWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
  251. {
  252. //
  253. // save valid data bit
  254. //
  255. ucData &= 0x02;
  256. //
  257. // CLK=low, DATA=xxxx
  258. //
  259. I2C_Out (HwDeviceExtension, ucData);
  260. //
  261. // CLK=high, DATA=xxxx
  262. //
  263. I2C_Out (HwDeviceExtension, (UCHAR) (ucData | 0x01));
  264. //
  265. // CLK=low, DATA=xxxx
  266. //
  267. I2C_Out(HwDeviceExtension, ucData);
  268. }
  269. /****************************************************************
  270. ; I2C_ByteWrite
  271. ;
  272. ; Output a byte of information to the Display.
  273. ;
  274. ; Input:
  275. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  276. ; ucData = Byte to be written.
  277. ;
  278. ; Output:
  279. ; TRUE - write successfully
  280. ; FALSE - write failure
  281. ;
  282. ;***************************************************************/
  283. UCHAR I2C_ByteWrite (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucData)
  284. {
  285. UCHAR uOutData;
  286. int i;
  287. uOutData = ucData;
  288. //
  289. // send MSB first
  290. //
  291. for (i=6; i >= 0; i--)
  292. {
  293. //
  294. // move data bit to bit 1
  295. //
  296. uOutData = (ucData >> i);
  297. I2C_BitWrite (HwDeviceExtension, uOutData);
  298. }
  299. //
  300. // now send LSB
  301. //
  302. uOutData = (ucData << 1);
  303. I2C_BitWrite (HwDeviceExtension, uOutData);
  304. //
  305. // float the data line high for ACK
  306. //
  307. I2C_BitWrite (HwDeviceExtension, 2);
  308. return (TRUE);
  309. }
  310. /****************************************************************
  311. ; I2C_AckWrite
  312. ;
  313. ; Send Acknowledgement when reading info.
  314. ;
  315. ; Input:
  316. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  317. ;
  318. ; Output:
  319. ;
  320. ;***************************************************************/
  321. VOID I2C_AckWrite (PHW_DEVICE_EXTENSION HwDeviceExtension)
  322. {
  323. I2C_BitWrite (HwDeviceExtension, 0);
  324. }
  325. /****************************************************************
  326. ; I2C_NackWrite
  327. ;
  328. ; Send Not ACKnowledgement when reading information.
  329. ; A NACK is DATA high during one clock pulse.
  330. ;
  331. ; Input:
  332. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  333. ;
  334. ; Output:
  335. ;
  336. ;***************************************************************/
  337. VOID I2C_NackWrite (PHW_DEVICE_EXTENSION HwDeviceExtension)
  338. {
  339. I2C_BitWrite (HwDeviceExtension, 02);
  340. }
  341. /****************************************************************
  342. ; I2C_BitRead
  343. ;
  344. ; Reads in 1 bit from SDA via the GIP.
  345. ;
  346. ; Input:
  347. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  348. ;
  349. ; Output:
  350. ; Bit 0 of return value contains bit read
  351. ;
  352. ;***************************************************************/
  353. UCHAR I2C_BitRead (PHW_DEVICE_EXTENSION HwDeviceExtension)
  354. {
  355. UCHAR ucRetval;
  356. //
  357. // CLK=low, DATA=high
  358. //
  359. I2C_Out (HwDeviceExtension, 0x02);
  360. //
  361. // CLK=high, DATA=high
  362. //
  363. I2C_Out (HwDeviceExtension, 0x03);
  364. //
  365. // now read in the data bit
  366. //
  367. ucRetval = (VideoPortReadRegisterUchar (MMFF20) & 0x08) >> 3;
  368. //
  369. // CLK=low, DATA=high
  370. //
  371. I2C_Out (HwDeviceExtension, 0x02);
  372. return (ucRetval);
  373. }
  374. /****************************************************************
  375. ; I2C_ByteRead
  376. ;
  377. ; Read a byte of information from the Display
  378. ;
  379. ; Input:
  380. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  381. ;
  382. ; Output:
  383. ; return value is the byte read
  384. ;
  385. ;***************************************************************/
  386. UCHAR I2C_ByteRead (PHW_DEVICE_EXTENSION HwDeviceExtension)
  387. {
  388. UCHAR ucRetval;
  389. int i;
  390. ucRetval = 0;
  391. for (i=0; i < 8; i++)
  392. {
  393. ucRetval <<= 1;
  394. ucRetval |= I2C_BitRead (HwDeviceExtension);
  395. }
  396. return (ucRetval);
  397. }
  398. /****************************************************************
  399. ; I2C_DATA_Request
  400. ;
  401. ; Setup Display to query EDID or VDIF information depending
  402. ; upon the offset given.
  403. ;
  404. ; Input:
  405. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  406. ; ucWriteAddr Write Address of info
  407. ; lLength Length to read,
  408. ; lFlags VERIFY_CHECKSUM
  409. ; pBuffer pointer to buffer to receive data
  410. ;
  411. ; Output:
  412. ; TRUE successful read
  413. ; FALSE read failure or bad checksum
  414. ;
  415. ;****************************************************************/
  416. UCHAR I2C_Data_Request ( PHW_DEVICE_EXTENSION HwDeviceExtension,
  417. UCHAR ucWriteAddr,
  418. long lLength,
  419. long lFlags,
  420. UCHAR *pBuffer )
  421. {
  422. UCHAR ucData;
  423. UCHAR ucCheckSum = 0;
  424. long lCount;
  425. I2C_StartService (HwDeviceExtension);
  426. I2C_ByteWrite (HwDeviceExtension, 0xA0); //Send Device Address + write
  427. I2C_ByteWrite (HwDeviceExtension, ucWriteAddr); //Send Write Address
  428. I2C_StartService (HwDeviceExtension);
  429. I2C_ByteWrite (HwDeviceExtension, 0xA1); //Send Device Address + read
  430. for (lCount = 0; lCount < lLength - 1; lCount++)
  431. {
  432. ucData= I2C_ByteRead (HwDeviceExtension);
  433. I2C_AckWrite (HwDeviceExtension);
  434. *pBuffer++ = ucData;
  435. ucCheckSum += ucData;
  436. }
  437. ucData= I2C_ByteRead (HwDeviceExtension);
  438. I2C_NackWrite (HwDeviceExtension);
  439. *pBuffer = ucData;
  440. ucCheckSum += ucData;
  441. I2C_StopService (HwDeviceExtension);
  442. if (lFlags & VERIFY_CHECKSUM)
  443. {
  444. if (ucCheckSum)
  445. {
  446. return (FALSE); // bad checksum
  447. }
  448. }
  449. return TRUE;
  450. }
  451. /****************************************************************
  452. ; GetDdcInformation
  453. ;
  454. ; Get 128 bytes EDID information if the monitor supports it.
  455. ; The caller is responsible for allocating the memory.
  456. ;
  457. ; Input:
  458. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  459. ; Buffer to receive information
  460. ;
  461. ; Output:
  462. ; TRUE successful
  463. ; FALSE cannot get DdcInformation
  464. ;
  465. ;***************************************************************/
  466. UCHAR GetDdcInformation (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer)
  467. {
  468. UCHAR ucOldCr40;
  469. UCHAR ucOldCr53;
  470. UCHAR ucOldCr55;
  471. UCHAR ucOldCr5C;
  472. UCHAR ucOldSr0D;
  473. UCHAR ucOldSr08;
  474. UCHAR ucOldMMFF20;
  475. UCHAR ucData;
  476. UCHAR ucRetval;
  477. //
  478. // unlock the Sequencer registers
  479. //
  480. VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
  481. ucOldSr08 = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
  482. ucData = UNLOCK_SEQ;
  483. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  484. VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
  485. ucOldSr0D = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
  486. ucData &= DISAB_FEATURE_BITS; // Disable feature connector
  487. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  488. //
  489. // Enable access to the enhanced registers
  490. //
  491. VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
  492. ucOldCr40 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  493. ucData |= ENABLE_ENH_REG_ACCESS;
  494. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  495. //
  496. // Enable MMIO
  497. //
  498. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
  499. ucOldCr53 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  500. ucData |= (ENABLE_OLDMMIO | ENABLE_NEWMMIO);
  501. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  502. //
  503. // GOP_1:0=00b, select MUX channel 0
  504. //
  505. VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
  506. ucOldCr5C = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  507. ucData |= 0x03;
  508. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  509. //
  510. // enable general input port
  511. //
  512. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
  513. ucOldCr55 = VideoPortReadPortUchar (CRT_DATA_REG);
  514. //
  515. // the 764 doesn't support MMFF20
  516. //
  517. // enable the General Input Port
  518. //
  519. if (HwDeviceExtension->SubTypeID == SUBTYPE_764)
  520. {
  521. VideoPortWritePortUchar (CRT_DATA_REG,
  522. (UCHAR) (ucOldCr55 | ENABLE_GEN_INPORT_READ));
  523. }
  524. else
  525. {
  526. //
  527. // enable the serial port
  528. //
  529. ucOldMMFF20 = VideoPortReadRegisterUchar (MMFF20);
  530. VideoPortWriteRegisterUchar (MMFF20, 0x13);
  531. }
  532. //
  533. // determine DDC capabilities and branch accordingly
  534. //
  535. switch ( Configure_Chip_DDC_Caps (HwDeviceExtension) )
  536. {
  537. case DDC2:
  538. I2C_Setup (HwDeviceExtension);
  539. ucRetval = I2C_Data_Request (
  540. HwDeviceExtension,
  541. 0, // address offset
  542. 128, // read 128 bytes
  543. VERIFY_CHECKSUM, // verify checksum
  544. pBuffer); // buffer to put data
  545. break;
  546. case DDC1:
  547. Disable_DAC_Video (HwDeviceExtension);
  548. //
  549. // first try to sync with the EDID header
  550. //
  551. if (ucRetval = Sync_EDID_Header (HwDeviceExtension))
  552. {
  553. //
  554. // now read in the remainder of the information
  555. //
  556. ucRetval = EDID_Buffer_Xfer (HwDeviceExtension, pBuffer);
  557. }
  558. Enable_DAC_Video (HwDeviceExtension);
  559. break;
  560. default:
  561. ucRetval = FALSE; // failure
  562. break;
  563. }
  564. //
  565. // restore the original register values
  566. //
  567. if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
  568. {
  569. VideoPortWriteRegisterUchar (MMFF20, ucOldMMFF20);
  570. }
  571. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
  572. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr55);
  573. VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
  574. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr5C);
  575. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
  576. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr53);
  577. VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
  578. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr40);
  579. VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
  580. VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr0D);
  581. VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
  582. VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr08);
  583. return (ucRetval);
  584. }
  585. /****************************************************************
  586. ; Wait_For_Active
  587. ;
  588. ; Use two loop method to find VSYNC then return just after the
  589. ; falling edge.
  590. ;
  591. ; Input:
  592. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  593. ;
  594. ; Output:
  595. ;
  596. ;***************************************************************/
  597. VOID Wait_For_Active (PHW_DEVICE_EXTENSION HwDeviceExtension)
  598. {
  599. PUCHAR InStatPort = SYSTEM_CONTROL_REG;
  600. while ((VideoPortReadPortUchar (InStatPort) & VSYNC_ACTIVE) != 0) ;
  601. while ((VideoPortReadPortUchar (InStatPort) & VSYNC_ACTIVE) == 0) ;
  602. }
  603. /****************************************************************
  604. ; Set_VSYNC
  605. ;
  606. ; Read the current polarity of the sync, then toggle it on
  607. ; if ucFlag=1, or off if ucFlag=0.
  608. ;
  609. ; Input:
  610. ; using Seq. registers PHW_DEVICE_EXTENSION
  611. ; ucFlag - see above comment
  612. ;
  613. ; Output:
  614. ;
  615. ;****************************************************************/
  616. VOID Set_Vsync (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR ucFlag)
  617. {
  618. UCHAR ucData;
  619. //
  620. // read Sequencer Register D and clear VSYNC bits
  621. //
  622. VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
  623. ucData = VideoPortReadPortUchar (SEQ_DATA_REG) & CLEAR_VSYNC;
  624. //
  625. // set VSYNC per the input flag
  626. //
  627. if (ucFlag)
  628. ucData = ((ucData & CLEAR_VSYNC) | SET_VSYNC1);
  629. else
  630. ucData = ((ucData & CLEAR_VSYNC) | SET_VSYNC0);
  631. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  632. }
  633. /****************************************************************
  634. ; Provide_Fake_VSYNC
  635. ;
  636. ; Use loop delays to create a fake VSYNC signal. (~14.9KHz)
  637. ;
  638. ; Input:
  639. ; using Seq. registers PHW_DEVICE_EXTENSION
  640. ;
  641. ; Output:
  642. ;
  643. ;***************************************************************/
  644. VOID Provide_Fake_VSYNC (PHW_DEVICE_EXTENSION HwDeviceExtension)
  645. {
  646. int i;
  647. Set_Vsync (HwDeviceExtension, 0x01); // Turn on VSYNC
  648. VideoPortStallExecution(5);
  649. Set_Vsync (HwDeviceExtension, 0x00); // Turn off VSYNC
  650. VideoPortStallExecution(5);
  651. }
  652. /****************************************************************
  653. ; Disable_DAC_Video
  654. ;
  655. ; Disable the DAC video driving BLANK active high. This is
  656. ; done by setting bit D5 of sequencer register 01.
  657. ;****************************************************************/
  658. VOID Disable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension)
  659. {
  660. UCHAR ucIndex;
  661. UCHAR ucData;
  662. ucIndex = VideoPortReadPortUchar (SEQ_ADDRESS_REG);
  663. VideoPortWritePortUchar (SEQ_ADDRESS_REG, CLK_MODE_SEQREG);
  664. //
  665. // set screen off bit
  666. //
  667. ucData = VideoPortReadPortUchar (SEQ_DATA_REG) | SCREEN_OFF_BIT;
  668. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  669. //
  670. // restore old index value
  671. //
  672. VideoPortWritePortUchar (SEQ_ADDRESS_REG, ucIndex);
  673. }
  674. /****************************************************************
  675. ; Disable_DAC_Video
  676. ;
  677. ; Enable the DAC video by clearing bit D5 in sequencer register 01
  678. ;***************************************************************/
  679. VOID Enable_DAC_Video (PHW_DEVICE_EXTENSION HwDeviceExtension)
  680. {
  681. UCHAR ucIndex;
  682. UCHAR ucData;
  683. ucIndex = VideoPortReadPortUchar (SEQ_ADDRESS_REG);
  684. VideoPortWritePortUchar (SEQ_ADDRESS_REG, CLK_MODE_SEQREG);
  685. //
  686. // clear screen off bit
  687. //
  688. ucData = VideoPortReadPortUchar (SEQ_DATA_REG) & (~SCREEN_OFF_BIT);
  689. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  690. //
  691. // restore old Index value
  692. //
  693. VideoPortWritePortUchar (SEQ_ADDRESS_REG, ucIndex);
  694. }
  695. /****************************************************************
  696. ; Read_EDID_Bit:
  697. ;
  698. ; Read the next DDC1 EDID data bit
  699. ;
  700. ; Inputs:
  701. ; PHW_DEVICE_EXTENSION HwDeviceExtension
  702. ;
  703. ; Return:
  704. ; UCHAR ucData - data in bit 0
  705. ;
  706. ;***************************************************************/
  707. UCHAR Read_EDID_Bit (PHW_DEVICE_EXTENSION HwDeviceExtension)
  708. {
  709. switch (HwDeviceExtension->SubTypeID)
  710. {
  711. case SUBTYPE_764:
  712. return (VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 1);
  713. break;
  714. default:
  715. return ((VideoPortReadRegisterUchar (MMFF20) & 8) >> 3);
  716. break;
  717. }
  718. }
  719. /****************************************************************
  720. ; Read_EDID_Byte
  721. ;
  722. ; Reads eight bits from the EDID string
  723. ;
  724. ; Input:
  725. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  726. ;
  727. ; Output:
  728. ; return byte value
  729. ;
  730. ;****************************************************************/
  731. UCHAR Read_EDID_Byte (PHW_DEVICE_EXTENSION HwDeviceExtension)
  732. {
  733. long i;
  734. UCHAR ucRetData;
  735. ucRetData = 0;
  736. for (i=0; i < 8; i++)
  737. {
  738. ucRetData <<= 1;
  739. Provide_Fake_VSYNC (HwDeviceExtension);
  740. ucRetData |= Read_EDID_Bit (HwDeviceExtension);
  741. }
  742. return (ucRetData);
  743. }
  744. /****************************************************************
  745. ; Sync_EDID_Header
  746. ;
  747. ; Find and sync to the header - 00 FF FF FF FF FF FF 00
  748. ;
  749. ; Inputs:
  750. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  751. ;
  752. ; Outputs:
  753. ; TRUE = Header Found
  754. ; FALSE = Header NOT Found
  755. ;
  756. ;***************************************************************/
  757. UCHAR Sync_EDID_Header (PHW_DEVICE_EXTENSION HwDeviceExtension)
  758. {
  759. long lBitCount;
  760. long lEndCount;
  761. UCHAR uInSync;
  762. UCHAR ucEdidData;
  763. //
  764. // there are 8 * 128 bits total, but we could start reading near
  765. // the end of the header and realize the error after starting into
  766. // the beginning of the header and have to read the entire header
  767. // again, so we will try reading up to 144 bytes for safety
  768. //
  769. // the header is 00 FF FF FF FF FF FF 00
  770. //
  771. lBitCount = 0; // init bit counter
  772. do
  773. {
  774. uInSync = TRUE; // assume found header
  775. //
  776. // looking for 00
  777. // checking first bit
  778. //
  779. for (lEndCount = lBitCount + 8; lBitCount < lEndCount; lBitCount++)
  780. {
  781. Provide_Fake_VSYNC (HwDeviceExtension);
  782. ucEdidData = Read_EDID_Bit (HwDeviceExtension);
  783. if (ucEdidData == 1)
  784. {
  785. uInSync = FALSE;
  786. break;
  787. }
  788. }
  789. if (!uInSync)
  790. continue; // start all over
  791. //
  792. // send ACK
  793. //
  794. Provide_Fake_VSYNC (HwDeviceExtension);
  795. //
  796. // looking for FF FF FF FF FF FF
  797. // 8 data bits
  798. // 1 bit of acknowledgement
  799. //
  800. for (lEndCount = lBitCount + 6 * 8; lBitCount < lEndCount; lBitCount++)
  801. {
  802. Provide_Fake_VSYNC (HwDeviceExtension);
  803. ucEdidData = Read_EDID_Bit (HwDeviceExtension);
  804. if (ucEdidData == 0)
  805. {
  806. uInSync = FALSE;
  807. break;
  808. }
  809. //
  810. // send an ACK if we have read 8 bits
  811. //
  812. if (!((lEndCount - lBitCount + 1) % 8))
  813. {
  814. Provide_Fake_VSYNC (HwDeviceExtension);
  815. }
  816. }
  817. if (!uInSync)
  818. continue; // start all over
  819. //
  820. // now looking for last 00 of header
  821. //
  822. for (lEndCount = lBitCount + 8; lBitCount < lEndCount; lBitCount++)
  823. {
  824. Provide_Fake_VSYNC (HwDeviceExtension);
  825. ucEdidData = Read_EDID_Bit (HwDeviceExtension);
  826. if (ucEdidData == 1)
  827. {
  828. uInSync = FALSE;
  829. break;
  830. }
  831. }
  832. if(!uInSync)
  833. continue; // start all over
  834. //
  835. // Acknowledgment
  836. //
  837. Provide_Fake_VSYNC (HwDeviceExtension);
  838. } while ( (!uInSync) && (lBitCount < (8 * 144)) );
  839. return (uInSync);
  840. }
  841. /****************************************************************
  842. ; EDID_Buffer_Xfer
  843. ;
  844. ; Transfer all EDID data to pBuffer. Caller must allocate enough
  845. ; memory to receive 128 bytes.
  846. ;
  847. ; Input:
  848. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  849. ; Pointer to receive buffer
  850. ;
  851. ; Output:
  852. ; TRUE data in buffer & checksum is correct
  853. ; FALSE error or bad checksum
  854. ;
  855. ;****************************************************************/
  856. UCHAR EDID_Buffer_Xfer (PHW_DEVICE_EXTENSION HwDeviceExtension, UCHAR* pBuffer)
  857. {
  858. UCHAR ucChecksum = 0x0FA;
  859. UCHAR ucEdidData;
  860. unsigned int uCount;
  861. //
  862. // put the 8 header bytes in the buffer
  863. //
  864. *pBuffer = 0;
  865. for (uCount = 1; uCount < 7; uCount++)
  866. *(pBuffer+uCount) = 0xFF;
  867. *(pBuffer+uCount) = 0x00;
  868. for (uCount = 8; uCount < 128; uCount++)
  869. {
  870. ucEdidData = Read_EDID_Byte (HwDeviceExtension);
  871. //
  872. // send Acknowledgment
  873. // add data to buffer
  874. // add data to checksum
  875. //
  876. Provide_Fake_VSYNC (HwDeviceExtension);
  877. *(pBuffer+uCount) = ucEdidData;
  878. ucChecksum += ucEdidData;
  879. }
  880. if (!ucChecksum)
  881. {
  882. return (TRUE); // checksum is OK
  883. }
  884. return (FALSE); // checksum is NOT
  885. }
  886. /****************************************************************
  887. ; Check_DDC1_Monitor
  888. ;
  889. ; Check for a DDC1 monitor using current vsync.
  890. ;
  891. ; Input:
  892. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  893. ;
  894. ; Output:
  895. ; TRUE possible DDC1 monitor
  896. ; FALSE no EDID data detected on input port
  897. ;
  898. ;****************************************************************/
  899. UCHAR Check_DDC1_Monitor (PHW_DEVICE_EXTENSION HwDeviceExtension)
  900. {
  901. UCHAR ucSaveOldData;
  902. UCHAR ucData;
  903. UCHAR ucGD0;
  904. unsigned int uCount;
  905. UCHAR ucDDC1;
  906. //
  907. // assume not DDC1
  908. //
  909. ucDDC1 = FALSE;
  910. switch (HwDeviceExtension->SubTypeID)
  911. {
  912. //
  913. // use reads from 3C8 on the 764 (undocumented, but this use
  914. // of the DAC register comes from the 764 BIOS source code).
  915. //
  916. case SUBTYPE_764:
  917. ucSaveOldData = VideoPortReadPortUchar (MISC_OUTPUT_REG_READ);
  918. //
  919. // Bit 7 = 0 Positive VSYNC
  920. //
  921. VideoPortWritePortUchar (MISC_OUTPUT_REG_WRITE,
  922. (UCHAR) (ucSaveOldData & SEL_POS_VSYNC));
  923. Wait_For_Active (HwDeviceExtension);
  924. ucData = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT);
  925. //
  926. // Another read for VL systems. (Data left on the GD/SD lines)
  927. //
  928. ucGD0 = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 0x01;
  929. //
  930. // read up to 350 bits looking for the data to toggle, indicating
  931. // DDC1 data is being sent
  932. //
  933. for (uCount = 0; uCount < 350; uCount++)
  934. {
  935. Wait_For_Active (HwDeviceExtension);
  936. ucData = VideoPortReadPortUchar (DAC_ADDRESS_WRITE_PORT) & 0x01;
  937. if (ucData != ucGD0)
  938. {
  939. //
  940. // data line toggled, assume DDC1 data is being sent
  941. //
  942. ucDDC1 = TRUE;
  943. break;
  944. }
  945. }
  946. //
  947. // restore old value
  948. //
  949. VideoPortWritePortUchar (MISC_OUTPUT_REG_WRITE, ucSaveOldData);
  950. break;
  951. //
  952. // else use MMFF20 on the other chips
  953. //
  954. default:
  955. Disable_DAC_Video (HwDeviceExtension);
  956. Provide_Fake_VSYNC (HwDeviceExtension);
  957. ucGD0 = VideoPortReadRegisterUchar (MMFF20) & 8;
  958. for (uCount = 0; uCount < 350; uCount++)
  959. {
  960. Provide_Fake_VSYNC (HwDeviceExtension);
  961. ucData = VideoPortReadRegisterUchar (MMFF20) & 8;
  962. if (ucData != ucGD0)
  963. {
  964. //
  965. // data line toggled, assume DDC1 data is being sent
  966. //
  967. ucDDC1 = TRUE;
  968. break;
  969. }
  970. }
  971. Enable_DAC_Video (HwDeviceExtension);
  972. break;
  973. }
  974. return (ucDDC1);
  975. }
  976. /****************************************************************
  977. ; Configure_Chip_DDC_Caps
  978. ;
  979. ; Determine DDC capabilities of display.
  980. ;
  981. ; Input:
  982. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  983. ;
  984. ; Output:
  985. ; NO_DDC
  986. ; DDC1: Support DDC1
  987. ; DDC2: Support DDC2
  988. ;
  989. ;****************************************************************/
  990. UCHAR Configure_Chip_DDC_Caps (PHW_DEVICE_EXTENSION HwDeviceExtension)
  991. {
  992. UCHAR ucBuffer[2];
  993. //
  994. // we will only use DDC1 on 764
  995. //
  996. if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
  997. {
  998. //
  999. // first check if DDC2 capable
  1000. //
  1001. I2C_Setup (HwDeviceExtension);
  1002. I2C_Data_Request ( HwDeviceExtension,
  1003. 0, // address offset
  1004. 2, // look at first 2 bytes
  1005. NO_FLAGS, // don't verify checksum
  1006. ucBuffer ); // buffer to place data
  1007. //
  1008. // check if the first 2 bytes of the EDID header look correct
  1009. //
  1010. if ( (ucBuffer [0] == 0) &&
  1011. (ucBuffer [1] == 0xFF) )
  1012. {
  1013. return (DDC2); // assume DDC2 capable
  1014. }
  1015. }
  1016. //
  1017. // try DDC1
  1018. //
  1019. if (Check_DDC1_Monitor (HwDeviceExtension))
  1020. {
  1021. return (DDC1);
  1022. }
  1023. return (NO_DDC);
  1024. }
  1025. //---------------------------------------------------------------------------
  1026. ULONG DdcMaxRefresh(ULONG uXresolution, UCHAR * pEdid)
  1027. {
  1028. ULONG uMaxFreq = 0;
  1029. ULONG uEdidRes;
  1030. ULONG uEdidFreq;
  1031. ULONG HorRes, VertRes;
  1032. ULONG i, Index;
  1033. //
  1034. // Detailed timing
  1035. //
  1036. for (i = 0; i < 4; ++i) // 4 Detailed Descriptions
  1037. {
  1038. Index = 54 + i * 18;
  1039. if ( (pEdid [Index] == 0) &&
  1040. (pEdid [Index + 1] == 0) &&
  1041. (pEdid [Index + 2] == 0) )
  1042. {
  1043. continue; // Monitor descriptor block, skip it
  1044. }
  1045. HorRes = ((ULONG) (pEdid [Index + 4] & 0xF0)) << 4;
  1046. HorRes += (ULONG) pEdid [Index + 2];
  1047. if (HorRes == uXresolution)
  1048. {
  1049. //
  1050. // add Horizontal blanking
  1051. //
  1052. HorRes += (ULONG) pEdid [Index + 3];
  1053. HorRes += ((ULONG) (pEdid [Index + 4] & 0x0F)) << 8;
  1054. //
  1055. // now get Vertical Total (Active & Blanking)
  1056. //
  1057. VertRes = ((ULONG) (pEdid [Index + 7] & 0xF0)) << 4;
  1058. VertRes += ((ULONG) (pEdid [Index + 7] & 0x0F)) << 8;
  1059. VertRes += (ULONG) pEdid [Index + 5];
  1060. VertRes += (ULONG) pEdid [Index + 6];
  1061. uEdidFreq = (((ULONG) pEdid [Index + 1]) << 8) +
  1062. ((ULONG) pEdid [Index]);
  1063. uEdidFreq = uEdidFreq * 10000 / HorRes / VertRes;
  1064. if (uEdidFreq > uMaxFreq)
  1065. {
  1066. uMaxFreq = uEdidFreq;
  1067. }
  1068. }
  1069. }
  1070. //
  1071. // Standard timing id.
  1072. //
  1073. for (i = 38; i < 54; i += 2)
  1074. {
  1075. uEdidRes = (((ULONG) pEdid[i]) + 31) * 8;
  1076. if (uXresolution == uEdidRes)
  1077. {
  1078. uEdidFreq = (((ULONG) pEdid[i+1]) & 0x3F) + 60;
  1079. if (uEdidFreq > uMaxFreq)
  1080. {
  1081. uMaxFreq = uEdidFreq;
  1082. }
  1083. }
  1084. }
  1085. //
  1086. // Established timing
  1087. //
  1088. switch (uXresolution)
  1089. {
  1090. case 640:
  1091. uEdidFreq = (ULONG)pEdid[0x23];
  1092. if (uEdidFreq & 0x020)
  1093. {
  1094. if (uMaxFreq < 60)
  1095. {
  1096. uMaxFreq = 60;
  1097. }
  1098. }
  1099. if (uEdidFreq & 0x08)
  1100. {
  1101. if (uMaxFreq < 72)
  1102. {
  1103. uMaxFreq = 72;
  1104. }
  1105. }
  1106. if (uEdidFreq & 0x04)
  1107. {
  1108. if (uMaxFreq < 75)
  1109. {
  1110. uMaxFreq = 75;
  1111. }
  1112. }
  1113. break;
  1114. case 800:
  1115. uEdidFreq = (ULONG)pEdid[0x23];
  1116. if (uEdidFreq & 0x02)
  1117. {
  1118. if (uMaxFreq < 56)
  1119. {
  1120. uMaxFreq = 56;
  1121. }
  1122. }
  1123. if (uEdidFreq & 0x01)
  1124. {
  1125. if (uMaxFreq < 60)
  1126. {
  1127. uMaxFreq = 60;
  1128. }
  1129. }
  1130. uEdidFreq = (ULONG)pEdid[0x24];
  1131. if (uEdidFreq & 0x80)
  1132. {
  1133. if (uMaxFreq < 72)
  1134. {
  1135. uMaxFreq = 72;
  1136. }
  1137. }
  1138. if (uEdidFreq & 0x40)
  1139. {
  1140. if (uMaxFreq < 75)
  1141. {
  1142. uMaxFreq = 75;
  1143. }
  1144. }
  1145. break;
  1146. case 1024:
  1147. uEdidFreq = (ULONG)pEdid[0x24];
  1148. if (uEdidFreq & 0x08)
  1149. {
  1150. if (uMaxFreq < 60)
  1151. {
  1152. uMaxFreq = 60;
  1153. }
  1154. }
  1155. if (uEdidFreq & 0x04)
  1156. {
  1157. if (uMaxFreq < 70)
  1158. {
  1159. uMaxFreq = 70;
  1160. }
  1161. }
  1162. if (uEdidFreq & 0x02)
  1163. {
  1164. if (uMaxFreq < 75)
  1165. {
  1166. uMaxFreq = 75;
  1167. }
  1168. }
  1169. break;
  1170. case 1280:
  1171. uEdidFreq = (ULONG)pEdid[0x24];
  1172. if (uEdidFreq & 0x01)
  1173. {
  1174. if (uMaxFreq < 75)
  1175. {
  1176. uMaxFreq = 75;
  1177. }
  1178. }
  1179. break;
  1180. }
  1181. return(uMaxFreq);
  1182. }
  1183. //---------------------------------------------------------------------------
  1184. ULONG DdcRefresh (PHW_DEVICE_EXTENSION hwDeviceExtension, ULONG uXResolution)
  1185. {
  1186. ULONG lRefresh = 0;
  1187. char szBuffer[200];
  1188. if (GetDdcInformation (hwDeviceExtension, szBuffer))
  1189. {
  1190. lRefresh = DdcMaxRefresh (uXResolution, szBuffer);
  1191. }
  1192. return lRefresh;
  1193. }
  1194. /****************************************************************
  1195. ; CheckDDCType
  1196. ;
  1197. ; Check the monitor for DDC type.
  1198. ;
  1199. ; Input:
  1200. ; Using MMIO Base in PHW_DEVICE_EXTENSION
  1201. ;
  1202. ; Output:
  1203. ; NO_DDC non-DDC monitor
  1204. ; DDC1 DDC1 monitor
  1205. ; DDC2 DDC2 monitor
  1206. ;
  1207. ;***************************************************************/
  1208. UCHAR CheckDDCType (PHW_DEVICE_EXTENSION HwDeviceExtension)
  1209. {
  1210. UCHAR ucOldCr40;
  1211. UCHAR ucOldCr53;
  1212. UCHAR ucOldCr55;
  1213. UCHAR ucOldCr5C;
  1214. UCHAR ucOldSr0D;
  1215. UCHAR ucOldSr08;
  1216. UCHAR ucOldMMFF20;
  1217. UCHAR ucData;
  1218. UCHAR ucRetval;
  1219. //
  1220. // unlock the Sequencer registers
  1221. //
  1222. VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
  1223. ucOldSr08 = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
  1224. ucData = UNLOCK_SEQ;
  1225. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  1226. VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
  1227. ucOldSr0D = ucData = VideoPortReadPortUchar (SEQ_DATA_REG);
  1228. ucData &= DISAB_FEATURE_BITS; // Disable feature connector
  1229. VideoPortWritePortUchar (SEQ_DATA_REG, ucData);
  1230. //
  1231. // Enable access to the enhanced registers
  1232. //
  1233. VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
  1234. ucOldCr40 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  1235. ucData |= ENABLE_ENH_REG_ACCESS;
  1236. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  1237. //
  1238. // Enable MMIO
  1239. //
  1240. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
  1241. ucOldCr53 = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  1242. ucData |= (ENABLE_OLDMMIO | ENABLE_NEWMMIO);
  1243. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  1244. //
  1245. // GOP_1:0=00b, select MUX channel 0
  1246. //
  1247. VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
  1248. ucOldCr5C = ucData = VideoPortReadPortUchar (CRT_DATA_REG);
  1249. ucData |= 0x03;
  1250. VideoPortWritePortUchar (CRT_DATA_REG, ucData);
  1251. //
  1252. // enable general input port
  1253. //
  1254. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
  1255. ucOldCr55 = VideoPortReadPortUchar (CRT_DATA_REG);
  1256. //
  1257. // the 764 doesn't support MMFF20
  1258. //
  1259. // enable the General Input Port
  1260. //
  1261. if (HwDeviceExtension->SubTypeID == SUBTYPE_764)
  1262. {
  1263. VideoPortWritePortUchar (CRT_DATA_REG,
  1264. (UCHAR) (ucOldCr55 | ENABLE_GEN_INPORT_READ));
  1265. }
  1266. else
  1267. {
  1268. //
  1269. // enable the serial port
  1270. //
  1271. ucOldMMFF20 = VideoPortReadRegisterUchar (MMFF20);
  1272. VideoPortWriteRegisterUchar (MMFF20, 0x13);
  1273. }
  1274. //
  1275. // determine DDC capabilities and branch accordingly
  1276. //
  1277. ucRetval = Configure_Chip_DDC_Caps (HwDeviceExtension);
  1278. //
  1279. // restore the original register values
  1280. //
  1281. if (HwDeviceExtension->SubTypeID != SUBTYPE_764)
  1282. {
  1283. VideoPortWriteRegisterUchar (MMFF20, ucOldMMFF20);
  1284. }
  1285. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_DAC_S3EXTREG);
  1286. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr55);
  1287. VideoPortWritePortUchar (CRT_ADDRESS_REG, GENERAL_OUT_S3EXTREG);
  1288. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr5C);
  1289. VideoPortWritePortUchar (CRT_ADDRESS_REG, EXT_MEM_CTRL1_S3EXTREG);
  1290. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr53);
  1291. VideoPortWritePortUchar (CRT_ADDRESS_REG, SYS_CONFIG_S3EXTREG);
  1292. VideoPortWritePortUchar (CRT_DATA_REG, ucOldCr40);
  1293. VideoPortWritePortUchar (SEQ_ADDRESS_REG, SRD_SEQREG);
  1294. VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr0D);
  1295. VideoPortWritePortUchar (SEQ_ADDRESS_REG, UNLOCK_SEQREG);
  1296. VideoPortWritePortUchar (SEQ_DATA_REG, ucOldSr08);
  1297. return (ucRetval);
  1298. }