2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * display.c - Functions to manage and find display.
25 * Copyright (c) 1998-2002 Apple Computer, Inc.
31 #include <IOKit/IOHibernatePrivate.h>
34 #include "appleboot.h"
35 #include "failedboot.h"
49 typedef struct DisplayInfo DisplayInfo
, *DisplayInfoPtr
;
52 static long FindDisplays();
53 static long OpenDisplays(int fill
);
54 static long OpenDisplay(long displayNum
, int fill
);
55 static long InitDisplay(long displayNum
, int fill
);
56 static long LookUpCLUTIndex(long index
, long depth
);
58 static long gNumDisplays
;
59 static long gMainDisplayNum
;
60 static DisplayInfo gDisplays
[16];
62 static unsigned char *gAppleBoot
;
63 static unsigned char *gNetBoot
;
64 static unsigned char *gFailedBoot
;
68 long InitDisplays(int fill
)
76 void CloseDisplays(void)
79 for (cnt
= 0; cnt
< gNumDisplays
; cnt
++) {
80 if (gDisplays
[cnt
].screenIH
)
81 Close(gDisplays
[cnt
].screenIH
);
85 long DrawSplashScreen(long stage
)
87 DisplayInfoPtr display
;
88 short *appleBoot16
, *netBoot16
;
89 long *appleBoot32
, *netBoot32
;
90 long cnt
, x
, y
, pixelSize
;
92 if (gMainDisplayNum
== -1) return 0;
94 display
= &gDisplays
[gMainDisplayNum
];
98 // Make sure the boot display is marked.
99 SetProp(display
->screenPH
, "AAPL,boot-display", NULL
, 0);
101 switch (display
->depth
) {
104 AllocateBootXMemory(kAppleBootWidth
* kAppleBootHeight
* 2);
105 for (cnt
= 0; cnt
< (kAppleBootWidth
* kAppleBootHeight
); cnt
++)
106 appleBoot16
[cnt
] = LookUpCLUTIndex(gAppleBootPict
[cnt
], 16);
107 gAppleBoot
= (char *)appleBoot16
;
112 AllocateBootXMemory(kAppleBootWidth
* kAppleBootHeight
* 4);
113 for (cnt
= 0; cnt
< (kAppleBootWidth
* kAppleBootHeight
); cnt
++)
114 appleBoot32
[cnt
] = LookUpCLUTIndex(gAppleBootPict
[cnt
], 32);
115 gAppleBoot
= (char *)appleBoot32
;
119 gAppleBoot
= (unsigned char *)gAppleBootPict
;
123 x
= (display
->width
- kAppleBootWidth
) / 2;
124 y
= (display
->height
- kAppleBootHeight
) / 2 + kAppleBootOffset
;
126 CallMethod(5, 0, display
->screenIH
, "draw-rectangle", (long)gAppleBoot
,
127 x
, y
, kAppleBootWidth
, kAppleBootHeight
);
129 if (gBootFileType
!= kNetworkDeviceType
) {
130 SpinInit(0, 0, NULL
, 0, 0, 0, 0, 0, 0, 0);
132 switch (display
->depth
) {
136 AllocateBootXMemory(kNetBootWidth
* kNetBootHeight
* kNetBootFrames
* 2);
137 for (cnt
= 0; cnt
< (kNetBootWidth
* kNetBootHeight
* kNetBootFrames
); cnt
++)
138 netBoot16
[cnt
] = LookUpCLUTIndex(gNetBootPict
[cnt
], 16);
139 gNetBoot
= (char *)netBoot16
;
145 AllocateBootXMemory(kNetBootWidth
* kNetBootHeight
* kNetBootFrames
* 4);
146 for (cnt
= 0; cnt
< (kNetBootWidth
* kNetBootHeight
* kNetBootFrames
); cnt
++)
147 netBoot32
[cnt
] = LookUpCLUTIndex(gNetBootPict
[cnt
], 32);
148 gNetBoot
= (char *)netBoot32
;
153 gNetBoot
= (unsigned char *)gNetBootPict
;
157 x
= (display
->width
- kNetBootWidth
) / 2;
158 y
= (display
->height
- kNetBootHeight
) / 2 + kNetBootOffset
;
160 CallMethod(5, 0, display
->screenIH
, "draw-rectangle", (long)gNetBoot
,
161 x
, y
, kNetBootWidth
, kNetBootHeight
);
163 // Set up the spin cursor.
164 SpinInit(display
->screenIH
, gNetBoot
,
166 kNetBootWidth
, kNetBootHeight
,
167 kNetBootFrames
, kNetBootFPS
, pixelSize
, 0);
172 x
= (display
->width
- kAppleBootWidth
) / 2;
173 y
= (display
->height
- kAppleBootHeight
) / 2 + kAppleBootOffset
;
175 CallMethod(5, 0, display
->screenIH
, "draw-rectangle", (long)gAppleBoot
,
176 x
, y
, kAppleBootWidth
, kAppleBootHeight
);
178 if (gBootFileType
== kNetworkDeviceType
) {
179 x
= (display
->width
- kNetBootWidth
) / 2;
180 y
= (display
->height
- kNetBootHeight
) / 2 + kNetBootOffset
;
182 // Erase the netboot picture with 75% grey.
183 CallMethod(5, 0, display
->screenIH
, "fill-rectangle",
184 LookUpCLUTIndex(0x01, display
->depth
),
185 x
, y
, kNetBootWidth
, kNetBootHeight
);
197 DECLARE_IOHIBERNATEPROGRESSALPHA
199 void SplashPreview(void *src
, uint8_t * saveunder
, uint32_t savelen
)
201 DisplayInfoPtr display
;
203 uint32_t rowBytes
, pixelShift
;
206 uint32_t alpha
, in
, color
, result
;
208 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
210 if (InitDisplays(0) != 0) return;
211 if (gMainDisplayNum
== -1) return;
213 display
= &gDisplays
[gMainDisplayNum
];
214 screen
= (uint8_t *) display
->address
;
215 rowBytes
= display
->linebytes
;
216 if (!src
|| !DecompressData(src
, (void *) screen
,
217 display
->width
, display
->height
,
218 display
->depth
>> 3, rowBytes
))
220 // Set the screen to 75% grey.
221 CallMethod(5, 0, display
->screenIH
, "fill-rectangle",
222 LookUpCLUTIndex(0x01, display
->depth
),
223 0, 0, display
->width
, display
->height
);
227 pixelShift
= display
->depth
>> 4;
228 if (pixelShift
< 1) return;
230 screen
+= ((display
->width
231 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
232 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
234 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
236 out
= screen
+ y
* rowBytes
;
237 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
239 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
240 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
242 alpha
= gIOHibernateProgressAlpha
[y
][x
];
250 in
= *((uint16_t *)out
) & 0x1f; // 16
251 in
= (in
<< 3) | (in
>> 2);
254 in
= *((uint32_t *)out
) & 0xff; // 32
255 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
256 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
261 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
264 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
266 out
+= (1 << pixelShift
);
268 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
273 void SplashProgress(uint8_t * saveunder
, int32_t firstBlob
, int32_t select
)
275 DisplayInfoPtr display
;
277 uint32_t rowBytes
, pixelShift
;
279 int32_t blob
, lastBlob
;
280 uint32_t alpha
, in
, color
, result
;
282 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
284 if (gMainDisplayNum
== -1) return;
286 display
= &gDisplays
[gMainDisplayNum
];
287 pixelShift
= display
->depth
>> 4;
288 if (pixelShift
< 1) return;
289 screen
= (uint8_t *) display
->address
;
290 rowBytes
= display
->linebytes
;
292 screen
+= ((display
->width
293 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
294 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
296 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
298 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
300 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
302 out
= screen
+ y
* rowBytes
;
303 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
305 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
306 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
308 alpha
= gIOHibernateProgressAlpha
[y
][x
];
314 in
= saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++];
315 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
320 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
323 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
325 out
+= (1 << pixelShift
);
327 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
332 long DrawFailedBootPicture(void)
336 long *failedBoot32
, posX
, posY
;
337 DisplayInfoPtr display
= &gDisplays
[gMainDisplayNum
];
339 switch (display
->depth
) {
341 failedBoot16
= AllocateBootXMemory(32 * 32 * 2);
342 for (cnt
= 0; cnt
< (32 * 32); cnt
++)
343 failedBoot16
[cnt
] = LookUpCLUTIndex(gFailedBootPict
[cnt
], 16);
344 gFailedBoot
= (char *)failedBoot16
;
348 failedBoot32
= AllocateBootXMemory(32 * 32 * 4);
349 for (cnt
= 0; cnt
< (32 * 32); cnt
++)
350 failedBoot32
[cnt
] = LookUpCLUTIndex(gFailedBootPict
[cnt
], 32);
351 gFailedBoot
= (char *)failedBoot32
;
355 gFailedBoot
= (unsigned char *)gFailedBootPict
;
359 // Erase the newboot picture with 75% grey.
360 posX
= (display
->width
- kNetBootWidth
) / 2;
361 posY
= (display
->height
- kNetBootHeight
) / 2 + kNetBootOffset
;
362 CallMethod(5, 0, display
->screenIH
, "fill-rectangle",
363 LookUpCLUTIndex(0x01, display
->depth
),
364 posX
, posY
, kNetBootWidth
, kNetBootHeight
);
366 // Draw the failed boot picture.
367 posX
= (display
->width
- kFailedBootWidth
) / 2;
368 posY
= ((display
->height
- kFailedBootHeight
)) / 2 + kFailedBootOffset
;
369 CallMethod(5, 0, display
->screenIH
, "draw-rectangle",
370 (long)gFailedBoot
, posX
, posY
,
371 kFailedBootWidth
, kFailedBootHeight
);
377 void GetMainScreenPH(Boot_Video_Ptr video
, int setProperties
)
379 DisplayInfoPtr display
;
382 if (gMainDisplayNum
== -1) {
383 // No display, set it to zero.
384 video
->v_baseAddr
= 0;
385 video
->v_rowBytes
= 0;
390 display
= &gDisplays
[gMainDisplayNum
];
392 video
->v_baseAddr
= display
->address
;
393 video
->v_rowBytes
= display
->linebytes
;
394 video
->v_width
= display
->width
;
395 video
->v_height
= display
->height
;
396 video
->v_depth
= display
->depth
;
399 if (!setProperties
) return;
402 // Allocate memory and a range for the CLUT.
403 address
= AllocateKernelMemory(size
);
404 AllocateMemoryRange("BootCLUT", address
, size
);
405 bcopy((char *)gClut
, (char *)address
, size
);
407 // Allocate memory and a range for the failed boot picture.
408 size
= 32 + kFailedBootWidth
* kFailedBootHeight
;
409 address
= AllocateKernelMemory(size
);
410 AllocateMemoryRange("Pict-FailedBoot", address
, size
);
411 ((long *)address
)[0] = kFailedBootWidth
;
412 ((long *)address
)[1] = kFailedBootHeight
;
413 ((long *)address
)[2] = kFailedBootOffset
;
414 bcopy((char *)gFailedBootPict
, (char *)(address
+ 32), size
- 32);
420 static long FindDisplays(void)
422 CICell screenPH
, controlPH
;
425 // Find all the screens in the system.
428 screenPH
= SearchForNode(screenPH
, 1, "device_type", "display");
429 if (screenPH
!= 0) gDisplays
[gNumDisplays
++].screenPH
= screenPH
;
433 // Find /chaos/control, and
434 // invalidate gStdOutPH if equal (since new OF was downloaded).
435 controlPH
= FindDevice("/chaos/control");
436 if (gStdOutPH
== controlPH
) gStdOutPH
= 0;
438 // Find the main screen using the screen alias or chaos/control.
439 gMainDisplayNum
= -1;
440 screenPH
= FindDevice("screen");
441 gDisplays
[gNumDisplays
++].screenPH
= screenPH
;
442 if (screenPH
== -1) screenPH
= controlPH
;
443 for (cnt
= 0; cnt
< gNumDisplays
; cnt
++)
444 if (gDisplays
[cnt
].screenPH
== screenPH
) gMainDisplayNum
= cnt
;
450 static long OpenDisplays(int fill
)
454 // Open the main screen or
455 // look for a main screen if we don't have one.
456 if ((gMainDisplayNum
== -1) || !OpenDisplay(gMainDisplayNum
, fill
)) {
457 gMainDisplayNum
= -1;
458 for (cnt
= 0; cnt
< gNumDisplays
; cnt
++) {
459 if (OpenDisplay(cnt
, fill
)) {
460 gMainDisplayNum
= cnt
;
466 // Open the rest of the displays
467 if (gOFVersion
>= kOFVersion3x
) {
468 for (cnt
= 0; cnt
< gNumDisplays
; cnt
++) {
477 static long OpenDisplay(long displayNum
, int fill
)
479 char screenPath
[258], displayType
[32];
480 CICell screenPH
, screenIH
;
483 // Only try to open a screen once.
484 if (gDisplays
[displayNum
].triedToOpen
) {
485 return gDisplays
[displayNum
].screenIH
!= 0;
487 gDisplays
[displayNum
].triedToOpen
= -1;
490 screenPH
= gDisplays
[displayNum
].screenPH
;
492 // Try to use mac-boot's ihandle.
493 Interpret(0, 1, "\" _screen-ihandle\" $find if execute else 0 then",
495 if ((screenIH
!= 0) && (InstanceToPackage(screenIH
) != screenPH
)) {
499 // Try to use stdout as the screen's ihandle
500 if ((screenIH
== 0) && (gStdOutPH
== screenPH
)) {
501 screenIH
= gStdOutIH
;
504 // Try to open the display.
506 screenPath
[255] = '\0';
507 ret
= PackageToPath(screenPH
, screenPath
, 255);
509 strcat(screenPath
, ":0");
510 screenIH
= Open(screenPath
);
514 // Find out what type of display is attached.
515 size
= GetProp(screenPH
, "display-type", displayType
, 31);
517 displayType
[size
] = '\0';
518 // If the display-type is NONE, don't use the display.
519 if (!strcmp(displayType
, "NONE")) screenIH
= 0;
522 // Save the ihandle for later use.
523 gDisplays
[displayNum
].screenIH
= screenIH
;
525 // Initialize the display.
526 if (screenIH
!= 0) InitDisplay(displayNum
, fill
);
528 return screenIH
!= 0;
532 static long InitDisplay(long displayNum
, int fill
)
534 DisplayInfoPtr display
= &gDisplays
[displayNum
];
535 CICell screenPH
= display
->screenPH
;
536 CICell screenIH
= display
->screenIH
;
538 // Get the vital info for this screen.
539 GetProp(screenPH
, "address", (char *)&(display
->address
), 4);
540 GetProp(screenPH
, "width", (char *)&(display
->width
), 4);
541 GetProp(screenPH
, "height", (char *)&(display
->height
), 4);
542 GetProp(screenPH
, "depth", (char *)&(display
->depth
), 4);
543 GetProp(screenPH
, "linebytes", (char *)&(display
->linebytes
), 4);
545 // Replace some of the drivers words.
550 " frame-buffer-adr value this-frame-buffer-adr"
552 " : rect-setup" // ( adr|index x y w h -- w adr|index xy-adr h )
553 " >r >r rowbytes * swap depthbytes * + this-frame-buffer-adr +"
554 " r> depthbytes * -rot r>"
557 " : DRAW-RECTANGLE" // ( adr x y w h -- )
558 " rect-setup" // ( w adr xy-adr h )
559 " 0 ?do" // ( w adr xy-adr )
561 " 2 pick rowbytes d+"
566 " : FILL-RECTANGLE" // ( index x y w h -- )
567 " rect-setup rot depthbytes case"
568 " 1 of dup 8 << or dup 10 << or endof"
569 " 2 of dup 10 << or endof"
570 " endcase -rot 0 ?do"
571 " dup 3 pick 3 pick filll"
577 " : READ-RECTANGLE" // ( adr x y w h -- )
578 " rect-setup >r swap r> 0 ?do"
580 " rowbytes 3 pick d+"
585 " this-frame-buffer-adr"
586 " 0 to active-package"
587 , display
->screenPH
, display
->linebytes
,
588 display
->depth
/ 8, &display
->address
);
590 // Set the CLUT for 8 bit displays.
591 if (display
->depth
== 8) {
592 CallMethod(3, 0, screenIH
, "set-colors", (long)gClut
, 0, 256);
596 // Set the screen to 75% grey.
597 CallMethod(5, 0, screenIH
, "fill-rectangle",
598 LookUpCLUTIndex(0x01, display
->depth
),
599 0, 0, display
->width
, display
->height
);
605 static long LookUpCLUTIndex(long index
, long depth
)
607 long result
, red
, green
, blue
;
609 red
= gClut
[index
* 3 + 0];
610 green
= gClut
[index
* 3 + 1];
611 blue
= gClut
[index
* 3 + 2];
615 result
= ((red
& 0xF8) << 7)|((green
& 0xF8) << 2)|((blue
& 0xF8) >> 3);
619 result
= (red
<< 16) | (green
<< 8) | blue
;
632 static void DumpDisplaysInfo(void);
634 static void DumpDisplaysInfo(void)
639 printf("gNumDisplays: %x, gMainDisplayNum: %x\n",
640 gNumDisplays
, gMainDisplayNum
);
642 for (cnt
= 0; cnt
< gNumDisplays
; cnt
++) {
643 printf("Display: %x, screenPH: %x, screenIH: %x\n",
644 cnt
, gDisplays
[cnt
].screenPH
, gDisplays
[cnt
].screenIH
);
646 if (gDisplays
[cnt
].screenPH
) {
647 length
= PackageToPath(gDisplays
[cnt
].screenPH
, tmpStr
, 511);
648 tmpStr
[length
] = '\0';
649 printf("PHandle Path: %s\n", tmpStr
);
652 if (gDisplays
[cnt
].screenIH
) {
653 length
= InstanceToPath(gDisplays
[cnt
].screenIH
, tmpStr
, 511);
654 tmpStr
[length
] = '\0';
655 printf("IHandle Path: %s\n", tmpStr
);
658 printf("address = %x\n", gDisplays
[cnt
].address
);
659 printf("linebytes = %x\n", gDisplays
[cnt
].linebytes
);
660 printf("width = %x\n", gDisplays
[cnt
].width
);
661 printf("height = %x\n", gDisplays
[cnt
].height
);
662 printf("depth = %x\n", gDisplays
[cnt
].depth
);