patch-2.3.13 linux/drivers/video/matroxfb.c

Next file: linux/drivers/video/mdacon.c
Previous file: linux/drivers/video/macfb.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.12/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
@@ -1,10 +1,10 @@
 /*
  *
- * Hardware accelerated Matrox Millennium I, II, Mystique and G200
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
  * (c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.15 1999/04/19
+ * Version: 1.19 1999/08/05
  *
  * MTRR stuff: 1998 Tom Rini <tmrini@ntplx.net>
  *
@@ -14,8 +14,8 @@
  *               "Kurt Garloff" <garloff@kg1.ping.de>
  *                     Betatesting, fixes, ideas, videomodes, videomodes timmings
  *
- *               "Tom Rini" <tmrini@ntplx.net>
- *                     MTRR stuff, betatesting, fixes, ideas
+ *               "Tom Rini" <trini@disparity.net>
+ *                     MTRR stuff, PPC cleanups, betatesting, fixes, ideas
  *
  *               "Bibek Sahu" <scorpio@dodds.net>
  *                     Access device through readb|w|l and write b|w|l
@@ -60,6 +60,9 @@
  *               "Cort Dougan" <cort@cs.nmt.edu>
  *                     CHRP fixes and PReP cleanup
  *
+ *               "Mark Vojkovich" <mvojkovi@ucsd.edu>
+ *                     G400 support
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -87,6 +90,11 @@
 /* Debug register calls, too? */
 #undef MATROXFB_DEBUG_REG
 
+/* Log reentrancy attempts - you must have printstate() patch applied */
+#undef MATROXFB_DEBUG_REENTER
+/* you must define DEBUG_REENTER to get debugged CONSOLEBH... */
+#undef MATROXFB_DEBUG_CONSOLEBH
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -127,12 +135,15 @@
 #include <video/macmodes.h>
 #endif
 
+/* always compile support for 32MB... It cost almost nothing */
+#define CONFIG_FB_MATROX_32MB
+
 #define FBCON_HAS_VGATEXT
 
 #ifdef MATROXFB_DEBUG
 
 #define DEBUG
-#define DBG(x)		printk("matroxfb: %s\n", (x));
+#define DBG(x)		printk(KERN_DEBUG "matroxfb: %s\n", (x));
 
 #ifdef MATROXFB_DEBUG_HEAVY
 #define DBG_HEAVY(x)	DBG(x)
@@ -217,6 +228,9 @@
 #ifndef PCI_DEVICE_ID_MATROX_G100_AGP
 #define PCI_DEVICE_ID_MATROX_G100_AGP	0x1001
 #endif
+#ifndef PCI_DEVICE_ID_MATROX_G400_AGP
+#define PCI_DEVICE_ID_MATROX_G400_AGP	0x0525
+#endif
 
 #ifndef PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP
 #define PCI_SS_ID_MATROX_GENERIC		0xFF00
@@ -422,7 +436,7 @@
 	unsigned char	MiscOutReg;
 	unsigned char	DACpal[768];
 	unsigned char	CRTC[25];
-	unsigned char	CRTCEXT[6];
+	unsigned char	CRTCEXT[9];
 	unsigned char	SEQ[5];
 	/* unused for MGA mode, but who knows... */
 	unsigned char	GCTL[9];
@@ -453,7 +467,8 @@
 }
 
 #define PMXINFO(p) mxinfo(p),
-#define MINFO_FROM_DISP(x) struct matrox_fb_info* minfo = mxinfo(x)
+#define MINFO_FROM(x)	   struct matrox_fb_info* minfo = x
+#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x))
 
 #else
 
@@ -476,6 +491,7 @@
 #endif
 
 #define PMXINFO(p)
+#define MINFO_FROM(x)
 #define MINFO_FROM_DISP(x)
 
 #endif
@@ -563,6 +579,9 @@
 		int		hwcursor;
 		int		blink;
 		int		sgram;
+#ifdef CONFIG_FB_MATROX_32MB
+		int		support32MB;
+#endif
 
 		int		accelerator;
 		int		text_type_aux;
@@ -609,6 +628,8 @@
 #if defined(CONFIG_FB_OF)
 unsigned char nvram_read_byte(int);
 int matrox_of_init(struct device_node *dp);
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
 #endif
 
 #define curr_ydstorg(x)	ACCESS_FBINFO2(x, curr.ydstorg.pixels)
@@ -678,6 +699,8 @@
 
 #define M_RESET		0x1E40
 
+#define M_AGP2PLL	0x1E4C
+
 #define M_OPMODE	0x1E54
 #define     M_OPMODE_DMA_GEN_WRITE	0x00
 #define     M_OPMODE_DMA_BLIT		0x04
@@ -713,6 +736,9 @@
 #define M_EXTVGA_INDEX	0x1FDE
 #define M_EXTVGA_DATA	0x1FDF
 
+/* G200 only */
+#define M_SRCORG	0x2CB4
+
 #define M_RAMDAC_BASE	0x3C00
 
 /* fortunately, same on TVP3026 and MGA1064 */
@@ -723,6 +749,9 @@
 #define M_X_INDEX	0x00
 #define M_X_DATAREG	0x0A
 
+#define DAC_XGENIOCTRL		0x2A
+#define DAC_XGENIODATA		0x2B
+
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define TVP3026_INDEX		0x00
 #define TVP3026_PALWRADD	0x00
@@ -1054,6 +1083,48 @@
 #define isMilleniumII(x) (0)
 #endif
 
+#ifdef MATROXFB_DEBUG_REENTER
+static atomic_t guard_counter = ATOMIC_INIT(1);
+static atomic_t guard_printing = ATOMIC_INIT(1);
+static void guard_start(void) {
+	if (atomic_dec_and_test(&guard_counter)) {	/* first level */
+		if (!(bh_mask & (1 << CONSOLE_BH)))	/* and CONSOLE_BH disabled */
+			return;				/* is OK */
+		/* otherwise it is first level with CONSOLE_BH enabled -
+		   - if we are __sti or SMP, reentering from console_bh possible */
+		atomic_dec(&guard_printing);	/* disable reentrancy warning */
+		printk(KERN_DEBUG "matroxfb entered without CONSOLE_BH disabled\n");
+#ifdef printstate
+		printstate();
+#endif
+		atomic_inc(&guard_printing);
+		return;
+	}
+	/* real reentering... You should be already warned by code above */
+	if (atomic_dec_and_test(&guard_printing)) {
+#ifdef printstate
+		printstate();
+#endif
+	}
+	atomic_inc(&guard_printing);
+}
+
+static inline void guard_end(void) {
+	atomic_inc(&guard_counter);
+}
+
+#define CRITBEGIN guard_start();
+#define CRITEND   guard_end();
+
+#else
+
+#define CRITBEGIN
+#define CRITEND
+
+#endif
+
+#define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l))
+
 static void matrox_cfbX_init(WPMINFO struct display* p) {
 	u_int32_t maccess;
 	u_int32_t mpitch;
@@ -1101,7 +1172,7 @@
 	mga_outl(M_OPMODE, mopmode);
 	mga_outl(M_CXBNDRY, 0xFFFF0000);
 	mga_outl(M_YTOP, 0);
-	mga_outl(M_YBOT, 0x007FFFFF);
+	mga_outl(M_YBOT, 0x01FFFFFF);
 	mga_outl(M_MACCESS, maccess);
 	ACCESS_FBINFO(accel.m_dwg_rect) = M_DWG_TRAP | M_DWG_SOLID | M_DWG_ARZERO | M_DWG_SGNZERO | M_DWG_SHIFTZERO;
 	if (isMilleniumII(MINFO)) ACCESS_FBINFO(accel.m_dwg_rect) |= M_DWG_TRANSC;
@@ -1113,7 +1184,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfbX_bmove")
-	
+
+	CRITBEGIN
+
 	sx *= fontwidth(p);
 	dx *= fontwidth(p);
 	width *= fontwidth(p);
@@ -1142,8 +1215,10 @@
 	mga_outl(M_AR0, end);
 	mga_outl(M_AR3, start);
 	mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx);
