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