532d681a745fe26e8536e4137bdcda20e1942e57
[reactos.git] / reactos / hal / halx86 / display.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: display.c,v 1.5 2003/06/21 14:25:30 gvg Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: ntoskrnl/hal/x86/display.c
24 * PURPOSE: Blue screen display
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 * UPDATE HISTORY:
27 * Created 08/10/99
28 */
29
30 /* DISPLAY OWNERSHIP
31 *
32 * So, who owns the physical display and is allowed to write to it?
33 *
34 * In MS NT, upon boot HAL owns the display. Somewhere in the boot
35 * sequence (haven't figured out exactly where or by who), some
36 * component calls HalAcquireDisplayOwnership. From that moment on,
37 * the display is owned by that component and is switched to graphics
38 * mode. The display is not supposed to return to text mode, except
39 * in case of a bug check. The bug check will call HalDisplayString
40 * to output a string to the text screen. HAL will notice that it
41 * currently doesn't own the display and will re-take ownership, by
42 * calling the callback function passed to HalAcquireDisplayOwnership.
43 * After the bugcheck, execution is halted. So, under NT, the only
44 * possible sequence of display modes is text mode -> graphics mode ->
45 * text mode (the latter hopefully happening very infrequently).
46 *
47 * Things are a little bit different in the current state of ReactOS.
48 * We want to have a functional interactive text mode. We should be
49 * able to switch from text mode to graphics mode when a GUI app is
50 * started and switch back to text mode when it's finished. Then, when
51 * another GUI app is started, another switch to and from graphics mode
52 * is possible. Also, when the system bugchecks in graphics mode we want
53 * to switch back to text mode to show the registers and stack trace.
54 * Last but not least, HalDisplayString is used a lot more in ReactOS,
55 * e.g. to print debug messages when the /DEBUGPORT=SCREEN boot option
56 * is present.
57 * 3 Components are involved in Reactos: HAL, BLUE.SYS and VIDEOPRT.SYS.
58 * As in NT, on boot HAL owns the display. When entering the text mode
59 * command interpreter, BLUE.SYS kicks in. It will write directly to the
60 * screen, more or less behind HALs back.
61 * When a GUI app is started, WIN32K.SYS will open the DISPLAY device.
62 * This open call will end up in VIDEOPRT.SYS. That component will then
63 * take ownership of the display by calling HalAcquireDisplayOwnership.
64 * When the GUI app terminates (WIN32K.SYS will close the DISPLAY device),
65 * we want to give ownership of the display back to HAL. Using the
66 * standard exported HAL functions, that's a bit of a problem, because
67 * there is no function defined to do that. In NT, this is handled by
68 * HalDisplayString, but that solution isn't satisfactory in ReactOS,
69 * because HalDisplayString is (in some cases) also used to output debug
70 * messages. If we do it the NT way, the first debug message output while
71 * in graphics mode would switch the display back to text mode.
72 * So, instead, if HalDisplayString detects that HAL doesn't have ownership
73 * of the display, it doesn't do anything.
74 * To return ownership to HAL, a new function is exported,
75 * HalReleaseDisplayOwnership. This function is called by the DISPLAY
76 * device Close routine in VIDEOPRT.SYS. It is also called at the beginning
77 * of a bug check, so HalDisplayString is activated again.
78 * Now, while the display is in graphics mode (not owned by HAL), BLUE.SYS
79 * should also refrain from writing to the screen buffer. The text mode
80 * screen buffer might overlap the graphics mode screen buffer, so changing
81 * something in the text mode buffer might mess up the graphics screen. To
82 * allow BLUE.SYS to detect if HAL owns the display, another new function is
83 * exported, HalQueryDisplayOwnership. BLUE.SYS will call this function to
84 * check if it's allowed to touch the text mode buffer.
85 *
86 * In an ideal world, when HAL takes ownership of the display, it should set
87 * up the CRT using real-mode (actually V86 mode, but who cares) INT 0x10
88 * calls. Unfortunately, this will require HAL to setup a real-mode interrupt
89 * table etc. So, we chickened out of that by having the loader set up the
90 * display before switching to protected mode. If HAL is given back ownership
91 * after a GUI app terminates, the INT 0x10 calls are made by VIDEOPRT.SYS,
92 * since there is already support for them via the VideoPortInt10 routine.
93 */
94
95 #include <ddk/ntddk.h>
96 #include <mps.h>
97
98 #define SCREEN_SYNCHRONIZATION
99
100
101 #define CRTC_COMMAND 0x3d4
102 #define CRTC_DATA 0x3d5
103
104 #define CRTC_COLUMNS 0x01
105 #define CRTC_OVERFLOW 0x07
106 #define CRTC_ROWS 0x12
107 #define CRTC_SCANLINES 0x09
108
109 #define CRTC_CURHI 0x0e
110 #define CRTC_CURLO 0x0f
111
112
113 #define CHAR_ATTRIBUTE 0x17 /* grey on blue */
114
115
116 /* VARIABLES ****************************************************************/
117
118 static ULONG CursorX = 0; /* Cursor Position */
119 static ULONG CursorY = 0;
120 static ULONG SizeX = 80; /* Display size */
121 static ULONG SizeY = 25;
122
123 static BOOLEAN DisplayInitialized = FALSE;
124 static BOOLEAN HalOwnsDisplay = TRUE;
125
126 static WORD *VideoBuffer = NULL;
127
128 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters = NULL;
129
130
131 /* STATIC FUNCTIONS *********************************************************/
132
133 static VOID
134 HalClearDisplay (VOID)
135 {
136 WORD *ptr = (WORD*)VideoBuffer;
137 ULONG i;
138
139 for (i = 0; i < SizeX * SizeY; i++, ptr++)
140 *ptr = ((CHAR_ATTRIBUTE << 8) + ' ');
141
142 CursorX = 0;
143 CursorY = 0;
144 }
145
146
147 VOID
148 HalScrollDisplay (VOID)
149 {
150 WORD *ptr;
151 int i;
152
153 ptr = VideoBuffer + SizeX;
154 RtlMoveMemory(VideoBuffer,
155 ptr,
156 SizeX * (SizeY - 1) * 2);
157
158 ptr = VideoBuffer + (SizeX * (SizeY - 1));
159 for (i = 0; i < SizeX; i++, ptr++)
160 {
161 *ptr = (CHAR_ATTRIBUTE << 8) + ' ';
162 }
163 }
164
165
166 static VOID
167 HalPutCharacter (CHAR Character)
168 {
169 WORD *ptr;
170
171 ptr = VideoBuffer + ((CursorY * SizeX) + CursorX);
172 *ptr = (CHAR_ATTRIBUTE << 8) + Character;
173 }
174
175
176 /* PRIVATE FUNCTIONS ********************************************************/
177
178 VOID
179 HalInitializeDisplay (PLOADER_PARAMETER_BLOCK LoaderBlock)
180 /*
181 * FUNCTION: Initalize the display
182 * ARGUMENTS:
183 * InitParameters = Parameters setup by the boot loader
184 */
185 {
186 if (DisplayInitialized == FALSE)
187 {
188 ULONG ScanLines;
189 ULONG Data;
190
191 VideoBuffer = (WORD *)(0xd0000000 + 0xb8000);
192 // VideoBuffer = HalMapPhysicalMemory (0xb8000, 2);
193
194 /* Set cursor position */
195 // CursorX = LoaderBlock->cursorx;
196 // CursorY = LoaderBlock->cursory;
197 CursorX = 0;
198 CursorY = 0;
199
200 /* read screen size from the crtc */
201 /* FIXME: screen size should be read from the boot parameters */
202 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_COLUMNS);
203 SizeX = READ_PORT_UCHAR((PUCHAR)CRTC_DATA) + 1;
204 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_ROWS);
205 SizeY = READ_PORT_UCHAR((PUCHAR)CRTC_DATA);
206 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_OVERFLOW);
207 Data = READ_PORT_UCHAR((PUCHAR)CRTC_DATA);
208 SizeY |= (((Data & 0x02) << 7) | ((Data & 0x40) << 3));
209 SizeY++;
210 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_SCANLINES);
211 ScanLines = (READ_PORT_UCHAR((PUCHAR)CRTC_DATA) & 0x1F) + 1;
212 SizeY = SizeY / ScanLines;
213
214 #ifdef BOCHS_30ROWS
215 SizeY=30;
216 #endif
217 HalClearDisplay();
218
219 DisplayInitialized = TRUE;
220 }
221 }
222
223
224 /* PUBLIC FUNCTIONS *********************************************************/
225
226 VOID STDCALL
227 HalReleaseDisplayOwnership()
228 /*
229 * FUNCTION: Release ownership of display back to HAL
230 */
231 {
232 if (HalResetDisplayParameters == NULL)
233 return;
234
235 if (HalOwnsDisplay == TRUE)
236 return;
237
238 if (HalResetDisplayParameters(SizeX, SizeY) == TRUE)
239 {
240 HalOwnsDisplay = TRUE;
241 HalClearDisplay();
242 }
243 }
244
245
246 VOID STDCALL
247 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters)
248 /*
249 * FUNCTION:
250 * ARGUMENTS:
251 * ResetDisplayParameters = Pointer to a driver specific
252 * reset routine.
253 */
254 {
255 HalOwnsDisplay = FALSE;
256 HalResetDisplayParameters = ResetDisplayParameters;
257 }
258
259 VOID STDCALL
260 HalDisplayString(IN PCH String)
261 /*
262 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
263 * already and displays a string
264 * ARGUMENT:
265 * string = ASCII string to display
266 * NOTE: Use with care because there is no support for returning from BSOD
267 * mode
268 */
269 {
270 PCH pch;
271 #ifdef SCREEN_SYNCHRONIZATION
272 int offset;
273 #endif
274 static KSPIN_LOCK Lock;
275 ULONG Flags;
276
277 /* See comment at top of file */
278 if (! HalOwnsDisplay)
279 {
280 return;
281 }
282
283 pch = String;
284
285 pushfl(Flags);
286 __asm__ ("cli\n\t");
287 KeAcquireSpinLockAtDpcLevel(&Lock);
288
289 #if 0
290 if (HalOwnsDisplay == FALSE)
291 {
292 HalReleaseDisplayOwnership();
293 }
294 #endif
295
296 #ifdef SCREEN_SYNCHRONIZATION
297 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI);
298 offset = READ_PORT_UCHAR((PUCHAR)CRTC_DATA)<<8;
299 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO);
300 offset += READ_PORT_UCHAR((PUCHAR)CRTC_DATA);
301
302 CursorY = offset / SizeX;
303 CursorX = offset % SizeX;
304 #endif
305
306 while (*pch != 0)
307 {
308 if (*pch == '\n')
309 {
310 CursorY++;
311 CursorX = 0;
312 }
313 else if (*pch != '\r')
314 {
315 HalPutCharacter (*pch);
316 CursorX++;
317
318 if (CursorX >= SizeX)
319 {
320 CursorY++;
321 CursorX = 0;
322 }
323 }
324
325 if (CursorY >= SizeY)
326 {
327 HalScrollDisplay ();
328 CursorY = SizeY - 1;
329 }
330
331 pch++;
332 }
333
334 #ifdef SCREEN_SYNCHRONIZATION
335 offset = (CursorY * SizeX) + CursorX;
336
337 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURLO);
338 WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, offset & 0xff);
339 WRITE_PORT_UCHAR((PUCHAR)CRTC_COMMAND, CRTC_CURHI);
340 WRITE_PORT_UCHAR((PUCHAR)CRTC_DATA, (offset >> 8) & 0xff);
341 #endif
342 KeReleaseSpinLockFromDpcLevel(&Lock);
343 popfl(Flags);
344 }
345
346 VOID STDCALL
347 HalQueryDisplayParameters(OUT PULONG DispSizeX,
348 OUT PULONG DispSizeY,
349 OUT PULONG CursorPosX,
350 OUT PULONG CursorPosY)
351 {
352 if (DispSizeX)
353 *DispSizeX = SizeX;
354 if (DispSizeY)
355 *DispSizeY = SizeY;
356 if (CursorPosX)
357 *CursorPosX = CursorX;
358 if (CursorPosY)
359 *CursorPosY = CursorY;
360 }
361
362
363 VOID STDCALL
364 HalSetDisplayParameters(IN ULONG CursorPosX,
365 IN ULONG CursorPosY)
366 {
367 CursorX = (CursorPosX < SizeX) ? CursorPosX : SizeX - 1;
368 CursorY = (CursorPosY < SizeY) ? CursorPosY : SizeY - 1;
369 }
370
371 BOOLEAN STDCALL
372 HalQueryDisplayOwnership()
373 {
374 return ! HalOwnsDisplay;
375 }
376
377 /* EOF */