]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/display.c
BootX-81.tar.gz
[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 #include <IOKit/IOHibernatePrivate.h>
32
33 #include "clut.h"
34 #include "appleboot.h"
35 #include "failedboot.h"
36 #include "netboot.h"
37
38 struct DisplayInfo {
39 CICell screenPH;
40 CICell screenIH;
41 CICell address;
42 CICell width;
43 CICell height;
44 CICell depth;
45 CICell linebytes;
46 CICell triedToOpen;
47 };
48
49 typedef struct DisplayInfo DisplayInfo, *DisplayInfoPtr;
50
51
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);
57
58 static long gNumDisplays;
59 static long gMainDisplayNum;
60 static DisplayInfo gDisplays[16];
61
62 static unsigned char *gAppleBoot;
63 static unsigned char *gNetBoot;
64 static unsigned char *gFailedBoot;
65
66 // Public Functions
67
68 long InitDisplays(int fill)
69 {
70 FindDisplays();
71 OpenDisplays(fill);
72
73 return 0;
74 }
75
76 void CloseDisplays(void)
77 {
78 int cnt;
79 for (cnt = 0; cnt < gNumDisplays; cnt++) {
80 if (gDisplays[cnt].screenIH)
81 Close(gDisplays[cnt].screenIH);
82 }
83 }
84
85 long DrawSplashScreen(long stage)
86 {
87 DisplayInfoPtr display;
88 short *appleBoot16, *netBoot16;
89 long *appleBoot32, *netBoot32;
90 long cnt, x, y, pixelSize;
91
92 if (gMainDisplayNum == -1) return 0;
93
94 display = &gDisplays[gMainDisplayNum];
95
96 switch (stage) {
97 case 0 :
98 // Make sure the boot display is marked.
99 SetProp(display->screenPH, "AAPL,boot-display", NULL, 0);
100
101 switch (display->depth) {
102 case 16 :
103 appleBoot16 =
104 AllocateBootXMemory(kAppleBootWidth * kAppleBootHeight * 2);
105 for (cnt = 0; cnt < (kAppleBootWidth * kAppleBootHeight); cnt++)
106 appleBoot16[cnt] = LookUpCLUTIndex(gAppleBootPict[cnt], 16);
107 gAppleBoot = (char *)appleBoot16;
108 break;
109
110 case 32 :
111 appleBoot32 =
112 AllocateBootXMemory(kAppleBootWidth * kAppleBootHeight * 4);
113 for (cnt = 0; cnt < (kAppleBootWidth * kAppleBootHeight); cnt++)
114 appleBoot32[cnt] = LookUpCLUTIndex(gAppleBootPict[cnt], 32);
115 gAppleBoot = (char *)appleBoot32;
116 break;
117
118 default :
119 gAppleBoot = (unsigned char *)gAppleBootPict;
120 break;
121 }
122
123 x = (display->width - kAppleBootWidth) / 2;
124 y = (display->height - kAppleBootHeight) / 2 + kAppleBootOffset;
125
126 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gAppleBoot,
127 x, y, kAppleBootWidth, kAppleBootHeight);
128
129 if (gBootFileType != kNetworkDeviceType) {
130 SpinInit(0, 0, NULL, 0, 0, 0, 0, 0, 0, 0);
131 } else {
132 switch (display->depth) {
133 case 16 :
134 pixelSize = 2;
135 netBoot16 =
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;
140 break;
141
142 case 32 :
143 pixelSize = 4;
144 netBoot32 =
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;
149 break;
150
151 default :
152 pixelSize = 1;
153 gNetBoot = (unsigned char *)gNetBootPict;
154 break;
155 }
156
157 x = (display->width - kNetBootWidth) / 2;
158 y = (display->height - kNetBootHeight) / 2 + kNetBootOffset;
159
160 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gNetBoot,
161 x, y, kNetBootWidth, kNetBootHeight);
162
163 // Set up the spin cursor.
164 SpinInit(display->screenIH, gNetBoot,
165 x, y,
166 kNetBootWidth, kNetBootHeight,
167 kNetBootFrames, kNetBootFPS, pixelSize, 0);
168 }
169 break;
170
171 case 1 :
172 x = (display->width - kAppleBootWidth) / 2;
173 y = (display->height - kAppleBootHeight) / 2 + kAppleBootOffset;
174
175 CallMethod(5, 0, display->screenIH, "draw-rectangle", (long)gAppleBoot,
176 x, y, kAppleBootWidth, kAppleBootHeight);
177
178 if (gBootFileType == kNetworkDeviceType) {
179 x = (display->width - kNetBootWidth) / 2;
180 y = (display->height - kNetBootHeight) / 2 + kNetBootOffset;
181
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);
186 }
187 break;
188
189 default :
190 return -1;
191 break;
192 }
193
194 return 0;
195 }
196
197 DECLARE_IOHIBERNATEPROGRESSALPHA
198
199 void SplashPreview(void *src, uint8_t * saveunder, uint32_t savelen)
200 {
201 DisplayInfoPtr display;
202 uint8_t * screen;
203 uint32_t rowBytes, pixelShift;
204 uint32_t x, y;
205 int32_t blob;
206 uint32_t alpha, in, color, result;
207 uint8_t * out;
208 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
209
210 if (InitDisplays(0) != 0) return;
211 if (gMainDisplayNum == -1) return;
212
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))
219 {
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);
224 DrawSplashScreen(0);
225 }
226
227 pixelShift = display->depth >> 4;
228 if (pixelShift < 1) return;
229
230 screen += ((display->width
231 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
232 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
233
234 for (y = 0; y < kIOHibernateProgressHeight; y++)
235 {
236 out = screen + y * rowBytes;
237 for (blob = 0; blob < kIOHibernateProgressCount; blob++)
238 {
239 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
240 for (x = 0; x < kIOHibernateProgressWidth; x++)
241 {
242 alpha = gIOHibernateProgressAlpha[y][x];
243 result = color;
244 if (alpha)
245 {
246 if (0xff != alpha)
247 {
248 if (1 == pixelShift)
249 {
250 in = *((uint16_t *)out) & 0x1f; // 16
251 in = (in << 3) | (in >> 2);
252 }
253 else
254 in = *((uint32_t *)out) & 0xff; // 32
255 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
256 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
257 }
258 if (1 == pixelShift)
259 {
260 result >>= 3;
261 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
262 }
263 else
264 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
265 }
266 out += (1 << pixelShift);
267 }
268 out += (kIOHibernateProgressSpacing << pixelShift);
269 }
270 }
271 }
272
273 void SplashProgress(uint8_t * saveunder, int32_t firstBlob, int32_t select)
274 {
275 DisplayInfoPtr display;
276 uint8_t * screen;
277 uint32_t rowBytes, pixelShift;
278 uint32_t x, y;
279 int32_t blob, lastBlob;
280 uint32_t alpha, in, color, result;
281 uint8_t * out;
282 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
283
284 if (gMainDisplayNum == -1) return;
285
286 display = &gDisplays[gMainDisplayNum];
287 pixelShift = display->depth >> 4;
288 if (pixelShift < 1) return;
289 screen = (uint8_t *) display->address;
290 rowBytes = display->linebytes;
291
292 screen += ((display->width
293 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
294 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
295
296 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
297
298 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
299
300 for (y = 0; y < kIOHibernateProgressHeight; y++)
301 {
302 out = screen + y * rowBytes;
303 for (blob = firstBlob; blob <= lastBlob; blob++)
304 {
305 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
306 for (x = 0; x < kIOHibernateProgressWidth; x++)
307 {
308 alpha = gIOHibernateProgressAlpha[y][x];
309 result = color;
310 if (alpha)
311 {
312 if (0xff != alpha)
313 {
314 in = saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++];
315 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
316 }
317 if (1 == pixelShift)
318 {
319 result >>= 3;
320 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
321 }
322 else
323 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
324 }
325 out += (1 << pixelShift);
326 }
327 out += (kIOHibernateProgressSpacing << pixelShift);
328 }
329 }
330 }
331
332 long DrawFailedBootPicture(void)
333 {
334 long cnt;
335 short *failedBoot16;
336 long *failedBoot32, posX, posY;
337 DisplayInfoPtr display = &gDisplays[gMainDisplayNum];
338
339 switch (display->depth) {
340 case 16 :
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;
345 break;
346
347 case 32 :
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;
352 break;
353
354 default :
355 gFailedBoot = (unsigned char *)gFailedBootPict;
356 break;
357 }
358
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);
365
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);
372
373 return 0;
374 }
375
376
377 void GetMainScreenPH(Boot_Video_Ptr video, int setProperties)
378 {
379 DisplayInfoPtr display;
380 long address, size;
381
382 if (gMainDisplayNum == -1) {
383 // No display, set it to zero.
384 video->v_baseAddr = 0;
385 video->v_rowBytes = 0;
386 video->v_width = 0;
387 video->v_height = 0;
388 video->v_depth = 0;
389 } else {
390 display = &gDisplays[gMainDisplayNum];
391
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;
397 }
398
399 if (!setProperties) return;
400
401 size = 256 * 3;
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);
406
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);
415 }
416
417
418 // Private Functions
419
420 static long FindDisplays(void)
421 {
422 CICell screenPH, controlPH;
423 long cnt;
424
425 // Find all the screens in the system.
426 screenPH = 0;
427 while (1) {
428 screenPH = SearchForNode(screenPH, 1, "device_type", "display");
429 if (screenPH != 0) gDisplays[gNumDisplays++].screenPH = screenPH;
430 else break;
431 }
432
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;
437
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;
445
446 return 0;
447 }
448
449
450 static long OpenDisplays(int fill)
451 {
452 long cnt;
453
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;
461 break;
462 }
463 }
464 }
465
466 // Open the rest of the displays
467 if (gOFVersion >= kOFVersion3x) {
468 for (cnt = 0; cnt < gNumDisplays; cnt++) {
469 OpenDisplay(cnt, 1);
470 }
471 }
472
473 return 0;
474 }
475
476
477 static long OpenDisplay(long displayNum, int fill)
478 {
479 char screenPath[258], displayType[32];
480 CICell screenPH, screenIH;
481 long ret, size;
482
483 // Only try to open a screen once.
484 if (gDisplays[displayNum].triedToOpen) {
485 return gDisplays[displayNum].screenIH != 0;
486 } else {
487 gDisplays[displayNum].triedToOpen = -1;
488 }
489
490 screenPH = gDisplays[displayNum].screenPH;
491
492 // Try to use mac-boot's ihandle.
493 Interpret(0, 1, "\" _screen-ihandle\" $find if execute else 0 then",
494 &screenIH);
495 if ((screenIH != 0) && (InstanceToPackage(screenIH) != screenPH)) {
496 screenIH = 0;
497 }
498
499 // Try to use stdout as the screen's ihandle
500 if ((screenIH == 0) && (gStdOutPH == screenPH)) {
501 screenIH = gStdOutIH;
502 }
503
504 // Try to open the display.
505 if (screenIH == 0) {
506 screenPath[255] = '\0';
507 ret = PackageToPath(screenPH, screenPath, 255);
508 if (ret != -1) {
509 strcat(screenPath, ":0");
510 screenIH = Open(screenPath);
511 }
512 }
513
514 // Find out what type of display is attached.
515 size = GetProp(screenPH, "display-type", displayType, 31);
516 if (size != -1) {
517 displayType[size] = '\0';
518 // If the display-type is NONE, don't use the display.
519 if (!strcmp(displayType, "NONE")) screenIH = 0;
520 }
521
522 // Save the ihandle for later use.
523 gDisplays[displayNum].screenIH = screenIH;
524
525 // Initialize the display.
526 if (screenIH != 0) InitDisplay(displayNum, fill);
527
528 return screenIH != 0;
529 }
530
531
532 static long InitDisplay(long displayNum, int fill)
533 {
534 DisplayInfoPtr display = &gDisplays[displayNum];
535 CICell screenPH = display->screenPH;
536 CICell screenIH = display->screenIH;
537
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);
544
545 // Replace some of the drivers words.
546 Interpret(3, 1,
547 " value depthbytes"
548 " value rowbytes"
549 " to active-package"
550 " frame-buffer-adr value this-frame-buffer-adr"
551
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>"
555 " ;"
556
557 " : DRAW-RECTANGLE" // ( adr x y w h -- )
558 " rect-setup" // ( w adr xy-adr h )
559 " 0 ?do" // ( w adr xy-adr )
560 " 2dup 4 pick move"
561 " 2 pick rowbytes d+"
562 " loop"
563 " 3drop"
564 " ;"
565
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"
572 " rowbytes +"
573 " loop"
574 " 3drop"
575 " ;"
576
577 " : READ-RECTANGLE" // ( adr x y w h -- )
578 " rect-setup >r swap r> 0 ?do"
579 " 2dup 4 pick move"
580 " rowbytes 3 pick d+"
581 " loop"
582 " 3drop"
583 " ;"
584
585 " this-frame-buffer-adr"
586 " 0 to active-package"
587 , display->screenPH, display->linebytes,
588 display->depth / 8, &display->address);
589
590 // Set the CLUT for 8 bit displays.
591 if (display->depth == 8) {
592 CallMethod(3, 0, screenIH, "set-colors", (long)gClut, 0, 256);
593 }
594
595 if (fill)
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);
600
601 return 0;
602 }
603
604
605 static long LookUpCLUTIndex(long index, long depth)
606 {
607 long result, red, green, blue;
608
609 red = gClut[index * 3 + 0];
610 green = gClut[index * 3 + 1];
611 blue = gClut[index * 3 + 2];
612
613 switch (depth) {
614 case 16 :
615 result = ((red & 0xF8) << 7)|((green & 0xF8) << 2)|((blue & 0xF8) >> 3);
616 break;
617
618 case 32 :
619 result = (red << 16) | (green << 8) | blue;
620 break;
621
622 default :
623 result = index;
624 break;
625 }
626
627 return result;
628 }
629
630
631 #if 0
632 static void DumpDisplaysInfo(void);
633
634 static void DumpDisplaysInfo(void)
635 {
636 long cnt, length;
637 char tmpStr[512];
638
639 printf("gNumDisplays: %x, gMainDisplayNum: %x\n",
640 gNumDisplays, gMainDisplayNum);
641
642 for (cnt = 0; cnt < gNumDisplays; cnt++) {
643 printf("Display: %x, screenPH: %x, screenIH: %x\n",
644 cnt, gDisplays[cnt].screenPH, gDisplays[cnt].screenIH);
645
646 if (gDisplays[cnt].screenPH) {
647 length = PackageToPath(gDisplays[cnt].screenPH, tmpStr, 511);
648 tmpStr[length] = '\0';
649 printf("PHandle Path: %s\n", tmpStr);
650 }
651
652 if (gDisplays[cnt].screenIH) {
653 length = InstanceToPath(gDisplays[cnt].screenIH, tmpStr, 511);
654 tmpStr[length] = '\0';
655 printf("IHandle Path: %s\n", tmpStr);
656 }
657
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);
663 printf("\n");
664 }
665 }
666 #endif