71 |
grub_vbe_probe (struct grub_vbe_info_block *info_block) |
grub_vbe_probe (struct grub_vbe_info_block *info_block) |
72 |
{ |
{ |
73 |
struct grub_vbe_info_block *vbe_ib; |
struct grub_vbe_info_block *vbe_ib; |
74 |
grub_uint32_t rc; |
grub_vbe_status_t status; |
75 |
|
|
76 |
/* Clear caller's controller info block. */ |
/* Clear caller's controller info block. */ |
77 |
if (info_block != 0) |
if (info_block) |
78 |
{ |
grub_memset (info_block, 0, sizeof (*info_block)); |
|
grub_memset (info_block, 0, sizeof(struct grub_vbe_info_block)); |
|
|
} |
|
79 |
|
|
80 |
/* Do not probe more than one time. */ |
/* Do not probe more than one time, if not necessary. */ |
81 |
if (vbe_detected != -1) |
if (vbe_detected == -1 || info_block) |
82 |
{ |
{ |
83 |
if (vbe_detected == 1) |
/* Clear old copy of controller info block. */ |
84 |
{ |
grub_memset (&controller_info, 0, sizeof (controller_info)); |
85 |
/* Make copy of controller info block to caller. */ |
|
86 |
if (info_block != 0) |
/* Mark VESA BIOS extension as undetected. */ |
87 |
{ |
vbe_detected = 0; |
88 |
grub_memcpy (info_block, |
|
89 |
&controller_info, |
/* Use low memory scratch area as temporary storage |
90 |
sizeof(struct grub_vbe_info_block)); |
for VESA BIOS call. */ |
91 |
} |
vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; |
92 |
return GRUB_ERR_NONE; |
|
93 |
} |
/* Prepare info block. */ |
94 |
else |
grub_memset (vbe_ib, 0, sizeof (*vbe_ib)); |
95 |
|
|
96 |
|
vbe_ib->signature[0] = 'V'; |
97 |
|
vbe_ib->signature[1] = 'B'; |
98 |
|
vbe_ib->signature[2] = 'E'; |
99 |
|
vbe_ib->signature[3] = '2'; |
100 |
|
|
101 |
|
/* Try to get controller info block. */ |
102 |
|
status = grub_vbe_get_controller_info (vbe_ib); |
103 |
|
if (status == 0x004F) |
104 |
{ |
{ |
105 |
return GRUB_ERR_BAD_DEVICE; |
/* Copy it for later usage. */ |
106 |
|
grub_memcpy (&controller_info, vbe_ib, sizeof (controller_info)); |
107 |
|
|
108 |
|
/* Mark VESA BIOS extension as detected. */ |
109 |
|
vbe_detected = 1; |
110 |
} |
} |
111 |
} |
} |
112 |
|
|
113 |
/* Clear old copy of controller info block. */ |
if (! vbe_detected) |
114 |
grub_memset (&controller_info, 0, sizeof(struct grub_vbe_info_block)); |
return grub_error (GRUB_ERR_BAD_DEVICE, "VESA BIOS Extension not found"); |
|
|
|
|
/* Mark VESA BIOS extension as undetected. */ |
|
|
vbe_detected = 0; |
|
|
|
|
|
/* Use low memory scratch area as temporary storage for VESA BIOS call. */ |
|
|
vbe_ib = (struct grub_vbe_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; |
|
|
|
|
|
/* Prepare info block. */ |
|
|
grub_memset (vbe_ib, 0, sizeof(struct grub_vbe_info_block)); |
|
|
|
|
|
vbe_ib->signature[0] = 'V'; |
|
|
vbe_ib->signature[1] = 'B'; |
|
|
vbe_ib->signature[2] = 'E'; |
|
|
vbe_ib->signature[3] = '2'; |
|
|
|
|
|
/* Try to get controller info block. */ |
|
|
rc = grub_vbe_get_controller_info (vbe_ib); |
|
|
if (rc != 0x004F) |
|
|
{ |
|
|
return GRUB_ERR_BAD_DEVICE; |
|
|
} |
|
115 |
|
|
116 |
/* Copy it for later usage. */ |
/* Make copy of controller info block to caller. */ |
117 |
grub_memcpy (&controller_info, |
if (info_block) |
118 |
vbe_ib, |
grub_memcpy (info_block, &controller_info, sizeof (*info_block)); |
|
sizeof(struct grub_vbe_info_block)); |
|
|
|
|
|
/* Copy it for caller. */ |
|
|
grub_memcpy (info_block, |
|
|
vbe_ib, |
|
|
sizeof(struct grub_vbe_info_block)); |
|
|
|
|
|
/* Mark VESA BIOS extension as detected. */ |
|
|
vbe_detected = 1; |
|
119 |
|
|
120 |
return GRUB_ERR_NONE; |
return GRUB_ERR_NONE; |
121 |
} |
} |
124 |
grub_vbe_set_video_mode (grub_uint32_t mode, |
grub_vbe_set_video_mode (grub_uint32_t mode, |
125 |
struct grub_vbe_mode_info_block *mode_info) |
struct grub_vbe_mode_info_block *mode_info) |
126 |
{ |
{ |
127 |
grub_uint32_t rc; |
grub_vbe_status_t status; |
128 |
|
grub_uint32_t old_mode; |
129 |
/* If grub_vesafb_probe has not been called or no VBE, abort. */ |
|
130 |
if (vbe_detected == 0) |
/* Make sure that VBE is supported. */ |
131 |
{ |
if (grub_vbe_probe (0) != GRUB_ERR_NONE) |
132 |
return GRUB_ERR_BAD_DEVICE; |
return grub_errno; |
|
} |
|
133 |
|
|
134 |
/* Try to get mode info. */ |
/* Try to get mode info. */ |
135 |
rc = grub_vbe_get_video_mode_info (mode, &active_mode_info); |
if (grub_vbe_get_video_mode_info (mode, &active_mode_info) != GRUB_ERR_NONE) |
136 |
if (rc != GRUB_ERR_NONE) |
return grub_errno; |
|
{ |
|
|
return rc; |
|
|
} |
|
137 |
|
|
138 |
/* For all VESA BIOS modes, force linear frame buffer. */ |
/* For all VESA BIOS modes, force linear frame buffer. */ |
139 |
if (mode >= 0x100) |
if (mode >= 0x100) |
142 |
mode |= 1 << 14; |
mode |= 1 << 14; |
143 |
|
|
144 |
/* Determine frame buffer pixel format. */ |
/* Determine frame buffer pixel format. */ |
145 |
switch(active_mode_info.memory_model) |
switch (active_mode_info.memory_model) |
146 |
{ |
{ |
147 |
case 0x04: |
case 0x04: |
148 |
index_color_mode = 1; |
index_color_mode = 1; |
149 |
break; |
break; |
150 |
|
|
151 |
case 0x06: |
case 0x06: |
152 |
index_color_mode = 0; |
index_color_mode = 0; |
153 |
break; |
break; |
154 |
|
|
155 |
default: |
default: |
156 |
return GRUB_ERR_BAD_DEVICE; |
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, |
157 |
|
"unsupported pixel format 0x%x", |
158 |
|
active_mode_info.memory_model); |
159 |
} |
} |
160 |
} |
} |
161 |
|
|
162 |
|
/* Get current mode. */ |
163 |
|
if (grub_vbe_get_video_mode (&old_mode) != GRUB_ERR_NONE) |
164 |
|
return grub_errno; |
165 |
|
|
166 |
/* Try to set video mode. */ |
/* Try to set video mode. */ |
167 |
rc = grub_vbe_set_mode (mode, 0); |
status = grub_vbe_set_mode (mode, 0); |
168 |
if (rc != 0x004F) |
if (status != 0x004F) |
169 |
{ |
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot set VBE mode %x", mode); |
|
return GRUB_ERR_BAD_DEVICE; |
|
|
} |
|
170 |
|
|
171 |
/* Save information for later usage. */ |
/* Save information for later usage. */ |
172 |
active_mode = mode; |
active_mode = mode; |
174 |
if (mode < 0x100) |
if (mode < 0x100) |
175 |
{ |
{ |
176 |
/* If this is not a VESA mode, guess address. */ |
/* If this is not a VESA mode, guess address. */ |
177 |
framebuffer = (grub_uint8_t *)0xA0000; |
framebuffer = (grub_uint8_t *) 0xA0000; |
178 |
index_color_mode = 1; |
index_color_mode = 1; |
179 |
} |
} |
180 |
else |
else |
181 |
{ |
{ |
182 |
framebuffer = (grub_uint8_t *)active_mode_info.phys_base_addr; |
framebuffer = (grub_uint8_t *) active_mode_info.phys_base_addr; |
183 |
|
|
184 |
if (controller_info.version >= 0x300) |
if (controller_info.version >= 0x300) |
185 |
{ |
bytes_per_scan_line = active_mode_info.lin_bytes_per_scan_line; |
|
bytes_per_scan_line = active_mode_info.lin_bytes_per_scan_line; |
|
|
} |
|
186 |
else |
else |
187 |
{ |
bytes_per_scan_line = active_mode_info.bytes_per_scan_line; |
|
bytes_per_scan_line = active_mode_info.bytes_per_scan_line; |
|
|
} |
|
188 |
} |
} |
189 |
|
|
190 |
/* If video mode is in indexed color, setup default VGA palette. */ |
/* If video mode is in indexed color, setup default VGA palette. */ |
191 |
if (index_color_mode != 0) |
if (index_color_mode) |
192 |
{ |
{ |
193 |
rc = grub_vbe_set_palette_data (16, 0, vga_colors); |
struct grub_vbe_palette_data *palette |
194 |
if (rc != 0x004F) |
= (struct grub_vbe_palette_data *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; |
195 |
{ |
|
196 |
return GRUB_ERR_BAD_DEVICE; |
/* Make sure that the BIOS can reach the palette. */ |
197 |
} |
grub_memcpy (palette, vga_colors, sizeof (vga_colors)); |
198 |
|
status = grub_vbe_set_palette_data (16, 0, palette); |
199 |
|
|
200 |
|
/* For now, ignore the status. Not sure if this is fatal. */ |
201 |
|
#if 0 |
202 |
|
if (status != 0x004F) |
203 |
|
{ |
204 |
|
grub_vbe_set_mode (old_mode, 0); |
205 |
|
return grub_error (GRUB_ERR_BAD_DEVICE, |
206 |
|
"cannot set the default VGA palette"); |
207 |
|
} |
208 |
|
#endif |
209 |
} |
} |
210 |
|
|
211 |
/* Copy mode info for caller. */ |
/* Copy mode info for caller. */ |
212 |
if (mode_info != 0) |
if (mode_info) |
213 |
{ |
grub_memcpy (mode_info, &active_mode_info, sizeof (*mode_info)); |
|
grub_memcpy (mode_info, |
|
|
&active_mode_info, |
|
|
sizeof(struct grub_vbe_mode_info_block)); |
|
|
} |
|
214 |
|
|
215 |
return GRUB_ERR_NONE; |
return GRUB_ERR_NONE; |
216 |
} |
} |
218 |
grub_err_t |
grub_err_t |
219 |
grub_vbe_get_video_mode (grub_uint32_t *mode) |
grub_vbe_get_video_mode (grub_uint32_t *mode) |
220 |
{ |
{ |
221 |
grub_uint32_t rc; |
grub_vbe_status_t status; |
222 |
|
|
223 |
/* If grub_vesafb_probe has not been called or no VBE, abort. */ |
/* Make sure that VBE is supported. */ |
224 |
if (vbe_detected == 0) |
if (grub_vbe_probe (0) != GRUB_ERR_NONE) |
225 |
{ |
return grub_errno; |
|
return GRUB_ERR_BAD_DEVICE; |
|
|
} |
|
226 |
|
|
227 |
/* Try to query current mode from VESA BIOS. */ |
/* Try to query current mode from VESA BIOS. */ |
228 |
rc = grub_vbe_get_mode (mode); |
status = grub_vbe_get_mode (mode); |
229 |
if (rc != 0x004F) |
if (status != 0x004F) |
230 |
{ |
return grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current VBE mode"); |
|
return GRUB_ERR_BAD_DEVICE; |
|
|
} |
|
231 |
|
|
232 |
return GRUB_ERR_NONE; |
return GRUB_ERR_NONE; |
233 |
} |
} |
236 |
grub_vbe_get_video_mode_info (grub_uint32_t mode, |
grub_vbe_get_video_mode_info (grub_uint32_t mode, |
237 |
struct grub_vbe_mode_info_block *mode_info) |
struct grub_vbe_mode_info_block *mode_info) |
238 |
{ |
{ |
239 |
struct grub_vbe_mode_info_block *mi_tmp = (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; |
struct grub_vbe_mode_info_block *mi_tmp |
240 |
grub_uint32_t rc; |
= (struct grub_vbe_mode_info_block *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR; |
241 |
|
grub_vbe_status_t status; |
242 |
/* If grub_vesafb_probe has not been called or no VBE, abort. */ |
|
243 |
if (vbe_detected == 0) |
/* Make sure that VBE is supported. */ |
244 |
{ |
if (grub_vbe_probe (0) != GRUB_ERR_NONE) |
245 |
return GRUB_ERR_BAD_DEVICE; |
return grub_errno; |
|
} |
|
246 |
|
|
247 |
/* If mode is not VESA mode, skip mode info query. */ |
/* If mode is not VESA mode, skip mode info query. */ |
248 |
if (mode >= 0x100) |
if (mode >= 0x100) |
249 |
{ |
{ |
250 |
/* Try to get mode info from VESA BIOS. */ |
/* Try to get mode info from VESA BIOS. */ |
251 |
rc = grub_vbe_get_mode_info (mode, mi_tmp); |
status = grub_vbe_get_mode_info (mode, mi_tmp); |
252 |
if (rc != 0x004F) |
if (status != 0x004F) |
253 |
{ |
return grub_error (GRUB_ERR_BAD_DEVICE, |
254 |
return GRUB_ERR_BAD_DEVICE; |
"cannot get information on the mode %x", mode); |
|
} |
|
255 |
|
|
256 |
/* Make copy of mode info block. */ |
/* Make copy of mode info block. */ |
257 |
grub_memcpy (mode_info, |
grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info)); |
|
mi_tmp, |
|
|
sizeof(struct grub_vbe_mode_info_block)); |
|
258 |
} |
} |
259 |
else |
else |
260 |
{ |
/* Just clear mode info block if it isn't a VESA mode. */ |
261 |
/* Just clear mode info block if it isn't a VESA mode. */ |
grub_memset (mode_info, 0, sizeof (*mode_info)); |
|
grub_memset (mode_info, |
|
|
0, |
|
|
sizeof(struct grub_vbe_mode_info_block)); |
|
|
} |
|
262 |
|
|
263 |
return GRUB_ERR_NONE; |
return GRUB_ERR_NONE; |
264 |
} |
} |
299 |
value |= blue << active_mode_info.blue_field_position; |
value |= blue << active_mode_info.blue_field_position; |
300 |
} |
} |
301 |
|
|
302 |
if (active_mode_info.bits_per_pixel == 32) |
switch (active_mode_info.bits_per_pixel) |
303 |
{ |
{ |
304 |
grub_uint32_t *ptr = (grub_uint32_t *)(framebuffer |
case 32: |
305 |
+ y * bytes_per_scan_line |
{ |
306 |
+ x * 4); |
grub_uint32_t *ptr = (grub_uint32_t *) (framebuffer |
307 |
|
+ y * bytes_per_scan_line |
308 |
|
+ x * 4); |
309 |
|
|
310 |
|
*ptr = value; |
311 |
|
} |
312 |
|
break; |
313 |
|
|
314 |
|
case 24: |
315 |
|
{ |
316 |
|
grub_uint8_t *ptr = (grub_uint8_t *) (framebuffer |
317 |
|
+ y * bytes_per_scan_line |
318 |
|
+ x * 3); |
319 |
|
grub_uint8_t *ptr2 = (grub_uint8_t *) &value; |
320 |
|
|
321 |
|
ptr[0] = ptr2[0]; |
322 |
|
ptr[1] = ptr2[1]; |
323 |
|
ptr[2] = ptr2[2]; |
324 |
|
} |
325 |
|
break; |
326 |
|
|
327 |
|
case 16: |
328 |
|
case 15: |
329 |
|
{ |
330 |
|
grub_uint16_t *ptr = (grub_uint16_t *) (framebuffer |
331 |
|
+ y * bytes_per_scan_line |
332 |
|
+ x * 2); |
333 |
|
|
334 |
|
*ptr = (grub_uint16_t) (value & 0xFFFF); |
335 |
|
} |
336 |
|
break; |
337 |
|
|
338 |
*ptr = value; |
default: |
339 |
} |
break; |
|
else if (active_mode_info.bits_per_pixel == 24) |
|
|
{ |
|
|
grub_uint8_t *ptr = (grub_uint8_t *)(framebuffer |
|
|
+ y * bytes_per_scan_line |
|
|
+ x * 3); |
|
|
grub_uint8_t *ptr2 = (grub_uint8_t *)&value; |
|
|
|
|
|
ptr[0] = ptr2[0]; |
|
|
ptr[1] = ptr2[1]; |
|
|
ptr[2] = ptr2[2]; |
|
|
} |
|
|
else if ((active_mode_info.bits_per_pixel == 16) || |
|
|
(active_mode_info.bits_per_pixel == 15)) |
|
|
{ |
|
|
grub_uint16_t *ptr = (grub_uint16_t *)(framebuffer |
|
|
+ y * bytes_per_scan_line |
|
|
+ x * 2); |
|
|
|
|
|
*ptr = (grub_uint16_t)(value & 0xFFFF); |
|
340 |
} |
} |
341 |
} |
} |
342 |
|
|
353 |
|
|
354 |
if (index_color_mode == 1) |
if (index_color_mode == 1) |
355 |
{ |
{ |
356 |
grub_uint8_t *ptr = (grub_uint8_t *)(framebuffer |
grub_uint8_t *ptr = (grub_uint8_t *) (framebuffer |
357 |
+ y * bytes_per_scan_line |
+ y * bytes_per_scan_line |
358 |
+ x); |
+ x); |
359 |
|
|
360 |
*ptr = color; |
*ptr = color; |
361 |
} |
} |
362 |
else |
else |
363 |
{ |
{ |
364 |
color &= 0x0F; |
color &= 0x0F; |
365 |
|
|
366 |
if (color < 16) |
if (color < 16) |
367 |
{ |
{ |
368 |
grub_vbe_set_pixel_rgb (x, |
grub_vbe_set_pixel_rgb (x, |
379 |
0, |
0, |
380 |
0); |
0); |
381 |
} |
} |
382 |
} |
} |
383 |
} |
} |