~ubuntu-branches/ubuntu/trusty/grub2/trusty-updates

« back to all changes in this revision

Viewing changes to grub-core/video/efi_gop.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-09-13 18:02:04 UTC
  • mfrom: (1.17.15 upstream)
  • mto: (17.6.27 experimental)
  • mto: This revision was merged to the branch mainline in revision 145.
  • Revision ID: package-import@ubuntu.com-20120913180204-mojnmocbimlom4im
Tags: upstream-2.00
ImportĀ upstreamĀ versionĀ 2.00

Show diffs side-by-side

added added

removed removed

Lines of Context:
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>
31
32
 
32
33
GRUB_MOD_LICENSE ("GPLv3+");
33
34
 
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;
 
43
 
 
44
static int
 
45
grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info));
38
46
 
39
47
static struct
40
48
{
41
49
  struct grub_video_mode_info mode_info;
42
50
  struct grub_video_render_target *render_target;
43
51
  grub_uint8_t *ptr;
 
52
  grub_uint8_t *offscreen;
44
53
} framebuffer;
45
54
 
46
55
 
47
56
static int
48
57
check_protocol (void)
49
58
{
50
 
  gop = grub_efi_locate_protocol (&graphics_output_guid, 0);
51
 
  if (gop)
 
59
  grub_efi_handle_t *handles;
 
60
  grub_efi_uintn_t num_handles, i;
 
61
  int have_usable_mode = 0;
 
62
 
 
63
  auto int hook (const struct grub_video_mode_info *info);
 
64
  int hook (const struct grub_video_mode_info *info __attribute__ ((unused)))
 
65
  {
 
66
    have_usable_mode = 1;
52
67
    return 1;
 
68
  }
 
69
 
 
70
  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL,
 
71
                                    &graphics_output_guid, NULL, &num_handles);
 
72
  if (!handles || num_handles == 0)
 
73
    return 0;
 
74
 
 
75
  for (i = 0; i < num_handles; i++)
 
76
    {
 
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);
 
81
      if (have_usable_mode)
 
82
        {
 
83
          grub_free (handles);
 
84
          return 1;
 
85
        }
 
86
    }
 
87
 
 
88
  gop = 0;
 
89
  gop_handle = 0;
53
90
 
54
91
  return 0;
55
92
}
69
106
      efi_call_2 (gop->set_mode, gop, old_mode);
70
107
      restore_needed = 0;
71
108
    }
 
109
  grub_free (framebuffer.offscreen);
 
110
  framebuffer.offscreen = 0;
72
111
  return grub_video_fb_fini ();
73
112
}
74
113
 
129
168
}
130
169
 
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)
135
174
{
136
175
  out->mode_number = mode;
137
176
  out->number_of_colors = 256;
187
226
  return GRUB_ERR_NONE;
188
227
}
189
228
 
 
229
static grub_err_t
 
230
grub_video_gop_fill_mode_info (unsigned mode,
 
231
                               struct grub_efi_gop_mode_info *in,
 
232
                               struct grub_video_mode_info *out)
 
233
{
 
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;
 
250
 
 
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);
 
254
 
 
255
  return GRUB_ERR_NONE;
 
256
}
 
257
 
190
258
static int
191
259
grub_video_gop_iterate (int (*hook) (const struct grub_video_mode_info *info))
192
260
{
221
289
}
222
290
 
223
291
static grub_err_t
 
292
grub_video_gop_get_edid (struct grub_video_edid_info *edid_info)
 
293
{
 
294
  struct grub_efi_active_edid *edid;
 
295
  grub_size_t copy_size;
 
296
 
 
297
  grub_memset (edid_info, 0, sizeof (*edid_info));
 
298
 
 
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);
 
304
 
 
305
  if (!edid || edid->size_of_edid == 0)
 
306
    {
 
307
      char edidname[] = "agp-internal-edid";
 
308
      grub_size_t datasize;
 
309
      grub_uint8_t *data;
 
310
      data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize);
 
311
      if (data && datasize > 16)
 
312
        {
 
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);
 
317
          grub_free (data);
 
318
          return GRUB_ERR_NONE;
 
319
        }
 
320
      return grub_error (GRUB_ERR_BAD_DEVICE, "EDID information not available");
 
321
    }
 
