- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / hal / halx86 / xbox / display_xbox.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: hal/halx86/xbox/display_xbox.c
6 * PURPOSE: Blue screen display
7 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
8 * UPDATE HISTORY:
9 * Created 08/10/99
10 * Modified for Xbox 2004/12/02 GvG
11 */
12
13 /* For an explanation about display ownership see generic/display.c */
14
15 #include <halxbox.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 #define I2C_IO_BASE 0xc000
21
22 #define CONTROL_FRAMEBUFFER_ADDRESS_OFFSET 0x600800
23
24 #define MAKE_COLOR(Red, Green, Blue) (0xff000000 | (((Red) & 0xff) << 16) | (((Green) & 0xff) << 8) | ((Blue) & 0xff))
25
26 /* Default to grey on blue */
27 #define DEFAULT_FG_COLOR MAKE_COLOR(127, 127, 127)
28 #define DEFAULT_BG_COLOR MAKE_COLOR(0, 0, 127)
29
30 #define TAG_HALX TAG('H', 'A', 'L', 'X')
31
32 /* VARIABLES ****************************************************************/
33
34 static ULONG CursorX = 0; /* Cursor Position */
35 static ULONG CursorY = 0;
36 static ULONG SizeX; /* Display size (characters) */
37 static ULONG SizeY;
38
39 static BOOLEAN DisplayInitialized = FALSE;
40 static BOOLEAN HalOwnsDisplay = TRUE;
41
42 static PHAL_RESET_DISPLAY_PARAMETERS HalResetDisplayParameters = NULL;
43
44 #define CHAR_WIDTH 8
45 #define CHAR_HEIGHT 16
46
47 static PVOID FrameBuffer;
48 static ULONG BytesPerPixel;
49 static ULONG Delta;
50
51 /*
52 * It turns out that reading from the frame buffer is a pretty expensive
53 * operation. So, we're keeping shadow arrays of the contents and use
54 * those when needed (only for scrolling) instead of reading from the fb.
55 * This cuts down boot time from about 45 sec to about 6 sec.
56 */
57 static PUCHAR CellContents;
58 static PULONG CellFgColor;
59 static PULONG CellBgColor;
60
61 /* PRIVATE FUNCTIONS *********************************************************/
62
63 static VOID FASTCALL
64 HalpXboxOutputChar(UCHAR Char, unsigned X, unsigned Y, ULONG FgColor, ULONG BgColor)
65 {
66 PUCHAR FontPtr;
67 PULONG Pixel;
68 UCHAR Mask;
69 unsigned Line;
70 unsigned Col;
71
72 FontPtr = XboxFont8x16 + Char * 16;
73 Pixel = (PULONG) ((char *) FrameBuffer + Y * CHAR_HEIGHT * Delta
74 + X * CHAR_WIDTH * BytesPerPixel);
75 for (Line = 0; Line < CHAR_HEIGHT; Line++)
76 {
77 Mask = 0x80;
78 for (Col = 0; Col < CHAR_WIDTH; Col++)
79 {
80 Pixel[Col] = (0 != (FontPtr[Line] & Mask) ? FgColor : BgColor);
81 Mask = Mask >> 1;
82 }
83 Pixel = (PULONG) ((char *) Pixel + Delta);
84 }
85
86 if (NULL != CellContents)
87 {
88 CellContents[Y * SizeX + X] = Char;
89 CellFgColor[Y * SizeX + X] = FgColor;
90 CellBgColor[Y * SizeX + X] = BgColor;
91 }
92 }
93
94 static ULONG FASTCALL
95 HalpXboxAttrToSingleColor(UCHAR Attr)
96 {
97 UCHAR Intensity;
98
99 Intensity = (0 == (Attr & 0x08) ? 127 : 255);
100
101 return 0xff000000 |
102 (0 == (Attr & 0x04) ? 0 : (Intensity << 16)) |
103 (0 == (Attr & 0x02) ? 0 : (Intensity << 8)) |
104 (0 == (Attr & 0x01) ? 0 : Intensity);
105 }
106
107 static VOID FASTCALL
108 HalpXboxAttrToColors(UCHAR Attr, ULONG *FgColor, ULONG *BgColor)
109 {
110 *FgColor = HalpXboxAttrToSingleColor(Attr & 0xf);
111 *BgColor = HalpXboxAttrToSingleColor((Attr >> 4) & 0xf);
112 }
113
114 static VOID FASTCALL
115 HalpXboxClearScreenColor(ULONG Color)
116 {
117 ULONG Line, Col;
118 PULONG p;
119
120 for (Line = 0; Line < SizeY * CHAR_HEIGHT; Line++)
121 {
122 p = (PULONG) ((char *) FrameBuffer + Line * Delta);
123 for (Col = 0; Col < SizeX * CHAR_WIDTH; Col++)
124 {
125 *p++ = Color;
126 }
127 }
128
129 if (NULL != CellContents)
130 {
131 for (Line = 0; Line < SizeY; Line++)
132 {
133 for (Col = 0; Col < SizeX; Col++)
134 {
135 CellContents[Line * SizeX + Col] = ' ';
136 CellFgColor[Line * SizeX + Col] = Color;
137 CellBgColor[Line * SizeX + Col] = Color;
138 }
139 }
140 }
141 }
142
143 VOID FASTCALL
144 HalClearDisplay(UCHAR CharAttribute)
145 {
146 ULONG FgColor, BgColor;
147
148 HalpXboxAttrToColors(CharAttribute, &FgColor, &BgColor);
149
150 HalpXboxClearScreenColor(BgColor);
151
152 CursorX = 0;
153 CursorY = 0;
154 }
155
156 VOID static
157 HalScrollDisplay (VOID)
158 {
159 ULONG Line, Col;
160 PULONG p;
161
162 if (NULL == CellContents)
163 {
164 p = (PULONG) ((char *) FrameBuffer + (Delta * CHAR_HEIGHT));
165 RtlMoveMemory(FrameBuffer,
166 p,
167 (Delta * CHAR_HEIGHT) * (SizeY - 1));
168
169 for (Line = 0; Line < CHAR_HEIGHT; Line++)
170 {
171 p = (PULONG) ((char *) FrameBuffer + (CHAR_HEIGHT * (SizeY - 1 ) + Line) * Delta);
172 for (Col = 0; Col < SizeX * CHAR_WIDTH; Col++)
173 {
174 *p++ = DEFAULT_BG_COLOR;
175 }
176 }
177 }
178 else
179 {
180 for (Line = 0; Line < SizeY - 1; Line++)
181 {
182 for (Col = 0; Col < SizeX; Col++)
183 {
184 HalpXboxOutputChar(CellContents[(Line + 1) * SizeX + Col], Col, Line,
185 CellFgColor[(Line + 1) * SizeX + Col],
186 CellBgColor[(Line + 1) * SizeX + Col]);
187 }
188 }
189 for (Col = 0; Col < SizeX; Col++)
190 {
191 HalpXboxOutputChar(' ', Col, SizeY - 1, DEFAULT_FG_COLOR, DEFAULT_BG_COLOR);
192 }
193 }
194 }
195
196 static VOID FASTCALL
197 HalPutCharacter(UCHAR Character)
198 {
199 HalpXboxOutputChar(Character, CursorX, CursorY, DEFAULT_FG_COLOR, DEFAULT_BG_COLOR);
200 }
201
202 static BOOLEAN
203 ReadfromSMBus(UCHAR Address, UCHAR bRegister, UCHAR Size, ULONG *Data_to_smbus)
204 {
205 int nRetriesToLive=50;
206
207 while (0 != (READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0)) & 0x0800))
208 {
209 ; /* Franz's spin while bus busy with any master traffic */
210 }
211
212 while (0 != nRetriesToLive--)
213 {
214 UCHAR b;
215 int temp;
216
217 WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 4), (Address << 1) | 1);
218 WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 8), bRegister);
219
220 temp = READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0));
221 WRITE_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 0), temp); /* clear down all preexisting errors */
222
223 switch (Size)
224 {
225 case 4:
226 WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0d); /* DWORD modus ? */
227 break;
228 case 2:
229 WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0b); /* WORD modus */
230 break;
231 default:
232 WRITE_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 2), 0x0a); // BYTE
233 break;
234 }
235
236 b = 0;
237
238 while (0 == (b & 0x36))
239 {
240 b = READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 0));
241 }
242
243 if (0 != (b & 0x24))
244 {
245 /* printf("I2CTransmitByteGetReturn error %x\n", b); */
246 }
247
248 if(0 == (b & 0x10))
249 {
250 /* printf("I2CTransmitByteGetReturn no complete, retry\n"); */
251 }
252 else
253 {
254 switch (Size)
255 {
256 case 4:
257 READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 6));
258 READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
259 READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
260 READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
261 READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 9));
262 break;
263 case 2:
264 *Data_to_smbus = READ_PORT_USHORT((PUSHORT) (I2C_IO_BASE + 6));
265 break;
266 default:
267 *Data_to_smbus = READ_PORT_UCHAR((PUCHAR) (I2C_IO_BASE + 6));
268 break;
269 }
270
271
272 return TRUE;
273 }
274 }
275
276 return FALSE;
277 }
278
279
280 static BOOLEAN
281 I2CTransmitByteGetReturn(UCHAR bPicAddressI2cFormat, UCHAR bDataToWrite, ULONG *Return)
282 {
283 return ReadfromSMBus(bPicAddressI2cFormat, bDataToWrite, 1, Return);
284 }
285
286 VOID FASTCALL
287 HalInitializeDisplay (PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
288 /*
289 * FUNCTION: Initalize the display
290 * ARGUMENTS:
291 * InitParameters = Parameters setup by the boot loader
292 */
293 {
294 ULONG ScreenWidthPixels;
295 ULONG ScreenHeightPixels;
296 PHYSICAL_ADDRESS PhysControl;
297 PHYSICAL_ADDRESS PhysBuffer;
298 ULONG AvMode = 0;
299 PVOID ControlBuffer;
300
301 if (! DisplayInitialized)
302 {
303 PhysBuffer.u.HighPart = 0;
304 if (0 != (LoaderBlock->Flags & MB_FLAGS_MEM_INFO))
305 {
306 PhysBuffer.u.LowPart = (LoaderBlock->MemHigher + 1024) * 1024;
307 }
308 else
309 {
310 /* Assume a 64Mb Xbox, last 4MB for video buf */
311 PhysBuffer.u.LowPart = 60 * 1024 * 1024;
312 }
313 PhysBuffer.u.LowPart |= 0xf0000000;
314
315 /* Tell the nVidia controller about the framebuffer */
316 PhysControl.u.HighPart = 0;
317 PhysControl.u.LowPart = 0xfd000000;
318 ControlBuffer = MmMapIoSpace(PhysControl, 0x1000000, MmNonCached);
319 if (NULL == ControlBuffer)
320 {
321 return;
322 }
323 *((PULONG) ((char *) ControlBuffer + CONTROL_FRAMEBUFFER_ADDRESS_OFFSET)) = (ULONG) PhysBuffer.u.LowPart;
324 MmUnmapIoSpace(ControlBuffer, 0x1000000);
325
326 FrameBuffer = MmMapIoSpace(PhysBuffer, 4 * 1024 * 1024, MmNonCached);
327 if (NULL == FrameBuffer)
328 {
329 return;
330 }
331
332 if (I2CTransmitByteGetReturn(0x10, 0x04, &AvMode))
333 {
334 if (1 == AvMode) /* HDTV */
335 {
336 ScreenWidthPixels = 720;
337 }
338 else
339 {
340 /* FIXME Other possible values of AvMode:
341 * 0 - AV_SCART_RGB
342 * 2 - AV_VGA_SOG
343 * 4 - AV_SVIDEO
344 * 6 - AV_COMPOSITE
345 * 7 - AV_VGA
346 * other AV_COMPOSITE
347 */
348 ScreenWidthPixels = 640;
349 }
350 }
351 else
352 {
353 ScreenWidthPixels = 640;
354 }
355 ScreenHeightPixels = 480;
356 BytesPerPixel = 4;
357
358 SizeX = ScreenWidthPixels / CHAR_WIDTH;
359 SizeY = ScreenHeightPixels / CHAR_HEIGHT;
360 Delta = (ScreenWidthPixels * BytesPerPixel + 3) & ~ 0x3;
361
362 CellFgColor = (PULONG) ExAllocatePoolWithTag(PagedPool,
363 SizeX * SizeY * (sizeof(ULONG) + sizeof(ULONG) + sizeof(UCHAR)),
364 TAG_HALX);
365 if (NULL != CellFgColor)
366 {
367 CellBgColor = CellFgColor + SizeX * SizeY;
368 CellContents = (PUCHAR) (CellBgColor + SizeX * SizeY);
369 }
370 else
371 {
372 CellBgColor = NULL;
373 CellContents = NULL;
374 }
375
376 HalpXboxClearScreenColor(MAKE_COLOR(0, 0, 0));
377
378 DisplayInitialized = TRUE;
379 }
380 }
381
382
383 /* PUBLIC FUNCTIONS *********************************************************/
384
385 VOID STDCALL
386 HalReleaseDisplayOwnership(VOID)
387 /*
388 * FUNCTION: Release ownership of display back to HAL
389 */
390 {
391 if (HalOwnsDisplay || NULL == HalResetDisplayParameters)
392 {
393 return;
394 }
395
396 HalResetDisplayParameters(SizeX, SizeY);
397
398 HalOwnsDisplay = TRUE;
399 HalpXboxClearScreenColor(DEFAULT_BG_COLOR);
400
401 CursorX = 0;
402 CursorY = 0;
403 }
404
405
406 VOID STDCALL
407 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters)
408 /*
409 * FUNCTION:
410 * ARGUMENTS:
411 * ResetDisplayParameters = Pointer to a driver specific
412 * reset routine.
413 */
414 {
415 HalOwnsDisplay = FALSE;
416 HalResetDisplayParameters = ResetDisplayParameters;
417 }
418
419 VOID STDCALL
420 HalDisplayString(IN PCH String)
421 /*
422 * FUNCTION: Switches the screen to HAL console mode (BSOD) if not there
423 * already and displays a string
424 * ARGUMENT:
425 * string = ASCII string to display
426 * NOTE: Use with care because there is no support for returning from BSOD
427 * mode
428 */
429 {
430 PCH pch;
431 static KSPIN_LOCK Lock;
432 KIRQL OldIrql;
433 ULONG Flags;
434
435 if (! HalOwnsDisplay || ! DisplayInitialized)
436 {
437 return;
438 }
439
440 pch = String;
441
442 OldIrql = KfRaiseIrql(HIGH_LEVEL);
443 KiAcquireSpinLock(&Lock);
444
445 Ki386SaveFlags(Flags);
446 Ki386DisableInterrupts();
447
448 while (*pch != 0)
449 {
450 if (*pch == '\n')
451 {
452 CursorY++;
453 CursorX = 0;
454 }
455 else if (*pch == '\b')
456 {
457 if (CursorX > 0)
458 {
459 CursorX--;
460 }
461 }
462 else if (*pch != '\r')
463 {
464 HalPutCharacter(*pch);
465 CursorX++;
466
467 if (SizeX <= CursorX)
468 {
469 CursorY++;
470 CursorX = 0;
471 }
472 }
473
474 if (SizeY <= CursorY)
475 {
476 HalScrollDisplay ();
477 CursorY = SizeY - 1;
478 }
479
480 pch++;
481 }
482
483 Ki386RestoreFlags(Flags);
484
485 KiReleaseSpinLock(&Lock);
486 KfLowerIrql(OldIrql);
487 }
488
489 VOID STDCALL
490 HalQueryDisplayParameters(OUT PULONG DispSizeX,
491 OUT PULONG DispSizeY,
492 OUT PULONG CursorPosX,
493 OUT PULONG CursorPosY)
494 {
495 if (DispSizeX)
496 *DispSizeX = SizeX;
497 if (DispSizeY)
498 *DispSizeY = SizeY;
499 if (CursorPosX)
500 *CursorPosX = CursorX;
501 if (CursorPosY)
502 *CursorPosY = CursorY;
503 }
504
505
506 VOID STDCALL
507 HalSetDisplayParameters(IN ULONG CursorPosX,
508 IN ULONG CursorPosY)
509 {
510 CursorX = (CursorPosX < SizeX) ? CursorPosX : SizeX - 1;
511 CursorY = (CursorPosY < SizeY) ? CursorPosY : SizeY - 1;
512 }
513
514
515 BOOLEAN STDCALL
516 HalQueryDisplayOwnership(VOID)
517 {
518 return ! HalOwnsDisplay;
519 }
520
521 /* EOF */