-	mga_outl(M_YDSTLEN | M_EXEC, ((dy)<<16) | height);
+	mga_ydstlen(dy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB4
@@ -1154,7 +1229,9 @@
 	   also odd, that means that we cannot use acceleration */
 	
 	DBG("matrox_cfb4_bmove")
-	
+
+	CRITBEGIN
+
 	if ((sx | dx | width) & fontwidth(p) & 1) {
 		fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width);
 		return;
@@ -1194,6 +1271,8 @@
 	mga_outl(M_YDST, dy*pixx >> 5);
 	mga_outl(M_LEN | M_EXEC, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1201,13 +1280,17 @@
 		int width) {
 	
 	DBG("matroxfb_accel_clear")
-	
-	mga_fifo(4);
+
+	CRITBEGIN
+
+	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE);
 	mga_outl(M_FCOL, color);
 	mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx);
-	mga_outl(M_YDSTLEN | M_EXEC, (sy << 16) | height);
+	mga_ydstlen(sy, height);
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) {
@@ -1225,7 +1308,9 @@
 	MINFO_FROM_DISP(p);
 
 	DBG("matrox_cfb4_clear")
-	
+
+	CRITBEGIN
+
 	whattodo = 0; 
 	bgx = attr_bgcol_ec(p, conp);
 	bgx |= bgx << 4;
@@ -1277,6 +1362,8 @@
 			}
 		}
 	}
+
+	CRITEND
 }
 #endif
 
@@ -1323,7 +1410,10 @@
 	charcell = fontwidth(p) * fontheight(p);
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
-	mga_fifo(7);
+
+	CRITBEGIN
+
+	mga_fifo(8);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	
 	mga_outl(M_FCOL, fgx);
@@ -1332,8 +1422,10 @@
 	ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell;
 	mga_outl(M_AR3, ar3);
 	mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 	
 static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) {
@@ -1345,6 +1437,9 @@
 	
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1367,7 +1462,7 @@
 		mga_outl(M_BCOL, bgx);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy<<16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell);
 	} else {
 		u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step;
@@ -1379,7 +1474,7 @@
 		mga_outl(M_AR5, 0);
 		mga_outl(M_AR3, 0);
 		mga_outl(M_AR0, ar0);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 
 		switch (step) {
 		case 1:	
@@ -1410,6 +1505,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1464,6 +1560,9 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 	charcell = fontwidth(p) * fontheight(p);
+
+	CRITBEGIN
+
 	mga_fifo(3);
 	mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE);
 	mga_outl(M_FCOL, fgx);
@@ -1475,10 +1574,12 @@
 		mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx);
 		mga_outl(M_AR3, ar3);
 		mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF);
-		mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+		mga_ydstlen(yy, fontheight(p));
 		xx += fontwidth(p);
 	}
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) {
@@ -1504,7 +1605,7 @@
 		step = 4;
 	charcell = fontheight(p)*step;
 	xlen = (charcell + 3) & ~3;
-	ydstlen = (yy<<16) | fontheight(p);
+	ydstlen = (yy << 16) | fontheight(p);
 	if (fontwidth(p) == step << 3) {
 		ar0 = fontheight(p)*fontwidth(p) - 1;
 		easy = 1;
@@ -1512,6 +1613,9 @@
 		ar0 = fontwidth(p) - 1;
 		easy = 0;
 	}
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
@@ -1529,7 +1633,7 @@
 	while (count--) {
 		u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell;
 
-		mga_fifo(5);
+		mga_fifo(6);
 		mga_writel(mmio, M_FXBNDRY, fxbndry);
 		mga_writel(mmio, M_AR0, ar0);
 		mga_writel(mmio, M_AR3, 0);
@@ -1573,6 +1677,7 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+	CRITEND
 }
 
 #ifdef FBCON_HAS_CFB8
@@ -1635,6 +1740,8 @@
 	xx |= (xx + fontwidth(p)) << 16;
 	xx >>= 1;
 
+	CRITBEGIN
+	
 	mga_fifo(5);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
@@ -1642,6 +1749,8 @@
 	mga_outl(M_YDST, yy * p->var.xres_virtual >> 6);
 	mga_outl(M_LEN | M_EXEC, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 } 
 #endif
 
@@ -1654,12 +1763,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0x0F0F0F0F);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 #endif
 
@@ -1671,12 +1784,16 @@
 	yy *= fontheight(p);
 	xx *= fontwidth(p);
 
+	CRITBEGIN
+	
 	mga_fifo(4);
 	mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR);
 	mga_outl(M_FCOL, 0xFFFFFFFF);
 	mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx);
-	mga_outl(M_YDSTLEN | M_EXEC, (yy << 16) | fontheight(p));
+	mga_ydstlen(yy, fontheight(p));
 	WaitTillIdle();
+
+	CRITEND
 }
 
 static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) {
@@ -1840,6 +1957,9 @@
 
 	DBG("matroxfb_ti3026_cursor")
 	
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -1914,6 +2034,9 @@
 	xline = (~0) << (32 - ACCESS_FBINFO(cursor.w));
 	cursorbase = ACCESS_FBINFO(video.vbase);
 	h = ACCESS_FBINFO(features.DAC1064.cursorimage);
+
+	CRITBEGIN
+
 #ifdef __BIG_ENDIAN
 	WaitTillIdle();
 	mga_outl(M_OPMODE, M_OPMODE_32BPP);
@@ -1944,12 +2067,17 @@
 #ifdef __BIG_ENDIAN
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
 #endif
+
+	CRITEND
 }
 	
 static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) {
 	unsigned long flags;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
 			spin_lock_irqsave(&ACCESS_FBINFO(lock.DAC), flags);
@@ -2010,6 +2138,9 @@
 	fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p);
 	if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size))
 		return 0;
+
+	CRITBEGIN
+
 	mga_outl(M_OPMODE, M_OPMODE_8BPP);
 	if (width <= 8) {
 		if (width == 8)
@@ -2100,6 +2231,9 @@
 		}
 	}
 	mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode));
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2117,6 +2251,8 @@
 	unsigned int step;
 	MINFO_FROM_DISP(p);
 
+	CRITBEGIN
+
 	step = ACCESS_FBINFO(devflags.textstep);
 	srcoff = (sy * p->next_line) + (sx * step);
 	dstoff = (dy * p->next_line) + (dx * step);
