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