~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/video.h>
 
20
#include <grub/types.h>
 
21
#include <grub/dl.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/mm.h>
 
24
 
 
25
/* The list of video adapters registered to system.  */
 
26
grub_video_adapter_t grub_video_adapter_list = NULL;
 
27
 
 
28
/* Active video adapter.  */
 
29
static grub_video_adapter_t grub_video_adapter_active;
 
30
 
 
31
/* Restore back to initial mode (where applicable).  */
 
32
grub_err_t
 
33
grub_video_restore (void)
 
34
{
 
35
  if (grub_video_adapter_active)
 
36
    {
 
37
      grub_video_adapter_active->fini ();
 
38
      if (grub_errno != GRUB_ERR_NONE)
 
39
        return grub_errno;
 
40
 
 
41
      grub_video_adapter_active = 0;
 
42
    }
 
43
  return GRUB_ERR_NONE;
 
44
}
 
45
 
 
46
/* Get information about active video mode.  */
 
47
grub_err_t
 
48
grub_video_get_info (struct grub_video_mode_info *mode_info)
 
49
{
 
50
  if (! grub_video_adapter_active)
 
51
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
52
 
 
53
  /* If mode_info is NULL just report that video adapter is active.  */
 
54
  if (! mode_info)
 
55
    {
 
56
      grub_errno = GRUB_ERR_NONE;
 
57
      return grub_errno;
 
58
    }
 
59
 
 
60
  return grub_video_adapter_active->get_info (mode_info);
 
61
}
 
62
 
 
63
grub_video_driver_id_t
 
64
grub_video_get_driver_id (void)
 
65
{
 
66
  if (! grub_video_adapter_active)
 
67
    return GRUB_VIDEO_DRIVER_NONE;
 
68
  return grub_video_adapter_active->id;
 
69
}
 
70
 
 
71
/* Get information about active video mode.  */
 
72
grub_err_t
 
73
grub_video_get_info_and_fini (struct grub_video_mode_info *mode_info,
 
74
                              void **framebuffer)
 
75
{
 
76
  grub_err_t err;
 
77
 
 
78
  if (! grub_video_adapter_active)
 
79
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
80
 
 
81
  err = grub_video_adapter_active->get_info_and_fini (mode_info, framebuffer);
 
82
  if (err)
 
83
    return err;
 
84
 
 
85
  grub_video_adapter_active = 0;
 
86
  return GRUB_ERR_NONE;
 
87
}
 
88
 
 
89
/* Determine optimized blitting formation for specified video mode info.  */
 
90
enum grub_video_blit_format
 
91
grub_video_get_blit_format (struct grub_video_mode_info *mode_info)
 
