aboutsummaryrefslogtreecommitdiffstats
path: root/packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch')
-rw-r--r--packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch3089
1 files changed, 0 insertions, 3089 deletions
diff --git a/packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch b/packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch
deleted file mode 100644
index 188ce6094e..0000000000
--- a/packages/linux/linux-rp-2.6.17/vesafb-tng-1.0-rc2-git-20060629.patch
+++ /dev/null
@@ -1,3089 +0,0 @@
-# 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 { \
-+ p_vbe(tsk->buf)->str = (u32) ""; \
-+ } \
-+}
-+
-+void vesafb_handle_getvbeib(struct vesafb_task *tsk)
-+{
-+ int addr, res;
-+
-+ tsk->regs.es = (BUF_ADDR >> 4);
-+ tsk->regs.edi = (BUF_ADDR & 0x000f);
-+ strncpy(p_vbe(BUF_ADDR)->vbe_signature, "VBE2", 4);
-+
-+ vesafb_do_vm86(&tsk->regs);
-+ memcpy(tsk->buf, (void*)(BUF_ADDR), sizeof(struct vesafb_vbe_ib));
-+
-+ /* The OEM fields were not defined prior to VBE 2.0 */
-+ if (p_vbe(tsk->buf)->vbe_version >= 0x200) {
-+ vesafb_get_string(oem_string_ptr);
-+ vesafb_get_string(oem_vendor_name_ptr);
-+ vesafb_get_string(oem_product_name_ptr);
-+ vesafb_get_string(oem_product_rev_ptr);
-+ }
-+
-+ /* This is basically the same as vesafb_get_string() */
-+ addr = ((p_vbe(tsk->buf)->mode_list_ptr & 0xffff0000) >> 12) +
-+ (p_vbe(tsk->buf)->mode_list_ptr & 0x0000ffff);
-+
-+ if (addr >= 0xa0000) {
-+ p_vbe(tsk->buf)->mode_list_ptr = (u32) __va(addr);
-+ } else if (addr > BUF_ADDR && addr < BUF_ADDR +
-+ sizeof(struct vesafb_vbe_ib)) {
-+ addr -= BUF_ADDR;
-+ p_vbe(tsk->buf)->mode_list_ptr = (u32) (tsk->buf + addr);
-+ } else {
-+ res = 0;
-+ printk(KERN_WARNING "vesafb: warning, copying modelist "
-+ "from somewhere in RAM!\n");
-+ while (*(u16*)(addr+res) != 0xffff &&
-+ res < (sizeof(p_vbe(tsk->buf)->reserved) - 2)) {
-+ *(u16*) ((u32)&(p_vbe(tsk->buf)->reserved) + res) =
-+ *(u16*)(addr+res);
-+ res += 2;
-+ }
-+ *(u16*) ((u32)&(p_vbe(tsk->buf)->reserved) + res) = 0xffff;
-+ }
-+}
-+
-+int vesafb_handle_tasks(void)
-+{
-+ struct vesafb_task *tsk;
-+ struct list_head *curr, *next;
-+ int ret = 0;
-+
-+ down(&vesafb_task_list_sem);
-+ list_for_each_safe(curr, next, &vesafb_task_list) {
-+ tsk = list_entry(curr, struct vesafb_task, node);
-+
-+ if (tsk->flags & TF_EXIT) {
-+ ret = 1;
-+ goto task_done;
-+ }
-+ if (tsk->flags & TF_GETVBEIB) {
-+ vesafb_handle_getvbeib(tsk);
-+ goto task_done;
-+ }
-+ /* Do we need to store a pointer to the buffer in ES:EDI? */
-+ if (tsk->flags & TF_BUF_DI) {
-+ tsk->regs.es = (BUF_ADDR >> 4);
-+ tsk->regs.edi = (BUF_ADDR & 0x000f);
-+ }
-+ /* Sometimes the pointer has to be in ES:EBX. */
-+ if (tsk->flags & TF_BUF_BX) {
-+ tsk->regs.es = (BUF_ADDR >> 4);
-+ tsk->regs.ebx = (BUF_ADDR & 0x000f);
-+ }
-+ if (tsk->flags & (TF_BUF_DI | TF_BUF_BX))
-+ memcpy((void*)BUF_ADDR, tsk->buf, tsk->buf_len);
-+
-+ vesafb_do_vm86(&tsk->regs);
-+
-+ if (tsk->flags & TF_RETURN_BUF)
-+ memcpy(tsk->buf, (void*)BUF_ADDR, tsk->buf_len);
-+
-+task_done: list_del(curr);
-+ complete(&tsk->done);
-+ }
-+
-+ /* If we're going to kill this thread, don't allow any elements
-+ * to be added to the task list. */
-+ if (!ret)
-+ up(&vesafb_task_list_sem);
-+
-+ return ret;
-+}
-+
-+/*
-+ * This 'hybrid' thread serves as a backend for vesafb-tng, handling all vm86
-+ * calls. It is started as a kernel thread. It then creates its own mm struct,
-+ * thus separating itself from any userspace processes. At this moment, it
-+ * stops being a kernel thread (kernel threads have mm = NULL) and becomes
-+ * a 'hybrid' thread -- one that has full access to kernel space, yet runs
-+ * with its own address space.
-+ *
-+ * This is necessary because in order to make vm86 calls some parts of the
-+ * first 1MB of RAM have to be setup to mimic the real mode. These are:
-+ * - interrupt vector table [0x00000-0x003ff]
-+ * - BIOS data area [0x00400-0x004ff]
-+ * - Extended BIOS data area [0x9fc00-0x9ffff]
-+ * - the video RAM [0xa0000-0xbffff]
-+ * - video BIOS [0xc0000-0xcffff]
-+ * - motherboard BIOS [0xf0000-0xfffff]
-+ */
-+int vesafb_thread(void *unused)
-+{
-+ int err = 0;
-+
-+ set_fs(KERNEL_DS);
-+ daemonize("vesafb");
-+
-+ if (set_new_mm()) {
-+ err = -ENOMEM;
-+ goto thr_end;
-+ }
-+ if (vesafb_init_mem()) {
-+ err = -ENOMEM;
-+ goto thr_end;
-+ }
-+
-+ DPRINTK("started vesafb thread\n");
-+
-+ /* Having an IO bitmap makes things faster as we avoid GPFs
-+ * when running vm86 code. We can live if it fails, though,
-+ * so don't bother checking for errors. */
-+ ioperm(0,1024,1);
-+ set_user_nice(current, -10);
-+
-+ complete(&vesafb_th_completion);
-+
-+ while (1) {
-+ if (vesafb_handle_tasks())
-+ break;
-+ wait_event_interruptible(vesafb_wait,
-+ !list_empty(&vesafb_task_list));
-+ try_to_freeze();
-+ }
-+
-+out: DPRINTK("exiting the vesafb thread\n");
-+ vesafb_pid = -1;
-+
-+ /* Now that all callers know this thread is no longer running
-+ * (pid < 0), allow them to continue. */
-+ up(&vesafb_task_list_sem);
-+ return err;
-+thr_end:
-+ down(&vesafb_task_list_sem);
-+ complete(&vesafb_th_completion);
-+ goto out;
-+}
-+
-+int vesafb_queue_task(struct vesafb_task *tsk)
-+{
-+ down(&vesafb_task_list_sem);
-+ if (vesafb_pid < 0)
-+ return -1;
-+ list_add_tail(&tsk->node, &vesafb_task_list);
-+ up(&vesafb_task_list_sem);
-+ wake_up(&vesafb_wait);
-+ return 0;
-+}
-+
-+int vesafb_wait_for_thread(void)
-+{
-+ /* PID 0 means that the thread is still initializing. */
-+ if (vesafb_pid < 0)
-+ return -1;
-+ wait_for_completion(&vesafb_th_completion);
-+ return 0;
-+}
-+
-+int __init vesafb_init_thread(void)
-+{
-+ vesafb_pid = kernel_thread(vesafb_thread,NULL,0);
-+ return 0;
-+}
-+
-+#ifdef MODULE
-+void __exit vesafb_kill_thread(void)
-+{
-+ struct vesafb_task *tsk;
-+ if (vesafb_pid <= 0)
-+ return;
-+
-+ vesafb_create_task(tsk);
-+ if (!tsk)
-+ return;
-+ tsk->flags |= TF_EXIT;
-+ vesafb_queue_task(tsk);
-+ vesafb_wait_for_task(tsk);
-+ kfree(tsk);
-+ return;
-+}
-+module_exit(vesafb_kill_thread);
-+#endif
-+module_init(vesafb_init_thread);
-+
-+EXPORT_SYMBOL_GPL(vesafb_queue_task);
-+EXPORT_SYMBOL_GPL(vesafb_wait_for_thread);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Michal Januszewski");
-+
---- /dev/null
-+++ linux-2.6.17/drivers/video/vesafb-tng.c
-@@ -0,0 +1,1598 @@
-+/*
-+ * Framebuffer driver for VBE 2.0+ compliant graphic boards
-+ *
-+ * (c) 2004-2006 Michal Januszewski <spock@gentoo.org>
-+ * Based upon vesafb code by Gerd Knorr <kraxel@goldbach.in-berlin.de>
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/tty.h>
-+#include <linux/delay.h>
-+#include <linux/fb.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/proc_fs.h>
-+#include <linux/completion.h>
-+#include <linux/platform_device.h>
-+#include <video/edid.h>
-+#include <video/vesa.h>
-+#include <video/vga.h>
-+#include <asm/io.h>
-+#include <asm/mtrr.h>
-+#include <asm/page.h>
-+#include <asm/pgtable.h>
-+#include "edid.h"
-+
-+#define dac_reg (0x3c8)
-+#define dac_val (0x3c9)
-+
-+#define VESAFB_NEED_EXACT_RES 1
-+#define VESAFB_NEED_EXACT_DEPTH 2
-+
-+/* --------------------------------------------------------------------- */
-+
-+static struct fb_var_screeninfo vesafb_defined __initdata = {
-+ .activate = FB_ACTIVATE_NOW,
-+ .height = 0,
-+ .width = 0,
-+ .right_margin = 32,
-+ .upper_margin = 16,
-+ .lower_margin = 4,
-+ .vsync_len = 4,
-+ .vmode = FB_VMODE_NONINTERLACED,
-+};
-+
-+static struct fb_fix_screeninfo vesafb_fix __initdata = {
-+ .id = "VESA VGA",
-+ .type = FB_TYPE_PACKED_PIXELS,
-+ .accel = FB_ACCEL_NONE,
-+};
-+
-+static int mtrr = 0; /* disable mtrr by default */
-+static int blank = 1; /* enable blanking by default */
-+static int ypan = 0; /* 0 - nothing, 1 - ypan, 2 - ywrap */
-+static int pmi_setpal = 1; /* pmi for palette changes */
-+static u16 *pmi_base = NULL; /* protected mode interface location */
-+static void (*pmi_start)(void) = NULL;
-+static void (*pmi_pal)(void) = NULL;
-+static struct vesafb_vbe_ib vbe_ib;
-+static struct vesafb_mode_ib *vbe_modes;
-+static int vbe_modes_cnt = 0;
-+static struct fb_info *vesafb_info = NULL;
-+static int nocrtc = 0; /* ignore CRTC settings */
-+static int noedid __initdata = 0; /* don't try DDC transfers */
-+static int vram_remap __initdata = 0; /* set amount of memory to be used */
-+static int vram_total __initdata = 0; /* set total amount of memory */
-+static u16 maxclk __initdata = 0; /* maximum pixel clock */
-+static u16 maxvf __initdata = 0; /* maximum vertical frequency */
-+static u16 maxhf __initdata = 0; /* maximum horizontal frequency */
-+static int gtf __initdata = 0; /* forces use of the GTF */
-+static char *mode_option __initdata = NULL;
-+static u16 vbemode __initdata = 0;
-+
-+/* --------------------------------------------------------------------- */
-+
-+static int vesafb_find_vbe_mode(int xres, int yres, int depth,
-+ unsigned char flags)
-+{
-+ int i, match = -1, h = 0, d = 0x7fffffff;
-+
-+ for (i = 0; i < vbe_modes_cnt; i++) {
-+ h = abs(vbe_modes[i].x_res - xres) +
-+ abs(vbe_modes[i].y_res - yres) +
-+ abs(depth - vbe_modes[i].depth);
-+ if (h == 0)
-+ return i;
-+ if (h < d || (h == d && vbe_modes[i].depth > depth)) {
-+ d = h;
-+ match = i;
-+ }
-+ }
-+ i = 1;
-+
-+ if (flags & VESAFB_NEED_EXACT_DEPTH && vbe_modes[match].depth != depth)
-+ i = 0;
-+ if (flags & VESAFB_NEED_EXACT_RES && d > 24)
-+ i = 0;
-+ if (i != 0)
-+ return match;
-+ else
-+ return -1;
-+}
-+
-+static int vesafb_pan_display(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ int offset;
-+
-+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
-+
-+ /* It turns out it's not the best idea to do panning via vm86,
-+ * so we only allow it if we have a PMI. */
-+ if (pmi_start) {
-+ __asm__ __volatile__(
-+ "call *(%%edi)"
-+ : /* no return value */
-+ : "a" (0x4f07), /* EAX */
-+ "b" (0), /* EBX */
-+ "c" (offset), /* ECX */
-+ "d" (offset >> 16), /* EDX */
-+ "D" (&pmi_start)); /* EDI */
-+ }
-+ return 0;
-+}
-+
-+static int vesafb_blank(int blank, struct fb_info *info)
-+{
-+ struct vesafb_task *tsk;
-+ int err = 1;
-+
-+ if (vbe_ib.capabilities & VBE_CAP_VGACOMPAT) {
-+ int loop = 10000;
-+ u8 seq = 0, crtc17 = 0;
-+
-+ if (blank == FB_BLANK_POWERDOWN) {
-+ seq = 0x20;
-+ crtc17 = 0x00;
-+ err = 0;
-+ } else {
-+ seq = 0x00;
-+ crtc17 = 0x80;
-+ err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL;
-+ }
-+
-+ vga_wseq(NULL, 0x00, 0x01);
-+ seq |= vga_rseq(NULL, 0x01) & ~0x20;
-+ vga_wseq(NULL, 0x00, seq);
-+
-+ crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80;
-+ while (loop--);
-+ vga_wcrt(NULL, 0x17, crtc17);
-+ vga_wseq(NULL, 0x00, 0x03);
-+ } else {
-+ vesafb_create_task (tsk);
-+ if (!tsk)
-+ return -ENOMEM;
-+ tsk->regs.eax = 0x4f10;
-+ switch (blank) {
-+ case FB_BLANK_UNBLANK:
-+ tsk->regs.ebx = 0x0001;
-+ break;
-+ case FB_BLANK_NORMAL:
-+ tsk->regs.ebx = 0x0101; /* standby */
-+ break;
-+ case FB_BLANK_POWERDOWN:
-+ tsk->regs.ebx = 0x0401; /* powerdown */
-+ break;
-+ default:
-+ goto out;
-+ }
-+ tsk->flags = TF_CALL;
-+ if (!vesafb_queue_task (tsk))
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) == 0x004f)
-+ err = 0;
-+out: kfree(tsk);
-+ }
-+ return err;
-+}
-+
-+static int vesafb_setpalette(struct vesafb_pal_entry *entries, int count,
-+ int start, struct fb_info *info)
-+{
-+ struct vesafb_task *tsk;
-+ int i = ((struct vesafb_par*)info->par)->mode_idx;
-+ int ret = 0;
-+
-+ /* We support palette modifications for 8 bpp modes only, so
-+ * there can never be more than 256 entries. */
-+ if (start + count > 256)
-+ return -EINVAL;
-+
-+ /* Use VGA registers if mode is VGA-compatible. */
-+ if (i >= 0 && i < vbe_modes_cnt &&
-+ vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) {
-+ for (i = 0; i < count; i++) {
-+ outb_p(start + i, dac_reg);
-+ outb_p(entries[i].red, dac_val);
-+ outb_p(entries[i].green, dac_val);
-+ outb_p(entries[i].blue, dac_val);
-+ }
-+ } else if (pmi_setpal) {
-+ __asm__ __volatile__(
-+ "call *(%%esi)"
-+ : /* no return value */
-+ : "a" (0x4f09), /* EAX */
-+ "b" (0), /* EBX */
-+ "c" (count), /* ECX */
-+ "d" (start), /* EDX */
-+ "D" (entries), /* EDI */
-+ "S" (&pmi_pal)); /* ESI */
-+ } else {
-+ vesafb_create_task (tsk);
-+ if (!tsk)
-+ return -ENOMEM;
-+ tsk->regs.eax = 0x4f09;
-+ tsk->regs.ebx = 0x0;
-+ tsk->regs.ecx = count;
-+ tsk->regs.edx = start;
-+ tsk->buf = entries;
-+ tsk->buf_len = sizeof(struct vesafb_pal_entry) * count;
-+ tsk->flags = TF_CALL | TF_BUF_DI;
-+
-+ if (!vesafb_queue_task (tsk))
-+ vesafb_wait_for_task(tsk);
-+ if ((tsk->regs.eax & 0xffff) != 0x004f)
-+ ret = 1;
-+ kfree(tsk);
-+ }
-+ return ret;
-+}
-+
-+static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
-+ unsigned blue, unsigned transp,
-+ struct fb_info *info)
-+{
-+ struct vesafb_pal_entry entry;
-+ int shift = 16 - info->var.green.length;
-+ int ret = 0;
-+
-+ if (regno >= info->cmap.len)
-+ return -EINVAL;
-+
-+ if (info->var.bits_per_pixel == 8) {
-+ entry.red = red >> shift;
-+ entry.green = green >> shift;
-+ entry.blue = blue >> shift;
-+ entry.pad = 0;
-+
-+ ret = vesafb_setpalette(&entry, 1, regno, info);
-+ } else if (regno < 16) {
-+ switch (info->var.bits_per_pixel) {
-+ case 16:
-+ if (info->var.red.offset == 10) {
-+ /* 1:5:5:5 */
-+ ((u32*) (info->pseudo_palette))[regno] =
-+ ((red & 0xf800) >> 1) |
-+ ((green & 0xf800) >> 6) |
-+ ((blue & 0xf800) >> 11);
-+ } else {
-+ /* 0:5:6:5 */
-+ ((u32*) (info->pseudo_palette))[regno] =
-+ ((red & 0xf800) ) |
-+ ((green & 0xfc00) >> 5) |
-+ ((blue & 0xf800) >> 11);
-+ }
-+ break;
-+
-+ case 24:
-+ case 32:
-+ red >>= 8;
-+ green >>= 8;
-+ blue >>= 8;
-+ ((u32 *)(info->pseudo_palette))[regno] =
-+ (red << info->var.red.offset) |
-+ (green << info->var.green.offset) |
-+ (blue << info->var.blue.offset);
-+ break;
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int vesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
-+{
-+ struct vesafb_pal_entry *entries;
-+ int shift = 16 - info->var.green.length;
-+ int i, ret = 0;
-+
-+ if (info->var.bits_per_pixel == 8) {
-+ if (cmap->start + cmap->len > info->cmap.start +
-+ info->cmap.len || cmap->start < info->cmap.start)
-+ return -EINVAL;
-+
-+ entries = vmalloc(sizeof(struct vesafb_pal_entry) * cmap->len);
-+ if (!entries)
-+ return -ENOMEM;
-+ for (i = 0; i < cmap->len; i++) {
-+ entries[i].red = cmap->red[i] >> shift;
-+ entries[i].green = cmap->green[i] >> shift;
-+ entries[i].blue = cmap->blue[i] >> shift;
-+ entries[i].pad = 0;
-+ }
-+ ret = vesafb_setpalette(entries, cmap->len, cmap->start, info);
-+ vfree(entries);
-+ } else {
-+ /* For modes with bpp > 8, we only set the pseudo palette in
-+ * the fb_info struct. We rely on vesafb_setcolreg to do all
-+ * sanity checking. */
-+ for (i = 0; i < cmap->len; i++) {
-+ ret += vesafb_setcolreg(cmap->start + i, cmap->red[i],
-+ cmap->green[i], cmap->blue[i],
-+ 0, info);
-+ }
-+ }
-+ return ret;
-+}
-+
-+static int vesafb_set_par(struct fb_info *info)
-+{
-+ struct vesafb_par *par = (struct vesafb_par *) info->par;
-+ struct vesafb_task *tsk;
-+ struct vesafb_crtc_ib *crtc = NULL;
-+ struct vesafb_mode_ib *mode = NULL;
-+ int i, err = 0, depth = info->var.bits_per_pixel;
-+
-+ if (depth > 8 && depth != 32)
-+ depth = info->var.red.length + info->var.green.length +
-+ info->var.blue.length;
-+
-+ i = vesafb_find_vbe_mode(info->var.xres, info->var.yres, depth,
-+ VESAFB_NEED_EXACT_RES |
-+ VESAFB_NEED_EXACT_DEPTH);
-+ if (i >= 0)
-+ mode = &vbe_modes[i];
-+ else
-+ return -EINVAL;
-+
-+ vesafb_create_task (tsk);
-+ if (!tsk)
-+ return -ENOMEM;
-+ tsk->regs.eax = 0x4f02;
-+ tsk->regs.ebx = mode->mode_id | 0x4000; /* use LFB */
-+ tsk->flags = TF_CALL;
-+
-+ if (vbe_ib.vbe_version >= 0x0300 && !nocrtc &&
-+ info->var.pixclock != 0) {
-+ tsk->regs.ebx |= 0x0800; /* use CRTC data */
-+ tsk->flags |= TF_BUF_DI;
-+ crtc = kmalloc(sizeof(struct vesafb_crtc_ib), GFP_KERNEL);
-+ if (!crtc) {
-+ err = -ENOMEM;
-+ goto out;
-+ }
-+ crtc->horiz_start = info->var.xres + info->var.right_margin;
-+ crtc->horiz_end = crtc->horiz_start + info->var.hsync_len;
-+ crtc->horiz_total = crtc->horiz_end + info->var.left_margin;
-+
-+ crtc->vert_start = info->var.yres + info->var.lower_margin;
-+ crtc->vert_end = crtc->vert_start + info->var.vsync_len;
-+ crtc->vert_total = crtc->vert_end + info->var.upper_margin;
-+
-+ crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000;
-+ crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock /
-+ (crtc->vert_total * crtc->horiz_total)));
-+ crtc->flags = 0;
-+
-+ if (info->var.vmode & FB_VMODE_DOUBLE)
-+ crtc->flags |= 0x1;
-+ if (info->var.vmode & FB_VMODE_INTERLACED)
-+ crtc->flags |= 0x2;
-+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
-+ crtc->flags |= 0x4;
-+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
-+ crtc->flags |= 0x8;
-+ memcpy(&par->crtc, crtc, sizeof(struct vesafb_crtc_ib));
-+ } else
-+ memset(&par->crtc, 0, sizeof(struct vesafb_crtc_ib));
-+
-+ tsk->buf = (void*)crtc;
-+ tsk->buf_len = sizeof(struct vesafb_crtc_ib);
-+
-+ if (vesafb_queue_task (tsk)) {
-+ err = -EINVAL;
-+ goto out;
-+ }
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f) {
-+ printk(KERN_ERR "vesafb: mode switch failed (eax: 0x%lx)\n",
-+ tsk->regs.eax);
-+ err = -EINVAL;
-+ goto out;
-+ }
-+ par->mode_idx = i;
-+
-+ /* For 8bpp modes, always try to set the DAC to 8 bits. */
-+ if (vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC &&
-+ mode->bits_per_pixel <= 8) {
-+ vesafb_reset_task(tsk);
-+ tsk->flags = TF_CALL;
-+ tsk->regs.eax = 0x4f08;
-+ tsk->regs.ebx = 0x0800;
-+
-+ if (!vesafb_queue_task (tsk))
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f ||
-+ ((tsk->regs.ebx & 0xff00) >> 8) != 8) {
-+ /* We've failed to set the DAC palette format -
-+ * time to correct var. */
-+ info->var.red.length = 6;
-+ info->var.green.length = 6;
-+ info->var.blue.length = 6;
-+ }
-+ }
-+
-+ info->fix.visual = (info->var.bits_per_pixel == 8) ?
-+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-+ info->fix.line_length = mode->bytes_per_scan_line;
-+
-+ DPRINTK("set new mode %dx%d-%d (0x%x)\n",
-+ info->var.xres, info->var.yres, info->var.bits_per_pixel,
-+ mode->mode_id);
-+
-+out: if (crtc != NULL)
-+ kfree(crtc);
-+ kfree(tsk);
-+
-+ return err;
-+}
-+
-+static void vesafb_setup_var(struct fb_var_screeninfo *var, struct fb_info *info,
-+ struct vesafb_mode_ib *mode)
-+{
-+ var->xres = mode->x_res;
-+ var->yres = mode->y_res;
-+ var->xres_virtual = mode->x_res;
-+ var->yres_virtual = (ypan) ?
-+ info->fix.smem_len / mode->bytes_per_scan_line :
-+ mode->y_res;
-+ var->xoffset = 0;
-+ var->yoffset = 0;
-+ var->bits_per_pixel = mode->bits_per_pixel;
-+
-+ if (var->bits_per_pixel == 15)
-+ var->bits_per_pixel = 16;
-+
-+ if (var->bits_per_pixel > 8) {
-+ var->red.offset = mode->red_off;
-+ var->red.length = mode->red_len;
-+ var->green.offset = mode->green_off;
-+ var->green.length = mode->green_len;
-+ var->blue.offset = mode->blue_off;
-+ var->blue.length = mode->blue_len;
-+ var->transp.offset = mode->rsvd_off;
-+ var->transp.length = mode->rsvd_len;
-+
-+ DPRINTK("directcolor: size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-+ mode->rsvd_len,
-+ mode->red_len,
-+ mode->green_len,
-+ mode->blue_len,
-+ mode->rsvd_off,
-+ mode->red_off,
-+ mode->green_off,
-+ mode->blue_off);
-+ } else {
-+ var->red.offset = 0;
-+ var->green.offset = 0;
-+ var->blue.offset = 0;
-+ var->transp.offset = 0;
-+
-+ /* We're assuming that we can switch the DAC to 8 bits. If
-+ * this proves to be incorrect, we'll update the fields
-+ * later in set_par(). */
-+ if (vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) {
-+ var->red.length = 8;
-+ var->green.length = 8;
-+ var->blue.length = 8;
-+ var->transp.length = 0;
-+ } else {
-+ var->red.length = 6;
-+ var->green.length = 6;
-+ var->blue.length = 6;
-+ var->transp.length = 0;
-+ }
-+ }
-+}
-+
-+static void inline vesafb_check_limits(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ struct fb_videomode *mode;
-+
-+ if (!var->pixclock)
-+ return;
-+ if (vbe_ib.vbe_version < 0x0300) {
-+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info);
-+ return;
-+ }
-+ if (!fb_validate_mode(var, info))
-+ return;
-+ mode = fb_find_best_mode(var, &info->modelist);
-+ if (mode) {
-+ DPRINTK("find_best_mode: %d %d @ %d (vmode: %d)\n",
-+ mode->xres, mode->yres, mode->refresh, mode->vmode);
-+ if (mode->xres == var->xres && mode->yres == var->yres &&
-+ !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) {
-+ fb_videomode_to_var(var, mode);
-+ return;
-+ }
-+ }
-+ if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
-+ return;
-+ /* Use default refresh rate */
-+ var->pixclock = 0;
-+}
-+
-+static int vesafb_check_var(struct fb_var_screeninfo *var,
-+ struct fb_info *info)
-+{
-+ int match = -1;
-+ int depth = var->red.length + var->green.length + var->blue.length;
-+
-+ /* Various apps will use bits_per_pixel to set the color depth,
-+ * which is theoretically incorrect, but which we'll try to handle
-+ * here. */
-+ if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8)
-+ depth = var->bits_per_pixel;
-+ match = vesafb_find_vbe_mode(var->xres, var->yres, depth,
-+ VESAFB_NEED_EXACT_RES);
-+
-+ if (match == -1) {
-+ DPRINTK("vesafb: mode %dx%d-%d not found\n", var->xres,
-+ var->yres, depth);
-+ return -EINVAL;
-+ }
-+
-+ vesafb_setup_var(var, info, &vbe_modes[match]);
-+ DPRINTK("found mode 0x%x (%dx%d-%dbpp)\n",
-+ vbe_modes[match].mode_id, vbe_modes[match].x_res,
-+ vbe_modes[match].y_res, vbe_modes[match].depth);
-+
-+ /* Check whether we have remapped enough memory for this mode. */
-+ if (var->yres * vbe_modes[match].bytes_per_scan_line >
-+ info->fix.smem_len) {
-+ return -EINVAL;
-+ }
-+
-+ if ((var->vmode & FB_VMODE_DOUBLE) &&
-+ !(vbe_modes[match].mode_attr & 0x100))
-+ var->vmode &= ~FB_VMODE_DOUBLE;
-+ if ((var->vmode & FB_VMODE_INTERLACED) &&
-+ !(vbe_modes[match].mode_attr & 0x200))
-+ var->vmode &= ~FB_VMODE_INTERLACED;
-+ vesafb_check_limits(var, info);
-+ return 0;
-+}
-+
-+static int vesafb_open(struct fb_info *info, int user)
-+{
-+ struct vesafb_task *tsk = NULL;
-+ struct vesafb_par *par = info->par;
-+ int cnt = atomic_read(&par->ref_count);
-+
-+ if (!cnt) {
-+ vesafb_create_task(tsk);
-+ if (!tsk)
-+ goto out;
-+
-+ /* Get the VBE state buffer size. We want all available
-+ * hardware state data (CL = 0x0f). */
-+ tsk->regs.eax = 0x4f04;
-+ tsk->regs.ecx = 0x000f;
-+ tsk->regs.edx = 0x0000;
-+ tsk->flags = TF_CALL;
-+
-+ if (vesafb_queue_task(tsk))
-+ goto out;
-+
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f) {
-+ printk(KERN_WARNING "vesafb: VBE state buffer size "
-+ "cannot be determined (eax: 0x%lx)\n",
-+ tsk->regs.eax);
-+ goto out;
-+ }
-+
-+ par->vbe_state_size = 64 * (tsk->regs.ebx & 0xffff);
-+ par->vbe_state = kzalloc(par->vbe_state_size, GFP_KERNEL);
-+ if (!par->vbe_state)
-+ goto out;
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f04;
-+ tsk->regs.ecx = 0x000f;
-+ tsk->regs.edx = 0x0001;
-+ tsk->flags = TF_CALL | TF_BUF_BX | TF_RETURN_BUF;
-+ tsk->buf = (void*)(par->vbe_state);
-+ tsk->buf_len = par->vbe_state_size;
-+
-+ if (vesafb_queue_task(tsk))
-+ goto getstate_failed;
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f) {
-+ printk(KERN_WARNING "vesafb: VBE get state call "
-+ "failed (eax: 0x%lx)\n", tsk->regs.eax);
-+ goto getstate_failed;
-+ }
-+ }
-+out:
-+ atomic_inc(&par->ref_count);
-+ if (tsk)
-+ kfree(tsk);
-+ return 0;
-+
-+getstate_failed:
-+ kfree(par->vbe_state);
-+ par->vbe_state = NULL;
-+ par->vbe_state_size = 0;
-+ goto out;
-+}
-+
-+static int vesafb_release(struct fb_info *info, int user)
-+{
-+ struct vesafb_task *tsk = NULL;
-+ struct vesafb_par *par = info->par;
-+ int cnt = atomic_read(&par->ref_count);
-+
-+ if (!cnt)
-+ return -EINVAL;
-+
-+ if (cnt == 1 && par->vbe_state && par->vbe_state_size) {
-+ vesafb_create_task(tsk);
-+ if (!tsk)
-+ goto out;
-+
-+ tsk->regs.eax = 0x0003;
-+ tsk->regs.ebx = 0x0000;
-+ tsk->flags = TF_CALL;
-+
-+ if (vesafb_queue_task(tsk))
-+ goto out;
-+
-+ vesafb_wait_for_task(tsk);
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f04;
-+ tsk->regs.ecx = 0x000f;
-+ tsk->regs.edx = 0x0002;
-+ tsk->buf = (void*)(par->vbe_state);
-+ tsk->buf_len = par->vbe_state_size;
-+ tsk->flags = TF_CALL | TF_BUF_BX;
-+
-+ if (vesafb_queue_task(tsk))
-+ goto out;
-+
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f)
-+ printk(KERN_WARNING "vesafb: VBE state restore call "
-+ "failed (eax: 0x%lx)\n",
-+ tsk->regs.eax);
-+ }
-+out:
-+ atomic_dec(&par->ref_count);
-+ if (tsk)
-+ kfree(tsk);
-+ return 0;
-+}
-+
-+static int __init vesafb_probe(struct platform_device *device);
-+
-+static struct fb_ops vesafb_ops = {
-+ .owner = THIS_MODULE,
-+ .fb_open = vesafb_open,
-+ .fb_release = vesafb_release,
-+ .fb_setcolreg = vesafb_setcolreg,
-+ .fb_setcmap = vesafb_setcmap,
-+ .fb_pan_display = vesafb_pan_display,
-+ .fb_blank = vesafb_blank,
-+ .fb_fillrect = cfb_fillrect,
-+ .fb_copyarea = cfb_copyarea,
-+ .fb_imageblit = cfb_imageblit,
-+ .fb_check_var = vesafb_check_var,
-+ .fb_set_par = vesafb_set_par
-+};
-+
-+static struct platform_driver vesafb_driver = {
-+ .probe = vesafb_probe,
-+ .driver = {
-+ .name = "vesafb",
-+ },
-+};
-+
-+static struct platform_device *vesafb_device;
-+
-+#ifndef MODULE
-+int __init vesafb_setup(char *options)
-+{
-+ char *this_opt;
-+
-+ if (!options || !*options)
-+ return 0;
-+
-+ DPRINTK("options %s\n",options);
-+
-+ while ((this_opt = strsep(&options, ",")) != NULL) {
-+ if (!*this_opt) continue;
-+
-+ DPRINTK("this_opt: %s\n",this_opt);
-+
-+ if (! strcmp(this_opt, "redraw"))
-+ ypan=0;
-+ else if (! strcmp(this_opt, "ypan"))
-+ ypan=1;
-+ else if (! strcmp(this_opt, "ywrap"))
-+ ypan=2;
-+ else if (! strcmp(this_opt, "vgapal"))
-+ pmi_setpal=0;
-+ else if (! strcmp(this_opt, "pmipal"))
-+ pmi_setpal=1;
-+ else if (! strncmp(this_opt, "mtrr:", 5))
-+ mtrr = simple_strtoul(this_opt+5, NULL, 0);
-+ else if (! strcmp(this_opt, "nomtrr"))
-+ mtrr=0;
-+ else if (! strcmp(this_opt, "nocrtc"))
-+ nocrtc=1;
-+ else if (! strcmp(this_opt, "noedid"))
-+ noedid=1;
-+ else if (! strcmp(this_opt, "noblank"))
-+ blank=0;
-+ else if (! strcmp(this_opt, "gtf"))
-+ gtf=1;
-+ else if (! strncmp(this_opt, "vtotal:", 7))
-+ vram_total = simple_strtoul(this_opt + 7, NULL, 0);
-+ else if (! strncmp(this_opt, "vremap:", 7))
-+ vram_remap = simple_strtoul(this_opt + 7, NULL, 0);
-+ else if (! strncmp(this_opt, "maxhf:", 6))
-+ maxhf = simple_strtoul(this_opt + 6, NULL, 0);
-+ else if (! strncmp(this_opt, "maxvf:", 6))
-+ maxvf = simple_strtoul(this_opt + 6, NULL, 0);
-+ else if (! strncmp(this_opt, "maxclk:", 7))
-+ maxclk = simple_strtoul(this_opt + 7, NULL, 0);
-+ else if (! strncmp(this_opt, "vbemode:", 8))
-+ vbemode = simple_strtoul(this_opt + 8, NULL,0);
-+ else if (this_opt[0] >= '0' && this_opt[0] <= '9') {
-+ DPRINTK("mode_option: %s\n",this_opt);
-+ mode_option = this_opt;
-+ } else {
-+ printk(KERN_WARNING
-+ "vesafb: unrecognized option %s\n", this_opt);
-+ }
-+ }
-+
-+ return 0;
-+}
-+#endif /* !MODULE */
-+
-+static int vesafb_read_proc_modes(char *buf, char **start, off_t offset,
-+ int len, int *eof, void *private)
-+{
-+ int clen = 0, i;
-+
-+ for (i = 0; i < vbe_modes_cnt; i++) {
-+ clen += sprintf(buf + clen, "%dx%d-%d\n", vbe_modes[i].x_res,
-+ vbe_modes[i].y_res, vbe_modes[i].depth);
-+ }
-+ *start = buf + offset;
-+
-+ if (clen > offset) {
-+ clen -= offset;
-+ } else {
-+ clen = 0;
-+ }
-+ return clen;
-+}
-+
-+static int vesafb_read_proc_vbe_info(char *buf, char **start, off_t offset,
-+ int len, int *eof, void *private)
-+{
-+ int clen = 0;
-+
-+ clen += sprintf(buf + clen, "Version: %d.%d\n",
-+ ((vbe_ib.vbe_version & 0xff00) >> 8),
-+ vbe_ib.vbe_version & 0xff);
-+ clen += sprintf(buf + clen, "Vendor: %s\n",
-+ (char*)vbe_ib.oem_vendor_name_ptr);
-+ clen += sprintf(buf + clen, "Product: %s\n",
-+ (char*)vbe_ib.oem_product_name_ptr);
-+ clen += sprintf(buf + clen, "OEM rev: %s\n",
-+ (char*)vbe_ib.oem_product_rev_ptr);
-+ clen += sprintf(buf + clen, "OEM string: %s\n",
-+ (char*)vbe_ib.oem_string_ptr);
-+
-+ *start = buf + offset;
-+
-+ if (clen > offset) {
-+ clen -= offset;
-+ } else {
-+ clen = 0;
-+ }
-+ return clen;
-+}
-+
-+static int __init inline vesafb_vbe_getinfo(struct vesafb_task *tsk)
-+{
-+ tsk->regs.eax = 0x4f00;
-+ tsk->flags = TF_CALL | TF_GETVBEIB;
-+ tsk->buf = &vbe_ib;
-+ tsk->buf_len = sizeof(vbe_ib);
-+ if (vesafb_queue_task (tsk))
-+ return -EINVAL;
-+ vesafb_wait_for_task(tsk);
-+
-+ if (vbe_ib.vbe_version < 0x0200) {
-+ printk(KERN_ERR "vesafb: Sorry, pre-VBE 2.0 cards are "
-+ "not supported.\n");
-+ return -EINVAL;
-+ }
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f) {
-+ printk(KERN_ERR "vesafb: Getting mode info block failed "
-+ "(eax=0x%x)\n", (u32)tsk->regs.eax);
-+ return -EINVAL;
-+ }
-+
-+ printk(KERN_INFO "vesafb: %s, %s, %s (OEM: %s)\n",
-+ (char*)vbe_ib.oem_vendor_name_ptr,
-+ (char*)vbe_ib.oem_product_name_ptr,
-+ (char*)vbe_ib.oem_product_rev_ptr,
-+ (char*)vbe_ib.oem_string_ptr);
-+
-+ printk(KERN_INFO "vesafb: VBE version: %d.%d\n",
-+ ((vbe_ib.vbe_version & 0xff00) >> 8),
-+ vbe_ib.vbe_version & 0xff);
-+ return 0;
-+}
-+
-+static int __init inline vesafb_vbe_getmodes(struct vesafb_task *tsk)
-+{
-+ u16 *mode = 0;
-+ int off = 0;
-+
-+ /* Count available modes. */
-+ mode = (u16*)vbe_ib.mode_list_ptr;
-+ while (*mode != 0xffff) {
-+ vbe_modes_cnt++;
-+ mode++;
-+ }
-+
-+ vbe_modes = kmalloc(sizeof(struct vesafb_mode_ib)*
-+ vbe_modes_cnt, GFP_KERNEL);
-+ if (!vbe_modes)
-+ return -ENOMEM;
-+
-+ /* Get mode info for all available modes. */
-+ mode = (u16*)vbe_ib.mode_list_ptr;
-+
-+ while (*mode != 0xffff) {
-+ struct vesafb_mode_ib *mib;
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f01;
-+ tsk->regs.ecx = (u32) *mode;
-+ tsk->flags = TF_CALL | TF_RETURN_BUF | TF_BUF_DI;
-+ tsk->buf = vbe_modes+off;
-+ tsk->buf_len = sizeof(struct vesafb_mode_ib);
-+ if (vesafb_queue_task(tsk))
-+ return -EINVAL;
-+ vesafb_wait_for_task(tsk);
-+ mib = p_mode(tsk->buf);
-+ mib->mode_id = *mode;
-+
-+ /* We only want modes that are supported with the currennt
-+ * hardware configuration (D0), color (D3), graphics (D4)
-+ * and that have support for the LFB (D7). */
-+ if ((mib->mode_attr & 0x99) == 0x99 &&
-+ mib->bits_per_pixel >= 8) {
-+ off++;
-+ } else {
-+ vbe_modes_cnt--;
-+ }
-+ mode++;
-+ mib->depth = mib->red_len + mib->green_len + mib->blue_len;
-+ /* Handle 8bpp modes and modes with broken color component
-+ * lengths. */
-+ if (mib->depth == 0 ||
-+ (mib->depth == 24 && mib->bits_per_pixel == 32))
-+ mib->depth = mib->bits_per_pixel;
-+ }
-+
-+ return 0;
-+}
-+
-+static int __init inline vesafb_vbe_getpmi(struct vesafb_task *tsk)
-+{
-+ int i;
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f0a;
-+ tsk->regs.ebx = 0x0;
-+ tsk->flags = TF_CALL;
-+ if (vesafb_queue_task(tsk))
-+ return -EINVAL;
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f || tsk->regs.es < 0xc000) {
-+ pmi_setpal = ypan = 0;
-+ } else {
-+ pmi_base = (u16*)phys_to_virt(((u32)tsk->regs.es << 4) +
-+ tsk->regs.edi);
-+ pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
-+ pmi_pal = (void*)((char*)pmi_base + pmi_base[2]);
-+ printk(KERN_INFO "vesafb: protected mode interface info at "
-+ "%04x:%04x\n",
-+ (u16)tsk->regs.es, (u16)tsk->regs.edi);
-+ printk(KERN_INFO "vesafb: pmi: set display start = %p, "
-+ "set palette = %p\n", pmi_start, pmi_pal);
-+
-+ if (pmi_base[3]) {
-+ printk(KERN_INFO "vesafb: pmi: ports = ");
-+ for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++)
-+ printk("%x ",pmi_base[i]);
-+ printk("\n");
-+
-+ /*
-+ * memory areas not supported (yet?)
-+ *
-+ * Rules are: we have to set up a descriptor for the
-+ * requested memory area and pass it in the ES register
-+ * to the BIOS function.
-+ */
-+ if (pmi_base[i] != 0xffff) {
-+ printk(KERN_INFO "vesafb: can't handle memory "
-+ "requests, pmi disabled\n");
-+ ypan = pmi_setpal = 0;
-+ }
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int __init inline vesafb_vbe_getedid(struct vesafb_task *tsk,
-+ struct fb_info *info)
-+{
-+ int res = 0;
-+
-+ if (noedid || vbe_ib.vbe_version < 0x0300)
-+ return -EINVAL;
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f15;
-+ tsk->regs.ebx = 0;
-+ tsk->regs.ecx = 0;
-+ if (vesafb_queue_task(tsk))
-+ return -EINVAL;
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) != 0x004f)
-+ return -EINVAL;
-+
-+ if ((tsk->regs.ebx & 0x3) == 3) {
-+ printk(KERN_INFO "vesafb: VBIOS/hardware supports both "
-+ "DDC1 and DDC2 transfers\n");
-+ } else if ((tsk->regs.ebx & 0x3) == 2) {
-+ printk(KERN_INFO "vesafb: VBIOS/hardware supports DDC2 "
-+ "transfers\n");
-+ } else if ((tsk->regs.ebx & 0x3) == 1) {
-+ printk(KERN_INFO "vesafb: VBIOS/hardware supports DDC1 "
-+ "transfers\n");
-+ } else {
-+ printk(KERN_INFO "vesafb: VBIOS/hardware doesn't support "
-+ "DDC transfers\n");
-+ return -EINVAL;
-+ }
-+
-+ vesafb_reset_task(tsk);
-+ tsk->regs.eax = 0x4f15;
-+ tsk->regs.ebx = 1;
-+ tsk->regs.ecx = tsk->regs.edx = 0;
-+ tsk->flags = TF_CALL | TF_RETURN_BUF | TF_BUF_DI;
-+ tsk->buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
-+ tsk->buf_len = EDID_LENGTH;
-+
-+ if (vesafb_queue_task(tsk)) {
-+ res = -EINVAL;
-+ goto out;
-+ }
-+ vesafb_wait_for_task(tsk);
-+
-+ if ((tsk->regs.eax & 0xffff) == 0x004f) {
-+ fb_edid_to_monspecs(tsk->buf, &info->monspecs);
-+ fb_videomode_to_modelist(info->monspecs.modedb,
-+ info->monspecs.modedb_len, &info->modelist);
-+ if (info->monspecs.vfmax && info->monspecs.hfmax) {
-+ /* If the maximum pixel clock wasn't specified in
-+ * the EDID block, set it to 300 MHz. */
-+ if (info->monspecs.dclkmax == 0)
-+ info->monspecs.dclkmax = 300 * 1000000;
-+ info->monspecs.gtf = 1;
-+ } else {
-+ res = -EINVAL;
-+ }
-+ }
-+
-+out: kfree(tsk->buf);
-+ return res;
-+}
-+
-+static void __init inline vesafb_vbe_getmonspecs(struct vesafb_task *tsk,
-+ struct fb_info *info)
-+{
-+ struct fb_var_screeninfo var;
-+ int i;
-+ memset(&info->monspecs, 0, sizeof(struct fb_monspecs));
-+
-+ /* If we didn't get all necessary data from the EDID block,
-+ * mark it as incompatible with the GTF. */
-+ if (vesafb_vbe_getedid(tsk, info))
-+ info->monspecs.gtf = 0;
-+
-+ /* Kernel command line overrides. */
-+ if (maxclk)
-+ info->monspecs.dclkmax = maxclk * 1000000;
-+ if (maxvf)
-+ info->monspecs.vfmax = maxvf;
-+ if (maxhf)
-+ info->monspecs.hfmax = maxhf * 1000;
-+
-+ /* In case DDC transfers are not supported the user can provide
-+ * monitor limits manually. Lower limits are set to "safe" values. */
-+ if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) {
-+ info->monspecs.dclkmin = 0;
-+ info->monspecs.vfmin = 60;
-+ info->monspecs.hfmin = 29000;
-+ info->monspecs.gtf = 1;
-+ }
-+
-+ if (info->monspecs.gtf) {
-+ printk(KERN_INFO
-+ "vesafb: monitor limits: vf = %d Hz, hf = %d kHz, "
-+ "clk = %d MHz\n", info->monspecs.vfmax,
-+ (int)(info->monspecs.hfmax / 1000),
-+ (int)(info->monspecs.dclkmax / 1000000));
-+ /* Add valid VESA video modes to our modelist. */
-+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
-+ fb_videomode_to_var(&var, (struct fb_videomode *)
-+ &vesa_modes[i]);
-+ if (!fb_validate_mode(&var, info))
-+ fb_add_videomode((struct fb_videomode *)
-+ &vesa_modes[i],
-+ &info->modelist);
-+ }
-+ } else {
-+ /* Add all VESA video modes to our modelist. */
-+ fb_videomode_to_modelist((struct fb_videomode *)vesa_modes,
-+ VESA_MODEDB_SIZE, &info->modelist);
-+ printk(KERN_INFO "vesafb: no monitor limits have been set\n");
-+ }
-+ return;
-+}
-+
-+static int __init inline vesafb_vbe_init(struct fb_info *info)
-+{
-+ struct vesafb_task *tsk;
-+ int res = 0;
-+
-+ vesafb_create_task(tsk);
-+ if (!tsk)
-+ return -EINVAL;
-+ if ((res = vesafb_vbe_getinfo(tsk)) != 0)
-+ goto out;
-+ if ((res = vesafb_vbe_getmodes(tsk)) != 0)
-+ goto out;
-+ if (pmi_setpal || ypan)
-+ vesafb_vbe_getpmi(tsk);
-+
-+ INIT_LIST_HEAD(&info->modelist);
-+ vesafb_vbe_getmonspecs(tsk, info);
-+
-+out: kfree(tsk);
-+ return res;
-+}
-+
-+static int __init decode_mode(u32 *xres, u32 *yres, u32 *bpp, u32 *refresh)
-+{
-+ int len = strlen(mode_option), i, err = 0;
-+ u8 res_specified = 0, bpp_specified = 0, refresh_specified = 0,
-+ yres_specified = 0;
-+
-+ for (i = len-1; i >= 0; i--) {
-+ switch (mode_option[i]) {
-+ case '@':
-+ len = i;
-+ if (!refresh_specified && !bpp_specified &&
-+ !yres_specified) {
-+ *refresh = simple_strtoul(&mode_option[i+1],
-+ NULL, 0);
-+ refresh_specified = 1;
-+ } else
-+ goto out;
-+ break;
-+ case '-':
-+ len = i;
-+ if (!bpp_specified && !yres_specified) {
-+ *bpp = simple_strtoul(&mode_option[i+1],
-+ NULL, 0);
-+ bpp_specified = 1;
-+ } else
-+ goto out;
-+ break;
-+ case 'x':
-+ if (!yres_specified) {
-+ *yres = simple_strtoul(&mode_option[i+1],
-+ NULL, 0);
-+ yres_specified = 1;
-+ } else
-+ goto out;
-+ break;
-+ case '0'...'9':
-+ break;
-+ default:
-+ goto out;
-+ }
-+ }
-+
-+ if (i < 0 && yres_specified) {
-+ *xres = simple_strtoul(mode_option, NULL, 0);
-+ res_specified = 1;
-+ }
-+
-+out: if (!res_specified || !yres_specified) {
-+ printk(KERN_ERR "vesafb: invalid resolution, "
-+ "%s not specified\n",
-+ (!res_specified) ? "width" : "height");
-+ err = -EINVAL;
-+ }
-+
-+ return err;
-+}
-+
-+static int __init vesafb_init_set_mode(struct fb_info *info)
-+{
-+ struct fb_videomode *fbmode;
-+ struct fb_videomode mode;
-+ int i, modeid, refresh = 0;
-+ u8 refresh_specified = 0;
-+
-+ if (!mode_option)
-+ mode_option = CONFIG_FB_VESA_DEFAULT_MODE;
-+
-+ if (vbemode > 0) {
-+ for (i = 0; i < vbe_modes_cnt; i++) {
-+ if (vbe_modes[i].mode_id == vbemode) {
-+ info->var.vmode = FB_VMODE_NONINTERLACED;
-+ info->var.sync = FB_SYNC_VERT_HIGH_ACT;
-+ vesafb_setup_var(&info->var, info,
-+ &vbe_modes[i]);
-+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
-+ 60, &info->var, info);
-+ /* With pixclock set to 0, the default BIOS
-+ * timings will be used in set_par(). */
-+ info->var.pixclock = 0;
-+ modeid = i;
-+ goto out;
-+ }
-+ }
-+ printk(KERN_INFO "specified VBE mode %d not found\n",
-+ vbemode);
-+ vbemode = 0;
-+ }
-+
-+ /* Decode the mode specified on the kernel command line. We save
-+ * the depth into bits_per_pixel, which is wrong, but will work
-+ * anyway. */
-+ if (decode_mode(&info->var.xres, &info->var.yres,
-+ &info->var.bits_per_pixel, &refresh))
-+ return -EINVAL;
-+ if (refresh)
-+ refresh_specified = 1;
-+ else
-+ refresh = 60;
-+
-+ /* Look for a matching VBE mode. We can live if an exact match
-+ * cannot be found. */
-+ modeid = vesafb_find_vbe_mode(info->var.xres, info->var.yres,
-+ info->var.bits_per_pixel, 0);
-+
-+ if (modeid == -1) {
-+ return -EINVAL;
-+ } else {
-+ info->var.vmode = FB_VMODE_NONINTERLACED;
-+ info->var.sync = FB_SYNC_VERT_HIGH_ACT;
-+ vesafb_setup_var(&info->var, info, &vbe_modes[modeid]);
-+ }
-+ if (vbe_ib.vbe_version < 0x0300) {
-+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
-+ &info->var, info);
-+ goto out;
-+ }
-+ if (!gtf) {
-+ struct fb_videomode tmode;
-+
-+ if (refresh_specified) {
-+ fb_var_to_videomode(&tmode, &info->var);
-+ tmode.refresh = refresh;
-+ fbmode = fb_find_nearest_mode(&tmode,
-+ &info->modelist);
-+ } else
-+ fbmode = fb_find_best_mode(&info->var,
-+ &info->modelist);
-+
-+ if (fbmode->xres == info->var.xres &&
-+ fbmode->yres == info->var.yres &&
-+ !(fbmode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))
-+ && (!refresh_specified ||
-+ abs(refresh - fbmode->refresh) <= 5)) {
-+ fb_videomode_to_var(&info->var, fbmode);
-+ return modeid;
-+ }
-+ }
-+ i = FB_MAXTIMINGS;
-+ if (!info->monspecs.gtf)
-+ i = FB_IGNOREMON | FB_VSYNCTIMINGS;
-+ else if (refresh_specified)
-+ i = FB_VSYNCTIMINGS;
-+ if (!fb_get_mode(i, refresh, &info->var, info))
-+ goto out;
-+ if (info->monspecs.gtf &&
-+ !fb_get_mode(FB_MAXTIMINGS, 0, &info->var, info))
-+ goto out;
-+ /* Use default refresh rate */
-+ printk(KERN_WARNING "vesafb: using default BIOS refresh rate\n");
-+ info->var.pixclock = 0;
-+
-+out:
-+ fb_var_to_videomode(&mode, &info->var);
-+ fb_add_videomode(&mode, &info->modelist);
-+ return modeid;
-+}
-+
-+static int __init vesafb_probe(struct platform_device *dev)
-+{
-+ char entry[16];
-+ struct fb_info *info;
-+ struct vesafb_mode_ib *mode = NULL;
-+ int err = 0, i, h;
-+ unsigned int size_vmode;
-+ unsigned int size_remap;
-+ unsigned int size_total;
-+
-+ vesafb_info = info = framebuffer_alloc(sizeof(struct vesafb_par) +
-+ sizeof(u32) * 256, &dev->dev);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ if (vesafb_wait_for_thread()) {
-+ printk(KERN_ERR "vesafb: vesafb thread not running\n");
-+ framebuffer_release(info);
-+ return -EINVAL;
-+ }
-+
-+ if (vesafb_vbe_init(info)) {
-+ printk(KERN_ERR "vesafb: vbe_init failed\n");
-+ err = -EINVAL;
-+ goto out;
-+ }
-+
-+ vesafb_fix.ypanstep = ypan ? 1 : 0;
-+ vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0;
-+
-+ info->pseudo_palette = ((u8*)info->par + sizeof(struct vesafb_par));
-+ info->fbops = &vesafb_ops;
-+ info->var = vesafb_defined;
-+ info->fix = vesafb_fix;
-+
-+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
-+ err = -ENXIO;
-+ goto out;
-+ }
-+
-+ i = vesafb_init_set_mode(info);
-+ if (i < 0) {
-+ err = -EINVAL;
-+ goto out_cmap;
-+ } else
-+ mode = &vbe_modes[i];
-+
-+ /* Disable blanking if the user requested so. */
-+ if (!blank) {
-+ info->fbops->fb_blank = NULL;
-+ }
-+
-+ /* Find out how much IO memory is required for the mode with
-+ * the highest resolution. */
-+ size_remap = 0;
-+ for (i = 0; i < vbe_modes_cnt; i++) {
-+ h = vbe_modes[i].bytes_per_scan_line * vbe_modes[i].y_res;
-+ if (h > size_remap)
-+ size_remap = h;
-+ }
-+ size_remap *= 2;
-+
-+ /* size_vmode -- that is the amount of memory needed for the
-+ * used video mode, i.e. the minimum amount of
-+ * memory we need. */
-+ if (mode != NULL) {
-+ size_vmode = info->var.yres * mode->bytes_per_scan_line;
-+ } else {
-+ size_vmode = info->var.yres * info->var.xres *
-+ ((info->var.bits_per_pixel + 7) >> 3);
-+ }
-+
-+ /* size_total -- all video memory we have. Used for mtrr
-+ * entries, ressource allocation and bounds
-+ * checking. */
-+ size_total = vbe_ib.total_memory * 65536;
-+ if (vram_total)
-+ size_total = vram_total * 1024 * 1024;
-+ if (size_total < size_vmode)
-+ size_total = size_vmode;
-+ ((struct vesafb_par*)(info->par))->mem_total = size_total;
-+
-+ /* size_remap -- the amount of video memory we are going to
-+ * use for vesafb. With modern cards it is no
-+ * option to simply use size_total as th
-+ * wastes plenty of kernel address space. */
-+ if (vram_remap)
-+ size_remap = vram_remap * 1024 * 1024;
-+ if (size_remap < size_vmode)
-+ size_remap = size_vmode;
-+ if (size_remap > size_total)
-+ size_remap = size_total;
-+
-+ info->fix.smem_len = size_remap;
-+ info->fix.smem_start = mode->phys_base_ptr;
-+
-+ /* We have to set it here, because when setup_var() was called,
-+ * smem_len wasn't defined yet. */
-+ info->var.yres_virtual = info->fix.smem_len /
-+ mode->bytes_per_scan_line;
-+
-+ if (ypan && info->var.yres_virtual > info->var.yres) {
-+ printk(KERN_INFO "vesafb: scrolling: %s "
-+ "using protected mode interface, "
-+ "yres_virtual=%d\n",
-+ (ypan > 1) ? "ywrap" : "ypan",info->var.yres_virtual);
-+ } else {
-+ printk(KERN_INFO "vesafb: scrolling: redraw\n");
-+ info->var.yres_virtual = info->var.yres;
-+ ypan = 0;
-+ }
-+
-+ info->flags = FBINFO_FLAG_DEFAULT |
-+ (ypan) ? FBINFO_HWACCEL_YPAN : 0;
-+
-+ if (!ypan)
-+ info->fbops->fb_pan_display = NULL;
-+
-+ if (!request_mem_region(info->fix.smem_start, size_total, "vesafb")) {
-+ printk(KERN_WARNING "vesafb: cannot reserve video memory at "
-+ "0x%lx\n", info->fix.smem_start);
-+ /* We cannot make this fatal. Sometimes this comes from magic
-+ spaces our resource handlers simply don't know about. */
-+ }
-+
-+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
-+
-+ if (!info->screen_base) {
-+ printk(KERN_ERR
-+ "vesafb: abort, cannot ioremap video memory "
-+ "0x%x @ 0x%lx\n",
-+ info->fix.smem_len, info->fix.smem_start);
-+ err = -EIO;
-+ goto out_mem;
-+ }
-+
-+ /* Request failure does not faze us, as vgacon probably has this
-+ region already (FIXME) */
-+ request_region(0x3c0, 32, "vesafb");
-+
-+#ifdef CONFIG_MTRR
-+ if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
-+ int temp_size = size_total;
-+ unsigned int type = 0;
-+
-+ switch (mtrr) {
-+ case 1:
-+ type = MTRR_TYPE_UNCACHABLE;
-+ break;
-+ case 2:
-+ type = MTRR_TYPE_WRBACK;
-+ break;
-+ case 3:
-+ type = MTRR_TYPE_WRCOMB;
-+ break;
-+ case 4:
-+ type = MTRR_TYPE_WRTHROUGH;
-+ break;
-+ default:
-+ type = 0;
-+ break;
-+ }
-+
-+ if (type) {
-+ int rc;
-+
-+ /* Find the largest power-of-two */
-+ while (temp_size & (temp_size - 1))
-+ temp_size &= (temp_size - 1);
-+
-+ /* Try and find a power of two to add */
-+ do {
-+ rc = mtrr_add(info->fix.smem_start,
-+ temp_size, type, 1);
-+ temp_size >>= 1;
-+ } while (temp_size >= PAGE_SIZE && rc == -EINVAL);
-+ }
-+ }
-+#endif /* CONFIG_MTRR */
-+
-+ if (register_framebuffer(info) < 0) {
-+ printk(KERN_ERR
-+ "vesafb: failed to register framebuffer device\n");
-+ err = -EINVAL;
-+ goto out_mem;
-+ }
-+
-+ printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, "
-+ "using %dk, total %dk\n", info->fix.smem_start,
-+ info->screen_base, size_remap/1024, size_total/1024);
-+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
-+ info->fix.id);
-+
-+ sprintf(entry, "fb%d", info->node);
-+ proc_mkdir(entry, 0);
-+
-+ sprintf(entry, "fb%d/modes", info->node);
-+ create_proc_read_entry(entry, 0, 0, vesafb_read_proc_modes, NULL);
-+
-+ sprintf(entry, "fb%d/vbe_info", info->node);
-+ create_proc_read_entry(entry, 0, 0, vesafb_read_proc_vbe_info, NULL);
-+ return 0;
-+
-+out_mem:
-+ release_mem_region(info->fix.smem_start, size_total);
-+ if (!list_empty(&info->modelist))
-+ fb_destroy_modelist(&info->modelist);
-+ fb_destroy_modedb(info->monspecs.modedb);
-+out_cmap:
-+ fb_dealloc_cmap(&info->cmap);
-+out:
-+ framebuffer_release(info);
-+ vesafb_info = NULL;
-+ kfree(vbe_modes);
-+ vbe_modes = NULL;
-+ return err;
-+}
-+
-+int __init vesafb_init(void)
-+{
-+ int ret;
-+#ifndef MODULE
-+ char *option = NULL;
-+
-+ if (fb_get_options("vesafb", &option))
-+ return -ENODEV;
-+ vesafb_setup(option);
-+#endif
-+ ret = platform_driver_register(&vesafb_driver);
-+
-+ if (!ret) {
-+ vesafb_device = platform_device_alloc("vesafb", 0);
-+
-+ if (vesafb_device)
-+ ret = platform_device_add(vesafb_device);
-+ else
-+ ret = -ENOMEM;
-+
-+ if (ret) {
-+ platform_device_put(vesafb_device);
-+ platform_driver_unregister(&vesafb_driver);
-+ }
-+ }
-+ return ret;
-+}
-+
-+module_init(vesafb_init);
-+
-+#ifdef MODULE
-+void __exit vesafb_exit(void)
-+{
-+ char entry[16];
-+
-+ if (vesafb_info)
-+ unregister_framebuffer(vesafb_info);
-+
-+ platform_device_unregister(vesafb_device);
-+ platform_driver_unregister(&vesafb_driver);
-+
-+ if (vesafb_info) {
-+ struct vesafb_par *par = (struct vesafb_par*)vesafb_info->par;
-+
-+ sprintf(entry, "fb%d/modes", vesafb_info->node);
-+ remove_proc_entry(entry, NULL);
-+
-+ sprintf(entry, "fb%d/vbe_info", vesafb_info->node);
-+ remove_proc_entry(entry, NULL);
-+
-+ sprintf(entry, "fb%d", vesafb_info->node);
-+ remove_proc_entry(entry, NULL);
-+
-+ iounmap(vesafb_info->screen_base);
-+ release_mem_region(vesafb_info->fix.smem_start,
-+ par->mem_total);
-+ fb_dealloc_cmap(&vesafb_info->cmap);
-+ if (!list_empty(&vesafb_info->modelist))
-+ fb_destroy_modelist(&vesafb_info->modelist);
-+ fb_destroy_modedb(vesafb_info->monspecs.modedb);
-+ framebuffer_release(vesafb_info);
-+ }
-+
-+ if (vbe_modes != NULL)
-+ kfree(vbe_modes);
-+}
-+
-+module_exit(vesafb_exit);
-+
-+static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
-+{
-+ return 0;
-+}
-+static inline int param_set_scroll(const char *val, struct kernel_param *kp)
-+{
-+ ypan = 0;
-+
-+ if (! strcmp(val, "redraw"))
-+ ypan = 0;
-+ else if (! strcmp(val, "ypan"))
-+ ypan = 1;
-+ else if (! strcmp(val, "ywrap"))
-+ ypan = 2;
-+
-+ return 0;
-+}
-+
-+#define param_check_scroll(name, p) __param_check(name, p, void);
-+
-+module_param_named(scroll, ypan, scroll, 0);
-+MODULE_PARM_DESC(scroll,"Scrolling mode, set to 'redraw', 'ypan' or 'ywrap'");
-+module_param_named(vgapal, pmi_setpal, invbool, 0);
-+MODULE_PARM_DESC(vgapal,"bool: set palette using VGA registers");
-+module_param_named(pmipal, pmi_setpal, bool, 0);
-+MODULE_PARM_DESC(pmipal,"bool: set palette using PMI calls");
-+module_param_named(nomtrr, mtrr, invbool, 0);
-+MODULE_PARM_DESC(nomtrr,"bool: disable use of MTRR registers");
-+module_param(blank, bool, 1);
-+MODULE_PARM_DESC(blank,"bool: enable hardware blanking");
-+module_param(nocrtc, bool, 0);
-+MODULE_PARM_DESC(nocrtc,"bool: ignore CRTC timings when setting modes");
-+module_param(noedid, bool, 0);
-+MODULE_PARM_DESC(noedid,"bool: ignore EDID-provided monitor limits "
-+ "when setting modes");
-+module_param(gtf, bool, 0);
-+MODULE_PARM_DESC(gtf,"bool: force use of VESA GTF to calculate mode timings");
-+module_param(vram_remap, uint, 0);
-+MODULE_PARM_DESC(vram_remap,"Set amount of video memory to be used [MiB]");
-+module_param(vram_total, uint, 0);
-+MODULE_PARM_DESC(vram_total,"Set total amount of video memoery [MiB]");
-+module_param(maxclk, ushort, 0);
-+MODULE_PARM_DESC(maxclk,"Maximum pixelclock [MHz], overrides EDID data");
-+module_param(maxhf, ushort, 0);
-+MODULE_PARM_DESC(maxhf,"Maximum horizontal frequency [kHz], "
-+ "overrides EDID data");
-+module_param(maxvf, ushort, 0);
-+MODULE_PARM_DESC(maxvf,"Maximum vertical frequency [Hz], "
-+ "overrides EDID data");
-+module_param_named(mode, mode_option, charp, 0);
-+MODULE_PARM_DESC(mode, "Specify resolution as "
-+ "\"<xres>x<yres>[-<bpp>][@<refresh>]\"");
-+module_param(vbemode, ushort, 0);
-+MODULE_PARM_DESC(vbemode,"VBE mode number to set, overrides 'mode' setting");
-+
-+#endif /* MODULE */
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Michal Januszewski");
-+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards");
-+
---- linux-2.6.17.orig/include/linux/sched.h
-+++ linux-2.6.17/include/linux/sched.h
-@@ -1159,6 +1159,8 @@ extern void mmput(struct mm_struct *);
- extern struct mm_struct *get_task_mm(struct task_struct *task);
- /* Remove the current tasks stale references to the old mm_struct */
- extern void mm_release(struct task_struct *, struct mm_struct *);
-+/* Create a new mm for a kernel thread */
-+extern int set_new_mm(void);
-
- extern int copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
- extern void flush_thread(void);
---- /dev/null
-+++ linux-2.6.17/include/video/vesa.h
-@@ -0,0 +1,150 @@
-+#if 0
-+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , \
-+ ## args)
-+#else
-+#define DPRINTK(fmt, args...)
-+#endif
-+
-+#define p_crtc(arg) ((struct vesafb_crtc_ib*)(arg))
-+#define p_vbe(arg) ((struct vesafb_vbe_ib*)(arg))
-+#define p_mode(arg) ((struct vesafb_mode_ib*)(arg))
-+
-+struct vesafb_task {
-+ u8 flags;
-+ void *buf;
-+ int buf_len;
-+ struct vm86_regs regs;
-+ struct list_head node;
-+ struct completion done;
-+};
-+
-+/* Vesafb task flags and masks */
-+#define TF_CALL 0x00
-+#define TF_EXIT 0x01
-+#define TF_GETVBEIB 0x02
-+#define TF_BUF_DI 0x04
-+#define TF_BUF_BX 0x08
-+#define TF_RETURN_BUF 0x10
-+
-+/* Macros and functions for manipulating vesafb tasks */
-+#define vesafb_create_task(task) \
-+do { \
-+ task = kmalloc(sizeof(struct vesafb_task), GFP_ATOMIC); \
-+ if (task) \
-+ memset(task, 0, sizeof(struct vesafb_task)); \
-+ init_completion(&task->done); \
-+} while (0)
-+
-+#define vesafb_wait_for_task(task) wait_for_completion(&task->done);
-+#define vesafb_reset_task(task) init_completion(&task->done);
-+int vesafb_queue_task(struct vesafb_task *task);
-+
-+/* Functions for controlling the vesafb thread */
-+int vesafb_wait_for_thread(void);
-+
-+#define VBE_CAP_CAN_SWITCH_DAC 0x01
-+#define VBE_CAP_VGACOMPAT 0x02
-+
-+/* This struct is 512 bytes long */
-+struct vesafb_vbe_ib {
-+ char vbe_signature[4];
-+ u16 vbe_version;
-+ u32 oem_string_ptr;
-+ u32 capabilities;
-+ u32 mode_list_ptr;
-+ u16 total_memory;
-+ u16 oem_software_rev;
-+ u32 oem_vendor_name_ptr;
-+ u32 oem_product_name_ptr;
-+ u32 oem_product_rev_ptr;
-+ u8 reserved[222];
-+ char oem_data[256];
-+} __attribute__ ((packed));
-+
-+struct vesafb_crtc_ib {
-+ u16 horiz_total;
-+ u16 horiz_start;
-+ u16 horiz_end;
-+ u16 vert_total;
-+ u16 vert_start;
-+ u16 vert_end;
-+ u8 flags;
-+ u32 pixel_clock;
-+ u16 refresh_rate;
-+ u8 reserved[40];
-+} __attribute__ ((packed));
-+
-+#define VBE_MODE_VGACOMPAT 0x20
-+
-+struct vesafb_mode_ib {
-+ /* for all VBE revisions */
-+ u16 mode_attr;
-+ u8 winA_attr;
-+ u8 winB_attr;
-+ u16 win_granularity;
-+ u16 win_size;
-+ u16 winA_seg;
-+ u16 winB_seg;
-+ u32 win_func_ptr;
-+ u16 bytes_per_scan_line;
-+
-+ /* for VBE 1.2+ */
-+ u16 x_res;
-+ u16 y_res;
-+ u8 x_char_size;
-+ u8 y_char_size;
-+ u8 planes;
-+ u8 bits_per_pixel;
-+ u8 banks;
-+ u8 memory_model;
-+ u8 bank_size;
-+ u8 image_pages;
-+ u8 reserved1;
-+
-+ /* Direct color fields for direct/6 and YUV/7 memory models. */
-+ /* Offsets are bit positions of lsb in the mask. */
-+ u8 red_len;
-+ u8 red_off;
-+ u8 green_len;
-+ u8 green_off;
-+ u8 blue_len;
-+ u8 blue_off;
-+ u8 rsvd_len;
-+ u8 rsvd_off;
-+ u8 direct_color_info; /* direct color mode attributes */
-+
-+ /* for VBE 2.0+ */
-+ u32 phys_base_ptr;
-+ u8 reserved2[6];
-+
-+ /* for VBE 3.0+ */
-+ u16 lin_bytes_per_scan_line;
-+ u8 bnk_image_pages;
-+ u8 lin_image_pages;
-+ u8 lin_red_len;
-+ u8 lin_red_off;
-+ u8 lin_green_len;
-+ u8 lin_green_off;
-+ u8 lin_blue_len;
-+ u8 lin_blue_off;
-+ u8 lin_rsvd_len;
-+ u8 lin_rsvd_off;
-+ u32 max_pixel_clock;
-+ u16 mode_id;
-+ u8 depth;
-+} __attribute__ ((packed));
-+
-+struct vesafb_pal_entry {
-+ u_char blue, green, red, pad;
-+} __attribute__ ((packed));
-+
-+struct vesafb_par {
-+ u8 *vbe_state;
-+ int vbe_state_size;
-+ atomic_t ref_count;
-+
-+ u32 mem_total;
-+ int mode_idx;
-+ struct vesafb_crtc_ib crtc;
-+};
-+
---- linux-2.6.17.orig/kernel/fork.c
-+++ linux-2.6.17/kernel/fork.c
-@@ -97,6 +97,7 @@ kmem_cache_t *fs_cachep;
-
- /* SLAB cache for vm_area_struct structures */
- kmem_cache_t *vm_area_cachep;
-+EXPORT_SYMBOL_GPL(vm_area_cachep);
-
- /* SLAB cache for mm_struct structures (tsk->mm) */
- static kmem_cache_t *mm_cachep;
-@@ -383,6 +384,40 @@ void mmput(struct mm_struct *mm)
- EXPORT_SYMBOL_GPL(mmput);
-
- /**
-+ * set_new_mm - allocate, init and activate a new mm for a kernel thread
-+ */
-+int set_new_mm(void)
-+{
-+ struct mm_struct *mm;
-+ struct task_struct *tsk = current;
-+ struct mm_struct *active_mm;
-+
-+ mm = mm_alloc();
-+ if (!mm)
-+ goto fail_nomem;
-+ if (init_new_context(current,mm))
-+ goto fail_nocontext;
-+
-+ task_lock(tsk);
-+ tsk->flags |= PF_BORROWED_MM;
-+ active_mm = tsk->active_mm;
-+ current->mm = mm;
-+ current->active_mm = mm;
-+ activate_mm(active_mm, mm);
-+ task_unlock(current);
-+
-+ /* Drop the previous active_mm */
-+ mmdrop(active_mm);
-+ return 0;
-+
-+fail_nocontext:
-+ mmdrop(mm);
-+fail_nomem:
-+ return -EINVAL;
-+}
-+EXPORT_SYMBOL_GPL(set_new_mm);
-+
-+/**
- * get_task_mm - acquire a reference to the task's mm
- *
- * Returns %NULL if the task has no mm. Checks PF_BORROWED_MM (meaning
---- linux-2.6.17.orig/mm/memory.c
-+++ linux-2.6.17/mm/memory.c
-@@ -1162,6 +1162,7 @@ int zeromap_page_range(struct vm_area_st
- } while (pgd++, addr = next, addr != end);
- return err;
- }
-+EXPORT_SYMBOL_GPL(zeromap_page_range);
-
- pte_t * fastcall get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl)
- {
---- linux-2.6.17.orig/mm/mmap.c
-+++ linux-2.6.17/mm/mmap.c
-@@ -1996,6 +1996,7 @@ int insert_vm_struct(struct mm_struct *
- vma_link(mm, vma, prev, rb_link, rb_parent);
- return 0;
- }
-+EXPORT_SYMBOL_GPL(insert_vm_struct);
-
- /*
- * Copy the vma structure to a new location in the same mm,