@@ -2144,6 +2280,7 @@
 			height--;
 		}
 	}
+	CRITEND
 }
 
 static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx,
@@ -2156,6 +2293,9 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = sy * p->next_line + sx * step;
 	val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8));
+
+	CRITBEGIN
+	
 	while (height > 0) {
 		int i;
 		for (i = width; i > 0; offs += step, i--)
@@ -2163,6 +2303,7 @@
 		offs += p->next_line - width * step;
 		height--;
 	}
+	CRITEND
 }
 
 static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) {
@@ -2175,7 +2316,12 @@
 	offs = yy * p->next_line + xx * step;
 	chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8);
 	if (chr & 0x10000) chr |= 0x08;
+
+	CRITBEGIN
+	
 	mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr));
+
+	CRITEND
 }
 
 static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s,
@@ -2188,12 +2334,17 @@
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step;
 	attr = attr_fgcol(p, scr_readw(s)) | (attr_bgcol(p, scr_readw(s)) << 4);
+
+	CRITBEGIN
+	
 	while (count-- > 0) {
 		unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8;
 		if (chr & 0x10000) chr ^= 0x10008;
 		mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr));
 		offs += step;
 	}
+
+	CRITEND
 }
 
 static void matrox_text_revc(struct display* p, int xx, int yy) {
@@ -2203,7 +2354,12 @@
 
 	step = ACCESS_FBINFO(devflags.textstep);
 	offs = yy * p->next_line + xx * step + 1;
+	
+	CRITBEGIN
+	
 	mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77);
+
+	CRITEND
 }
 
 static int matrox_text_loadfont(WPMINFO struct display* p) {
@@ -2221,6 +2377,9 @@
 	dst = ACCESS_FBINFO(video.vbase);
 	i = 2;
 	font = (u_int8_t*)p->fontdata;
+
+	CRITBEGIN
+
 	mga_setr(M_SEQ_INDEX, 0x02, 0x04);
 	while (fsize--) {
 		int l;
@@ -2233,6 +2392,9 @@
 		i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep);
 	}
 	mga_setr(M_SEQ_INDEX, 0x02, 0x03);
+
+	CRITEND
+
 	return 1;
 }
 
@@ -2242,17 +2404,31 @@
 		return;
 
 	matroxfb_createcursorshape(PMINFO p, 0);
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
 	mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1);
+
+	CRITEND
 }
 
 static void matrox_text_cursor(struct display* p, int mode, int x, int y) {
 	unsigned int pos;
 	MINFO_FROM_DISP(p);
 
+	if (ACCESS_FBINFO(currcon_display) != p)
+		return;
+
 	if (mode == CM_ERASE) {
 		if (ACCESS_FBINFO(cursor.state) != CM_ERASE) {
+
+			CRITBEGIN
+			
 			mga_setr(M_CRTC_INDEX, 0x0A, 0x20);
+
+			CRITEND
+
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 		}
 		return;
@@ -2264,10 +2440,16 @@
 	ACCESS_FBINFO(cursor.x) = x;
 	ACCESS_FBINFO(cursor.y) = y;
 	pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x;
+
+	CRITBEGIN
+	
 	mga_setr(M_CRTC_INDEX, 0x0F, pos);
 	mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8);
 
 	mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u));
+
+	CRITEND
+
 	ACCESS_FBINFO(cursor.state) = CM_DRAW;
 }
 
@@ -2523,6 +2705,9 @@
 static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
 	unsigned int pos;
 	unsigned short p0, p1, p2;
+#ifdef CONFIG_FB_MATROX_32MB
+	unsigned int p3;
+#endif
 	struct display *disp;
 
 	DBG("matrox_pan_var")
@@ -2536,10 +2721,22 @@
 	}
 	p0 = ACCESS_FBINFO(currenthw)->CRTC[0x0D] = pos & 0xFF;
 	p1 = ACCESS_FBINFO(currenthw)->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+	p2 = ACCESS_FBINFO(currenthw)->CRTCEXT[0] = (ACCESS_FBINFO(currenthw)->CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+#ifdef CONFIG_FB_MATROX_32MB
+	p3 = ACCESS_FBINFO(currenthw)->CRTCEXT[8] = pos >> 21;
+#endif	
+
+	CRITBEGIN
+
 	mga_setr(M_CRTC_INDEX, 0x0D, p0);
 	mga_setr(M_CRTC_INDEX, 0x0C, p1);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 0x08, p3);
+#endif
 	mga_setr(M_EXTVGA_INDEX, 0x00, p2);
+
+	CRITEND
 }
 
 	/*
@@ -2627,13 +2824,16 @@
 		case 0:		return xres;
 		case 4:		rounding = 128;
 				break;
-		case 8:		rounding = 64;
+		case 8:		rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		case 16:	rounding = 32;
 				break;
-		case 24:	rounding = 64;
+		case 24:	rounding = 64;	/* doc says 64; 32 is OK for G400 */
 				break;
 		default:	rounding = 16;
+				/* on G400, 16 really does not work */
+				if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
+					rounding = 32;
 				break;
 	}
 	if (isInterleave(MINFO)) {
@@ -3140,7 +3340,7 @@
 	hw->DACclk[2] = p;
 }
 
-__initfunc(static void DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem)) {
+static void __init DAC1064_setmclk(CPMINFO struct matrox_hw_state* hw, int oscinfo, unsigned long fmem){
 	u_int32_t mx;
 
 	DBG("DAC1064_setmclk")
@@ -3288,6 +3488,8 @@
 static void DAC1064_restore_1(CPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw) {
 	
 	DBG("DAC1064_restore_1")
+
+	CRITBEGIN
 	
 	outDAC1064(PMINFO DAC1064_XSYSPLLM, hw->DACclk[3]);
 	outDAC1064(PMINFO DAC1064_XSYSPLLN, hw->DACclk[4]);
@@ -3298,6 +3500,8 @@
 		for (i = 0; i < sizeof(MGA1064_DAC_regs); i++)
 			outDAC1064(PMINFO MGA1064_DAC_regs[i], hw->DACreg[i]);
 	}
+
+	CRITEND
 }
 
 static void DAC1064_restore_2(WPMINFO const struct matrox_hw_state* hw, const struct matrox_hw_state* oldhw, struct display* p) {
@@ -3305,6 +3509,8 @@
 	unsigned int tmout;
 	
 	DBG("DAC1064_restore_2")
+
+	CRITBEGIN
 	
 	for (i = 0; i < 3; i++)
 		outDAC1064(PMINFO M1064_XPIXPLLCM + i, hw->DACclk[i]);
@@ -3313,6 +3519,9 @@
 			break;
 		udelay(10);
 	};
+
+	CRITEND
+
 	if (!tmout)
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 
@@ -3585,7 +3794,9 @@
 			var->pixclock = 15000;	/* limit for "normal" gclk & mclk */
 #endif
 	}
-
+	/* YDSTLEN contains only signed 16bit value */
+	if (var->yres_virtual > 32767)
+		var->yres_virtual = 32767;
 	if (var->yres_virtual < var->yres)
 		var->yres = var->yres_virtual;
 	if (var->xres_virtual < var->xres)