92
{
 
93
  /* Check if we have any known 32 bit modes.  */
 
94
  if (mode_info->bpp == 32)
 
95
    {
 
96
      if ((mode_info->red_mask_size == 8)
 
97
          && (mode_info->red_field_pos == 16)
 
98
          && (mode_info->green_mask_size == 8)
 
99
          && (mode_info->green_field_pos == 8)
 
100
          && (mode_info->blue_mask_size == 8)
 
101
          && (mode_info->blue_field_pos == 0))
 
102
        {
 
103
          return GRUB_VIDEO_BLIT_FORMAT_BGRA_8888;
 
104
        }
 
105
      else if ((mode_info->red_mask_size == 8)
 
106
               && (mode_info->red_field_pos == 0)
 
107
               && (mode_info->green_mask_size == 8)
 
108
               && (mode_info->green_field_pos == 8)
 
109
               && (mode_info->blue_mask_size == 8)
 
110
               && (mode_info->blue_field_pos == 16))
 
111
        {
 
112
          return GRUB_VIDEO_BLIT_FORMAT_RGBA_8888;
 
113
        }
 
114
    }
 
115
  /* Check if we have any known 24 bit modes.  */
 
116
  else if (mode_info->bpp == 24)
 
117
    {
 
118
      if ((mode_info->red_mask_size == 8)
 
119
          && (mode_info->red_field_pos == 16)
 
120
          && (mode_info->green_mask_size == 8)
 
121
          && (mode_info->green_field_pos == 8)
 
122
          && (mode_info->blue_mask_size == 8)
 
123
          && (mode_info->blue_field_pos == 0))
 
124
        {
 
125
          return GRUB_VIDEO_BLIT_FORMAT_BGR_888;
 
126
        }
 
127
      else if ((mode_info->red_mask_size == 8)
 
128
               && (mode_info->red_field_pos == 0)
 
129
               && (mode_info->green_mask_size == 8)
 
130
               && (mode_info->green_field_pos == 8)
 
131
               && (mode_info->blue_mask_size == 8)
 
132
               && (mode_info->blue_field_pos == 16))
 
133
        {
 
134
          return GRUB_VIDEO_BLIT_FORMAT_RGB_888;
 
135
        }
 
136
    }
 
137
  /* Check if we have any known 16 bit modes.  */
 
138
  else if (mode_info->bpp == 16)
 
139
    {
 
140
      if ((mode_info->red_mask_size == 5)
 
141
          && (mode_info->red_field_pos == 11)
 
142
          && (mode_info->green_mask_size == 6)
 
143
          && (mode_info->green_field_pos == 5)
 
144
          && (mode_info->blue_mask_size == 5)
 
145
          && (mode_info->blue_field_pos == 0))
 
146
        {
 
147
          return GRUB_VIDEO_BLIT_FORMAT_BGR_565;
 
148
        }
 
149
      else if ((mode_info->red_mask_size == 5)
 
150
               && (mode_info->red_field_pos == 0)
 
151
               && (mode_info->green_mask_size == 6)
 
152
               && (mode_info->green_field_pos == 5)
 
153
               && (mode_info->blue_mask_size == 5)
 
154
               && (mode_info->blue_field_pos == 11))
 
155
        {
 
156
          return GRUB_VIDEO_BLIT_FORMAT_RGB_565;
 
157
        }
 
158
    }
 
159
  else if (mode_info->bpp == 1)
 
160
    return GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED;
 
161
 
 
162
  /* Backup route.  Unknown format.  */
 
163
 
 
164
  /* If there are more than 8 bits per color, assume RGB(A) mode.  */
 
165
  if (mode_info->bpp > 8)
 
166
    {
 
167
      if (mode_info->reserved_mask_size > 0)
 
168
        {
 
169
          return GRUB_VIDEO_BLIT_FORMAT_RGBA;
 
170
        }
 
171
      else
 
172
        {
 
173
          return GRUB_VIDEO_BLIT_FORMAT_RGB;
 
174
        }
 
175
    }
 
176
 
 
177
  /* Assume as indexcolor mode.  */
 
178
  return GRUB_VIDEO_BLIT_FORMAT_INDEXCOLOR;
 
179
}
 
180
 
 
181
/* Set new indexed color palette entries.  */
 
182
grub_err_t
 
183
grub_video_set_palette (unsigned int start, unsigned int count,
 
184
                        struct grub_video_palette_data *palette_data)
 
185
{
 
186
  if (! grub_video_adapter_active)
 
187
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
188
 
 
189
  return grub_video_adapter_active->set_palette (start, count, palette_data);
 
190
}
 
191
 
 
192
/* Get indexed color palette entries.  */
 
193
grub_err_t
 
194
grub_video_get_palette (unsigned int start, unsigned int count,
 
195
                        struct grub_video_palette_data *palette_data)
 
196
{
 
197
  if (! grub_video_adapter_active)
 
198
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
199
 
 
200
  return grub_video_adapter_active->get_palette (start, count, palette_data);
 
201
}
 
202
 
 
203
/* Set viewport dimensions.  */
 
204
grub_err_t
 
205
grub_video_set_viewport (unsigned int x, unsigned int y,
 
206
                         unsigned int width, unsigned int height)
 
207
{
 
208
  if (! grub_video_adapter_active)
 
209
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
210
 
 
211
  return grub_video_adapter_active->set_viewport (x, y, width, height);
 
212
}
 
213
 
 
214
/* Get viewport dimensions.  */
 
215
grub_err_t
 
216
grub_video_get_viewport (unsigned int *x, unsigned int *y,
 
217
                         unsigned int *width, unsigned int *height)
 
