diff --git a/ChangeLog.videomask b/ChangeLog.videomask new file mode 100644 index 000000000..7c58d0b57 --- /dev/null +++ b/ChangeLog.videomask @@ -0,0 +1,10 @@ +2009-11-20 Vladimir Serbinenko + + Use flag-based instead of hook-based video mode selection and "auto" + keyword. + + * include/grub/video.h (grub_video_adapter): Changed 'setup' member. + (grub_video_set_mode): Changed prototype. All users updated. + (grub_video_check_mode_flag): New inline function. + * video/video.c (parse_modespec): New function. + (grub_video_set_mode): Parse flags and keywords. diff --git a/commands/videotest.c b/commands/videotest.c index 850639bd9..1730a2031 100644 --- a/commands/videotest.c +++ b/commands/videotest.c @@ -31,9 +31,7 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - if (grub_video_set_mode ("1024x768;800x600;640x480", 0) != GRUB_ERR_NONE) - return grub_errno; - + grub_err_t err; grub_video_color_t color; unsigned int x; unsigned int y; @@ -50,6 +48,10 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), const char *str; int texty; + err = grub_video_set_mode ("auto", GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); + if (err) + return err; + grub_video_get_viewport (&x, &y, &width, &height); grub_video_create_render_target (&text_layer, width, height, @@ -153,12 +155,13 @@ grub_cmd_videotest (grub_command_t cmd __attribute__ ((unused)), grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY); - for (i = 0; i < 255; i++) + for (i = 0; i < 5; i++) { color = grub_video_map_rgb (i, 33, 77); grub_video_fill_rect (color, 0, 0, width, height); grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, 0, 0, 0, 0, width, height); + grub_video_swap_buffers (); } grub_getkey (); diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index fb5b11d04..3846fa9f2 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -154,7 +154,7 @@ efi_gop_mod_CFLAGS = $(COMMON_CFLAGS) efi_gop_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c \ +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c \ loader/macho32.c loader/macho64.c loader/macho.c loader/xnu.c xnu_mod_CFLAGS = $(COMMON_CFLAGS) xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 6f7b4f26c..6c4f64f91 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -180,7 +180,7 @@ linux_mod_CFLAGS = $(COMMON_CFLAGS) linux_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/pc/xnu.c \ +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c \ loader/macho32.c loader/macho64.c loader/macho.c loader/xnu.c xnu_mod_CFLAGS = $(COMMON_CFLAGS) xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 235cf2b3d..0ee09655f 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -155,7 +155,7 @@ efi_gop_mod_CFLAGS = $(COMMON_CFLAGS) efi_gop_mod_LDFLAGS = $(COMMON_LDFLAGS) pkglib_MODULES += xnu.mod -xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/i386/efi/xnu.c \ +xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c \ loader/macho32.c loader/macho64.c loader/macho.c loader/xnu.c xnu_mod_CFLAGS = $(COMMON_CFLAGS) xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/include/grub/i386/xnu.h b/include/grub/i386/xnu.h index d3ac5ba0c..386c8b9e0 100644 --- a/include/grub/i386/xnu.h +++ b/include/grub/i386/xnu.h @@ -114,7 +114,5 @@ extern grub_uint32_t grub_xnu_stack; extern grub_uint32_t grub_xnu_arg1; extern char grub_xnu_cmdline[1024]; grub_err_t grub_xnu_boot (void); -grub_err_t grub_xnu_set_video (struct grub_xnu_boot_params *bootparams_relloc); -grub_err_t -grub_cpu_xnu_fill_devicetree (void); +grub_err_t grub_cpu_xnu_fill_devicetree (void); #endif diff --git a/include/grub/video.h b/include/grub/video.h index 985fa9208..fb0151878 100644 --- a/include/grub/video.h +++ b/include/grub/video.h @@ -180,7 +180,7 @@ struct grub_video_adapter grub_err_t (*fini) (void); grub_err_t (*setup) (unsigned int width, unsigned int height, - unsigned int mode_type); + unsigned int mode_type, unsigned int mode_mask); grub_err_t (*get_info) (struct grub_video_mode_info *mode_info); @@ -316,8 +316,17 @@ grub_err_t grub_video_set_active_render_target (struct grub_video_render_target grub_err_t grub_video_get_active_render_target (struct grub_video_render_target **target); grub_err_t grub_video_set_mode (const char *modestring, - int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p, - struct grub_video_mode_info *mode_info)); -grub_video_driver_id_t grub_video_get_driver_id (void); + unsigned int modemask, + unsigned int modevalue); + +static inline int +grub_video_check_mode_flag (unsigned int flags, unsigned int mask, + unsigned int flag, int def) +{ + return (flag & mask) ? !! (flags & flag) : def; +} + +grub_video_driver_id_t +grub_video_get_driver_id (void); #endif /* ! GRUB_VIDEO_HEADER */ diff --git a/loader/i386/efi/xnu.c b/loader/i386/efi/xnu.c deleted file mode 100644 index a7ede1960..000000000 --- a/loader/i386/efi/xnu.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Setup video for xnu. Big parts are copied from linux.c. */ - -static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; - -#define RGB_MASK 0xffffff -#define RGB_MAGIC 0x121314 -#define LINE_MIN 800 -#define LINE_MAX 4096 -#define FBTEST_STEP (0x10000 >> 2) -#define FBTEST_COUNT 8 - -static int -find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len) -{ - grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base; - int i; - - for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP) - { - if ((*base & RGB_MASK) == RGB_MAGIC) - { - int j; - - for (j = LINE_MIN; j <= LINE_MAX; j++) - { - if ((base[j] & RGB_MASK) == RGB_MAGIC) - { - *fb_base = (grub_uint32_t) (grub_target_addr_t) base; - *line_len = j << 2; - - return 1; - } - } - - break; - } - } - - return 0; -} - -static int -find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) -{ - int found = 0; - - auto int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, - grub_pci_id_t pciid); - - int NESTED_FUNC_ATTR find_card (grub_pci_device_t dev, - grub_pci_id_t pciid) - { - grub_pci_address_t addr; - - addr = grub_pci_make_address (dev, 2); - if (grub_pci_read (addr) >> 24 == 0x3) - { - int i; - - grub_printf ("Display controller: %d:%d.%d\nDevice id: %x\n", - grub_pci_get_bus (dev), grub_pci_get_device (dev), - grub_pci_get_function (dev), pciid); - addr += 8; - for (i = 0; i < 6; i++, addr += 4) - { - grub_uint32_t old_bar1, old_bar2, type; - grub_uint64_t base64; - - old_bar1 = grub_pci_read (addr); - if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO)) - continue; - - type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK; - if (type == GRUB_PCI_ADDR_MEM_TYPE_64) - { - if (i == 5) - break; - - old_bar2 = grub_pci_read (addr + 4); - } - else - old_bar2 = 0; - - base64 = old_bar2; - base64 <<= 32; - base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK); - - grub_printf ("%s(%d): 0x%llx\n", - ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ? - "VMEM" : "MMIO"), i, - (unsigned long long) base64); - - if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found)) - { - *fb_base = base64; - if (find_line_len (fb_base, line_len)) - found++; - } - - if (type == GRUB_PCI_ADDR_MEM_TYPE_64) - { - i++; - addr += 4; - } - } - } - - return found; - } - - grub_pci_iterate (find_card); - return found; -} - -grub_err_t -grub_xnu_set_video (struct grub_xnu_boot_params *params) -{ - grub_efi_uga_draw_protocol_t *c; - grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len; - int ret; - - c = grub_efi_locate_protocol (&uga_draw_guid, 0); - if (! c) - return grub_error (GRUB_ERR_IO, "couldn't find UGADraw"); - - if (efi_call_5 (c->get_mode, c, &width, &height, &depth, &rate)) - return grub_error (GRUB_ERR_IO, "couldn't retrieve video mode"); - - grub_printf ("Video mode: %ux%u-%u@%u\n", width, height, depth, rate); - - grub_efi_set_text_mode (0); - pixel = RGB_MAGIC; - efi_call_10 (c->blt, c, (struct grub_efi_uga_pixel *) &pixel, - GRUB_EFI_UGA_VIDEO_FILL, 0, 0, 0, 0, 1, height, 0); - ret = find_framebuf (&fb_base, &line_len); - grub_efi_set_text_mode (1); - - if (! ret) - return grub_error (GRUB_ERR_IO, "can\'t find frame buffer address"); - - grub_printf ("Frame buffer base: 0x%x\n", fb_base); - grub_printf ("Video line length: %d\n", line_len); - - params->lfb_width = width; - params->lfb_height = height; - params->lfb_depth = depth; - params->lfb_line_len = line_len; - params->lfb_mode = GRUB_XNU_VIDEO_TEXT_IN_VIDEO; - params->lfb_base = fb_base; - return GRUB_ERR_NONE; -} diff --git a/loader/i386/linux.c b/loader/i386/linux.c index 691d0912d..9fdf9b445 100644 --- a/loader/i386/linux.c +++ b/loader/i386/linux.c @@ -597,11 +597,11 @@ grub_linux_boot (void) if (! tmp) return grub_errno; grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, 0); + err = grub_video_set_mode (tmp, 0, 0); grub_free (tmp); } else - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0); if (err) { diff --git a/loader/i386/pc/xnu.c b/loader/i386/pc/xnu.c deleted file mode 100644 index ebb176bb4..000000000 --- a/loader/i386/pc/xnu.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 2009 Free Software Foundation, Inc. - * - * GRUB is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * GRUB is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GRUB. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#define max(a,b) (((a) > (b)) ? (a) : (b)) - -#define DEFAULT_VIDEO_MODE "1024x768x32,800x600x32,640x480x32" - -static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)), - struct grub_video_mode_info *info) -{ - if (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) - return 0; - - return 1; -} - -/* Setup video for xnu. */ -grub_err_t -grub_xnu_set_video (struct grub_xnu_boot_params *params) -{ - struct grub_video_mode_info mode_info; - int ret; - char *tmp, *modevar; - void *framebuffer; - grub_err_t err; - - modevar = grub_env_get ("gfxpayload"); - if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); - else - { - tmp = grub_malloc (grub_strlen (modevar) - + sizeof (DEFAULT_VIDEO_MODE) + 1); - if (! tmp) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, - "couldn't allocate temporary storag"); - grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, video_hook); - grub_free (tmp); - } - - if (err) - return err; - - if (grub_xnu_bitmap) - { - int x, y; - - x = mode_info.width - grub_xnu_bitmap->mode_info.width; - x /= 2; - y = mode_info.height - grub_xnu_bitmap->mode_info.height; - y /= 2; - err = grub_video_blit_bitmap (grub_xnu_bitmap, - GRUB_VIDEO_BLIT_REPLACE, - x > 0 ? x : 0, - y > 0 ? y : 0, - x < 0 ? -x : 0, - y < 0 ? -y : 0, - min (grub_xnu_bitmap->mode_info.width, - mode_info.width), - min (grub_xnu_bitmap->mode_info.height, - mode_info.height)); - if (err) - { - grub_print_error (); - grub_errno = GRUB_ERR_NONE; - grub_xnu_bitmap = 0; - } - err = GRUB_ERR_NONE; - } - - ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); - if (ret) - return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); - - params->lfb_width = mode_info.width; - params->lfb_height = mode_info.height; - params->lfb_depth = mode_info.bpp; - params->lfb_line_len = mode_info.pitch; - - params->lfb_base = PTR_TO_UINT32 (framebuffer); - params->lfb_mode = grub_xnu_bitmap - ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; - - return GRUB_ERR_NONE; -} - diff --git a/loader/i386/xnu.c b/loader/i386/xnu.c index ce520bcde..a39f2bc7d 100644 --- a/loader/i386/xnu.c +++ b/loader/i386/xnu.c @@ -34,6 +34,11 @@ #include #include +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +#define DEFAULT_VIDEO_MODE "auto" + char grub_xnu_cmdline[1024]; grub_uint32_t grub_xnu_entry_point, grub_xnu_arg1, grub_xnu_stack; @@ -834,6 +839,84 @@ grub_xnu_boot_resume (void) return grub_relocator32_boot (grub_xnu_relocator, state); } +/* Setup video for xnu. */ +static grub_err_t +grub_xnu_set_video (struct grub_xnu_boot_params *params) +{ + struct grub_video_mode_info mode_info; + int ret; + char *tmp, *modevar; + void *framebuffer; + grub_err_t err; + + modevar = grub_env_get ("gfxpayload"); + /* Consider only graphical 32-bit deep modes. */ + if (! modevar || *modevar == 0) + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); + else + { + tmp = grub_malloc (grub_strlen (modevar) + + sizeof (DEFAULT_VIDEO_MODE) + 1); + if (! tmp) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "couldn't allocate temporary storag"); + grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); + err = grub_video_set_mode (tmp, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT + | GRUB_VIDEO_MODE_TYPE_DEPTH_MASK, + 32 << GRUB_VIDEO_MODE_TYPE_DEPTH_POS); + grub_free (tmp); + } + + if (err) + return err; + + if (grub_xnu_bitmap) + { + int x, y; + + x = mode_info.width - grub_xnu_bitmap->mode_info.width; + x /= 2; + y = mode_info.height - grub_xnu_bitmap->mode_info.height; + y /= 2; + err = grub_video_blit_bitmap (grub_xnu_bitmap, + GRUB_VIDEO_BLIT_REPLACE, + x > 0 ? x : 0, + y > 0 ? y : 0, + x < 0 ? -x : 0, + y < 0 ? -y : 0, + min (grub_xnu_bitmap->mode_info.width, + mode_info.width), + min (grub_xnu_bitmap->mode_info.height, + mode_info.height)); + if (err) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + grub_xnu_bitmap = 0; + } + err = GRUB_ERR_NONE; + } + + ret = grub_video_get_info_and_fini (&mode_info, &framebuffer); + if (ret) + return grub_error (GRUB_ERR_IO, "couldn't retrieve video parameters"); + + params->lfb_width = mode_info.width; + params->lfb_height = mode_info.height; + params->lfb_depth = mode_info.bpp; + params->lfb_line_len = mode_info.pitch; + + params->lfb_base = PTR_TO_UINT32 (framebuffer); + params->lfb_mode = grub_xnu_bitmap + ? GRUB_XNU_VIDEO_SPLASH : GRUB_XNU_VIDEO_TEXT_IN_VIDEO; + + return GRUB_ERR_NONE; +} + /* Boot xnu. */ grub_err_t grub_xnu_boot (void) diff --git a/term/gfxterm.c b/term/gfxterm.c index fa19a5d85..f493f882c 100644 --- a/term/gfxterm.c +++ b/term/gfxterm.c @@ -27,7 +27,7 @@ #include #include -#define DEFAULT_VIDEO_MODE "1024x768,800x600,640x480" +#define DEFAULT_VIDEO_MODE "auto" #define DEFAULT_BORDER_WIDTH 10 #define DEFAULT_STANDARD_COLOR 0x07 @@ -244,12 +244,6 @@ grub_virtual_screen_setup (unsigned int x, unsigned int y, return grub_errno; } -static int NESTED_FUNC_ATTR video_hook (grub_video_adapter_t p __attribute__ ((unused)), - struct grub_video_mode_info *info) -{ - return ! (info->mode_type & GRUB_VIDEO_MODE_TYPE_PURE_TEXT); -} - static grub_err_t grub_gfxterm_init (void) { @@ -269,13 +263,15 @@ grub_gfxterm_init (void) /* Parse gfxmode environment variable if set. */ modevar = grub_env_get ("gfxmode"); if (! modevar || *modevar == 0) - err = grub_video_set_mode (DEFAULT_VIDEO_MODE, video_hook); + err = grub_video_set_mode (DEFAULT_VIDEO_MODE, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); else { tmp = grub_malloc (grub_strlen (modevar) + sizeof (DEFAULT_VIDEO_MODE) + 1); grub_sprintf (tmp, "%s;" DEFAULT_VIDEO_MODE, modevar); - err = grub_video_set_mode (tmp, video_hook); + err = grub_video_set_mode (tmp, + GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0); grub_free (tmp); } diff --git a/video/efi_gop.c b/video/efi_gop.c index 13ef0ddae..86a2881f8 100644 --- a/video/efi_gop.c +++ b/video/efi_gop.c @@ -185,7 +185,7 @@ grub_video_gop_fill_mode_info (struct grub_efi_gop_mode_info *in, static grub_err_t grub_video_gop_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; struct grub_efi_gop_mode_info *info = NULL; diff --git a/video/efi_uga.c b/video/efi_uga.c index 7ef7594cc..e86837b06 100644 --- a/video/efi_uga.c +++ b/video/efi_uga.c @@ -198,7 +198,7 @@ grub_video_uga_fini (void) static grub_err_t grub_video_uga_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask __attribute__ ((unused))) { unsigned int depth; int found = 0; diff --git a/video/i386/pc/vbe.c b/video/i386/pc/vbe.c index 918bab0b0..34745b474 100644 --- a/video/i386/pc/vbe.c +++ b/video/i386/pc/vbe.c @@ -369,7 +369,7 @@ grub_video_vbe_fini (void) static grub_err_t grub_video_vbe_setup (unsigned int width, unsigned int height, - unsigned int mode_type) + unsigned int mode_type, unsigned int mode_mask) { grub_uint16_t *p; struct grub_vbe_mode_info_block vbe_mode_info; @@ -415,32 +415,40 @@ grub_video_vbe_setup (unsigned int width, unsigned int height, /* Not compatible memory model. */ continue; - if ((vbe_mode_info.x_resolution != width) - || (vbe_mode_info.y_resolution != height)) + if (((vbe_mode_info.x_resolution != width) + || (vbe_mode_info.y_resolution != height)) && width != 0 && height != 0) /* Non matching resolution. */ continue; /* Check if user requested RGB or index color mode. */ - if ((mode_type & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0) + if ((mode_mask & GRUB_VIDEO_MODE_TYPE_COLOR_MASK) != 0) { - if (((mode_type & GRUB_VIDEO_MODE_TYPE_INDEX_COLOR) != 0) - && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL)) - /* Requested only index color modes. */ - continue; + unsigned my_mode_type = 0; - if (((mode_type & GRUB_VIDEO_MODE_TYPE_RGB) != 0) - && (vbe_mode_info.memory_model != GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR)) - /* Requested only RGB modes. */ - continue; + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_PACKED_PIXEL) + my_mode_type |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + + if (vbe_mode_info.memory_model == GRUB_VBE_MEMORY_MODEL_DIRECT_COLOR) + my_mode_type |= GRUB_VIDEO_MODE_TYPE_RGB; + + if ((my_mode_type & mode_mask + & (GRUB_VIDEO_MODE_TYPE_RGB | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR)) + != (mode_type & mode_mask + & (GRUB_VIDEO_MODE_TYPE_RGB + | GRUB_VIDEO_MODE_TYPE_INDEX_COLOR))) + continue; } /* If there is a request for specific depth, ignore others. */ if ((depth != 0) && (vbe_mode_info.bits_per_pixel != depth)) continue; - /* Select mode with most number of bits per pixel. */ + /* Select mode with most of "volume" (size of framebuffer in bits). */ if (best_vbe_mode != 0) - if (vbe_mode_info.bits_per_pixel < best_vbe_mode_info.bits_per_pixel) + if ((grub_uint64_t) vbe_mode_info.bits_per_pixel + * vbe_mode_info.x_resolution * vbe_mode_info.y_resolution + < (grub_uint64_t) best_vbe_mode_info.bits_per_pixel + * best_vbe_mode_info.x_resolution * best_vbe_mode_info.y_resolution) continue; /* Save so far best mode information for later use. */ diff --git a/video/video.c b/video/video.c index e678c2982..f6b1aad9e 100644 --- a/video/video.c +++ b/video/video.c @@ -407,21 +407,81 @@ grub_video_get_active_render_target (struct grub_video_render_target **target) return grub_video_adapter_active->get_active_render_target (target); } +/* Parse x[x]*/ +static grub_err_t +parse_modespec (const char *current_mode, int *width, int *height, int *depth) +{ + const char *value; + const char *param = current_mode; + + *width = *height = *depth = -1; + + if (grub_strcmp (param, "auto") == 0) + { + *width = *height = 0; + return GRUB_ERR_NONE; + } + + /* Find width value. */ + value = param; + param = grub_strchr(param, 'x'); + if (param == NULL) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + param++; + + *width = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + /* Find height value. */ + value = param; + param = grub_strchr(param, 'x'); + if (param == NULL) + { + *height = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + } + else + { + /* We have optional color depth value. */ + param++; + + *height = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + + /* Convert color depth value. */ + value = param; + *depth = grub_strtoul (value, 0, 0); + if (grub_errno != GRUB_ERR_NONE) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Invalid mode: %s\n", + current_mode); + } + return GRUB_ERR_NONE; +} + grub_err_t grub_video_set_mode (const char *modestring, - int NESTED_FUNC_ATTR (*hook) (grub_video_adapter_t p, - struct grub_video_mode_info *mode_info)) + unsigned int modemask, + unsigned int modevalue) { char *tmp; char *next_mode; char *current_mode; - char *param; - char *value; char *modevar; - int width = -1; - int height = -1; - int depth = -1; - int flags = 0; + + modevalue &= modemask; /* Take copy of env.var. as we don't want to modify that. */ modevar = grub_strdup (modestring); @@ -437,26 +497,26 @@ grub_video_set_mode (const char *modestring, || grub_memcmp (next_mode, "keep,", sizeof ("keep,") - 1) == 0 || grub_memcmp (next_mode, "keep;", sizeof ("keep;") - 1) == 0) { - struct grub_video_mode_info mode_info; int suitable = 1; grub_err_t err; - grub_memset (&mode_info, 0, sizeof (mode_info)); - if (grub_video_adapter_active) { + struct grub_video_mode_info mode_info; + grub_memset (&mode_info, 0, sizeof (mode_info)); err = grub_video_get_info (&mode_info); if (err) { suitable = 0; grub_errno = GRUB_ERR_NONE; } + if ((mode_info.mode_type & modemask) != modevalue) + suitable = 0; } - else - mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT; + else if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0) + && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0)) + suitable = 0; - if (suitable && hook) - suitable = hook (grub_video_adapter_active, &mode_info); if (suitable) { grub_free (modevar); @@ -490,15 +550,16 @@ grub_video_set_mode (const char *modestring, /* Loop until all modes has been tested out. */ while (next_mode != NULL) { + int width = -1; + int height = -1; + int depth = -1; + grub_err_t err; + unsigned int flags = modevalue; + unsigned int flagmask = modemask; + /* Use last next_mode as current mode. */ tmp = next_mode; - /* Reset video mode settings. */ - width = -1; - height = -1; - depth = -1; - flags = 0; - /* Save position of next mode and separate modes. */ for (; *next_mode; next_mode++) if (*next_mode == ',' || *next_mode == ';') @@ -517,19 +578,16 @@ grub_video_set_mode (const char *modestring, /* Initialize token holders. */ current_mode = tmp; - param = tmp; - value = NULL; /* XXX: we assume that we're in pure text mode if no video mode is initialized. Is it always true? */ - if (grub_strcmp (param, "text") == 0) + if (grub_strcmp (current_mode, "text") == 0) { struct grub_video_mode_info mode_info; grub_memset (&mode_info, 0, sizeof (mode_info)); - mode_info.mode_type = GRUB_VIDEO_MODE_TYPE_PURE_TEXT; - - if (! hook || hook (0, &mode_info)) + if (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) == 0) + || ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) != 0)) { /* Valid mode found from adapter, and it has been activated. Specify it as active adapter. */ @@ -542,121 +600,31 @@ grub_video_set_mode (const char *modestring, } } - /* Parse x[x]*/ - - /* Find width value. */ - value = param; - param = grub_strchr(param, 'x'); - if (param == NULL) + err = parse_modespec (current_mode, &width, &height, &depth); + if (err) { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid mode: %s", - current_mode); - /* Free memory before returning. */ grub_free (modevar); - return rc; - } - - *param = 0; - param++; - - width = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid mode: %s", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - - /* Find height value. */ - value = param; - param = grub_strchr(param, 'x'); - if (param == NULL) - { - height = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid mode: %s", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - } - else - { - /* We have optional color depth value. */ - *param = 0; - param++; - - height = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid mode: %s", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } - - /* Convert color depth value. */ - value = param; - depth = grub_strtoul (value, 0, 0); - if (grub_errno != GRUB_ERR_NONE) - { - grub_err_t rc; - - /* First setup error message. */ - rc = grub_error (GRUB_ERR_BAD_ARGUMENT, - "invalid mode: %s", - current_mode); - - /* Free memory before returning. */ - grub_free (modevar); - - return rc; - } + return err; } /* Try out video mode. */ - /* If we have 8 or less bits, then assume that it is indexed color mode. */ - if ((depth <= 8) && (depth != -1)) - flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR; + /* If user requested specific depth check if this depth is supported. */ + if (depth != -1 && (flagmask & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + && + (((flags & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK) + != ((depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK)))) + continue; - /* We have more than 8 bits, then assume that it is RGB color mode. */ - if (depth > 8) - flags |= GRUB_VIDEO_MODE_TYPE_RGB; - - /* If user requested specific depth, forward that information to driver. */ if (depth != -1) - flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) - & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + { + flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + flagmask |= GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + } /* Try to initialize requested mode. Ignore any errors. */ grub_video_adapter_t p; @@ -664,7 +632,6 @@ grub_video_set_mode (const char *modestring, /* Loop thru all possible video adapter trying to find requested mode. */ for (p = grub_video_adapter_list; p; p = p->next) { - grub_err_t err; struct grub_video_mode_info mode_info; grub_memset (&mode_info, 0, sizeof (mode_info)); @@ -678,7 +645,7 @@ grub_video_set_mode (const char *modestring, } /* Try to initialize video mode. */ - err = p->setup (width, height, flags); + err = p->setup (width, height, flags, flagmask); if (err != GRUB_ERR_NONE) { p->fini (); @@ -694,7 +661,15 @@ grub_video_set_mode (const char *modestring, continue; } - if (hook && ! hook (p, &mode_info)) + flags = mode_info.mode_type & ~GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + flags |= (mode_info.bpp << GRUB_VIDEO_MODE_TYPE_DEPTH_POS) + & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK; + + /* Check that mode is suitable for upper layer. */ + if ((flags & GRUB_VIDEO_MODE_TYPE_PURE_TEXT) + ? (((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modemask) != 0) + && ((GRUB_VIDEO_MODE_TYPE_PURE_TEXT & modevalue) == 0)) + : ((flags & modemask) != modevalue)) { p->fini (); grub_errno = GRUB_ERR_NONE;