]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/display.c
997de211b9b623ba177f90749bf90e4a13f356c8
[apple/bootx.git] / bootx.tproj / sl.subproj / display.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * display.c - Functions to manage and find display.
27 *
28 * Copyright (c) 1998-2002 Apple Computer, Inc.
29 *
30 * DRI: Josh de Cesare
31 */
32
33 #include <sl.h>
34
35 #include "clut.h"
36 #include "appleboot.h"
37 #include "failedboot.h"
38 #include "netboot.h"
39
40 struct DisplayInfo {
41 CICell screenPH;
42 CICell screenIH;
43 CICell address;
44 CICell width;
45 CICell height;
46 CICell depth;
47 CICell linebytes;
48 CICell triedToOpen;
49 };
50
51 typedef struct DisplayInfo DisplayInfo, *DisplayInfoPtr;
52
53
54 static long FindDisplays(void);
55 static long OpenDisplays(void);
56 static long OpenDisplay(long displayNum);
57 static long InitDisplay(long displayNum);
58 static long LookUpCLUTIndex(long index, long depth);
59
60 static long gNumDisplays;
61 static long gMainDisplayNum;
62 static DisplayInfo gDisplays[16];
63
64 static unsigned char *gAppleBoot;
65 static unsigned char *gNetBoot;
66 static unsigned char *gFailedBoot;
67
68 // Public Functions
69
70 long InitDisplays(void)
71 {
72 FindDisplays();
73 OpenDisplays();
74
75 return 0;
76 }
77
78
79 long DrawSplashScreen(long stage)
80 {
81 DisplayInfoPtr display;
82 short *appleBoot16, *netBoot16;
83 long *appleBoot32, *netBoot32;
84 long cnt, x, y, pixelSize;
85
86 if (gMainDisplayNum == -1) return 0;
87
88 display = &gDisplays[gMainDisplayNum];
89
90 switch (stage) {
91 case 0 :
92 // Make sure the boot display is marked.
93 SetProp(display->screenPH, "AAPL,boot-display", NULL, 0);
94
95 switch (display->depth) {
96 case 16 :
97 appleBoot16 =
98 AllocateBootXMemory(kAppleBootWidth * kAppleBootHeight * 2);
99 for (cnt = 0; cnt < (kAppleBootWidth * kAppleBootHeight); cnt++)
100 appleBoot16[cnt] = LookUpCLUTIndex(gAppleBootPict[cnt], 16);
101 gAppleBoot = (char *)appleBoot16;
102 break;
103
104 case 32 :
105 appleBoot32 =
106 AllocateBootXMemory(kAppleBootWidth * kAppleBootHeight * 4);
107 for (cnt = 0; cnt < (kAppleBootWidth * kAppleBootHeight); cnt++)
108 appleBoot32[cnt] = LookUpCLUTIndex(gAppleBootPict[cnt], 32);
109 gAppleBoot = (char *)appleBoot32;
110 break;
111
112 default :
113 gAppleBoot = (unsigned char *)gAppleBootPict;
114 break;
115 }
116
117 x = (display->width - kAppleBootWidth) / 2;
118 y = (display->height - kAppleBootHeight) / 2 + kAppleBootOffset;
119
120 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gAppleBoot,
121 x, y, kAppleBootWidth, kAppleBootHeight);
122
123 if (gBootFileType != kNetworkDeviceType) {
124 SpinInit(0, 0, NULL, 0, 0, 0, 0, 0, 0, 0);
125 } else {
126 switch (display->depth) {
127 case 16 :
128 pixelSize = 2;
129 netBoot16 =
130 AllocateBootXMemory(kNetBootWidth * kNetBootHeight * kNetBootFrames * 2);
131 for (cnt = 0; cnt < (kNetBootWidth * kNetBootHeight * kNetBootFrames); cnt++)
132 netBoot16[cnt] = LookUpCLUTIndex(gNetBootPict[cnt], 16);
133 gNetBoot = (char *)netBoot16;
134 break;
135
136 case 32 :
137 pixelSize = 4;
138 netBoot32 =
139 AllocateBootXMemory(kNetBootWidth * kNetBootHeight * kNetBootFrames * 4);
140 for (cnt = 0; cnt < (kNetBootWidth * kNetBootHeight * kNetBootFrames); cnt++)
141 netBoot32[cnt] = LookUpCLUTIndex(gNetBootPict[cnt], 32);
142 gNetBoot = (char *)netBoot32;
143 break;
144
145 default :
146 pixelSize = 1;
147 gNetBoot = (unsigned char *)gNetBootPict;
148 break;
149 }
150
151 x = (display->width - kNetBootWidth) / 2;
152 y = (display->height - kNetBootHeight) / 2 + kNetBootOffset;
153
154 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gNetBoot,
155 x, y, kNetBootWidth, kNetBootHeight);
156
157 // Set up the spin cursor.
158 SpinInit(display->screenIH, gNetBoot,
159 x, y,
160 kNetBootWidth, kNetBootHeight,
161 kNetBootFrames, kNetBootFPS, pixelSize, 0);
162 }
163 break;
164
165 case 1 :
166 x = (display->width - kAppleBootWidth) / 2;
167 y = (display->height - kAppleBootHeight) / 2 + kAppleBootOffset;
168
169 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gAppleBoot,
170 x, y, kAppleBootWidth, kAppleBootHeight);
171
172 if (gBootFileType == kNetworkDeviceType) {
173 x = (display->width - kNetBootWidth) / 2;
174 y = (display->height - kNetBootHeight) / 2 + kNetBootOffset;
175
176 // Erase the netboot picture with 75% grey.
177 CallMethod(5, 0, display->screenIH, "fill-rectangle",
178 LookUpCLUTIndex(0x01, display->depth),
179 x, y, kNetBootWidth, kNetBootHeight);
180 }
181 break;
182
183 default :
184 return -1;
185 break;
186 }
187
188 return 0;
189 }
190
191
192 long DrawFailedBootPicture(void)
193 {
194 long cnt;
195 short *failedBoot16;
196 long *failedBoot32, posX, posY;
197 DisplayInfoPtr display = &gDisplays[gMainDisplayNum];
198
199 switch (display->depth) {
200 case 16 :
201 failedBoot16 = AllocateBootXMemory(32 * 32 * 2);
202 for (cnt = 0; cnt < (32 * 32); cnt++)
203 failedBoot16[cnt] = LookUpCLUTIndex(gFailedBootPict[cnt], 16);
204 gFailedBoot = (char *)failedBoot16;
205 break;
206
207 case 32 :
208 failedBoot32 = AllocateBootXMemory(32 * 32 * 4);
209 for (cnt = 0; cnt < (32 * 32); cnt++)
210 failedBoot32[cnt] = LookUpCLUTIndex(gFailedBootPict[cnt], 32);
211 gFailedBoot = (char *)failedBoot32;
212 break;
213
214 default :
215 gFailedBoot = (unsigned char *)gFailedBootPict;
216 break;
217 }
218
219 // Erase the newboot picture with 75% grey.
220 posX = (display->width - kNetBootWidth) / 2;
221 posY = (display->height - kNetBootHeight) / 2 + kNetBootOffset;
222 CallMethod(5, 0, display->screenIH, "fill-rectangle",
223 LookUpCLUTIndex(0x01, display->depth),
224 posX, posY, kNetBootWidth, kNetBootHeight);
225
226 // Draw the failed boot picture.
227 posX = (display->width - kFailedBootWidth) / 2;
228 posY = ((display->height - kFailedBootHeight)) / 2 + kFailedBootOffset;
229 CallMethod(5, 0, display->screenIH, "draw-rectangle",
230 (long)gFailedBoot, posX, posY,
231 kFailedBootWidth, kFailedBootHeight);
232
233 return 0;
234 }
235
236
237 void GetMainScreenPH(Boot_Video_Ptr video)
238 {
239 DisplayInfoPtr display;
240 long address, size;
241
242 if (gMainDisplayNum == -1) {
243 // No display, set it to zero.
244 video->v_baseAddr = 0;
245 video->v_rowBytes = 0;
246 video->v_width = 0;
247 video->v_height = 0;
248 video->v_depth = 0;
249 } else {
250 display = &gDisplays[gMainDisplayNum];
251
252 video->v_baseAddr = display->address;
253 video->v_rowBytes = display->linebytes;
254 video->v_width = display->width;
255 video->v_height = display->height;
256 video->v_depth = display->depth;
257 }
258
259 // Allocate memory and a range for the CLUT.
260 size = 256 * 3;
261 address = AllocateKernelMemory(size);
262 AllocateMemoryRange("BootCLUT", address, size);
263 bcopy((char *)gClut, (char *)address, size);
264
265 // Allocate memory and a range for the failed boot picture.
266 size = 32 + kFailedBootWidth * kFailedBootHeight;
267 address = AllocateKernelMemory(size);
268 AllocateMemoryRange("Pict-FailedBoot", address, size);
269 ((long *)address)[0] = kFailedBootWidth;
270 ((long *)address)[1] = kFailedBootHeight;
271 ((long *)address)[2] = kFailedBootOffset;
272 bcopy((char *)gFailedBootPict, (char *)(address + 32), size - 32);
273 }
274
275
276 // Private Functions
277
278 static long FindDisplays(void)
279 {
280 CICell screenPH, controlPH;
281 long cnt;
282
283 // Find all the screens in the system.
284 screenPH = 0;
285 while (1) {
286 screenPH = SearchForNode(screenPH, 1, "device_type", "display");
287 if (screenPH != 0) gDisplays[gNumDisplays++].screenPH = screenPH;
288 else break;
289 }
290
291 // Find /chaos/control, and
292 // invalidate gStdOutPH if equal (since new OF was downloaded).
293 controlPH = FindDevice("/chaos/control");
294 if (gStdOutPH == controlPH) gStdOutPH = 0;
295
296 // Find the main screen using the screen alias or chaos/control.
297 gMainDisplayNum = -1;
298 screenPH = FindDevice("screen");
299 if (screenPH == -1) screenPH = controlPH;
300 for (cnt = 0; cnt < gNumDisplays; cnt++)
301 if (gDisplays[cnt].screenPH == screenPH) gMainDisplayNum = cnt;
302
303 return 0;
304 }
305
306
307 static long OpenDisplays(void)
308 {
309 long cnt;
310
311 // Open the main screen or
312 // look for a main screen if we don't have one.
313 if ((gMainDisplayNum == -1) || !OpenDisplay(gMainDisplayNum)) {
314 gMainDisplayNum = -1;
315 for (cnt = 0; cnt < gNumDisplays; cnt++) {
316 if (OpenDisplay(cnt)) {
317 gMainDisplayNum = cnt;
318 break;
319 }
320 }
321 }
322
323 // Open the rest of the displays
324 if (gOFVersion >= kOFVersion3x) {
325 for (cnt = 0; cnt < gNumDisplays; cnt++) {
326 OpenDisplay(cnt);
327 }
328 }
329
330 return 0;
331 }
332
333
334 static long OpenDisplay(long displayNum)
335 {
336 char screenPath[258], displayType[32];
337 CICell screenPH, screenIH;
338 long ret, size;
339
340 // Only try to open a screen once.
341 if (gDisplays[displayNum].triedToOpen) {
342 return gDisplays[displayNum].screenIH != 0;
343 } else {
344 gDisplays[displayNum].triedToOpen = -1;
345 }
346
347 screenPH = gDisplays[displayNum].screenPH;
348
349 // Try to use mac-boot's ihandle.
350 Interpret(0, 1, "\" _screen-ihandle\" $find if execute else 0 then",
351 &screenIH);
352 if ((screenIH != 0) && (InstanceToPackage(screenIH) != screenPH)) {
353 screenIH = 0;
354 }
355
356 // Try to use stdout as the screen's ihandle
357 if ((screenIH == 0) && (gStdOutPH == screenPH)) {
358 screenIH = gStdOutIH;
359 }
360
361 // Try to open the display.
362 if (screenIH == 0) {
363 screenPath[255] = '\0';
364 ret = PackageToPath(screenPH, screenPath, 255);
365 if (ret != -1) {
366 strcat(screenPath, ":0");
367 screenIH = Open(screenPath);
368 }
369 }
370
371 // Find out what type of display is attached.
372 size = GetProp(screenPH, "display-type", displayType, 31);
373 if (size != -1) {
374 displayType[size] = '\0';
375 // If the display-type is NONE, don't use the display.
376 if (!strcmp(displayType, "NONE")) screenIH = 0;
377 }
378
379 // Save the ihandle for later use.
380 gDisplays[displayNum].screenIH = screenIH;
381
382 // Initialize the display.
383 if (screenIH != 0) InitDisplay(displayNum);
384
385 return screenIH != 0;
386 }
387
388
389 static long InitDisplay(long displayNum)
390 {
391 DisplayInfoPtr display = &gDisplays[displayNum];
392 CICell screenPH = display->screenPH;
393 CICell screenIH = display->screenIH;
394
395 // Get the vital info for this screen.
396 GetProp(screenPH, "address", (char *)&(display->address), 4);
397 GetProp(screenPH, "width", (char *)&(display->width), 4);
398 GetProp(screenPH, "height", (char *)&(display->height), 4);
399 GetProp(screenPH, "depth", (char *)&(display->depth), 4);
400 GetProp(screenPH, "linebytes", (char *)&(display->linebytes), 4);
401
402 // Replace some of the drivers words.
403 Interpret(3, 1,
404 " value depthbytes"
405 " value rowbytes"
406 " to active-package"
407 " frame-buffer-adr value this-frame-buffer-adr"
408
409 " : rect-setup" // ( adr|index x y w h -- w adr|index xy-adr h )
410 " >r >r rowbytes * swap depthbytes * + this-frame-buffer-adr +"
411 " r> depthbytes * -rot r>"
412 " ;"
413
414 " : DRAW-RECTANGLE" // ( adr x y w h -- )
415 " rect-setup" // ( w adr xy-adr h )
416 " 0 ?do" // ( w adr xy-adr )
417 " 2dup 4 pick move"
418 " 2 pick rowbytes d+"
419 " loop"
420 " 3drop"
421 " ;"
422
423 " : FILL-RECTANGLE" // ( index x y w h -- )
424 " rect-setup rot depthbytes case"
425 " 1 of dup 8 << or dup 10 << or endof"
426 " 2 of dup 10 << or endof"
427 " endcase -rot 0 ?do"
428 " dup 3 pick 3 pick filll"
429 " rowbytes +"
430 " loop"
431 " 3drop"
432 " ;"
433
434 " : READ-RECTANGLE" // ( adr x y w h -- )
435 " rect-setup >r swap r> 0 ?do"
436 " 2dup 4 pick move"
437 " rowbytes 3 pick d+"
438 " loop"
439 " 3drop"
440 " ;"
441
442 " this-frame-buffer-adr"
443 " 0 to active-package"
444 , display->screenPH, display->linebytes,
445 display->depth / 8, &display->address);
446
447 // Set the CLUT for 8 bit displays.
448 if (display->depth == 8) {
449 CallMethod(3, 0, screenIH, "set-colors", (long)gClut, 0, 256);
450 }
451
452 // Set the screen to 75% grey.
453 CallMethod(5, 0, screenIH, "fill-rectangle",
454 LookUpCLUTIndex(0x01, display->depth),
455 0, 0, display->width, display->height);
456
457 return 0;
458 }
459
460
461 static long LookUpCLUTIndex(long index, long depth)
462 {
463 long result, red, green, blue;
464
465 red = gClut[index * 3 + 0];
466 green = gClut[index * 3 + 1];
467 blue = gClut[index * 3 + 2];
468
469 switch (depth) {
470 case 16 :
471 result = ((red & 0xF8) << 7)|((green & 0xF8) << 2)|((blue & 0xF8) >> 3);
472 break;
473
474 case 32 :
475 result = (red << 16) | (green << 8) | blue;
476 break;
477
478 default :
479 result = index;
480 break;
481 }
482
483 return result;
484 }
485
486
487 #if 0
488 static void DumpDisplaysInfo(void);
489
490 static void DumpDisplaysInfo(void)
491 {
492 long cnt, length;
493 char tmpStr[512];
494
495 printf("gNumDisplays: %x, gMainDisplayNum: %x\n",
496 gNumDisplays, gMainDisplayNum);
497
498 for (cnt = 0; cnt < gNumDisplays; cnt++) {
499 printf("Display: %x, screenPH: %x, screenIH: %x\n",
500 cnt, gDisplays[cnt].screenPH, gDisplays[cnt].screenIH);
501
502 if (gDisplays[cnt].screenPH) {
503 length = PackageToPath(gDisplays[cnt].screenPH, tmpStr, 511);
504 tmpStr[length] = '\0';
505 printf("PHandle Path: %s\n", tmpStr);
506 }
507
508 if (gDisplays[cnt].screenIH) {
509 length = InstanceToPath(gDisplays[cnt].screenIH, tmpStr, 511);
510 tmpStr[length] = '\0';
511 printf("IHandle Path: %s\n", tmpStr);
512 }
513
514 printf("address = %x\n", gDisplays[cnt].address);
515 printf("linebytes = %x\n", gDisplays[cnt].linebytes);
516 printf("width = %x\n", gDisplays[cnt].width);
517 printf("height = %x\n", gDisplays[cnt].height);
518 printf("depth = %x\n", gDisplays[cnt].depth);
519 printf("\n");
520 }
521 }
522 #endif