diff options
Diffstat (limited to 'packages/linux/linux-rp-2.6.22/vesafb-tng-1.0-rc2-2.6.20-rc2.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.22/vesafb-tng-1.0-rc2-2.6.20-rc2.patch | 3141 |
1 files changed, 0 insertions, 3141 deletions
diff --git a/packages/linux/linux-rp-2.6.22/vesafb-tng-1.0-rc2-2.6.20-rc2.patch b/packages/linux/linux-rp-2.6.22/vesafb-tng-1.0-rc2-2.6.20-rc2.patch deleted file mode 100644 index b1b0fc3549..0000000000 --- a/packages/linux/linux-rp-2.6.22/vesafb-tng-1.0-rc2-2.6.20-rc2.patch +++ /dev/null @@ -1,3141 +0,0 @@ -diff --git a/Documentation/fb/vesafb.txt b/Documentation/fb/vesafb.txt -index ee277dd..93d6e6e 100644 ---- a/Documentation/fb/vesafb.txt -+++ b/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 are: - - | 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 BIOS which does not. VESA BIOS - 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 is non-accelerated. Running - 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. -+ -+If you want to use the default BIOS refresh rate while switching modes -+on a running system, set pixclock to 0. - -- * 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 -+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. -- --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" -- --Accepted options: -- --invers no comment... -- --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). -- --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. -- -- --vgapal Use the standard vga registers for palette changes. -- This is the default. --pmipal Use the protected mode interface for palette changes. -- --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". -+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 a comma, like this: -+"video=vesafb:ypan,1024x768-32@85" -+ -+Note that vesafb-tng still uses the "video=vesafb:option" format of the -+kernel command line video parameter. "video=vesafb-tng:xxx" is incorrect. -+ -+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 -+ 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. -+ -+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. -+ -+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 -+ -+ 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: -+ -+<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). - -- Gerd -+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> -+ -diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S -index 2c5b5cc..2c2d4b5 100644 ---- a/arch/i386/boot/video.S -+++ b/arch/i386/boot/video.S -@@ -163,10 +163,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 -@@ -199,6 +201,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 -@@ -281,6 +284,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: -@@ -495,10 +499,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 - -@@ -570,6 +576,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 -@@ -603,6 +610,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 -diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c -index 1393523..8a05f95 100644 ---- a/drivers/char/sysrq.c -+++ b/drivers/char/sysrq.c -@@ -240,7 +240,7 @@ static void send_sig_all(int sig) - struct task_struct *p; - - for_each_process(p) { -- if (p->mm && !is_init(p)) -+ if (p->mm && !is_init(p) && !(p->flags & PF_BORROWED_MM)) - /* Not swapper, init nor kernel thread */ - force_sig(sig, p); - } -diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 4e83f01..ae122fd 100644 ---- a/drivers/video/Kconfig -+++ b/drivers/video/Kconfig -@@ -547,8 +547,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 -@@ -557,7 +571,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 an enhanced generic frame buffer device driver for -+ VBE 2.0 compliant graphic cards. It can take advantage of VBE 3.0 -+ features (refresh rate adjustment) when these are available. -+ The driver also makes it possible to change the video mode -+ on the fly and to switch back to text mode when it's unloaded. -+ -+ If the driver is compiled as a module, the module will be called -+ vesafb-tng. -+ -+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 FB_IMAC - bool "Intel-based Macintosh Framebuffer Support" -diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index 309a26d..e57b0e7 100644 ---- a/drivers/video/Makefile -+++ b/drivers/video/Makefile -@@ -102,7 +102,11 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ - obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.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_IMAC) += imacfb.o - obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o - obj-$(CONFIG_FB_OF) += offb.o -diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c -index 3cfea31..bfb39cc 100644 ---- a/drivers/video/fbmem.c -+++ b/drivers/video/fbmem.c -@@ -1408,6 +1408,7 @@ fbmem_init(void) - printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); - fb_class = NULL; - } -+ - return 0; - } - -diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c -index 5df41f6..f838a53 100644 ---- a/drivers/video/modedb.c -+++ b/drivers/video/modedb.c -@@ -674,6 +674,7 @@ void fb_var_to_videomode(struct fb_videomode *mode, - { - u32 pixclock, hfreq, htotal, vtotal; - -+ mode->refresh = 0; - mode->name = NULL; - mode->xres = var->xres; - mode->yres = var->yres; -@@ -1025,3 +1026,4 @@ EXPORT_SYMBOL(fb_find_best_mode); - EXPORT_SYMBOL(fb_find_nearest_mode); - EXPORT_SYMBOL(fb_videomode_to_modelist); - EXPORT_SYMBOL(fb_find_mode); -+EXPORT_SYMBOL(fb_destroy_modelist); -diff --git a/drivers/video/vesafb-thread.c b/drivers/video/vesafb-thread.c -new file mode 100644 -index 0000000..543e202 ---- /dev/null -+++ b/drivers/video/vesafb-thread.c -@@ -0,0 +1,751 @@ -+/* -+ * Framebuffer driver for VBE 2.0+ compliant graphic boards. -+ * Kernel thread and vm86 routines. -+ * -+ * (c) 2004-2006 Michal Januszewski <spock@gentoo.org> -+ * -+ */ -+ -+#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/freezer.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" -+ -+static int errno; -+ -+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; -+ -+#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) -+ -+/* Syscalls used by the vesafb thread */ -+static int vm86old(struct vm86_struct __user* v86) -+{ -+ long res; -+ __asm__ volatile ("push %%ebx; movl %2, %%ebx ; int $0x80 ; pop %%ebx" -+ : "=a" (res) -+ : "0" (__NR_vm86old), "ri" ((long)(v86)) : "memory"); -+ -+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { -+ errno = -res; -+ res = -1; -+ } -+ return (int)res; -+} -+ -+static int ioperm(unsigned long a, unsigned long b, unsigned long c) -+{ -+ long res; -+ __asm__ volatile ("push %%ebx; movl %2, %%ebx ; int $0x80 ; pop %%ebx" -+ : "=a" (res) -+ : "0" (__NR_ioperm), "ri" ((long)(a)), "c" ((long)(b)), -+ "d" ((long)(c)) : "memory"); -+ -+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { -+ errno = -res; -+ res = -1; -+ } -+ return (int)res; -+} -+ -+/* 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, GFP_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"); -+ -diff --git a/drivers/video/vesafb-tng.c b/drivers/video/vesafb-tng.c -new file mode 100644 -index 0000000..b4d4394 ---- /dev/null -+++ b/drivers/video/vesafb-tng.c -@@ -0,0 +1,1586 @@ -+/* -+ * 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 += min(snprintf(buf + clen, len - clen, "%dx%d-%d\n", vbe_modes[i].x_res, -+ vbe_modes[i].y_res, vbe_modes[i].depth), len - clen); -+ } -+ *eof = 1; -+ 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 += min(snprintf(buf + clen, len, "Version: %d.%d\n", -+ ((vbe_ib.vbe_version & 0xff00) >> 8), -+ vbe_ib.vbe_version & 0xff), len); -+ clen += min(snprintf(buf + clen, len - clen, "Vendor: %s\n", -+ (char*)vbe_ib.oem_vendor_name_ptr), len - clen); -+ clen += min(snprintf(buf + clen, len - clen, "Product: %s\n", -+ (char*)vbe_ib.oem_product_name_ptr), len - clen); -+ clen += min(snprintf(buf + clen, len - clen, "OEM rev: %s\n", -+ (char*)vbe_ib.oem_product_rev_ptr), len - clen); -+ clen += min(snprintf(buf + clen, len - clen, "OEM string: %s\n", -+ (char*)vbe_ib.oem_string_ptr), len - clen); -+ -+ *eof = 1; -+ 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(mtrr, uint, 0); -+MODULE_PARM_DESC(mtrr,"Memory Type Range Registers setting. Use 0 to disable."); -+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"); -+ -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 4463735..7283e48 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -1390,6 +1390,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); -diff --git a/include/video/vesa.h b/include/video/vesa.h -new file mode 100644 -index 0000000..bb5abcf ---- /dev/null -+++ b/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; -+}; -+ -diff --git a/kernel/fork.c b/kernel/fork.c -index fc723e5..dc8f93b 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -100,6 +100,7 @@ struct kmem_cache *fs_cachep; - - /* SLAB cache for vm_area_struct structures */ - struct kmem_cache *vm_area_cachep; -+EXPORT_SYMBOL_GPL(vm_area_cachep); - - /* SLAB cache for mm_struct structures (tsk->mm) */ - static struct kmem_cache *mm_cachep; -@@ -399,6 +400,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 -diff --git a/mm/memory.c b/mm/memory.c -index 563792f..a9519ea 100644 ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -1193,6 +1193,7 @@ int zeromap_page_range(struct vm_area_struct *vma, - } 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) - { -diff --git a/mm/mmap.c b/mm/mmap.c -index 9717337..6fa5b1c 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -2024,6 +2024,7 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) - 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, |