summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@rpsys.net>2006-10-31 15:51:14 +0000
committerRichard Purdie <rpurdie@rpsys.net>2006-10-31 15:51:14 +0000
commit107e16ef26b39adda7c81f6685cb000aec2e7ac8 (patch)
treee775be3f0abe85ea722db87703bfce2c253fb8d5 /packages
parentfcd0c98b96d5b27573f7ca346ba522ec8692ae6c (diff)
linux-oz-2.6: Add missing patch.
Diffstat (limited to 'packages')
-rw-r--r--packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch3089
1 files changed, 3089 insertions, 0 deletions
diff --git a/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch b/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch
new file mode 100644
index 0000000000..188ce6094e
--- /dev/null
+++ b/packages/linux/linux-openzaurus-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch
@@ -0,0 +1,3089 @@
+# Patch generated against a6047eef1c465c38aacfbdab193161b3f0cd144
+---
+# Documentation/fb/vesafb.txt | 250 ++++--
+# arch/i386/boot/video.S | 12
+# drivers/video/Kconfig | 56 +
+# drivers/video/Makefile | 6
+# drivers/video/fbmem.c | 1
+# drivers/video/modedb.c | 1
+# drivers/video/vesafb-thread.c | 727 +++++++++++++++++++
+# drivers/video/vesafb-tng.c | 1598 ++++++++++++++++++++++++++++++++++++++++++
+# include/linux/sched.h | 2
+# include/video/vesa.h | 150 +++
+# kernel/fork.c | 35
+# mm/memory.c | 1
+# mm/mmap.c | 1
+# 13 files changed, 2748 insertions(+), 92 deletions(-)
+#
+--- linux-2.6.17.orig/Documentation/fb/vesafb.txt
++++ linux-2.6.17/Documentation/fb/vesafb.txt
+@@ -2,16 +2,18 @@
+ What is vesafb?
+ ===============
+
+-This is a generic driver for a graphic framebuffer on intel boxes.
++Vesafb is a generic framebuffer driver for x86 and x86_64 boxes.
+
+-The idea is simple: Turn on graphics mode at boot time with the help
+-of the BIOS, and use this as framebuffer device /dev/fb0, like the m68k
+-(and other) ports do.
++VESA BIOS Extensions Version 2.0 are required, because we need access to
++a linear frame buffer. VBE 3.0 is required if you want to use modes with a
++higher (than the standard 60 Hz) refresh rate.
+
+-This means we decide at boot time whenever we want to run in text or
+-graphics mode. Switching mode later on (in protected mode) is
+-impossible; BIOS calls work in real mode only. VESA BIOS Extensions
+-Version 2.0 are required, because we need a linear frame buffer.
++The VESA framebuffer driver comes in two flavors - the standard 'vesafb'
++and 'vesafb-tng'. Vesafb-tng is available only on 32-bit x86 due to the
++technology it uses (vm86). Vesafb-tng has more features than vesafb
++(adjusting the refresh rate on VBE 3.0 compliant boards, switching the
++video mode without rebooting, selecting a mode by providing its
++modedb name, and more).
+
+ Advantages:
+
+@@ -29,26 +31,35 @@ Disadvantages:
+ How to use it?
+ ==============
+
+-Switching modes is done using the vga=... boot parameter. Read
+-Documentation/svga.txt for details.
++If you are running a 32-bit x86 system and you decide to use vesafb-tng,
++you can either compile the driver into the kernel or use it as a module.
++The graphics mode you want to use is in both cases specified using the
++standard modedb format.
+
+-You should compile in both vgacon (for text mode) and vesafb (for
+-graphics mode). Which of them takes over the console depends on
+-whenever the specified mode is text or graphics.
++If your system doesn't support vm86 calls, things get a little more tricky.
++Since on such systems you can't do BIOS calls from protected mode in which
++kernel runs, you have to decide at boot time whenever you want to run in text
++or in graphics mode. Switching mode later on is impossible. Switching modes
++is done using the vga=... boot parameter. Read Documentation/svga.txt for
++details. Below is a more detailed description of what to do on systems using
++the standard vesafb driver.
+
+-The graphic modes are NOT in the list which you get if you boot with
+-vga=ask and hit return. The mode you wish to use is derived from the
+-VESA mode number. Here are those VESA mode numbers:
++You should compile in both vgacon (for text mode) and vesafb (for graphics
++mode). Which of them takes over the console depends on whenever the
++specified mode is text or graphics.
++
++The graphic modes are NOT in the list which you get if you boot with vga=ask
++and hit return. The mode you wish to use is derived from the VESA mode number.
++Here are those VESA mode numbers:
+
+ | 640x480 800x600 1024x768 1280x1024
+ ----+-------------------------------------
+-256 | 0x101 0x103 0x105 0x107
+-32k | 0x110 0x113 0x116 0x119
+-64k | 0x111 0x114 0x117 0x11A
+-16M | 0x112 0x115 0x118 0x11B
++256 | 0x101 0x103 0x105 0x107
++32k | 0x110 0x113 0x116 0x119
++64k | 0x111 0x114 0x117 0x11A
++16M | 0x112 0x115 0x118 0x11B
+
+-The video mode number of the Linux kernel is the VESA mode number plus
+-0x200.
++The video mode number of the Linux kernel is the VESA mode number plus 0x200.
+
+ Linux_kernel_mode_number = VESA_mode_number + 0x200
+
+@@ -56,15 +67,15 @@ So the table for the Kernel mode numbers
+
+ | 640x480 800x600 1024x768 1280x1024
+ ----+-------------------------------------
+-256 | 0x301 0x303 0x305 0x307
+-32k | 0x310 0x313 0x316 0x319
+-64k | 0x311 0x314 0x317 0x31A
+-16M | 0x312 0x315 0x318 0x31B
++256 | 0x301 0x303 0x305 0x307
++32k | 0x310 0x313 0x316 0x319
++64k | 0x311 0x314 0x317 0x31A
++16M | 0x312 0x315 0x318 0x31B
+
+-To enable one of those modes you have to specify "vga=ask" in the
+-lilo.conf file and rerun LILO. Then you can type in the desired
+-mode at the "vga=ask" prompt. For example if you like to use
+-1024x768x256 colors you have to say "305" at this prompt.
++To enable one of those modes you have to specify "vga=ask" in the lilo.conf
++file and rerun LILO. Then you can type in the desired mode at the "vga=ask"
++prompt. For example if you like to use 1024x768x256 colors you have to say
++"305" at this prompt.
+
+ If this does not work, this might be because your BIOS does not support
+ linear framebuffers or because it does not support this mode at all.
+@@ -72,11 +83,12 @@ Even if your board does, it might be the
+ Extensions v2.0 are required, 1.2 is NOT sufficient. You will get a
+ "bad mode number" message if something goes wrong.
+
+-1. Note: LILO cannot handle hex, for booting directly with
++1. Note: LILO cannot handle hex, for booting directly with
+ "vga=mode-number" you have to transform the numbers to decimal.
+ 2. Note: Some newer versions of LILO appear to work with those hex values,
+ if you set the 0x in front of the numbers.
+
++
+ X11
+ ===
+
+@@ -84,98 +96,164 @@ XF68_FBDev should work just fine, but it
+ another (accelerated) X-Server like XF86_SVGA might or might not work.
+ It depends on X-Server and graphics board.
+
+-The X-Server must restore the video mode correctly, else you end up
++The X-Server must restore the video mode correctly, or else you end up
+ with a broken console (and vesafb cannot do anything about this).
++With vesafb-tng chances are that the console will be restored properly
++even if the X server messes up the video mode.
+
+
+ Refresh rates
+ =============
+
+-There is no way to change the vesafb video mode and/or timings after
+-booting linux. If you are not happy with the 60 Hz refresh rate, you
+-have these options:
++With VBE 3.0 compatible BIOSes and vesafb-tng it is possible to change
++the refresh rate either at boot time (by specifying the @<rr> part of
++the mode name) or later, using the fbset utility.
+
+- * configure and load the DOS-Tools for your the graphics board (if
+- available) and boot linux with loadlin.
+- * use a native driver (matroxfb/atyfb) instead if vesafb. If none
++If you want to use the default BIOS refresh rate while switching modes
++on a running system, set pixclock to 0.
++
++With VBE 2.0 there is no way to change the mode timings after booting
++Linux. If you are not happy with the 60 Hz refresh rate, you have
++the following options:
++
++ * Configure and load the DOS tools for your the graphics board (if
++ available) and boot Linux with loadlin.
++ * Use a native driver (matroxfb/atyfb) instead of vesafb. If none
+ is available, write a new one!
+- * VBE 3.0 might work too. I have neither a gfx board with VBE 3.0
+- support nor the specs, so I have not checked this yet.
++ * Use a BIOS editor to change the default refresh rate (such an
++ editor does exist at least for ATI Radeon BIOSes).
++ * If you're running a non-vm86 and VBE 3.0 compatible system, you can
++ use a kernel patch (vesafb-rrc) to hard-code some mode timings in
++ the kernel and use these while setting the video mode at boot time.
++
++Note that there are some boards (nVidia 59**, 57** and newer models)
++claiming that their Video BIOS is VBE 3.0 compliant, while ignoring the
++CRTC values provided by software such as vesafb-tng. You'll not be able
++to adjust the refresh rate if you're using one of these boards.
+
+
+ Configuration
+ =============
+
+-The VESA BIOS provides protected mode interface for changing
+-some parameters. vesafb can use it for palette changes and
+-to pan the display. It is turned off by default because it
+-seems not to work with some BIOS versions, but there are options
+-to turn it on.
++The VESA BIOS provides protected mode interface for changing some parameters.
++vesafb can use it for palette changes and to pan the display. It is turned
++off by default because it seems not to work with some BIOS versions, but
++there are options to turn it on.
+
+-You can pass options to vesafb using "video=vesafb:option" on
+-the kernel command line. Multiple options should be separated
+-by comma, like this: "video=vesafb:ypan,invers"
++You can pass options to vesafb using "video=vesafb:option" on the kernel
++command line. Multiple options should be separated by a comma, like this:
++"video=vesafb:ypan,1024x768-32@85"
+
+-Accepted options:
++Note that vesafb-tng still uses the "video=vesafb:option" format of the
++kernel command line video parameter. "video=vesafb-tng:xxx" is incorrect.
+
+-invers no comment...
++Accepted options (both vesafb and vesafb-tng):
+
+-ypan enable display panning using the VESA protected mode
+- interface. The visible screen is just a window of the
+- video memory, console scrolling is done by changing the
+- start of the window.
+- pro: * scrolling (fullscreen) is fast, because there is
+- no need to copy around data.
+- * You'll get scrollback (the Shift-PgUp thing),
+- the video memory can be used as scrollback buffer
+- kontra: * scrolling only parts of the screen causes some
+- ugly flicker effects (boot logo flickers for
+- example).
++ypan Enable display panning using the VESA protected mode interface
++ The visible screen is just a window of the video memory,
++ console scrolling is done by changing the start of the window.
++ pro: * scrolling (fullscreen) is fast, because there is
++ no need to copy around data.
++ * you'll get scrollback (the Shift-PgUp thing),
++ the video memory can be used as scrollback buffer
++ con: * scrolling only parts of the screen causes some
++ ugly flicker effects (boot logo flickers for
++ example).
+
+-ywrap Same as ypan, but assumes your gfx board can wrap-around
+- the video memory (i.e. starts reading from top if it
+- reaches the end of video memory). Faster than ypan.
++ywrap Same as ypan, but assumes your gfx board can wrap-around the video
++ memory (i.e. starts reading from top if it reaches the end of
++ video memory). Faster than ypan.
+
+-redraw scroll by redrawing the affected part of the screen, this
+- is the safe (and slow) default.
++redraw Scroll by redrawing the affected part of the screen, this is the
++ safe (and slow) default.
+
++vgapal Use the standard VGA registers for palette changes.
+
+-vgapal Use the standard vga registers for palette changes.
+- This is the default.
+-pmipal Use the protected mode interface for palette changes.
++pmipal Use the protected mode interface for palette changes.
++ This is the default is the protected mode interface is available.
+
+-mtrr:n setup memory type range registers for the vesafb framebuffer
+- where n:
+- 0 - disabled (equivalent to nomtrr) (default)
+- 1 - uncachable
+- 2 - write-back
+- 3 - write-combining
+- 4 - write-through
++mtrr:n Setup memory type range registers for the vesafb framebuffer
++ where n:
++ 0 - disabled (equivalent to nomtrr) (default)
++ 1 - uncachable
++ 2 - write-back
++ 3 - write-combining
++ 4 - write-through
+
+- If you see the following in dmesg, choose the type that matches the
+- old one. In this example, use "mtrr:2".
++ If you see the following in dmesg, choose the type that matches
++ the old one. In this example, use "mtrr:2".
+ ...
+ mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining
+ ...
+
+-nomtrr disable mtrr
++nomtrr Do not use memory type range registers for vesafb.
+
+ vremap:n
+ remap 'n' MiB of video RAM. If 0 or not specified, remap memory
+- according to video mode. (2.5.66 patch/idea by Antonino Daplas
+- reversed to give override possibility (allocate more fb memory
+- than the kernel would) to 2.4 by tmb@iki.fi)
++ according to video mode. (2.5.66 patch/idea by Antonino Daplas
++ reversed to give override possibility (allocate more fb memory
++ than the kernel would) to 2.4 by tmb@iki.fi)
+
+ vtotal:n
+ if the video BIOS of your card incorrectly determines the total
+ amount of video RAM, use this option to override the BIOS (in MiB).
+
+-Have fun!
++Options accepted only by vesafb-tng:
+
+- Gerd
++<mode> The mode you want to set, in the standard modedb format. Refer to
++ modedb.txt for a detailed description. If you specify a mode that is
++ not supported by your board's BIOS, vesafb-tng will attempt to set a
++ similar mode. The list of supported modes can be found in
++ /proc/fbx/modes, where x is the framebuffer number (usually 0).
++ When vesafb-tng is compiled as a module, the mode string should be
++ provided as a value of the parameter 'mode'.
++
++vbemode:x
++ Force the use of VBE mode x. The mode will only be set if it's
++ found in the VBE-provided list of supported modes.
++ NOTE: The mode number 'x' should be specified in VESA mode number
++ notation, not the Linux kernel one (eg. 257 instead of 769).
++ HINT: If you use this option because normal <mode> parameter does
++ not work for you and you use a X server, you'll probably want to
++ set the 'nocrtc' option to ensure that the video mode is properly
++ restored after console <-> X switches.
++
++nocrtc Do not use CRTC timings while setting the video mode. This option
++ makes sence only with VBE 3.0 compliant systems. Use it if you have
++ problems with modes set in the standard way. Note that using this
++ option means that any refresh rate adjustments will be ignored
++ and the refresh rate will stay at your BIOS default (60 Hz).
++
++noedid Do not try to fetch and use EDID-provided modes.
++
++noblank Disable hardware blanking.
++
++gtf Force the use of VESA's GTF (Generalized Timing Formula). Specifying
++ this will cause vesafb to skip its internal modedb and EDID-modedb
++ and jump straight to the GTF part of the code (normally used only if
++ everything else failed). This can be useful if you want to get as
++ much as possible from your graphics board but your BIOS doesn't
++ support modes with the refresh rates you require. Note that you may
++ need to specify the maxhf, maxvf and maxclk parameters if they are not
++ provided by the EDID block.
++
++Additionally, the following parameters may be provided. They all override the
++EDID-provided values and BIOS defaults. Refer to your monitor's specs to get
++the correct values for maxhf, maxvf and maxclk for your hardware.
++
++maxhf:n Maximum horizontal frequency (in kHz).
++maxvf:n Maximum vertical frequency (in Hz).
++maxclk:n Maximum pixel clock (in MHz).
++
++Have fun!
+
+ --
++Original document for the vesafb driver by
+ Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+-Minor (mostly typo) changes
+-by Nico Schmoigl <schmoigl@rumms.uni-mannheim.de>
++Minor (mostly typo) changes by
++Nico Schmoigl <schmoigl@rumms.uni-mannheim.de>
++
++Extended documentation for vm86, VBE 3.0 and vesafb-tng by
++Michal Januszewski <spock@gentoo.org>
++
+--- linux-2.6.17.orig/arch/i386/boot/video.S
++++ linux-2.6.17/arch/i386/boot/video.S
+@@ -165,10 +165,12 @@ basret: ret
+ # parameters in the default 80x25 mode -- these are set directly,
+ # because some very obscure BIOSes supply insane values.
+ mode_params:
++#ifdef CONFIG_FB_VESA_STD
+ #ifdef CONFIG_VIDEO_SELECT
+ cmpb $0, graphic_mode
+ jnz mopar_gr
+ #endif
++#endif
+ movb $0x03, %ah # Read cursor position
+ xorb %bh, %bh
+ int $0x10
+@@ -201,6 +203,7 @@ mopar2: movb %al, %fs:(PARAM_VIDEO_LINES
+ ret
+
+ #ifdef CONFIG_VIDEO_SELECT
++#ifdef CONFIG_FB_VESA_STD
+ # Fetching of VESA frame buffer parameters
+ mopar_gr:
+ leaw modelist+1024, %di
+@@ -283,6 +286,7 @@ dac_done:
+ movw %es, %fs:(PARAM_VESAPM_SEG)
+ movw %di, %fs:(PARAM_VESAPM_OFF)
+ no_pm: ret
++#endif
+
+ # The video mode menu
+ mode_menu:
+@@ -497,10 +501,12 @@ mode_set:
+
+ cmpb $VIDEO_FIRST_V7>>8, %ah
+ jz setv7
+-
++
++#ifdef CONFIG_FB_VESA_STD
+ cmpb $VIDEO_FIRST_VESA>>8, %ah
+ jnc check_vesa
+-
++#endif
++
+ orb %ah, %ah
+ jz setmenu
+
+@@ -572,6 +578,7 @@ setr1: lodsw
+ movw -4(%si), %ax # Fetch mode ID
+ jmp _m_s
+
++#ifdef CONFIG_FB_VESA_STD
+ check_vesa:
+ leaw modelist+1024, %di
+ subb $VIDEO_FIRST_VESA>>8, %bh
+@@ -605,6 +612,7 @@ check_vesa:
+ ret
+
+ _setbad: jmp setbad # Ugly...
++#endif
+
+ # Recalculate vertical display end registers -- this fixes various
+ # inconsistencies of extended modes on many adapters. Called when
+--- linux-2.6.17.orig/drivers/video/Kconfig
++++ linux-2.6.17/drivers/video/Kconfig
+@@ -472,8 +472,22 @@ config FB_TGA
+ cards. Say Y if you have one of those.
+
+ config FB_VESA
+- bool "VESA VGA graphics support"
+- depends on (FB = y) && X86
++ tristate "VESA VGA graphics support"
++ depends on (FB = y) && (X86 || X86_64)
++ help
++ This is the frame buffer device driver for generic VESA 2.0
++ compliant graphic cards. The older VESA 1.2 cards are not supported.
++ You will get a boot time penguin logo at no additional cost. Please
++ read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
++
++choice
++ prompt "VESA driver type"
++ depends on FB_VESA
++ default FB_VESA_STD if X86_64
++ default FB_VESA_TNG if X86
++
++config FB_VESA_STD
++ bool "vesafb"
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+@@ -481,7 +495,43 @@ config FB_VESA
+ This is the frame buffer device driver for generic VESA 2.0
+ compliant graphic cards. The older VESA 1.2 cards are not supported.
+ You will get a boot time penguin logo at no additional cost. Please
+- read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
++ read <file:Documentation/fb/vesafb.txt>. Choose this driver if you
++ are experiencing problems with vesafb-tng or if you own a 64-bit system.
++
++ Note that this driver cannot be compiled as a module.
++
++config FB_VESA_TNG
++ bool "vesafb-tng"
++ depends on !X86_64
++ select FB_MODE_HELPERS
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ help
++ This is the frame buffer device driver for generic VESA 2.0
++ compliant graphic cards. It is capable of taking advantage of
++ VBE 3.0 features. With this driver you will be able to adjust
++ the refresh rate (VBE 3.0 compliant boards only) and change
++ the graphic mode on-the-fly.
++
++ You will also get a boot time penguin logo at no additional cost. Please
++ read <file:Documentation/fb/vesafb.txt>.
++
++endchoice
++
++config FB_VESA_DEFAULT_MODE
++ string "VESA default mode"
++ depends on FB_VESA_TNG
++ default "640x480@60"
++ help
++ This option is used to determine the default mode vesafb is
++ supposed to switch to in case no mode is provided as a kernel
++ command line parameter.
++
++config VIDEO_SELECT
++ bool
++ depends on FB_VESA
++ default y
+
+ config VIDEO_SELECT
+ bool
+--- linux-2.6.17.orig/drivers/video/Makefile
++++ linux-2.6.17/drivers/video/Makefile
+@@ -97,7 +97,11 @@ obj-$(CONFIG_FB_IMX) += imx
+ obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+
+ # Platform or fallback drivers go here
+-obj-$(CONFIG_FB_VESA) += vesafb.o
++ifeq ($(CONFIG_FB_VESA_STD),y)
++ obj-y += vesafb.o
++else
++ obj-$(CONFIG_FB_VESA) += vesafb-thread.o vesafb-tng.o
++endif
+ obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
+ obj-$(CONFIG_FB_OF) += offb.o
+
+--- linux-2.6.17.orig/drivers/video/fbmem.c
++++ linux-2.6.17/drivers/video/fbmem.c
+@@ -1438,6 +1438,7 @@ fbmem_init(void)
+ printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
+ fb_class = NULL;
+ }
++
+ return 0;
+ }
+
+--- linux-2.6.17.orig/drivers/video/modedb.c
++++ linux-2.6.17/drivers/video/modedb.c
+@@ -671,6 +671,7 @@ void fb_var_to_videomode(struct fb_video
+ {
+ u32 pixclock, hfreq, htotal, vtotal;
+
++ mode->refresh = 0;
+ mode->name = NULL;
+ mode->xres = var->xres;
+ mode->yres = var->yres;
+--- /dev/null
++++ linux-2.6.17/drivers/video/vesafb-thread.c
+@@ -0,0 +1,727 @@
++/*
++ * Framebuffer driver for VBE 2.0+ compliant graphic boards.
++ * Kernel thread and vm86 routines.
++ *
++ * (c) 2004-2006 Michal Januszewski <spock@gentoo.org>
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/slab.h>
++#include <linux/workqueue.h>
++#include <linux/completion.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/delay.h>
++#include <linux/signal.h>
++#include <linux/suspend.h>
++#include <linux/unistd.h>
++#include <video/vesa.h>
++#include <video/edid.h>
++#include <asm/mman.h>
++#include <asm/page.h>
++#include <asm/vm86.h>
++#include <asm/thread_info.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++#include "edid.h"
++
++#ifdef MODULE
++int errno;
++#endif
++
++static DECLARE_COMPLETION(vesafb_th_completion);
++static DECLARE_MUTEX(vesafb_task_list_sem);
++static LIST_HEAD(vesafb_task_list);
++static DECLARE_WAIT_QUEUE_HEAD(vesafb_wait);
++
++static struct vm86_struct vm86;
++static int vesafb_pid = 0;
++
++_syscall3(int,ioperm,unsigned long, a, unsigned long, b, unsigned long, c);
++_syscall1(int,vm86old,struct vm86_struct __user*, v86);
++
++#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK)
++#define VM86_PUSHW(x) \
++do { \
++ vm86.regs.esp -= 2; \
++ *(u16*)(STACK_ADDR + vm86.regs.esp) = x; \
++} while(0);
++
++/* Stack, the return code and buffers will be put into
++ * one contiguous memory chunk:
++ *
++ * [ STACK | RET_CODE | BUFFER ]
++ *
++ * Some video BIOSes (sis6326) try to store data somewhere
++ * in 0x7000-0x7fff, so we zeromap more memory to be safe.
++ */
++#define IVTBDA_SIZE PAGE_SIZE
++#define RET_CODE_SIZE 0x0010
++#define STACK_SIZE 0x0500
++#define BUFFER_SIZE 0x10000
++
++/* The amount of memory that will be allocated should be a multiple
++ * of PAGE_SIZE. */
++#define __MEM_SIZE (RET_CODE_SIZE + STACK_SIZE + BUFFER_SIZE)
++#define REAL_MEM_SIZE (((__MEM_SIZE / PAGE_SIZE) + 1) * PAGE_SIZE)
++
++#define IVTBDA_ADDR 0x00000
++#define STACK_ADDR (IVTBDA_ADDR + IVTBDA_SIZE)
++#define RET_CODE_ADDR (STACK_ADDR + STACK_SIZE)
++#define BUF_ADDR (RET_CODE_ADDR + RET_CODE_SIZE)
++
++#define FLAG_D (1 << 10)
++
++/* Segment prefix opcodes */
++enum {
++ P_CS = 0x2e,
++ P_SS = 0x36,
++ P_DS = 0x3e,
++ P_ES = 0x26,
++ P_FS = 0x64,
++ P_GS = 0x65
++};
++
++/* Emulated vm86 ins instruction */
++static void vm86_ins(int size)
++{
++ u32 edx, edi;
++ edx = vm86.regs.edx & 0xffff;
++ edi = (vm86.regs.edi & 0xffff) + (u32)(vm86.regs.es << 4);
++
++ if (vm86.regs.eflags & FLAG_D)
++ asm volatile ("std\n");
++ else
++ asm volatile ("cld\n");
++
++ switch (size) {
++ case 4:
++ asm volatile ("insl\n" : "=D" (edi) : "d" (edx), "0" (edi));
++ break;
++ case 2:
++ asm volatile ("insw\n" : "=D" (edi) : "d" (edx), "0" (edi));
++ break;
++ case 1:
++ asm volatile ("insb\n" : "=D" (edi) : "d" (edx), "0" (edi));
++ break;
++ }
++
++ if (vm86.regs.eflags & FLAG_D)
++ asm volatile ("cld\n");
++
++ edi -= (u32)(vm86.regs.es << 4);
++
++ vm86.regs.edi &= 0xffff0000;
++ vm86.regs.edi |= edi & 0xffff;
++}
++
++static void vm86_rep_ins(int size)
++{
++ u16 cx = vm86.regs.ecx;
++ while (cx--)
++ vm86_ins(size);
++
++ vm86.regs.ecx &= 0xffff0000;
++}
++
++/* Emulated vm86 outs instruction */
++static void vm86_outs(int size, int segment)
++{
++ u32 edx, esi, base;
++
++ edx = vm86.regs.edx & 0xffff;
++ esi = vm86.regs.esi & 0xffff;
++
++ switch (segment) {
++ case P_CS: base = vm86.regs.cs; break;
++ case P_SS: base = vm86.regs.ss; break;
++ case P_ES: base = vm86.regs.es; break;
++ case P_FS: base = vm86.regs.fs; break;
++ case P_GS: base = vm86.regs.gs; break;
++ default: base = vm86.regs.ds; break;
++ }
++
++ esi += base << 4;
++
++ if (vm86.regs.eflags & FLAG_D)
++ asm volatile ("std\n");
++ else
++ asm volatile ("cld\n");
++
++ switch (size) {
++ case 4:
++ asm volatile ("outsl\n" : "=S" (esi) : "d" (edx), "0" (esi));
++ break;
++ case 2:
++ asm volatile ("outsw\n" : "=S" (esi) : "d" (edx), "0" (esi));
++ break;
++ case 1:
++ asm volatile ("outsb\n" : "=S" (esi) : "d" (edx), "0" (esi));
++ break;
++ }
++
++ if (vm86.regs.eflags & FLAG_D)
++ asm volatile ("cld");
++
++ esi -= base << 4;
++ vm86.regs.esi &= 0xffff0000;
++ vm86.regs.esi |= (esi & 0xffff);
++}
++
++static void vm86_rep_outs(int size, int segment)
++{
++ u16 cx = vm86.regs.ecx;
++ while (cx--)
++ vm86_outs(size, segment);
++
++ vm86.regs.ecx &= 0xffff0000;
++}
++
++static int vm86_do_unknown(void)
++{
++ u8 data32 = 0, segment = P_DS, rep = 0;
++ u8 *instr;
++ int ret = 0, i = 0;
++
++ instr = (u8*)((vm86.regs.cs << 4) + vm86.regs.eip);
++
++ while (1) {
++ switch(instr[i]) {
++ case 0x66: /* operand size prefix */
++ data32 = 1 - data32;
++ i++;
++ break;
++ case 0xf2: /* repnz */
++ case 0xf3: /* rep */
++ rep = 1;
++ i++;
++ break;
++ case P_CS: /* segment prefix */
++ case P_SS:
++ case P_DS:
++ case P_ES:
++ case P_FS:
++ case P_GS:
++ segment = instr[i];
++ i++;
++ break;
++ case 0xf0: /* LOCK - ignored */
++ case 0x67: /* address size prefix - ignored */
++ i++;
++ break;
++ case 0x6c: /* insb */
++ if (rep)
++ vm86_rep_ins(1);
++ else
++ vm86_ins(1);
++ i++;
++ goto out;
++ case 0x6d: /* insw / insd */
++ if (rep) {
++ if (data32)
++ vm86_rep_ins(4);
++ else
++ vm86_rep_ins(2);
++ } else {
++ if (data32)
++ vm86_ins(4);
++ else
++ vm86_ins(2);
++ }
++ i++;
++ goto out;
++ case 0x6e: /* outsb */
++ if (rep)
++ vm86_rep_outs(1, segment);
++ else
++ vm86_outs(1, segment);
++ i++;
++ goto out;
++ case 0x6f: /* outsw / outsd */
++ if (rep) {
++ if (data32)
++ vm86_rep_outs(4, segment);
++ else
++ vm86_rep_outs(2, segment);
++ } else {
++ if (data32)
++ vm86_outs(4, segment);
++ else
++ vm86_outs(2, segment);
++ }
++ i++;
++ goto out;
++ case 0xe4: /* inb xx */
++ asm volatile (
++ "inb %w1, %b0"
++ : "=a" (vm86.regs.eax)
++ : "d" (instr[i+1]), "0" (vm86.regs.eax));
++ i += 2;
++ goto out;
++ case 0xe5: /* inw xx / ind xx */
++ if (data32) {
++ asm volatile (
++ "inl %w1, %0"
++ : "=a" (vm86.regs.eax)
++ : "d" (instr[i+1]),
++ "0" (vm86.regs.eax));
++ } else {
++ asm volatile (
++ "inw %w1, %w0"
++ : "=a" (vm86.regs.eax)
++ : "d" (instr[i+1]),
++ "0" (vm86.regs.eax));
++ }
++ i += 2;
++ goto out;
++
++ case 0xec: /* inb dx */
++ asm volatile (
++ "inb %w1, %b0"
++ : "=a" (vm86.regs.eax)
++ : "d" (vm86.regs.edx), "0" (vm86.regs.eax));
++ i++;
++ goto out;
++ case 0xed: /* inw dx / ind dx */
++ if (data32) {
++ asm volatile (
++ "inl %w1, %0"
++ : "=a" (vm86.regs.eax)
++ : "d" (vm86.regs.edx));
++ } else {
++ asm volatile (
++ "inw %w1, %w0"
++ : "=a" (vm86.regs.eax)
++ : "d" (vm86.regs.edx));
++ }
++ i++;
++ goto out;
++ case 0xe6: /* outb xx */
++ asm volatile (
++ "outb %b0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax), "d" (instr[i+1]));
++ i += 2;
++ goto out;
++ case 0xe7: /* outw xx / outd xx */
++ if (data32) {
++ asm volatile (
++ "outl %0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax),
++ "d" (instr[i+1]));
++ } else {
++ asm volatile (
++ "outw %w0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax),
++ "d" (instr[i+1]));
++ }
++ i += 2;
++ goto out;
++ case 0xee: /* outb dx */
++ asm volatile (
++ "outb %b0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax), "d" (vm86.regs.edx));
++ i++;
++ goto out;
++ case 0xef: /* outw dx / outd dx */
++ if (data32) {
++ asm volatile (
++ "outl %0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax),
++ "d" (vm86.regs.edx));
++ } else {
++ asm volatile (
++ "outw %w0, %w1"
++ : /* no return value */
++ : "a" (vm86.regs.eax),
++ "d" (vm86.regs.edx));
++ }
++ i++;
++ goto out;
++ default:
++ printk(KERN_ERR "vesafb: BUG, opcode 0x%x emulation "
++ "not supported (EIP: 0x%lx)\n",
++ instr[i], (u32)(vm86.regs.cs << 4) +
++ vm86.regs.eip);
++ ret = 1;
++ goto out;
++ }
++ }
++out: vm86.regs.eip += i;
++ return ret;
++}
++
++void vesafb_do_vm86(struct vm86_regs *regs)
++{
++ unsigned int ret;
++ u8 *retcode = (void*)RET_CODE_ADDR;
++
++ memset(&vm86,0,sizeof(vm86));
++ memcpy(&vm86.regs, regs, sizeof(struct vm86_regs));
++
++ /* The return code */
++ retcode[0] = 0xcd; /* int opcode */
++ retcode[1] = 0xff; /* int number (255) */
++
++ /* We use int 0xff to get back to protected mode */
++ memset(&vm86.int_revectored, 0, sizeof(vm86.int_revectored));
++ ((unsigned char *)&vm86.int_revectored)[0xff / 8] |= (1 << (0xff % 8));
++
++ /*
++ * We want to call int 0x10, so we set:
++ * CS = 0x42 = 0x10 * 4 + 2
++ * IP = 0x40 = 0x10 * 4
++ * and SS:ESP. It's up to the caller to set the rest of the registers.
++ */
++ vm86.regs.eflags = DEFAULT_VM86_FLAGS;
++ vm86.regs.cs = *(unsigned short *)0x42;
++ vm86.regs.eip = *(unsigned short *)0x40;
++ vm86.regs.ss = (STACK_ADDR >> 4);
++ vm86.regs.esp = ((STACK_ADDR & 0x0000f) + STACK_SIZE);
++
++ /* These will be fetched off the stack when we come to an iret in the
++ * int's 0x10 code. */
++ VM86_PUSHW(DEFAULT_VM86_FLAGS);
++ VM86_PUSHW((RET_CODE_ADDR >> 4)); /* return code segment */
++ VM86_PUSHW((RET_CODE_ADDR & 0x0000f)); /* return code offset */
++
++ while(1) {
++ ret = vm86old(&vm86);
++
++ if (VM86_TYPE(ret) == VM86_INTx) {
++ int vint = VM86_ARG(ret);
++
++ /* If exit from vm86 was caused by int 0xff, then
++ * we're done.. */
++ if (vint == 0xff)
++ goto out;
++
++ /* .. otherwise, we have to call the int handler
++ * manually */
++ VM86_PUSHW(vm86.regs.eflags);
++ VM86_PUSHW(vm86.regs.cs);
++ VM86_PUSHW(vm86.regs.eip);
++
++ vm86.regs.cs = *(u16 *)((vint << 2) + 2);
++ vm86.regs.eip = *(u16 *)(vint << 2);
++ vm86.regs.eflags &= ~(VIF_MASK | TF_MASK);
++ } else if (VM86_TYPE(ret) == VM86_UNKNOWN) {
++ if (vm86_do_unknown())
++ goto out;
++ } else {
++ printk(KERN_ERR "vesafb: BUG, returned from "
++ "vm86 with %x (EIP: 0x%lx)\n",
++ ret, (u32)(vm86.regs.cs << 4) +
++ vm86.regs.eip);
++ goto out;
++ }
++ }
++
++out: /* copy the registers' state back to the caller's struct */
++ memcpy(regs, &vm86.regs, sizeof(struct vm86_regs));
++}
++
++static int vesafb_remap_pfn_range(unsigned long start, unsigned long end,
++ unsigned long pgoff, unsigned long prot,
++ int type)
++{
++ struct vm_area_struct *vma;
++ struct mm_struct *mm = current->mm;
++ int ret = 0;
++
++ vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
++ if (!vma)
++ return -ENOMEM;
++ memset(vma, 0, sizeof(*vma));
++ down_write(&mm->mmap_sem);
++ vma->vm_mm = mm;
++ vma->vm_start = start;
++ vma->vm_end = end;
++ vma->vm_flags = VM_READ | VM_WRITE | VM_EXEC;
++ vma->vm_flags |= mm->def_flags;
++ vma->vm_page_prot.pgprot = prot;
++ vma->vm_pgoff = pgoff;
++
++ if ((ret = insert_vm_struct(mm, vma))) {
++ up_write(&mm->mmap_sem);
++ kmem_cache_free(vm_area_cachep, vma);
++ return ret;
++ }
++
++ if (type) {
++ ret = zeromap_page_range(vma,
++ vma->vm_start,
++ vma->vm_end - vma->vm_start,
++ vma->vm_page_prot);
++ } else {
++ vma->vm_flags |= VM_SHARED;
++ ret = remap_pfn_range(vma,
++ vma->vm_start,
++ vma->vm_pgoff,
++ vma->vm_end - vma->vm_start,
++ vma->vm_page_prot);
++ }
++ up_write(&mm->mmap_sem);
++ return ret;
++}
++
++static inline int vesafb_init_mem(void)
++{
++ int ret = 0;
++
++ /* The memory chunks we're remapping here should be multiples
++ * of PAGE_SIZE. */
++ ret += vesafb_remap_pfn_range(0x00000, IVTBDA_SIZE, 0,
++ PROT_READ | PROT_EXEC | PROT_WRITE, 0);
++ ret += vesafb_remap_pfn_range(IVTBDA_SIZE, REAL_MEM_SIZE, 0,
++ PROT_READ | PROT_EXEC | PROT_WRITE, 1);
++ ret += vesafb_remap_pfn_range(0x9f000, 0x100000,
++ 0x9f000 >> PAGE_SHIFT,
++ PROT_READ | PROT_EXEC | PROT_WRITE, 0);
++ if (ret)
++ printk(KERN_ERR "vesafb thread: memory remapping failed\n");
++
++ return ret;
++}
++
++#define vesafb_get_string(str) \
++{ \
++ /* The address is in the form ssssoooo, where oooo = offset, \
++ * ssss = segment */ \
++ addr = ((p_vbe(tsk->buf)->str & 0xffff0000) >> 12) + \
++ (p_vbe(tsk->buf)->str & 0x0000ffff); \
++ \
++ /* The data is in ROM which is shared between processes, so we \
++ * just translate the real mode address into one visible from \
++ * kernel space */ \
++ if (addr >= 0xa0000) { \
++ p_vbe(tsk->buf)->str = (u32) __va(addr); \
++ \
++ /* The data is in the buffer, we just have to convert the \
++ * address so that it points into the buffer user provided. */ \
++ } else if (addr > BUF_ADDR && addr < BUF_ADDR + \
++ sizeof(struct vesafb_vbe_ib)) { \
++ addr -= BUF_ADDR; \
++ p_vbe(tsk->buf)->str = (u32) (tsk->buf + addr); \
++ \
++ /* This should never happen: someone was insane enough to put \
++ * the data somewhere in RAM.. */ \
++ } else {