@@ -3684,7 +3895,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static void ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout)) {
+static void __init ti3026_setMCLK(CPMINFO struct matrox_hw_state* hw, int fout){
 	unsigned int f_pll;
 	unsigned int pclk_m, pclk_n, pclk_p;
 	unsigned int mclk_m, mclk_n, mclk_p;
@@ -3783,7 +3994,7 @@
 		printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 }
 
-__initfunc(static void ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init ti3026_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("ti3026_ramdac_init")
 
@@ -3800,7 +4011,7 @@
 }
 #endif
 
-__initfunc(static void matroxfb_fastfont_init(struct matrox_fb_info* minfo)) {
+static void matroxfb_fastfont_init(struct matrox_fb_info* minfo){
 	unsigned int size;
 
 	size = ACCESS_FBINFO(fastfont.size);
@@ -3824,7 +4035,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-__initfunc(static void MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_ramdac_init(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_ramdac_init");
 
@@ -3841,7 +4052,7 @@
 	DAC1064_setmclk(PMINFO hw, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333);
 }
 
-__initfunc(static int MGA1064_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGA1064_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_mystique[] = { 512,        640, 768,  800,  832,  960, 
 					     1024, 1152, 1280,      1600, 1664, 1920, 
 					     2048,    0};
@@ -3873,7 +4084,7 @@
 	return 0;
 }
 
-__initfunc(static void MGA1064_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGA1064_reset(WPMINFO struct matrox_hw_state* hw){
 
 	DBG("MGA1064_reset");
 
@@ -3893,7 +4104,7 @@
 static int def50 = 0;	/* reg50, & 0x0F, & 0x3000 (only 0x0000, 0x1000, 0x2000 (0x3000 disallowed and treated as 0) */
 #endif
 
-__initfunc(static void MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p)) {
+static void __init MGAG100_progPixClock(CPMINFO int flags, int m, int n, int p){
 	int reg;
 	int selClk;
 	int clk;
@@ -3937,7 +4148,7 @@
 	outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) & ~M1064_XPIXCLKCTRL_DIS);
 }
 
-__initfunc(static void MGAG100_setPixClock(CPMINFO int flags, int freq)) {
+static void __init MGAG100_setPixClock(CPMINFO int flags, int freq){
 	unsigned int m, n, p;
 
 	DBG("MGAG100_setPixClock")
@@ -3946,7 +4157,7 @@
 	MGAG100_progPixClock(PMINFO flags, m, n, p);
 }
 
-__initfunc(static int MGAG100_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init MGAG100_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_g100[] = {  512,        640, 768,  800,  832,  960, 
                                           1024, 1152, 1280,      1600, 1664, 1920, 
                                           2048, 0};
@@ -4036,7 +4247,7 @@
 	return 0;
 }
 	
-__initfunc(static void MGAG100_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init MGAG100_reset(WPMINFO struct matrox_hw_state* hw){
 	u_int8_t b;
 
 	DBG("MGAG100_reset")
@@ -4104,6 +4315,8 @@
 		dprintk("%02X:", hw->ATTR[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0);
 	mga_outb(M_MISC_REG, hw->MiscOutReg);
@@ -4125,6 +4338,8 @@
 		mga_outb(M_DAC_VAL, hw->DACpal[i]);
 	mga_inb(M_ATTR_RESET);
 	mga_outb(M_ATTR_INDEX, 0x20);
+
+	CRITEND
 }
 
 static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -4227,10 +4442,15 @@
 	int i;
 
 	DBG("MGA1064_restore")
+
+	CRITBEGIN
 	
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 	mga_outb(M_IEN, 0x00);
 	mga_outb(M_CACHEFLUSH, 0x00);
+
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
 	for (i = 0; i < 6; i++)
@@ -4244,10 +4464,18 @@
 	int i;
 
 	DBG("MGAG100_restore")
-	
+
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
+	CRITEND
+
 	DAC1064_restore_1(PMINFO hw, oldhw);
 	vgaHWrestore(PMINFO hw, oldhw);
+#ifdef CONFIG_FB_MATROX_32MB
+	if (ACCESS_FBINFO(devflags.support32MB))
+		mga_setr(M_EXTVGA_INDEX, 8, hw->CRTCEXT[8]);
+#endif
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 	DAC1064_restore_2(PMINFO hw, oldhw, p);
@@ -4265,9 +4493,16 @@
 		dprintk("%02X:", hw->CRTCEXT[i]);
 	dprintk("\n");
 
+	CRITBEGIN
+
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
 
+	CRITEND
+
 	vgaHWrestore(PMINFO hw, oldhw);
+
+	CRITBEGIN
+
 	for (i = 0; i < 6; i++)
 		mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]);
 
@@ -4285,11 +4520,13 @@
 		oldhw->DACclk[2] = inTi3026(PMINFO TVP3026_XPIXPLLDATA);
 		oldhw->DACclk[5] = inTi3026(PMINFO TVP3026_XLOOPPLLDATA);
 	}
+	CRITEND
 	if (!oldhw || memcmp(hw->DACclk, oldhw->DACclk, 6)) {
 		/* agrhh... setting up PLL is very slow on Millenium... */
 		/* Mystique PLL is locked in few ms, but Millenium PLL lock takes about 0.15 s... */
 		/* Maybe even we should call schedule() ? */
 
+		CRITBEGIN
 		outTi3026(PMINFO TVP3026_XCLKCTRL, hw->DACreg[POS3026_XCLKCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x2A);
 		outTi3026(PMINFO TVP3026_XLOOPPLLDATA, 0);
@@ -4307,24 +4544,31 @@
 					break;
 				udelay(10);
 			}
+
+			CRITEND
+
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Pixel PLL not locked after 5 secs\n");
 			else
 				dprintk(KERN_INFO "PixelPLL: %d\n", 500000-tmout);
+			CRITBEGIN
 		}
 		outTi3026(PMINFO TVP3026_XMEMPLLCTRL, hw->DACreg[POS3026_XMEMPLLCTRL]);
 		outTi3026(PMINFO TVP3026_XPLLADDR, 0x00);
 		for (i = 3; i < 6; i++)
 			outTi3026(PMINFO TVP3026_XLOOPPLLDATA, hw->DACclk[i]);
+		CRITEND
 		if ((hw->MiscOutReg & 0x08) && ((hw->DACclk[5] & 0x80) == 0x80)) {
 			int tmout;
 
+			CRITBEGIN
 			outTi3026(PMINFO TVP3026_XPLLADDR, 0x3F);
 			for (tmout = 500000; tmout; --tmout) {
 				if (inTi3026(PMINFO TVP3026_XLOOPPLLDATA) & 0x40) 
 					break;
 				udelay(10);
 			}
+			CRITEND
 			if (!tmout)
 				printk(KERN_ERR "matroxfb: Loop PLL not locked after 5 secs\n");
 			else
@@ -4379,7 +4623,7 @@
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = (void*)ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
-	fix->smem_len = ACCESS_FBINFO(video.len) - ACCESS_FBINFO(curr.ydstorg.bytes);
+	fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
 	fix->type = p->type;
 	fix->type_aux = p->type_aux;
 	fix->visual = p->visual;
@@ -4531,7 +4775,8 @@
 
 			hw->CRTC[0x0D] = pos & 0xFF;
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
-			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F);
+			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
+			hw->CRTCEXT[8] = pos >> 21;
 			ACCESS_FBINFO(hw_switch->restore(PMINFO hw, ohw, display));
 			ACCESS_FBINFO(cursor.redraw) = 1;
 			ACCESS_FBINFO(currenthw) = hw;
@@ -4717,10 +4962,16 @@
 		case 4:  seq = 0x20; crtc = 0x30; break;
 		default: seq = 0x00; crtc = 0x00; break;
 	}
+
+	CRITBEGIN
+	
 	mga_outb(M_SEQ_INDEX, 1);
 	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
 	mga_outb(M_EXTVGA_INDEX, 1);
 	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+
 #undef minfo
 }
 
@@ -4739,7 +4990,8 @@
 #define RS1056x344	12	/* 132 x 43 text */
 #define RS1056x400	13	/* 132 x 50 text */
 #define RS1056x480	14	/* 132 x 60 text */
-/* 0F-FF */
+#define RSNoxNo		15
+/* 10-FF */
 static struct { int xres, yres, left, right, upper, lower, hslen, vslen, vfreq; } timmings[] __initdata = {
 	{  640,  400,  48, 16, 39,  8,  96, 2, 70 },
 	{  640,  480,  48, 16, 33, 10,  96, 2, 60 },
@@ -4754,7 +5006,8 @@
 	{  640,  350,  48, 16, 39,  8,  96, 2, 70 },
 	{ 1056,  344,  96, 24, 59, 44, 160, 2, 70 },
 	{ 1056,  400,  96, 24, 39,  8, 160, 2, 70 },
-	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 }
+	{ 1056,  480,  96, 24, 36, 12, 160, 3, 60 },
+	{    0,    0,  ~0, ~0, ~0, ~0,   0, 0,  0 }
 };
 
 #define RSDepth(X)	(((X) >> 8) & 0x0F)
@@ -4775,13 +5028,14 @@
 	{ {  0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, {  0, 0, 0},  4 },
 	{ { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, {  0, 0, 0}, 24 },
 	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode with (default) VGA8x16 */
-	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 }	/* textmode hardwired to VGA8x8 */
+	{ {  0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, {  0, 0, 0},  0 },	/* textmode hardwired to VGA8x8 */
 };
 
 #define RSCreate(X,Y)	((X) | ((Y) << 8))
 static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = {
 /* default must be first */
 #ifdef FBCON_HAS_CFB8
+	{    ~0, RSCreate(RSNoxNo,     RS8bpp ) },
 	{ 0x101, RSCreate(RS640x480,   RS8bpp ) },
 	{ 0x100, RSCreate(RS640x400,   RS8bpp ) },
 	{ 0x180, RSCreate(RS768x576,   RS8bpp ) },
@@ -4793,14 +5047,8 @@
 	{ 0x198, RSCreate(RS1408x1056, RS8bpp ) },
 	{ 0x11C, RSCreate(RS1600x1200, RS8bpp ) },
 #endif
-#ifdef FBCON_HAS_CFB4
-	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
-	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
-	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
-	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
-	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
-#endif
 #ifdef FBCON_HAS_CFB16
+	{    ~0, RSCreate(RSNoxNo,     RS15bpp) },
 	{ 0x110, RSCreate(RS640x480,   RS15bpp) },
 	{ 0x181, RSCreate(RS768x576,   RS15bpp) },
 	{ 0x113, RSCreate(RS800x600,   RS15bpp) },
@@ -4821,6 +5069,7 @@
 	{ 0x11E, RSCreate(RS1600x1200, RS16bpp) },
 #endif
 #ifdef FBCON_HAS_CFB24
+	{    ~0, RSCreate(RSNoxNo,     RS24bpp) },
 	{ 0x1B2, RSCreate(RS640x480,   RS24bpp) },
 	{ 0x184, RSCreate(RS768x576,   RS24bpp) },
 	{ 0x1B5, RSCreate(RS800x600,   RS24bpp) },
@@ -4832,6 +5081,7 @@
 	{ 0x1BF, RSCreate(RS1600x1200, RS24bpp) },
 #endif
 #ifdef FBCON_HAS_CFB32
+	{    ~0, RSCreate(RSNoxNo,     RS32bpp) },
 	{ 0x112, RSCreate(RS640x480,   RS32bpp) },
 	{ 0x183, RSCreate(RS768x576,   RS32bpp) },
 	{ 0x115, RSCreate(RS800x600,   RS32bpp) },
@@ -4843,6 +5093,7 @@
 	{ 0x11F, RSCreate(RS1600x1200, RS32bpp) },
 #endif
 #ifdef FBCON_HAS_VGATEXT
+	{    ~0, RSCreate(RSNoxNo,     RSText)  },
 	{ 0x002, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x003, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
 	{ 0x007, RSCreate(RS640x400,   RSText)  },	/* 80x25 */
@@ -4853,6 +5104,14 @@
 	{ 0x10B, RSCreate(RS1056x400,  RSText8) },	/* 132x50 */
 	{ 0x10C, RSCreate(RS1056x480,  RSText8) },	/* 132x60 */
 #endif
+#ifdef FBCON_HAS_CFB4
+	{    ~0, RSCreate(RSNoxNo,     RS4bpp ) },
+	{ 0x010, RSCreate(RS640x350,   RS4bpp ) },
+	{ 0x012, RSCreate(RS640x480,   RS4bpp ) },
+	{ 0x102, RSCreate(RS800x600,   RS4bpp ) },
+	{ 0x104, RSCreate(RS1024x768,  RS4bpp ) },
+	{ 0x106, RSCreate(RS1280x1024, RS4bpp ) },
+#endif
 	{     0, 0                                 }};
 
 /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
@@ -4871,19 +5130,21 @@
 static int hwcursor = 1;		/* "matrox:nohwcursor" */
 static int blink = 1;			/* "matrox:noblink" */
 static int sgram = 0;			/* "matrox:sgram" */
+#ifdef CONFIG_MTRR
 static int mtrr = 1;			/* "matrox:nomtrr" */
+#endif
 static int grayscale = 0;		/* "matrox:grayscale" */
 static unsigned int fastfont = 0;	/* "matrox:fastfont:xxxxx" */
 static int dev = -1;			/* "matrox:dev:xxxxx" */
-static unsigned int vesa = 0x101;	/* "matrox:vesa:xxxxx" */
+static unsigned int vesa = ~0;		/* "matrox:vesa:xxxxx" */
 static int depth = -1;			/* "matrox:depth:xxxxx" */
 static unsigned int xres = 0;		/* "matrox:xres:xxxxx" */
 static unsigned int yres = 0;		/* "matrox:yres:xxxxx" */
-static unsigned int upper = 0;		/* "matrox:upper:xxxxx" */
-static unsigned int lower = 0;		/* "matrox:lower:xxxxx" */
+static unsigned int upper = ~0;		/* "matrox:upper:xxxxx" */
+static unsigned int lower = ~0;		/* "matrox:lower:xxxxx" */
 static unsigned int vslen = 0;		/* "matrox:vslen:xxxxx" */
-static unsigned int left = 0;		/* "matrox:left:xxxxx" */
-static unsigned int right = 0;		/* "matrox:right:xxxxx" */
+static unsigned int left = ~0;		/* "matrox:left:xxxxx" */
+static unsigned int right = ~0;		/* "matrox:right:xxxxx" */
 static unsigned int hslen = 0;		/* "matrox:hslen:xxxxx" */
 static unsigned int pixclock = 0;	/* "matrox:pixclock:xxxxx" */
 static int sync = -1;			/* "matrox:sync:xxxxx" */
@@ -4893,7 +5154,7 @@
 static char fontname[64];		/* "matrox:font:xxxxx" */
 
 #ifndef MODULE
-__initfunc(void matroxfb_setup(char *options, int *ints)) {
+void __init matroxfb_setup(char *options, int *ints){
 	char *this_opt;
 	
 	DBG("matroxfb_setup")
@@ -4901,7 +5162,7 @@
 	fontname[0] = '\0';
 	
 	if (!options || !*options)
-		return;
+		return 0;
 	
 	for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
 		if (!*this_opt) continue;
@@ -4954,6 +5215,31 @@
 			fv = simple_strtoul(this_opt+3, NULL, 0);
 		else if (!strncmp(this_opt, "mem:", 4)) 
 			mem = simple_strtoul(this_opt+4, NULL, 0);
+		else if (!strncmp(this_opt, "mode:", 5))
+			strcpy(videomode, this_opt+5);
+#ifdef CONFIG_FB_OF
+		else if (!strncmp(this_opt, "vmode:", 6)) {
+			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+            		if (vmode > 0 && vmode <= VMODE_MAX)
+				default_vmode = vmode;
+		} else if (!strncmp(this_opt, "cmode:", 6)) {
+			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+			switch (cmode) {
+				case 0:
+				case 8:
+					default_cmode = CMODE_8;
+					break;
+				case 15:
+				case 16:
+					default_cmode = CMODE_16;
+					break;
+				case 24:
+				case 32:
+					default_cmode = CMODE_32;
+					break;
+			}
+		}
+#endif
 		else if (!strncmp(this_opt, "fastfont:", 9))
 			fastfont = simple_strtoul(this_opt+9, NULL, 0);
 		else if (!strcmp(this_opt, "nofastfont"))	/* fastfont:N and nofastfont (nofastfont = fastfont:0) */
@@ -4987,8 +5273,10 @@
 				nobios = !value;
 			else if (!strcmp(this_opt, "init"))
 				noinit = !value;
+#ifdef CONFIG_MTRR
 			else if (!strcmp(this_opt, "mtrr"))
 				mtrr = value;
+#endif
 			else if (!strcmp(this_opt, "inv24"))
 				inv24 = value;
 			else if (!strcmp(this_opt, "cross4MB"))
@@ -5004,15 +5292,16 @@
 			}
 		}
 	}
+	return 0;
 }
 #endif
 
-__initfunc(static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize)) {
+static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
 	vaddr_t vm;
 	unsigned int offs;
 	unsigned int offs2;
 	unsigned char store;
-	unsigned char bytes[16];
+	unsigned char bytes[32];
 	unsigned char* tmp;
 	unsigned long cbase;
 	unsigned long mbase;
@@ -5025,7 +5314,7 @@
 	maxSize &= ~0x1FFFFF;	/* must be X*2MB (really it must be 2 or X*4MB) */
 	/* at least 2MB */
 	if (maxSize < 0x0200000) return 0;
-	if (maxSize > 0x1000000) maxSize = 0x1000000;
+	if (maxSize > 0x2000000) maxSize = 0x2000000;
 
 	mga_outb(M_EXTVGA_INDEX, 0x03);
 	mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80);
