When using packed color modes, Linux expects we fill the color
sizes with the value obtained from the DAC.  If we give it zeroes
(like we currently do) it displays a blank screen.

This can be reproduced by attempting to boot Linux with a 8-bit
color mode (e.g. set gfxpayload=800x600x8).

Now I'm not completely sure where does this belong.  I think it's somewhat
generic and we can reasonably expect other OSes to want this information
too, but I'm not completely sure.

An alternative would be to do this query in the Linux loader, but this has
the disadvantage that we're putting backend-specific code in the loader which
aims to be completely backend-independant someday.

Also, tell me what you think about the "getset" hack.  It looks like a clean
way of providing both functions in less space, but then I'm not sure if we
really want both functions.  For now we only use the "set" one.  Then again,
once you have "set" getting "get" comes really cheap.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."
Index: kern/i386/pc/startup.S
===================================================================
--- kern/i386/pc/startup.S	(revision 2439)
+++ kern/i386/pc/startup.S	(working copy)
@@ -1733,6 +1733,52 @@
 	ret
 
 /*
+ * grub_vbe_status_t grub_vbe_bios_getset_dac_palette_width (int set, int *dac_mask_size)
+ *
+ * Register allocations for parameters:
+ * %eax		set
+ * %edx		*dac_mask_size
+ */
+FUNCTION(grub_vbe_bios_getset_dac_palette_width)
+	pushl	%ebp
+	pushl	%ebx
+
+	xorl	%ebx, %ebx
+
+	/* If we only want to fetch the value, set %bl to 1.  */
+	testl	%eax, %eax
+	jne	1f
+	incb	%bl
+1:
+
+	/* Put desired width in %bh.  */
+	movl	(%edx), %eax
+	movb	%al, %bh
+
+	call    prot_to_real
+	.code16
+
+	movw	$0x4f08, %ax
+	int	$0x10
+
+	movw	%ax, %dx	/* real_to_prot destroys %eax.  */
+
+	DATA32 call	real_to_prot
+	.code32
+
+	/* Move result back to *dac_mask_size.  */
+	movb	%bh, %al
+	movl	%eax, (%edx)
+
+	/* Return value in %eax.  */
+	xorl	%eax, %eax
+	movw	%dx, %ax
+
+	popl	%ebx
+	popl	%ebp
+	ret
+
+/*
  * grub_vbe_status_t grub_vbe_bios_set_memory_window (grub_uint32_t window,
  *						      grub_uint32_t position);
  *
Index: video/i386/pc/vbe.c
===================================================================
--- video/i386/pc/vbe.c	(revision 2439)
+++ video/i386/pc/vbe.c	(working copy)
@@ -300,6 +300,24 @@
 
       /* Make copy of mode info block.  */
       grub_memcpy (mode_info, mi_tmp, sizeof (*mode_info));
+
+      /* Packed mode.  Query DAC Palette width for color sizes.  */
+      if (mode_info->bits_per_pixel <= 8)
+	{
+	  int width = 8;
+	  status = 0;
+
+	  if (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH)
+	    status = grub_vbe_bios_set_dac_palette_width (& width);
+
+	  if (status != 0x004F)
+	    /* 6 is default after mode reset.  */
+	    width = 6;
+
+	  mode_info->red_mask_size = mode_info->green_mask_size
+	    = mode_info->blue_mask_size = mode_info->rsvd_mask_size
+	    = width;
+	}
     }
   else
     /* Just clear mode info block if it isn't a VESA mode.  */
Index: include/grub/i386/pc/vbe.h
===================================================================
--- include/grub/i386/pc/vbe.h	(revision 2439)
+++ include/grub/i386/pc/vbe.h	(working copy)
@@ -30,6 +30,8 @@
 /* VBE status codes.  */
 #define GRUB_VBE_STATUS_OK		0x004f
 
+#define GRUB_VBE_CAPABILITY_DACWIDTH	(1 << 0)
+
 /* Bits from the GRUB_VBE "mode_attributes" field in the mode info struct.  */
 #define GRUB_VBE_MODEATTR_SUPPORTED                 (1 << 0)
 #define GRUB_VBE_MODEATTR_RESERVED_1                (1 << 1)
@@ -181,6 +183,11 @@
 grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_get_mode_info) (grub_uint32_t mode,
                                                             struct grub_vbe_mode_info_block *mode_info);
 
+grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_getset_dac_palette_width) (int set, int *width);
+
+#define grub_vbe_bios_get_dac_palette_width(width)	grub_vbe_bios_getset_dac_palette_width(0, (width))
+#define grub_vbe_bios_set_dac_palette_width(width)	grub_vbe_bios_getset_dac_palette_width(1, (width))
+
 /* Call VESA BIOS 0x4f02 to set video mode, return status.  */
 grub_vbe_status_t EXPORT_FUNC(grub_vbe_bios_set_mode) (grub_uint32_t mode,
                                                        struct grub_vbe_crtc_info_block *crtc_info);
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to