218
{
 
219
  if (! grub_video_adapter_active)
 
220
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
221
 
 
222
  return grub_video_adapter_active->get_viewport (x, y, width, height);
 
223
}
 
224
 
 
225
/* Map color name to adapter specific color.  */
 
226
grub_video_color_t
 
227
grub_video_map_color (grub_uint32_t color_name)
 
228
{
 
229
  if (! grub_video_adapter_active)
 
230
    return 0;
 
231
 
 
232
  return grub_video_adapter_active->map_color (color_name);
 
233
}
 
234
 
 
235
/* Map RGB value to adapter specific color.  */
 
236
grub_video_color_t
 
237
grub_video_map_rgb (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue)
 
238
{
 
239
  if (! grub_video_adapter_active)
 
240
    return 0;
 
241
 
 
242
  return grub_video_adapter_active->map_rgb (red, green, blue);
 
243
}
 
244
 
 
245
/* Map RGBA value to adapter specific color.  */
 
246
grub_video_color_t
 
247
grub_video_map_rgba (grub_uint8_t red, grub_uint8_t green, grub_uint8_t blue,
 
248
                     grub_uint8_t alpha)
 
249
{
 
250
  if (! grub_video_adapter_active)
 
251
    return 0;
 
252
 
 
253
  return grub_video_adapter_active->map_rgba (red, green, blue, alpha);
 
254
}
 
255
 
 
256
/* Unmap video color back to RGBA components.  */
 
257
grub_err_t
 
258
grub_video_unmap_color (grub_video_color_t color, grub_uint8_t *red,
 
259
                        grub_uint8_t *green, grub_uint8_t *blue,
 
260
                        grub_uint8_t *alpha)
 
261
{
 
262
  if (! grub_video_adapter_active)
 
263
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
264
 
 
265
  return grub_video_adapter_active->unmap_color (color,
 
266
                                                 red,
 
267
                                                 green,
 
268
                                                 blue,
 
269
                                                 alpha);
 
270
}
 
271
 
 
272
/* Fill rectangle using specified color.  */
 
273
grub_err_t
 
274
grub_video_fill_rect (grub_video_color_t color, int x, int y,
 
275
                      unsigned int width, unsigned int height)
 
276
{
 
277
  if (! grub_video_adapter_active)
 
278
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
279
 
 
280
  return grub_video_adapter_active->fill_rect (color, x, y, width, height);
 
281
}
 
282
 
 
283
/* Blit bitmap to screen.  */
 
284
grub_err_t
 
285
grub_video_blit_bitmap (struct grub_video_bitmap *bitmap,
 
286
                        enum grub_video_blit_operators oper,
 
287
                        int x, int y, int offset_x, int offset_y,
 
288
                        unsigned int width, unsigned int height)
 
289
{
 
290
  if (! grub_video_adapter_active)
 
291
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
292
 
 
293
  return grub_video_adapter_active->blit_bitmap (bitmap, oper, x, y,
 
294
                                                 offset_x, offset_y,
 
295
                                                 width, height);
 
296
}
 
297
 
 
298
/* Blit render target to active render target.  */
 
299
grub_err_t
 
300
grub_video_blit_render_target (struct grub_video_render_target *target,
 
301
                               enum grub_video_blit_operators oper,
 
302
                               int x, int y, int offset_x, int offset_y,
 
303
                               unsigned int width, unsigned int height)
 
304
{
 
305
  if (! grub_video_adapter_active)
 
306
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
307
 
 
308
  return grub_video_adapter_active->blit_render_target (target, oper, x, y,
 
309
                                                        offset_x, offset_y,
 
310
                                                        width, height);
 
311
}
 
312
 
 
313
/* Scroll viewport and fill new areas with specified color.  */
 
314
grub_err_t
 
315
grub_video_scroll (grub_video_color_t color, int dx, int dy)
 
316
{
 
317
  if (! grub_video_adapter_active)
 
318
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
319
 
 
320
  return grub_video_adapter_active->scroll (color, dx, dy);
 
321
}
 
322
 
 
323
/* Swap buffers (swap active render target).  */
 
324
grub_err_t
 
325
grub_video_swap_buffers (void)
 
