27
27
#include <grub/video_fb.h>
28
28
#include <grub/efi/api.h>
29
29
#include <grub/efi/efi.h>
30
#include <grub/efi/edid.h>
30
31
#include <grub/efi/graphics_output.h>
32
33
GRUB_MOD_LICENSE ("GPLv3+");
34
35
static grub_efi_guid_t graphics_output_guid = GRUB_EFI_GOP_GUID;
36
static grub_efi_guid_t active_edid_guid = GRUB_EFI_EDID_ACTIVE_GUID;
37
static grub_efi_guid_t discovered_edid_guid = GRUB_EFI_EDID_DISCOVERED_GUID;
38
static grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
35
39
static struct grub_efi_gop *gop;
36
40
static unsigned old_mode;
37
41
static int restore_needed;
42
static grub_efi_handle_t gop_handle;
45
grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info));
41
49
struct grub_video_mode_info mode_info;
42
50
struct grub_video_render_target *render_target;
52
grub_uint8_t *offscreen;
48
57
check_protocol (void)
50
gop = grub_efi_locate_protocol (&graphics_output_guid, 0);
59
grub_efi_handle_t *handles;
60
grub_efi_uintn_t num_handles, i;
61
int have_usable_mode = 0;
63
auto int hook (const struct grub_video_mode_info *info);
64
int hook (const struct grub_video_mode_info *info __attribute__ ((unused)))
70
handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
71
&graphics_output_guid, NULL, &num_handles);
72
if (!handles || num_handles == 0)
75
for (i = 0; i < num_handles; i++)
77
gop_handle = handles[i];
78
gop = grub_efi_open_protocol (gop_handle, &graphics_output_guid,
79
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
80
grub_video_gop_iterate (hook);
69
106
efi_call_2 (gop->set_mode, gop, old_mode);
70
107
restore_needed = 0;
109
grub_free (framebuffer.offscreen);
110
framebuffer.offscreen = 0;
72
111
return grub_video_fb_fini ();
131
170
static grub_err_t
132
grub_video_gop_fill_mode_info (unsigned mode,
133
struct grub_efi_gop_mode_info *in,
134
struct grub_video_mode_info *out)
171
grub_video_gop_fill_real_mode_info (unsigned mode,
172
struct grub_efi_gop_mode_info *in,
173
struct grub_video_mode_info *out)
136
175
out->mode_number = mode;
137
176
out->number_of_colors = 256;
187
226
return GRUB_ERR_NONE;
230
grub_video_gop_fill_mode_info (unsigned mode,
231
struct grub_efi_gop_mode_info *in,
232
struct grub_video_mode_info *out)
234
out->mode_number = mode;
235
out->number_of_colors = 256;
236
out->width = in->width;
237
out->height = in->height;
238
out->mode_type = GRUB_VIDEO_MODE_TYPE_RGB;
239
out->bytes_per_pixel = sizeof (struct grub_efi_gop_blt_pixel);
240
out->bpp = out->bytes_per_pixel << 3;
241
out->pitch = in->width * out->bytes_per_pixel;
242
out->red_mask_size = 8;
243
out->red_field_pos = 16;
244
out->green_mask_size = 8;
245
out->green_field_pos = 8;
246
out->blue_mask_size = 8;
247
out->blue_field_pos = 0;
248
out->reserved_mask_size = 8;
249
out->reserved_field_pos = 24;
251
out->blit_format = GRUB_VIDEO_BLIT_FORMAT_BGRA_8888;
252
out->mode_type |= (GRUB_VIDEO_MODE_TYPE_DOUBLE_BUFFERED
253
| GRUB_VIDEO_MODE_TYPE_UPDATING_SWAP);
255
return GRUB_ERR_NONE;
191
259
grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info))
223
291
static grub_err_t
292
grub_video_gop_get_edid (struct grub_video_edid_info *edid_info)
294
struct grub_efi_active_edid *edid;
295
grub_size_t copy_size;
297
grub_memset (edid_info, 0, sizeof (*edid_info));
299
edid = grub_efi_open_protocol (gop_handle, &active_edid_guid,
300
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
301
if (!edid || edid->size_of_edid == 0)
302
edid = grub_efi_open_protocol (gop_handle, &discovered_edid_guid,
303
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
305
if (!edid || edid->size_of_edid == 0)
307
char edidname[] = "agp-internal-edid";
308
grub_size_t datasize;
310
data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize);
311
if (data && datasize > 16)
313
copy_size = datasize - 16;
314
if (copy_size > sizeof (*edid_info))
315
copy_size = sizeof (*edid_info);
316
grub_memcpy (edid_info, data + 16, copy_size);
318
return GRUB_ERR_NONE;
320
return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available");
323
copy_size = edid->size_of_edid;
324
if (copy_size > sizeof (*edid_info))
325
copy_size = sizeof (*edid_info);
326
grub_memcpy (edid_info, edid->edid, copy_size);
328
return GRUB_ERR_NONE;
332
grub_gop_get_preferred_mode (unsigned int *width, unsigned int *height)
334
struct grub_video_edid_info edid_info;
337
err = grub_video_gop_get_edid (&edid_info);
340
err = grub_video_edid_checksum (&edid_info);
343
err = grub_video_edid_preferred_mode (&edid_info, width, height);
346
return GRUB_ERR_NONE;
224
350
grub_video_gop_setup (unsigned int width, unsigned int height,
225
351
unsigned int mode_type,
226
352
unsigned int mode_mask __attribute__ ((unused)))
234
360
unsigned long long best_volume = 0;
361
unsigned int preferred_width = 0, preferred_height = 0;
362
grub_uint8_t *buffer;
236
364
depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
237
365
>> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
367
if (width == 0 && height == 0)
370
grub_gop_get_preferred_mode (&preferred_width, &preferred_height);
371
if (err || preferred_width >= 4096 || preferred_height >= 4096)
373
preferred_width = 800;
374
preferred_height = 600;
375
grub_errno = GRUB_ERR_NONE;
239
379
/* Keep current mode if possible. */
240
380
if (gop->mode->info)
270
410
grub_dprintf ("video", "GOP: mode %d: %dx%d\n", mode, info->width,
413
if (preferred_width && (info->width > preferred_width
414
|| info->height > preferred_height))
416
grub_dprintf ("video", "GOP: mode %d: too large\n", mode);
273
420
bpp = grub_video_gop_get_bpp (info);
330
477
framebuffer.ptr = (void *) (grub_addr_t) gop->mode->fb_base;
478
framebuffer.offscreen
479
= grub_malloc (framebuffer.mode_info.height
480
* framebuffer.mode_info.width
481
* sizeof (struct grub_efi_gop_blt_pixel));
483
buffer = framebuffer.offscreen;
487
grub_dprintf ("video", "GOP: couldn't allocate shadow\n");
489
err = grub_video_gop_fill_mode_info (gop->mode->mode, info,
490
&framebuffer.mode_info);
491
buffer = framebuffer.ptr;
332
494
grub_dprintf ("video", "GOP: initialising FB @ %p %dx%dx%d\n",
333
495
framebuffer.ptr, framebuffer.mode_info.width,
334
496
framebuffer.mode_info.height, framebuffer.mode_info.bpp);
336
498
err = grub_video_fb_create_render_target_from_pointer
337
(&framebuffer.render_target, &framebuffer.mode_info, framebuffer.ptr);
499
(&framebuffer.render_target, &framebuffer.mode_info, buffer);
364
526
static grub_err_t
365
527
grub_video_gop_swap_buffers (void)
367
/* TODO: Implement buffer swapping. */
529
if (framebuffer.offscreen)
531
efi_call_10 (gop->blt, gop, framebuffer.offscreen,
532
GRUB_EFI_BLT_BUFFER_TO_VIDEO, 0, 0, 0, 0,
533
framebuffer.mode_info.width, framebuffer.mode_info.height,
534
framebuffer.mode_info.width * 4);
368
536
return GRUB_ERR_NONE;
381
549
grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info,
384
grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
554
err = grub_video_gop_fill_real_mode_info (gop->mode->mode, gop->mode->info,
558
grub_dprintf ("video", "GOP: couldn't fill mode info\n");
385
562
*framebuf = (char *) framebuffer.ptr;
387
564
grub_video_fb_fini ();
566
grub_free (framebuffer.offscreen);
567
framebuffer.offscreen = 0;
389
569
return GRUB_ERR_NONE;
401
581
.setup = grub_video_gop_setup,
402
582
.get_info = grub_video_fb_get_info,
403
583
.get_info_and_fini = grub_video_gop_get_info_and_fini,
584
.get_edid = grub_video_gop_get_edid,
404
585
.set_palette = grub_video_fb_set_palette,
405
586
.get_palette = grub_video_fb_get_palette,
406
587
.set_viewport = grub_video_fb_set_viewport,