1/*
2 * Copyright 2004-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2008, Stephan A��mus <superstippi@gmx.de>
4 * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include <arch/cpu.h>
10#include <boot/stage2.h>
11#include <boot/platform.h>
12#include <boot/menu.h>
13#include <boot/kernel_args.h>
14#include <boot/platform/generic/video.h>
15#include <boot/images.h>
16
17#include <stdio.h>
18#include <stdlib.h>
19
20#include <zlib.h>
21
22
23//#define TRACE_VIDEO
24#ifdef TRACE_VIDEO
25#	define TRACE(x) dprintf x
26#else
27#	define TRACE(x) ;
28#endif
29
30
31static status_t
32uncompress(const uint8 compressed[], unsigned int compressedSize,
33	uint8* uncompressed, unsigned int uncompressedSize)
34{
35	if (compressedSize == 0 || uncompressedSize == 0)
36		return B_BAD_VALUE;
37
38	// prepare zlib stream
39	z_stream zStream = {
40		(Bytef*)compressed,		// next_in
41		compressedSize,			// avail_in
42		0,						// total_in
43		(Bytef*)uncompressed,	// next_out
44		uncompressedSize,		// avail_out
45		0,						// total_out
46		0,						// msg
47		0,						// state
48		Z_NULL,					// zalloc (kernel_args_malloc?)
49		Z_NULL,					// zfree (kernel_args_free?)
50		Z_NULL,					// opaque
51		0,						// data_type
52		0,						// adler
53		0						// reserved
54	};
55
56	int zlibError = inflateInit(&zStream);
57	if (zlibError != Z_OK)
58		return B_ERROR;	// TODO: translate zlibError
59
60	// inflate
61	status_t status = B_OK;
62	zlibError = inflate(&zStream, Z_FINISH);
63	if (zlibError != Z_STREAM_END) {
64		if (zlibError == Z_OK)
65			status = B_BUFFER_OVERFLOW;
66		else
67			status = B_ERROR;	// TODO: translate zlibError
68	}
69
70	// clean up
71	zlibError = inflateEnd(&zStream);
72	if (zlibError != Z_OK && status == B_OK)
73		status = B_ERROR;	// TODO: translate zlibError
74
75	if (status == B_OK && zStream.total_out != uncompressedSize)
76		status = B_ERROR;
77
78	return status;
79}
80
81
82extern "C" status_t
83video_display_splash(addr_t frameBuffer)
84{
85	if (!gKernelArgs.frame_buffer.enabled)
86		return B_NO_INIT;
87
88	addr_t pos = 0;
89	// Limit area to clear to estimated screen area
90	// UEFI can happily report a >256M framebuffer
91	addr_t size = min_c(gKernelArgs.frame_buffer.width
92			* gKernelArgs.frame_buffer.height * 4u,
93		gKernelArgs.frame_buffer.physical_buffer.size);
94
95	if (size >= 64) {
96		// Align writes
97		for (addr_t align = (8 - (frameBuffer & 7)) & 7; pos < align; pos++)
98			*(char*)(frameBuffer + pos) = 0;
99		// Write eight bytes, many many times, but not too many
100		for (addr_t alignSize = size - 8; pos < alignSize; pos +=8) {
101			*(uint32*)(frameBuffer + pos) = 0;
102			*(uint32*)(frameBuffer + pos + 4) = 0;
103		}
104	}
105	// Write a few bytes more
106	for (; pos < size; pos++)
107		*(char*)(frameBuffer + pos) = 0;
108
109	uint8* uncompressedLogo = NULL;
110	unsigned int uncompressedSize = kSplashLogoWidth * kSplashLogoHeight;
111	switch (gKernelArgs.frame_buffer.depth) {
112		case 8:
113			platform_set_palette(k8BitPalette);
114			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
115			if (uncompressedLogo == NULL)
116				return B_NO_MEMORY;
117
118			uncompress(kSplashLogo8BitCompressedImage,
119				sizeof(kSplashLogo8BitCompressedImage), uncompressedLogo,
120				uncompressedSize);
121		break;
122		default: // 24 bits is assumed here
123			uncompressedSize *= 3;
124			uncompressedLogo = (uint8*)kernel_args_malloc(uncompressedSize);
125			if (uncompressedLogo == NULL)
126				return B_NO_MEMORY;
127
128			uncompress(kSplashLogo24BitCompressedImage,
129				sizeof(kSplashLogo24BitCompressedImage), uncompressedLogo,
130				uncompressedSize);
131		break;
132	}
133
134	// TODO: support 4-bit indexed version of the images!
135
136	// render splash logo
137	uint16 iconsHalfHeight = kSplashIconsHeight / 2;
138
139	int width = min_c(kSplashLogoWidth, gKernelArgs.frame_buffer.width);
140	int height = min_c(kSplashLogoHeight + iconsHalfHeight,
141		gKernelArgs.frame_buffer.height);
142	int placementX = max_c(0, min_c(100, kSplashLogoPlacementX));
143	int placementY = max_c(0, min_c(100, kSplashLogoPlacementY));
144
145	int x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
146	int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100;
147
148	height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height);
149	switch (gKernelArgs.frame_buffer.depth) {
150		case 8:
151			break;
152	}
153	video_blit_image(frameBuffer, uncompressedLogo, width, height,
154		kSplashLogoWidth, x, y);
155
156	kernel_args_free(uncompressedLogo);
157
158	const uint8* lowerHalfIconImage;
159	uncompressedSize = kSplashIconsWidth * kSplashIconsHeight;
160	switch (gKernelArgs.frame_buffer.depth) {
161		case 8:
162			// pointer into the lower half of the icons image data
163			gKernelArgs.boot_splash
164				= (uint8*)kernel_args_malloc(uncompressedSize);
165			if (gKernelArgs.boot_splash == NULL)
166				return B_NO_MEMORY;
167			uncompress(kSplashIcons8BitCompressedImage,
168				sizeof(kSplashIcons8BitCompressedImage),
169				gKernelArgs.boot_splash, uncompressedSize);
170			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
171				+ (kSplashIconsWidth * iconsHalfHeight);
172		break;
173		default:	// 24bits is assumed here
174			uncompressedSize *= 3;
175			// pointer into the lower half of the icons image data
176			gKernelArgs.boot_splash
177				= (uint8*)kernel_args_malloc(uncompressedSize);
178			if (gKernelArgs.boot_splash == NULL)
179				return B_NO_MEMORY;
180			uncompress(kSplashIcons24BitCompressedImage,
181				sizeof(kSplashIcons24BitCompressedImage),
182				gKernelArgs.boot_splash, uncompressedSize);
183			lowerHalfIconImage = (uint8 *)gKernelArgs.boot_splash
184				+ (kSplashIconsWidth * iconsHalfHeight) * 3;
185		break;
186	}
187
188	// render initial (grayed out) icons
189	// the grayed out version is the lower half of the icons image
190
191	width = min_c(kSplashIconsWidth, gKernelArgs.frame_buffer.width);
192	height = min_c(kSplashLogoHeight + iconsHalfHeight,
193		gKernelArgs.frame_buffer.height);
194	placementX = max_c(0, min_c(100, kSplashIconsPlacementX));
195	placementY = max_c(0, min_c(100, kSplashIconsPlacementY));
196
197	x = (gKernelArgs.frame_buffer.width - width) * placementX / 100;
198	y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height)
199		* placementY / 100;
200
201	height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height);
202	video_blit_image(frameBuffer, lowerHalfIconImage, width, height,
203		kSplashIconsWidth, x, y);
204	return B_OK;
205}
206
207
208
209