@@ -5080,7 +5369,7 @@
 }
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-__initfunc(static int Ti3026_preinit(WPMINFO struct matrox_hw_state* hw)) {
+static int __init Ti3026_preinit(WPMINFO struct matrox_hw_state* hw){
 	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960, 
 					  1024, 1152, 1280,      1600, 1664, 1920, 
 					  2048, 0};
@@ -5133,7 +5422,7 @@
 	return 0;
 }
 
-__initfunc(static void Ti3026_reset(WPMINFO struct matrox_hw_state* hw)) {
+static void __init Ti3026_reset(WPMINFO struct matrox_hw_state* hw){
 	
 	DBG("Ti3026_reset")
 	
@@ -5163,20 +5452,28 @@
 
 struct video_board {
 	int maxvram;
+	int maxdisplayable;
 	int accelID;
 	struct matrox_switch* lowlevel;
 		 };
 #ifdef CONFIG_FB_MATROX_MILLENIUM
-static struct video_board vbMillenium __initdata	= {0x0800000,	FB_ACCEL_MATROX_MGA2064W,	&matrox_millenium};
-static struct video_board vbMillenium2 __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W,	&matrox_millenium};
-static struct video_board vbMillenium2A __initdata	= {0x1000000,	FB_ACCEL_MATROX_MGA2164W_AGP,	&matrox_millenium};
+static struct video_board vbMillenium __initdata   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA2064W,	  &matrox_millenium};
+static struct video_board vbMillenium2 __initdata  = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W,	  &matrox_millenium};
+static struct video_board vbMillenium2A __initdata = {0x1000000, 0x0800000, FB_ACCEL_MATROX_MGA2164W_AGP, &matrox_millenium};
 #endif	/* CONFIG_FB_MATROX_MILLENIUM */
 #ifdef CONFIG_FB_MATROX_MYSTIQUE
