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.

643 lines
15 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spvidvga.c
  5. Abstract:
  6. Text setup display support displays with a text mode.
  7. Author:
  8. Ted Miller (tedm) 2-Aug-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #include "ntddser.h"
  13. #include <hdlsblk.h>
  14. #include <hdlsterm.h>
  15. #pragma hdrstop
  16. //
  17. // Vector for text-mode functions.
  18. //
  19. VIDEO_FUNCTION_VECTOR VgaVideoVector =
  20. {
  21. VgaDisplayString,
  22. VgaClearRegion,
  23. VgaSpecificInit,
  24. VgaSpecificReInit,
  25. VgaSpecificTerminate,
  26. VgaSpecificInitPalette,
  27. VgaSpecificScrollUp
  28. };
  29. BOOLEAN VgaInitialized = FALSE;
  30. VOID
  31. pSpvgaInitializeFont(
  32. VOID
  33. );
  34. VOID
  35. VgaSpecificInit(
  36. IN PVIDEO_MODE_INFORMATION VideoModes,
  37. IN ULONG NumberOfModes,
  38. IN ULONG ModeSize
  39. )
  40. /*++
  41. Routine Description:
  42. Arguments:
  43. Return Value:
  44. --*/
  45. {
  46. NTSTATUS Status;
  47. IO_STATUS_BLOCK IoStatusBlock;
  48. VIDEO_MODE VideoMode;
  49. ULONG mode;
  50. ULONG StandardMode = -1;
  51. ULONG HeadlessMode = -1;
  52. ULONG HeadlessLines = 0;
  53. VIDEO_CURSOR_ATTRIBUTES VideoCursorAttributes;
  54. PVIDEO_MODE_INFORMATION pVideoMode = &VideoModes[0];
  55. if(VgaInitialized) {
  56. return;
  57. }
  58. //
  59. // Find a mode that will work. If we are not running on a headless machine,
  60. // then we search for standard 720x400 mode. Otherwise we try and find the
  61. // mode that will result in a screen closest to the terminal height.
  62. //
  63. for(mode=0; mode<NumberOfModes; mode++) {
  64. if(!(pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS)
  65. && (pVideoMode->VisScreenWidth == 720)
  66. && (pVideoMode->VisScreenHeight == 400)) {
  67. StandardMode = mode;
  68. }
  69. if ((HeadlessTerminalConnected) &&
  70. ((pVideoMode->VisScreenHeight / FontCharacterHeight) >= HEADLESS_SCREEN_HEIGHT)
  71. && (!(pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS))) {
  72. if ((HeadlessMode == -1) ||
  73. ((pVideoMode->VisScreenHeight / FontCharacterHeight) < HeadlessLines)) {
  74. HeadlessMode = mode;
  75. HeadlessLines = pVideoMode->VisScreenHeight / FontCharacterHeight;
  76. }
  77. }
  78. pVideoMode = (PVIDEO_MODE_INFORMATION) (((PUCHAR) pVideoMode) + ModeSize);
  79. }
  80. //
  81. // if we're in headless mode, we might not have found an acceptable mode
  82. // first try to use the standard video mode if that's available.
  83. // otherwise we have to assume that there isn't any video, etc.
  84. //
  85. if (HeadlessTerminalConnected && (HeadlessMode == -1)) {
  86. if (StandardMode != -1) {
  87. HeadlessMode = StandardMode;
  88. } else {
  89. KdPrintEx((
  90. DPFLTR_SETUP_ID,
  91. DPFLTR_ERROR_LEVEL,
  92. "SETUP: no video mode present in headless mode. Run w/out video\n"));
  93. }
  94. }
  95. if (((StandardMode == -1) && !HeadlessTerminalConnected)) {
  96. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Desired video mode not supported!\n"));
  97. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_BADMODE, 0);
  98. while(TRUE); // loop forever
  99. }
  100. if (HeadlessTerminalConnected && (HeadlessMode == -1)) {
  101. return;
  102. }
  103. pVideoMode = HeadlessTerminalConnected
  104. ? &VideoModes[HeadlessMode]
  105. : &VideoModes[StandardMode];
  106. VideoVars.VideoModeInfo = *pVideoMode;
  107. //
  108. // Set the desired mode.
  109. //
  110. VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
  111. Status = ZwDeviceIoControlFile(
  112. VideoVars.hDisplay,
  113. NULL,
  114. NULL,
  115. NULL,
  116. &IoStatusBlock,
  117. IOCTL_VIDEO_SET_CURRENT_MODE,
  118. &VideoMode,
  119. sizeof(VideoMode),
  120. NULL,
  121. 0
  122. );
  123. if(!NT_SUCCESS(Status)) {
  124. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
  125. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
  126. while(TRUE); // loop forever
  127. }
  128. pSpvidMapVideoMemory(TRUE);
  129. pSpvgaInitializeFont();
  130. //
  131. // Shut the hardware cursor off.
  132. //
  133. RtlZeroMemory(&VideoCursorAttributes,sizeof(VideoCursorAttributes));
  134. Status = ZwDeviceIoControlFile(
  135. VideoVars.hDisplay,
  136. NULL,
  137. NULL,
  138. NULL,
  139. &IoStatusBlock,
  140. IOCTL_VIDEO_SET_CURSOR_ATTR,
  141. &VideoCursorAttributes,
  142. sizeof(VideoCursorAttributes),
  143. NULL,
  144. 0
  145. );
  146. if(!NT_SUCCESS(Status)) {
  147. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to turn hw cursor off (status = %lx)\n",Status));
  148. }
  149. VgaInitialized = TRUE;
  150. ASSERT(VideoVars.VideoModeInfo.ScreenStride = 160);
  151. ASSERT(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN);
  152. VideoVars.ScreenWidth = 80;
  153. VideoVars.ScreenHeight = VideoVars.VideoModeInfo.VisScreenHeight / FontCharacterHeight;
  154. //
  155. // allocate the background video buffer, if needed
  156. //
  157. if (SP_IS_UPGRADE_GRAPHICS_MODE()) {
  158. VideoVars.VideoBufferSize =
  159. (VideoVars.VideoModeInfo.ScreenStride * VideoVars.VideoModeInfo.VisScreenHeight) / 8;
  160. VideoVars.VideoBuffer = SpMemAlloc(VideoVars.VideoBufferSize);
  161. if (!VideoVars.VideoBuffer) {
  162. //
  163. // Out of memory, run only in textmode
  164. //
  165. VideoVars.VideoBufferSize = 0;
  166. SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
  167. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  168. } else {
  169. VideoVars.ActiveVideoBuffer = VideoVars.VideoBuffer;
  170. }
  171. } else {
  172. VideoVars.VideoBufferSize = 0;
  173. VideoVars.VideoBuffer = NULL;
  174. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  175. }
  176. }
  177. BOOLEAN
  178. VgaSpecificInitPalette(
  179. VOID
  180. )
  181. {
  182. NTSTATUS Status;
  183. IO_STATUS_BLOCK IoStatusBlock;
  184. USHORT InitialPalette[] = {
  185. 16, // 16 entries
  186. 0, // start with first palette register
  187. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
  188. if (!VgaInitialized) {
  189. return(TRUE);
  190. }
  191. Status = ZwDeviceIoControlFile(
  192. VideoVars.hDisplay,
  193. NULL,
  194. NULL,
  195. NULL,
  196. &IoStatusBlock,
  197. IOCTL_VIDEO_SET_PALETTE_REGISTERS,
  198. InitialPalette,
  199. sizeof(InitialPalette),
  200. NULL,
  201. 0
  202. );
  203. if(!NT_SUCCESS(Status)) {
  204. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set palette (status = %lx)\n",Status));
  205. return(FALSE);
  206. }
  207. return (TRUE);
  208. }
  209. VOID
  210. VgaSpecificReInit(
  211. VOID
  212. )
  213. /*++
  214. Routine Description:
  215. Arguments:
  216. Return Value:
  217. --*/
  218. {
  219. NTSTATUS Status;
  220. IO_STATUS_BLOCK IoStatusBlock;
  221. VIDEO_MODE VideoMode;
  222. VIDEO_CURSOR_ATTRIBUTES VideoCursorAttributes;
  223. if(!VgaInitialized) {
  224. return;
  225. }
  226. //
  227. // Set the desired mode back
  228. //
  229. VideoMode.RequestedMode = VideoVars.VideoModeInfo.ModeIndex;
  230. Status = ZwDeviceIoControlFile(
  231. VideoVars.hDisplay,
  232. NULL,
  233. NULL,
  234. NULL,
  235. &IoStatusBlock,
  236. IOCTL_VIDEO_SET_CURRENT_MODE,
  237. &VideoMode,
  238. sizeof(VideoMode),
  239. NULL,
  240. 0
  241. );
  242. if(!NT_SUCCESS(Status)) {
  243. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set mode %u (status = %lx)\n",VideoMode.RequestedMode,Status));
  244. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETMODE, Status);
  245. while(TRUE); // loop forever
  246. }
  247. pSpvgaInitializeFont();
  248. //
  249. // Shut the hardware cursor off.
  250. //
  251. RtlZeroMemory(&VideoCursorAttributes,sizeof(VideoCursorAttributes));
  252. Status = ZwDeviceIoControlFile(
  253. VideoVars.hDisplay,
  254. NULL,
  255. NULL,
  256. NULL,
  257. &IoStatusBlock,
  258. IOCTL_VIDEO_SET_CURSOR_ATTR,
  259. &VideoCursorAttributes,
  260. sizeof(VideoCursorAttributes),
  261. NULL,
  262. 0
  263. );
  264. if(!NT_SUCCESS(Status)) {
  265. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to turn hw cursor off (status = %lx)\n",Status));
  266. }
  267. VgaSpecificInitPalette();
  268. //
  269. // Blast the cached video memory to the real framebuffer now
  270. //
  271. if (SP_IS_UPGRADE_GRAPHICS_MODE() && VideoVars.VideoBuffer &&
  272. VideoVars.VideoBufferSize) {
  273. PUCHAR Source = VideoVars.VideoBuffer;
  274. PUCHAR Destination = VideoVars.VideoMemoryInfo.FrameBufferBase;
  275. ULONG Index;
  276. for (Index=0; Index < VideoVars.VideoBufferSize; Index++) {
  277. WRITE_REGISTER_UCHAR(Destination + Index, *(Source + Index));
  278. }
  279. SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
  280. VideoVars.ActiveVideoBuffer = VideoVars.VideoMemoryInfo.FrameBufferBase;
  281. }
  282. }
  283. VOID
  284. VgaSpecificTerminate(
  285. VOID
  286. )
  287. /*++
  288. Routine Description:
  289. Perform text display specific termination. This includes
  290. - unmapping video memory
  291. Arguments:
  292. None.
  293. Return Value:
  294. --*/
  295. {
  296. if(VgaInitialized) {
  297. pSpvidMapVideoMemory(FALSE);
  298. if (VideoVars.VideoBuffer && VideoVars.VideoBufferSize) {
  299. SpMemFree(VideoVars.VideoBuffer);
  300. VideoVars.VideoBuffer = NULL;
  301. VideoVars.VideoBufferSize = 0;
  302. }
  303. VgaInitialized = FALSE;
  304. }
  305. }
  306. VOID
  307. VgaDisplayString(
  308. IN PSTR String,
  309. IN UCHAR Attribute,
  310. IN ULONG X, // 0-based coordinates (character units)
  311. IN ULONG Y
  312. )
  313. /*++
  314. Routine Description:
  315. Write a string of characters to the display.
  316. Arguments:
  317. Character - supplies a string (OEM charset) to be displayed
  318. at the given position.
  319. Attribute - supplies the attributes for the characters in the string.
  320. X,Y - specify the character-based (0-based) position of the output.
  321. Return Value:
  322. None.
  323. --*/
  324. {
  325. PUCHAR Destination;
  326. PUCHAR pch;
  327. if (!VgaInitialized) {
  328. return;
  329. }
  330. ASSERT(X < VideoVars.ScreenWidth);
  331. ASSERT(Y < VideoVars.ScreenHeight);
  332. Destination = (PUCHAR)VideoVars.ActiveVideoBuffer
  333. + (Y * VideoVars.VideoModeInfo.ScreenStride)
  334. + (2*X);
  335. for(pch=String; *pch; pch++) {
  336. WRITE_REGISTER_UCHAR(Destination ,*pch);
  337. WRITE_REGISTER_UCHAR(Destination+1,Attribute);
  338. Destination += 2;
  339. }
  340. }
  341. VOID
  342. VgaClearRegion(
  343. IN ULONG X,
  344. IN ULONG Y,
  345. IN ULONG W,
  346. IN ULONG H,
  347. IN UCHAR Attribute
  348. )
  349. /*++
  350. Routine Description:
  351. Clear out a screen region to a specific attribute.
  352. Arguments:
  353. X,Y,W,H - specify rectangle in 0-based character coordinates.
  354. Attribute - Low nibble specifies attribute to be filled in the rectangle
  355. (ie, the background color to be cleared to).
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. PUSHORT Destination;
  361. USHORT Fill;
  362. ULONG i,j;
  363. if (!VgaInitialized) {
  364. return;
  365. }
  366. Destination = (PUSHORT)((PUCHAR)VideoVars.ActiveVideoBuffer
  367. + (Y * VideoVars.VideoModeInfo.ScreenStride)
  368. + (2*X));
  369. Fill = ((USHORT)VideoVars.AttributeToColorValue[Attribute] << 12) + ' ';
  370. for(i=0; i<H; i++) {
  371. for(j=0; j<W; j++) {
  372. WRITE_REGISTER_USHORT(&Destination[j],Fill);
  373. }
  374. Destination += VideoVars.VideoModeInfo.ScreenStride / sizeof(USHORT);
  375. }
  376. }
  377. BOOLEAN
  378. VgaSpecificScrollUp(
  379. IN ULONG TopLine,
  380. IN ULONG BottomLine,
  381. IN ULONG LineCount,
  382. IN UCHAR FillAttribute
  383. )
  384. {
  385. PUSHORT Source,Target;
  386. ULONG Count;
  387. if (!VgaInitialized) {
  388. return(TRUE);
  389. }
  390. Target = (PUSHORT)VideoVars.ActiveVideoBuffer
  391. + ((TopLine * VideoVars.VideoModeInfo.ScreenStride)/2);
  392. Source = Target + ((LineCount * VideoVars.VideoModeInfo.ScreenStride)/2);
  393. Count = ((((BottomLine - TopLine) + 1) - LineCount) * VideoVars.VideoModeInfo.ScreenStride) / 2;
  394. while (Count--) {
  395. WRITE_REGISTER_USHORT(Target++, READ_REGISTER_USHORT(Source++));
  396. }
  397. //
  398. // Clear bottom of scroll region
  399. //
  400. VgaClearRegion(0,
  401. (BottomLine - LineCount) + 1,
  402. VideoVars.ScreenWidth,
  403. LineCount,
  404. FillAttribute
  405. );
  406. return(TRUE);
  407. }
  408. VOID
  409. pSpvgaInitializeFont(
  410. VOID
  411. )
  412. /*++
  413. Routine Description:
  414. Set up font support for the VGA. This assumes that the mode has been
  415. set to the standard 720x400 VGA text mode. The current font (in .fnt
  416. format) is transformed into a vga-loadable font and then loaded into
  417. the VGA character generator.
  418. Arguments:
  419. None.
  420. Return Value:
  421. None.
  422. --*/
  423. {
  424. USHORT i;
  425. PVIDEO_LOAD_FONT_INFORMATION DstFont;
  426. NTSTATUS Status;
  427. IO_STATUS_BLOCK IoStatusBlock;
  428. PUCHAR FontBuffer;
  429. ULONG FontBufferSize;
  430. FontBufferSize = (256*FontCharacterHeight) + sizeof(VIDEO_LOAD_FONT_INFORMATION);
  431. FontBuffer = SpMemAlloc(FontBufferSize);
  432. DstFont = (PVIDEO_LOAD_FONT_INFORMATION)FontBuffer;
  433. DstFont->WidthInPixels = 9;
  434. DstFont->HeightInPixels = (USHORT)FontCharacterHeight;
  435. DstFont->FontSize = 256*FontCharacterHeight;
  436. //
  437. // Special case character 0 because it is not in vgaoem.fon, and we don't
  438. // want to use the default character for it.
  439. //
  440. RtlZeroMemory(DstFont->Font,FontCharacterHeight);
  441. //
  442. // If i is not a USHORT, then (i<=255) is always TRUE!
  443. //
  444. for(i=1; i<=255; i++) {
  445. UCHAR x;
  446. if((i < FontHeader->FirstCharacter) || (i > FontHeader->LastCharacter)) {
  447. x = FontHeader->DefaultCharacter;
  448. } else {
  449. x = (UCHAR)i;
  450. }
  451. x -= FontHeader->FirstCharacter;
  452. RtlMoveMemory(
  453. DstFont->Font + (i*FontCharacterHeight),
  454. (PUCHAR)FontHeader + FontHeader->Map[x].Offset,
  455. FontCharacterHeight
  456. );
  457. }
  458. Status = ZwDeviceIoControlFile(
  459. VideoVars.hDisplay,
  460. NULL,
  461. NULL,
  462. NULL,
  463. &IoStatusBlock,
  464. IOCTL_VIDEO_LOAD_AND_SET_FONT,
  465. FontBuffer,
  466. FontBufferSize,
  467. NULL,
  468. 0
  469. );
  470. SpMemFree(FontBuffer);
  471. if(!NT_SUCCESS(Status)) {
  472. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set vga font (%lx)\n",Status));
  473. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_SETFONT, Status);
  474. while(TRUE); // loop forever
  475. }
  476. }