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.

2035 lines
68 KiB

  1. /************************************************************************/
  2. /* */
  3. /* SERVICES.C */
  4. /* */
  5. /* Aug 26 1993 (c) 1993, ATI Technologies Incorporated. */
  6. /************************************************************************/
  7. /********************** PolyTron RCS Utilities
  8. $Revision: 1.33 $
  9. $Date: 15 Apr 1996 16:59:44 $
  10. $Author: RWolff $
  11. $Log: S:/source/wnt/ms11/miniport/archive/services.c_v $
  12. *
  13. * Rev 1.33 15 Apr 1996 16:59:44 RWolff
  14. * Now calls new routine to report which flavour of the Mach 64 is
  15. * in use, rather than reporting "Mach 64" for all ASIC types.
  16. *
  17. * Rev 1.32 12 Apr 1996 16:18:16 RWolff
  18. * Now rejects 24BPP modes if linear aperture is not present, since new
  19. * source stream display driver can't do 24BPP in a paged aperture. This
  20. * rejection should be done in the display driver (the card still supports
  21. * the mode, but the display driver doesn't want to handle it), but at
  22. * the point where the display driver must decide to either accept or reject
  23. * modes, it doesn't have access to the aperture information.
  24. *
  25. * Rev 1.31 10 Apr 1996 17:05:28 RWolff
  26. * Made routine delay() nonpageable.
  27. *
  28. * Rev 1.30 01 Mar 1996 12:16:38 RWolff
  29. * Fix for DEC Alpha under NT 4.0: memory-mapped register access is
  30. * via direct pointer read/write in dense space and via VideoPort
  31. * routines in sparse space (VideoPort routines no longer work in
  32. * dense space - this is a HAL bug).
  33. *
  34. * Rev 1.29 09 Feb 1996 13:27:36 RWolff
  35. * Now reports only accelerator memory to display applet for Mach 8 combo
  36. * cards.
  37. *
  38. * Rev 1.28 02 Feb 1996 17:20:10 RWolff
  39. * DDC/VDIF merge source information is now stored in hardware device
  40. * extension rather than static variables, added DEC's workaround to
  41. * Lio[Inp|Outp]([w|d])() routines for NT 4.0 memory mapped register
  42. * access, added routine GetVgaBuffer() to (nondestructively) obtain
  43. * a buffer in physical memory below 1M.
  44. *
  45. * Rev 1.27 23 Jan 1996 11:49:20 RWolff
  46. * Added debug print statements.
  47. *
  48. * Rev 1.26 11 Jan 1996 19:44:34 RWolff
  49. * SetFixedModes() now restricts modes based on pixel clock frequency.
  50. *
  51. * Rev 1.25 22 Dec 1995 14:54:30 RWolff
  52. * Added support for Mach 64 GT internal DAC, switched to TARGET_BUILD
  53. * to identify the NT version for which the driver is being built.
  54. *
  55. * Rev 1.24 21 Nov 1995 11:02:54 RWolff
  56. * Now reads DDC timing data rather than VDIF file if card and monitor
  57. * both support DDC.
  58. *
  59. * Rev 1.23 08 Sep 1995 16:35:52 RWolff
  60. * Added support for AT&T 408 DAC (STG1703 equivalent).
  61. *
  62. * Rev 1.22 28 Jul 1995 14:40:14 RWolff
  63. * Added support for the Mach 64 VT (CT equivalent with video overlay).
  64. *
  65. * Rev 1.21 26 Jul 1995 13:08:30 mgrubac
  66. * Moved mode tables merging from SetFixedModes to VDIFCallback()
  67. * routine.
  68. *
  69. * Rev 1.20 20 Jul 1995 18:00:26 mgrubac
  70. * Added support for VDIF files.
  71. *
  72. * Rev 1.19 02 Jun 1995 14:32:58 RWOLFF
  73. * Added routine UpperCase() to change string into upper case because
  74. * toupper() was coming back as unresolved external on some platforms.
  75. *
  76. * Rev 1.18 10 Apr 1995 17:05:06 RWOLFF
  77. * Made LioInpd() and LioOutpd() nonpageable, since they are called
  78. * (indirectly) by ATIMPResetHw(), which must be nonpageable.
  79. *
  80. * Rev 1.17 31 Mar 1995 11:53:14 RWOLFF
  81. * Changed from all-or-nothing debug print statements to thresholds
  82. * depending on importance of the message.
  83. *
  84. * Rev 1.16 08 Mar 1995 11:35:28 ASHANMUG
  85. * Modified return values to be correct
  86. *
  87. * Rev 1.15 30 Jan 1995 11:55:52 RWOLFF
  88. * Now reports presence of CT internal DAC.
  89. *
  90. * Rev 1.14 25 Jan 1995 14:08:24 RWOLFF
  91. * Fixed "ampersand is reserved character" bug in FillInRegistry() that
  92. * caused AT&T 49[123] and AT&T 498 to drop the ampersand and underline
  93. * the second T.
  94. *
  95. * Rev 1.13 18 Jan 1995 15:40:14 RWOLFF
  96. * Chrontel DAC now supported as separate type rather than being
  97. * lumped in with STG1702.
  98. *
  99. * Rev 1.12 11 Jan 1995 14:03:16 RWOLFF
  100. * Replaced VCS logfile comment that was accidentally deleted when
  101. * checking in the last revision.
  102. *
  103. * Rev 1.11 04 Jan 1995 13:22:06 RWOLFF
  104. * Removed dead code.
  105. *
  106. * Rev 1.10 23 Dec 1994 10:48:10 ASHANMUG
  107. * ALPHA/Chrontel-DAC
  108. *
  109. * Rev 1.9 18 Nov 1994 11:46:44 RWOLFF
  110. * GetSelector() now increases the size of the frequency "window" and checks
  111. * again, rather than giving up and taking the selector/divisor pair that
  112. * produces the highest freqency that does not exceed the target frequency,
  113. * if a match is not found on the first pass. Added support for split rasters.
  114. *
  115. * Rev 1.8 31 Aug 1994 16:28:56 RWOLFF
  116. * Now uses VideoPort[Read|Write]Register[Uchar|Ushort|Ulong]() instead
  117. * of direct memory writes for memory mapped registers under Daytona
  118. * (functions didn't work properly under NT retail), added support
  119. * for 1152x864 and 1600x1200.
  120. *
  121. * Rev 1.7 19 Aug 1994 17:14:50 RWOLFF
  122. * Added support for SC15026 DAC and non-standard pixel clock generators.
  123. *
  124. * Rev 1.6 20 Jul 1994 13:00:08 RWOLFF
  125. * Added routine FillInRegistry() which writes to new registry fields that
  126. * let the display applet know what chipset and DAC the graphics card is
  127. * using, along with the amount of video memory and the type of adapter.
  128. *
  129. * Rev 1.5 12 May 1994 11:20:06 RWOLFF
  130. * Added routine SetFixedModes() which adds predefined refresh rates
  131. * to list of mode tables.
  132. *
  133. * Rev 1.4 27 Apr 1994 13:51:30 RWOLFF
  134. * Now sets Mach 64 1280x1024 pitch to 2048 when disabling LFB.
  135. *
  136. * Rev 1.3 26 Apr 1994 12:35:58 RWOLFF
  137. * Added routine ISAPitchAdjust() which increases screen pitch to 1024
  138. * and removes mode tables for which there is no longer enough memory.
  139. *
  140. * Rev 1.2 14 Mar 1994 16:36:14 RWOLFF
  141. * Functions used by ATIMPResetHw() are not pageable.
  142. *
  143. * Rev 1.1 07 Feb 1994 14:13:44 RWOLFF
  144. * Added alloc_text() pragmas to allow miniport to be swapped out when
  145. * not needed.
  146. *
  147. * Rev 1.0 31 Jan 1994 11:20:16 RWOLFF
  148. * Initial revision.
  149. Rev 1.7 24 Jan 1994 18:10:38 RWOLFF
  150. Added routine TripleClock() which returns the selector/divisor pair that
  151. will produce the lowest clock frequency that is at least three times
  152. that produced by the input selector/divisor pair.
  153. Rev 1.6 14 Jan 1994 15:26:14 RWOLFF
  154. No longer prints message each time memory mapped registers
  155. are read or written.
  156. Rev 1.5 15 Dec 1993 15:31:46 RWOLFF
  157. Added routine used for SC15021 DAC at 24BPP and above.
  158. Rev 1.4 30 Nov 1993 18:29:38 RWOLFF
  159. Speeded up IsBufferBacked(), fixed LioOutpd()
  160. Rev 1.3 05 Nov 1993 13:27:02 RWOLFF
  161. Added routines to check whether a buffer is backed by physical memory,
  162. double pixel clock frequency, and get pixel clock frequency for a given
  163. selector/divisor pair.
  164. Rev 1.2 24 Sep 1993 11:46:06 RWOLFF
  165. Switched to direct memory writes instead of VideoPortWriteRegister<length>()
  166. calls which don't work properly.
  167. Rev 1.1 03 Sep 1993 14:24:40 RWOLFF
  168. Card-independent service routines.
  169. End of PolyTron RCS section *****************/
  170. #ifdef DOC
  171. SERVICES.C - Service routines required by the miniport.
  172. DESCRIPTION
  173. This file contains routines which provide miscelaneous services
  174. used by the miniport. All routines in this module are independent
  175. of the type of ATI accelerator being used.
  176. To secure this independence, routines here may make calls to
  177. the operating system, or call routines from other modules
  178. which read or write registers on the graphics card, but must
  179. not make INP/OUTP calls directly.
  180. OTHER FILES
  181. #endif
  182. #include "dderror.h"
  183. #include <stdio.h>
  184. #include <stdlib.h>
  185. #include <string.h>
  186. #include "miniport.h"
  187. #include "ntddvdeo.h"
  188. #include "video.h"
  189. #include "stdtyp.h"
  190. #include "amach1.h"
  191. #include "atimp.h"
  192. #include "atint.h"
  193. #include "cvtvga.h"
  194. #include "query_cx.h"
  195. #define INCLUDE_SERVICES
  196. #include "services.h"
  197. #include "cvtvdif.h"
  198. #include "cvtddc.h"
  199. /*
  200. * Allow miniport to be swapped out when not needed.
  201. */
  202. #if defined (ALLOC_PRAGMA)
  203. #pragma alloc_text(PAGE_COM, short_delay)
  204. /* delay() can't be made pageable */
  205. #pragma alloc_text(PAGE_COM, IsBufferBacked)
  206. #pragma alloc_text(PAGE_COM, DoubleClock)
  207. #pragma alloc_text(PAGE_COM, ThreeHalvesClock)
  208. #pragma alloc_text(PAGE_COM, TripleClock)
  209. #pragma alloc_text(PAGE_COM, GetFrequency)
  210. #pragma alloc_text(PAGE_COM, GetSelector)
  211. #pragma alloc_text(PAGE_COM, GetShiftedSelector)
  212. #pragma alloc_text(PAGE_COM, ISAPitchAdjust)
  213. #pragma alloc_text(PAGE_COM, SetFixedModes)
  214. #pragma alloc_text(PAGE_COM, FillInRegistry)
  215. #pragma alloc_text(PAGE_COM, MapFramebuffer)
  216. #pragma alloc_text(PAGE_COM, Get_BIOS_Seg)
  217. #pragma alloc_text(PAGE_COM, UpperCase)
  218. #pragma alloc_text(PAGE_COM, GetVgaBuffer)
  219. /* LioInp() can't be made pageable */
  220. /* LioOutp() can't be made pageable */
  221. /* LioInpw() can't be made pageable */
  222. /* LioOutpw() can't be made pageable */
  223. /* LioInpd() can't be made pageable */
  224. /* LioOutpd() can't be made pageable */
  225. #endif
  226. /*
  227. * Static variables used by this module.
  228. */
  229. static BYTE ati_signature[] = "761295520";
  230. /*
  231. * void short_delay(void);
  232. *
  233. * Wait a minimum of 26 microseconds.
  234. */
  235. void short_delay(void)
  236. {
  237. VideoPortStallExecution (26);
  238. return;
  239. }
  240. /*
  241. * void delay(delay_time);
  242. *
  243. * int delay_time; How many milliseconds to wait
  244. *
  245. * Wait for the specified amount of time to pass.
  246. */
  247. void delay(int delay_time)
  248. {
  249. unsigned long Counter;
  250. /*
  251. * This must NOT be done as a single call to
  252. * VideoPortStallExecution() with the parameter equal to the
  253. * total delay desired. According to the documentation for this
  254. * function, we're already pushing the limit in order to minimize
  255. * the effects of function call overhead.
  256. */
  257. for (Counter = 10*delay_time; Counter > 0; Counter--)
  258. VideoPortStallExecution (100);
  259. return;
  260. }
  261. /***************************************************************************
  262. *
  263. * BOOL IsBufferBacked(StartAddress, Size);
  264. *
  265. * PUCHAR StartAddress; Pointer to the beginning of the buffer
  266. * ULONG Size; Size of the buffer in bytes
  267. *
  268. * DESCRIPTION:
  269. * Check to see whether the specified buffer is backed by physical
  270. * memory.
  271. *
  272. * RETURN VALUE:
  273. * TRUE if the buffer is backed by physical memory
  274. * FALSE if the buffer contains a "hole" in physical memory
  275. *
  276. * GLOBALS CHANGED:
  277. * None, but the contents of the buffer are overwritten.
  278. *
  279. * CALLED BY:
  280. * This function may be called by any routine.
  281. *
  282. * AUTHOR:
  283. * Robert Wolff
  284. *
  285. * CHANGE HISTORY:
  286. *
  287. * TEST HISTORY:
  288. *
  289. ***************************************************************************/
  290. BOOL IsBufferBacked(PUCHAR StartAddress, ULONG Size)
  291. {
  292. ULONG Count; /* Loop counter */
  293. ULONG NumDwords; /* Number of doublewords filled by Size bytes */
  294. ULONG NumTailChars; /* Number of bytes in the last (partially-filled) DWORD) */
  295. PULONG TestAddress; /* Address to start doing DWORD testing */
  296. PUCHAR TailAddress; /* Address of the last (partially-filled) DWORD */
  297. /*
  298. * Fill the buffer with our test value. The value 0x5A is used because
  299. * it contains odd bits both set and clear, and even bits both set and
  300. * clear. Since nonexistent memory normally reads as either all bits set
  301. * or all bits clear, it is highly unlikely that we will read back this
  302. * value if there is no physical RAM.
  303. *
  304. * For performance reasons, check as much as possible of the buffer
  305. * in DWORDs, then only use byte-by-byte testing for that portion
  306. * of the buffer which partially fills a DWORD.
  307. */
  308. NumDwords = Size/(sizeof(ULONG)/sizeof(UCHAR));
  309. TestAddress = (PULONG) StartAddress;
  310. NumTailChars = Size%(sizeof(ULONG)/sizeof(UCHAR));
  311. TailAddress = StartAddress + NumDwords * (sizeof(ULONG)/sizeof(UCHAR));
  312. for (Count = 0; Count < NumDwords; Count++)
  313. {
  314. VideoPortWriteRegisterUlong(&(TestAddress[Count]), 0x5A5A5A5A);
  315. }
  316. if (NumTailChars != 0)
  317. {
  318. for (Count = 0; Count < NumTailChars; Count++)
  319. {
  320. VideoPortWriteRegisterUchar(&(TailAddress[Count]), (UCHAR)0x5A);
  321. }
  322. }
  323. /*
  324. * Read back the contents of the buffer. If we find even one byte that
  325. * does not contain our test value, then assume that the buffer is not
  326. * backed by physical memory.
  327. */
  328. for (Count = 0; Count < NumDwords; Count++)
  329. {
  330. if (VideoPortReadRegisterUlong(&(TestAddress[Count])) != 0x5A5A5A5A)
  331. {
  332. return FALSE;
  333. }
  334. }
  335. /*
  336. * If the buffer contains a partially filled DWORD at the end, check
  337. * the bytes in this DWORD.
  338. */
  339. if (NumTailChars != 0)
  340. {
  341. for (Count = 0; Count < NumTailChars; Count++)
  342. {
  343. if (VideoPortReadRegisterUchar(&(TailAddress[Count])) != 0x5A)
  344. {
  345. return FALSE;
  346. }
  347. }
  348. }
  349. /*
  350. * We were able to read back our test value from every byte in the
  351. * buffer, so we know it is backed by physical memory.
  352. */
  353. return TRUE;
  354. } /* IsBufferBacked() */
  355. /***************************************************************************
  356. *
  357. * UCHAR DoubleClock(ClockSelector);
  358. *
  359. * UCHAR ClockSelector; Initial clock selector
  360. *
  361. * DESCRIPTION:
  362. * Find the clock selector and divisor pair which will produce the
  363. * lowest clock frequency that is at least double that produced by
  364. * the input selector/divisor pair (format 000DSSSS).
  365. *
  366. * A divisor of 0 is treated as divide-by-1, while a divisor of 1
  367. * is treated as divide-by-2.
  368. *
  369. * RETURN VALUE:
  370. * Clock selector/devisor pair (format 000DSSSS) if an appropriate pair
  371. * exists, 0x0FF if no such pair exists.
  372. *
  373. * GLOBALS CHANGED:
  374. * none
  375. *
  376. * CALLED BY:
  377. * May be called by any function.
  378. *
  379. * AUTHOR:
  380. * Robert Wolff
  381. *
  382. * CHANGE HISTORY:
  383. *
  384. * TEST HISTORY:
  385. *
  386. ***************************************************************************/
  387. UCHAR DoubleClock(UCHAR ClockSelector)
  388. {
  389. ULONG MinimumFreq; /* Minimum acceptable pixel clock frequency */
  390. ULONG ThisFreq; /* Current frequency being tested */
  391. ULONG BestFreq=0x0FFFFFFFF; /* Closest match to double the original frequency */
  392. UCHAR BestSelector=0x0FF; /* Divisor/selector pair to produce BestFreq */
  393. short Selector; /* Used to loop through the selector */
  394. short Divisor; /* Used to loop through the divisor */
  395. /*
  396. * Easy way out: If the current pixel clock frequency is obtained by
  397. * dividing by 2, switch to divide-by-1.
  398. */
  399. if ((ClockSelector & DIVISOR_MASK) != 0)
  400. return (ClockSelector ^ DIVISOR_MASK);
  401. /*
  402. * Cycle through the selector/divisor pairs to get the closest
  403. * match to double the original frequency. We already know that
  404. * we are using a divide-by-1 clock, since divide-by-2 will have
  405. * been caught by the shortcut above.
  406. */
  407. MinimumFreq = ClockGenerator[ClockSelector & SELECTOR_MASK] * 2;
  408. for (Selector = 0; Selector < 16; Selector++)
  409. {
  410. for (Divisor = 0; Divisor <= 1; Divisor++)
  411. {
  412. ThisFreq = ClockGenerator[Selector] >> Divisor;
  413. /*
  414. * If the frequency being tested is at least equal
  415. * to double the original frequency and is closer
  416. * to the ideal (double the original) than the previous
  417. * "best", make it the new "best".
  418. */
  419. if ((ThisFreq >= MinimumFreq) && (ThisFreq < BestFreq))
  420. {
  421. BestFreq = ThisFreq;
  422. BestSelector = Selector | (Divisor << DIVISOR_SHIFT);
  423. }
  424. }
  425. }
  426. return BestSelector;
  427. } /* DoubleClock() */
  428. /***************************************************************************
  429. *
  430. * UCHAR ThreeHalvesClock(ClockSelector);
  431. *
  432. * UCHAR ClockSelector; Initial clock selector
  433. *
  434. * DESCRIPTION:
  435. * Find the clock selector and divisor pair which will produce the
  436. * lowest clock frequency that is at least 50% greater than that
  437. * produced by the input selector/divisor pair (format 000DSSSS).
  438. *
  439. * A divisor of 0 is treated as divide-by-1, while a divisor of 1
  440. * is treated as divide-by-2.
  441. *
  442. * RETURN VALUE:
  443. * Clock selector/devisor pair (format 000DSSSS) if an appropriate pair
  444. * exists, 0x0FF if no such pair exists.
  445. *
  446. * GLOBALS CHANGED:
  447. * none
  448. *
  449. * CALLED BY:
  450. * May be called by any function.
  451. *
  452. * AUTHOR:
  453. * Robert Wolff
  454. *
  455. * CHANGE HISTORY:
  456. *
  457. * TEST HISTORY:
  458. *
  459. ***************************************************************************/
  460. UCHAR ThreeHalvesClock(UCHAR ClockSelector)
  461. {
  462. ULONG MinimumFreq; /* Minimum acceptable pixel clock frequency */
  463. ULONG ThisFreq; /* Current frequency being tested */
  464. ULONG BestFreq=0x0FFFFFFFF; /* Closest match to 1.5x the original frequency */
  465. UCHAR BestSelector=0x0FF; /* Divisor/selector pair to produce BestFreq */
  466. short Selector; /* Used to loop through the selector */
  467. short Divisor; /* Used to loop through the divisor */
  468. /*
  469. * Cycle through the selector/divisor pairs to get the closest
  470. * match to 1.5 times the original frequency.
  471. */
  472. MinimumFreq = ClockGenerator[ClockSelector & SELECTOR_MASK];
  473. if (ClockSelector & DIVISOR_MASK)
  474. MinimumFreq /= 2;
  475. MinimumFreq *= 3;
  476. MinimumFreq /= 2;
  477. for (Selector = 0; Selector < 16; Selector++)
  478. {
  479. for (Divisor = 0; Divisor <= 1; Divisor++)
  480. {
  481. ThisFreq = ClockGenerator[Selector] >> Divisor;
  482. /*
  483. * If the frequency being tested is at least equal
  484. * to 1.5 times the original frequency and is closer
  485. * to the ideal (1.5 times the original) than the previous
  486. * "best", make it the new "best".
  487. */
  488. if ((ThisFreq >= MinimumFreq) && (ThisFreq < BestFreq))
  489. {
  490. BestFreq = ThisFreq;
  491. BestSelector = Selector | (Divisor << DIVISOR_SHIFT);
  492. }
  493. }
  494. }
  495. return BestSelector;
  496. } /* ThreeHalvesClock() */
  497. /***************************************************************************
  498. *
  499. * UCHAR TripleClock(ClockSelector);
  500. *
  501. * UCHAR ClockSelector; Initial clock selector
  502. *
  503. * DESCRIPTION:
  504. * Find the clock selector and divisor pair which will produce the
  505. * lowest clock frequency that is at least triple that produced by
  506. * the input selector/divisor pair (format 000DSSSS).
  507. *
  508. * A divisor of 0 is treated as divide-by-1, while a divisor of 1
  509. * is treated as divide-by-2.
  510. *
  511. * RETURN VALUE:
  512. * Clock selector/devisor pair (format 000DSSSS) if an appropriate pair
  513. * exists, 0x0FF if no such pair exists.
  514. *
  515. * GLOBALS CHANGED:
  516. * none
  517. *
  518. * CALLED BY:
  519. * May be called by any function.
  520. *
  521. * AUTHOR:
  522. * Robert Wolff
  523. *
  524. * CHANGE HISTORY:
  525. *
  526. * TEST HISTORY:
  527. *
  528. ***************************************************************************/
  529. UCHAR TripleClock(UCHAR ClockSelector)
  530. {
  531. ULONG MinimumFreq; /* Minimum acceptable pixel clock frequency */
  532. ULONG ThisFreq; /* Current frequency being tested */
  533. ULONG BestFreq=0x0FFFFFFFF; /* Closest match to triple the original frequency */
  534. UCHAR BestSelector=0x0FF; /* Divisor/selector pair to produce BestFreq */
  535. short Selector; /* Used to loop through the selector */
  536. short Divisor; /* Used to loop through the divisor */
  537. /*
  538. * Cycle through the selector/divisor pairs to get the closest
  539. * match to triple the original frequency.
  540. */
  541. MinimumFreq = ClockGenerator[ClockSelector & SELECTOR_MASK];
  542. if (ClockSelector & DIVISOR_MASK)
  543. MinimumFreq /= 2;
  544. MinimumFreq *= 3;
  545. for (Selector = 0; Selector < 16; Selector++)
  546. {
  547. for (Divisor = 0; Divisor <= 1; Divisor++)
  548. {
  549. ThisFreq = ClockGenerator[Selector] >> Divisor;
  550. /*
  551. * If the frequency being tested is at least equal
  552. * to triple the original frequency and is closer
  553. * to the ideal (triple the original) than the previous
  554. * "best", make it the new "best".
  555. */
  556. if ((ThisFreq >= MinimumFreq) && (ThisFreq < BestFreq))
  557. {
  558. BestFreq = ThisFreq;
  559. BestSelector = Selector | (Divisor << DIVISOR_SHIFT);
  560. }
  561. }
  562. }
  563. return BestSelector;
  564. } /* TripleClock() */
  565. /***************************************************************************
  566. *
  567. * ULONG GetFrequency(ClockSelector);
  568. *
  569. * UCHAR ClockSelector; Clock selector/divisor pair
  570. *
  571. * DESCRIPTION:
  572. * Find the clock frequency for the specified selector/divisor pair
  573. * (format 000DSSSS).
  574. *
  575. * A divisor of 0 is treated as divide-by-1, while a divisor of 1
  576. * is treated as divide-by-2.
  577. *
  578. * RETURN VALUE:
  579. * Clock frequency in hertz.
  580. *
  581. * GLOBALS CHANGED:
  582. * none
  583. *
  584. * CALLED BY:
  585. * May be called by any function.
  586. *
  587. * AUTHOR:
  588. * Robert Wolff
  589. *
  590. * NOTE:
  591. * This routine is the inverse of GetSelector()
  592. *
  593. * CHANGE HISTORY:
  594. *
  595. * TEST HISTORY:
  596. *
  597. ***************************************************************************/
  598. ULONG GetFrequency(UCHAR ClockSelector)
  599. {
  600. ULONG BaseFrequency;
  601. short Divisor;
  602. Divisor = (ClockSelector & DIVISOR_MASK) >> DIVISOR_SHIFT;
  603. BaseFrequency = ClockGenerator[ClockSelector & SELECTOR_MASK];
  604. return BaseFrequency >> Divisor;
  605. } /* GetFrequency() */
  606. /***************************************************************************
  607. *
  608. * UCHAR GetSelector(Frequency);
  609. *
  610. * ULONG *Frequency; Clock frequency in hertz
  611. *
  612. * DESCRIPTION:
  613. * Find the pixel clock selector and divisor values needed to generate
  614. * the best possible approximation of the input pixel clock frequency.
  615. * The first value found which is within FREQ_TOLERANCE of the input
  616. * value will be used (worst case error would be 0.6% frequency
  617. * difference on 18811-1 clock chip if FREQ_TOLERANCE is 100 kHz).
  618. *
  619. * If no selector/divisor pair produces a frequency which is within
  620. * FREQ_TOLERANCE (very rare - I have only seen it happen in 24BPP
  621. * on a DAC that needs the clock frequency multiplied by 1.5 at
  622. * this pixel depth), increase the tolerance and try again. If we
  623. * still can't find a selector/divisor pair before the tolerance
  624. * gets too large, use the pair which produces the highest frequency
  625. * not exceeding the input value.
  626. *
  627. * RETURN VALUE:
  628. * Clock selector/divisor pair (format 000DSSSS). A divisor of 0
  629. * indicates divide-by-1, while a divisor of 1 indicates divide-by-2.
  630. *
  631. * If all available selector/divisor pairs produce clock frequencies
  632. * greater than (*Frequency + FREQ_TOLERANCE), 0xFF is returned.
  633. *
  634. * GLOBALS CHANGED:
  635. * *Frequency is changed to the actual frequency produced by the
  636. * selector/divisor pair.
  637. *
  638. * CALLED BY:
  639. * May be called by any function.
  640. *
  641. * AUTHOR:
  642. * Robert Wolff
  643. *
  644. * NOTE:
  645. * This routine is the inverse of GetFrequency()
  646. * Since the input frequency may be changed, do not use a
  647. * constant as the parameter.
  648. *
  649. * CHANGE HISTORY:
  650. *
  651. * TEST HISTORY:
  652. *
  653. ***************************************************************************/
  654. UCHAR GetSelector(ULONG *Frequency)
  655. {
  656. long Select; /* Clock select value */
  657. long Divisor; /* Clock divisor */
  658. long TestFreq; /* Clock frequency under test */
  659. long TPIRFreq; /* Highest frequency found that doesn't exceed *Frequency */
  660. long TPIRSelect; /* Selector to produce TIPRFreq */
  661. long TPIRDivisor; /* Divisor to produce TPIRFreq */
  662. long Tolerance; /* Maximum acceptable deviation from desired frequency */
  663. /*
  664. * Set up for no match.
  665. */
  666. TPIRFreq = 0;
  667. TPIRSelect = 0xFF;
  668. /*
  669. * To accomodate DACs which occasionally require a frequency
  670. * which is significantly different from the available frequencies,
  671. * we need a large tolerance. On the other hand, to avoid selecting
  672. * a poor match that happens earlier in the search sequence than
  673. * a better match, we need a small tolerance. These conflicting
  674. * goals can be met if we start with a small tolerance and increase
  675. * it if we don't find a match.
  676. *
  677. * The maximum tolerance before we give up and take the highest
  678. * frequency which does not exceed the target frequency was chosen
  679. * by trial-and-error. On a card with an STG1702/1703 DAC in 24BPP
  680. * (requires a pixel clock which is 1.5x normal, and which can
  681. * miss available frequencies by a wide margin), I increased
  682. * this value until all supported 24BPP modes remained on-screen.
  683. */
  684. for (Tolerance = FREQ_TOLERANCE; Tolerance <= 16*FREQ_TOLERANCE; Tolerance *= 2)
  685. {
  686. /*
  687. * Go through all the possible frequency/divisor pairs
  688. * looking for a match.
  689. */
  690. for(Select = 0; Select < 16; Select++)
  691. {
  692. for(Divisor = 1; Divisor <= 2; Divisor++)
  693. {
  694. TestFreq = ClockGenerator[Select] / Divisor;
  695. /*
  696. * If this pair is close enough, use it.
  697. */
  698. if ( ((TestFreq - (signed long)*Frequency) < Tolerance) &&
  699. ((TestFreq - (signed long)*Frequency) > -Tolerance))
  700. {
  701. *Frequency = (unsigned long) TestFreq;
  702. return ((UCHAR)(Select) | ((UCHAR)(Divisor - 1) << 4));
  703. }
  704. /*
  705. * If this pair produces a frequency higher than TPIRFreq
  706. * but not exceeding *Frequency, use it as the new TPIRFreq.
  707. * The equality test is redundant, since equality would
  708. * have been caught in the test above.
  709. *
  710. * Except on the first pass through the outermost loop
  711. * (tightest "window"), this test should never succeed,
  712. * since TPIRFreq should already match the highest
  713. * frequency that doesn't exceed the target frequency.
  714. */
  715. if ((TestFreq > TPIRFreq) && (TestFreq <= (signed long)*Frequency))
  716. {
  717. TPIRFreq = TestFreq;
  718. TPIRSelect = Select;
  719. TPIRDivisor = Divisor;
  720. }
  721. } /* end for (loop on Divisor) */
  722. } /* end for (loop on Select) */
  723. } /* end for (loop on Tolerance) */
  724. /*
  725. * We didn't find a selector/divisor pair which was within tolerance,
  726. * so settle for second-best: the pair which produced the highest
  727. * frequency not exceeding the input frequency.
  728. */
  729. *Frequency = (unsigned long) TPIRFreq;
  730. return ((UCHAR)(TPIRSelect) | ((UCHAR)(TPIRDivisor - 1) << 4));
  731. } /* GetSelector() */
  732. /***************************************************************************
  733. *
  734. * UCHAR GetShiftedSelector(Frequency);
  735. *
  736. * ULONG Frequency; Clock frequency in hertz
  737. *
  738. * DESCRIPTION:
  739. * Find the pixel clock selector and divisor values needed to generate
  740. * the best possible approximation of the input pixel clock frequency.
  741. * The first value found which is within FREQ_TOLERANCE of the input
  742. * value will be used (worst case error would be 0.6% frequency
  743. * difference on 18811-1 clock chip if FREQ_TOLERANCE is 100 kHz).
  744. *
  745. * If no selector/divisor pair produces a frequency which is within
  746. * FREQ_TOLERANCE, use the pair which produces the highest frequency
  747. * not exceeding the input value.
  748. *
  749. * RETURN VALUE:
  750. * Clock selector/divisor pair (format 0DSSSS00). A divisor of 0
  751. * indicates divide-by-1, while a divisor of 1 indicates divide-by-2.
  752. * This format is the same as is used by the CLOCK_SEL register
  753. * on Mach 8 and Mach 32 cards.
  754. *
  755. * If all available selector/divisor pairs produce clock frequencies
  756. * greater than (Frequency + FREQ_TOLERANCE), 0xFF is returned.
  757. *
  758. * GLOBALS CHANGED:
  759. * None
  760. *
  761. * CALLED BY:
  762. * May be called by any function.
  763. *
  764. * AUTHOR:
  765. * Robert Wolff
  766. *
  767. * NOTE:
  768. * The selector/divisor pair returned may produce a frequency
  769. * different from the input.
  770. *
  771. * CHANGE HISTORY:
  772. *
  773. * TEST HISTORY:
  774. *
  775. ***************************************************************************/
  776. UCHAR GetShiftedSelector(ULONG Frequency)
  777. {
  778. UCHAR RawPair; /* Selector/divisor pair returned by GetSelector() */
  779. ULONG TempFreq; /* Temporary copy of input parameter */
  780. TempFreq = Frequency;
  781. RawPair = GetSelector(&TempFreq);
  782. /*
  783. * If GetSelector() was unable to find a match, pass on this
  784. * information. Otherwise, shift the selector/divisor pair
  785. * into the desired format.
  786. */
  787. if (RawPair == 0xFF)
  788. return RawPair;
  789. else
  790. return (RawPair << 2);
  791. } /* GetShiftedSelector() */
  792. /***************************************************************************
  793. *
  794. * void ISAPitchAdjust(QueryPtr);
  795. *
  796. * struct query_structure *QueryPtr; Query structure for video card
  797. *
  798. * DESCRIPTION:
  799. * Eliminates split rasters by setting the screen pitch to 1024 for
  800. * all mode tables with a horizontal resolution less than 1024, then
  801. * packs the list of mode tables to eliminate any for which there is
  802. * no longer enough video memory due to the increased pitch.
  803. *
  804. * GLOBALS CHANGED:
  805. * QueryPtr->q_number_modes
  806. *
  807. * CALLED BY:
  808. * IsApertureConflict_m() and IsApertureConflict_cx()
  809. *
  810. * AUTHOR:
  811. * Robert Wolff
  812. *
  813. * CHANGE HISTORY:
  814. *
  815. * TEST HISTORY:
  816. *
  817. ***************************************************************************/
  818. void ISAPitchAdjust(struct query_structure *QueryPtr)
  819. {
  820. struct st_mode_table *ReadPtr; /* Mode table pointer to read from */
  821. struct st_mode_table *WritePtr; /* Mode table pointer to write to */
  822. UCHAR AvailModes; /* Number of available modes */
  823. int Counter; /* Loop counter */
  824. ULONG BytesNeeded; /* Bytes of video memory needed for current mode */
  825. ULONG MemAvail; /* Bytes of video memory available */
  826. /*
  827. * Set both mode table pointers to the beginning of the list of
  828. * mode tables. We haven't yet found any video modes, and all
  829. * video modes must fit into the memory space above the VGA boundary.
  830. */
  831. ReadPtr = (struct st_mode_table *)QueryPtr; /* First mode table at end of query structure */
  832. ((struct query_structure *)ReadPtr)++;
  833. WritePtr = ReadPtr;
  834. AvailModes = 0;
  835. MemAvail = (QueryPtr->q_memory_size - QueryPtr->q_VGA_boundary) * QUARTER_MEG;
  836. /*
  837. * Go through the list of mode tables, and adjust each table as needed.
  838. */
  839. VideoDebugPrint((DEBUG_DETAIL, "Original: %d modes\n", QueryPtr->q_number_modes));
  840. for (Counter = 0; Counter < QueryPtr->q_number_modes; Counter++, ReadPtr++)
  841. {
  842. /*
  843. * The pitch only needs to be adjusted if the horizontal resolution
  844. * is less than 1024.
  845. */
  846. #if !defined (SPLIT_RASTERS)
  847. if (ReadPtr->m_x_size < 1024)
  848. ReadPtr->m_screen_pitch = 1024;
  849. /*
  850. * Temporary until split raster support for Mach 64 is added
  851. * (no engine-only driver for Mach 64).
  852. */
  853. if ((phwDeviceExtension->ModelNumber == MACH64_ULTRA) &&
  854. (ReadPtr->m_x_size > 1024))
  855. ReadPtr->m_screen_pitch = 2048;
  856. #endif
  857. /*
  858. * Get the amount of video memory needed for the current mode table
  859. * now that the pitch has been increased. If there is no longer
  860. * enough memory for this mode, skip it.
  861. */
  862. BytesNeeded = (ReadPtr->m_screen_pitch * ReadPtr->m_y_size * ReadPtr->m_pixel_depth)/8;
  863. if (BytesNeeded >= MemAvail)
  864. {
  865. VideoDebugPrint((DEBUG_DETAIL, "Rejected: %dx%d, %dBPP\n", ReadPtr->m_x_size, ReadPtr->m_y_size, ReadPtr->m_pixel_depth));
  866. continue;
  867. }
  868. /*
  869. * Our new source stream display driver needs a linear aperture
  870. * in order to handle 24BPP. Since the display driver doesn't
  871. * have access to the aperture information when it is deciding
  872. * which modes to pass on to the display applet, it can't make
  873. * the decision to reject 24BPP modes for cards with only a
  874. * VGA aperture. This decision must therefore be made in the
  875. * miniport, so in a paged aperture configuration there are no
  876. * 24BPP modes for the display driver to accept or reject.
  877. */
  878. if (ReadPtr->m_pixel_depth == 24)
  879. {
  880. VideoDebugPrint((1, "Rejected %dx%d, %dBPP - need LFB for 24BPP\n", ReadPtr->m_x_size, ReadPtr->m_y_size, ReadPtr->m_pixel_depth));
  881. continue;
  882. }
  883. /*
  884. * There is enough memory for this mode even with the pitch increased.
  885. * If we have not yet skipped a mode (read and write pointers are
  886. * the same), the mode table is already where we need it. Otherwise,
  887. * copy it to the next available slot in the list of mode tables.
  888. * In either case, move to the next slot in the list of mode tables
  889. * and increment the number of modes that can still be used.
  890. */
  891. if (ReadPtr != WritePtr)
  892. {
  893. VideoPortMoveMemory(WritePtr, ReadPtr, sizeof(struct st_mode_table));
  894. VideoDebugPrint((DEBUG_DETAIL, "Moved: %dx%d, %dBPP\n", ReadPtr->m_x_size, ReadPtr->m_y_size, ReadPtr->m_pixel_depth));
  895. }
  896. else
  897. {
  898. VideoDebugPrint((DEBUG_DETAIL, "Untouched: %dx%d, %dBPP\n", ReadPtr->m_x_size, ReadPtr->m_y_size, ReadPtr->m_pixel_depth));
  899. }
  900. AvailModes++;
  901. WritePtr++;
  902. }
  903. /*
  904. * Record the new number of available modes
  905. */
  906. QueryPtr->q_number_modes = AvailModes;
  907. VideoDebugPrint((DEBUG_DETAIL, "New: %d modes\n", QueryPtr->q_number_modes));
  908. return;
  909. } /* ISAPitchAdjust() */
  910. /***************************************************************************
  911. *
  912. * WORD SetFixedModes(StartIndex, EndIndex, Multiplier, PixelDepth,
  913. * Pitch, FreeTables, MaxDotClock, ppmode);
  914. *
  915. * WORD StartIndex; First entry from "book" tables to use
  916. * WORD EndIndex; Last entry from "book" tables to use
  917. * WORD Multiplier; What needs to be done to the pixel clock
  918. * WORD PixelDepth; Number of bits per pixel
  919. * WORD Pitch; Screen pitch to use
  920. * WORD FreeTables; Number of free mode tables that can be added
  921. * ULONG MaxDotClock; Maximum pixel clock frequency, in hertz
  922. * struct st_mode_table **ppmode; Pointer to list of mode tables
  923. *
  924. * DESCRIPTION:
  925. * Generates a list of "canned" mode tables merged with tables found
  926. * in VDIF file (either ASCII or binary file), so the tables are in
  927. * increasing order of frame rate, with the "canned" entry discarded
  928. * if two with matching frame rates are found. This allows the user
  929. * to select either a resolution which was not configured using
  930. * INSTALL, or a refresh rate other than the one which was configured,
  931. * allowing the use of uninstalled cards, and dropping
  932. * the refresh rate for high pixel depths.
  933. *
  934. * RETURN VALUE:
  935. * Number of mode tables added to the list
  936. *
  937. * GLOBALS CHANGED:
  938. * pCallbackArgs
  939. *
  940. * CALLED BY:
  941. * QueryMach32(), QueryMach64(), OEMGetParms(), ReadAST()
  942. *
  943. * AUTHOR:
  944. * Robert Wolff
  945. *
  946. * CHANGE HISTORY:
  947. * 95 11 20 Robert Wolff
  948. * Now obtains tables from EDID structure rather than VDIF file if
  949. * both monitor and card support DDC
  950. *
  951. * 95 07 12 Miroslav Grubac
  952. * Now produces a merged list of fixed mode tables and tables found in
  953. * VDIF file
  954. *
  955. * TEST HISTORY:
  956. *
  957. ***************************************************************************/
  958. WORD SetFixedModes(WORD StartIndex,
  959. WORD EndIndex,
  960. WORD Multiplier,
  961. WORD PixelDepth,
  962. WORD Pitch,
  963. short FreeTables,
  964. ULONG MaxDotClock,
  965. struct st_mode_table **ppmode)
  966. {
  967. WORD HighBound; /* The highest frame rate */
  968. struct stVDIFCallbackData stCallbArgs;
  969. pCallbackArgs = (void *) (& stCallbArgs);
  970. /*
  971. * Assign values to members of stCallbArgs structure which is used
  972. * to pass input variables to VDIFCallback() and also to return output
  973. * values back to SetFixedModes(),i.e. this is the way these two routines
  974. * exchange data, because callback routines cannot be passed arguments
  975. * as ordinary functions. Global pointer variable pCallbackArgs is
  976. * used to pass pointer to stCallbArgs from SetFixedModes to VDIFCallback().
  977. * In this manner only one global variable is required to transfer
  978. * any number of parameters to the callback routine.
  979. *
  980. */
  981. stCallbArgs.FreeTables = FreeTables;
  982. stCallbArgs.NumModes = 0;
  983. stCallbArgs.EndIndex = EndIndex;
  984. stCallbArgs.LowBound = 1;
  985. stCallbArgs.Multiplier = Multiplier;
  986. stCallbArgs.HorRes = (BookValues[StartIndex].HDisp + 1) * 8;
  987. stCallbArgs.VerRes = (((BookValues[StartIndex].VDisp >> 1) &
  988. 0x0FFFC) | (BookValues[StartIndex].VDisp & 0x03)) + 1;
  989. stCallbArgs.PixelDepth = PixelDepth;
  990. stCallbArgs.Pitch = Pitch;
  991. stCallbArgs.MaxDotClock = MaxDotClock;
  992. stCallbArgs.ppFreeTables = ppmode;
  993. /*
  994. * Determine which method we should use to find the
  995. * mode tables corresponding to the monitor. Only the
  996. * Mach 64 supports DDC, so all non-Mach 64 cards
  997. * go directly to VDIF files read from disk.
  998. */
  999. if (phwDeviceExtension->MergeSource == MERGE_UNKNOWN)
  1000. {
  1001. if (phwDeviceExtension->ModelNumber == MACH64_ULTRA)
  1002. {
  1003. phwDeviceExtension->MergeSource = IsDDCSupported();
  1004. }
  1005. else
  1006. {
  1007. phwDeviceExtension->MergeSource = MERGE_VDIF_FILE;
  1008. VideoDebugPrint((DEBUG_DETAIL, "Not Mach 64, so DDC is not supported\n"));
  1009. }
  1010. }
  1011. for (stCallbArgs.Index = StartIndex;
  1012. stCallbArgs.Index <= EndIndex && stCallbArgs.FreeTables > 0;
  1013. stCallbArgs.Index++)
  1014. {
  1015. HighBound = BookValues[stCallbArgs.Index].Refresh;
  1016. /*
  1017. * If we can use DDC to get mode tables, merge the tables
  1018. * obtained via DDC with our "canned" tables.
  1019. *
  1020. * If MergeEDIDTables() can't get the mode tables via
  1021. * DDC, it will not fill in any mode tables. For this
  1022. * reason, we use two separate "if" statements rather
  1023. * than an "if/else if" pair.
  1024. */
  1025. if (phwDeviceExtension->MergeSource == MERGE_EDID_DDC)
  1026. {
  1027. if (MergeEDIDTables() != NO_ERROR)
  1028. phwDeviceExtension->MergeSource = MERGE_VDIF_FILE;
  1029. }
  1030. if ((stCallbArgs.LowBound <= HighBound) &&
  1031. (BookValues[stCallbArgs.Index].ClockFreq <= MaxDotClock) &&
  1032. (stCallbArgs.FreeTables > 0) )
  1033. {
  1034. /*
  1035. * Unsuccesful MiniPort Function call to process VDIF file.
  1036. * Fill the next table with this value of Index from
  1037. * BookValues[]
  1038. */
  1039. BookVgaTable(stCallbArgs.Index, *stCallbArgs.ppFreeTables);
  1040. SetOtherModeParameters(PixelDepth, Pitch, Multiplier,
  1041. *stCallbArgs.ppFreeTables);
  1042. ++ *stCallbArgs.ppFreeTables;
  1043. ++stCallbArgs.NumModes;
  1044. --stCallbArgs.FreeTables;
  1045. stCallbArgs.LowBound = BookValues[stCallbArgs.Index].Refresh + 1;
  1046. }
  1047. } /* for(Index in range and space left) */
  1048. return stCallbArgs.NumModes;
  1049. } /* SetFixedModes() */
  1050. /***************************************************************************
  1051. *
  1052. * void FillInRegistry(QueryPtr);
  1053. *
  1054. * struct query_structure *QueryPtr; Pointer to query structure
  1055. *
  1056. * DESCRIPTION:
  1057. * Fill in the Chip Type, DAC Type, Memory Size, and Adapter String
  1058. * fields in the registry.
  1059. *
  1060. * GLOBALS CHANGED:
  1061. * None
  1062. *
  1063. * CALLED BY:
  1064. * ATIMPInitialize()
  1065. *
  1066. * AUTHOR:
  1067. * Robert Wolff
  1068. *
  1069. * CHANGE HISTORY:
  1070. * Robert Wolff 96 04 15
  1071. * Now identifies specific Mach 64 ASIC types rather than reporting
  1072. * a single value for all types of Mach 64.
  1073. *
  1074. * TEST HISTORY:
  1075. *
  1076. ***************************************************************************/
  1077. void FillInRegistry(struct query_structure *QueryPtr)
  1078. {
  1079. PWSTR ChipString; /* Identification string for the ASIC in use */
  1080. PWSTR DACString; /* Identification string for the DAC in use */
  1081. PWSTR AdapterString; /* Identifies this as an ATI accelerator */
  1082. ULONG MemorySize; /* Number of bytes of accelerator memory */
  1083. ULONG ChipLen; /* Length of ChipString */
  1084. ULONG DACLen; /* Length of DACString */
  1085. ULONG AdapterLen; /* Length of AdapterString */
  1086. /*
  1087. * Report that this is an ATI graphics accelerator.
  1088. */
  1089. AdapterString = L"ATI Graphics Accelerator";
  1090. AdapterLen = sizeof(L"ATI Graphics Accelerator");
  1091. /*
  1092. * Report which of our accelerators is in use.
  1093. */
  1094. switch (QueryPtr->q_asic_rev)
  1095. {
  1096. case CI_38800_1:
  1097. ChipString = L"Mach 8";
  1098. ChipLen = sizeof(L"Mach 8");
  1099. break;
  1100. case CI_68800_3:
  1101. ChipString = L"Mach 32 rev. 3";
  1102. ChipLen = sizeof(L"Mach 32 rev. 3");
  1103. break;
  1104. case CI_68800_6:
  1105. ChipString = L"Mach 32 rev. 6";
  1106. ChipLen = sizeof(L"Mach 32 rev. 6");
  1107. break;
  1108. case CI_68800_UNKNOWN:
  1109. ChipString = L"Mach 32 unknown revision";
  1110. ChipLen = sizeof(L"Mach 32 unknown revision");
  1111. break;
  1112. case CI_68800_AX:
  1113. ChipString = L"Mach 32 AX";
  1114. ChipLen = sizeof(L"Mach 32 AX");
  1115. break;
  1116. case CI_88800_GX:
  1117. ChipString = IdentifyMach64Asic(QueryPtr, &ChipLen);
  1118. break;
  1119. default:
  1120. ChipString = L"Unknown ATI accelerator";
  1121. ChipLen = sizeof(L"Unknown ATI accelerator");
  1122. break;
  1123. }
  1124. /*
  1125. * Report which DAC we are using.
  1126. */
  1127. switch(QueryPtr->q_DAC_type)
  1128. {
  1129. case DAC_ATI_68830:
  1130. DACString = L"ATI 68830";
  1131. DACLen = sizeof(L"ATI 68830");
  1132. break;
  1133. case DAC_SIERRA:
  1134. DACString = L"Sierra SC1148x";
  1135. DACLen = sizeof(L"Sierra SC1148x");
  1136. break;
  1137. case DAC_TI34075:
  1138. DACString = L"TI 34075/ATI 68875";
  1139. DACLen = sizeof(L"TI 34075/ATI 68875");
  1140. break;
  1141. case DAC_BT47x:
  1142. DACString = L"Brooktree BT47x";
  1143. DACLen = sizeof(L"Brooktree BT47x");
  1144. break;
  1145. case DAC_BT48x:
  1146. DACString = L"Brooktree BT48x";
  1147. DACLen = sizeof(L"Brooktree BT48x");
  1148. break;
  1149. case DAC_ATI_68860:
  1150. DACString = L"ATI 68860";
  1151. DACLen = sizeof(L"ATI 68860");
  1152. break;
  1153. case DAC_STG1700:
  1154. DACString = L"S.G. Thompson STG170x";
  1155. DACLen = sizeof(L"S.G. Thompson STG170x");
  1156. break;
  1157. case DAC_SC15021:
  1158. DACString = L"Sierra SC15021";
  1159. DACLen = sizeof(L"Sierra SC15021");
  1160. break;
  1161. case DAC_ATT491:
  1162. DACString = L"AT&&T 49[123]";
  1163. DACLen = sizeof(L"AT&&T 49[123]");
  1164. break;
  1165. case DAC_ATT498:
  1166. DACString = L"AT&&T 498";
  1167. DACLen = sizeof(L"AT&&T 498");
  1168. break;
  1169. case DAC_SC15026:
  1170. DACString = L"Sierra SC15026";
  1171. DACLen = sizeof(L"Sierra SC15026");
  1172. break;
  1173. case DAC_TVP3026:
  1174. DACString = L"Texas Instruments TVP3026";
  1175. DACLen = sizeof(L"Texas Instruments TVP3026");
  1176. break;
  1177. case DAC_IBM514:
  1178. DACString = L"IBM RGB514";
  1179. DACLen = sizeof(L"IBM RGB514");
  1180. break;
  1181. case DAC_STG1702:
  1182. DACString = L"S.G. Thompson STG1702/1703";
  1183. DACLen = sizeof(L"S.G. Thompson STG1702/1703");
  1184. break;
  1185. case DAC_STG1703:
  1186. DACString = L"S.G. Thompson STG1703";
  1187. DACLen = sizeof(L"S.G. Thompson STG1703");
  1188. break;
  1189. case DAC_CH8398:
  1190. DACString = L"Chrontel CH8398";
  1191. DACLen = sizeof(L"Chrontel CH8398");
  1192. break;
  1193. case DAC_ATT408:
  1194. DACString = L"AT&&T 408";
  1195. DACLen = sizeof(L"AT&&T 408");
  1196. break;
  1197. case DAC_INTERNAL_CT:
  1198. case DAC_INTERNAL_GT:
  1199. case DAC_INTERNAL_VT:
  1200. DACString = L"DAC built into ASIC";
  1201. DACLen = sizeof(L"DAC built into ASIC");
  1202. break;
  1203. default:
  1204. DACString = L"Unknown DAC type";
  1205. DACLen = sizeof(L"Unknown DAC type");
  1206. break;
  1207. }
  1208. /*
  1209. * Report the amount of accelerator memory. On Mach 8
  1210. * combo cards, the q_memory_size field includes VGA-only
  1211. * memory which the accelerator can't access. On all
  1212. * other cards, it reports accelerator-accessible memory.
  1213. */
  1214. if (phwDeviceExtension->ModelNumber == GRAPHICS_ULTRA)
  1215. {
  1216. switch (QueryPtr->q_memory_size)
  1217. {
  1218. case VRAM_768k: /* 512k accelerator/256k VGA */
  1219. case VRAM_1mb: /* 512k accelerator/512k VGA */
  1220. MemorySize = HALF_MEG;
  1221. break;
  1222. case VRAM_1_25mb: /* 1M accelerator/256k VGA */
  1223. case VRAM_1_50mb: /* 1M accelerator/512k VGA */
  1224. MemorySize = ONE_MEG;
  1225. break;
  1226. default: /* Should never happen */
  1227. VideoDebugPrint((DEBUG_ERROR, "Non-production Mach 8 combo\n"));
  1228. MemorySize = ONE_MEG;
  1229. break;
  1230. }
  1231. }
  1232. else
  1233. {
  1234. MemorySize = QueryPtr->q_memory_size * QUARTER_MEG;
  1235. }
  1236. /*
  1237. * Write the information to the registry.
  1238. */
  1239. VideoPortSetRegistryParameters(phwDeviceExtension,
  1240. L"HardwareInformation.ChipType",
  1241. ChipString,
  1242. ChipLen);
  1243. VideoPortSetRegistryParameters(phwDeviceExtension,
  1244. L"HardwareInformation.DacType",
  1245. DACString,
  1246. DACLen);
  1247. VideoPortSetRegistryParameters(phwDeviceExtension,
  1248. L"HardwareInformation.MemorySize",
  1249. &MemorySize,
  1250. sizeof(ULONG));
  1251. VideoPortSetRegistryParameters(phwDeviceExtension,
  1252. L"HardwareInformation.AdapterString",
  1253. AdapterString,
  1254. AdapterLen);
  1255. return;
  1256. } /* FillInRegistry() */
  1257. /*
  1258. * PVOID MapFramebuffer(StartAddress, Size);
  1259. *
  1260. * ULONG StartAddress; Physical address of start of framebuffer
  1261. * long Size; Size of framebuffer in bytes
  1262. *
  1263. * Map the framebuffer into Windows NT's address space.
  1264. *
  1265. * Returns:
  1266. * Pointer to start of framebuffer if successful
  1267. * Zero if unable to map the framebuffer
  1268. */
  1269. PVOID MapFramebuffer(ULONG StartAddress, long Size)
  1270. {
  1271. VIDEO_ACCESS_RANGE FramebufferData;
  1272. FramebufferData.RangeLength = Size;
  1273. FramebufferData.RangeStart.LowPart = StartAddress;
  1274. FramebufferData.RangeStart.HighPart = 0;
  1275. FramebufferData.RangeInIoSpace = 0;
  1276. FramebufferData.RangeVisible = 0;
  1277. return VideoPortGetDeviceBase(phwDeviceExtension,
  1278. FramebufferData.RangeStart,
  1279. FramebufferData.RangeLength,
  1280. FramebufferData.RangeInIoSpace);
  1281. } /* MapFrameBuffer() */
  1282. /**************************************************************************
  1283. *
  1284. * unsigned short *Get_BIOS_Seg(void);
  1285. *
  1286. * DESCRIPTION:
  1287. * Verify BIOS presence and return BIOS segment
  1288. * Check for ATI Video BIOS, by checking for product signature
  1289. * near beginning of BIOS segment. It should be ASCII string "761295520"
  1290. *
  1291. * RETURN VALUE:
  1292. * Segment of BIOS code. If multiple ATI Video BIOS segments are
  1293. * found, return the highest one (probable cause: VGAWonder and
  1294. * 8514/ULTRA, this will return the BIOS segment for the 8514/ULTRA).
  1295. *
  1296. * If no ATI video BIOS segment is found, returns FALSE.
  1297. *
  1298. * GLOBALS CHANGED:
  1299. * none
  1300. *
  1301. * CALLED BY:
  1302. * ATIMPFindAdapter(), DetectMach64()
  1303. *
  1304. **************************************************************************/
  1305. unsigned short *Get_BIOS_Seg(void)
  1306. {
  1307. /*
  1308. * Offset of the start of the video BIOS segment
  1309. * from the start of the BIOS area
  1310. */
  1311. long SegmentOffset;
  1312. PUCHAR SegmentStart; /* Start address of the BIOS segment being tested */
  1313. ULONG SigOffset; /* Offset of signature string from start of BIOS segment */
  1314. ULONG SigLoop; /* Counter to check for match */
  1315. BOOL SigFound; /* Whether or not the signature string was found */
  1316. /*
  1317. * Try to allocate the block of address space where the BIOS
  1318. * is found. If we can't, report that we didn't find the BIOS.
  1319. */
  1320. if ((phwDeviceExtension->RomBaseRange =
  1321. VideoPortGetDeviceBase(phwDeviceExtension,
  1322. RawRomBaseRange.RangeStart,
  1323. RawRomBaseRange.RangeLength,
  1324. RawRomBaseRange.RangeInIoSpace)) == NULL)
  1325. {
  1326. VideoDebugPrint((DEBUG_NORMAL, "Get_BIOS_Seg() can't allocate BIOS address range, assuming no BIOS\n"));
  1327. return FALSE;
  1328. }
  1329. /*
  1330. * For each candidate for the start of the video BIOS segment,
  1331. * check to see if it is the start of a BIOS segment. Start at
  1332. * the top and work down because if the system contains both a
  1333. * VGAWonder and an 8514/ULTRA, the 8514/ULTRA BIOS will be at
  1334. * a higher address than the VGAWonder BIOS, and we want to get
  1335. * information from the 8514/ULTRA BIOS.
  1336. */
  1337. for (SegmentOffset = MAX_BIOS_START; SegmentOffset >= 0; SegmentOffset -= ROM_GRANULARITY)
  1338. {
  1339. SegmentStart = (PUCHAR)phwDeviceExtension->RomBaseRange + SegmentOffset;
  1340. /*
  1341. * If this candidate does not begin with the "start of BIOS segment"
  1342. * identifier, then it is not the start of the video BIOS segment.
  1343. */
  1344. if (VideoPortReadRegisterUshort((PUSHORT)SegmentStart) == VIDEO_ROM_ID)
  1345. {
  1346. /*
  1347. * We've found the start of a BIOS segment. Search through
  1348. * the range of offsets from the start of the segment where
  1349. * the ATI signature string can start. If we find it,
  1350. * then we know that this is the video BIOS segment.
  1351. */
  1352. for (SigOffset = SIG_AREA_START; SigOffset <= SIG_AREA_END; SigOffset++)
  1353. {
  1354. /*
  1355. * If the first character of the signature string isn't at the
  1356. * current offset into the segment, then we haven't found the
  1357. * signature string yet.
  1358. */
  1359. if (VideoPortReadRegisterUchar(SegmentStart + SigOffset) != ati_signature[0])
  1360. continue;
  1361. /*
  1362. * We have found the first character of the signature string. Scan
  1363. * through the following characters to see if they contain the
  1364. * remainder of the signature string. If, before we reach the
  1365. * null terminator on the test string, we find a character that
  1366. * does not match the test string, then what we thought was the
  1367. * signature string is actually unrelated data that happens to
  1368. * match the first few characters.
  1369. */
  1370. SigFound = TRUE;
  1371. for (SigLoop = 1; ati_signature[SigLoop] != 0; SigLoop++)
  1372. {
  1373. if (VideoPortReadRegisterUchar(SegmentStart + SigOffset + SigLoop) != ati_signature[SigLoop])
  1374. {
  1375. SigFound = FALSE;
  1376. continue;
  1377. }
  1378. } /* end for (checking for entire signature string) */
  1379. /*
  1380. * We have found the entire signature string.
  1381. */
  1382. if (SigFound == TRUE)
  1383. {
  1384. VideoDebugPrint((DEBUG_NORMAL, "Get_BIOS_Seg() found the BIOS signature string\n"));
  1385. return (unsigned short *)SegmentStart;
  1386. }
  1387. } /* end for (checking BIOS segment for signature string) */
  1388. } /* end if (a BIOS segment starts here) */
  1389. } /* end for (check each possible BIOS start address) */
  1390. /*
  1391. * We have checked all the candidates for the start of the BIOS segment,
  1392. * and none contained the signature string.
  1393. */
  1394. VideoDebugPrint((DEBUG_NORMAL, "Get_BIOS_Seg() didn't find the BIOS signature string\n"));
  1395. return FALSE;
  1396. } /* Get_BIOS_Seg() */
  1397. /***************************************************************************
  1398. *
  1399. * void UpperCase(TxtString);
  1400. *
  1401. * PUCHAR TxtString; Text string to process
  1402. *
  1403. * DESCRIPTION:
  1404. * Convert a null-terminated string to uppercase. This function wouldn't
  1405. * be necessary if strupr() were available in all versions of the
  1406. * NT build environment.
  1407. *
  1408. * GLOBALS CHANGED:
  1409. * None, but the contents of the buffer are overwritten.
  1410. *
  1411. * CALLED BY:
  1412. * This function may be called by any routine.
  1413. *
  1414. * AUTHOR:
  1415. * Robert Wolff
  1416. *
  1417. * CHANGE HISTORY:
  1418. *
  1419. * TEST HISTORY:
  1420. *
  1421. ***************************************************************************/
  1422. void UpperCase(PUCHAR TxtString)
  1423. {
  1424. PUCHAR CurrentChar; /* Current character being processed */
  1425. CurrentChar = TxtString;
  1426. /*
  1427. * Continue until we encounter the null terminator.
  1428. */
  1429. while (*CurrentChar != '\0')
  1430. {
  1431. /*
  1432. * If the current character is a lower case letter,
  1433. * convert it to upper case. Don't change any characters
  1434. * that aren't lower case letters.
  1435. */
  1436. if ((*CurrentChar >= 'a') && (*CurrentChar <= 'z'))
  1437. *CurrentChar -= ('a' - 'A');
  1438. CurrentChar++;
  1439. }
  1440. return;
  1441. } /* UpperCase() */
  1442. /***************************************************************************
  1443. *
  1444. * PUCHAR GetVgaBuffer(Size, Offset, Segment, SaveBuffer);
  1445. *
  1446. * ULONG Size; Size of the buffer in bytes
  1447. * ULONG Offset; How far into the VGA segment we want
  1448. * the buffer to start
  1449. * PULONG Segment; Pointer to storage location for the segment
  1450. * where the buffer is located
  1451. * PUCHAR SaveBuffer; Pointer to temporary storage location where the
  1452. * original contents of the buffer are to be saved,
  1453. * NULL if there is no need to save the original
  1454. * contents of the buffer.
  1455. *
  1456. * DESCRIPTION:
  1457. * Map a buffer of a specified size at a specified offset (must be
  1458. * a multiple of 16 bytes) into VGA memory. If desired, the original
  1459. * contents of the buffer are saved. This function tries the 3 VGA
  1460. * apertures in the following order - colour text screen, mono text
  1461. * screen, graphics screen - until it finds one where we can place
  1462. * the buffer. If we can't map the desired buffer, we return failure
  1463. * rather than forcing a mode set to create the buffer. On return,
  1464. * *Segment:0 is the physical address of the start of the buffer
  1465. * (this is why Offset must be a multiple of 16 bytes).
  1466. *
  1467. * This function is used to find a buffer below 1 megabyte physical,
  1468. * since some of the Mach 64 BIOS routines require a buffer in this
  1469. * region. If future versions of Windows NT add a function which can
  1470. * give us a buffer below 1 megabyte physical, such a routine would
  1471. * be preferable to using VGA memory as the buffer.
  1472. *
  1473. * RETURN VALUE:
  1474. * Pointer to start of buffer if successful
  1475. * Zero if unable to obtain a buffer
  1476. *
  1477. * NOTE
  1478. * If zero is returned, the values returned in Segment and SaveBuffer
  1479. * are undefined.
  1480. *
  1481. * On VGA text screens (colour and mono), we try to use the offscreen
  1482. * portion of video memory.
  1483. *
  1484. * GLOBALS CHANGED:
  1485. * None
  1486. *
  1487. * CALLED BY:
  1488. * This function may be called by any routine, so long as the entry
  1489. * point resulting in the call is ATIMPInitialize() or ATIMPStartIO().
  1490. *
  1491. * AUTHOR:
  1492. * Robert Wolff
  1493. *
  1494. * CHANGE HISTORY:
  1495. *
  1496. * TEST HISTORY:
  1497. *
  1498. ***************************************************************************/
  1499. PUCHAR GetVgaBuffer(ULONG Size, ULONG Offset, PULONG Segment, PUCHAR SaveBuffer)
  1500. {
  1501. PUCHAR MappedBuffer; /* Pointer to buffer under test */
  1502. ULONG BufferSeg; /* Segment to use for buffer */
  1503. ULONG Scratch; /* Temporary variable */
  1504. /*
  1505. * Check for a valid offset.
  1506. */
  1507. if (Offset & 0x0000000F)
  1508. {
  1509. VideoDebugPrint((DEBUG_ERROR, "GetVgaBuffer() - Offset must be a multiple of 16\n"));
  1510. return 0;
  1511. }
  1512. BufferSeg = 0x0BA00 + Offset; /* Colour text */
  1513. MappedBuffer = MapFramebuffer((BufferSeg << 4), Size);
  1514. if (MappedBuffer != 0)
  1515. {
  1516. if (SaveBuffer != NULL)
  1517. {
  1518. for (Scratch = 0; Scratch < Size; Scratch++)
  1519. SaveBuffer[Scratch] = VideoPortReadRegisterUchar(&(MappedBuffer[Scratch]));
  1520. }
  1521. if (IsBufferBacked(MappedBuffer, Size) == FALSE)
  1522. {
  1523. VideoDebugPrint((DEBUG_NORMAL, "Colour text screen not backed by physical memory\n"));
  1524. VideoPortFreeDeviceBase(phwDeviceExtension, MappedBuffer);
  1525. MappedBuffer = 0;
  1526. }
  1527. }
  1528. else
  1529. {
  1530. VideoDebugPrint((DEBUG_NORMAL, "Can't map colour text screen\n"));
  1531. }
  1532. /*
  1533. * If we were unable to allocate a large enough buffer in the
  1534. * colour text screen, try the monochrome text screen.
  1535. */
  1536. if (MappedBuffer == 0)
  1537. {
  1538. VideoDebugPrint((DEBUG_NORMAL, "Can't use colour text screen, trying monochrome text screen\n"));
  1539. BufferSeg = 0x0B200 + Offset;
  1540. if ((MappedBuffer = MapFramebuffer((BufferSeg << 4), Size)) != 0)
  1541. {
  1542. if (SaveBuffer != NULL)
  1543. {
  1544. for (Scratch = 0; Scratch < Size; Scratch++)
  1545. SaveBuffer[Scratch] = VideoPortReadRegisterUchar(&(MappedBuffer[Scratch]));
  1546. }
  1547. if (IsBufferBacked(MappedBuffer, Size) == FALSE)
  1548. {
  1549. VideoDebugPrint((DEBUG_NORMAL, "Monochrome text screen not backed by physical memory\n"));
  1550. VideoPortFreeDeviceBase(phwDeviceExtension, MappedBuffer);
  1551. MappedBuffer = 0;
  1552. }
  1553. }
  1554. else
  1555. {
  1556. VideoDebugPrint((DEBUG_NORMAL, "Can't map monochrome text screen\n"));
  1557. }
  1558. }
  1559. /*
  1560. * If we were unable to allocate a large enough buffer in either of
  1561. * the text screens, try the VGA graphics screen.
  1562. */
  1563. if (MappedBuffer == 0)
  1564. {
  1565. VideoDebugPrint((DEBUG_NORMAL, "Can't use monochrome text screen, trying graphics screen\n"));
  1566. BufferSeg = 0x0A000 + Offset;
  1567. if ((MappedBuffer = MapFramebuffer((BufferSeg << 4), Size)) == 0)
  1568. {
  1569. VideoDebugPrint((DEBUG_ERROR, "Can't map graphics screen - aborting DDC query\n"));
  1570. return 0;
  1571. }
  1572. if (SaveBuffer != NULL)
  1573. {
  1574. for (Scratch = 0; Scratch < Size; Scratch++)
  1575. SaveBuffer[Scratch] = VideoPortReadRegisterUchar(&(MappedBuffer[Scratch]));
  1576. }
  1577. if (IsBufferBacked(MappedBuffer, Size) == FALSE)
  1578. {
  1579. VideoDebugPrint((DEBUG_ERROR, "Graphics screen not backed by memory - aborting\n"));
  1580. VideoPortFreeDeviceBase(phwDeviceExtension, MappedBuffer);
  1581. return 0;
  1582. }
  1583. }
  1584. /*
  1585. * Report the segment where we found the buffer.
  1586. */
  1587. *Segment = BufferSeg;
  1588. return MappedBuffer;
  1589. } /* GetVgaBuffer() */
  1590. /*
  1591. * Low level Input/Output routines. These are not needed on an MS-DOS
  1592. * platform because the standard inp<size>() and outp<size>() routines
  1593. * are available.
  1594. */
  1595. /*
  1596. * UCHAR LioInp(Port, Offset);
  1597. *
  1598. * int Port; Register to read from
  1599. * int Offset; Offset into desired register
  1600. *
  1601. * Read an unsigned character from a given register. Works with both normal
  1602. * I/O ports and memory-mapped registers. Offset is zero for 8 bit registers
  1603. * and the least significant byte of 16 and 32 bit registers, 1 for the
  1604. * most significant byte of 16 bit registers and the second least significant
  1605. * byte of 32 bit registers, up to 3 for the most significant byte of 32 bit
  1606. * registers.
  1607. *
  1608. * Returns:
  1609. * Value held in the register.
  1610. */
  1611. UCHAR LioInp(int Port, int Offset)
  1612. {
  1613. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1614. {
  1615. /*
  1616. * In early versions of Windows NT, VideoPort[Read|Write]Register<size>()
  1617. * didn't work properly, but these routines are preferable to
  1618. * direct pointer read/write for versions where they do work.
  1619. *
  1620. * On the DEC Alpha, these routines no longer work for memory
  1621. * in dense space as of NT 4.0, so we must revert to the old
  1622. * method. Microsoft doesn't like this, but until DEC fixes
  1623. * the HAL there's nothing else we can do. All Alpha machines
  1624. * with PCI bus support dense space, but some older (Jensen)
  1625. * systems only support sparse space. Since these systems have
  1626. * only an EISA bus, we use the bus type of the card to determine
  1627. * whether to use dense or sparse memory space (PCI cards can
  1628. * use dense space since all machines with PCI buses support
  1629. * it, ISA cards may be in either an older or a newer machine,
  1630. * so they must use sparse space, no Alpha machines support
  1631. * VLB, and there are no EISA Mach 64 cards).
  1632. */
  1633. #if (TARGET_BUILD < 350)
  1634. return *(PUCHAR)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset);
  1635. #else
  1636. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1637. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1638. return *(PUCHAR)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset);
  1639. else
  1640. #endif
  1641. return VideoPortReadRegisterUchar ((PUCHAR)(((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressMM[Port]) + Offset);
  1642. #endif
  1643. }
  1644. else
  1645. {
  1646. return VideoPortReadPortUchar ((PUCHAR)(((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressIO[Port]) + Offset);
  1647. }
  1648. }
  1649. /*
  1650. * USHORT LioInpw(Port, Offset);
  1651. *
  1652. * int Port; Register to read from
  1653. * int Offset; Offset into desired register
  1654. *
  1655. * Read an unsigned short integer from a given register. Works with both
  1656. * normal I/O ports and memory-mapped registers. Offset is either zero for
  1657. * 16 bit registers and the least significant word of 32 bit registers, or
  1658. * 2 for the most significant word of 32 bit registers.
  1659. *
  1660. * Returns:
  1661. * Value held in the register.
  1662. */
  1663. USHORT LioInpw(int Port, int Offset)
  1664. {
  1665. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1666. {
  1667. #if (TARGET_BUILD < 350)
  1668. return *(PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset);
  1669. #else
  1670. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1671. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1672. return *(PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset);
  1673. else
  1674. #endif
  1675. return VideoPortReadRegisterUshort ((PUSHORT)((PUCHAR)(((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressMM[Port]) + Offset));
  1676. #endif
  1677. }
  1678. else
  1679. {
  1680. return VideoPortReadPortUshort ((PUSHORT)((PUCHAR)(((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressIO[Port]) + Offset));
  1681. }
  1682. }
  1683. /*
  1684. * ULONG LioInpd(Port);
  1685. *
  1686. * int Port; Register to read from
  1687. *
  1688. * Read an unsigned long integer from a given register. Works with both
  1689. * normal I/O ports and memory-mapped registers.
  1690. *
  1691. * Returns:
  1692. * Value held in the register.
  1693. */
  1694. ULONG LioInpd(int Port)
  1695. {
  1696. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1697. {
  1698. #if (TARGET_BUILD < 350)
  1699. return *(PULONG)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]));
  1700. #else
  1701. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1702. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1703. return *(PULONG)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]));
  1704. else
  1705. #endif
  1706. return VideoPortReadRegisterUlong (((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressMM[Port]);
  1707. #endif
  1708. }
  1709. else
  1710. {
  1711. return VideoPortReadPortUlong (((PHW_DEVICE_EXTENSION)phwDeviceExtension)->aVideoAddressIO[Port]);
  1712. }
  1713. }
  1714. /*
  1715. * VOID LioOutp(Port, Data, Offset);
  1716. *
  1717. * int Port; Register to write to
  1718. * UCHAR Data; Data to write
  1719. * int Offset; Offset into desired register
  1720. *
  1721. * Write an unsigned character to a given register. Works with both normal
  1722. * I/O ports and memory-mapped registers. Offset is zero for 8 bit registers
  1723. * and the least significant byte of 16 and 32 bit registers, 1 for the
  1724. * most significant byte of 16 bit registers and the second least significant
  1725. * byte of 32 bit registers, up to 3 for the most significant byte of 32 bit
  1726. * registers.
  1727. */
  1728. VOID LioOutp(int Port, UCHAR Data, int Offset)
  1729. {
  1730. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1731. {
  1732. #if (TARGET_BUILD < 350)
  1733. *(PUCHAR)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset) = Data;
  1734. #else
  1735. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1736. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1737. *(PUCHAR)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset) = Data;
  1738. else
  1739. #endif
  1740. VideoPortWriteRegisterUchar ((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset, (BYTE)(Data));
  1741. #endif
  1742. }
  1743. else
  1744. {
  1745. VideoPortWritePortUchar ((PUCHAR)(phwDeviceExtension->aVideoAddressIO[Port]) + Offset, (BYTE)(Data));
  1746. }
  1747. return;
  1748. }
  1749. /*
  1750. * VOID LioOutpw(Port, Data, Offset);
  1751. *
  1752. * int Port; Register to write to
  1753. * USHORT Data; Data to write
  1754. * int Offset; Offset into desired register
  1755. *
  1756. * Write an unsigned short integer to a given register. Works with both
  1757. * normal I/O ports and memory-mapped registers. Offset is either zero for
  1758. * 16 bit registers and the least significant word of 32 bit registers, or
  1759. * 2 for the most significant word of 32 bit registers.
  1760. */
  1761. VOID LioOutpw(int Port, USHORT Data, int Offset)
  1762. {
  1763. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1764. {
  1765. #if (TARGET_BUILD < 350)
  1766. *(PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset) = (WORD)(Data);
  1767. #else
  1768. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1769. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1770. *(PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset) = Data;
  1771. else
  1772. #endif
  1773. VideoPortWriteRegisterUshort ((PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port]) + Offset), (WORD)(Data));
  1774. #endif
  1775. }
  1776. else
  1777. {
  1778. VideoPortWritePortUshort ((PUSHORT)((PUCHAR)(phwDeviceExtension->aVideoAddressIO[Port]) + Offset), (WORD)(Data));
  1779. }
  1780. return;
  1781. }
  1782. /*
  1783. * VOID LioOutpd(Port, Data);
  1784. *
  1785. * int Port; Register to write to
  1786. * ULONG Data; Data to write
  1787. *
  1788. * Write an unsigned long integer to a given register. Works with both
  1789. * normal I/O ports and memory-mapped registers.
  1790. */
  1791. VOID LioOutpd(int Port, ULONG Data)
  1792. {
  1793. if (phwDeviceExtension->aVideoAddressMM[Port] != 0)
  1794. {
  1795. #if (TARGET_BUILD < 350)
  1796. *(PULONG)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port])) = (ULONG)(Data);
  1797. #else
  1798. #if ((defined (ALPHA) || defined(_ALPHA_)) && (TARGET_BUILD >= 400))
  1799. if (((struct query_structure *)phwDeviceExtension->CardInfo)->q_bus_type == BUS_PCI)
  1800. *(PULONG)((PUCHAR)(phwDeviceExtension->aVideoAddressMM[Port])) = Data;
  1801. else
  1802. #endif
  1803. VideoPortWriteRegisterUlong (phwDeviceExtension->aVideoAddressMM[Port], Data);
  1804. #endif
  1805. }
  1806. else
  1807. {
  1808. VideoPortWritePortUlong (phwDeviceExtension->aVideoAddressIO[Port], Data);
  1809. }
  1810. return;
  1811. }