322
 
 
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);
 
327
 
 
328
  return GRUB_ERR_NONE;
 
329
}
 
330
 
 
331
static grub_err_t
 
332
grub_gop_get_preferred_mode (unsigned int *width, unsigned int *height)
 
333
{
 
334
  struct grub_video_edid_info edid_info;
 
335
  grub_err_t err;
 
336
 
 
337
  err = grub_video_gop_get_edid (&edid_info);
 
338
  if (err)
 
339
    return err;
 
340
  err = grub_video_edid_checksum (&edid_info);
 
341
  if (err)
 
342
    return err;
 
343
  err = grub_video_edid_preferred_mode (&edid_info, width, height);
 
344
  if (err)
 
345
    return err;
 
346
  return GRUB_ERR_NONE;
 
347
}
 
348
 
 
349
static grub_err_t
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)))
232
358
  unsigned bpp;
233
359
  int found = 0;
234
360
  unsigned long long best_volume = 0;
 
361
  unsigned int preferred_width = 0, preferred_height = 0;
 
362
  grub_uint8_t *buffer;
235
363
 
236
364
  depth = (mode_type & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
237
365
    >> GRUB_VIDEO_MODE_TYPE_DEPTH_POS;
238
366
 
 
367
  if (width == 0 && height == 0)
 
368
    {
 
369
      err = 1;
 
370
      grub_gop_get_preferred_mode (&preferred_width, &preferred_height);
 
371
      if (err || preferred_width >= 4096 || preferred_height >= 4096)
 
372
        {
 
373
          preferred_width = 800;
 
374
          preferred_height = 600;
 
375
          grub_errno = GRUB_ERR_NONE;
 
376
        }
 
377
    }
 
378
 
239
379
  /* Keep current mode if possible.  */
240
380
  if (gop->mode->info)
241
381
    {
270
410
          grub_dprintf ("video", "GOP: mode %d: %dx%d\n", mode, info->width,
271
411
                        info->height);
272
412
 
 
413
          if (preferred_width && (info->width > preferred_width
 
414
                                  || info->height > preferred_height))
 
415
            {
 
416
              grub_dprintf ("video", "GOP: mode %d: too large\n", mode);
 
417
              continue;
 
418
            }
 
419
 
273
420
          bpp = grub_video_gop_get_bpp (info);
274
421
          if (!bpp)
275
422
            {
328
475
    }
329
476
 
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));
331
482
 
 
483
  buffer = framebuffer.offscreen;
 
484
      
 
485
  if (!buffer)
 
486
    {
 
487
      grub_dprintf ("video", "GOP: couldn't allocate shadow\n");
 
488
      grub_errno = 0;
 
489
      err = grub_video_gop_fill_mode_info (gop->mode->mode, info,
 
490
                                           &framebuffer.mode_info);
 
491
      buffer = framebuffer.ptr;
 
492
    }
 
493
    
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);
335
497
 
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);
338
500
 
339
501
  if (err)
340
502
    {
364
526
static grub_err_t
365
527
grub_video_gop_swap_buffers (void)
366
528
{
367
 
  /* TODO: Implement buffer swapping.  */
 
529
  if (framebuffer.offscreen)
 
530
    {
 
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);
 
535
    }
368
536
  return GRUB_ERR_NONE;
369
537
}
370
538
 
381
549
grub_video_gop_get_info_and_fini (struct grub_video_mode_info *mode_info,
382
550
                                  void **framebuf)
383
551
{
384
 
  grub_memcpy (mode_info, &(framebuffer.mode_info), sizeof (*mode_info));
 
552
  grub_err_t err;
 
553
 
 
554
  err = grub_video_gop_fill_real_mode_info (gop->mode->mode, gop->mode->info,
 
555
                                            mode_info);
 
556
  if (err)
 
557
    {
 
558
      grub_dprintf ("video", "GOP: couldn't fill mode info\n");
 
559
      return err;
 
560
    }
 
561
 
385
562
  *framebuf = (char *) framebuffer.ptr;
386
563
 
387
564
  grub_video_fb_fini ();
388
565
 
 
566
  grub_free (framebuffer.offscreen);
 
567
  framebuffer.offscreen = 0;
 
568
 
389
569
  return GRUB_ERR_NONE;
390
570
}
391
571
 
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,