patch-2.4.21 linux-2.4.21/drivers/video/matrox/matroxfb_crtc2.c

Next file: linux-2.4.21/drivers/video/matrox/matroxfb_crtc2.h
Previous file: linux-2.4.21/drivers/video/matrox/matroxfb_base.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/video/matrox/matroxfb_crtc2.c linux-2.4.21/drivers/video/matrox/matroxfb_crtc2.c
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  */
 
@@ -28,8 +28,8 @@
 
 static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
 		unsigned *blue, unsigned *transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	if (regno > 16)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	if (regno >= 16)
 		return 1;
 	*red = m2info->palette[regno].red;
 	*blue = m2info->palette[regno].blue;
@@ -41,10 +41,10 @@
 
 static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
 		unsigned blue, unsigned transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
-	if (regno > 16)
+	if (regno >= 16)
 		return 1;
 	m2info->palette[regno].red = red;
 	m2info->palette[regno].blue = blue;
@@ -84,86 +84,129 @@
 #undef m2info
 }
 
-static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
-	if (p->cmap.len)
-		fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
+static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info)
+{
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &m2info->currcon_display->cmap;
+	
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 	else
 		fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 }
 
+
 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
 		struct my_timming* mt,
 		struct display* p,
 		int mode,
 		unsigned int pos) {
-	u_int32_t tmp;
+	struct matrox_crtc2 c2;
 	MINFO_FROM(m2info->primary_dev);
 
 	switch (mode) {
 		case 15:
-			tmp = 0x00200000;
+			c2.ctl = 0x00200000;
 			break;
 		case 16:
-			tmp = 0x00400000;
+			c2.ctl = 0x00400000;
 			break;
 /*		case 32: */
 		default:
-			tmp = 0x00800000;
+			c2.ctl = 0x00800000;
 			break;
 	}
-
-	if (ACCESS_FBINFO(output.sh)) {
-		tmp |= 0x00000001;	/* enable CRTC2 */
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			if (ACCESS_FBINFO(devflags.g450dac)) {
-				tmp |= 0x00000006; /* source from secondary pixel PLL */
-				/* no vidrst */
-			} else {
-				tmp |= 0x00000002; /* source from VDOCLK */
-				tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
-				/* MGA TVO is our clock source */
+	c2.ctl |= 0x00000001;	/* enable CRTC2 */
+	c2.datactl = 0;
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			c2.ctl |= 0x00000006; /* source from secondary pixel PLL */
+			/* no vidrst when in monitor mode */
+			if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+				c2.ctl |=  0xC0001000; /* Enable H/V vidrst */
 			}
-		} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			tmp |= 0x00000004; /* source from pixclock */
-			/* PIXPLL is our clock source */
-		}
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
-			tmp |= 0x00100000;	/* connect CRTC2 to DAC */
+		} else {
+			c2.ctl |= 0x00000002; /* source from VDOCLK */
+			c2.ctl |= 0xC0000000; /* enable vvidrst & hvidrst */
+			/* MGA TVO is our clock source */
+		}
+	} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00000004; /* source from pixclock */
+		/* PIXPLL is our clock source */
+	}
+	if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00100000;	/* connect CRTC2 to DAC */
 	}
 	if (mt->interlaced) {
-		tmp |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
+		c2.ctl |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
 		mt->VDisplay >>= 1;
 		mt->VSyncStart >>= 1;
 		mt->VSyncEnd >>= 1;
 		mt->VTotal >>= 1;
 	}