326
{
 
327
  if (! grub_video_adapter_active)
 
328
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
329
 
 
330
  return grub_video_adapter_active->swap_buffers ();
 
331
}
 
332
 
 
333
/* Create new render target.  */
 
334
grub_err_t
 
335
grub_video_create_render_target (struct grub_video_render_target **result,
 
336
                                 unsigned int width, unsigned int height,
 
337
                                 unsigned int mode_type)
 
338
{
 
339
  if (! grub_video_adapter_active)
 
340
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
341
 
 
342
  return grub_video_adapter_active->create_render_target (result,
 
343
                                                          width, height,
 
344
                                                          mode_type);
 
345
}
 
346
 
 
347
/* Delete render target.  */
 
348
grub_err_t
 
349
grub_video_delete_render_target (struct grub_video_render_target *target)
 
350
{
 
351
  if (! grub_video_adapter_active)
 
352
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
353
 
 
354
  return grub_video_adapter_active->delete_render_target (target);
 
355
}
 
356
 
 
357
/* Set active render target.  */
 
358
grub_err_t
 
359
grub_video_set_active_render_target (struct grub_video_render_target *target)
 
360
{
 
361
  if (! grub_video_adapter_active)
 
362
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
363
 
 
364
  return grub_video_adapter_active->set_active_render_target (target);
 
365
}
 
366
 
 
367
/* Get active render target.  */
 
368
grub_err_t
 
369
grub_video_get_active_render_target (struct grub_video_render_target **target)
 
370
{
 
371
  if (! grub_video_adapter_active)
 
372
    return grub_error (GRUB_ERR_BAD_DEVICE, "no video mode activated");
 
373
 
 
374
  return grub_video_adapter_active->get_active_render_target (target);
 
375
}
 
376
 
 
377
/* Parse <width>x<height>[x<depth>]*/
 
378
static grub_err_t
 
379
parse_modespec (const char *current_mode, int *width, int *height, int *depth)
 
380
{
 
381
  const char *value;
 
382
  const char *param = current_mode;
 
383
 
 
384
  *width = *height = *depth = -1;
 
385
 
 
386
  if (grub_strcmp (param, "auto") == 0)
 
387
    {
 
388
      *width = *height = 0;
 
389
      return GRUB_ERR_NONE;
 
390
    }
 
391
 
 
392
  /* Find width value.  */
 
393
  value = param;
 
394
  param = grub_strchr(param, 'x');
 
395
  if (param == NULL)
 
396
    return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
397
                       "Invalid mode: %s\n",
 
398
                       current_mode);
 
399
 
 
400
  param++;
 
401
  
 
402
  *width = grub_strtoul (value, 0, 0);
 
403
  if (grub_errno != GRUB_ERR_NONE)
 
404
      return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
405
                         "Invalid mode: %s\n",
 
406
                         current_mode);
 
407
  
 
408
  /* Find height value.  */
 
409
  value = param;
 
410
  param = grub_strchr(param, 'x');
 
411
  if (param == NULL)
 
412
    {
 
413
      *height = grub_strtoul (value, 0, 0);
 
414
      if (grub_errno != GRUB_ERR_NONE)
 
415
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
416
                           "Invalid mode: %s\n",
 
417
                           current_mode);
 
418
    }
 
419
  else
 
420
    {
 
421
      /* We have optional color depth value.  */
 
422
      param++;
 
423
      
 
424
      *height = grub_strtoul (value, 0, 0);
 
425
      if (grub_errno != GRUB_ERR_NONE)
 
426
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
427
                           "Invalid mode: %s\n",
 
428
                           current_mode);
 
429
      
 
430
      /* Convert color depth value.  */
 
431
      value = param;
 
432
      *depth = grub_strtoul (value, 0, 0);
 
433
      if (grub_errno != GRUB_ERR_NONE)
 
434
        return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
435
                           "Invalid mode: %s\n",
 
436
                           current_mode);
 
437
    }
 
438
  return GRUB_ERR_NONE;
 
439
}
 
440
 
 
441
grub_err_t
 
442
grub_video_set_mode (const char *modestring,
 
443
                     unsigned int modemask,
 
444
                     unsigned int modevalue)
 