-static struct video_board vbMystique __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGA1064SG,	&matrox_mystique};
+static struct video_board vbMystique __initdata    = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGA1064SG,	  &matrox_mystique};
 #endif	/* CONFIG_FB_MATROX_MYSTIQUE */
 #ifdef CONFIG_FB_MATROX_G100
-static struct video_board vbG100 __initdata		= {0x0800000,	FB_ACCEL_MATROX_MGAG100,	&matrox_G100};
-static struct video_board vbG200 __initdata		= {0x1000000,	FB_ACCEL_MATROX_MGAG200,	&matrox_G100};
+static struct video_board vbG100 __initdata	   = {0x0800000, 0x0800000, FB_ACCEL_MATROX_MGAG100,	  &matrox_G100};
+static struct video_board vbG200 __initdata	   = {0x1000000, 0x1000000, FB_ACCEL_MATROX_MGAG200,	  &matrox_G100};
+#ifdef CONFIG_FB_MATROX_32MB
+/* from doc it looks like that accelerator can draw only to low 16MB :-( Direct accesses & displaying are OK for
+   whole 32MB */
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#else
+static struct video_board vbG400 __initdata	   = {0x2000000, 0x1000000, FB_ACCEL_MATROX_MGAG400,	  &matrox_G100};
+#endif
 #endif
 
 #define DEVF_VIDEO64BIT	0x01
@@ -5185,6 +5482,15 @@
 #define	DEVF_MILLENIUM2	0x08
 #define DEVF_CROSS4MB	0x10
 #define DEVF_TEXT4B	0x20
