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.

1050 lines
27 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spvideo.c
  5. Abstract:
  6. Text setup display support.
  7. Author:
  8. Ted Miller (tedm) 29-July-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #include <hdlsblk.h>
  13. #include <hdlsterm.h>
  14. #pragma hdrstop
  15. extern BOOLEAN ForceConsole;
  16. //
  17. // Video function vectors.
  18. //
  19. PVIDEO_FUNCTION_VECTOR VideoFunctionVector;
  20. //
  21. // Other display paramters
  22. //
  23. SP_VIDEO_VARS VideoVars;
  24. BOOLEAN VideoInitialized = FALSE;
  25. POEM_FONT_FILE_HEADER FontHeader;
  26. ULONG FontBytesPerRow;
  27. ULONG FontCharacterHeight;
  28. ULONG FontCharacterWidth;
  29. //
  30. // bootfont.bin file image
  31. //
  32. PVOID BootFontImage = NULL;
  33. ULONG BootFontImageLength = 0;
  34. //
  35. // The following structures and constants are used in font files.
  36. //
  37. //
  38. // Define OS/2 executable resource information structure.
  39. //
  40. #define FONT_DIRECTORY 0x8007
  41. #define FONT_RESOURCE 0x8008
  42. typedef struct _RESOURCE_TYPE_INFORMATION {
  43. USHORT Ident;
  44. USHORT Number;
  45. LONG Proc;
  46. } RESOURCE_TYPE_INFORMATION, *PRESOURCE_TYPE_INFORMATION;
  47. //
  48. // Define OS/2 executable resource name information structure.
  49. //
  50. typedef struct _RESOURCE_NAME_INFORMATION {
  51. USHORT Offset;
  52. USHORT Length;
  53. USHORT Flags;
  54. USHORT Ident;
  55. USHORT Handle;
  56. USHORT Usage;
  57. } RESOURCE_NAME_INFORMATION, *PRESOURCE_NAME_INFORMATION;
  58. //
  59. // These values are passed to us by setupldr and represent monitor config
  60. // data from the monitor peripheral for the display we are supposed to use
  61. // during setup. They are used only for non-vga displays.
  62. //
  63. PMONITOR_CONFIGURATION_DATA MonitorConfigData;
  64. PCHAR MonitorFirmwareIdString;
  65. //
  66. // Function prototypes.
  67. //
  68. BOOLEAN
  69. pSpvidInitPalette(
  70. VOID
  71. );
  72. VOID
  73. SpvidInitialize0(
  74. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  75. )
  76. /*++
  77. Routine Description:
  78. Perform phase-0 display initialization. This routine is used to
  79. perform initialization that can be performed only at driver load time.
  80. Actions:
  81. - initialize the font. We retreive the hal oem font image
  82. from the loader block and copy it into locally allocated memory.
  83. This must be done here because the loader block is gone
  84. when setup is actually started.
  85. Arguments:
  86. LoaderBlock - supplies pointer to loader parameter block.
  87. Return Value:
  88. None. Does not return if error.
  89. --*/
  90. {
  91. POEM_FONT_FILE_HEADER fontHeader;
  92. PSETUP_LOADER_BLOCK SetupBlock;
  93. BOOLEAN bValidOemFont;
  94. //
  95. // Check if the file has a font file header. Use SEH so that we don't bugcheck if
  96. // we got passed something screwy.
  97. //
  98. try {
  99. fontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile;
  100. if ((fontHeader->Version != OEM_FONT_VERSION) ||
  101. (fontHeader->Type != OEM_FONT_TYPE) ||
  102. (fontHeader->Italic != OEM_FONT_ITALIC) ||
  103. (fontHeader->Underline != OEM_FONT_UNDERLINE) ||
  104. (fontHeader->StrikeOut != OEM_FONT_STRIKEOUT) ||
  105. (fontHeader->CharacterSet != OEM_FONT_CHARACTER_SET) ||
  106. (fontHeader->Family != OEM_FONT_FAMILY) ||
  107. (fontHeader->PixelWidth > 32))
  108. {
  109. bValidOemFont = FALSE;
  110. } else {
  111. bValidOemFont = TRUE;
  112. }
  113. } except(EXCEPTION_EXECUTE_HANDLER) {
  114. bValidOemFont = FALSE;
  115. }
  116. if(!bValidOemFont) {
  117. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: oem hal font image is not a .fnt file.\n"));
  118. SpBugCheck(SETUP_BUGCHECK_BAD_OEM_FONT,0,0,0);
  119. }
  120. FontHeader = SpMemAlloc(fontHeader->FileSize);
  121. RtlMoveMemory(FontHeader,fontHeader,fontHeader->FileSize);
  122. FontBytesPerRow = (FontHeader->PixelWidth + 7) / 8;
  123. FontCharacterHeight = FontHeader->PixelHeight;
  124. FontCharacterWidth = FontHeader->PixelWidth;
  125. //
  126. // Get pointer to the setup loader block.
  127. //
  128. SetupBlock = LoaderBlock->SetupLoaderBlock;
  129. //
  130. // Save away monitor data.
  131. //
  132. if(SetupBlock->Monitor) {
  133. RtlMoveMemory(
  134. MonitorConfigData = SpMemAlloc(sizeof(MONITOR_CONFIGURATION_DATA)),
  135. SetupBlock->Monitor,
  136. sizeof(MONITOR_CONFIGURATION_DATA)
  137. );
  138. }
  139. if(SetupBlock->MonitorId) {
  140. MonitorFirmwareIdString = SpDupString(SetupBlock->MonitorId);
  141. }
  142. //
  143. // save off bootfont.bin file image, if any
  144. //
  145. if (SetupBlock->BootFontFile && SetupBlock->BootFontFileLength) {
  146. BootFontImage = SpMemAlloc(SetupBlock->BootFontFileLength);
  147. if (BootFontImage) {
  148. BootFontImageLength = SetupBlock->BootFontFileLength;
  149. RtlMoveMemory(BootFontImage,
  150. SetupBlock->BootFontFile,
  151. BootFontImageLength);
  152. }
  153. }
  154. //
  155. // Initialize the global video state
  156. //
  157. RtlZeroMemory(&VideoVars, sizeof(SP_VIDEO_VARS));
  158. }
  159. VOID
  160. SpvidInitialize(
  161. VOID
  162. )
  163. {
  164. NTSTATUS Status;
  165. OBJECT_ATTRIBUTES Attributes;
  166. IO_STATUS_BLOCK IoStatusBlock;
  167. UNICODE_STRING UnicodeString;
  168. VIDEO_NUM_MODES NumModes;
  169. PVIDEO_MODE_INFORMATION VideoModes;
  170. PVIDEO_MODE_INFORMATION pVideoMode;
  171. ULONG VideoModesSize;
  172. ULONG mode;
  173. BOOLEAN IsVga;
  174. PVIDEO_FUNCTION_VECTOR NewVector;
  175. PVIDEO_MODE_INFORMATION GraphicsVideoMode = NULL;
  176. //
  177. // If video is already initialized, we are performing a reinit.
  178. //
  179. if(VideoInitialized) {
  180. //
  181. // Request video function vector from the locale/lang-specific module.
  182. //
  183. NewVector = SplangGetVideoFunctionVector(
  184. (VideoFunctionVector == &VgaVideoVector) ? SpVideoVga : SpVideoFrameBuffer,
  185. &VideoVars
  186. );
  187. //
  188. // If there is no alternate video then we're done. Else go into action.
  189. //
  190. if(NewVector) {
  191. SpvidTerminate();
  192. } else {
  193. return;
  194. }
  195. } else {
  196. NewVector = NULL;
  197. }
  198. // Initialize the headless terminal
  199. SpTermInitialize();
  200. //
  201. // Open \Device\Video0.
  202. //
  203. RtlInitUnicodeString(&UnicodeString,L"\\Device\\Video0");
  204. InitializeObjectAttributes(
  205. &Attributes,
  206. &UnicodeString,
  207. OBJ_CASE_INSENSITIVE,
  208. NULL,
  209. NULL
  210. );
  211. Status = ZwCreateFile(
  212. &VideoVars.hDisplay,
  213. GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  214. &Attributes,
  215. &IoStatusBlock,
  216. NULL, // allocation size
  217. FILE_ATTRIBUTE_NORMAL,
  218. 0, // no sharing
  219. FILE_OPEN,
  220. FILE_SYNCHRONOUS_IO_NONALERT,
  221. NULL, // no EAs
  222. 0
  223. );
  224. if(!NT_SUCCESS(Status)) {
  225. //
  226. // if we're in headless mode, try to operate without the video card
  227. // present...otherwise we're done
  228. //
  229. if (HeadlessTerminalConnected) {
  230. //
  231. // if there's no video card, then we default into VGA mode,
  232. // which will do nothing if there is no video card
  233. //
  234. VideoFunctionVector = &VgaVideoVector;
  235. VideoVars.ScreenWidth = 80;
  236. VideoVars.ScreenHeight = HEADLESS_SCREEN_HEIGHT;
  237. //
  238. // Allocate a buffer for use translating unicode to oem.
  239. // Assuming each unicode char translates to a dbcs char,
  240. // we need a buffer twice the width of the screen to hold
  241. // (the width of the screen being the longest string
  242. // we'll display in one shot).
  243. //
  244. VideoVars.SpvCharTranslationBufferSize = (VideoVars.ScreenWidth+1)*2;
  245. VideoVars.SpvCharTranslationBuffer = SpMemAlloc(VideoVars.SpvCharTranslationBufferSize);
  246. VideoInitialized = TRUE;
  247. return;
  248. } else {
  249. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: NtOpenFile of \\device\\video0 returns %lx\n",Status));
  250. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_OPEN, Status);
  251. while(TRUE); // loop forever
  252. }
  253. }
  254. //
  255. // Request a list of video modes.
  256. //
  257. Status = ZwDeviceIoControlFile(
  258. VideoVars.hDisplay,
  259. NULL,
  260. NULL,
  261. NULL,
  262. &IoStatusBlock,
  263. IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES,
  264. NULL,
  265. 0,
  266. &NumModes,
  267. sizeof(NumModes)
  268. );
  269. if(!NT_SUCCESS(Status)) {
  270. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to query video mode count (status = %lx)\n",Status));
  271. ZwClose(VideoVars.hDisplay);
  272. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_GETNUMMODES, Status);
  273. while(TRUE); // loop forever
  274. }
  275. VideoModesSize = NumModes.NumModes * NumModes.ModeInformationLength;
  276. VideoModes = SpMemAlloc(VideoModesSize);
  277. Status = ZwDeviceIoControlFile(
  278. VideoVars.hDisplay,
  279. NULL,
  280. NULL,
  281. NULL,
  282. &IoStatusBlock,
  283. IOCTL_VIDEO_QUERY_AVAIL_MODES,
  284. NULL,
  285. 0,
  286. VideoModes,
  287. VideoModesSize
  288. );
  289. if(!NT_SUCCESS(Status)) {
  290. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get list of video modes (status = %lx)\n",Status));
  291. SpMemFree(VideoModes);
  292. ZwClose(VideoVars.hDisplay);
  293. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_GETMODES, Status);
  294. while(TRUE); // loop forever
  295. }
  296. //
  297. // If we have a 720 x 400 text mode, it's vga.
  298. // Otherwise it's a frame buffer.
  299. //
  300. IsVga = FALSE;
  301. pVideoMode = &VideoModes[0];
  302. for(mode=0; mode<NumModes.NumModes; mode++) {
  303. if(!IsVga && !(pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS)
  304. && (pVideoMode->VisScreenWidth == 720)
  305. && (pVideoMode->VisScreenHeight == 400))
  306. {
  307. IsVga = TRUE;
  308. }
  309. if ((pVideoMode->AttributeFlags & VIDEO_MODE_GRAPHICS) &&
  310. (pVideoMode->VisScreenWidth == 640) &&
  311. (pVideoMode->VisScreenHeight == 480) &&
  312. (pVideoMode->NumberOfPlanes == 4) &&
  313. (pVideoMode->BitsPerPlane == 1)) {
  314. GraphicsVideoMode = pVideoMode;
  315. }
  316. pVideoMode = (PVIDEO_MODE_INFORMATION) (((PUCHAR) pVideoMode) + NumModes.ModeInformationLength);
  317. }
  318. VideoFunctionVector = NewVector ? NewVector : (IsVga ? &VgaVideoVector : &FrameBufferVideoVector);
  319. //
  320. // Headless redirection only works in the VGA case.
  321. // If you enable another video mode, you must fix headless for that video
  322. // mode and then remove this assert
  323. //
  324. ASSERT( HeadlessTerminalConnected
  325. ? (VideoFunctionVector == &VgaVideoVector)
  326. : TRUE );
  327. if (GraphicsVideoMode) {
  328. VideoVars.GraphicsModeInfo = *GraphicsVideoMode;
  329. } else {
  330. //
  331. // disable graphics mode
  332. //
  333. SP_SET_UPGRADE_GRAPHICS_MODE(FALSE);
  334. }
  335. spvidSpecificInitialize(VideoModes,NumModes.NumModes,NumModes.ModeInformationLength);
  336. // Set the terminal Height to the correct value
  337. if (HeadlessTerminalConnected) {
  338. VideoVars.ScreenHeight = HEADLESS_SCREEN_HEIGHT;
  339. }
  340. //
  341. // Allocate a buffer for use translating unicode to oem.
  342. // Assuming each unicode char translates to a dbcs char,
  343. // we need a buffer twice the width of the screen to hold
  344. // (the width of the screen being the longest string
  345. // we'll display in one shot).
  346. //
  347. VideoVars.SpvCharTranslationBufferSize = (VideoVars.ScreenWidth+1)*2;
  348. VideoVars.SpvCharTranslationBuffer = SpMemAlloc(VideoVars.SpvCharTranslationBufferSize);
  349. pSpvidInitPalette();
  350. if (!SP_IS_UPGRADE_GRAPHICS_MODE()) {
  351. CLEAR_ENTIRE_SCREEN();
  352. }
  353. VideoInitialized = TRUE;
  354. SpMemFree(VideoModes);
  355. }
  356. VOID
  357. SpvidTerminate(
  358. VOID
  359. )
  360. {
  361. NTSTATUS Status;
  362. if(VideoInitialized) {
  363. spvidSpecificTerminate();
  364. SpTermTerminate();
  365. if (VideoVars.hDisplay) {
  366. Status = ZwClose(VideoVars.hDisplay);
  367. if(!NT_SUCCESS(Status)) {
  368. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to close \\device\\video0 (status = %lx)\n",Status));
  369. }
  370. }
  371. SpMemFree(VideoVars.SpvCharTranslationBuffer);
  372. VideoVars.SpvCharTranslationBuffer = NULL;
  373. VideoInitialized = FALSE;
  374. }
  375. }
  376. UCHAR
  377. GetDefaultAttr(
  378. void
  379. )
  380. {
  381. return (UCHAR)(ForceConsole ? (ATT_FG_WHITE | ATT_BG_BLACK) : (ATT_FG_WHITE | ATT_BG_BLUE));
  382. }
  383. UCHAR
  384. GetDefaultBackground(
  385. void
  386. )
  387. {
  388. return (UCHAR)(ForceConsole ? ATT_BLACK : ATT_BLUE);
  389. }
  390. UCHAR
  391. GetDefaultStatusAttr(
  392. void
  393. )
  394. {
  395. return (UCHAR)(ForceConsole ? (ATT_FG_WHITE | ATT_BG_BLACK) : (ATT_FG_BLACK | ATT_BG_WHITE));
  396. }
  397. UCHAR
  398. GetDefaultStatusBackground(
  399. void
  400. )
  401. {
  402. return (UCHAR)(ForceConsole ? ATT_BLACK : ATT_WHITE);
  403. }
  404. BOOLEAN
  405. SpvidGetModeParams(
  406. OUT PULONG XResolution,
  407. OUT PULONG YResolution,
  408. OUT PULONG BitsPerPixel,
  409. OUT PULONG VerticalRefresh,
  410. OUT PULONG InterlacedFlag
  411. )
  412. {
  413. if(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_GRAPHICS) {
  414. *XResolution = VideoVars.VideoModeInfo.VisScreenWidth;
  415. *YResolution = VideoVars.VideoModeInfo.VisScreenHeight;
  416. *BitsPerPixel = VideoVars.VideoModeInfo.BitsPerPlane;
  417. *VerticalRefresh = VideoVars.VideoModeInfo.Frequency;
  418. *InterlacedFlag = (VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_INTERLACED) ? 1 : 0;
  419. return(TRUE);
  420. } else {
  421. //
  422. // VGA/text mode. Params are not interesting.
  423. //
  424. return(FALSE);
  425. }
  426. }
  427. BOOLEAN
  428. pSpvidInitPalette(
  429. VOID
  430. )
  431. /*++
  432. Routine Description:
  433. Set the display up so we can use the standard 16 cga attributes.
  434. If the video mode is direct color, then we construct a table of
  435. attribute to color mappings based on the number of bits for
  436. red, green, and blue.
  437. If the video mode is palette driven, then we actually construct
  438. a 16-color palette and pass it to the driver.
  439. Arguments:
  440. VOID
  441. Return Value:
  442. TRUE if display set up successfully, false if not.
  443. --*/
  444. {
  445. ULONG i;
  446. ULONG MaxVal[3];
  447. ULONG MidVal[3];
  448. #define C_RED 0
  449. #define C_GRE 1
  450. #define C_BLU 2
  451. if(VideoVars.VideoModeInfo.AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN) {
  452. UCHAR Buffer[sizeof(VIDEO_CLUT)+(sizeof(VIDEO_CLUTDATA)*15)]; // size is close enough
  453. PVIDEO_CLUT clut = (PVIDEO_CLUT)Buffer;
  454. NTSTATUS Status;
  455. IO_STATUS_BLOCK IoStatusBlock;
  456. //
  457. // Palette driven. Set up the attribute to color table
  458. // as a one-to-one mapping so we can use attribute values
  459. // directly in the frame buffer and get the expected result.
  460. //
  461. MaxVal[C_RED] = ((1 << VideoVars.VideoModeInfo.NumberRedBits ) - 1);
  462. MaxVal[C_GRE] = ((1 << VideoVars.VideoModeInfo.NumberGreenBits) - 1);
  463. MaxVal[C_BLU] = ((1 << VideoVars.VideoModeInfo.NumberBlueBits ) - 1);
  464. MidVal[C_RED] = 2 * MaxVal[C_RED] / 3;
  465. MidVal[C_GRE] = 2 * MaxVal[C_GRE] / 3;
  466. MidVal[C_BLU] = 2 * MaxVal[C_BLU] / 3;
  467. clut->NumEntries = 16;
  468. clut->FirstEntry = 0;
  469. for(i=0; i<16; i++) {
  470. VideoVars.AttributeToColorValue[i] = i;
  471. clut->LookupTable[i].RgbArray.Red = (UCHAR)((i & ATT_RED )
  472. ? ((i & ATT_INTENSE) ? MaxVal[C_RED] : MidVal[C_RED])
  473. : 0);
  474. clut->LookupTable[i].RgbArray.Green = (UCHAR)((i & ATT_GREEN)
  475. ? ((i & ATT_INTENSE) ? MaxVal[C_GRE] : MidVal[C_GRE])
  476. : 0);
  477. clut->LookupTable[i].RgbArray.Blue = (UCHAR)((i & ATT_BLUE )
  478. ? ((i & ATT_INTENSE) ? MaxVal[C_BLU] : MidVal[C_BLU])
  479. : 0);
  480. clut->LookupTable[i].RgbArray.Unused = 0;
  481. }
  482. Status = ZwDeviceIoControlFile(
  483. VideoVars.hDisplay,
  484. NULL,
  485. NULL,
  486. NULL,
  487. &IoStatusBlock,
  488. IOCTL_VIDEO_SET_COLOR_REGISTERS,
  489. clut,
  490. sizeof(Buffer),
  491. NULL,
  492. 0
  493. );
  494. if(!NT_SUCCESS(Status)) {
  495. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set palette (status = %lx)\n",Status));
  496. return(FALSE);
  497. }
  498. } else {
  499. //
  500. // Direct color. Construct an attribute to color value table.
  501. //
  502. ULONG mask[3];
  503. ULONG bitcnt[3];
  504. ULONG bits;
  505. ULONG shift[3];
  506. unsigned color;
  507. //
  508. // Determine the ranges for each of red, green, and blue.
  509. //
  510. mask[C_RED] = VideoVars.VideoModeInfo.RedMask;
  511. mask[C_GRE] = VideoVars.VideoModeInfo.GreenMask;
  512. mask[C_BLU] = VideoVars.VideoModeInfo.BlueMask;
  513. bitcnt[C_RED] = VideoVars.VideoModeInfo.NumberRedBits;
  514. bitcnt[C_GRE] = VideoVars.VideoModeInfo.NumberGreenBits;
  515. bitcnt[C_BLU] = VideoVars.VideoModeInfo.NumberBlueBits;
  516. shift[C_RED] = 32;
  517. shift[C_GRE] = 32;
  518. shift[C_BLU] = 32;
  519. for(color=0; color<3; color++) {
  520. bits = 0;
  521. //
  522. // Count the number of 1 bits and determine the shift value
  523. // to shift in that color component.
  524. //
  525. for(i=0; i<32; i++) {
  526. if(mask[color] & (1 << i)) {
  527. bits++;
  528. //
  529. // Remember the position of the least significant bit
  530. // in this mask.
  531. //
  532. if(shift[color] == 32) {
  533. shift[color] = i;
  534. }
  535. }
  536. }
  537. //
  538. // Calculate the maximum color value for this color component.
  539. //
  540. MaxVal[color] = (1 << bits) - 1;
  541. //
  542. // Make sure we haven't overflowed the actual number of bits
  543. // available for this color component.
  544. //
  545. if(bitcnt[color] && (MaxVal[color] > ((ULONG)(1 << bitcnt[color]) - 1))) {
  546. MaxVal[color] = (ULONG)(1 << bitcnt[color]) - 1;
  547. }
  548. }
  549. MidVal[C_RED] = 2 * MaxVal[C_RED] / 3;
  550. MidVal[C_GRE] = 2 * MaxVal[C_GRE] / 3;
  551. MidVal[C_BLU] = 2 * MaxVal[C_BLU] / 3;
  552. //
  553. // Now go through and construct the color table.
  554. //
  555. for(i=0; i<16; i++) {
  556. VideoVars.AttributeToColorValue[i] =
  557. (((i & ATT_RED)
  558. ? ((i & ATT_INTENSE) ? MaxVal[C_RED] : MidVal[C_RED])
  559. : 0)
  560. << shift[C_RED])
  561. | (((i & ATT_GREEN)
  562. ? ((i & ATT_INTENSE) ? MaxVal[C_GRE] : MidVal[C_GRE])
  563. : 0)
  564. << shift[C_GRE])
  565. | (((i & ATT_BLUE)
  566. ? ((i & ATT_INTENSE) ? MaxVal[C_BLU] : MidVal[C_BLU])
  567. : 0)
  568. << shift[C_BLU]);
  569. }
  570. }
  571. //
  572. // Perform any display-specific palette setup.
  573. //
  574. return(spvidSpecificInitPalette());
  575. }
  576. VOID
  577. pSpvidMapVideoMemory(
  578. IN BOOLEAN Map
  579. )
  580. /*++
  581. Routine Description:
  582. Map or unmap video memory. Fills in or uses the VideoMemoryInfo global.
  583. Arguments:
  584. Map - if TRUE, map video memory.
  585. if FALSE, unmap video memory.
  586. Return Value:
  587. --*/
  588. {
  589. NTSTATUS Status;
  590. IO_STATUS_BLOCK IoStatusBlock;
  591. VIDEO_MEMORY VideoMemory;
  592. VideoMemory.RequestedVirtualAddress = Map ? NULL : VideoVars.VideoMemoryInfo.VideoRamBase;
  593. Status = ZwDeviceIoControlFile(
  594. VideoVars.hDisplay,
  595. NULL,
  596. NULL,
  597. NULL,
  598. &IoStatusBlock,
  599. Map ? IOCTL_VIDEO_MAP_VIDEO_MEMORY : IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
  600. &VideoMemory,
  601. sizeof(VideoMemory),
  602. Map ? &VideoVars.VideoMemoryInfo : NULL,
  603. Map ? sizeof(VideoVars.VideoMemoryInfo) : 0
  604. );
  605. if(!NT_SUCCESS(Status)) {
  606. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to %smap video memory (status = %lx)\n",Map ? "" : "un",Status));
  607. if(Map) {
  608. SpDisplayRawMessage(SP_SCRN_VIDEO_ERROR_RAW, 2, VIDEOBUG_MAP, Status);
  609. while(TRUE); // loop forever
  610. }
  611. }
  612. }
  613. VOID
  614. SpvidDisplayString(
  615. IN PWSTR String,
  616. IN UCHAR Attribute,
  617. IN ULONG X,
  618. IN ULONG Y
  619. )
  620. {
  621. //
  622. // Convert unicode string to oem, guarding against overflow.
  623. //
  624. RtlUnicodeToOemN(
  625. VideoVars.SpvCharTranslationBuffer,
  626. VideoVars.SpvCharTranslationBufferSize-1, // guarantee room for nul
  627. NULL,
  628. String,
  629. (wcslen(String)+1)*sizeof(WCHAR)
  630. );
  631. VideoVars.SpvCharTranslationBuffer[VideoVars.SpvCharTranslationBufferSize-1] = 0;
  632. spvidSpecificDisplayString(VideoVars.SpvCharTranslationBuffer,Attribute,X,Y);
  633. SpTermDisplayStringOnTerminal( String, Attribute, X, Y);
  634. }
  635. VOID
  636. SpvidDisplayOemString(
  637. IN PSTR String,
  638. IN UCHAR Attribute,
  639. IN ULONG X,
  640. IN ULONG Y
  641. )
  642. {
  643. spvidSpecificDisplayString(String,Attribute,X,Y);
  644. RtlOemToUnicodeN(
  645. (PWSTR)VideoVars.SpvCharTranslationBuffer,
  646. VideoVars.SpvCharTranslationBufferSize-1, // guarantee room for nul
  647. NULL,
  648. String,
  649. (strlen(String)+1)*sizeof(CHAR));
  650. //
  651. // make it a unicode NULL at the end
  652. //
  653. VideoVars.SpvCharTranslationBuffer[VideoVars.SpvCharTranslationBufferSize-1] = '\0';
  654. VideoVars.SpvCharTranslationBuffer[VideoVars.SpvCharTranslationBufferSize-2] = '\0';
  655. SpTermDisplayStringOnTerminal((PWSTR)VideoVars.SpvCharTranslationBuffer, Attribute, X, Y);
  656. }
  657. VOID
  658. SpvidClearScreenRegion(
  659. IN ULONG X,
  660. IN ULONG Y,
  661. IN ULONG W,
  662. IN ULONG H,
  663. IN UCHAR Attribute
  664. )
  665. /*++
  666. Routine Description:
  667. Clear out a screen region to a specific attribute.
  668. Arguments:
  669. X,Y,W,H - specify rectangle in 0-based character coordinates.
  670. If W or H are 0, clear the entire screen.
  671. Attribute - Low nibble specifies attribute to be filled in the rectangle
  672. (ie, the background color to be cleared to).
  673. Return Value:
  674. None.
  675. --*/
  676. {
  677. ULONG i;
  678. UCHAR FillAttribute;
  679. WCHAR TerminalLine[80];
  680. BOOLEAN ToEOL;
  681. if(!W || !H) {
  682. X = Y = 0;
  683. W = VideoVars.ScreenWidth;
  684. H = VideoVars.ScreenHeight;
  685. } else {
  686. ASSERT(X+W <= VideoVars.ScreenWidth);
  687. ASSERT(X <= VideoVars.ScreenWidth);
  688. ASSERT(W <= VideoVars.ScreenWidth);
  689. ASSERT(Y+H <= VideoVars.ScreenHeight);
  690. ASSERT(Y <= VideoVars.ScreenHeight);
  691. ASSERT(H <= VideoVars.ScreenHeight);
  692. if (W > VideoVars.ScreenWidth)
  693. W = VideoVars.ScreenWidth;
  694. if (X > VideoVars.ScreenWidth)
  695. X = VideoVars.ScreenWidth;
  696. if(X+W > VideoVars.ScreenWidth) {
  697. W = VideoVars.ScreenWidth-X;
  698. }
  699. if(Y > VideoVars.ScreenHeight) {
  700. Y = VideoVars.ScreenHeight;
  701. }
  702. if(H > VideoVars.ScreenHeight) {
  703. H = VideoVars.ScreenHeight;
  704. }
  705. if(Y+H > VideoVars.ScreenHeight) {
  706. H = VideoVars.ScreenHeight-Y;
  707. }
  708. }
  709. spvidSpecificClearRegion(X,Y,W,H,Attribute);
  710. FillAttribute = (Attribute << 4) | Attribute;
  711. ToEOL = FALSE;
  712. if (X + W < 80) {
  713. for (i = 0; i<W;i++) {
  714. TerminalLine[i] = L' ';
  715. }
  716. TerminalLine[W] = L'\0';
  717. } else {
  718. for (i = 0; i<(79-X); i++) {
  719. TerminalLine[i] = L' ';
  720. }
  721. TerminalLine[79 - X] = L'\0';
  722. if ((X == 0) && (Attribute == DEFAULT_BACKGROUND)) {
  723. ToEOL = TRUE;
  724. }
  725. }
  726. for(i=0; i<H; i++) {
  727. if (ToEOL) {
  728. SpTermDisplayStringOnTerminal(HEADLESS_CLEAR_TO_EOL_STRING,
  729. FillAttribute,
  730. X,
  731. Y + i
  732. );
  733. } else {
  734. SpTermDisplayStringOnTerminal(TerminalLine, FillAttribute, X, Y + i);
  735. }
  736. }
  737. }
  738. BOOLEAN
  739. SpvidScrollUp(
  740. IN ULONG TopLine,
  741. IN ULONG BottomLine,
  742. IN ULONG LineCount,
  743. IN UCHAR FillAttribute
  744. )
  745. {
  746. BOOLEAN vidSpecificRet;
  747. ULONG i;
  748. ULONG line;
  749. WCHAR TerminalLine[80];
  750. vidSpecificRet = spvidSpecificScrollUp(TopLine,BottomLine,LineCount,FillAttribute);
  751. if (!HeadlessTerminalConnected) {
  752. return(vidSpecificRet);
  753. }
  754. if ((TopLine == 0) && (BottomLine==VideoVars.ScreenHeight-1)) {
  755. //
  756. // Efficient scrolling for *whole screen* by
  757. // issuing the <CSI>x;80H escape, which moves the cursor to
  758. // the bottom right corner of the VT100. Each time we
  759. // move the cursor to this position, it makes the VT100 scroll
  760. // one line.
  761. //
  762. swprintf(TerminalLine, L"\033[%d;80H\n", BottomLine+1);
  763. for (i=0;i<LineCount; i++){
  764. SpTermSendStringToTerminal(TerminalLine,
  765. TRUE
  766. );
  767. }
  768. return vidSpecificRet;
  769. }
  770. //
  771. // We have to scroll it the hard way because we're not doing the
  772. // entire screen
  773. //
  774. //
  775. // Select the top and bottom line numbers via <CSI>x;yr escape
  776. // this will be some portion of the active display
  777. //
  778. swprintf(TerminalLine,L"\033[%d;%dr", TopLine+1, BottomLine+1);
  779. SpTermSendStringToTerminal(TerminalLine,
  780. TRUE
  781. );
  782. //
  783. // move the cursor to the bottom right corner of the selected area
  784. // via <CSI>x;80H escape. Each time we write to this area, it makes
  785. // the selected area scroll one line
  786. //
  787. swprintf(TerminalLine, L"\033[%d;80H\n", BottomLine+1);
  788. for(i = 0; i< LineCount; i++){
  789. SpTermSendStringToTerminal(TerminalLine,
  790. TRUE
  791. );
  792. }
  793. //
  794. // get a line of whitespace to clear out the bottom lines that may
  795. // have garbage in them now.
  796. //
  797. for (i=0;i<79;i++) {
  798. TerminalLine[i] = L' ';
  799. }
  800. TerminalLine[79] = '\0';
  801. line = BottomLine - LineCount + 1;
  802. for(i=0;i<LineCount;i++){
  803. SpTermDisplayStringOnTerminal(TerminalLine,
  804. FillAttribute,
  805. 0,
  806. line + i
  807. );
  808. }
  809. //
  810. // send <CSI>r escape, which resets the selected line numbers
  811. // so that the entire display is active again.
  812. //
  813. swprintf(TerminalLine, L"\033[r");
  814. SpTermSendStringToTerminal(TerminalLine,
  815. TRUE
  816. );
  817. return vidSpecificRet;
  818. }