445
{
 
446
  char *tmp;
 
447
  char *next_mode;
 
448
  char *current_mode;
 
449
  char *modevar;
 
450
 
 
451
  modevalue &= modemask;
 
452
 
 
453
  /* Take copy of env.var. as we don't want to modify that.  */
 
454
  modevar = grub_strdup (modestring);
 
455
 
 
456
  /* Initialize next mode.  */
 
457
  next_mode = modevar;
 
458
 
 
459
  if (! modevar)
 
460
    return grub_error (GRUB_ERR_OUT_OF_MEMORY,
 
461
                       "couldn't allocate space for local modevar copy");
 
462
 
 
463
  if (grub_memcmp (next_mode, "keep", sizeof ("keep")) == 0
 
464
      || grub_memcmp (next_mode, "keep,", sizeof ("keep,") - 1) == 0
 
465
      || grub_memcmp (next_mode, "keep;", sizeof ("keep;") - 1) == 0)
 
466
    {
 
467
      int suitable = 1;
 
468
      grub_err_t err;
 
469
 
 
470
      if (grub_video_adapter_active)
 
471
        {
 
472
          struct grub_video_mode_info mode_info;
 
473
          grub_memset (&mode_info, 0, sizeof (mode_info));
 
474
          err = grub_video_get_info (&mode_info);
 
475
          if (err)
 
476
            {
 
477
              suitable = 0;
 
478
              grub_errno = GRUB_ERR_NONE;
 
479
            }
 
480
          if ((mode_info.mode_type & modemask) != modevalue)
 
481
            suitable = 0;
 
482
        }
 
483
      else if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0)
 
484
               && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0))
 
485
        suitable = 0;
 
486
 
 
487
      if (suitable)
 
488
        {
 
489
          grub_free (modevar);
 
490
          return GRUB_ERR_NONE;
 
491
        }
 
492
      next_mode += sizeof ("keep") - 1;
 
493
      if (! *next_mode)
 
494
        {
 
495
          grub_free (modevar);
 
496
 
 
497
          return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
498
                             "no suitable mode found");
 
499
        }
 
500
 
 
501
      /* Skip separator. */
 
502
      next_mode++;
 
503
    }
 
504
 
 
505
  /* De-activate last set video adapter.  */
 
506
  if (grub_video_adapter_active)
 
507
    {
 
508
      /* Finalize adapter.  */
 
509
      grub_video_adapter_active->fini ();
 
510
      if (grub_errno != GRUB_ERR_NONE)
 
511
        grub_errno = GRUB_ERR_NONE;
 
512
 
 
513
      /* Mark active adapter as not set.  */
 
514
      grub_video_adapter_active = 0;
 
515
    }
 
516
 
 
517
  /* Loop until all modes has been tested out.  */
 
518
  while (next_mode != NULL)
 
519
    {
 
520
      int width = -1;
 
521
      int height = -1;
 
522
      int depth = -1;
 
523
      grub_err_t err;
 
524
      unsigned int flags = modevalue;
 
525
      unsigned int flagmask = modemask;
 
526
 
 
527
      /* Use last next_mode as current mode.  */
 
528
      tmp = next_mode;
 
529
 
 
530
      /* Save position of next mode and separate modes.  */
 
531
      for (; *next_mode; next_mode++)
 
532
        if (*next_mode == ',' || *next_mode == ';')
 
533
          break;
 
534
      if (*next_mode)
 
535
        {
 
536
          *next_mode = 0;
 
537
          next_mode++;
 
538
        }
 
539
      else
 
540
        next_mode = 0;
 
541
 
 
542
      /* Skip whitespace.  */
 
543
      while (grub_isspace (*tmp))
 
544
        tmp++;
 
545
 
 
546
      /* Initialize token holders.  */
 
547
      current_mode = tmp;
 
548
 
 
549
      /* XXX: we assume that we're in pure text mode if
 
550
         no video mode is initialized. Is it always true? */
 
551
      if (grub_strcmp (current_mode, "text") == 0)
 
552
        {
 
553
          struct grub_video_mode_info mode_info;
 
554
 
 
555
          grub_memset (&mode_info, 0, sizeof (mode_info));
 
556
          if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) == 0)
 