-	mga_outl(0x3C10, tmp | 0x10000000);	/* depth and so on... 0x10000000 is VIDRST polarity */
-	mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
-	mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
-	mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
-	mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
-	mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart));	/* preload */
+	if ((mt->HTotal & 7) == 2) {
+		c2.datactl |= 0x00000010;
+		mt->HTotal &= ~7;
+	}
+	c2.ctl |= 0x10000000;	/* 0x10000000 is VIDRST polarity */
+	c2.hparam = ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8);
+	c2.hsync = ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8);
+	c2.vparam = ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1);
+	c2.vsync = ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1);
+	c2.preload = ((mt->VSyncStart) << 16) | (mt->HSyncStart);
+	mga_outl(0x3C14, c2.hparam);
+	mga_outl(0x3C18, c2.hsync);
+	mga_outl(0x3C1C, c2.vparam);
+	mga_outl(0x3C20, c2.vsync);
+	mga_outl(0x3C24, c2.preload);
 	{
 		u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
-		if (mt->interlaced) {
+		if (c2.ctl & 0x02000000) {
 			/* field #0 is smaller, so... */
 			mga_outl(0x3C2C, pos);			/* field #1 vmemory start */
 			mga_outl(0x3C28, pos + linelen);	/* field #0 vmemory start */
 			linelen <<= 1;
+			m2info->interlaced = 1;
 		} else {
 			mga_outl(0x3C28, pos);		/* vmemory start */
+			m2info->interlaced = 0;
 		}
 		mga_outl(0x3C40, linelen);
 	}
-	tmp = 0x0FFF0000;		/* line compare */
-	if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
-		tmp |= 0x00000100;
-	if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
-		tmp |= 0x00000200;
-	mga_outl(0x3C44, tmp);
-	mga_outl(0x3C4C, 0);		/* data control */
+	mga_outl(0x3C4C, c2.datactl);		/* data control */
+	if (c2.ctl & 0x02000000) {
+		int i;
+
+		mga_outl(0x3C10, c2.ctl & ~0x02000000);
+                for (i = 0; i < 2; i++) {
+                        unsigned int nl;
+                        unsigned int lastl = 0;
+
+                        while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
+                                lastl = nl;
+                        }
+                }
+	}
+        mga_outl(0x3C10, c2.ctl);
+	ACCESS_FBINFO(hw).crtc2.ctl = c2.ctl;
+	{
+		u_int32_t tmp;
+
+		tmp = 0x0FFF0000;		/* line compare */
+		if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
+			tmp |= 0x00000100;
+		if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
+			tmp |= 0x00000200;
+		mga_outl(0x3C44, tmp);
+	}
+}
+
+static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
+	MINFO_FROM(m2info->primary_dev);
+
+	mga_outl(0x3C10, 0x00000004);	/* disable CRTC2, CRTC1->DAC1, PLL as clock source */
+	ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
 }
 
 static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
@@ -176,19 +219,18 @@
 	unsigned int pos;
 	unsigned int linelen;
 	unsigned int pixelsize;
+	MINFO_FROM(m2info->primary_dev);
 
-#define minfo (m2info->primary_dev)
 	pixelsize = var->bits_per_pixel >> 3;
 	linelen = var->xres_virtual * pixelsize;
 	pos = var->yoffset * linelen + var->xoffset * pixelsize;
 	pos += m2info->video.offbase;
-	if (var->vmode & FB_VMODE_INTERLACED) {
+	if (m2info->interlaced) {
 		mga_outl(0x3C2C, pos);
 		mga_outl(0x3C28, pos + linelen);
 	} else {
 		mga_outl(0x3C28, pos);
 	}
-#undef minfo
 }
 
 static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
@@ -292,7 +334,7 @@
 }
 
 static int matroxfb_dh_open(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -305,7 +347,7 @@
 }
 
 static int matroxfb_dh_release(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -316,7 +358,7 @@
 
 static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
 	if (con >= 0)
@@ -345,7 +387,7 @@
 
 static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (con < 0)
 		*var = m2info->fbcon.disp->var;
 	else
@@ -356,7 +398,7 @@
 
 static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 	int chgvar;
 	int visual;
@@ -390,7 +432,7 @@
 		chgvar = 0;
 	p->var = *var;
 	/* cmap */
-	p->screen_base = vaddr_va(m2info->video.vbase);
+	p->screen_base = m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
 	p->visual = visual;
 	p->ypanstep = 1;
 	p->ywrapstep = 0;
@@ -405,48 +447,52 @@
 	if (con == m2info->currcon) {
 		struct my_timming mt;
 		unsigned int pos;
+		int out;
+		int cnt;
 
 		matroxfb_var2my(var, &mt);
+		mt.crtc = MATROXFB_SRC_CRTC2;
 		/* CRTC2 delay */
 		mt.delay = 34;
 
 		pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
 		pos += m2info->video.offbase;
-		DAC1064_global_init(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->compute(MINFO, &mt);
+		cnt = 0;
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+				cnt++;
+				if (ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-			up_read(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
+		ACCESS_FBINFO(crtc2).mnp = mt.mnp;
+		up_read(&ACCESS_FBINFO(altout).lock);
+		if (cnt) {
+			matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		} else {
+			matroxfb_dh_disable(m2info);
 		}
-		matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		DAC1064_global_init(PMINFO2);
 		DAC1064_global_restore(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->program(MINFO);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->start(MINFO);
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->program) {
+				ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->start) {
+				ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
+		up_read(&ACCESS_FBINFO(altout).lock);
 		matroxfb_dh_cfbX_init(m2info, p);
-		do_install_cmap(m2info, p);
+		my_install_cmap(m2info);
 	}
 	return 0;
 #undef m2info
@@ -454,7 +500,7 @@
 
 static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -473,7 +519,7 @@
 
 static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -497,7 +543,7 @@
 
 static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
 	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
 		return -EINVAL;
@@ -530,7 +576,7 @@
 		unsigned long arg,
 		int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	DBG("matroxfb_crtc2_ioctl")
@@ -557,38 +603,84 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int out;
+				int changes;
 
 				if (get_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.ph))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP)
-					return -EINVAL;
-				if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
-					return -EINVAL;
-				if (tmp == ACCESS_FBINFO(output.sh))
+				for (out = 0; out < 32; out++) {
+					if (tmp & (1 << out)) {
+						if (out >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[out]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+						return -EINVAL;
+					if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
+						return -EBUSY;
+				}
+				changes = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (tmp & (1 << out)) {
+						if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
+						}
+					} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.sh) = tmp;
 				matroxfb_dh_switch(m2info->currcon, info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						conn |= 1 << out;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t tmp = 0;
+				int out;
 
-				/* we do not support DFP from CRTC2 */
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
-				/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).output) {
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								tmp |= 1 << out;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
+					if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
+						tmp = 0;
+					}
+				}
 				if (put_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
@@ -598,6 +690,24 @@
 #undef m2info
 }
 
+static int matroxfb_dh_blank(int blank, struct fb_info* info) {
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	switch (blank) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		default:;
+	}
+	/* do something... */
+	return 0;
+#undef m2info
+}
+
+static void matroxfb_dh_blank24(int blank, struct fb_info* info) {
+	matroxfb_dh_blank(blank, info);
+}
+
 static struct fb_ops matroxfb_dh_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	matroxfb_dh_open,