+#define DEVF_DDC_8_2	0x40
+#define DEVF_DMA	0x80
+#define DEVF_SUPPORT32MB	0x100
+#define DEVF_ANY_VXRES		0x200
+
+#define DEVF_G100	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2) /* no doc, no vxres... */
+#define DEVF_G200	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES)
+#define DEVF_G400	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2 | DEVF_ANY_VXRES | DEVF_SUPPORT32MB)
+
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
 	unsigned int flags;
@@ -5229,88 +5535,94 @@
 #ifdef CONFIG_FB_MATROX_G100
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_PCI,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"MGA-G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_PRODUCTIVA_G100_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"Productiva G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G100_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G100,
 		230000,
 		&vbG100,
 		"unknown G100 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_PCI,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"unknown G200 (PCI)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_GENERIC,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		220000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MYSTIQUE_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Mystique G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENIUM_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		250000,
 		&vbG200,
 		"Millennium G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MARVEL_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"Marvel G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		PCI_SS_VENDOR_ID_SIEMENS_NIXDORF,	PCI_SS_ID_SIEMENS_MGA_G200_AGP,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"MGA-G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G200_AGP,	0xFF,
 		0,			0,
-		DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB,
+		DEVF_G200,
 		230000,
 		&vbG200,
 		"unknown G200 (AGP)"},
+	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400_AGP,	0xFF,
+		0,			0,
+		DEVF_G400,
+		360000,
+		&vbG400,
+		"unknown G400 (AGP)"},
 #endif
 	{0,			0,				0xFF,
 		0,			0,
@@ -5319,7 +5631,7 @@
 		NULL,
 		NULL}};
 	
-__initfunc(static int initMatrox2(WPMINFO struct display* d, struct board* b)) {
+static int __init initMatrox2(WPMINFO struct display* d, struct board* b){
 	unsigned long ctrlptr_phys = 0;
 	unsigned long video_base_phys = 0;
 	unsigned int memsize;
@@ -5348,17 +5660,21 @@
 		ACCESS_FBINFO(devflags.vgastepdisp) = 64;
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
+#ifdef CONFIG_FB_MATROX_32MB
+	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+#endif
+	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
 	if (ACCESS_FBINFO(capable.cross4MB) < 0)
 		ACCESS_FBINFO(capable.cross4MB) = b->flags & DEVF_CROSS4MB;
 	if (b->flags & DEVF_SWAPS) {
-		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x3FFF;
-		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x7FFFFF;	/* aligned at 8MB (or 16 for Mill 2) */
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
+		video_base_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
 	} else {
-		ctrlptr_phys = ACCESS_FBINFO(pcidev)->base_address[0] & ~0x3FFF;
-		video_base_phys = ACCESS_FBINFO(pcidev)->base_address[1] & ~0x7FFFFF;	/* aligned at 8MB */
+		ctrlptr_phys = ACCESS_FBINFO(pcidev)->resource[0].start;
+		video_base_phys = ACCESS_FBINFO(pcidev)->resource[1].start;
 	}
 	if (!ctrlptr_phys) {
 		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
@@ -5472,8 +5788,8 @@
 		return -ENOMEM;
 	}
 	ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len);
-	if (ACCESS_FBINFO(video.len_usable) > 0x08000000)
-		ACCESS_FBINFO(video.len_usable) = 0x08000000;
+	if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable)
+		ACCESS_FBINFO(video.len_usable) = b->base->maxdisplayable;
 #ifdef CONFIG_MTRR
 	if (mtrr) {
 		ACCESS_FBINFO(mtrr.vram) = mtrr_add(video_base_phys, ACCESS_FBINFO(video.len), MTRR_TYPE_WRCOMB, 1);
@@ -5482,11 +5798,16 @@
 	}
 #endif	/* CONFIG_MTRR */
 
+	if (!ACCESS_FBINFO(devflags.novga))
+		request_region(0x3C0, 32, "matrox");
+	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
+
 /* validate params, autodetect k, M */
 	if (fh < 1000) fh *= 1000;	/* 1kHz minimum */
 	if (maxclk < 1000) maxclk *= 1000;	/* kHz -> Hz, MHz -> kHz */
 	if (maxclk < 1000000) maxclk *= 1000;	/* kHz -> Hz, 1MHz minimum */
-	vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
+	if (vesa != ~0)
+		vesa &= 0x1DFF;		/* mask out clearscreen, acceleration and so on */
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
 	ACCESS_FBINFO(fbcon.monspecs.hfmax) = fh;
@@ -5504,19 +5825,19 @@
 	}
 	{
 		int res = RSResolution(RSptr->info)-1;
-		if (!left)
+		if (left == ~0)
 			left = timmings[res].left;
 		if (!xres)
 			xres = timmings[res].xres;
-		if (!right)
+		if (right == ~0)
 			right = timmings[res].right;
 		if (!hslen)
 			hslen = timmings[res].hslen;
-		if (!upper)
+		if (upper == ~0)
 			upper = timmings[res].upper;
 		if (!yres)
 			yres = timmings[res].yres;
-		if (!lower)
+		if (lower == ~0)
 			lower = timmings[res].lower;
 		if (!vslen)
 			vslen = timmings[res].vslen;
@@ -5525,6 +5846,7 @@
 		if (depth == -1)
 			depth = RSDepth(RSptr->info);
 	}
+#if 0	
 	if (sync == -1) {
 		sync = 0;
 		if (yres < 400)
@@ -5532,31 +5854,7 @@
 		else if (yres < 480)
 			sync |= FB_SYNC_VERT_HIGH_ACT;
 	}
-	if (xres < 320)
-		xres = 320;
-	if (xres > 2048)
-		xres = 2048;
-	if (yres < 200)
-		yres = 200;
-	if (yres > 2048)
-		yres = 2048;
-	{
-		unsigned int tmp;
-
-		if (fv) {
-			tmp = fv * (upper + yres + lower + vslen);
-			if ((tmp < fh) || (fh == 0)) fh = tmp;
-		}
-		if (fh) {
-			tmp = fh * (left + xres + right + hslen);
-			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
-		}
-		maxclk = (maxclk + 499) / 500;
-		if (maxclk) {
-			tmp = (2000000000 + maxclk) / maxclk;
-			if (tmp > pixclock) pixclock = tmp;
-		}
-	}
+#endif
 	if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) {
 		strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8");
 	}
@@ -5564,27 +5862,8 @@
 	vesafb_defined.green = colors[depth-1].green;
 	vesafb_defined.blue = colors[depth-1].blue;
 	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
-	if (pixclock < 2000)		/* > 500MHz */
-		pixclock = 4000;	/* 250MHz */
-	if (pixclock > 1000000)
-		pixclock = 1000000;	/* 1MHz */
-	vesafb_defined.xres = xres;
-	vesafb_defined.yres = yres;
-	vesafb_defined.xoffset = 0;
-	vesafb_defined.yoffset = 0;
 	vesafb_defined.grayscale = grayscale;
-	vesafb_defined.pixclock = pixclock;
-	vesafb_defined.left_margin = left;
-	vesafb_defined.right_margin = right;
-	vesafb_defined.hsync_len = hslen;
-	vesafb_defined.upper_margin = upper;
-	vesafb_defined.lower_margin = lower;
-	vesafb_defined.vsync_len = vslen;
-	vesafb_defined.sync = sync;
 	vesafb_defined.vmode = 0;
