| 1 |
# This is a BitKeeper generated diff -Nru style patch. |
| 2 |
# |
| 3 |
# ChangeSet |
| 4 |
# 2005/01/15 14:00:12+01:00 spock@spock.one.pl |
| 5 |
# Made video option parsing more fool-proof, fixed delayed console switches for people using the 'redraw' option, fixed a MTRR problem. |
| 6 |
# |
| 7 |
# drivers/video/vesafb-tng.c |
| 8 |
# 2005/01/15 14:00:02+01:00 spock@spock.one.pl +6 -7 |
| 9 |
# Made video option parsing more fool-proof, fixed delayed console switches for people using the 'redraw' option, fixed a MTRR problem. |
| 10 |
# |
| 11 |
# ChangeSet |
| 12 |
# 2005/01/12 19:50:57+01:00 spock@spock.one.pl |
| 13 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 14 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 15 |
# |
| 16 |
# drivers/video/fbmem.c |
| 17 |
# 2005/01/12 19:50:29+01:00 spock@spock.one.pl +0 -0 |
| 18 |
# Auto merged |
| 19 |
# |
| 20 |
# ChangeSet |
| 21 |
# 2005/01/05 14:46:25+01:00 spock@spock.one.pl |
| 22 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 23 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 24 |
# |
| 25 |
# drivers/video/fbmem.c |
| 26 |
# 2005/01/05 14:46:03+01:00 spock@spock.one.pl +0 -0 |
| 27 |
# Auto merged |
| 28 |
# |
| 29 |
# ChangeSet |
| 30 |
# 2004/12/18 15:53:56+01:00 spock@spock.one.pl |
| 31 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 32 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 33 |
# |
| 34 |
# drivers/video/fbmem.c |
| 35 |
# 2004/12/18 15:53:33+01:00 spock@spock.one.pl +0 -0 |
| 36 |
# Auto merged |
| 37 |
# |
| 38 |
# ChangeSet |
| 39 |
# 2004/11/22 15:44:23+01:00 spock@spock.one.pl |
| 40 |
# Fixed compilation warnings (remap_page_range -> io_remap_page_range). |
| 41 |
# |
| 42 |
# drivers/video/vesafb-thread.c |
| 43 |
# 2004/11/22 15:44:08+01:00 spock@spock.one.pl +2 -2 |
| 44 |
# Fixed compilation warnings (remap_page_range -> io_remap_page_range). |
| 45 |
# |
| 46 |
# ChangeSet |
| 47 |
# 2004/11/21 14:18:54+01:00 spock@spock.one.pl |
| 48 |
# Only use fb_get_options() if vesafb-tng is compiled into the kernel. |
| 49 |
# |
| 50 |
# drivers/video/vesafb-tng.c |
| 51 |
# 2004/11/21 14:15:09+01:00 spock@spock.one.pl +4 -2 |
| 52 |
# Only use fb_get_options() if vesafb-tng is compiled into the kernel. |
| 53 |
# |
| 54 |
# ChangeSet |
| 55 |
# 2004/11/21 10:52:50+01:00 spock@spock.one.pl |
| 56 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 57 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 58 |
# |
| 59 |
# drivers/video/fbmem.c |
| 60 |
# 2004/11/21 10:52:33+01:00 spock@spock.one.pl +0 -0 |
| 61 |
# Auto merged |
| 62 |
# |
| 63 |
# ChangeSet |
| 64 |
# 2004/11/01 19:28:20+01:00 spock@spock.one.pl |
| 65 |
# Fixed partially broken mode-matching code. |
| 66 |
# |
| 67 |
# drivers/video/vesafb-tng.c |
| 68 |
# 2004/11/01 19:10:52+01:00 spock@spock.one.pl +18 -7 |
| 69 |
# Fixed partially broken mode-matching code. |
| 70 |
# |
| 71 |
# ChangeSet |
| 72 |
# 2004/11/01 19:06:12+01:00 spock@spock.one.pl |
| 73 |
# Merge |
| 74 |
# |
| 75 |
# drivers/video/fbmem.c |
| 76 |
# 2004/11/01 19:06:10+01:00 spock@spock.one.pl +0 -0 |
| 77 |
# SCCS merged |
| 78 |
# |
| 79 |
# drivers/video/Makefile |
| 80 |
# 2004/10/30 21:23:36+02:00 spock@spock.one.pl +0 -0 |
| 81 |
# Auto merged |
| 82 |
# |
| 83 |
# drivers/video/Kconfig |
| 84 |
# 2004/10/30 21:23:35+02:00 spock@spock.one.pl +0 -0 |
| 85 |
# Auto merged |
| 86 |
# |
| 87 |
# ChangeSet |
| 88 |
# 2004/10/28 19:02:21+02:00 spock@spock.one.pl |
| 89 |
# Added a fix for yres_virtual. |
| 90 |
# |
| 91 |
# drivers/video/vesafb-tng.c |
| 92 |
# 2004/10/28 19:02:09+02:00 spock@spock.one.pl +6 -2 |
| 93 |
# Added a fix for yres_virtual. |
| 94 |
# |
| 95 |
# ChangeSet |
| 96 |
# 2004/10/28 00:34:25+02:00 spock@spock.one.pl |
| 97 |
# Merged changes from vesafb (vram_remap, vram_total). |
| 98 |
# |
| 99 |
# drivers/video/vesafb-tng.c |
| 100 |
# 2004/10/28 00:34:12+02:00 spock@spock.one.pl +66 -24 |
| 101 |
# Merged changes from vesafb (vram_remap, vram_total). |
| 102 |
# |
| 103 |
# ChangeSet |
| 104 |
# 2004/10/28 00:25:27+02:00 spock@spock.one.pl |
| 105 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 106 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 107 |
# |
| 108 |
# drivers/video/fbmem.c |
| 109 |
# 2004/10/28 00:25:12+02:00 spock@spock.one.pl +0 -0 |
| 110 |
# Auto merged |
| 111 |
# |
| 112 |
# drivers/video/Kconfig |
| 113 |
# 2004/10/28 00:25:12+02:00 spock@spock.one.pl +0 -0 |
| 114 |
# Auto merged |
| 115 |
# |
| 116 |
# arch/i386/boot/video.S |
| 117 |
# 2004/10/28 00:25:12+02:00 spock@spock.one.pl +0 -0 |
| 118 |
# Auto merged |
| 119 |
# |
| 120 |
# Documentation/fb/vesafb.txt |
| 121 |
# 2004/10/28 00:25:12+02:00 spock@spock.one.pl +0 -0 |
| 122 |
# Auto merged |
| 123 |
# |
| 124 |
# ChangeSet |
| 125 |
# 2004/10/21 22:19:02+02:00 spock@spock.one.pl |
| 126 |
# Added automatic selection of FB_MODE_HELPERS. |
| 127 |
# |
| 128 |
# drivers/video/Kconfig |
| 129 |
# 2004/10/21 22:18:49+02:00 spock@spock.one.pl +1 -0 |
| 130 |
# Added automatic selection of FB_MODE_HELPERS. |
| 131 |
# |
| 132 |
# ChangeSet |
| 133 |
# 2004/10/18 16:24:05+02:00 spock@spock.one.pl |
| 134 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 135 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 136 |
# |
| 137 |
# drivers/video/Kconfig |
| 138 |
# 2004/10/18 16:23:59+02:00 spock@spock.one.pl +0 -0 |
| 139 |
# Auto merged |
| 140 |
# |
| 141 |
# ChangeSet |
| 142 |
# 2004/09/30 16:33:03+02:00 spock@spock.one.pl |
| 143 |
# Changed the code to reflect changes in fb_get_options' behaviour. |
| 144 |
# |
| 145 |
# drivers/video/vesafb-tng.c |
| 146 |
# 2004/09/30 16:19:46+02:00 spock@spock.one.pl +3 -1 |
| 147 |
# Changed to reflect changes in fb_get_options' behaviour. |
| 148 |
# |
| 149 |
# ChangeSet |
| 150 |
# 2004/09/30 16:14:04+02:00 spock@spock.one.pl |
| 151 |
# Resolved makefile conflicts. |
| 152 |
# |
| 153 |
# drivers/video/Makefile |
| 154 |
# 2004/09/30 16:13:51+02:00 spock@spock.one.pl +17 -1 |
| 155 |
# Fixed makefile. |
| 156 |
# |
| 157 |
# drivers/video/fbmem.c |
| 158 |
# 2004/09/30 16:07:32+02:00 spock@spock.one.pl +0 -0 |
| 159 |
# Auto merged |
| 160 |
# |
| 161 |
# ChangeSet |
| 162 |
# 2004/09/15 16:47:57+02:00 spock@spock.one.pl |
| 163 |
# Moved module_init() call to make the driver work with the new fb init code. |
| 164 |
# |
| 165 |
# drivers/video/vesafb-tng.c |
| 166 |
# 2004/09/15 16:47:46+02:00 spock@spock.one.pl +2 -1 |
| 167 |
# Moved module_init() call to make the driver work with the new fb init code. |
| 168 |
# |
| 169 |
# ChangeSet |
| 170 |
# 2004/09/14 19:46:14+02:00 spock@spock.one.pl |
| 171 |
# Merged minor changes. |
| 172 |
# |
| 173 |
# drivers/video/vesafb-tng.c |
| 174 |
# 2004/09/14 19:12:58+02:00 spock@spock.one.pl +1 -0 |
| 175 |
# Merged minor changes. |
| 176 |
# |
| 177 |
# ChangeSet |
| 178 |
# 2004/09/14 19:03:28+02:00 spock@spock.one.pl |
| 179 |
# Resolved vesafb-tng conflicts. |
| 180 |
# |
| 181 |
# drivers/video/fbmem.c |
| 182 |
# 2004/09/14 19:03:19+02:00 spock@spock.one.pl +6 -0 |
| 183 |
# Resolved vesafb-tng conflicts. |
| 184 |
# |
| 185 |
# drivers/video/Makefile |
| 186 |
# 2004/09/14 19:03:19+02:00 spock@spock.one.pl +17 -1 |
| 187 |
# Resolved vesafb-tng conflicts. |
| 188 |
# |
| 189 |
# ChangeSet |
| 190 |
# 2004/09/10 22:06:10+02:00 spock@spock.one.pl |
| 191 |
# Removed info about 'used hacks' from the docs. |
| 192 |
# TAG: vesafb-tng-0.9-rc4-r3 |
| 193 |
# |
| 194 |
# Documentation/fb/vesafb.txt |
| 195 |
# 2004/09/10 22:05:53+02:00 spock@spock.one.pl +3 -11 |
| 196 |
# Removed info about 'used hacks' from the docs. |
| 197 |
# |
| 198 |
# ChangeSet |
| 199 |
# 2004/09/10 21:17:52+02:00 spock@spock.one.pl |
| 200 |
# Removed the code for copying OEM data from RAM. |
| 201 |
# |
| 202 |
# drivers/video/vesafb-thread.c |
| 203 |
# 2004/09/10 21:17:37+02:00 spock@spock.one.pl +5 -14 |
| 204 |
# Removed the code for copying OEM data from RAM. |
| 205 |
# |
| 206 |
# ChangeSet |
| 207 |
# 2004/09/10 20:11:45+02:00 spock@spock.one.pl |
| 208 |
# Changed the VBE mode matching and mode setting logic. Cleaned up the code. |
| 209 |
# |
| 210 |
# drivers/video/vesafb-tng.c |
| 211 |
# 2004/09/10 20:11:36+02:00 spock@spock.one.pl +252 -242 |
| 212 |
# Changed the VBE mode matching and mode setting logic. Cleaned up the code. |
| 213 |
# |
| 214 |
# ChangeSet |
| 215 |
# 2004/09/09 16:48:42+02:00 spock@spock.one.pl |
| 216 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 217 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 218 |
# |
| 219 |
# drivers/video/fbmem.c |
| 220 |
# 2004/09/09 16:48:36+02:00 spock@spock.one.pl +0 -0 |
| 221 |
# Auto merged |
| 222 |
# |
| 223 |
# drivers/video/Makefile |
| 224 |
# 2004/09/09 16:48:36+02:00 spock@spock.one.pl +0 -0 |
| 225 |
# Auto merged |
| 226 |
# |
| 227 |
# ChangeSet |
| 228 |
# 2004/08/24 23:02:56+02:00 spock@spock.one.pl |
| 229 |
# Merge spock.one.pl:/devel/kernel/linux-2.5 |
| 230 |
# into spock.one.pl:/devel/kernel/linux-vesafb-tng |
| 231 |
# |
| 232 |
# drivers/video/fbmem.c |
| 233 |
# 2004/08/24 23:02:46+02:00 spock@spock.one.pl +0 -0 |
| 234 |
# Auto merged |
| 235 |
# |
| 236 |
# drivers/video/Makefile |
| 237 |
# 2004/08/24 23:02:46+02:00 spock@spock.one.pl +0 -0 |
| 238 |
# Auto merged |
| 239 |
# |
| 240 |
# drivers/video/Kconfig |
| 241 |
# 2004/08/24 23:02:45+02:00 spock@spock.one.pl +0 -0 |
| 242 |
# Auto merged |
| 243 |
# |
| 244 |
# arch/i386/boot/video.S |
| 245 |
# 2004/08/24 23:02:45+02:00 spock@spock.one.pl +0 -0 |
| 246 |
# Auto merged |
| 247 |
# |
| 248 |
# ChangeSet |
| 249 |
# 2004/08/24 11:18:50+02:00 spock@spock.one.pl |
| 250 |
# Updated the docs, fixed a minor bug with maxclk, add the code to switch the DAC palette format to 8 bit. |
| 251 |
# TAG: vesafb-tng-0.9-rc4-r1 |
| 252 |
# |
| 253 |
# drivers/video/vesafb-tng.c |
| 254 |
# 2004/08/24 11:18:42+02:00 spock@spock.one.pl +48 -19 |
| 255 |
# Added the code to switch DAC palette format to 8bit in 256 color modes. Changes 'forward-ported' from vesafb. |
| 256 |
# Fixed a type which caused maxpixclock to be set to 0 in some cases. |
| 257 |
# |
| 258 |
# include/video/vesa.h |
| 259 |
# 2004/08/23 17:13:30+02:00 spock@spock.one.pl +1 -0 |
| 260 |
# Added the CAP_CAN_SWITCH_DAC constant. |
| 261 |
# |
| 262 |
# Documentation/fb/vesafb.txt |
| 263 |
# 2004/08/23 16:42:35+02:00 spock@spock.one.pl +4 -0 |
| 264 |
# Added a hint about vbemode and nocrtc no the docs. |
| 265 |
# |
| 266 |
# ChangeSet |
| 267 |
# 2004/08/23 16:16:51+02:00 spock@spock.one.pl |
| 268 |
# Fixed a stupid bit-logic problem ('do not clear the screen' bit set instead of 'use linear framebuffer'), fixed Makefile and Kconfig. |
| 269 |
# |
| 270 |
# drivers/video/Kconfig |
| 271 |
# 2004/08/23 16:16:35+02:00 spock@spock.one.pl +1 -1 |
| 272 |
# Changed Kconfig to not allow to choose vesafb-tng on x86_64 systems. |
| 273 |
# |
| 274 |
# drivers/video/Makefile |
| 275 |
# 2004/08/23 16:11:41+02:00 spock@spock.one.pl +14 -13 |
| 276 |
# Fixed a bug in the Makefile that caused vesafb to be built even if CONFIG_FB_VESA was set to 'n'. |
| 277 |
# |
| 278 |
# BitKeeper/etc/config |
| 279 |
# 2004/08/19 00:20:28+02:00 spock@spock.one.pl +2 -3 |
| 280 |
# Changed configuration settings for vesafb-tng |
| 281 |
# |
| 282 |
# BitKeeper/etc/logging_ok |
| 283 |
# 2004/08/19 00:10:17+02:00 spock@spock.one.pl +0 -6 |
| 284 |
# Removed all entries |
| 285 |
# |
| 286 |
# drivers/video/vesafb-tng.c |
| 287 |
# 2004/08/18 23:35:52+02:00 spock@spock.one.pl +1 -5 |
| 288 |
# Fixed the LFB bit problem (D15 was set instead of D14). |
| 289 |
# |
| 290 |
# ChangeSet |
| 291 |
# 2004/08/18 23:33:08+02:00 spock@spock.one.pl |
| 292 |
# Merged vesafb-tng-0.9-rc4 |
| 293 |
# |
| 294 |
# drivers/video/fbmem.c |
| 295 |
# 2004/08/18 23:32:56+02:00 spock@spock.one.pl +4 -1 |
| 296 |
# Merged vesafb-tng-0.9-rc4 |
| 297 |
# |
| 298 |
# drivers/video/Makefile |
| 299 |
# 2004/08/18 23:32:56+02:00 spock@spock.one.pl +18 -1 |
| 300 |
# Merged vesafb-tng-0.9-rc4 |
| 301 |
# |
| 302 |
# drivers/video/Kconfig |
| 303 |
# 2004/08/18 23:32:56+02:00 spock@spock.one.pl +42 -1 |
| 304 |
# Merged vesafb-tng-0.9-rc4 |
| 305 |
# |
| 306 |
# arch/i386/boot/video.S |
| 307 |
# 2004/08/18 23:32:56+02:00 spock@spock.one.pl +10 -2 |
| 308 |
# Merged vesafb-tng-0.9-rc4 |
| 309 |
# |
| 310 |
# Documentation/fb/vesafb.txt |
| 311 |
# 2004/08/18 23:30:19+02:00 spock@spock.one.pl +171 -62 |
| 312 |
# |
| 313 |
# include/video/vesa.h |
| 314 |
# 2004/08/18 23:29:33+02:00 spock@spock.one.pl +125 -0 |
| 315 |
# |
| 316 |
# include/video/vesa.h |
| 317 |
# 2004/08/18 23:29:33+02:00 spock@spock.one.pl +0 -0 |
| 318 |
# BitKeeper file /devel/kernel/linux-vesafb-tng/include/video/vesa.h |
| 319 |
# |
| 320 |
# drivers/video/vesafb-tng.c |
| 321 |
# 2004/08/18 23:29:22+02:00 spock@spock.one.pl +1124 -0 |
| 322 |
# |
| 323 |
# drivers/video/vesafb-tng.c |
| 324 |
# 2004/08/18 23:29:22+02:00 spock@spock.one.pl +0 -0 |
| 325 |
# BitKeeper file /devel/kernel/linux-vesafb-tng/drivers/video/vesafb-tng.c |
| 326 |
# |
| 327 |
# drivers/video/vesafb-thread.c |
| 328 |
# 2004/08/18 23:29:21+02:00 spock@spock.one.pl +578 -0 |
| 329 |
# |
| 330 |
# drivers/video/vesafb-thread.c |
| 331 |
# 2004/08/18 23:29:21+02:00 spock@spock.one.pl +0 -0 |
| 332 |
# BitKeeper file /devel/kernel/linux-vesafb-tng/drivers/video/vesafb-thread.c |
| 333 |
# |
| 334 |
diff -Nru a/Documentation/fb/vesafb.txt b/Documentation/fb/vesafb.txt |
| 335 |
--- a/Documentation/fb/vesafb.txt 2005-01-15 14:00:49 +01:00 |
| 336 |
+++ b/Documentation/fb/vesafb.txt 2005-01-15 14:00:49 +01:00 |
| 337 |
@@ -2,16 +2,18 @@ |
| 338 |
What is vesafb? |
| 339 |
=============== |
| 340 |
|
| 341 |
-This is a generic driver for a graphic framebuffer on intel boxes. |
| 342 |
+Vesafb is a generic framebuffer driver for x86 and x86_64 boxes. |
| 343 |
|
| 344 |
-The idea is simple: Turn on graphics mode at boot time with the help |
| 345 |
-of the BIOS, and use this as framebuffer device /dev/fb0, like the m68k |
| 346 |
-(and other) ports do. |
| 347 |
- |
| 348 |
-This means we decide at boot time whenever we want to run in text or |
| 349 |
-graphics mode. Switching mode later on (in protected mode) is |
| 350 |
-impossible; BIOS calls work in real mode only. VESA BIOS Extensions |
| 351 |
-Version 2.0 are required, because we need a linear frame buffer. |
| 352 |
+VESA BIOS Extensions Version 2.0 are required, because we need a linear |
| 353 |
+frame buffer. VBE 3.0 is required if you want to use modes with a higher |
| 354 |
+(than the standard 60Hz) refresh rate. |
| 355 |
+ |
| 356 |
+The VESA framebuffer driver comes in two flavors - the standard vesafb |
| 357 |
+and vesafb-tng. Vesafb-tng is available only on 32-bit x86 due to the |
| 358 |
+technology it uses (vm86). Vesafb-tng has more features than vesafb |
| 359 |
+(adjusting the refresh rate on VBE3.0-compliant boards, switching the |
| 360 |
+video mode without rebooting, selecting a mode by providing its |
| 361 |
+modedb name, and more) but might be unstable on some systems. |
| 362 |
|
| 363 |
Advantages: |
| 364 |
|
| 365 |
@@ -29,16 +31,27 @@ |
| 366 |
How to use it? |
| 367 |
============== |
| 368 |
|
| 369 |
-Switching modes is done using the vga=... boot parameter. Read |
| 370 |
-Documentation/svga.txt for details. |
| 371 |
- |
| 372 |
-You should compile in both vgacon (for text mode) and vesafb (for |
| 373 |
-graphics mode). Which of them takes over the console depends on |
| 374 |
-whenever the specified mode is text or graphics. |
| 375 |
- |
| 376 |
-The graphic modes are NOT in the list which you get if you boot with |
| 377 |
-vga=ask and hit return. The mode you wish to use is derived from the |
| 378 |
-VESA mode number. Here are those VESA mode numbers: |
| 379 |
+If you are running your system on hardware platform where vm86 is supported |
| 380 |
+(this is 32-bit x86 only as of the time of writing this document) and you |
| 381 |
+decide to use vesafb-tng, you can either the driver into the kernel or use it |
| 382 |
+as a module. The graphic mode you want to use is in both cases specified using |
| 383 |
+the standard modedb format. |
| 384 |
+ |
| 385 |
+If your system doesn't support vm86 calls yet (all 64-bit platforms), things |
| 386 |
+get a little more tricky. Since on such systems you can't do BIOS calls from |
| 387 |
+protected mode in which kernel runs, you have to decide at boot time whenever |
| 388 |
+you want to run in text or in graphics mode. Switching mode later on is |
| 389 |
+impossible. Switching modes is done using the vga=... boot parameter. Read |
| 390 |
+Documentation/svga.txt for details. Below is a more detailed description of |
| 391 |
+what to do on systems using the standard vesafb driver. |
| 392 |
+ |
| 393 |
+You should compile in both vgacon (for text mode) and vesafb (for graphics mode). |
| 394 |
+Which of them takes over the console depends on whenever the specified mode is |
| 395 |
+text or graphics. |
| 396 |
+ |
| 397 |
+The graphic modes are NOT in the list which you get if you boot with vga=ask |
| 398 |
+and hit return. The mode you wish to use is derived from the VESA mode number. |
| 399 |
+Here are those VESA mode numbers: |
| 400 |
|
| 401 |
| 640x480 800x600 1024x768 1280x1024 |
| 402 |
----+------------------------------------- |
| 403 |
@@ -47,8 +60,7 @@ |
| 404 |
64k | 0x111 0x114 0x117 0x11A |
| 405 |
16M | 0x112 0x115 0x118 0x11B |
| 406 |
|
| 407 |
-The video mode number of the Linux kernel is the VESA mode number plus |
| 408 |
-0x200. |
| 409 |
+The video mode number of the Linux kernel is the VESA mode number plus 0x200. |
| 410 |
|
| 411 |
Linux_kernel_mode_number = VESA_mode_number + 0x200 |
| 412 |
|
| 413 |
@@ -61,10 +73,10 @@ |
| 414 |
64k | 0x311 0x314 0x317 0x31A |
| 415 |
16M | 0x312 0x315 0x318 0x31B |
| 416 |
|
| 417 |
-To enable one of those modes you have to specify "vga=ask" in the |
| 418 |
-lilo.conf file and rerun LILO. Then you can type in the desired |
| 419 |
-mode at the "vga=ask" prompt. For example if you like to use |
| 420 |
-1024x768x256 colors you have to say "305" at this prompt. |
| 421 |
+To enable one of those modes you have to specify "vga=ask" in the lilo.conf |
| 422 |
+file and rerun LILO. Then you can type in the desired mode at the "vga=ask" |
| 423 |
+prompt. For example if you like to use 1024x768x256 colors you have to say |
| 424 |
+"305" at this prompt. |
| 425 |
|
| 426 |
If this does not work, this might be because your BIOS does not support |
| 427 |
linear framebuffers or because it does not support this mode at all. |
| 428 |
@@ -77,6 +89,7 @@ |
| 429 |
2. Note: Some newer versions of LILO appear to work with those hex values, |
| 430 |
if you set the 0x in front of the numbers. |
| 431 |
|
| 432 |
+ |
| 433 |
X11 |
| 434 |
=== |
| 435 |
|
| 436 |
@@ -86,65 +99,73 @@ |
| 437 |
|
| 438 |
The X-Server must restore the video mode correctly, else you end up |
| 439 |
with a broken console (and vesafb cannot do anything about this). |
| 440 |
+With vesafb-tng chances are that the console will be restored properly |
| 441 |
+even if the X server messed up the video mode. |
| 442 |
|
| 443 |
|
| 444 |
Refresh rates |
| 445 |
============= |
| 446 |
|
| 447 |
-There is no way to change the vesafb video mode and/or timings after |
| 448 |
-booting linux. If you are not happy with the 60 Hz refresh rate, you |
| 449 |
-have these options: |
| 450 |
+With VBE3.0 compatible BIOSes and vesafb-tng it is possible to change |
| 451 |
+the refresh rate either at boot time (by specifying the @<rr> part of |
| 452 |
+the mode name) or later, using the fbset utility. |
| 453 |
+ |
| 454 |
+With VBE2.0 there is no way to change the mode timings after booting |
| 455 |
+Linux. If you are not happy with the 60 Hz refresh rate, you have |
| 456 |
+these options: |
| 457 |
|
| 458 |
- * configure and load the DOS-Tools for your the graphics board (if |
| 459 |
- available) and boot linux with loadlin. |
| 460 |
+ * configure and load the DOS tools for your the graphics board (if |
| 461 |
+ available) and boot Linux with loadlin. |
| 462 |
* use a native driver (matroxfb/atyfb) instead if vesafb. If none |
| 463 |
is available, write a new one! |
| 464 |
- * VBE 3.0 might work too. I have neither a gfx board with VBE 3.0 |
| 465 |
- support nor the specs, so I have not checked this yet. |
| 466 |
+ * use a BIOS editor to change the default refresh rate (such an |
| 467 |
+ editor does exist at least for ATI Radeon BIOSes). |
| 468 |
+ * if you're running a non-vm86 and VBE3.0-compatible system, you can |
| 469 |
+ use a kernel patch to hard-code some mode timings in the kernel and |
| 470 |
+ use these while setting the graphic mode at boot time. |
| 471 |
|
| 472 |
|
| 473 |
Configuration |
| 474 |
============= |
| 475 |
|
| 476 |
-The VESA BIOS provides protected mode interface for changing |
| 477 |
-some parameters. vesafb can use it for palette changes and |
| 478 |
-to pan the display. It is turned off by default because it |
| 479 |
-seems not to work with some BIOS versions, but there are options |
| 480 |
-to turn it on. |
| 481 |
- |
| 482 |
-You can pass options to vesafb using "video=vesafb:option" on |
| 483 |
-the kernel command line. Multiple options should be separated |
| 484 |
-by comma, like this: "video=vesafb:ypan,invers" |
| 485 |
- |
| 486 |
-Accepted options: |
| 487 |
- |
| 488 |
-invers no comment... |
| 489 |
- |
| 490 |
-ypan enable display panning using the VESA protected mode |
| 491 |
- interface. The visible screen is just a window of the |
| 492 |
+The VESA BIOS provides protected mode interface for changing some parameters. |
| 493 |
+vesafb can use it for palette changes and to pan the display. It is turned |
| 494 |
+off by default because it seems not to work with some BIOS versions, but there |
| 495 |
+are options to turn it on. |
| 496 |
+ |
| 497 |
+You can pass options to vesafb using "video=vesafb:option" on the kernel |
| 498 |
+command line. Multiple options should be separated by comma, like this: |
| 499 |
+"video=vesafb:ypan,1024x768-32@85" |
| 500 |
+ |
| 501 |
+Accepted options (both vesafb and vesafb-tng): |
| 502 |
+ |
| 503 |
+ypan Enable display panning using the VESA protected mode |
| 504 |
+ interface or vm86 calls. The visible screen is just a window of the |
| 505 |
video memory, console scrolling is done by changing the |
| 506 |
start of the window. |
| 507 |
pro: * scrolling (fullscreen) is fast, because there is |
| 508 |
no need to copy around data. |
| 509 |
- * You'll get scrollback (the Shift-PgUp thing), |
| 510 |
+ * you'll get scrollback (the Shift-PgUp thing), |
| 511 |
the video memory can be used as scrollback buffer |
| 512 |
- kontra: * scrolling only parts of the screen causes some |
| 513 |
+ con: * scrolling only parts of the screen causes some |
| 514 |
ugly flicker effects (boot logo flickers for |
| 515 |
example). |
| 516 |
|
| 517 |
-ywrap Same as ypan, but assumes your gfx board can wrap-around |
| 518 |
- the video memory (i.e. starts reading from top if it |
| 519 |
- reaches the end of video memory). Faster than ypan. |
| 520 |
- |
| 521 |
-redraw scroll by redrawing the affected part of the screen, this |
| 522 |
- is the safe (and slow) default. |
| 523 |
+ywrap Same as ypan, but assumes your gfx board can wrap-around the video |
| 524 |
+ memory (i.e. starts reading from top if it reaches the end of video |
| 525 |
+ memory). Faster than ypan. |
| 526 |
|
| 527 |
+redraw Scroll by redrawing the affected part of the screen, this is the |
| 528 |
+ safe (and slow) default. |
| 529 |
|
| 530 |
-vgapal Use the standard vga registers for palette changes. |
| 531 |
+vgapal Use the standard VGA registers for palette changes. |
| 532 |
This is the default. |
| 533 |
+ |
| 534 |
pmipal Use the protected mode interface for palette changes. |
| 535 |
|
| 536 |
-mtrr setup memory type range registers for the vesafb framebuffer. |
| 537 |
+mtrr Setup memory type range registers for the vesafb framebuffer. |
| 538 |
+ |
| 539 |
+nomtrr Do not use memory type range registers for vesafb. |
| 540 |
|
| 541 |
vremap:n |
| 542 |
remap 'n' MiB of video RAM. If 0 or not specified, remap memory |
| 543 |
@@ -156,12 +177,96 @@ |
| 544 |
if the video BIOS of your card incorrectly determines the total |
| 545 |
amount of video RAM, use this option to override the BIOS (in MiB). |
| 546 |
|
| 547 |
-Have fun! |
| 548 |
+Options accepted only by vesafb-tng: |
| 549 |
+ |
| 550 |
+<mode> The mode you want to set, in the standard modedb format. Refer to |
| 551 |
+ modedb.txt for detailed description. If you specify a mode that is |
| 552 |
+ not supported by your board's BIOS, vesafb will attempt to set a |
| 553 |
+ similar mode. The list of supported modes can be found in |
| 554 |
+ /proc/fbx/modes, where x is the framebuffer number (usually 0). |
| 555 |
+ When vesafb is compiled as a module, the mode string should be |
| 556 |
+ provided as a value of the parameter 'mode'. |
| 557 |
+ |
| 558 |
+vbemode:x |
| 559 |
+ Force the use of VBE mode x. The mode will only be set if it's |
| 560 |
+ found in VBE-provided list of supported modes. |
| 561 |
+ NOTE: The mode number 'x' should be specified in VESA mode number |
| 562 |
+ notation, not the Linux kernel one (ie. 257 instead of 769). |
| 563 |
+ HINT: If you use this option because normal <mode> parameter does |
| 564 |
+ not work for you and you use a X server, you'll probably want to |
| 565 |
+ set the 'nocrtc' option to ensure that the video mode is properly |
| 566 |
+ restored after console <-> X switches. |
| 567 |
+ |
| 568 |
+nocrtc Do not use CRTC timings while setting the graphic mode. This option |
| 569 |
+ makes sence only with VBE3.0 compliant systems. Use it if you have |
| 570 |
+ problems with the modes set in the standard way. Note that specifying |
| 571 |
+ this option means the refresh rate will be ignored and will stay at |
| 572 |
+ your BIOS' default (60 Hz). |
| 573 |
+ |
| 574 |
+noedid Do not try to fetch and use EDID-provided modes. |
| 575 |
+ |
| 576 |
+gtf Force the use of VESA's GTF (Generalized Timing Formula). Specifying |
| 577 |
+ this will cause vesafb to skip it's internal modedb and EDID-modedb |
| 578 |
+ and jump straight to the GTF part of the code (normally used only is |
| 579 |
+ everything else failed). This can be useful if you want to get as much |
| 580 |
+ as possible from you graphics board but your BIOS doesn't support |
| 581 |
+ modes with refresh rates you require. Note that you may need to |
| 582 |
+ specify the maxhf, maxvf and maxclk parameters if they are not |
| 583 |
+ provided by EDID. |
| 584 |
+ |
| 585 |
+Additionally, the following parameters may be provided. They all override the |
| 586 |
+EDID-provided values and BIOS defaults. Refer to you monitor's specs to get |
| 587 |
+the correct values for maxhf, maxvf and maxclk for your hardware. |
| 588 |
+ |
| 589 |
+maxhf:n Maximum horizontal frequency (in kHz). |
| 590 |
+maxvf:n Maximum vertical frequency (in Hz). |
| 591 |
+maxclk:n Maximum pixel clock (in MHz). |
| 592 |
+ |
| 593 |
+ |
| 594 |
+Vesafb-tng Technical details |
| 595 |
+============================ |
| 596 |
+ |
| 597 |
+1. The driver architecture. |
| 598 |
+ |
| 599 |
+The driver's code is stored in 3 files: |
| 600 |
+ /drivers/video/vesafb-tng.c |
| 601 |
+ /drivers/video/vesafb-thread.c |
| 602 |
+ /include/video/vesa.h |
| 603 |
+ |
| 604 |
+vesafb-tng.c contains the main code. vesafb-thread.c contains code for the |
| 605 |
+vesafb service thread. A separate thread is necessary because we need to remap |
| 606 |
+memory in order to be able to use the vm86 calls. The service thread is started |
| 607 |
+regardless of whether vesafb is compiled into the kernel or compiled as a |
| 608 |
+module. This is necessary because of the active_mm stuff, better described in |
| 609 |
+the header of vesafb-thread.c. |
| 610 |
+ |
| 611 |
+2. The driver initialization |
| 612 |
+ |
| 613 |
+ o vesafb_vbe_init |
| 614 |
+ - get basic info about the graphics BIOS |
| 615 |
+ - fetch data about all modes supported by VBE |
| 616 |
+ - get info about the protected mode interface |
| 617 |
+ - get EDID data and attempt to create an EDID modedb |
| 618 |
+ |
| 619 |
+ o vesafb_probe |
| 620 |
+ - get service thread's PID (started earlier from fbmem.c) |
| 621 |
+ - call vesafb_vbe_init |
| 622 |
+ - find a matching VBE mode |
| 623 |
+ - try to find the specified mode in vesa_modes modedb |
| 624 |
+ - try to find the specified mode in the EDID modedb |
| 625 |
+ - try to calculate timings with the GTF |
| 626 |
+ - low level setup - request_mem_region, ioremap, etc. |
| 627 |
+ - setup /proc/fb<x>/modes and /proc/fb<x>/vbe_info |
| 628 |
|
| 629 |
- Gerd |
| 630 |
+Have fun! |
| 631 |
|
| 632 |
-- |
| 633 |
+Original document for the vesafb driver by |
| 634 |
Gerd Knorr <kraxel@goldbach.in-berlin.de> |
| 635 |
|
| 636 |
-Minor (mostly typo) changes |
| 637 |
-by Nico Schmoigl <schmoigl@rumms.uni-mannheim.de> |
| 638 |
+Minor (mostly typo) changes by |
| 639 |
+Nico Schmoigl <schmoigl@rumms.uni-mannheim.de> |
| 640 |
+ |
| 641 |
+Extended documentation for vm86, VBE3.0 and vesafb-tng by |
| 642 |
+Micha³ Januszewski <spock@gentoo.org> |
| 643 |
+ |
| 644 |
diff -Nru a/arch/i386/boot/video.S b/arch/i386/boot/video.S |
| 645 |
--- a/arch/i386/boot/video.S 2005-01-15 14:00:49 +01:00 |
| 646 |
+++ b/arch/i386/boot/video.S 2005-01-15 14:00:49 +01:00 |
| 647 |
@@ -164,10 +164,12 @@ |
| 648 |
# parameters in the default 80x25 mode -- these are set directly, |
| 649 |
# because some very obscure BIOSes supply insane values. |
| 650 |
mode_params: |
| 651 |
+#ifdef CONFIG_FB_VESA_STD |
| 652 |
#ifdef CONFIG_VIDEO_SELECT |
| 653 |
cmpb $0, graphic_mode |
| 654 |
jnz mopar_gr |
| 655 |
#endif |
| 656 |
+#endif |
| 657 |
movb $0x03, %ah # Read cursor position |
| 658 |
xorb %bh, %bh |
| 659 |
int $0x10 |
| 660 |
@@ -200,6 +202,7 @@ |
| 661 |
ret |
| 662 |
|
| 663 |
#ifdef CONFIG_VIDEO_SELECT |
| 664 |
+#ifdef CONFIG_FB_VESA_STD |
| 665 |
# Fetching of VESA frame buffer parameters |
| 666 |
mopar_gr: |
| 667 |
leaw modelist+1024, %di |
| 668 |
@@ -278,6 +281,7 @@ |
| 669 |
movw %es, %fs:(PARAM_VESAPM_SEG) |
| 670 |
movw %di, %fs:(PARAM_VESAPM_OFF) |
| 671 |
no_pm: ret |
| 672 |
+#endif |
| 673 |
|
| 674 |
# The video mode menu |
| 675 |
mode_menu: |
| 676 |
@@ -492,10 +496,12 @@ |
| 677 |
|
| 678 |
cmpb $VIDEO_FIRST_V7>>8, %ah |
| 679 |
jz setv7 |
| 680 |
- |
| 681 |
+ |
| 682 |
+#ifdef CONFIG_FB_VESA_STD |
| 683 |
cmpb $VIDEO_FIRST_VESA>>8, %ah |
| 684 |
jnc check_vesa |
| 685 |
- |
| 686 |
+#endif |
| 687 |
+ |
| 688 |
orb %ah, %ah |
| 689 |
jz setmenu |
| 690 |
|
| 691 |
@@ -567,6 +573,7 @@ |
| 692 |
movw -4(%si), %ax # Fetch mode ID |
| 693 |
jmp _m_s |
| 694 |
|
| 695 |
+#ifdef CONFIG_FB_VESA_STD |
| 696 |
check_vesa: |
| 697 |
leaw modelist+1024, %di |
| 698 |
subb $VIDEO_FIRST_VESA>>8, %bh |
| 699 |
@@ -600,6 +607,7 @@ |
| 700 |
ret |
| 701 |
|
| 702 |
_setbad: jmp setbad # Ugly... |
| 703 |
+#endif |
| 704 |
|
| 705 |
# Recalculate vertical display end registers -- this fixes various |
| 706 |
# inconsistencies of extended modes on many adapters. Called when |
| 707 |
diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig |
| 708 |
--- a/drivers/video/Kconfig 2005-01-15 14:00:49 +01:00 |
| 709 |
+++ b/drivers/video/Kconfig 2005-01-15 14:00:49 +01:00 |
| 710 |
@@ -329,13 +329,55 @@ |
| 711 |
cards. Say Y if you have one of those. |
| 712 |
|
| 713 |
config FB_VESA |
| 714 |
- bool "VESA VGA graphics support" |
| 715 |
+ tristate "VESA VGA graphics support" |
| 716 |
depends on FB && (X86 || X86_64) |
| 717 |
help |
| 718 |
This is the frame buffer device driver for generic VESA 2.0 |
| 719 |
compliant graphic cards. The older VESA 1.2 cards are not supported. |
| 720 |
You will get a boot time penguin logo at no additional cost. Please |
| 721 |
read <file:Documentation/fb/vesafb.txt>. If unsure, say Y. |
| 722 |
+ |
| 723 |
+choice |
| 724 |
+ prompt "VESA driver type" |
| 725 |
+ depends on FB_VESA |
| 726 |
+ default FB_VESA_STD if X86_64 |
| 727 |
+ default FB_VESA_TNG if X86 |
| 728 |
+ |
| 729 |
+config FB_VESA_STD |
| 730 |
+ bool "vesafb" |
| 731 |
+ help |
| 732 |
+ This is the frame buffer device driver for generic VESA 2.0 |
| 733 |
+ compliant graphic cards. The older VESA 1.2 cards are not supported. |
| 734 |
+ You will get a boot time penguin logo at no additional cost. Please |
| 735 |
+ read <file:Documentation/fb/vesafb.txt>. Choose this driver if you |
| 736 |
+ are experiencing problems with vesafb-tng or if you own a 64-bit system. |
| 737 |
+ |
| 738 |
+ Note that this driver cannot be compiled as a module. |
| 739 |
+ |
| 740 |
+config FB_VESA_TNG |
| 741 |
+ bool "vesafb-tng" |
| 742 |
+ depends on !X86_64 |
| 743 |
+ select FB_MODE_HELPERS |
| 744 |
+ help |
| 745 |
+ This is the frame buffer device driver for generic VESA 2.0 |
| 746 |
+ compliant graphic cards. It is capable of taking advantage of |
| 747 |
+ VBE 3.0 features. With this driver you will be able to adjust |
| 748 |
+ the refresh rate (VBE 3.0 compliant boards only) and change |
| 749 |
+ the graphic mode on-the-fly. |
| 750 |
+ |
| 751 |
+ You will also get a boot time penguin logo at no additional cost. Please |
| 752 |
+ read <file:Documentation/fb/vesafb.txt>. |
| 753 |
+ |
| 754 |
+endchoice |
| 755 |
+ |
| 756 |
+config FB_VESA_DEFAULT_MODE |
| 757 |
+ string "VESA default mode" |
| 758 |
+ depends on FB_VESA_TNG |
| 759 |
+ default "640x480@60" |
| 760 |
+ help |
| 761 |
+ This option is used to determine the default mode vesafb is |
| 762 |
+ supposed to switch to in case no mode is provided as a kernel |
| 763 |
+ command line parameter. |
| 764 |
|
| 765 |
config VIDEO_SELECT |
| 766 |
bool |
| 767 |
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile |
| 768 |
--- a/drivers/video/Makefile 2005-01-15 14:00:49 +01:00 |
| 769 |
+++ b/drivers/video/Makefile 2005-01-15 14:00:49 +01:00 |
| 770 |
@@ -96,7 +96,23 @@ |
| 771 |
obj-$(CONFIG_FB_PXA) += pxafb.o cfbimgblt.o cfbcopyarea.o cfbfillrect.o |
| 772 |
|
| 773 |
# Platform or fallback drivers go here |
| 774 |
-obj-$(CONFIG_FB_VESA) += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o |
| 775 |
+ifeq ($(CONFIG_FB_VESA),m) |
| 776 |
+ ifeq ($(CONFIG_FB_VESA_STD),y) |
| 777 |
+ obj-y += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o |
| 778 |
+ else |
| 779 |
+ obj-m += vesafb-tng.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o |
| 780 |
+ obj-y += vesafb-thread.o |
| 781 |
+ endif |
| 782 |
+else |
| 783 |
+ ifeq ($(CONFIG_FB_VESA),y) |
| 784 |
+ ifeq ($(CONFIG_FB_VESA_STD),y) |
| 785 |
+ obj-y += vesafb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o |
| 786 |
+ else |
| 787 |
+ obj-y += vesafb-tng.o vesafb-thread.o cfbfillrect.o \ |
| 788 |
+ cfbcopyarea.o cfbimgblt.o |
| 789 |
+ endif |
| 790 |
+ endif |
| 791 |
+endif |
| 792 |
obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ |
| 793 |
cfbimgblt.o vgastate.o |
| 794 |
obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o |
| 795 |
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c |
| 796 |
--- a/drivers/video/fbmem.c 2005-01-15 14:00:49 +01:00 |
| 797 |
+++ b/drivers/video/fbmem.c 2005-01-15 14:00:49 +01:00 |
| 798 |
@@ -51,6 +51,8 @@ |
| 799 |
* Frame buffer device initialization and setup routines |
| 800 |
*/ |
| 801 |
|
| 802 |
+extern int vesafb_init_thread(void); |
| 803 |
+ |
| 804 |
#define FBPIXMAPSIZE (1024 * 8) |
| 805 |
|
| 806 |
static struct notifier_block *fb_notifier_list; |
| 807 |
@@ -1177,6 +1179,10 @@ |
| 808 |
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); |
| 809 |
fb_class = NULL; |
| 810 |
} |
| 811 |
+ |
| 812 |
+#if defined(CONFIG_FB_VESA_TNG) || defined(CONFIG_FB_VESA_TNG_MODULE) |
| 813 |
+ vesafb_init_thread(); |
| 814 |
+#endif |
| 815 |
return 0; |
| 816 |
} |
| 817 |
subsys_initcall(fbmem_init); |
| 818 |
diff -Nru a/drivers/video/vesafb-thread.c b/drivers/video/vesafb-thread.c |
| 819 |
--- /dev/null Wed Dec 31 16:00:00 196900 |
| 820 |
+++ b/drivers/video/vesafb-thread.c 2005-01-15 14:00:49 +01:00 |
| 821 |
@@ -0,0 +1,569 @@ |
| 822 |
+/* |
| 823 |
+ * Framebuffer driver for VBE 2.0+ compliant graphic boards - kernel thread |
| 824 |
+ * and vm86 routines. |
| 825 |
+ * |
| 826 |
+ * This code has to be compiled into the kernel even if vesafb is configured |
| 827 |
+ * as a module. If vesafb_thread were to be started while the module is being |
| 828 |
+ * initialized, it would share its active_mm with modprobe. This mm would be |
| 829 |
+ * lost after modprobe finished its work, and we can't allow it, because we |
| 830 |
+ * need it for as long as the vesafb thread is active. |
| 831 |
+ * |
| 832 |
+ * (c) 2004 Micha³ Januszewski <spock@gentoo.org> |
| 833 |
+ * |
| 834 |
+ */ |
| 835 |
+ |
| 836 |
+#include <linux/workqueue.h> |
| 837 |
+#include <linux/module.h> |
| 838 |
+#include <linux/kernel.h> |
| 839 |
+#include <linux/errno.h> |
| 840 |
+#include <linux/mm.h> |
| 841 |
+#include <linux/slab.h> |
| 842 |
+#include <linux/delay.h> |
| 843 |
+#include <linux/signal.h> |
| 844 |
+#include <linux/suspend.h> |
| 845 |
+#include <video/vesa.h> |
| 846 |
+#include <video/edid.h> |
| 847 |
+#include <asm/mman.h> |
| 848 |
+#include <asm/page.h> |
| 849 |
+#include <asm/vm86.h> |
| 850 |
+#include <asm/unistd.h> |
| 851 |
+#include <asm/thread_info.h> |
| 852 |
+#include <asm/uaccess.h> |
| 853 |
+#include "edid.h" |
| 854 |
+ |
| 855 |
+#ifdef DEBUG |
| 856 |
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) |
| 857 |
+#else |
| 858 |
+#define DPRINTK(fmt, args...) |
| 859 |
+#endif |
| 860 |
+ |
| 861 |
+static int errno = 0; |
| 862 |
+int vesafb_pid = 0; |
| 863 |
+struct vm86_struct vm86; |
| 864 |
+ |
| 865 |
+static DECLARE_MUTEX(vesafb_sem); |
| 866 |
+static LIST_HEAD(vesafb_task_list); |
| 867 |
+static DECLARE_WAIT_QUEUE_HEAD(vesafb_wait); |
| 868 |
+ |
| 869 |
+_syscall3(int,ioperm,unsigned long, a, unsigned long, b, unsigned long, c); |
| 870 |
+_syscall1(int,vm86old,struct vm86_struct __user*, v86); |
| 871 |
+ |
| 872 |
+#define DEFAULT_VM86_FLAGS (IF_MASK | IOPL_MASK) |
| 873 |
+#define VM86_PUSHW(x) vm86.regs.esp -= 2; *(unsigned short*)(real_mem+vm86.regs.esp) = x; |
| 874 |
+#define REAL_MEM_SIZE 0x20000 |
| 875 |
+#define REAL_MEM 0x10000 |
| 876 |
+#define RET_CODE_SIZE 0x02 |
| 877 |
+#define STACK_SIZE 0x500 |
| 878 |
+#define BUFFER (STACK_SIZE + RET_CODE_SIZE) |
| 879 |
+#define FLAG_D (1 << 10) |
| 880 |
+ |
| 881 |
+/* segment prefix opcodes */ |
| 882 |
+enum { |
| 883 |
+ P_CS = 0x2e, |
| 884 |
+ P_SS = 0x36, |
| 885 |
+ P_DS = 0x3e, |
| 886 |
+ P_ES = 0x26, |
| 887 |
+ P_FS = 0x64, |
| 888 |
+ P_GS = 0x65 |
| 889 |
+}; |
| 890 |
+ |
| 891 |
+void vesafb_queue_task(struct vesafb_task *task) |
| 892 |
+{ |
| 893 |
+ list_add_tail(&task->node, &vesafb_task_list); |
| 894 |
+ wake_up(&vesafb_wait); |
| 895 |
+} |
| 896 |
+ |
| 897 |
+/* emulated vm86 ins instruction */ |
| 898 |
+static void vm86_ins(int size) |
| 899 |
+{ |
| 900 |
+ u32 edx, edi; |
| 901 |
+ |
| 902 |
+ edx = vm86.regs.edx & 0xffff; |
| 903 |
+ edi = (vm86.regs.edi & 0xffff) + (u32)(vm86.regs.es << 4); |
| 904 |
+ |
| 905 |
+ if (vm86.regs.eflags & FLAG_D) |
| 906 |
+ asm volatile ("std\n"); |
| 907 |
+ else |
| 908 |
+ asm volatile ("cld\n"); |
| 909 |
+ |
| 910 |
+ switch (size) { |
| 911 |
+ case 4: asm volatile ("insl\n" : "=D" (edi) : "d" (edx), "0" (edi)); break; |
| 912 |
+ case 2: asm volatile ("insw\n" : "=D" (edi) : "d" (edx), "0" (edi)); break; |
| 913 |
+ case 1: asm volatile ("insb\n" : "=D" (edi) : "d" (edx), "0" (edi)); |
| 914 |
+ } |
| 915 |
+ |
| 916 |
+ if (vm86.regs.eflags & FLAG_D) |
| 917 |
+ asm volatile ("cld\n"); |
| 918 |
+ |
| 919 |
+ edi -= (u32)(vm86.regs.es << 4); |
| 920 |
+ |
| 921 |
+ vm86.regs.edi &= 0xffff0000; |
| 922 |
+ vm86.regs.edi |= edi & 0xffff; |
| 923 |
+} |
| 924 |
+ |
| 925 |
+static void vm86_rep_ins(int size) |
| 926 |
+{ |
| 927 |
+ u16 cx = vm86.regs.ecx; |
| 928 |
+ |
| 929 |
+ while (cx--) |
| 930 |
+ vm86_ins(size); |
| 931 |
+ |
| 932 |
+ vm86.regs.ecx &= 0xffff0000; |
| 933 |
+} |
| 934 |
+ |
| 935 |
+/* emulated vm86 outs instruction */ |
| 936 |
+static void vm86_outs(int size, int segment) |
| 937 |
+{ |
| 938 |
+ u32 edx, esi, base; |
| 939 |
+ |
| 940 |
+ edx = vm86.regs.edx & 0xffff; |
| 941 |
+ esi = vm86.regs.esi & 0xffff; |
| 942 |
+ |
| 943 |
+ switch (segment) { |
| 944 |
+ case P_CS: base = vm86.regs.cs; break; |
| 945 |
+ case P_SS: base = vm86.regs.ss; break; |
| 946 |
+ case P_ES: base = vm86.regs.es; break; |
| 947 |
+ case P_FS: base = vm86.regs.fs; break; |
| 948 |
+ case P_GS: base = vm86.regs.gs; break; |
| 949 |
+ default: base = vm86.regs.ds; break; |
| 950 |
+ } |
| 951 |
+ |
| 952 |
+ esi += base << 4; |
| 953 |
+ |
| 954 |
+ if (vm86.regs.eflags & FLAG_D) |
| 955 |
+ asm volatile ("std\n"); |
| 956 |
+ else |
| 957 |
+ asm volatile ("cld\n"); |
| 958 |
+ |
| 959 |
+ switch (size) { |
| 960 |
+ case 4: asm volatile ("outsl\n" : "=S" (esi) : "d" (edx), "0" (esi)); break; |
| 961 |
+ case 2: asm volatile ("outsw\n" : "=S" (esi) : "d" (edx), "0" (esi)); break; |
| 962 |
+ case 1: asm volatile ("outsb\n" : "=S" (esi) : "d" (edx), "0" (esi)); break; |
| 963 |
+ } |
| 964 |
+ |
| 965 |
+ if (vm86.regs.eflags & FLAG_D) |
| 966 |
+ asm volatile ("cld"); |
| 967 |
+ |
| 968 |
+ esi -= base << 4; |
| 969 |
+ vm86.regs.esi &= 0xffff0000; |
| 970 |
+ vm86.regs.esi |= (esi & 0xffff); |
| 971 |
+} |
| 972 |
+ |
| 973 |
+static void vm86_rep_outs(int size, int segment) |
| 974 |
+{ |
| 975 |
+ u16 cx = vm86.regs.ecx; |
| 976 |
+ |
| 977 |
+ while (cx--) |
| 978 |
+ vm86_outs(size, segment); |
| 979 |
+ |
| 980 |
+ vm86.regs.ecx &= 0xffff0000; |
| 981 |
+} |
| 982 |
+ |
| 983 |
+void vesafb_do_vm86(struct vm86_regs *regs) |
| 984 |
+{ |
| 985 |
+ unsigned char *real_mem = (void*)REAL_MEM; |
| 986 |
+ unsigned int ret; |
| 987 |
+ |
| 988 |
+ memset(&vm86,0,sizeof(vm86)); |
| 989 |
+ memcpy(&vm86.regs, regs, sizeof(struct vm86_regs)); |
| 990 |
+ |
| 991 |
+ /* the return code */ |
| 992 |
+ real_mem[0] = 0xcd; /* int opcode */ |
| 993 |
+ real_mem[1] = 0xff; /* int number (255) */ |
| 994 |
+ |
| 995 |
+ /* we use int 255 to get back to protected mode */ |
| 996 |
+ memset(&vm86.int_revectored, 0, sizeof(vm86.int_revectored)); |
| 997 |
+ ((unsigned char *) &vm86.int_revectored)[0xff / 8] |= (1 << (0xff % 8)); /* int 0xff */ |
| 998 |
+ |
| 999 |
+ /* it's up to the caller to set the rest of the registers */ |
| 1000 |
+ vm86.regs.eflags = DEFAULT_VM86_FLAGS; |
| 1001 |
+ vm86.regs.cs = *(unsigned short *)0x42; /* 0x10 * 4 + 2 - the int map starts at 0x0 */ |
| 1002 |
+ vm86.regs.eip = *(unsigned short *)0x40; /* 0x10 * 4 */ |
| 1003 |
+ |
| 1004 |
+ /* stack @ 0x10500, size: 0x500-4 - should be enough for our needs */ |
| 1005 |
+ vm86.regs.ss = (REAL_MEM >> 4); |
| 1006 |
+ vm86.regs.esp = STACK_SIZE+RET_CODE_SIZE; |
| 1007 |
+ |
| 1008 |
+ /* these will be fetched off the stack when we come to an iret in the int's 0x10 code */ |
| 1009 |
+ VM86_PUSHW(DEFAULT_VM86_FLAGS); |
| 1010 |
+ VM86_PUSHW((REAL_MEM >> 4)); /* return code segment */ |
| 1011 |
+ VM86_PUSHW(0x0000); /* return code offset */ |
| 1012 |
+ |
| 1013 |
+ while(1) { |
| 1014 |
+ ret = vm86old(&vm86); |
| 1015 |
+ |
| 1016 |
+ if (VM86_TYPE(ret) == VM86_INTx) { |
| 1017 |
+ |
| 1018 |
+ int vint = VM86_ARG(ret); |
| 1019 |
+ |
| 1020 |
+ /* if exit from vm86 was caused by int 0xff - we're done.. */ |
| 1021 |
+ if (vint == 0xff) |
| 1022 |
+ goto vm86_done_call; |
| 1023 |
+ |
| 1024 |
+ /* .. otherwise, we have call the int handler manually */ |
| 1025 |
+ VM86_PUSHW(vm86.regs.eflags); |
| 1026 |
+ VM86_PUSHW(vm86.regs.cs); |
| 1027 |
+ VM86_PUSHW(vm86.regs.eip); |
| 1028 |
+ |
| 1029 |
+ vm86.regs.cs = *(unsigned short *)((vint << 2) + 2); |
| 1030 |
+ vm86.regs.eip = *(unsigned short *)(vint << 2); |
| 1031 |
+ vm86.regs.eflags &= ~(VIF_MASK | TF_MASK); |
| 1032 |
+ |
| 1033 |
+ } else if (VM86_TYPE(ret) == VM86_UNKNOWN) { |
| 1034 |
+ |
| 1035 |
+ u8 *instr; |
| 1036 |
+ u8 data32 = 0, segment = P_DS, rep = 0; |
| 1037 |
+ int i = 0; |
| 1038 |
+ |
| 1039 |
+ instr = (u8*)((vm86.regs.cs << 4) + vm86.regs.eip); |
| 1040 |
+ |
| 1041 |
+ while (1) { |
| 1042 |
+ |
| 1043 |
+ switch(instr[i]) { |
| 1044 |
+ |
| 1045 |
+ case 0x66: /* operand size prefix */ |
| 1046 |
+ data32 = 1 - data32; |
| 1047 |
+ i++; |
| 1048 |
+ break; |
| 1049 |
+ case 0xf2: /* repnz */ |
| 1050 |
+ case 0xf3: /* rep */ |
| 1051 |
+ rep = 1; |
| 1052 |
+ i++; |
| 1053 |
+ break; |
| 1054 |
+ case P_CS: /* segment prefix */ |
| 1055 |
+ case P_SS: |
| 1056 |
+ case P_DS: |
| 1057 |
+ case P_ES: |
| 1058 |
+ case P_FS: |
| 1059 |
+ case P_GS: |
| 1060 |
+ segment = instr[i]; |
| 1061 |
+ i++; |
| 1062 |
+ break; |
| 1063 |
+ case 0xf0: /* LOCK - ignored */ |
| 1064 |
+ case 0x67: /* address size prefix - ignored */ |
| 1065 |
+ i++; |
| 1066 |
+ break; |
| 1067 |
+ case 0x6c: /* insb */ |
| 1068 |
+ if (rep) vm86_rep_ins(1); |
| 1069 |
+ else vm86_ins(1); |
| 1070 |
+ i++; |
| 1071 |
+ goto vm86_done_emu; |
| 1072 |
+ case 0x6d: /* insw / insd */ |
| 1073 |
+ if (rep) |
| 1074 |
+ if (data32) vm86_rep_ins(4); |
| 1075 |
+ else vm86_rep_ins(2); |
| 1076 |
+ else |
| 1077 |
+ if (data32) vm86_ins(4); |
| 1078 |
+ else vm86_ins(2); |
| 1079 |
+ i++; |
| 1080 |
+ goto vm86_done_emu; |
| 1081 |
+ case 0x6e: /* outsb */ |
| 1082 |
+ if (rep) vm86_rep_outs(1, segment); |
| 1083 |
+ else vm86_outs(1, segment); |
| 1084 |
+ i++; |
| 1085 |
+ goto vm86_done_emu; |
| 1086 |
+ case 0x6f: /* outsw / outsd */ |
| 1087 |
+ if (rep) |
| 1088 |
+ if (data32) vm86_rep_outs(4, segment); |
| 1089 |
+ else vm86_rep_outs(2, segment); |
| 1090 |
+ else |
| 1091 |
+ if (data32) vm86_outs(4, segment); |
| 1092 |
+ else vm86_outs(2, segment); |
| 1093 |
+ i++; |
| 1094 |
+ goto vm86_done_emu; |
| 1095 |
+ case 0xe4: /* inb xx */ |
| 1096 |
+ asm volatile ( |
| 1097 |
+ "inb %w1, %b0" |
| 1098 |
+ : "=a" (vm86.regs.eax) |
| 1099 |
+ : "d" (instr[i+1]), "0" (vm86.regs.eax)); |
| 1100 |
+ i += 2; |
| 1101 |
+ goto vm86_done_emu; |
| 1102 |
+ case 0xe5: /* inw xx / ind xx */ |
| 1103 |
+ if (data32) |
| 1104 |
+ asm volatile ( |
| 1105 |
+ "inl %w1, %0" |
| 1106 |
+ : "=a" (vm86.regs.eax) |
| 1107 |
+ : "d" (instr[i+1]), "0" (vm86.regs.eax)); |
| 1108 |
+ else |
| 1109 |
+ asm volatile ( |
| 1110 |
+ "inw %w1, %w0" |
| 1111 |
+ : "=a" (vm86.regs.eax) |
| 1112 |
+ : "d" (instr[i+1]), "0" (vm86.regs.eax)); |
| 1113 |
+ i += 2; |
| 1114 |
+ goto vm86_done_emu; |
| 1115 |
+ case 0xec: /* inb dx */ |
| 1116 |
+ asm volatile ( |
| 1117 |
+ "inb %w1, %b0" |
| 1118 |
+ : "=a" (vm86.regs.eax) |
| 1119 |
+ : "d" (vm86.regs.edx), "0" (vm86.regs.eax)); |
| 1120 |
+ i++; |
| 1121 |
+ goto vm86_done_emu; |
| 1122 |
+ case 0xed: /* inw dx / ind dx */ |
| 1123 |
+ if (data32) |
| 1124 |
+ asm volatile ( |
| 1125 |
+ "inl %w1, %0" |
| 1126 |
+ : "=a" (vm86.regs.eax) |
| 1127 |
+ : "d" (vm86.regs.edx)); |
| 1128 |
+ else |
| 1129 |
+ asm volatile ( |
| 1130 |
+ "inw %w1, %w0" |
| 1131 |
+ : "=a" (vm86.regs.eax) |
| 1132 |
+ : "d" (vm86.regs.edx)); |
| 1133 |
+ i++; |
| 1134 |
+ goto vm86_done_emu; |
| 1135 |
+ case 0xe6: /* outb xx */ |
| 1136 |
+ asm volatile ( |
| 1137 |
+ "outb %b0, %w1" |
| 1138 |
+ : : "a" (vm86.regs.eax), "d" (instr[i+1])); |
| 1139 |
+ i += 2; |
| 1140 |
+ goto vm86_done_emu; |
| 1141 |
+ case 0xe7: /* outw xx / outd xx */ |
| 1142 |
+ if (data32) |
| 1143 |
+ asm volatile ( |
| 1144 |
+ "outl %0, %w1" |
| 1145 |
+ : : "a" (vm86.regs.eax), "d" (instr[i+1])); |
| 1146 |
+ else |
| 1147 |
+ asm volatile ( |
| 1148 |
+ "outw %w0, %w1" |
| 1149 |
+ : : "a" (vm86.regs.eax), "d" (instr[i+1])); |
| 1150 |
+ i += 2; |
| 1151 |
+ goto vm86_done_emu; |
| 1152 |
+ case 0xee: /* outb dx */ |
| 1153 |
+ asm volatile ( |
| 1154 |
+ "outb %b0, %w1" |
| 1155 |
+ : : "a" (vm86.regs.eax), "d" (vm86.regs.edx)); |
| 1156 |
+ i++; |
| 1157 |
+ goto vm86_done_emu; |
| 1158 |
+ case 0xef: /* outw dx / outd dx */ |
| 1159 |
+ if (data32) |
| 1160 |
+ asm volatile ( |
| 1161 |
+ "outl %0, %w1" |
| 1162 |
+ : : "a" (vm86.regs.eax), "d" (vm86.regs.edx)); |
| 1163 |
+ else |
| 1164 |
+ asm volatile ( |
| 1165 |
+ "outw %w0, %w1" |
| 1166 |
+ : : "a" (vm86.regs.eax), "d" (vm86.regs.edx)); |
| 1167 |
+ i++; |
| 1168 |
+ goto vm86_done_emu; |
| 1169 |
+ default: |
| 1170 |
+ printk(KERN_ERR "vesafb: BUG, opcode %x emulation not supported\n", instr[i]); |
| 1171 |
+ goto vm86_done_call; |
| 1172 |
+ } |
| 1173 |
+ } |
| 1174 |
+vm86_done_emu: vm86.regs.eip += i; |
| 1175 |
+ } else { |
| 1176 |
+ printk(KERN_ERR "vesafb: BUG, returned from vm86 with %x\n", ret); |
| 1177 |
+ goto vm86_done_call; |
| 1178 |
+ } |
| 1179 |
+ } |
| 1180 |
+ |
| 1181 |
+vm86_done_call: |
| 1182 |
+ |
| 1183 |
+ /* copy the registers' state back to the caller's struct */ |
| 1184 |
+ memcpy(regs, &vm86.regs, sizeof(struct vm86_regs)); |
| 1185 |
+} |
| 1186 |
+ |
| 1187 |
+#define vesafb_get_string(str) { \ |
| 1188 |
+ \ |
| 1189 |
+ /* the address is in the form ssssoooo, where oooo = offset, ssss = segment */ \ |
| 1190 |
+ addr = ((vbe_pib(task->res)->str & 0xffff0000) >> 12) + \ |
| 1191 |
+ (vbe_pib(task->res)->str & 0x0000ffff); \ |
| 1192 |
+ \ |
| 1193 |
+ /* the data is in ROM which is shared between processes, so we just translate the \ |
| 1194 |
+ real mode address into one visible from the kernel space */ \ |
| 1195 |
+ if (addr >= 0xa0000) { \ |
| 1196 |
+ vbe_pib(task->res)->str = (u32) __va(addr); \ |
| 1197 |
+ \ |
| 1198 |
+ /* the data is in the buffer, we just have to convert the address so that it would \ |
| 1199 |
+ point into the buffer user provided */ \ |
| 1200 |
+ } else if (addr > REAL_MEM+BUFFER && addr < REAL_MEM+BUFFER + \ |
| 1201 |
+ sizeof(struct vesafb_vbe_info_block)) { \ |
| 1202 |
+ addr -= BUFFER+REAL_MEM; \ |
| 1203 |
+ vbe_pib(task->res)->str = (u32) (task->res + addr); \ |
| 1204 |
+ \ |
| 1205 |
+ /* this should never happen: someone was insane enough to put the data somewhere in the RAM */ \ |
| 1206 |
+ } else { \ |
| 1207 |
+ vbe_pib(task->res)->str = (u32) ""; \ |
| 1208 |
+ } \ |
| 1209 |
+} |
| 1210 |
+ |
| 1211 |
+void vesafb_handle_tasks(void) |
| 1212 |
+{ |
| 1213 |
+ struct vesafb_task *task; |
| 1214 |
+ struct list_head *node, *next; |
| 1215 |
+ int addr, res; |
| 1216 |
+ |
| 1217 |
+ down(&vesafb_sem); |
| 1218 |
+ list_for_each_safe(node, next, &vesafb_task_list) { |
| 1219 |
+ |
| 1220 |
+ task = container_of(node, struct vesafb_task, node); |
| 1221 |
+ |
| 1222 |
+ switch (task->type) { |
| 1223 |
+ |
| 1224 |
+ case VESAFB_TASK_DOVM86: |
| 1225 |
+ vesafb_do_vm86(&task->regs); |
| 1226 |
+ break; |
| 1227 |
+ |
| 1228 |
+ case VESAFB_TASK_GETVBE_IB: |
| 1229 |
+ task->regs.es = (REAL_MEM >> 4); |
| 1230 |
+ task->regs.edi = BUFFER; |
| 1231 |
+ strncpy(vbe_pib(REAL_MEM+BUFFER)->vbe_signature,"VBE2",4); |
| 1232 |
+ |
| 1233 |
+ vesafb_do_vm86(&task->regs); |
| 1234 |
+ |
| 1235 |
+ memcpy(task->res, (void*)(REAL_MEM + BUFFER), sizeof(struct vesafb_vbe_info_block)); |
| 1236 |
+ |
| 1237 |
+ /* the OEM fields were not defined prior to VBE 2.0 */ |
| 1238 |
+ if (vbe_pib(task->res)->vbe_version >= 0x200) { |
| 1239 |
+ vesafb_get_string(oem_string_ptr); |
| 1240 |
+ vesafb_get_string(oem_vendor_name_ptr); |
| 1241 |
+ vesafb_get_string(oem_product_name_ptr); |
| 1242 |
+ vesafb_get_string(oem_product_rev_ptr); |
| 1243 |
+ } |
| 1244 |
+ |
| 1245 |
+ /* this is basically the same as vesafb_get_string */ |
| 1246 |
+ addr = ((vbe_pib(task->res)->mode_list_ptr & 0xffff0000) >> 12) + |
| 1247 |
+ (vbe_pib(task->res)->mode_list_ptr & 0x0000ffff); |
| 1248 |
+ |
| 1249 |
+ if (addr >= 0xa0000) { |
| 1250 |
+ vbe_pib(task->res)->mode_list_ptr = (u32) __va(addr); |
| 1251 |
+ } else if (addr > REAL_MEM+BUFFER && addr < REAL_MEM+BUFFER + |
| 1252 |
+ sizeof(struct vesafb_vbe_info_block)) |
| 1253 |
+ { |
| 1254 |
+ addr -= BUFFER+REAL_MEM; |
| 1255 |
+ vbe_pib(task->res)->mode_list_ptr = (u32) (task->res + addr); |
| 1256 |
+ } else { |
| 1257 |
+ res = 0; |
| 1258 |
+ printk(KERN_WARNING "vesafb: warning, copying modelist from somewhere in RAM!\n"); |
| 1259 |
+ while (*(u16*)(addr+res) != 0xffff && |
| 1260 |
+ res < (sizeof(vbe_pib(task->res)->reserved) - 2) ) |
| 1261 |
+ { |
| 1262 |
+ *(u16*) ((u32)&(vbe_pib(task->res)->reserved) + res) = |
| 1263 |
+ *(u16*)(addr+res); |
| 1264 |
+ res += 2; |
| 1265 |
+ } |
| 1266 |
+ |
| 1267 |
+ *(u16*) ((u32)&(vbe_pib(task->res)->reserved) + res) = 0xffff; |
| 1268 |
+ } |
| 1269 |
+ break; |
| 1270 |
+ |
| 1271 |
+ case VESAFB_TASK_GETVBE_MODEINFO: |
| 1272 |
+ task->regs.es = (REAL_MEM >> 4); |
| 1273 |
+ task->regs.edi = BUFFER; |
| 1274 |
+ vesafb_do_vm86(&task->regs); |
| 1275 |
+ memcpy(task->res, (void*)(REAL_MEM + BUFFER), sizeof(struct vesafb_mode_info_block)); |
| 1276 |
+ break; |
| 1277 |
+ |
| 1278 |
+ case VESAFB_TASK_SWITCHMODE: |
| 1279 |
+ if (task->res != NULL) { |
| 1280 |
+ task->regs.es = (REAL_MEM >> 4); |
| 1281 |
+ task->regs.edi = BUFFER; |
| 1282 |
+ memcpy((void*)(REAL_MEM + BUFFER), task->res, sizeof(struct vesafb_crtc_info_block)); |
| 1283 |
+ } |
| 1284 |
+ |
| 1285 |
+ vesafb_do_vm86(&task->regs); |
| 1286 |
+ break; |
| 1287 |
+ |
| 1288 |
+ case VESAFB_TASK_SETPAL: |
| 1289 |
+ task->regs.es = (REAL_MEM >> 4); |
| 1290 |
+ task->regs.edi = BUFFER; |
| 1291 |
+ memcpy((void*)(REAL_MEM + BUFFER), task->res, sizeof(struct vesafb_pal_entry)); |
| 1292 |
+ vesafb_do_vm86(&task->regs); |
| 1293 |
+ break; |
| 1294 |
+ |
| 1295 |
+ case VESAFB_TASK_GETEDID: |
| 1296 |
+ task->regs.es = (REAL_MEM >> 4); |
| 1297 |
+ task->regs.edi = BUFFER; |
| 1298 |
+ vesafb_do_vm86(&task->regs); |
| 1299 |
+ memcpy(task->res, (void*)(REAL_MEM + BUFFER), EDID_LENGTH); |
| 1300 |
+ |
| 1301 |
+ default: |
| 1302 |
+ break; |
| 1303 |
+ } |
| 1304 |
+ |
| 1305 |
+ task->done = 1; |
| 1306 |
+ if (task->flags & VESAFB_FLAG_FREESTRUCT) { |
| 1307 |
+ kfree(task); |
| 1308 |
+ } |
| 1309 |
+ } |
| 1310 |
+ |
| 1311 |
+ up(&vesafb_sem); |
| 1312 |
+ list_del_init(node); |
| 1313 |
+} |
| 1314 |
+ |
| 1315 |
+int vesafb_thread(void *unused) |
| 1316 |
+{ |
| 1317 |
+ struct vm_area_struct vma; |
| 1318 |
+ struct page *page; |
| 1319 |
+ |
| 1320 |
+ int ret, err = 0; |
| 1321 |
+ void *mem; |
| 1322 |
+ |
| 1323 |
+ set_fs(KERNEL_DS); |
| 1324 |
+ daemonize("vesafb"); |
| 1325 |
+ DPRINTK("started vesafb thread\n"); |
| 1326 |
+ |
| 1327 |
+ current->mm = current->active_mm; |
| 1328 |
+ mem = kmalloc(REAL_MEM_SIZE,GFP_KERNEL); |
| 1329 |
+ |
| 1330 |
+ if (!mem) |
| 1331 |
+ return -ENOMEM; |
| 1332 |
+ |
| 1333 |
+ for (page = virt_to_page(mem); page < virt_to_page(mem+REAL_MEM_SIZE); page++) { |
| 1334 |
+ SetPageReserved(page); |
| 1335 |
+ } |
| 1336 |
+ |
| 1337 |
+#ifdef CONFIG_SMP |
| 1338 |
+ cpus_clear(current->active_mm->cpu_vm_mask); |
| 1339 |
+ cpu_set(smp_processor_id(), current->active_mm->cpu_vm_mask); |
| 1340 |
+#endif |
| 1341 |
+ |
| 1342 |
+ vma.vm_mm = current->active_mm; |
| 1343 |
+ vma.vm_page_prot.pgprot = PROT_READ | PROT_EXEC | PROT_WRITE; |
| 1344 |
+ |
| 1345 |
+ ret = io_remap_page_range(&vma, 0x000000, __pa(mem), REAL_MEM_SIZE, vma.vm_page_prot); |
| 1346 |
+ ret += io_remap_page_range(&vma, 0x0a0000, 0x0a0000, 0x100000 - 0x0a0000, vma.vm_page_prot); |
| 1347 |
+ |
| 1348 |
+ if (ret) { |
| 1349 |
+ printk(KERN_ERR "vesafb thread: memory remapping failed\n"); |
| 1350 |
+ err = -EINVAL; |
| 1351 |
+ goto thr_end; |
| 1352 |
+ } |
| 1353 |
+ |
| 1354 |
+ /* copy the first 0x20000 bytes from low mem to our private memory, which is |
| 1355 |
+ * then used for the vm86 calls */ |
| 1356 |
+ memcpy((void*)0x0, __va(0x0), REAL_MEM_SIZE); |
| 1357 |
+ |
| 1358 |
+ ioperm(0,1024,1); /* we can live if it fails, so don't bother checking for errors */ |
| 1359 |
+ set_user_nice(current, -10); |
| 1360 |
+ |
| 1361 |
+ while (1) { |
| 1362 |
+ vesafb_handle_tasks(); |
| 1363 |
+ wait_event_interruptible(vesafb_wait, !list_empty(&vesafb_task_list)); |
| 1364 |
+ if (current->flags & PF_FREEZE) |
| 1365 |
+ refrigerator(PF_FREEZE); |
| 1366 |
+ |
| 1367 |
+ if (signal_pending(current)) |
| 1368 |
+ break; |
| 1369 |
+ } |
| 1370 |
+ |
| 1371 |
+thr_end: |
| 1372 |
+ DPRINTK("exiting the vesafb thread\n"); |
| 1373 |
+ vesafb_pid = 0; |
| 1374 |
+ |
| 1375 |
+ for (page = virt_to_page(mem); page < virt_to_page(mem+REAL_MEM_SIZE); page++) { |
| 1376 |
+ ClearPageReserved(page); |
| 1377 |
+ } |
| 1378 |
+ |
| 1379 |
+ kfree(mem); |
| 1380 |
+ return err; |
| 1381 |
+} |
| 1382 |
+ |
| 1383 |
+int vesafb_init_thread(void) |
| 1384 |
+{ |
| 1385 |
+ vesafb_pid = kernel_thread(vesafb_thread,NULL,0); |
| 1386 |
+ return 0; |
| 1387 |
+} |
| 1388 |
+ |
| 1389 |
+EXPORT_SYMBOL(vesafb_pid); |
| 1390 |
+EXPORT_SYMBOL(vesafb_queue_task); |
| 1391 |
diff -Nru a/drivers/video/vesafb-tng.c b/drivers/video/vesafb-tng.c |
| 1392 |
--- /dev/null Wed Dec 31 16:00:00 196900 |
| 1393 |
+++ b/drivers/video/vesafb-tng.c 2005-01-15 14:00:49 +01:00 |
| 1394 |
@@ -0,0 +1,1221 @@ |
| 1395 |
+/* |
| 1396 |
+ * Framebuffer driver for VBE 2.0+ compliant graphic boards |
| 1397 |
+ * |
| 1398 |
+ * (c) 2004 Micha³ Januszewski <spock@gentoo.org> |
| 1399 |
+ * Based upon vesafb code by Gerd Knorr <kraxel@goldbach.in-berlin.de> |
| 1400 |
+ * |
| 1401 |
+ */ |
| 1402 |
+ |
| 1403 |
+#ifdef DEBUG |
| 1404 |
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) |
| 1405 |
+#else |
| 1406 |
+#define DPRINTK(fmt, args...) |
| 1407 |
+#endif |
| 1408 |
+ |
| 1409 |
+#include <linux/module.h> |
| 1410 |
+#include <linux/kernel.h> |
| 1411 |
+#include <linux/errno.h> |
| 1412 |
+#include <linux/string.h> |
| 1413 |
+#include <linux/mm.h> |
| 1414 |
+#include <linux/tty.h> |
| 1415 |
+#include <linux/delay.h> |
| 1416 |
+#include <linux/fb.h> |
| 1417 |
+#include <linux/ioport.h> |
| 1418 |
+#include <linux/init.h> |
| 1419 |
+#include <linux/proc_fs.h> |
| 1420 |
+#include <video/edid.h> |
| 1421 |
+#include <video/vesa.h> |
| 1422 |
+ |
| 1423 |
+#include <asm/io.h> |
| 1424 |
+#include <asm/mtrr.h> |
| 1425 |
+#include "edid.h" |
| 1426 |
+ |
| 1427 |
+#define dac_reg (0x3c8) |
| 1428 |
+#define dac_val (0x3c9) |
| 1429 |
+ |
| 1430 |
+#define VESAFB_NEED_EXACT_RES 1 |
| 1431 |
+#define VESAFB_NEED_EXACT_DEPTH 2 |
| 1432 |
+ |
| 1433 |
+/* --------------------------------------------------------------------- */ |
| 1434 |
+ |
| 1435 |
+static struct fb_var_screeninfo vesafb_defined __initdata = { |
| 1436 |
+ .activate = FB_ACTIVATE_NOW, |
| 1437 |
+ .height = -1, |
| 1438 |
+ .width = -1, |
| 1439 |
+ .right_margin = 32, |
| 1440 |
+ .upper_margin = 16, |
| 1441 |
+ .lower_margin = 4, |
| 1442 |
+ .vsync_len = 4, |
| 1443 |
+ .vmode = FB_VMODE_NONINTERLACED, |
| 1444 |
+}; |
| 1445 |
+ |
| 1446 |
+static struct fb_fix_screeninfo vesafb_fix __initdata = { |
| 1447 |
+ .id = "VESA VGA", |
| 1448 |
+ .type = FB_TYPE_PACKED_PIXELS, |
| 1449 |
+ .accel = FB_ACCEL_NONE, |
| 1450 |
+}; |
| 1451 |
+ |
| 1452 |
+static int mtrr = 1; /* use MTRR */ |
| 1453 |
+static int ypan = 0; /* 0 - nothing, 1 - ypan, 2 -ywrap */ |
| 1454 |
+static int pmi_setpal = 0; /* pmi for palette changes */ |
| 1455 |
+static unsigned short *pmi_base = NULL; /* protected mode interface location in memory */ |
| 1456 |
+static void (*pmi_start)(void) = NULL; |
| 1457 |
+static void (*pmi_pal)(void) = NULL; |
| 1458 |
+static struct task_struct *vesafb_serv_thread = NULL; |
| 1459 |
+static struct vesafb_vbe_info_block vbe_ib; |
| 1460 |
+static struct vesafb_mode_info_block *vbe_modes; |
| 1461 |
+static int vbe_modes_cnt = 0; |
| 1462 |
+static u8 mon_limits = 0; /* 0 - no monitor limits, 1 - full monitor limits, |
| 1463 |
+ 2 - monitor limits with default pixel clock */ |
| 1464 |
+static int nocrtc = 0; /* ignore CRTC settings */ |
| 1465 |
+static struct fb_info *vesafb_info = NULL; |
| 1466 |
+static struct fb_videomode *edid_modes __initdata = NULL; |
| 1467 |
+static int edid_modes_cnt __initdata = 0; |
| 1468 |
+static int noedid __initdata = 0; /* don't try the DDC transfers */ |
| 1469 |
+static int vram_remap __initdata = 0; /* set amount of memory to be used */ |
| 1470 |
+static int vram_total __initdata = 0; /* set total amount of memory */ |
| 1471 |
+static unsigned short maxclk __initdata = 0; /* maximum pixel clock */ |
| 1472 |
+static unsigned short maxvf __initdata = 0; /* maximum vertical frequency */ |
| 1473 |
+static unsigned short maxhf __initdata = 0; /* maximum horizontal frequency */ |
| 1474 |
+static int gtf __initdata = 0; /* forces use of the GTF */ |
| 1475 |
+static char *mode_option __initdata = NULL; |
| 1476 |
+static unsigned short vbemode = 0; |
| 1477 |
+ |
| 1478 |
+extern int vesafb_pid; /* PID of the vesafb service thread */ |
| 1479 |
+ |
| 1480 |
+/* --------------------------------------------------------------------- */ |
| 1481 |
+ |
| 1482 |
+#define vesafb_create_task(task) { task = kmalloc(sizeof(struct vesafb_task), GFP_ATOMIC); \ |
| 1483 |
+ if (task) memset(task,0,sizeof(struct vesafb_task)); } |
| 1484 |
+ |
| 1485 |
+#define vesafb_wait_for_task(task) { while (task->done == 0) { schedule(); } } |
| 1486 |
+ |
| 1487 |
+extern void vesafb_queue_task(struct vesafb_task *task); |
| 1488 |
+static int vesafb_find_vbe_mode(int xres, int yres, int bpp, unsigned char flags); |
| 1489 |
+ |
| 1490 |
+/* --------------------------------------------------------------------- */ |
| 1491 |
+ |
| 1492 |
+static int vesafb_pan_display(struct fb_var_screeninfo *var, |
| 1493 |
+ struct fb_info *info) |
| 1494 |
+{ |
| 1495 |
+#ifdef __i386__ |
| 1496 |
+ int offset; |
| 1497 |
+ |
| 1498 |
+ if (!ypan) |
| 1499 |
+ return -EINVAL; |
| 1500 |
+ if (var->xoffset) |
| 1501 |
+ return -EINVAL; |
| 1502 |
+ if (var->yoffset > var->yres_virtual) |
| 1503 |
+ return -EINVAL; |
| 1504 |
+ if ((ypan==1) && var->yoffset+var->yres > var->yres_virtual) |
| 1505 |
+ return -EINVAL; |
| 1506 |
+ |
| 1507 |
+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4; |
| 1508 |
+ |
| 1509 |
+ /* It turns out it's not the best idea to do panning via vm86, |
| 1510 |
+ * so we only allow it if we have a PMI */ |
| 1511 |
+ if (pmi_start) { |
| 1512 |
+ __asm__ __volatile__( |
| 1513 |
+ "call *(%%edi)" |
| 1514 |
+ : /* no return value */ |
| 1515 |
+ : "a" (0x4f07), /* EAX */ |
| 1516 |
+ "b" (0), /* EBX */ |
| 1517 |
+ "c" (offset), /* ECX */ |
| 1518 |
+ "d" (offset >> 16), /* EDX */ |
| 1519 |
+ "D" (&pmi_start)); /* EDI */ |
| 1520 |
+ } |
| 1521 |
+#endif |
| 1522 |
+ return 0; |
| 1523 |
+} |
| 1524 |
+ |
| 1525 |
+static void vesa_setpalette(int regno, unsigned red, unsigned green, unsigned blue, int shift) |
| 1526 |
+{ |
| 1527 |
+ struct vesafb_pal_entry entry; |
| 1528 |
+ struct vesafb_task *mytask; |
| 1529 |
+ |
| 1530 |
+#ifdef __i386__ |
| 1531 |
+ entry.red = red >> shift; |
| 1532 |
+ entry.green = green >> shift; |
| 1533 |
+ entry.blue = blue >> shift; |
| 1534 |
+ entry.pad = 0; |
| 1535 |
+ |
| 1536 |
+ if (pmi_setpal) { |
| 1537 |
+ __asm__ __volatile__( |
| 1538 |
+ "call *(%%esi)" |
| 1539 |
+ : /* no return value */ |
| 1540 |
+ : "a" (0x4f09), /* EAX */ |
| 1541 |
+ "b" (0), /* EBX */ |
| 1542 |
+ "c" (1), /* ECX */ |
| 1543 |
+ "d" (regno), /* EDX */ |
| 1544 |
+ "D" (&entry), /* EDI */ |
| 1545 |
+ "S" (&pmi_pal)); /* ESI */ |
| 1546 |
+ } else { |
| 1547 |
+ vesafb_create_task (mytask); |
| 1548 |
+ |
| 1549 |
+ mytask->regs.eax = 0x4f09; |
| 1550 |
+ mytask->regs.ebx = 0x0; |
| 1551 |
+ mytask->regs.ecx = 1; |
| 1552 |
+ mytask->regs.edx = regno; |
| 1553 |
+ mytask->res = &entry; |
| 1554 |
+ mytask->type = VESAFB_TASK_SETPAL; |
| 1555 |
+ |
| 1556 |
+ vesafb_queue_task (mytask); |
| 1557 |
+ vesafb_wait_for_task(mytask); |
| 1558 |
+ kfree(mytask); |
| 1559 |
+ } |
| 1560 |
+#endif |
| 1561 |
+} |
| 1562 |
+ |
| 1563 |
+static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green, |
| 1564 |
+ unsigned blue, unsigned transp, |
| 1565 |
+ struct fb_info *info) |
| 1566 |
+{ |
| 1567 |
+ /* |
| 1568 |
+ * Set a single color register. The values supplied are |
| 1569 |
+ * already rounded down to the hardware's capabilities |
| 1570 |
+ * (according to the entries in the `var' structure). Return |
| 1571 |
+ * != 0 for invalid regno. |
| 1572 |
+ */ |
| 1573 |
+ |
| 1574 |
+ if (regno >= info->cmap.len) |
| 1575 |
+ return 1; |
| 1576 |
+ |
| 1577 |
+ switch (info->var.bits_per_pixel) { |
| 1578 |
+ case 8: |
| 1579 |
+ vesa_setpalette(regno,red,green,blue,16 - info->var.green.length); |
| 1580 |
+ break; |
| 1581 |
+ case 16: |
| 1582 |
+ if (info->var.red.offset == 10) { |
| 1583 |
+ /* 1:5:5:5 */ |
| 1584 |
+ ((u32*) (info->pseudo_palette))[regno] = |
| 1585 |
+ ((red & 0xf800) >> 1) | |
| 1586 |
+ ((green & 0xf800) >> 6) | |
| 1587 |
+ ((blue & 0xf800) >> 11); |
| 1588 |
+ } else { |
| 1589 |
+ /* 0:5:6:5 */ |
| 1590 |
+ ((u32*) (info->pseudo_palette))[regno] = |
| 1591 |
+ ((red & 0xf800) ) | |
| 1592 |
+ ((green & 0xfc00) >> 5) | |
| 1593 |
+ ((blue & 0xf800) >> 11); |
| 1594 |
+ } |
| 1595 |
+ break; |
| 1596 |
+ case 24: |
| 1597 |
+ red >>= 8; |
| 1598 |
+ green >>= 8; |
| 1599 |
+ blue >>= 8; |
| 1600 |
+ ((u32 *)(info->pseudo_palette))[regno] = |
| 1601 |
+ (red << info->var.red.offset) | |
| 1602 |
+ (green << info->var.green.offset) | |
| 1603 |
+ (blue << info->var.blue.offset); |
| 1604 |
+ break; |
| 1605 |
+ case 32: |
| 1606 |
+ red >>= 8; |
| 1607 |
+ green >>= 8; |
| 1608 |
+ blue >>= 8; |
| 1609 |
+ ((u32 *)(info->pseudo_palette))[regno] = |
| 1610 |
+ (red << info->var.red.offset) | |
| 1611 |
+ (green << info->var.green.offset) | |
| 1612 |
+ (blue << info->var.blue.offset); |
| 1613 |
+ break; |
| 1614 |
+ } |
| 1615 |
+ return 0; |
| 1616 |
+} |
| 1617 |
+ |
| 1618 |
+static int vesafb_set_par(struct fb_info *info) |
| 1619 |
+{ |
| 1620 |
+ struct vesafb_par *par = (struct vesafb_par *) info->par; |
| 1621 |
+ struct vesafb_task *mytask; |
| 1622 |
+ struct vesafb_crtc_info_block *crtc = NULL; |
| 1623 |
+ struct vesafb_mode_info_block *mode = NULL; |
| 1624 |
+ int err = 0, i; |
| 1625 |
+ |
| 1626 |
+ /* has the VBE mode number been specified? */ |
| 1627 |
+ if (vbemode > 0) { |
| 1628 |
+ for (i = 0; i < vbe_modes_cnt; i++) { |
| 1629 |
+ if (vbe_modes[i].mode_id == vbemode) { |
| 1630 |
+ mode = &vbe_modes[i]; |
| 1631 |
+ break; |
| 1632 |
+ } |
| 1633 |
+ } |
| 1634 |
+ } else { |
| 1635 |
+ i = vesafb_find_vbe_mode(info->var.xres, info->var.yres, |
| 1636 |
+ info->var.bits_per_pixel, VESAFB_NEED_EXACT_RES | VESAFB_NEED_EXACT_DEPTH); |
| 1637 |
+ if (i > 0) |
| 1638 |
+ mode = &vbe_modes[i]; |
| 1639 |
+ } |
| 1640 |
+ |
| 1641 |
+ if (mode == NULL) |
| 1642 |
+ return -EINVAL; |
| 1643 |
+ |
| 1644 |
+ vesafb_create_task (mytask); |
| 1645 |
+ |
| 1646 |
+ mytask->regs.eax = 0x4f02; |
| 1647 |
+ mytask->regs.ebx = mode->mode_id | 0x4000; /* use LFB */ |
| 1648 |
+ |
| 1649 |
+ if (vbe_ib.vbe_version >= 0x0300 && !nocrtc && !vbemode) { |
| 1650 |
+ |
| 1651 |
+ mytask->regs.ebx |= 0x0800; /* use CRTC data */ |
| 1652 |
+ crtc = kmalloc(sizeof(struct vesafb_crtc_info_block), GFP_KERNEL); |
| 1653 |
+ |
| 1654 |
+ if (!crtc) { |
| 1655 |
+ err = -ENOMEM; |
| 1656 |
+ goto out; |
| 1657 |
+ } |
| 1658 |
+ crtc->horiz_start = info->var.xres + info->var.right_margin; |
| 1659 |
+ crtc->horiz_end = crtc->horiz_start + info->var.hsync_len; |
| 1660 |
+ crtc->horiz_total = crtc->horiz_end + info->var.left_margin; |
| 1661 |
+ |
| 1662 |
+ crtc->vert_start = info->var.yres + info->var.lower_margin; |
| 1663 |
+ crtc->vert_end = crtc->vert_start + info->var.vsync_len; |
| 1664 |
+ crtc->vert_total = crtc->vert_end + info->var.upper_margin; |
| 1665 |
+ |
| 1666 |
+ crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000; |
| 1667 |
+ crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock / (crtc->vert_total * crtc->horiz_total))); |
| 1668 |
+ crtc->flags = 0; |
| 1669 |
+ |
| 1670 |
+ if (info->var.vmode & FB_VMODE_DOUBLE) |
| 1671 |
+ crtc->flags |= 0x1; |
| 1672 |
+ |
| 1673 |
+ if (info->var.vmode & FB_VMODE_INTERLACED) |
| 1674 |
+ crtc->flags |= 0x2; |
| 1675 |
+ |
| 1676 |
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) |
| 1677 |
+ crtc->flags |= 0x4; |
| 1678 |
+ |
| 1679 |
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) |
| 1680 |
+ crtc->flags |= 0x8; |
| 1681 |
+ |
| 1682 |
+ memcpy(&par->crtc, crtc, sizeof(struct vesafb_crtc_info_block)); |
| 1683 |
+ } else |
| 1684 |
+ memset(&par->crtc, 0, sizeof(struct vesafb_crtc_info_block)); |
| 1685 |
+ |
| 1686 |
+ mytask->res = (void*)crtc; |
| 1687 |
+ mytask->type = VESAFB_TASK_SWITCHMODE; |
| 1688 |
+ |
| 1689 |
+ vesafb_queue_task (mytask); |
| 1690 |
+ vesafb_wait_for_task(mytask); |
| 1691 |
+ |
| 1692 |
+ if ((mytask->regs.eax & 0xffff) != 0x004f) { |
| 1693 |
+ printk(KERN_ERR "vesafb: mode switch failed (eax: 0x%lx)\n", mytask->regs.eax); |
| 1694 |
+ err = -EINVAL; |
| 1695 |
+ goto out; |
| 1696 |
+ } |
| 1697 |
+ |
| 1698 |
+ /* the VBE mode number is valid only the first time the mode is set */ |
| 1699 |
+ if (vbemode) |
| 1700 |
+ vbemode = 0; |
| 1701 |
+ |
| 1702 |
+ if (vbe_ib.capabilities & VESAFB_CAP_CAN_SWITCH_DAC && mode->bits_per_pixel <= 8) { |
| 1703 |
+ mytask->done = 0; |
| 1704 |
+ mytask->type = VESAFB_TASK_DOVM86; |
| 1705 |
+ mytask->regs.eax = 0x4f08; |
| 1706 |
+ mytask->regs.ebx = 0x0800; |
| 1707 |
+ |
| 1708 |
+ vesafb_queue_task (mytask); |
| 1709 |
+ vesafb_wait_for_task(mytask); |
| 1710 |
+ |
| 1711 |
+ if ((mytask->regs.eax & 0xffff) != 0x004f || |
| 1712 |
+ ((mytask->regs.ebx & 0xff00) >> 8) != 8) { |
| 1713 |
+ |
| 1714 |
+ /* we've failed to set the DAC palette format - time to correct var */ |
| 1715 |
+ info->var.red.length = 6; |
| 1716 |
+ info->var.green.length = 6; |
| 1717 |
+ info->var.blue.length = 6; |
| 1718 |
+ } |
| 1719 |
+ } |
| 1720 |
+ |
| 1721 |
+ info->fix.visual = (info->var.bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
| 1722 |
+ info->fix.line_length = mode->bytes_per_scan_line; |
| 1723 |
+ par->vbe_mode = mode->mode_id; |
| 1724 |
+ |
| 1725 |
+ DPRINTK("set new mode %dx%d-%d (0x%x)\n", info->var.xres, info->var.yres, info->var.bits_per_pixel, mode->mode_id); |
| 1726 |
+ |
| 1727 |
+out: if (crtc != NULL) |
| 1728 |
+ kfree(crtc); |
| 1729 |
+ kfree(mytask); |
| 1730 |
+ |
| 1731 |
+ return err; |
| 1732 |
+} |
| 1733 |
+ |
| 1734 |
+static void vesafb_setup_var(struct fb_var_screeninfo *var, struct fb_info *info, |
| 1735 |
+ struct vesafb_mode_info_block *mode) |
| 1736 |
+{ |
| 1737 |
+ var->xres = mode->x_res; |
| 1738 |
+ var->yres = mode->y_res; |
| 1739 |
+ var->xres_virtual = mode->x_res; |
| 1740 |
+ var->yres_virtual = (ypan) ? info->fix.smem_len / mode->bytes_per_scan_line : mode->y_res; |
| 1741 |
+ var->xoffset = 0; |
| 1742 |
+ var->yoffset = 0; |
| 1743 |
+ var->bits_per_pixel = mode->bits_per_pixel; |
| 1744 |
+ |
| 1745 |
+ if (var->bits_per_pixel == 15) |
| 1746 |
+ var->bits_per_pixel = 16; |
| 1747 |
+ |
| 1748 |
+ if (var->bits_per_pixel > 8) { |
| 1749 |
+ var->red.offset = mode->red_off; |
| 1750 |
+ var->red.length = mode->red_len; |
| 1751 |
+ var->green.offset = mode->green_off; |
| 1752 |
+ var->green.length = mode->green_len; |
| 1753 |
+ var->blue.offset = mode->blue_off; |
| 1754 |
+ var->blue.length = mode->blue_len; |
| 1755 |
+ var->transp.offset = mode->rsvd_off; |
| 1756 |
+ var->transp.length = mode->rsvd_len; |
| 1757 |
+ |
| 1758 |
+ DPRINTK("directcolor: size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n", |
| 1759 |
+ mode->rsvd_len, |
| 1760 |
+ mode->red_len, |
| 1761 |
+ mode->green_len, |
| 1762 |
+ mode->blue_len, |
| 1763 |
+ mode->rsvd_off, |
| 1764 |
+ mode->red_off, |
| 1765 |
+ mode->green_off, |
| 1766 |
+ mode->blue_off); |
| 1767 |
+ } else { |
| 1768 |
+ var->red.offset = 0; |
| 1769 |
+ var->green.offset = 0; |
| 1770 |
+ var->blue.offset = 0; |
| 1771 |
+ var->transp.offset = 0; |
| 1772 |
+ |
| 1773 |
+ /* We're assuming that we can switch the DAC to 8 bits. If this proves |
| 1774 |
+ * to be incorrect, we'll update the fields later in set_par. */ |
| 1775 |
+ if (vbe_ib.capabilities & VESAFB_CAP_CAN_SWITCH_DAC) { |
| 1776 |
+ var->red.length = 8; |
| 1777 |
+ var->green.length = 8; |
| 1778 |
+ var->blue.length = 8; |
| 1779 |
+ var->transp.length = 0; |
| 1780 |
+ } else { |
| 1781 |
+ var->red.length = 6; |
| 1782 |
+ var->green.length = 6; |
| 1783 |
+ var->blue.length = 6; |
| 1784 |
+ var->transp.length = 0; |
| 1785 |
+ } |
| 1786 |
+ } |
| 1787 |
+} |
| 1788 |
+ |
| 1789 |
+static int inline vesafb_check_limits(struct fb_var_screeninfo *var, struct fb_info *info) |
| 1790 |
+{ |
| 1791 |
+ if (mon_limits) |
| 1792 |
+ return fb_validate_mode(var, info); |
| 1793 |
+ else |
| 1794 |
+ return 0; |
| 1795 |
+} |
| 1796 |
+ |
| 1797 |
+static int vesafb_find_vbe_mode(int xres, int yres, int bpp, unsigned char flags) |
| 1798 |
+{ |
| 1799 |
+ int i, match = -1, h = 0, d = 0x7fffffff; |
| 1800 |
+ |
| 1801 |
+ for (i = 0; i < vbe_modes_cnt; i++) { |
| 1802 |
+ |
| 1803 |
+ h = abs(vbe_modes[i].x_res - xres) + abs(vbe_modes[i].y_res - yres) + |
| 1804 |
+ abs(bpp - vbe_modes[i].bits_per_pixel); |
| 1805 |
+ |
| 1806 |
+ if (h == 0) |
| 1807 |
+ return i; |
| 1808 |
+ |
| 1809 |
+ if (h < d || (h == d && vbe_modes[i].bits_per_pixel > bpp)) { |
| 1810 |
+ d = h; |
| 1811 |
+ match = i; |
| 1812 |
+ } |
| 1813 |
+ } |
| 1814 |
+ |
| 1815 |
+ i = 1; |
| 1816 |
+ |
| 1817 |
+ if (flags & VESAFB_NEED_EXACT_RES && d > 24) |
| 1818 |
+ i = 0; |
| 1819 |
+ |
| 1820 |
+ if (flags & VESAFB_NEED_EXACT_DEPTH && d > 1) |
| 1821 |
+ i = 0; |
| 1822 |
+ |
| 1823 |
+ if (i != 0) |
| 1824 |
+ return match; |
| 1825 |
+ else |
| 1826 |
+ return -1; |
| 1827 |
+} |
| 1828 |
+ |
| 1829 |
+static int vesafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
| 1830 |
+{ |
| 1831 |
+ int match = -1; |
| 1832 |
+ |
| 1833 |
+ if (vesafb_check_limits(var, info)) |
| 1834 |
+ return -EINVAL; |
| 1835 |
+ |
| 1836 |
+ /* FIXME: we should allow interlaced/double modes if an appropriate mode is supported by the VBE */ |
| 1837 |
+ if (var->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE)) |
| 1838 |
+ return -EINVAL; |
| 1839 |
+ |
| 1840 |
+ match = vesafb_find_vbe_mode(var->xres, var->yres, var->bits_per_pixel, VESAFB_NEED_EXACT_RES); |
| 1841 |
+ |
| 1842 |
+ if (match == -1) { |
| 1843 |
+ printk(KERN_ERR "vesafb: mode %dx%d-%d not found\n", var->xres, var->yres, var->bits_per_pixel); |
| 1844 |
+ return -EINVAL; |
| 1845 |
+ } else { |
| 1846 |
+ var->bits_per_pixel = vbe_modes[match].bits_per_pixel; |
| 1847 |
+ vesafb_setup_var(var, info, &vbe_modes[match]); |
| 1848 |
+ |
| 1849 |
+ DPRINTK("found mode 0x%x (%dx%d-%dbpp)\n", |
| 1850 |
+ vbe_modes[match].mode_id, vbe_modes[match].x_res, vbe_modes[match].y_res, |
| 1851 |
+ vbe_modes[match].bits_per_pixel); |
| 1852 |
+ } |
| 1853 |
+ |
| 1854 |
+ return 0; |
| 1855 |
+} |
| 1856 |
+ |
| 1857 |
+static void vesafb_platform_release(struct device *device) |
| 1858 |
+{ |
| 1859 |
+ return; |
| 1860 |
+} |
| 1861 |
+ |
| 1862 |
+static int __init vesafb_probe(struct device *device); |
| 1863 |
+ |
| 1864 |
+static struct fb_ops vesafb_ops = { |
| 1865 |
+ .owner = THIS_MODULE, |
| 1866 |
+ .fb_setcolreg = vesafb_setcolreg, |
| 1867 |
+ .fb_pan_display = vesafb_pan_display, |
| 1868 |
+ .fb_fillrect = cfb_fillrect, |
| 1869 |
+ .fb_copyarea = cfb_copyarea, |
| 1870 |
+ .fb_imageblit = cfb_imageblit, |
| 1871 |
+ .fb_cursor = soft_cursor, |
| 1872 |
+ .fb_check_var = vesafb_check_var, |
| 1873 |
+ .fb_set_par = vesafb_set_par |
| 1874 |
+}; |
| 1875 |
+ |
| 1876 |
+static struct device_driver vesafb_driver = { |
| 1877 |
+ .name = "vesafb", |
| 1878 |
+ .bus = &platform_bus_type, |
| 1879 |
+ .probe = vesafb_probe, |
| 1880 |
+}; |
| 1881 |
+ |
| 1882 |
+static struct platform_device vesafb_device = { |
| 1883 |
+ .name = "vesafb", |
| 1884 |
+ .dev = { |
| 1885 |
+ .release = vesafb_platform_release, |
| 1886 |
+ } |
| 1887 |
+}; |
| 1888 |
+ |
| 1889 |
+#ifndef MODULE |
| 1890 |
+int __init vesafb_setup(char *options) |
| 1891 |
+{ |
| 1892 |
+ char *this_opt; |
| 1893 |
+ |
| 1894 |
+ if (!options || !*options) |
| 1895 |
+ return 0; |
| 1896 |
+ |
| 1897 |
+ DPRINTK("options %s\n",options); |
| 1898 |
+ |
| 1899 |
+ while ((this_opt = strsep(&options, ",")) != NULL) { |
| 1900 |
+ if (!*this_opt) continue; |
| 1901 |
+ |
| 1902 |
+ DPRINTK("this_opt: %s\n",this_opt); |
| 1903 |
+ |
| 1904 |
+ if (! strcmp(this_opt, "redraw")) |
| 1905 |
+ ypan=0; |
| 1906 |
+ else if (! strcmp(this_opt, "ypan")) |
| 1907 |
+ ypan=1; |
| 1908 |
+ else if (! strcmp(this_opt, "ywrap")) |
| 1909 |
+ ypan=2; |
| 1910 |
+ else if (! strcmp(this_opt, "vgapal")) |
| 1911 |
+ pmi_setpal=0; |
| 1912 |
+ else if (! strcmp(this_opt, "pmipal")) |
| 1913 |
+ pmi_setpal=1; |
| 1914 |
+ else if (! strcmp(this_opt, "mtrr")) |
| 1915 |
+ mtrr=1; |
| 1916 |
+ else if (! strcmp(this_opt, "nomtrr")) |
| 1917 |
+ mtrr=0; |
| 1918 |
+ else if (! strcmp(this_opt, "nocrtc")) |
| 1919 |
+ nocrtc=1; |
| 1920 |
+ else if (! strcmp(this_opt, "noedid")) |
| 1921 |
+ noedid=1; |
| 1922 |
+ else if (! strcmp(this_opt, "gtf")) |
| 1923 |
+ gtf=1; |
| 1924 |
+ else if (! strncmp(this_opt, "vtotal:", 7)) |
| 1925 |
+ vram_total = simple_strtoul(this_opt+7, NULL, 0); |
| 1926 |
+ else if (! strncmp(this_opt, "vremap:", 7)) |
| 1927 |
+ vram_remap = simple_strtoul(this_opt+7, NULL, 0); |
| 1928 |
+ else if (! strncmp(this_opt, "maxhf:", 6)) |
| 1929 |
+ maxhf = simple_strtoul(this_opt + 6, NULL, 0); |
| 1930 |
+ else if (! strncmp(this_opt, "maxvf:", 6)) |
| 1931 |
+ maxvf = simple_strtoul(this_opt + 6, NULL, 0); |
| 1932 |
+ else if (! strncmp(this_opt, "maxclk:", 7)) |
| 1933 |
+ maxclk = simple_strtoul(this_opt + 7, NULL, 0); |
| 1934 |
+ else if (! strncmp(this_opt, "vbemode:", 8)) |
| 1935 |
+ vbemode = simple_strtoul(this_opt + 8, NULL,0); |
| 1936 |
+ else if (this_opt[0] >= '0' && this_opt[0] <= '9') { |
| 1937 |
+ DPRINTK("mode_option: %s\n",this_opt); |
| 1938 |
+ mode_option = this_opt; |
| 1939 |
+ } else { |
| 1940 |
+ printk(KERN_WARNING "vesafb: unrecognized option %s\n", this_opt); |
| 1941 |
+ } |
| 1942 |
+ } |
| 1943 |
+ |
| 1944 |
+ return 0; |
| 1945 |
+} |
| 1946 |
+ |
| 1947 |
+#endif /* !MODULE */ |
| 1948 |
+ |
| 1949 |
+static int vesafb_read_proc_modes(char *buf, char **start, off_t offset, |
| 1950 |
+ int len, int *eof, void *private) |
| 1951 |
+{ |
| 1952 |
+ int clen = 0, i; |
| 1953 |
+ |
| 1954 |
+ for (i = 0; i < vbe_modes_cnt; i++) |
| 1955 |
+ clen += sprintf(buf + clen, "%dx%d-%d\n", vbe_modes[i].x_res, |
| 1956 |
+ vbe_modes[i].y_res, vbe_modes[i].bits_per_pixel); |
| 1957 |
+ |
| 1958 |
+ *start = buf + offset; |
| 1959 |
+ |
| 1960 |
+ if (clen > offset) |
| 1961 |
+ clen -= offset; |
| 1962 |
+ else |
| 1963 |
+ clen = 0; |
| 1964 |
+ |
| 1965 |
+ return clen; |
| 1966 |
+} |
| 1967 |
+ |
| 1968 |
+static int vesafb_read_proc_vbe_info(char *buf, char **start, off_t offset, |
| 1969 |
+ int len, int *eof, void *private) |
| 1970 |
+{ |
| 1971 |
+ int clen = 0; |
| 1972 |
+ |
| 1973 |
+ clen += sprintf(buf + clen, "Version: %d.%d\n", ((vbe_ib.vbe_version & 0xff00) >> 8), vbe_ib.vbe_version & 0xff); |
| 1974 |
+ clen += sprintf(buf + clen, "Vendor: %s\n", (char*)vbe_ib.oem_vendor_name_ptr); |
| 1975 |
+ clen += sprintf(buf + clen, "Product: %s\n", (char*)vbe_ib.oem_product_name_ptr); |
| 1976 |
+ clen += sprintf(buf + clen, "OEM rev: %s\n", (char*)vbe_ib.oem_product_rev_ptr); |
| 1977 |
+ clen += sprintf(buf + clen, "OEM string: %s\n", (char*)vbe_ib.oem_string_ptr); |
| 1978 |
+ |
| 1979 |
+ *start = buf + offset; |
| 1980 |
+ |
| 1981 |
+ if (clen > offset) |
| 1982 |
+ clen -= offset; |
| 1983 |
+ else |
| 1984 |
+ clen = 0; |
| 1985 |
+ |
| 1986 |
+ return clen; |
| 1987 |
+} |
| 1988 |
+ |
| 1989 |
+static int __init vesafb_vbe_init(struct fb_info *info) |
| 1990 |
+{ |
| 1991 |
+ struct vesafb_task *mytask; |
| 1992 |
+ u16 *mode = 0; |
| 1993 |
+ int i, off = 0; |
| 1994 |
+ |
| 1995 |
+ vesafb_create_task (mytask); |
| 1996 |
+ mytask->regs.eax = 0x4f00; |
| 1997 |
+ mytask->type = VESAFB_TASK_GETVBE_IB; |
| 1998 |
+ mytask->res = &vbe_ib; |
| 1999 |
+ vesafb_queue_task (mytask); |
| 2000 |
+ vesafb_wait_for_task(mytask); |
| 2001 |
+ |
| 2002 |
+ if (vbe_ib.vbe_version < 0x0200) { |
| 2003 |
+ printk(KERN_ERR "vesafb: Sorry, pre-VBE 2.0 cards are not supported.\n"); |
| 2004 |
+ kfree(mytask); |
| 2005 |
+ return 1; |
| 2006 |
+ } |
| 2007 |
+ |
| 2008 |
+ if ((mytask->regs.eax & 0xffff) != 0x004f) { |
| 2009 |
+ printk(KERN_ERR "vesafb: Getting mode info block failed (eax=0x%x)\n",(u32)mytask->regs.eax); |
| 2010 |
+ kfree(mytask); |
| 2011 |
+ return 1; |
| 2012 |
+ } |
| 2013 |
+ |
| 2014 |
+ printk(KERN_INFO "vesafb: %s, %s, %s (OEM: %s)\n", (char*)vbe_ib.oem_vendor_name_ptr, |
| 2015 |
+ (char*)vbe_ib.oem_product_name_ptr, (char*)vbe_ib.oem_product_rev_ptr, |
| 2016 |
+ (char*)vbe_ib.oem_string_ptr); |
| 2017 |
+ |
| 2018 |
+ printk(KERN_INFO "vesafb: VBE version: %d.%d\n",((vbe_ib.vbe_version & 0xff00) >> 8), vbe_ib.vbe_version & 0xff); |
| 2019 |
+ |
| 2020 |
+ /* count the available modes */ |
| 2021 |
+ mode = (u16*)vbe_ib.mode_list_ptr; |
| 2022 |
+ while (*mode != 0xffff) { |
| 2023 |
+ vbe_modes_cnt++; |
| 2024 |
+ mode++; |
| 2025 |
+ } |
| 2026 |
+ |
| 2027 |
+ vbe_modes = kmalloc(sizeof(struct vesafb_mode_info_block)*vbe_modes_cnt,GFP_KERNEL); |
| 2028 |
+ |
| 2029 |
+ /* get mode info for all available modes */ |
| 2030 |
+ mode = (u16*)vbe_ib.mode_list_ptr; |
| 2031 |
+ |
| 2032 |
+ while (*mode != 0xffff) { |
| 2033 |
+ mytask->regs.eax = 0x4f01; |
| 2034 |
+ mytask->regs.ecx = (u32) *mode; |
| 2035 |
+ mytask->type = VESAFB_TASK_GETVBE_MODEINFO; |
| 2036 |
+ mytask->res = vbe_modes+off; |
| 2037 |
+ mytask->done = 0; |
| 2038 |
+ |
| 2039 |
+ vesafb_queue_task (mytask); |
| 2040 |
+ vesafb_wait_for_task(mytask); |
| 2041 |
+ |
| 2042 |
+ vesafb_pmib(mytask->res)->mode_id = *mode; |
| 2043 |
+ |
| 2044 |
+ /* forget text modes */ |
| 2045 |
+ if ((vesafb_pmib(mytask->res)->mode_attr & 0x10) != 0 && |
| 2046 |
+ vesafb_pmib(mytask->res)->bits_per_pixel >= 8) |
| 2047 |
+ off++; |
| 2048 |
+ else |
| 2049 |
+ vbe_modes_cnt--; |
| 2050 |
+ |
| 2051 |
+ mode++; |
| 2052 |
+ } |
| 2053 |
+ |
| 2054 |
+ mytask->regs.eax = 0x4f0a; |
| 2055 |
+ mytask->regs.ebx = 0x0; |
| 2056 |
+ mytask->type = VESAFB_TASK_DOVM86; |
| 2057 |
+ mytask->res = NULL; |
| 2058 |
+ mytask->done = 0; |
| 2059 |
+ |
| 2060 |
+ vesafb_queue_task(mytask); |
| 2061 |
+ vesafb_wait_for_task(mytask); |
| 2062 |
+ |
| 2063 |
+ if ((mytask->regs.eax & 0xffff) != 0x004f || mytask->regs.es < 0xc000) { |
| 2064 |
+ pmi_setpal = ypan = 0; |
| 2065 |
+ } else { |
| 2066 |
+ printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", (u16)mytask->regs.es, (u16)mytask->regs.edi); |
| 2067 |
+ pmi_base = (unsigned short*)phys_to_virt(((unsigned long)mytask->regs.es << 4) + mytask->regs.edi); |
| 2068 |
+ pmi_start = (void*)((char*)pmi_base + pmi_base[1]); |
| 2069 |
+ pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); |
| 2070 |
+ printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); |
| 2071 |
+ |
| 2072 |
+ if (pmi_base[3]) { |
| 2073 |
+ printk(KERN_INFO "vesafb: pmi: ports = "); |
| 2074 |
+ for (i = pmi_base[3]/2; pmi_base[i] != 0xffff; i++) |
| 2075 |
+ printk("%x ",pmi_base[i]); |
| 2076 |
+ printk("\n"); |
| 2077 |
+ |
| 2078 |
+ if (pmi_base[i] != 0xffff) { |
| 2079 |
+ /* |
| 2080 |
+ * memory areas not supported (yet?) |
| 2081 |
+ * |
| 2082 |
+ * Rules are: we have to set up a descriptor for the requested |
| 2083 |
+ * memory area and pass it in the ES register to the BIOS function. |
| 2084 |
+ */ |
| 2085 |
+ printk(KERN_INFO "vesafb: can't handle memory requests, pmi disabled\n"); |
| 2086 |
+ ypan = pmi_setpal = 0; |
| 2087 |
+ } |
| 2088 |
+ } |
| 2089 |
+ } |
| 2090 |
+ |
| 2091 |
+ if (noedid || vbe_ib.vbe_version < 0x0300) |
| 2092 |
+ goto set_monspecs; |
| 2093 |
+ |
| 2094 |
+ mytask->regs.eax = 0x4f15; |
| 2095 |
+ mytask->regs.ebx = 0; |
| 2096 |
+ mytask->regs.ecx = 0; |
| 2097 |
+ mytask->done = 0; |
| 2098 |
+ |
| 2099 |
+ vesafb_queue_task(mytask); |
| 2100 |
+ vesafb_wait_for_task(mytask); |
| 2101 |
+ |
| 2102 |
+ if ((mytask->regs.eax & 0xffff) != 0x004f) |
| 2103 |
+ goto set_monspecs; |
| 2104 |
+ |
| 2105 |
+ if ((mytask->regs.ebx & 0x3) == 3) { |
| 2106 |
+ printk(KERN_INFO "vesafb: hardware supports both DCC1 and DCC2 transfers\n"); |
| 2107 |
+ } else if ((mytask->regs.ebx & 0x3) == 2) { |
| 2108 |
+ printk(KERN_INFO "vesafb: hardware supports DCC2 transfers\n"); |
| 2109 |
+ } else if ((mytask->regs.ebx & 0x3) == 1) { |
| 2110 |
+ printk(KERN_INFO "vesafb: hardware supports DCC1 transfers\n"); |
| 2111 |
+ } else { |
| 2112 |
+ printk(KERN_INFO "vesafb: hardware doesn't support DCC transfers\n"); |
| 2113 |
+ goto set_monspecs; |
| 2114 |
+ } |
| 2115 |
+ |
| 2116 |
+ mytask->regs.eax = 0x4f15; |
| 2117 |
+ mytask->regs.ebx = 1; |
| 2118 |
+ mytask->regs.ecx = mytask->regs.edx = mytask->done = 0; |
| 2119 |
+ mytask->type = VESAFB_TASK_GETEDID; |
| 2120 |
+ mytask->res = kmalloc(EDID_LENGTH, GFP_KERNEL); |
| 2121 |
+ |
| 2122 |
+ vesafb_queue_task(mytask); |
| 2123 |
+ vesafb_wait_for_task(mytask); |
| 2124 |
+ |
| 2125 |
+ if ((mytask->regs.eax & 0xffff) == 0x004f) { |
| 2126 |
+ |
| 2127 |
+ mon_limits = !fb_get_monitor_limits(mytask->res, &info->monspecs); |
| 2128 |
+ |
| 2129 |
+ /* if no maximum clock is specified, set to 300 MHz */ |
| 2130 |
+ if (mon_limits && info->monspecs.dclkmax == 0) { |
| 2131 |
+ info->monspecs.dclkmax = 300 * 1000000; |
| 2132 |
+ } |
| 2133 |
+ |
| 2134 |
+ edid_modes = fb_create_modedb(mytask->res, &edid_modes_cnt); |
| 2135 |
+ } |
| 2136 |
+ kfree(mytask->res); |
| 2137 |
+ |
| 2138 |
+set_monspecs: |
| 2139 |
+ if (maxclk) |
| 2140 |
+ info->monspecs.dclkmax = maxclk * 1000000; |
| 2141 |
+ |
| 2142 |
+ if (maxvf) |
| 2143 |
+ info->monspecs.vfmax = maxvf; |
| 2144 |
+ |
| 2145 |
+ if (maxhf) |
| 2146 |
+ info->monspecs.hfmax = maxhf * 1000; |
| 2147 |
+ |
| 2148 |
+ /* in case DCC transfers are not supported the user can provide monitor limits |
| 2149 |
+ manually, lower limits are set to "safe" values */ |
| 2150 |
+ if (!mon_limits && maxclk && maxvf && maxhf) { |
| 2151 |
+ info->monspecs.dclkmin = 0; |
| 2152 |
+ info->monspecs.vfmin = 60; |
| 2153 |
+ info->monspecs.hfmin = 29000; |
| 2154 |
+ } |
| 2155 |
+ |
| 2156 |
+ printk(KERN_INFO "vesafb: monitor limits: vf = %d Hz, hf = %d kHz, clk = %d MHz\n", |
| 2157 |
+ info->monspecs.vfmax, (int)(info->monspecs.hfmax / 1000), |
| 2158 |
+ (int)(info->monspecs.dclkmax / 1000000)); |
| 2159 |
+ |
| 2160 |
+ kfree(mytask); |
| 2161 |
+ return 0; |
| 2162 |
+} |
| 2163 |
+ |
| 2164 |
+static int __init decode_mode(u32 *xres, u32 *yres, u32 *bpp, u32 *refresh) |
| 2165 |
+{ |
| 2166 |
+ int len = strlen(mode_option), i, err = 0; |
| 2167 |
+ u8 res_specified = 0, bpp_specified = 0, refresh_specified = 0, |
| 2168 |
+ yres_specified = 0; |
| 2169 |
+ |
| 2170 |
+ for (i = len-1; i >= 0; i--) { |
| 2171 |
+ switch (mode_option[i]) { |
| 2172 |
+ case '@': |
| 2173 |
+ len = i; |
| 2174 |
+ if (!refresh_specified && !bpp_specified && |
| 2175 |
+ !yres_specified) { |
| 2176 |
+ *refresh = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 2177 |
+ refresh_specified = 1; |
| 2178 |
+ } else |
| 2179 |
+ goto out; |
| 2180 |
+ break; |
| 2181 |
+ case '-': |
| 2182 |
+ len = i; |
| 2183 |
+ if (!bpp_specified && !yres_specified) { |
| 2184 |
+ *bpp = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 2185 |
+ bpp_specified = 1; |
| 2186 |
+ } else |
| 2187 |
+ goto out; |
| 2188 |
+ break; |
| 2189 |
+ case 'x': |
| 2190 |
+ if (!yres_specified) { |
| 2191 |
+ *yres = simple_strtoul(&mode_option[i+1], NULL, 0); |
| 2192 |
+ yres_specified = 1; |
| 2193 |
+ } else |
| 2194 |
+ goto out; |
| 2195 |
+ break; |
| 2196 |
+ case '0'...'9': |
| 2197 |
+ break; |
| 2198 |
+ default: |
| 2199 |
+ goto out; |
| 2200 |
+ } |
| 2201 |
+ } |
| 2202 |
+ |
| 2203 |
+ if (i < 0 && yres_specified) { |
| 2204 |
+ *xres = simple_strtoul(mode_option, NULL, 0); |
| 2205 |
+ res_specified = 1; |
| 2206 |
+ } |
| 2207 |
+ |
| 2208 |
+out: if (!res_specified || !yres_specified) { |
| 2209 |
+ printk(KERN_ERR "vesafb: invalid resolution, %s not specified\n", |
| 2210 |
+ (!res_specified) ? "width" : "height"); |
| 2211 |
+ err = -EINVAL; |
| 2212 |
+ } |
| 2213 |
+ |
| 2214 |
+ return err; |
| 2215 |
+} |
| 2216 |
+ |
| 2217 |
+static int __init vesafb_init_set_mode(struct fb_info *info) |
| 2218 |
+{ |
| 2219 |
+ char buf[32]; |
| 2220 |
+ int i, modeid, refresh = 0; |
| 2221 |
+ u8 refresh_specified = 0; |
| 2222 |
+ |
| 2223 |
+ if (!mode_option) |
| 2224 |
+ mode_option = CONFIG_FB_VESA_DEFAULT_MODE; |
| 2225 |
+ |
| 2226 |
+ if (vbemode > 0) { |
| 2227 |
+ for (i = 0; i < vbe_modes_cnt; i++) { |
| 2228 |
+ if (vbe_modes[i].mode_id == vbemode) { |
| 2229 |
+ info->var.vmode = FB_VMODE_NONINTERLACED; |
| 2230 |
+ info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 2231 |
+ vesafb_setup_var(&info->var, info, &vbe_modes[i]); |
| 2232 |
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &info->var, info); |
| 2233 |
+ return i; |
| 2234 |
+ } |
| 2235 |
+ } |
| 2236 |
+ |
| 2237 |
+ printk(KERN_INFO "specified VBE mode %d not found\n",vbemode); |
| 2238 |
+ } |
| 2239 |
+ |
| 2240 |
+ if (decode_mode(&info->var.xres, &info->var.yres, |
| 2241 |
+ &info->var.bits_per_pixel, &refresh)) |
| 2242 |
+ return -EINVAL; |
| 2243 |
+ |
| 2244 |
+ if (refresh) |
| 2245 |
+ refresh_specified = 1; |
| 2246 |
+ else |
| 2247 |
+ refresh = 60; |
| 2248 |
+ |
| 2249 |
+ modeid = vesafb_find_vbe_mode(info->var.xres, info->var.yres, info->var.bits_per_pixel, 0); |
| 2250 |
+ |
| 2251 |
+ if (modeid == -1) { |
| 2252 |
+ return -EINVAL; |
| 2253 |
+ } else { |
| 2254 |
+ info->var.vmode = FB_VMODE_NONINTERLACED; |
| 2255 |
+ info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 2256 |
+ vesafb_setup_var(&info->var, info, &vbe_modes[modeid]); |
| 2257 |
+ } |
| 2258 |
+ |
| 2259 |
+ if (gtf) |
| 2260 |
+ goto timings_gtf; |
| 2261 |
+ |
| 2262 |
+ sprintf(buf, "%dx%d-%d@%d", info->var.xres, info->var.yres, info->var.bits_per_pixel, refresh); |
| 2263 |
+ i = fb_find_mode(&info->var, info, buf, vesa_modes, VESA_MODEDB_SIZE, NULL, 0); |
| 2264 |
+ DPRINTK("fb_find_mode returned %d\n", i); |
| 2265 |
+ |
| 2266 |
+ if (i == 1 || (i == 2 && vbe_ib.vbe_version < 0x0300)) |
| 2267 |
+ return modeid; |
| 2268 |
+ |
| 2269 |
+ /* The call to fb_find_mode could have changed our var struct, so we need |
| 2270 |
+ * to restore it. */ |
| 2271 |
+ info->var.vmode = FB_VMODE_NONINTERLACED; |
| 2272 |
+ info->var.sync = FB_SYNC_VERT_HIGH_ACT; |
| 2273 |
+ vesafb_setup_var(&info->var, info, &vbe_modes[modeid]); |
| 2274 |
+ |
| 2275 |
+ if (edid_modes != NULL && !gtf) { |
| 2276 |
+ DPRINTK("looking for EDID modes\n"); |
| 2277 |
+ |
| 2278 |
+ for (i = 0; i < edid_modes_cnt; i++) { |
| 2279 |
+ |
| 2280 |
+ if (edid_modes[i].xres == info->var.xres && |
| 2281 |
+ edid_modes[i].yres == info->var.yres && |
| 2282 |
+ abs(edid_modes[i].refresh - refresh) < 5) { |
| 2283 |
+ |
| 2284 |
+ info->var.pixclock = edid_modes[i].pixclock; |
| 2285 |
+ info->var.left_margin = edid_modes[i].left_margin; |
| 2286 |
+ info->var.right_margin = edid_modes[i].right_margin; |
| 2287 |
+ info->var.upper_margin = edid_modes[i].upper_margin; |
| 2288 |
+ info->var.lower_margin = edid_modes[i].lower_margin; |
| 2289 |
+ info->var.hsync_len = edid_modes[i].hsync_len; |
| 2290 |
+ info->var.vsync_len = edid_modes[i].vsync_len; |
| 2291 |
+ info->var.sync = edid_modes[i].sync; |
| 2292 |
+ info->var.vmode = edid_modes[i].vmode; |
| 2293 |
+ DPRINTK("using EDID-provided mode\n"); |
| 2294 |
+ return modeid; |
| 2295 |
+ } |
| 2296 |
+ } |
| 2297 |
+ } |
| 2298 |
+ |
| 2299 |
+timings_gtf: |
| 2300 |
+ if (refresh_specified) |
| 2301 |
+ i = FB_VSYNCTIMINGS; |
| 2302 |
+ else |
| 2303 |
+ i = FB_MAXTIMINGS; |
| 2304 |
+ |
| 2305 |
+ if (vbe_ib.vbe_version < 0x0300) { |
| 2306 |
+ i = FB_VSYNCTIMINGS | FB_IGNOREMON; |
| 2307 |
+ refresh = 60; |
| 2308 |
+ } |
| 2309 |
+ |
| 2310 |
+ if (!mon_limits) |
| 2311 |
+ i |= FB_IGNOREMON; |
| 2312 |
+ |
| 2313 |
+ if (!fb_get_mode(i, refresh, &info->var, info)) |
| 2314 |
+ return modeid; |
| 2315 |
+ |
| 2316 |
+ printk(KERN_WARNING "vesafb: trying maximum allowed refresh rate\n"); |
| 2317 |
+ |
| 2318 |
+ if (i & FB_VSYNCTIMINGS && refresh > 60 && mon_limits) { |
| 2319 |
+ if (!fb_get_mode(FB_MAXTIMINGS, refresh, &info->var, info)) |
| 2320 |
+ return modeid; |
| 2321 |
+ } |
| 2322 |
+ |
| 2323 |
+ printk(KERN_WARNING "vesafb: using default BIOS refresh rate\n"); |
| 2324 |
+ vbemode = vbe_modes[modeid].mode_id; |
| 2325 |
+ |
| 2326 |
+ return modeid; |
| 2327 |
+} |
| 2328 |
+ |
| 2329 |
+static int __init vesafb_probe(struct device *device) |
| 2330 |
+{ |
| 2331 |
+ char entry[16]; |
| 2332 |
+ struct platform_device *dev = to_platform_device(device); |
| 2333 |
+ struct fb_info *info; |
| 2334 |
+ struct vesafb_mode_info_block *mode = NULL; |
| 2335 |
+ int err = 0, i; |
| 2336 |
+ unsigned int size_vmode; |
| 2337 |
+ unsigned int size_remap; |
| 2338 |
+ unsigned int size_total; |
| 2339 |
+ |
| 2340 |
+ vesafb_info = info = framebuffer_alloc(sizeof(struct vesafb_par) + sizeof(u32) * 256, &dev->dev); |
| 2341 |
+ |
| 2342 |
+ if (!info) |
| 2343 |
+ return -ENOMEM; |
| 2344 |
+ |
| 2345 |
+ if (vesafb_pid) |
| 2346 |
+ vesafb_serv_thread = find_task_by_pid(vesafb_pid); |
| 2347 |
+ else { |
| 2348 |
+ printk(KERN_ERR "vesafb: vesafb thread not running\n"); |
| 2349 |
+ framebuffer_release(info); |
| 2350 |
+ return -EINVAL; |
| 2351 |
+ } |
| 2352 |
+ |
| 2353 |
+ if (vesafb_vbe_init(info)) { |
| 2354 |
+ printk(KERN_ERR "vesafb: vbe_init failed\n"); |
| 2355 |
+ err = -EINVAL; |
| 2356 |
+ goto out; |
| 2357 |
+ } |
| 2358 |
+ |
| 2359 |
+ vesafb_fix.ypanstep = ypan ? 1 : 0; |
| 2360 |
+ vesafb_fix.ywrapstep = (ypan>1) ? 1 : 0; |
| 2361 |
+ |
| 2362 |
+ info->pseudo_palette = ((u8*)info->par + sizeof(struct vesafb_par)); |
| 2363 |
+ info->fbops = &vesafb_ops; |
| 2364 |
+ info->var = vesafb_defined; |
| 2365 |
+ info->fix = vesafb_fix; |
| 2366 |
+ |
| 2367 |
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { |
| 2368 |
+ err = -ENXIO; |
| 2369 |
+ goto out; |
| 2370 |
+ } |
| 2371 |
+ |
| 2372 |
+ i = vesafb_init_set_mode(info); |
| 2373 |
+ if (i < 0) |
| 2374 |
+ goto out_cmap; |
| 2375 |
+ |
| 2376 |
+ /* Has the VBE mode number been specified? */ |
| 2377 |
+ if (vbemode > 0) { |
| 2378 |
+ for (i = 0; i < vbe_modes_cnt; i++) { |
| 2379 |
+ if (vbe_modes[i].mode_id == vbemode) { |
| 2380 |
+ mode = &vbe_modes[i]; |
| 2381 |
+ break; |
| 2382 |
+ } |
| 2383 |
+ } |
| 2384 |
+ } else { |
| 2385 |
+ i = vesafb_find_vbe_mode(info->var.xres, info->var.yres, |
| 2386 |
+ info->var.bits_per_pixel, VESAFB_NEED_EXACT_RES | VESAFB_NEED_EXACT_DEPTH); |
| 2387 |
+ if (i > 0) |
| 2388 |
+ mode = &vbe_modes[i]; |
| 2389 |
+ } |
| 2390 |
+ |
| 2391 |
+ /* size_vmode -- that is the amount of memory needed for the |
| 2392 |
+ * used video mode, i.e. the minimum amount of |
| 2393 |
+ * memory we need. */ |
| 2394 |
+ if (mode != NULL) { |
| 2395 |
+ size_vmode = info->var.yres * mode->bytes_per_scan_line; |
| 2396 |
+ } else { |
| 2397 |
+ size_vmode = info->var.yres * info->var.xres * |
| 2398 |
+ ((info->var.bits_per_pixel + 7) >> 3); |
| 2399 |
+ } |
| 2400 |
+ |
| 2401 |
+ /* size_total -- all video memory we have. Used for mtrr |
| 2402 |
+ * entries, ressource allocation and bounds |
| 2403 |
+ * checking. */ |
| 2404 |
+ size_total = vbe_ib.total_memory * 65536; |
| 2405 |
+ if (vram_total) |
| 2406 |
+ size_total = vram_total * 1024 * 1024; |
| 2407 |
+ if (size_total < size_vmode) |
| 2408 |
+ size_total = size_vmode; |
| 2409 |
+ |
| 2410 |
+ /* size_remap -- the amount of video memory we are going to |
| 2411 |
+ * use for vesafb. With modern cards it is no |
| 2412 |
+ * option to simply use size_total as that |
| 2413 |
+ * wastes plenty of kernel address space. */ |
| 2414 |
+ size_remap = size_vmode * 2; |
| 2415 |
+ if (vram_remap) |
| 2416 |
+ size_remap = vram_remap * 1024 * 1024; |
| 2417 |
+ if (size_remap < size_vmode) |
| 2418 |
+ size_remap = size_vmode; |
| 2419 |
+ if (size_remap > size_total) |
| 2420 |
+ size_remap = size_total; |
| 2421 |
+ |
| 2422 |
+ info->fix.smem_len = size_remap; |
| 2423 |
+ info->fix.smem_start = mode->phys_base_ptr; |
| 2424 |
+ |
| 2425 |
+ /* We have to set it here, because when setup_var() was called, smem_len |
| 2426 |
+ wasn't defined yet. */ |
| 2427 |
+ info->var.yres_virtual = info->fix.smem_len / mode->bytes_per_scan_line; |
| 2428 |
+ |
| 2429 |
+ if (ypan && info->var.yres_virtual > info->var.yres) { |
| 2430 |
+ printk(KERN_INFO "vesafb: scrolling: %s using protected mode interface, yres_virtual=%d\n", |
| 2431 |
+ (ypan > 1) ? "ywrap" : "ypan",info->var.yres_virtual); |
| 2432 |
+ } else { |
| 2433 |
+ printk(KERN_INFO "vesafb: scrolling: redraw\n"); |
| 2434 |
+ info->var.yres_virtual = info->var.yres; |
| 2435 |
+ ypan = 0; |
| 2436 |
+ } |
| 2437 |
+ |
| 2438 |
+ info->flags = FBINFO_FLAG_DEFAULT | |
| 2439 |
+ (ypan) ? FBINFO_HWACCEL_YPAN : 0; |
| 2440 |
+ |
| 2441 |
+ if (!request_mem_region(info->fix.smem_start, size_total, "vesafb")) { |
| 2442 |
+ printk(KERN_WARNING "vesafb: cannot reserve video memory at 0x%lx\n", info->fix.smem_start); |
| 2443 |
+ /* We cannot make this fatal. Sometimes this comes from magic |
| 2444 |
+ spaces our resource handlers simply don't know about */ |
| 2445 |
+ } |
| 2446 |
+ |
| 2447 |
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); |
| 2448 |
+ |
| 2449 |
+ if (!info->screen_base) { |
| 2450 |
+ printk(KERN_ERR |
| 2451 |
+ "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", |
| 2452 |
+ info->fix.smem_len, info->fix.smem_start); |
| 2453 |
+ err = -EIO; |
| 2454 |
+ goto out_mem; |
| 2455 |
+ } |
| 2456 |
+ |
| 2457 |
+ /* request failure does not faze us, as vgacon probably has this |
| 2458 |
+ region already (FIXME) */ |
| 2459 |
+ request_region(0x3c0, 32, "vesafb"); |
| 2460 |
+ |
| 2461 |
+ if (mtrr) { |
| 2462 |
+ int temp_size = size_total; |
| 2463 |
+ |
| 2464 |
+ /* Find the largest power-of-two */ |
| 2465 |
+ while (temp_size & (temp_size - 1)) |
| 2466 |
+ temp_size &= (temp_size - 1); |
| 2467 |
+ |
| 2468 |
+ /* Try and find a power of two to add */ |
| 2469 |
+ while (temp_size && mtrr_add(info->fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1) == -EINVAL) { |
| 2470 |
+ temp_size >>= 1; |
| 2471 |
+ } |
| 2472 |
+ } |
| 2473 |
+ |
| 2474 |
+ if (register_framebuffer(info) < 0) { |
| 2475 |
+ printk(KERN_ERR "vesafb: failed to register framebuffer device\n"); |
| 2476 |
+ err = -EINVAL; |
| 2477 |
+ goto out_mem; |
| 2478 |
+ } |
| 2479 |
+ |
| 2480 |
+ printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, using %dk, total %dk\n", |
| 2481 |
+ info->fix.smem_start, info->screen_base, size_remap/1024, size_total/1024); |
| 2482 |
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); |
| 2483 |
+ |
| 2484 |
+ sprintf(entry, "fb%d", info->node); |
| 2485 |
+ proc_mkdir(entry, 0); |
| 2486 |
+ |
| 2487 |
+ sprintf(entry, "fb%d/modes", info->node); |
| 2488 |
+ create_proc_read_entry(entry, 0, 0, vesafb_read_proc_modes, NULL); |
| 2489 |
+ |
| 2490 |
+ sprintf(entry, "fb%d/vbe_info", info->node); |
| 2491 |
+ create_proc_read_entry(entry, 0, 0, vesafb_read_proc_vbe_info, NULL); |
| 2492 |
+ |
| 2493 |
+ fb_destroy_modedb(edid_modes); |
| 2494 |
+ return 0; |
| 2495 |
+ |
| 2496 |
+out_mem: |
| 2497 |
+ release_mem_region(info->fix.smem_start, size_total); |
| 2498 |
+out_cmap: |
| 2499 |
+ fb_dealloc_cmap(&info->cmap); |
| 2500 |
+out: |
| 2501 |
+ framebuffer_release(info); |
| 2502 |
+ vesafb_info = NULL; |
| 2503 |
+ |
| 2504 |
+ fb_destroy_modedb(edid_modes); |
| 2505 |
+ kfree(vbe_modes); |
| 2506 |
+ vbe_modes = NULL; |
| 2507 |
+ return err; |
| 2508 |
+} |
| 2509 |
+ |
| 2510 |
+int __init vesafb_init(void) |
| 2511 |
+{ |
| 2512 |
+ int ret; |
| 2513 |
+#ifndef MODULE |
| 2514 |
+ char *option = NULL; |
| 2515 |
+ |
| 2516 |
+ if (fb_get_options("vesafb", &option)) |
| 2517 |
+ return -ENODEV; |
| 2518 |
+ vesafb_setup(option); |
| 2519 |
+#endif |
| 2520 |
+ ret = driver_register(&vesafb_driver); |
| 2521 |
+ |
| 2522 |
+ if (!ret) { |
| 2523 |
+ ret = platform_device_register(&vesafb_device); |
| 2524 |
+ if (ret) |
| 2525 |
+ driver_unregister(&vesafb_driver); |
| 2526 |
+ } |
| 2527 |
+ |
| 2528 |
+ return ret; |
| 2529 |
+} |
| 2530 |
+ |
| 2531 |
+module_init(vesafb_init); |
| 2532 |
+ |
| 2533 |
+#ifdef MODULE |
| 2534 |
+void vesafb_exit(void) |
| 2535 |
+{ |
| 2536 |
+ char entry[16]; |
| 2537 |
+ |
| 2538 |
+ if (vesafb_info) |
| 2539 |
+ unregister_framebuffer(vesafb_info); |
| 2540 |
+ |
| 2541 |
+ platform_device_unregister(&vesafb_device); |
| 2542 |
+ driver_unregister(&vesafb_driver); |
| 2543 |
+ |
| 2544 |
+ if (vesafb_info) { |
| 2545 |
+ sprintf(entry, "fb%d/modes", vesafb_info->node); |
| 2546 |
+ remove_proc_entry(entry, NULL); |
| 2547 |
+ |
| 2548 |
+ sprintf(entry, "fb%d/vbe_info", vesafb_info->node); |
| 2549 |
+ remove_proc_entry(entry, NULL); |
| 2550 |
+ |
| 2551 |
+ sprintf(entry, "fb%d", vesafb_info->node); |
| 2552 |
+ remove_proc_entry(entry, NULL); |
| 2553 |
+ |
| 2554 |
+ release_mem_region(vesafb_info->fix.smem_start, vesafb_info->fix.smem_len); |
| 2555 |
+ fb_dealloc_cmap(&vesafb_info->cmap); |
| 2556 |
+ framebuffer_release(vesafb_info); |
| 2557 |
+ } |
| 2558 |
+ |
| 2559 |
+ if (vbe_modes != NULL) |
| 2560 |
+ kfree(vbe_modes); |
| 2561 |
+} |
| 2562 |
+ |
| 2563 |
+module_exit(vesafb_exit); |
| 2564 |
+ |
| 2565 |
+static inline int param_get_scroll(char *buffer, struct kernel_param *kp) { return 0; } |
| 2566 |
+static inline int param_set_scroll(const char *val, struct kernel_param *kp) |
| 2567 |
+{ |
| 2568 |
+ ypan = 0; |
| 2569 |
+ |
| 2570 |
+ if (! strcmp(val, "redraw")) |
| 2571 |
+ ypan=0; |
| 2572 |
+ else if (! strcmp(val, "ypan")) |
| 2573 |
+ ypan=1; |
| 2574 |
+ else if (! strcmp(val, "ywrap")) |
| 2575 |
+ ypan=2; |
| 2576 |
+ |
| 2577 |
+ return 0; |
| 2578 |
+} |
| 2579 |
+ |
| 2580 |
+#define param_check_scroll(name, p) __param_check(name, p, void); |
| 2581 |
+ |
| 2582 |
+module_param_named(scroll, ypan, scroll, 0); |
| 2583 |
+MODULE_PARM_DESC(scroll,"Scrolling mode, set to 'redraw', 'ypan' or 'ywrap'"); |
| 2584 |
+module_param_named(vgapal, pmi_setpal, invbool, 0); |
| 2585 |
+MODULE_PARM_DESC(vgapal,"bool: set palette using VGA registers"); |
| 2586 |
+module_param_named(pmipal, pmi_setpal, bool, 0); |
| 2587 |
+MODULE_PARM_DESC(pmipal,"bool: set palette using PMI calls"); |
| 2588 |
+module_param_named(nomtrr, mtrr, invbool, 0); |
| 2589 |
+MODULE_PARM_DESC(nomtrr,"bool: disable use of MTRR registers"); |
| 2590 |
+module_param(nocrtc, bool, 0); |
| 2591 |
+MODULE_PARM_DESC(nocrtc,"bool: ignore CRTC timings when setting modes"); |
| 2592 |
+module_param(noedid, bool, 0); |
| 2593 |
+MODULE_PARM_DESC(noedid,"bool: ignore EDID-provided monitor limits when setting modes"); |
| 2594 |
+module_param(gtf, bool, 0); |
| 2595 |
+MODULE_PARM_DESC(gtf,"bool: force use of VESA GTF to calculate mode timings"); |
| 2596 |
+module_param(vram_remap, uint, 0); |
| 2597 |
+MODULE_PARM_DESC(vram_remap,"Set amount of video memory to be used [MiB]"); |
| 2598 |
+module_param(vram_total, uint, 0); |
| 2599 |
+MODULE_PARM_DESC(vram_total,"Set total amount of video memoery [MiB]"); |
| 2600 |
+module_param(maxclk, ushort, 0); |
| 2601 |
+MODULE_PARM_DESC(maxclk,"Maximum pixelclock [MHz], overrides EDID data"); |
| 2602 |
+module_param(maxhf, ushort, 0); |
| 2603 |
+MODULE_PARM_DESC(maxhf,"Maximum horizontal frequency [kHz], overrides EDID data"); |
| 2604 |
+module_param(maxvf, ushort, 0); |
| 2605 |
+MODULE_PARM_DESC(maxvf,"Maximum vertical frequency [Hz], overrides EDID data"); |
| 2606 |
+module_param_named(mode, mode_option, charp, 0); |
| 2607 |
+MODULE_PARM_DESC(mode,"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\""); |
| 2608 |
+module_param(vbemode, ushort, 0); |
| 2609 |
+MODULE_PARM_DESC(vbemode,"VBE mode number to set, overrides 'mode' setting"); |
| 2610 |
+ |
| 2611 |
+#endif /* MODULE */ |
| 2612 |
+ |
| 2613 |
+MODULE_LICENSE("GPL"); |
| 2614 |
+MODULE_AUTHOR("Michal Januszewski"); |
| 2615 |
+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphic boards"); |
| 2616 |
diff -Nru a/include/video/vesa.h b/include/video/vesa.h |
| 2617 |
--- /dev/null Wed Dec 31 16:00:00 196900 |
| 2618 |
+++ b/include/video/vesa.h 2005-01-15 14:00:49 +01:00 |
| 2619 |
@@ -0,0 +1,126 @@ |
| 2620 |
+#define crtc_pib(arg) ((struct vesafb_crtc_info_block*)(arg)) |
| 2621 |
+#define vbe_pib(arg) ((struct vesafb_vbe_info_block*)(arg)) |
| 2622 |
+#define vesafb_pmib(arg) ((struct vesafb_mode_info_block*)(arg)) |
| 2623 |
+ |
| 2624 |
+struct vesafb_task { |
| 2625 |
+ enum { |
| 2626 |
+ VESAFB_TASK_DOVM86, |
| 2627 |
+ VESAFB_TASK_GETVBE_IB, |
| 2628 |
+ VESAFB_TASK_GETVBE_MODEINFO, |
| 2629 |
+ VESAFB_TASK_SWITCHMODE, |
| 2630 |
+ VESAFB_TASK_GETEDID, |
| 2631 |
+ VESAFB_TASK_SETPAL |
| 2632 |
+ } type; |
| 2633 |
+ |
| 2634 |
+ unsigned short flags; |
| 2635 |
+ struct vm86_regs regs; |
| 2636 |
+ |
| 2637 |
+ unsigned char done; |
| 2638 |
+ void *res; |
| 2639 |
+ |
| 2640 |
+ struct list_head node; |
| 2641 |
+}; |
| 2642 |
+ |
| 2643 |
+#define VESAFB_FLAG_FREESTRUCT 0x0001 |
| 2644 |
+#define VESAFB_CAP_CAN_SWITCH_DAC 0x01 |
| 2645 |
+ |
| 2646 |
+/* this struct is 512 bytes long */ |
| 2647 |
+struct vesafb_vbe_info_block { |
| 2648 |
+ char vbe_signature[4]; |
| 2649 |
+ u16 vbe_version; |
| 2650 |
+ u32 oem_string_ptr; |
| 2651 |
+ u32 capabilities; |
| 2652 |
+ u32 mode_list_ptr; |
| 2653 |
+ u16 total_memory; |
| 2654 |
+ u16 oem_software_rev; |
| 2655 |
+ u32 oem_vendor_name_ptr; |
| 2656 |
+ u32 oem_product_name_ptr; |
| 2657 |
+ u32 oem_product_rev_ptr; |
| 2658 |
+ u8 reserved[222]; |
| 2659 |
+ char oem_data[256]; |
| 2660 |
+} __attribute__ ((packed)); |
| 2661 |
+ |
| 2662 |
+struct vesafb_crtc_info_block { |
| 2663 |
+ |
| 2664 |
+ u16 horiz_total; |
| 2665 |
+ u16 horiz_start; |
| 2666 |
+ u16 horiz_end; |
| 2667 |
+ u16 vert_total; |
| 2668 |
+ u16 vert_start; |
| 2669 |
+ u16 vert_end; |
| 2670 |
+ u8 flags; |
| 2671 |
+ u32 pixel_clock; |
| 2672 |
+ u16 refresh_rate; |
| 2673 |
+ u8 reserved[40]; |
| 2674 |
+ |
| 2675 |
+} __attribute__ ((packed)); |
| 2676 |
+ |
| 2677 |
+/* this struct is 256 bytes long */ |
| 2678 |
+struct vesafb_mode_info_block { |
| 2679 |
+ |
| 2680 |
+ /* for all VBE revisions */ |
| 2681 |
+ u16 mode_attr; |
| 2682 |
+ u8 winA_attr; |
| 2683 |
+ u8 winB_attr; |
| 2684 |
+ u16 win_granularity; |
| 2685 |
+ u16 win_size; |
| 2686 |
+ u16 winA_seg; |
| 2687 |
+ u16 winB_seg; |
| 2688 |
+ u32 win_func_ptr; |
| 2689 |
+ u16 bytes_per_scan_line; |
| 2690 |
+ |
| 2691 |
+ /* for VBE 1.2+ */ |
| 2692 |
+ u16 x_res; |
| 2693 |
+ u16 y_res; |
| 2694 |
+ u8 x_char_size; |
| 2695 |
+ u8 y_char_size; |
| 2696 |
+ u8 planes; |
| 2697 |
+ u8 bits_per_pixel; |
| 2698 |
+ u8 banks; |
| 2699 |
+ u8 memory_model; |
| 2700 |
+ u8 bank_size; |
| 2701 |
+ u8 image_pages; |
| 2702 |
+ u8 reserved1; |
| 2703 |
+ |
| 2704 |
+ /* direct color fields for direct/6 and YUV/7 memory models */ |
| 2705 |
+ u8 red_len; |
| 2706 |
+ u8 red_off; /* offsets are bit positions of lsb in the mask */ |
| 2707 |
+ u8 green_len; |
| 2708 |
+ u8 green_off; |
| 2709 |
+ u8 blue_len; |
| 2710 |
+ u8 blue_off; |
| 2711 |
+ u8 rsvd_len; |
| 2712 |
+ u8 rsvd_off; |
| 2713 |
+ u8 direct_color_info; /* direct color mode attributes */ |
| 2714 |
+ |
| 2715 |
+ /* for VBE 2.0+ */ |
| 2716 |
+ u32 phys_base_ptr; |
| 2717 |
+ u8 reserved2[6]; |
| 2718 |
+ |
| 2719 |
+ /* for VBE 3.0+ */ |
| 2720 |
+ u16 lin_bytes_per_scan_line; |
| 2721 |
+ u8 bnk_image_pages; |
| 2722 |
+ u8 lin_image_pages; |
| 2723 |
+ u8 lin_red_len; |
| 2724 |
+ u8 lin_red_off; |
| 2725 |
+ u8 lin_green_len; |
| 2726 |
+ u8 lin_green_off; |
| 2727 |
+ u8 lin_blue_len; |
| 2728 |
+ u8 lin_blue_off; |
| 2729 |
+ u8 lin_rsvd_len; |
| 2730 |
+ u8 lin_rsvd_off; |
| 2731 |
+ u32 max_pixel_clock; |
| 2732 |
+ |
| 2733 |
+ u16 mode_id; |
| 2734 |
+ |
| 2735 |
+} __attribute__ ((packed)); |
| 2736 |
+ |
| 2737 |
+struct vesafb_par { |
| 2738 |
+ u16 vbe_mode; |
| 2739 |
+ struct vesafb_crtc_info_block crtc; |
| 2740 |
+}; |
| 2741 |
+ |
| 2742 |
+ |
| 2743 |
+struct vesafb_pal_entry { |
| 2744 |
+ u_char blue, green, red, pad; |
| 2745 |
+} __attribute__ ((packed)); |