@@ -612,7 +722,7 @@
 };
 
 static int matroxfb_dh_switch(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display* p;
 
@@ -635,25 +745,12 @@
 }
 
 static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	matroxfb_dh_pan_var(m2info, &fb_display[con].var);
 	return 0;
 #undef m2info
 }
 
-static void matroxfb_dh_blank(int blank, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	switch (blank) {
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		default:;
-	}
-	/* do something... */
-#undef m2info
-}
-
 static struct fb_var_screeninfo matroxfb_dh_defined = {
 		640,480,640,480,/* W,H, virtual W,H */
 		0,0,		/* offset */
@@ -692,7 +789,7 @@
 	m2info->fbcon.disp = d;
 	m2info->fbcon.switch_con = &matroxfb_dh_switch;
 	m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
-	m2info->fbcon.blank = &matroxfb_dh_blank;
+	m2info->fbcon.blank = &matroxfb_dh_blank24;
 	m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
 	m2info->currcon = -1;
 	m2info->currcon_display = d;
@@ -722,11 +819,10 @@
 	/*
 	 *  If we have unused output, connect CRTC2 to it...
 	 */
-	if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && 
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
-		ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
+	if (ACCESS_FBINFO(outputs[1]).output &&
+	    ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
+	    ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
 	}
 
 	matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
@@ -739,7 +835,7 @@
 	}
 	down_write(&ACCESS_FBINFO(crtc2.lock));
 	oldcrtc2 = ACCESS_FBINFO(crtc2.info);
-	ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
+	ACCESS_FBINFO(crtc2.info) = m2info;
 	up_write(&ACCESS_FBINFO(crtc2.lock));
 	if (oldcrtc2) {
 		printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
@@ -768,16 +864,16 @@
 #define minfo (m2info->primary_dev)
 	if (m2info->fbcon_registered) {
 		int id;
-		struct fb_info* crtc2;
+		struct matroxfb_dh_fb_info* crtc2;
 
 		down_write(&ACCESS_FBINFO(crtc2.lock));
 		crtc2 = ACCESS_FBINFO(crtc2.info);
-		if (crtc2 == &m2info->fbcon)
+		if (crtc2 == m2info)
 			ACCESS_FBINFO(crtc2.info) = NULL;
 		up_write(&ACCESS_FBINFO(crtc2.lock));
-		if (crtc2 != &m2info->fbcon) {
+		if (crtc2 != m2info) {
 			printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
-				crtc2, &m2info->fbcon);
+				crtc2, m2info);
 			printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
 			return;
 		}
@@ -815,6 +911,7 @@
 
 static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
 	matroxfb_dh_deregisterfb(crtc2);
+	kfree(crtc2);
 }
 
 static struct matroxfb_driver crtc2 = {
@@ -831,7 +928,7 @@
 	matroxfb_unregister_driver(&crtc2);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_crtc2_init);

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