-
-	if (!ACCESS_FBINFO(devflags.novga))
-		request_region(0x3C0, 32, "matrox");
 	if (noaccel)
 		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;
 
@@ -5597,8 +5876,60 @@
 	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
 	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
 	ACCESS_FBINFO(fbcon.flags) = FBINFO_FLAG_DEFAULT;
-	ACCESS_FBINFO(hw_switch->reset(PMINFO hw));
 	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
+
+#if 0
+	fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL,
+		NULL, 0, NULL, vesafb_defined.bits_per_pixel);
+#endif
+	/* mode modifiers */
+	if (sync != -1)
+		vesafb_defined.sync = sync;
+	if (hslen)
+		vesafb_defined.hsync_len = hslen;
+	if (vslen)
+		vesafb_defined.vsync_len = vslen;
+	if (left != ~0)
+		vesafb_defined.left_margin = left;
+	if (right != ~0)
+		vesafb_defined.right_margin = right;
+	if (upper != ~0)
+		vesafb_defined.upper_margin = upper;
+	if (lower != ~0)
+		vesafb_defined.lower_margin = lower;
+	if (xres)
+		vesafb_defined.xres = xres;
+	if (yres)
+		vesafb_defined.yres = yres;
+	/* fv, fh, maxclk limits was specified */
+	{
+		unsigned int tmp;
+
+		if (fv) {
+			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres 
+			          + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+			if ((tmp < fh) || (fh == 0)) fh = tmp;
+		}
+		if (fh) {
+			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres 
+			          + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
+		}
+		maxclk = (maxclk + 499) / 500;
+		if (maxclk) {
+			tmp = (2000000000 + maxclk) / maxclk;
+			if (tmp > pixclock) pixclock = tmp;
+		}
+	}
+	if (pixclock) {
+		if (pixclock < 2000)		/* > 500MHz */
+			pixclock = 4000;	/* 250MHz */
+		if (pixclock > 1000000)
+			pixclock = 1000000;	/* 1MHz */
+		vesafb_defined.pixclock = pixclock;
+	}
+		
+	/* FIXME: Where to move this?! */
 #if defined(CONFIG_FB_OF)
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 	strcpy(ACCESS_FBINFO(matrox_name), "MTRX,");	/* OpenFirmware naming convension */
@@ -5608,30 +5939,30 @@
 #endif
 	if ((xres <= 640) && (yres <= 480)) {
 		struct fb_var_screeninfo var;
-		int default_vmode = nvram_read_byte(NV_VMODE);
-		int default_cmode = nvram_read_byte(NV_CMODE);
-
-		if ((default_vmode <= 0) || (default_vmode > VMODE_MAX))
+		if (default_vmode == VMODE_NVRAM) {
+			default_vmode = nvram_read_byte(NV_VMODE);
+			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+				default_vmode = VMODE_CHOOSE;
+		}
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
 			default_vmode = VMODE_640_480_60;
-		if ((default_cmode < CMODE_8) || (default_cmode > CMODE_32))
+		if (default_cmode == CMODE_NVRAM)
+			default_cmode = nvram_read_byte(NV_CMODE);
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
 			default_cmode = CMODE_8;
 		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
 			var.accel_flags = vesafb_defined.accel_flags;
 			var.xoffset = var.yoffset = 0;
 			vesafb_defined = var; /* Note: mac_vmode_to_var() doesnot set all parameters */
-		}
+              }
 	}
 #endif
-	{
-		int pixel_size = vesafb_defined.bits_per_pixel;
-
-		vesafb_defined.xres_virtual = matroxfb_pitch_adjust(PMINFO vesafb_defined.xres, pixel_size);
-		if (nopan) {
-			vesafb_defined.yres_virtual = vesafb_defined.yres;
-		} else {
-			vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
-			                                        to yres_virtual * xres_virtual < 2^32 */
-		}
+	vesafb_defined.xres_virtual = vesafb_defined.xres;
+	if (nopan) {
+		vesafb_defined.yres_virtual = vesafb_defined.yres;
+	} else {
+		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
+		                                        to yres_virtual * xres_virtual < 2^32 */
 	}
 	if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) {
 		printk(KERN_ERR "matroxfb: cannot set required parameters\n");
@@ -5647,8 +5978,9 @@
 /* We do not have to set currcon to 0... register_framebuffer do it for us on first console
  * and we do not want currcon == 0 for subsequent framebuffers */
 
-	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0)
+	if (register_framebuffer(&ACCESS_FBINFO(fbcon)) < 0) {
 		return -EINVAL;
+	}
 	printk("fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(ACCESS_FBINFO(fbcon.node)), ACCESS_FBINFO(fbcon.modename));
 	if (ACCESS_FBINFO(currcon) < 0) {
@@ -5663,7 +5995,7 @@
 
 static struct matrox_fb_info* fb_list = NULL;
 
-__initfunc(static int matrox_init(void)) {
+static int __init matrox_init(void){
 	struct pci_dev* pdev = NULL;
 
 	DBG("matrox_init")
@@ -5756,7 +6088,7 @@
 #ifndef MODULE
 static int __init initialized = 0;
 
-__initfunc(void matroxfb_init(void))
+void __init matroxfb_init(void)
 {
 	DBG("matroxfb_init")
 	
@@ -5764,10 +6096,12 @@
 		initialized = 1;
 		matrox_init();
 	}
+	if (!fb_list) return -ENXIO;
+	return 0;
 }
 
 #if defined(CONFIG_FB_OF)
-__initfunc(int matrox_of_init(struct device_node *dp)) {
+int __init matrox_of_init(struct device_node *dp){
 	DBG("matrox_of_init");
 	
 	if (!initialized) {
@@ -5781,8 +6115,8 @@
 
 #else
 
-MODULE_AUTHOR("(c) 1998 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200");
+MODULE_AUTHOR("(c) 1998,1999 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400");
 MODULE_PARM(mem, "i");
 MODULE_PARM_DESC(mem, "Size of available memory in MB, KB or B (2,4,8,12,16MB, default=autodetect)");
 MODULE_PARM(disabled, "i");
@@ -5802,7 +6136,7 @@
 MODULE_PARM(mtrr, "i");
 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
 MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
 MODULE_PARM(inv24, "i");
 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
 MODULE_PARM(inverse, "i");
@@ -5855,14 +6189,20 @@
 MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)");
 MODULE_PARM(cross4MB, "i");
 MODULE_PARM_DESC(cross4MB, "Specifies that 4MB boundary can be in middle of line. (default=autodetected)");
+#ifdef CONFIG_FB_OF
+MODULE_PARM(vmode, "i");
+MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)");
+MODULE_PARM(cmode, "i");
+MODULE_PARM_DESC(cmode, "Specify the video depth that should be used (8bit default)");
+#endif
 
-__initfunc(int init_module(void)) {
+int __init init_module(void){
 
 	DBG("init_module")
 
 #ifdef DEBUG
 	if( disabled )
-		return 0;
+		return -ENXIO;
 #endif /* DEBUG */
 
 	if (depth == 0)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)