557
              || ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) != 0))
 
558
            {
 
559
              /* Valid mode found from adapter, and it has been activated.
 
560
                 Specify it as active adapter.  */
 
561
              grub_video_adapter_active = NULL;
 
562
 
 
563
              /* Free memory.  */
 
564
              grub_free (modevar);
 
565
 
 
566
              return GRUB_ERR_NONE;
 
567
            }
 
568
        }
 
569
 
 
570
      err = parse_modespec (current_mode, &width, &height, &depth);
 
571
      if (err)
 
572
        {
 
573
          /* Free memory before returning.  */
 
574
          grub_free (modevar);
 
575
 
 
576
          return err;
 
577
        }
 
578
 
 
579
      /* Try out video mode.  */
 
580
 
 
581
      /* If user requested specific depth check if this depth is supported.  */
 
582
      if (depth != -1 && (flagmask & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
 
583
          &&
 
584
          (((flags & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)
 
585
            != ((depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
 
586
                & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK))))
 
587
        continue;
 
588
 
 
589
      if (depth != -1)
 
590
        {
 
591
          flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
 
592
            & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
 
593
          flagmask |= GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
 
594
        }
 
595
 
 
596
      /* Try to initialize requested mode.  Ignore any errors.  */
 
597
      grub_video_adapter_t p;
 
598
 
 
599
      /* Loop thru all possible video adapter trying to find requested mode.  */
 
600
      for (p = grub_video_adapter_list; p; p = p->next)
 
601
        {
 
602
          struct grub_video_mode_info mode_info;
 
603
 
 
604
          grub_memset (&mode_info, 0, sizeof (mode_info));
 
605
 
 
606
          /* Try to initialize adapter, if it fails, skip to next adapter.  */
 
607
          err = p->init ();
 
608
          if (err != GRUB_ERR_NONE)
 
609
            {
 
610
              grub_errno = GRUB_ERR_NONE;
 
611
              continue;
 
612
            }
 
613
 
 
614
          /* Try to initialize video mode.  */
 
615
          err = p->setup (width, height, flags, flagmask);
 
616
          if (err != GRUB_ERR_NONE)
 
617
            {
 
618
              p->fini ();
 
619
              grub_errno = GRUB_ERR_NONE;
 
620
              continue;
 
621
            }
 
622
 
 
623
          err = p->get_info (&mode_info);
 
624
          if (err != GRUB_ERR_NONE)
 
625
            {
 
626
              p->fini ();
 
627
              grub_errno = GRUB_ERR_NONE;
 
628
              continue;
 
629
            }
 
630
 
 
631
          flags = mode_info.mode_type & ~GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
 
632
          flags |= (mode_info.bpp << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
 
633
            & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
 
634
 
 
635
          /* Check that mode is suitable for upper layer.  */
 
636
          if ((flags & GRUB_VIDEO_MODE_TYPE_PURE_TEXT)
 
637
              ? (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0)
 
638
                 && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0))
 
639
              : ((flags & modemask) != modevalue))
 
640
            {
 
641
              p->fini ();
 
642
              grub_errno = GRUB_ERR_NONE;
 
643
              continue;
 
644
            }
 
645
 
 
646
          /* Valid mode found from adapter, and it has been activated.
 
647
             Specify it as active adapter.  */
 
648
          grub_video_adapter_active = p;
 
649
 
 
650
          /* Free memory.  */
 
651
          grub_free (modevar);
 
652
 
 
653
          return GRUB_ERR_NONE;
 
654
        }
 
655
 
 
656
    }
 
657
 
 
658
  /* Free memory.  */
 
659
  grub_free (modevar);
 
660
 
 
661
  return grub_error (GRUB_ERR_BAD_ARGUMENT,
 
662
                     "no suitable mode found");
 
663
}
 
664
 
 
665
/* Initialize Video API module.  */
 
666
GRUB_MOD_INIT(video)
 
667
{
 
668
}
 
669
 
 
670
/* Finalize Video API module.  */
 
671
GRUB_MOD_FINI(video)
 
672
{
 
673
}