patch-2.4.2 linux/drivers/video/riva/fbdev.c

Next file: linux/drivers/video/riva/riva_hw.c
Previous file: linux/drivers/video/riva/accel.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.1/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c
@@ -12,6 +12,8 @@
  *
  *	Ferenc Bakonyi:  Bug fixes, cleanup, modularization
  *
+ *	Jindrich Makovicka:  Accel code help, hw cursor, mtrr
+ *
  * Initial template from skeletonfb.c, created 28 Dec 1997 by Geert Uytterhoeven
  * Includes riva_hw.c from nVidia, see copyright below.
  * KGI code provided the basis for state storage, init, and mode switching.
@@ -19,11 +21,13 @@
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
  * for more details.
+ *
+ * Known bugs and issues:
+ *	restoring text mode fails
+ *	doublescan modes are broken
+ *	option 'noaccel' has no effect
  */
 
-/* version number of this driver */
-#define RIVAFB_VERSION "0.7.3"
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -32,34 +36,36 @@
 #include <linux/mm.h>
 #include <linux/selection.h>
 #include <linux/tty.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-
-#include <video/fbcon.h>
-
-#include "riva_hw.h"
-#include "nv4ref.h"
+#include <linux/console.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include "rivafb.h"
 #include "nvreg.h"
-#include "../vga.h"
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb32.h>
 
 #ifndef CONFIG_PCI		/* sanity check */
 #error This driver requires PCI support.
 #endif
 
-/*****************************************************************
+
+
+/* version number of this driver */
+#define RIVAFB_VERSION "0.9.2a"
+
+
+
+/* ------------------------------------------------------------------------- *
  *
  * various helpful macros and constants
  *
- */
+ * ------------------------------------------------------------------------- */
 
-/* #define RIVAFBDEBUG */
+#undef RIVAFBDEBUG
 #ifdef RIVAFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
@@ -69,31 +75,50 @@
 #ifndef RIVA_NDEBUG
 #define assert(expr) \
 	if(!(expr)) { \
-        printk( "Assertion failed! %s,%s,%s,line=%d\n",\
-        #expr,__FILE__,__FUNCTION__,__LINE__); \
+	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
+	#expr,__FILE__,__FUNCTION__,__LINE__); \
 	BUG(); \
-        }
+	}
 #else
 #define assert(expr)
 #endif
 
-/* GGI compatibility macros */
-#define io_out8			outb
-#define io_in8			inb
-#define NUM_SEQ_REGS		0x05
-#define NUM_CRT_REGS		0x41
-#define NUM_GRC_REGS		0x09
-#define NUM_ATC_REGS		0x15
-
 #define PFX "rivafb: "
 
-#define CNVT_TOHW(val,width)	((((val)<<(width))+0x7FFF-(val))>>16)
-
 /* macro that allows you to set overflow bits */
 #define SetBitField(value,from,to) SetBF(to,GetBF(value,from))
 #define SetBit(n)		(1<<(n))
 #define Set8Bits(value)		((value)&0xff)
 
+/* HW cursor parameters */
+#define DEFAULT_CURSOR_BLINK_RATE	(40)
+#define CURSOR_HIDE_DELAY		(20)
+#define CURSOR_SHOW_DELAY		(3)
+
+#define CURSOR_COLOR		0x7fff
+#define TRANSPARENT_COLOR	0x0000
+#define MAX_CURS		32
+
+
+
+/* ------------------------------------------------------------------------- *
+ *
+ * prototypes
+ *
+ * ------------------------------------------------------------------------- */
+
+static void rivafb_blank(int blank, struct fb_info *info);
+
+extern void riva_setup_accel(struct rivafb_info *rinfo);
+extern inline void wait_for_idle(struct rivafb_info *rinfo);
+
+
+
+/* ------------------------------------------------------------------------- *
+ *
+ * card identification
+ *
+ * ------------------------------------------------------------------------- */
 
 enum riva_chips {
 	CH_RIVA_128 = 0,
@@ -103,187 +128,170 @@
 	CH_RIVA_VTNT2,	/* VTNT2 */
 	CH_RIVA_UVTNT2,	/* VTNT2 */
 	CH_RIVA_ITNT2,	/* ITNT2 */
+	CH_GEFORCE_SDR,
+	CH_GEFORCE_DDR,
+	CH_QUADRO,
+	CH_GEFORCE2_MX,
+	CH_QUADRO2_MXR,
+	CH_GEFORCE2_GTS,
+	CH_GEFORCE2_ULTRA,
+	CH_QUADRO2_PRO,
 };
 
-
 /* directly indexed by riva_chips enum, above */
 static struct riva_chip_info {
 	const char *name;
 	unsigned arch_rev;
 } riva_chip_info[] __devinitdata = {
-	{ "RIVA-128", 3 },
-	{ "RIVA-TNT", 4 },
-	{ "RIVA-TNT2", 5 },
-	{ "RIVA-UTNT2", 5 },
-	{ "RIVA-VTNT2", 5 },
-	{ "RIVA-UVTNT2", 5 },
-	{ "RIVA-ITNT2", 5 },
+	{ "RIVA-128", NV_ARCH_03 },
+	{ "RIVA-TNT", NV_ARCH_04 },
+	{ "RIVA-TNT2", NV_ARCH_04 },
+	{ "RIVA-UTNT2", NV_ARCH_04 },
+	{ "RIVA-VTNT2", NV_ARCH_04 },
+	{ "RIVA-UVTNT2", NV_ARCH_04 },
+	{ "RIVA-ITNT2", NV_ARCH_04 },
+	{ "GeForce-SDR", NV_ARCH_10},
+	{ "GeForce-DDR", NV_ARCH_10},
+	{ "Quadro", NV_ARCH_10},
+	{ "GeForce2-MX", NV_ARCH_10},
+	{ "Quadro2-MXR", NV_ARCH_10},
+	{ "GeForce2-GTS", NV_ARCH_10},
+	{ "GeForce2-ULTRA", NV_ARCH_10},
+	{ "Quadro2-PRO", NV_ARCH_10},
 };
 
-
 static struct pci_device_id rivafb_pci_tbl[] __devinitdata = {
-	{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_128 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 },
+	{ PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_128 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_TNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_UTNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_VTNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RIVA_ITNT2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_SDR },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE_DDR },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_MX },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_MXR },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_GEFORCE2_GTS },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_QUADRO2_PRO },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, rivafb_pci_tbl);
 
 
-/* holds the state of the VGA core and extended Riva hw state from riva_hw.c.
- * From KGI originally. */
-struct riva_regs {
-	u8 attr[NUM_ATC_REGS];
-	u8 crtc[NUM_CRT_REGS];
-	u8 gra[NUM_GRC_REGS];
-	u8 seq[NUM_SEQ_REGS];
-	u8 misc_output;
-	RIVA_HW_STATE ext;
-};
 
+/* ------------------------------------------------------------------------- *
+ *
+ * framebuffer related structures
+ *
+ * ------------------------------------------------------------------------- */
 
-/*
- * describes the state of a Riva board
- */
+#ifdef FBCON_HAS_CFB8
+extern struct display_switch fbcon_riva8;
+#endif
+#ifdef FBCON_HAS_CFB16
+extern struct display_switch fbcon_riva16;
+#endif
+#ifdef FBCON_HAS_CFB32
+extern struct display_switch fbcon_riva32;
+#endif
+
+#if 0
+/* describes the state of a Riva board */
 struct rivafb_par {
 	struct riva_regs state;	/* state of hw board */
 	__u32 visual;		/* FB_VISUAL_xxx */
 	unsigned depth;		/* bpp of current mode */
 };
-
-typedef struct {
-	unsigned char red, green, blue, transp;
-} riva_cfb8_cmap_t;
-
-
-
-struct rivafb_info;
-struct rivafb_info {
-	struct fb_info info;	/* kernel framebuffer info */
-
-	RIVA_HW_INST riva;	/* interface to riva_hw.c */
-
-	const char *drvr_name;	/* Riva hardware board type */
-
-	unsigned long ctrl_base_phys;	/* physical control register base addr */
-	unsigned long fb_base_phys;	/* physical framebuffer base addr */
-
-	caddr_t ctrl_base;	/* virtual control register base addr */
-	caddr_t fb_base;	/* virtual framebuffer base addr */
-
-	unsigned ram_amount;	/* amount of RAM on card, in bytes */
-	unsigned dclk_max;	/* max DCLK */
-
-	struct riva_regs initial_state;	/* initial startup video mode */
-
-	struct display disp;
-	int currcon;
-	struct display *currcon_display;
-
-	struct rivafb_info *next;
-
-	struct pci_dev *pd;	/* pointer to board's pci info */
-	unsigned base0_region_size;	/* size of control register region */
-	unsigned base1_region_size;	/* size of framebuffer region */
-
-	riva_cfb8_cmap_t palette[256];	/* VGA DAC palette cache */
-
-#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-	union {
-#ifdef FBCON_HAS_CFB16
-		u_int16_t cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-		u_int32_t cfb32[16];
 #endif
-	} con_cmap;
-#endif				/* FBCON_HAS_CFB16 | FBCON_HAS_CFB32 */
+
+struct riva_cursor {
+	int enable;
+	int on;
+	int vbl_cnt;
+	int last_move_delay;
+	int blink_rate;
+	struct {
+		u16 x, y;
+	} pos, size;
+	unsigned short image[MAX_CURS*MAX_CURS];
+	struct timer_list *timer;
 };
 
-/* ------------------- global variables ------------------------ */
 
 
-static struct rivafb_info *riva_boards = NULL;
+/* ------------------------------------------------------------------------- *
+ *
+ * global variables
+ *
+ * ------------------------------------------------------------------------- */
+
+struct rivafb_info *riva_boards = NULL;
 
 /* command line data, set in rivafb_setup() */
 static char fontname[40] __initdata = { 0 };
+static char noaccel __initdata = 0;
+static char nomove = 0;
+static char nohwcursor __initdata = 0;
+static char noblink = 0;
+#ifdef CONFIG_MTRR
+static char nomtrr __initdata = 0;
+#endif
+
 #ifndef MODULE
-static char noaccel __initdata = 0;	/* unused */
 static const char *mode_option __initdata = NULL;
+#else
+static char *font = NULL;
 #endif
 
 static struct fb_var_screeninfo rivafb_default_var = {
-	/* 640x480-8@60, yres_virtual=2400 (fits for all Riva cards */
-	640, 480, 640, 2400, 0, 0, 8, 0,
-	{0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0},
-	0, 0, -1, -1, 0, 39721, 40, 24, 32, 11, 96, 2,
-	0, FB_VMODE_NONINTERLACED
-};
-
-
-/* ------------------- prototypes ------------------------------ */
-
-static int rivafb_get_fix (struct fb_fix_screeninfo *fix, int con,
-		    struct fb_info *info);
-static int rivafb_get_var (struct fb_var_screeninfo *var, int con,
-		    struct fb_info *info);
-static int rivafb_set_var (struct fb_var_screeninfo *var, int con,
-		    struct fb_info *info);
-static int rivafb_get_cmap (struct fb_cmap *cmap, int kspc, int con,
-		     struct fb_info *info);
-static int rivafb_set_cmap (struct fb_cmap *cmap, int kspc, int con,
-		     struct fb_info *info);
-static int rivafb_pan_display (struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int rivafb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-		  unsigned long arg, int con, struct fb_info *info);
-static int rivafb_switch (int con, struct fb_info *info);
-static int rivafb_updatevar (int con, struct fb_info *info);
-static void rivafb_blank (int blank, struct fb_info *info);
-
-static void riva_load_video_mode (struct rivafb_info *rivainfo,
-				  struct fb_var_screeninfo *video_mode);
-static int riva_getcolreg (unsigned regno, unsigned *red, unsigned *green,
-			   unsigned *blue, unsigned *transp,
-			   struct fb_info *info);
-static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   struct fb_info *info);
-static int riva_get_cmap_len (const struct fb_var_screeninfo *var);
-
-static int riva_set_fbinfo (struct rivafb_info *rinfo);
-
-static void riva_save_state (struct rivafb_info *rinfo, struct riva_regs *regs);
-static void riva_load_state (struct rivafb_info *rinfo, struct riva_regs *regs);
-static struct rivafb_info *riva_board_list_add (struct rivafb_info *board_list,
-					 struct rivafb_info *new_node);
-static struct rivafb_info *riva_board_list_del (struct rivafb_info *board_list,
-					 struct rivafb_info *del_node);
-static void riva_wclut (unsigned char regnum, unsigned char red,
-			unsigned char green, unsigned char blue);
-
-
-
-
-/* kernel interface */
-static struct fb_ops riva_fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	rivafb_get_fix,
-	fb_get_var:	rivafb_get_var,
-	fb_set_var:	rivafb_set_var,
-	fb_get_cmap:	rivafb_get_cmap,
-	fb_set_cmap:	rivafb_set_cmap,
-	fb_pan_display:	rivafb_pan_display,
-	fb_ioctl:	rivafb_ioctl,
+	xres:		640,
+	yres:		480,
+	xres_virtual:	640,
+	yres_virtual:	480,
+	xoffset:	0,
+	yoffset:	0,
+	bits_per_pixel:	8,
+	grayscale:	0,
+	red:		{0, 6, 0},
+	green:		{0, 6, 0},
+	blue:		{0, 6, 0},
+	transp:		{0, 0, 0},
+	nonstd:		0,
+	activate:	0,
+	height:		-1,
+	width:		-1,
+	accel_flags:	0,
+	pixclock:	39721,
+	left_margin:	40,
+	right_margin:	24,
+	upper_margin:	32,
+	lower_margin:	11,
+	hsync_len:	96,
+	vsync_len:	2,
+	sync:		0,
+	vmode:		FB_VMODE_NONINTERLACED
 };
 
-
-
-
 /* from GGI */
 static const struct riva_regs reg_template = {
 	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* ATTR */
@@ -297,425 +305,985 @@
 	 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* 0x30 */
 	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	 0x00,			/* 0x40 */
+	 0x00,							/* 0x40 */
 	 },
 	{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,	/* GRA  */
 	 0xFF},
-	{0x03, 0x01, 0x0F, 0x00, 0x0E},	/* SEQ  */
-	0xEB			/* MISC */
+	{0x03, 0x01, 0x0F, 0x00, 0x0E},				/* SEQ  */
+	0xEB							/* MISC */
 };
 
 
 
-/* ------------------- general utility functions -------------------------- */
-
-/**
- * riva_set_dispsw
- * @rinfo: pointer to internal driver struct for a given Riva card
+/* ------------------------------------------------------------------------- *
  *
- * DESCRIPTION:
- * Sets up console Low level operations depending on the current? color depth
- * of the display
- */
+ * MMIO access macros
+ *
+ * ------------------------------------------------------------------------- */
 
-static void riva_set_dispsw (struct rivafb_info *rinfo)
+static inline void CRTCout(struct rivafb_info *rinfo, unsigned char index,
+			   unsigned char val)
 {
-	struct display *disp = &rinfo->disp;
+	VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
+	VGA_WR08(rinfo->riva.PCIO, 0x3d5, val);
+}
 
-	DPRINTK ("ENTER\n");
+static inline unsigned char CRTCin(struct rivafb_info *rinfo,
+				   unsigned char index)
+{
+	VGA_WR08(rinfo->riva.PCIO, 0x3d4, index);
+	return (VGA_RD08(rinfo->riva.PCIO, 0x3d5));
+}
 
-	assert (rinfo != NULL);
+static inline void GRAout(struct rivafb_info *rinfo, unsigned char index,
+			  unsigned char val)
+{
+	VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
+	VGA_WR08(rinfo->riva.PVIO, 0x3cf, val);
+}
 
-	disp->dispsw_data = NULL;
+static inline unsigned char GRAin(struct rivafb_info *rinfo,
+				  unsigned char index)
+{
+	VGA_WR08(rinfo->riva.PVIO, 0x3ce, index);
+	return (VGA_RD08(rinfo->riva.PVIO, 0x3cf));
+}
 
-	switch (disp->var.bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
-	case 1:
-		disp->dispsw = &fbcon_mfb;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB4
-	case 4:
-		disp->dispsw = &fbcon_cfb4;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		disp->dispsw = &fbcon_cfb8;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 15:
-	case 16:
-		disp->dispsw = &fbcon_cfb16;
-		disp->dispsw_data = &rinfo->con_cmap.cfb16;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	case 24:
-		disp->dispsw = &fbcon_cfb24;
-		disp->dispsw_data = rinfo->con_cmap.cfb24;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		disp->dispsw = &fbcon_cfb32;
-		disp->dispsw_data = rinfo->con_cmap.cfb32;
-		break;
-#endif
-	default:
-		DPRINTK ("Setting fbcon_dummy renderer\n");
-		disp->dispsw = &fbcon_dummy;
-	}
+static inline void SEQout(struct rivafb_info *rinfo, unsigned char index,
+			  unsigned char val)
+{
+	VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
+	VGA_WR08(rinfo->riva.PVIO, 0x3c5, val);
+}
 
-	DPRINTK ("EXIT\n");
+static inline unsigned char SEQin(struct rivafb_info *rinfo,
+				  unsigned char index)
+{
+	VGA_WR08(rinfo->riva.PVIO, 0x3c4, index);
+	return (VGA_RD08(rinfo->riva.PVIO, 0x3c5));
 }
 
+static inline void ATTRout(struct rivafb_info *rinfo, unsigned char index,
+			   unsigned char val)
+{
+	VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
+	VGA_WR08(rinfo->riva.PCIO, 0x3c0, val);
+}
 
+static inline unsigned char ATTRin(struct rivafb_info *rinfo,
+				   unsigned char index)
+{
+	VGA_WR08(rinfo->riva.PCIO, 0x3c0, index);
+	return (VGA_RD08(rinfo->riva.PCIO, 0x3c1));
+}
 
+static inline void MISCout(struct rivafb_info *rinfo, unsigned char val)
+{
+	VGA_WR08(rinfo->riva.PVIO, 0x3c2, val);
+}
 
-static int riva_init_disp_var (struct rivafb_info *rinfo)
+static inline unsigned char MISCin(struct rivafb_info *rinfo)
 {
-#ifndef MODULE
-	if (mode_option)
-		fb_find_mode (&rinfo->disp.var, &rinfo->info, mode_option,
-			      NULL, 0, NULL, 8);
-#endif				/* !MODULE */
-	return 0;
+	return (VGA_RD08(rinfo->riva.PVIO, 0x3cc));
 }
 
 
 
+/* ------------------------------------------------------------------------- *
+ *
+ * cursor stuff
+ *
+ * ------------------------------------------------------------------------- */
 
-static int __devinit riva_init_disp (struct rivafb_info *rinfo)
+/**
+ * riva_cursor_timer_handler - blink timer
+ * @dev_addr: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Cursor blink timer.
+ */
+static void riva_cursor_timer_handler(unsigned long dev_addr)
 {
-	struct fb_info *info;
-	struct display *disp;
-
-	DPRINTK ("ENTER\n");
-
-	assert (rinfo != NULL);
+	struct rivafb_info *rinfo = (struct rivafb_info *)dev_addr;
 
-	info = &rinfo->info;
-	disp = &rinfo->disp;
-
-	disp->var = rivafb_default_var;
-	info->disp = disp;
+	if (!rinfo->cursor) return;
 
-	/* FIXME: assure that disp->cmap is completely filled out */
+	if (!rinfo->cursor->enable) goto out;
 
-	disp->screen_base = rinfo->fb_base;
-	disp->visual = FB_VISUAL_PSEUDOCOLOR;
-	disp->type = FB_TYPE_PACKED_PIXELS;
-	disp->type_aux = 0;
-	disp->ypanstep = 1;
-	disp->ywrapstep = 0;
-	disp->next_line = disp->line_length =
-	    (disp->var.xres_virtual * disp->var.bits_per_pixel) >> 3;
-	disp->can_soft_blank = 1;
-	disp->inverse = 0;
+	if (rinfo->cursor->last_move_delay < 1000)
+		rinfo->cursor->last_move_delay++;
 
-	riva_set_dispsw (rinfo);
+	if (rinfo->cursor->vbl_cnt && --rinfo->cursor->vbl_cnt == 0) {
+		rinfo->cursor->on ^= 1;
+		if (rinfo->cursor->on)
+			*(rinfo->riva.CURSORPOS) = (rinfo->cursor->pos.x & 0xFFFF)
+						   | (rinfo->cursor->pos.y << 16);
+		rinfo->riva.ShowHideCursor(&rinfo->riva, rinfo->cursor->on);
+		if (!noblink)
+			rinfo->cursor->vbl_cnt = rinfo->cursor->blink_rate;
+	}
+out:
+	rinfo->cursor->timer->expires = jiffies + (HZ / 100);
+	add_timer(rinfo->cursor->timer);
+}
 
-	disp->scrollmode = 0;
+/**
+ * rivafb_init_cursor - allocates cursor structure and starts blink timer
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Allocates cursor structure and starts blink timer.
+ *
+ * RETURNS:
+ * Pointer to allocated cursor structure.
+ *
+ * CALLED FROM:
+ * rivafb_init_one()
+ */
+static struct riva_cursor * __init rivafb_init_cursor(struct rivafb_info *rinfo)
+{
+	struct riva_cursor *cursor;
 
-	rinfo->currcon_display = disp;
+	cursor = kmalloc(sizeof(struct riva_cursor), GFP_KERNEL);
+	if (!cursor) return 0;
+	memset(cursor, 0, sizeof(*cursor));
 
-	if ((riva_init_disp_var (rinfo)) < 0) {	/* must be done last */
-		DPRINTK ("EXIT, returning -1\n");
-		return -1;
+	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
+	if (!cursor->timer) {
+		kfree(cursor);
+		return 0;
 	}
+	memset(cursor->timer, 0, sizeof(*cursor->timer));
 
-	DPRINTK ("EXIT, returning 0\n");
-	return 0;
+	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
 
+	init_timer(cursor->timer);
+	cursor->timer->expires = jiffies + (HZ / 100);
+	cursor->timer->data = (unsigned long)rinfo;
+	cursor->timer->function = riva_cursor_timer_handler;
+	add_timer(cursor->timer);
+
+	return cursor;
 }
 
+/**
+ * rivafb_exit_cursor - stops blink timer and releases cursor structure
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Stops blink timer and releases cursor structure.
+ *
+ * CALLED FROM:
+ * rivafb_init_one()
+ * rivafb_remove_one()
+ */
+static void rivafb_exit_cursor(struct rivafb_info *rinfo)
+{
+	struct riva_cursor *cursor = rinfo->cursor;
 
+	if (cursor) {
+		if (cursor->timer) {
+			del_timer_sync(cursor->timer);
+			kfree(cursor->timer);
+		}
+		kfree(cursor);
+		rinfo->cursor = 0;
+	}
+}
 
-static int __devinit riva_set_fbinfo (struct rivafb_info *rinfo)
+/**
+ * rivafb_download_cursor - writes cursor shape into card registers
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Writes cursor shape into card registers.
+ *
+ * CALLED FROM:
+ * riva_load_video_mode()
+ */
+static void rivafb_download_cursor(struct rivafb_info *rinfo)
 {
-	struct fb_info *info;
+	int i, save;
+	int *image;
+	
+	if (!rinfo->cursor) return;
 
-	assert (rinfo != NULL);
+	image = (int *)rinfo->cursor->image;
+	save = rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
+	for (i = 0; i < (MAX_CURS*MAX_CURS*2)/sizeof(int); i++)
+		writel(image[i], rinfo->riva.CURSOR + i);
 
-	info = &rinfo->info;
+	rinfo->riva.ShowHideCursor(&rinfo->riva, save);
+}
 
-	strcpy (info->modename, rinfo->drvr_name);
-	info->node = -1;
-	info->flags = FBINFO_FLAG_DEFAULT;
-	info->fbops = &riva_fb_ops;
+/**
+ * rivafb_create_cursor - sets rectangular cursor
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ * @width: cursor width in pixels
+ * @height: cursor height in pixels
+ *
+ * DESCRIPTION:
+ * Sets rectangular cursor.
+ *
+ * CALLED FROM:
+ * rivafb_set_font()
+ * rivafb_set_var()
+ */
+static void rivafb_create_cursor(struct rivafb_info *rinfo, int width, int height)
+{
+	struct riva_cursor *c = rinfo->cursor;
+	int i, j, idx;
 
-	/* FIXME: set monspecs to what??? */
+	if (c) {
+		if (width <= 0 || height <= 0) {
+			width = 8;
+			height = 16;
+		}
+		if (width > MAX_CURS) width = MAX_CURS;
+		if (height > MAX_CURS) height = MAX_CURS;
 
-	info->display_fg = NULL;
-	strncpy (info->fontname, fontname, sizeof (info->fontname));
-	info->fontname[sizeof (info->fontname) - 1] = 0;
+		c->size.x = width;
+		c->size.y = height;
+		
+		idx = 0;
 
-	info->changevar = NULL;
-	info->switch_con = rivafb_switch;
-	info->updatevar = rivafb_updatevar;
-	info->blank = rivafb_blank;
+		for (i = 0; i < height; i++) {
+			for (j = 0; j < width; j++,idx++)
+				c->image[idx] = CURSOR_COLOR;
+			for (j = width; j < MAX_CURS; j++,idx++)
+				c->image[idx] = TRANSPARENT_COLOR;
+		}
+		for (i = height; i < MAX_CURS; i++)
+			for (j = 0; j < MAX_CURS; j++,idx++)
+				c->image[idx] = TRANSPARENT_COLOR;
+	}
+}
 
-	if (riva_init_disp (rinfo) < 0)	/* must be done last */
-		return -1;
+/**
+ * rivafb_set_font - change font size
+ * @p: pointer to display object
+ * @width: font width in pixels
+ * @height: font height in pixels
+ *
+ * DESCRIPTION:
+ * Callback function called if font settings changed.
+ *
+ * RETURNS:
+ * 1 (Always succeeds.)
+ */
+static int rivafb_set_font(struct display *p, int width, int height)
+{
+	struct rivafb_info *fb = (struct rivafb_info *)(p->fb_info);
 
-	return 0;
+	rivafb_create_cursor(fb, width, height);
+	return 1;
 }
 
+/**
+ * rivafb_cursor - cursor handler
+ * @p: pointer to display object
+ * @mode: cursor mode (see CM_*)
+ * @x: cursor x coordinate in characters
+ * @y: cursor y coordinate in characters
+ *
+ * DESCRIPTION:
+ * Cursor handler.
+ */
+static void rivafb_cursor(struct display *p, int mode, int x, int y)
+{
+	struct rivafb_info *rinfo = (struct rivafb_info *)(p->fb_info);
+	struct riva_cursor *c = rinfo->cursor;
+
+	if (!c)	return;
 
+	x = x * fontwidth(p) - p->var.xoffset;
+	y = y * fontheight(p) - p->var.yoffset;
+
+	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
+		return;
 
+	c->enable = 0;
+	if (c->on) rinfo->riva.ShowHideCursor(&rinfo->riva, 0);
+		
+	c->pos.x = x;
+	c->pos.y = y;
 
-/* ----------------------------- PCI bus ----------------------------- */
+	switch (mode) {
+	case CM_ERASE:
+		c->on = 0;
+		break;
+	case CM_DRAW:
+	case CM_MOVE:
+		if (c->last_move_delay <= 1) { /* rapid cursor movement */
+			c->vbl_cnt = CURSOR_SHOW_DELAY;
+		} else {
+			*(rinfo->riva.CURSORPOS) = (x & 0xFFFF) | (y << 16);
+			rinfo->riva.ShowHideCursor(&rinfo->riva, 1);
+			if (!noblink) c->vbl_cnt = CURSOR_HIDE_DELAY;
+			c->on = 1;
+		}
+		c->last_move_delay = 0;
+		c->enable = 1;
+		break;
+	}
+}
 
 
 
+/* ------------------------------------------------------------------------- *
+ *
+ * general utility functions
+ *
+ * ------------------------------------------------------------------------- */
 
-static int __devinit rivafb_init_one (struct pci_dev *pd,
-				      const struct pci_device_id *ent)
+/**
+ * riva_set_dispsw - sets dispsw
+ * @rinfo: pointer to internal driver struct for a given Riva card
+ * @disp: pointer to display object
+ *
+ * DESCRIPTION:
+ * Sets up console low level operations depending on the current? color depth
+ * of the display.
+ *
+ * CALLED FROM:
+ * rivafb_set_var()
+ * rivafb_switch()
+ * riva_init_disp()
+ */
+static void riva_set_dispsw(struct rivafb_info *rinfo, struct display *disp)
 {
-	struct rivafb_info *rinfo;
-	struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
+	int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
 
-	assert (pd != NULL);
-	assert (rci != NULL);
+	DPRINTK("ENTER\n");
 
-	rinfo = kmalloc (sizeof (struct rivafb_info), GFP_KERNEL);
-	if (!rinfo)
-		goto err_out;
+	assert(rinfo != NULL);
 
-	memset (rinfo, 0, sizeof (struct rivafb_info));
+	disp->dispsw_data = NULL;
 
-	rinfo->drvr_name = rci->name;
-	rinfo->riva.Architecture = rci->arch_rev;
-
-	rinfo->pd = pd;
-	rinfo->base0_region_size = pci_resource_len (pd, 0);
-	rinfo->base1_region_size = pci_resource_len (pd, 1);
+	disp->screen_base = rinfo->fb_base;
+	disp->type = FB_TYPE_PACKED_PIXELS;
+	disp->type_aux = 0;
+	disp->ypanstep = 1;
+	disp->ywrapstep = 0;
+	disp->can_soft_blank = 1;
+	disp->inverse = 0;
 
-	assert (rinfo->base0_region_size >= 0x00800000);	/* from GGI */
-	assert (rinfo->base1_region_size >= 0x01000000);	/* from GGI */
+	switch (disp->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		rinfo->dispsw = accel ? fbcon_riva8 : fbcon_cfb8;
+		disp->dispsw = &rinfo->dispsw;
+		disp->line_length = disp->var.xres_virtual;
+		disp->visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		rinfo->dispsw = accel ? fbcon_riva16 : fbcon_cfb16;
+		disp->dispsw_data = &rinfo->con_cmap.cfb16;
+		disp->dispsw = &rinfo->dispsw;
+		disp->line_length = disp->var.xres_virtual * 2;
+		disp->visual = FB_VISUAL_DIRECTCOLOR;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		rinfo->dispsw = accel ? fbcon_riva32 : fbcon_cfb32;
+		disp->dispsw_data = rinfo->con_cmap.cfb32;
+		disp->dispsw = &rinfo->dispsw;
+		disp->line_length = disp->var.xres_virtual * 4;
+		disp->visual = FB_VISUAL_DIRECTCOLOR;
+		break;
+#endif
+	default:
+		DPRINTK("Setting fbcon_dummy renderer\n");
+		rinfo->dispsw = fbcon_dummy;
+		disp->dispsw = &rinfo->dispsw;
+	}
 
-	rinfo->ctrl_base_phys = pci_resource_start (rinfo->pd, 0);
-	rinfo->fb_base_phys = pci_resource_start (rinfo->pd, 1);
+	/* FIXME: verify that the above code sets dsp->* fields correctly */
 
-	if (!request_mem_region (rinfo->ctrl_base_phys,
-				 rinfo->base0_region_size, "rivafb")) {
-		printk (KERN_ERR PFX "cannot reserve MMIO region\n");
-		goto err_out_kfree;
+	if (rinfo->cursor) {
+		rinfo->dispsw.cursor = rivafb_cursor;
+		rinfo->dispsw.set_font = rivafb_set_font;
 	}
 
-	if (!request_mem_region (rinfo->fb_base_phys,
-				 rinfo->base1_region_size, "rivafb")) {
-		printk (KERN_ERR PFX "cannot reserve FB region\n");
-		goto err_out_free_base0;
+	DPRINTK("EXIT\n");
+}
+
+/**
+ * riva_wclut - set CLUT entry
+ * @chip: pointer to RIVA_HW_INST object
+ * @regnum: register number
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ *
+ * DESCRIPTION:
+ * Sets color register @regnum.
+ *
+ * CALLED FROM:
+ * riva_setcolreg()
+ */
+static void riva_wclut(RIVA_HW_INST *chip,
+		       unsigned char regnum, unsigned char red,
+		       unsigned char green, unsigned char blue)
+{
+	VGA_WR08(chip->PDIO, 0x3c8, regnum);
+	VGA_WR08(chip->PDIO, 0x3c9, red);
+	VGA_WR08(chip->PDIO, 0x3c9, green);
+	VGA_WR08(chip->PDIO, 0x3c9, blue);
+}
+
+/**
+ * riva_save_state - saves current chip state
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Saves current chip state to @regs.
+ *
+ * CALLED FROM:
+ * rivafb_init_one()
+ */
+/* from GGI */
+static void riva_save_state(struct rivafb_info *rinfo, struct riva_regs *regs)
+{
+	int i;
+
+	rinfo->riva.LockUnlock(&rinfo->riva, 0);
+
+	rinfo->riva.UnloadStateExt(&rinfo->riva, &regs->ext);
+
+	regs->misc_output = MISCin(rinfo);
+
+	for (i = 0; i < NUM_CRT_REGS; i++) {
+		regs->crtc[i] = CRTCin(rinfo, i);
 	}
 
-	rinfo->ctrl_base = ioremap (rinfo->ctrl_base_phys,
-				    rinfo->base0_region_size);
-	if (!rinfo->ctrl_base) {
-		printk (KERN_ERR PFX "cannot ioremap MMIO base\n");
-		goto err_out_free_base1;
+	for (i = 0; i < NUM_ATC_REGS; i++) {
+		regs->attr[i] = ATTRin(rinfo, i);
 	}
-	
-	rinfo->fb_base = ioremap (rinfo->fb_base_phys,
-				  rinfo->base1_region_size);
-	if (!rinfo->fb_base) {
-		printk (KERN_ERR PFX "cannot ioremap FB base\n");
-		goto err_out_iounmap_ctrl;
+
+	for (i = 0; i < NUM_GRC_REGS; i++) {
+		regs->gra[i] = GRAin(rinfo, i);
 	}
-	
-	rinfo->riva.EnableIRQ = 0;
-	rinfo->riva.IO = (inb (0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
-	rinfo->riva.PRAMDAC = (unsigned *) (rinfo->ctrl_base + 0x00680000);
-	rinfo->riva.PFB = (unsigned *) (rinfo->ctrl_base + 0x00100000);
-	rinfo->riva.PFIFO = (unsigned *) (rinfo->ctrl_base + 0x00002000);
-	rinfo->riva.PGRAPH = (unsigned *) (rinfo->ctrl_base + 0x00400000);
-	rinfo->riva.PEXTDEV = (unsigned *) (rinfo->ctrl_base + 0x00101000);
-	rinfo->riva.PTIMER = (unsigned *) (rinfo->ctrl_base + 0x00009000);
-	rinfo->riva.PMC = (unsigned *) (rinfo->ctrl_base + 0x00000000);
-	rinfo->riva.FIFO = (unsigned *) (rinfo->ctrl_base + 0x00800000);
 
-	switch (rinfo->riva.Architecture) {
-	case 3:
-		rinfo->riva.PRAMIN =
-		    (unsigned *) (rinfo->fb_base + 0x00C00000);
-		break;
-	case 4:
-	case 5:
-		rinfo->riva.PCRTC =
-		    (unsigned *) (rinfo->ctrl_base + 0x00600000);
-		rinfo->riva.PRAMIN =
-		    (unsigned *) (rinfo->ctrl_base + 0x00710000);
-		break;
+	for (i = 0; i < NUM_SEQ_REGS; i++) {
+		regs->seq[i] = SEQin(rinfo, i);
 	}
+}
 
-	RivaGetConfig (&rinfo->riva);
+/**
+ * riva_load_state - loads current chip state
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ * @regs: pointer to riva_regs object
+ *
+ * DESCRIPTION:
+ * Loads chip state from @regs.
+ *
+ * CALLED FROM:
+ * riva_load_video_mode()
+ * rivafb_init_one()
+ * rivafb_remove_one()
+ */
+/* from GGI */
+static void riva_load_state(struct rivafb_info *rinfo, struct riva_regs *regs)
+{
+	int i;
+	RIVA_HW_STATE *state = &regs->ext;
 
-	/* back to normal */
+	CRTCout(rinfo, 0x11, 0x00);
 
-	assert (rinfo->pd != NULL);
+	rinfo->riva.LockUnlock(&rinfo->riva, 0);
 
-	/* unlock io */
-	vga_io_wcrt (0x11, 0xFF);	/* vgaHWunlock() + riva unlock (0x7F) */
-	outb (rinfo->riva.LockUnlockIndex, rinfo->riva.LockUnlockIO);
-	outb (0x57, rinfo->riva.LockUnlockIO + 1);
-
-	memcpy (&rinfo->initial_state, &reg_template,
-		sizeof (reg_template));
-	riva_save_state (rinfo, &rinfo->initial_state);
+	rinfo->riva.LoadStateExt(&rinfo->riva, state);
 
-	rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
-	rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
+	MISCout(rinfo, regs->misc_output);
 
-	riva_set_fbinfo (rinfo);
+	for (i = 0; i < NUM_CRT_REGS; i++) {
+		switch (i) {
+		case 0x19:
+		case 0x20 ... 0x40:
+			break;
+		default:
+			CRTCout(rinfo, i, regs->crtc[i]);
+		}
+	}
 
-	fb_memset (rinfo->fb_base, 0, rinfo->ram_amount);
+	for (i = 0; i < NUM_ATC_REGS; i++) {
+		ATTRout(rinfo, i, regs->attr[i]);
+	}
 
-	riva_load_video_mode (rinfo, &rinfo->disp.var);
+	for (i = 0; i < NUM_GRC_REGS; i++) {
+		GRAout(rinfo, i, regs->gra[i]);
+	}
 
-	if (register_framebuffer ((struct fb_info *) rinfo) < 0) {
-		printk (KERN_ERR PFX
-			"error registering riva framebuffer\n");
-		goto err_out_iounmap_fb;
+	for (i = 0; i < NUM_SEQ_REGS; i++) {
+		SEQout(rinfo, i, regs->seq[i]);
 	}
+}
 
-	riva_boards = riva_board_list_add(riva_boards, rinfo);
+/**
+ * riva_load_video_mode - calculate timings
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ * @video_mode: video mode to set
+ *
+ * DESCRIPTION:
+ * Calculate some timings and then send em off to riva_load_state().
+ *
+ * CALLED FROM:
+ * rivafb_set_var()
+ */
+static void riva_load_video_mode(struct rivafb_info *rinfo,
+				 struct fb_var_screeninfo *video_mode)
+{
+	struct riva_regs newmode;
+	int bpp, width, hDisplaySize, hDisplay, hStart,
+	    hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
 
-	pci_set_drvdata (pd, rinfo);
+	/* time to calculate */
 
-	printk (KERN_INFO PFX
-		"PCI Riva NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
-		rinfo->riva.Architecture,
-		RIVAFB_VERSION,
-		rinfo->drvr_name,
-		rinfo->ram_amount / (1024 * 1024) + 1,
-		rinfo->fb_base_phys);
+	rivafb_blank(1, (struct fb_info *)rinfo);
 
-	return 0;
+	bpp = video_mode->bits_per_pixel;
+	if (bpp == 16 && video_mode->green.length == 5)
+		bpp = 15;
+	width = video_mode->xres_virtual;
+	hDisplaySize = video_mode->xres;
+	hDisplay = (hDisplaySize / 8) - 1;
+	hStart = (hDisplaySize + video_mode->right_margin) / 8 + 2;
+	hEnd = (hDisplaySize + video_mode->right_margin +
+		video_mode->hsync_len) / 8 - 1;
+	hTotal = (hDisplaySize + video_mode->right_margin +
+		  video_mode->hsync_len + video_mode->left_margin) / 8 - 1;
+	height = video_mode->yres_virtual;
+	vDisplay = video_mode->yres - 1;
+	vStart = video_mode->yres + video_mode->lower_margin - 1;
+	vEnd = video_mode->yres + video_mode->lower_margin +
+	       video_mode->vsync_len - 1;
+	vTotal = video_mode->yres + video_mode->lower_margin +
+		 video_mode->vsync_len + video_mode->upper_margin + 2;
+	dotClock = 1000000000 / video_mode->pixclock;
 
-err_out_iounmap_fb:
-	iounmap (rinfo->fb_base);
-err_out_iounmap_ctrl:
-	iounmap (rinfo->ctrl_base);
-err_out_free_base1:
-	release_mem_region (rinfo->fb_base_phys, rinfo->base1_region_size);
-err_out_free_base0:
-	release_mem_region (rinfo->ctrl_base_phys, rinfo->base0_region_size);
-err_out_kfree:
-	kfree (rinfo);
-err_out:
-	return -ENODEV;
+	memcpy(&newmode, &reg_template, sizeof(struct riva_regs));
+
+	newmode.crtc[0x0] = Set8Bits (hTotal - 4);
+	newmode.crtc[0x1] = Set8Bits (hDisplay);
+	newmode.crtc[0x2] = Set8Bits (hDisplay);
+	newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
+	newmode.crtc[0x4] = Set8Bits (hStart);
+	newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
+		| SetBitField (hEnd, 4: 0, 4:0);
+	newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
+	newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
+		| SetBitField (vDisplay, 8: 8, 1:1)
+		| SetBitField (vStart, 8: 8, 2:2)
+		| SetBitField (vDisplay, 8: 8, 3:3)
+		| SetBit (4)
+		| SetBitField (vTotal, 9: 9, 5:5)
+		| SetBitField (vDisplay, 9: 9, 6:6)
+		| SetBitField (vStart, 9: 9, 7:7);
+	newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
+		| SetBit (6);
+	newmode.crtc[0x10] = Set8Bits (vStart);
+	newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
+		| SetBit (5);
+	newmode.crtc[0x12] = Set8Bits (vDisplay);
+	newmode.crtc[0x13] = ((width / 8) * ((bpp + 1) / 8)) & 0xFF;
+	newmode.crtc[0x15] = Set8Bits (vDisplay);
+	newmode.crtc[0x16] = Set8Bits (vTotal + 1);
+
+	newmode.ext.bpp = bpp;
+	newmode.ext.width = width;
+	newmode.ext.height = height;
+
+	rinfo->riva.CalcStateExt(&rinfo->riva, &newmode.ext, bpp, width,
+				  hDisplaySize, hDisplay, hStart, hEnd,
+				  hTotal, height, vDisplay, vStart, vEnd,
+				  vTotal, dotClock);
+
+	rinfo->current_state = newmode;
+	riva_load_state(rinfo, &rinfo->current_state);
+
+	rinfo->riva.LockUnlock(&rinfo->riva, 0); /* important for HW cursor */
+	rivafb_download_cursor(rinfo);
 }
 
+/**
+ * riva_board_list_add - maintains board list
+ * @board_list: root node of list of boards
+ * @new_node: new node to be added
+ *
+ * DESCRIPTION:
+ * Adds @new_node to the list referenced by @board_list.
+ *
+ * RETURNS:
+ * New root node
+ *
+ * CALLED FROM:
+ * rivafb_init_one()
+ */
+static struct rivafb_info *riva_board_list_add(struct rivafb_info *board_list,
+					       struct rivafb_info *new_node)
+{
+	struct rivafb_info *i_p = board_list;
 
-static void __devexit rivafb_remove_one (struct pci_dev *pd)
+	new_node->next = NULL;
+
+	if (board_list == NULL)
+		return new_node;
+
+	while (i_p->next != NULL)
+		i_p = i_p->next;
+	i_p->next = new_node;
+
+	return board_list;
+}
+
+/**
+ * riva_board_list_del - maintains board list
+ * @board_list: root node of list of boards
+ * @del_node: node to be removed
+ *
+ * DESCRIPTION:
+ * Removes @del_node from the list referenced by @board_list.
+ *
+ * RETURNS:
+ * New root node
+ *
+ * CALLED FROM:
+ * rivafb_remove_one()
+ */
+static struct rivafb_info *riva_board_list_del(struct rivafb_info *board_list,
+					       struct rivafb_info *del_node)
 {
-	struct rivafb_info *board = pci_get_drvdata (pd);
-	
-	if (!board)
-		return;
-		
-	riva_boards = riva_board_list_del(riva_boards, board);
+	struct rivafb_info *i_p = board_list;
 
-	riva_load_state (board, &board->initial_state);
+	if (board_list == del_node)
+		return del_node->next;
 
-	unregister_framebuffer ((struct fb_info *) board);
+	while (i_p->next != del_node)
+		i_p = i_p->next;
+	i_p->next = del_node->next;
+
+	return board_list;
+}
 
-	iounmap (board->ctrl_base);
-	iounmap (board->fb_base);
+/**
+ * rivafb_do_maximize - 
+ * @rinfo: pointer to rivafb_info object containing info for current riva board
+ * @var:
+ * @v:
+ * @nom:
+ * @den:
+ *
+ * DESCRIPTION:
+ * .
+ *
+ * RETURNS:
+ * -EINVAL on failure, 0 on success
+ * 
+ *
+ * CALLED FROM:
+ * rivafb_set_var()
+ */
+static int rivafb_do_maximize(struct rivafb_info *rinfo,
+			      struct fb_var_screeninfo *var,
+			      struct fb_var_screeninfo *v,
+			      int nom, int den)
+{
+	static struct {
+		int xres, yres;
+	} modes[] = {
+		{1600, 1280},
+		{1280, 1024},
+		{1024, 768},
+		{800, 600},
+		{640, 480},
+		{-1, -1}
+	};
+	int i;
 
-	release_mem_region (board->ctrl_base_phys,
-			    board->base0_region_size);
-	release_mem_region (board->fb_base_phys,
-			    board->base1_region_size);
+	/* use highest possible virtual resolution */
+	if (v->xres_virtual == -1 && v->yres_virtual == -1) {
+		printk(KERN_WARNING PFX
+		       "using maximum available virtual resolution\n");
+		for (i = 0; modes[i].xres != -1; i++) {
+			if (modes[i].xres * nom / den * modes[i].yres <
+			    rinfo->ram_amount / 2)
+				break;
+		}
+		if (modes[i].xres == -1) {
+			printk(KERN_ERR PFX
+			       "could not find a virtual resolution that fits into video memory!!\n");
+			DPRINTK("EXIT - EINVAL error\n");
+			return -EINVAL;
+		}
+		v->xres_virtual = modes[i].xres;
+		v->yres_virtual = modes[i].yres;
 
-	kfree (board);
+		printk(KERN_INFO PFX
+		       "virtual resolution set to maximum of %dx%d\n",
+		       v->xres_virtual, v->yres_virtual);
+	} else if (v->xres_virtual == -1) {
+		v->xres_virtual = (rinfo->ram_amount * den /
+			(nom * v->yres_virtual * 2)) & ~15;
+		printk(KERN_WARNING PFX
+		       "setting virtual X resolution to %d\n", v->xres_virtual);
+	} else if (v->yres_virtual == -1) {
+		v->xres_virtual = (v->xres_virtual + 15) & ~15;
+		v->yres_virtual = rinfo->ram_amount * den /
+			(nom * v->xres_virtual * 2);
+		printk(KERN_WARNING PFX
+		       "setting virtual Y resolution to %d\n", v->yres_virtual);
+	} else {
+		v->xres_virtual = (v->xres_virtual + 15) & ~15;
+		if (v->xres_virtual * nom / den * v->yres_virtual > rinfo->ram_amount) {
+			printk(KERN_ERR PFX
+			       "mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+			       var->xres, var->yres, var->bits_per_pixel);
+			DPRINTK("EXIT - EINVAL error\n");
+			return -EINVAL;
+		}
+	}
+	
+	if (v->xres_virtual * nom / den >= 8192) {
+		printk(KERN_WARNING PFX
+		       "virtual X resolution (%d) is too high, lowering to %d\n",
+		       v->xres_virtual, 8192 * den / nom - 16);
+		v->xres_virtual = 8192 * den / nom - 16;
+	}
+	
+	if (v->xres_virtual < v->xres) {
+		printk(KERN_ERR PFX
+		       "virtual X resolution (%d) is smaller than real\n", v->xres_virtual);
+		return -EINVAL;
+	}
 
-	pci_set_drvdata (pd, NULL);
+	if (v->yres_virtual < v->yres) {
+		printk(KERN_ERR PFX
+		       "virtual Y resolution (%d) is smaller than real\n", v->yres_virtual);
+		return -EINVAL;
+	}
+	
+	return 0;
 }
 
 
-/*** riva_wclut - set CLUT entry ***/
-static void riva_wclut (unsigned char regnum, unsigned char red,
-			unsigned char green, unsigned char blue)
+
+/* ------------------------------------------------------------------------- *
+ *
+ * internal fb_ops helper functions
+ *
+ * ------------------------------------------------------------------------- */
+
+/**
+ * riva_get_cmap_len - query current color map length
+ * @var: standard kernel fb changeable data
+ *
+ * DESCRIPTION:
+ * Get current color map length.
+ *
+ * RETURNS:
+ * Length of color map
+ *
+ * CALLED FROM:
+ * riva_getcolreg()
+ * riva_setcolreg()
+ * rivafb_get_cmap()
+ * rivafb_set_cmap()
+ */
+static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
 {
-	unsigned int data = VGA_PEL_D;
+	int rc = 16;		/* reasonable default */
+
+	assert(var != NULL);
 
-	/* address write mode register is not translated.. */
-	vga_io_w (VGA_PEL_IW, regnum);
+	switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		rc = 256;	/* pseudocolor... 256 entries HW palette */
+		break;
+#endif
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		rc = 16;	/* directcolor... 16 entries SW palette */
+		break;		/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		rc = 16;	/* directcolor... 16 entries SW palette */
+		break;		/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
+#endif
+	default:
+		assert(0);
+		/* should not occur */
+		break;
+	}
 
-	vga_io_w (data, red);
-	vga_io_w (data, green);
-	vga_io_w (data, blue);
+	return rc;
 }
 
+/**
+ * riva_getcolreg
+ * @regno: register index
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ * @transp: transparency
+ * @info: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Read a single color register and split it into colors/transparent.
+ * The return values must have a 16 bit magnitude.
+ *
+ * RETURNS:
+ * Return != 0 for invalid regno.
+ *
+ * CALLED FROM:
+ * rivafb_get_cmap()
+ * rivafb_switch()
+ * fbcmap.c:fb_get_cmap()
+ *	fbgen.c:fbgen_get_cmap()
+ *	fbgen.c:fbgen_switch()
+ */
+static int riva_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			  unsigned *blue, unsigned *transp,
+			  struct fb_info *info)
+{
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 
+	if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
+		return 1;
 
-/* ------------ Hardware Independent Functions ------------ */
+	*red = rivainfo->palette[regno].red;
+	*green = rivainfo->palette[regno].green;
+	*blue = rivainfo->palette[regno].blue;
+	*transp = 0;
 
-#ifndef MODULE
-int __init rivafb_setup (char *options)
+	return 0;
+}
+
+/**
+ * riva_setcolreg
+ * @regno: register index
+ * @red: red component
+ * @green: green component
+ * @blue: blue component
+ * @transp: transparency
+ * @info: pointer to rivafb_info object containing info for current riva board
+ *
+ * DESCRIPTION:
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude.
+ *
+ * RETURNS:
+ * Return != 0 for invalid regno.
+ *
+ * CALLED FROM:
+ * rivafb_set_cmap()
+ * fbcmap.c:fb_set_cmap()
+ *	fbgen.c:fbgen_get_cmap()
+ *	fbgen.c:fbgen_install_cmap()
+ *		fbgen.c:fbgen_set_var()
+ *		fbgen.c:fbgen_switch()
+ *		fbgen.c:fbgen_blank()
+ *	fbgen.c:fbgen_blank()
+ */
+static int riva_setcolreg(unsigned regno, unsigned red, unsigned green,
+			  unsigned blue, unsigned transp,
+			  struct fb_info *info)
 {
-	char *this_opt;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
+	RIVA_HW_INST *chip = &rivainfo->riva;
+	struct display *p;
 
-	if (!options || !*options)
-		return 0;
+	DPRINTK("ENTER\n");
 
-	for (this_opt = strtok (options, ","); this_opt;
-	     this_opt = strtok (NULL, ",")) {
-		if (!strncmp (this_opt, "font:", 5)) {
-			char *p;
-			int i;
+	assert(rivainfo != NULL);
+	assert(rivainfo->currcon_display != NULL);
 
-			p = this_opt + 5;
-			for (i = 0; i < sizeof (fontname) - 1; i++)
-				if (!*p || *p == ' ' || *p == ',')
-					break;
-			memcpy (fontname, this_opt + 5, i);
-			fontname[i] = 0;
-		}
+	p = rivainfo->currcon_display;
+
+	if (regno >= riva_get_cmap_len(&p->var))
+		return -EINVAL;
+
+	rivainfo->palette[regno].red = red;
+	rivainfo->palette[regno].green = green;
+	rivainfo->palette[regno].blue = blue;
+
+	if (p->var.grayscale) {
+		/* gray = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue =
+		    (red * 77 + green * 151 + blue * 28) >> 8;
+	}
 
-		else if (!strncmp (this_opt, "noaccel", 7)) {
-			noaccel = 1;
+	switch (p->var.bits_per_pixel) {
+#ifdef FBCON_HAS_CFB8
+	case 8:
+		/* "transparent" stuff is completely ignored. */
+		riva_wclut(chip, regno, red >> 8, green >> 8, blue >> 8);
+		break;
+#endif /* FBCON_HAS_CFB8 */
+#ifdef FBCON_HAS_CFB16
+	case 16:
+		assert(regno < 16);
+		if (p->var.green.length == 5) {
+			/* 0rrrrrgg gggbbbbb */
+			rivainfo->con_cmap.cfb16[regno] =
+			    ((red & 0xf800) >> 1) |
+			    ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+		} else {
+			/* rrrrrggg gggbbbbb */
+			rivainfo->con_cmap.cfb16[regno] =
+			    ((red & 0xf800) >> 0) |
+			    ((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
 		}
-
-		else
-			mode_option = this_opt;
+		break;
+#endif /* FBCON_HAS_CFB16 */
+#ifdef FBCON_HAS_CFB32
+	case 32:
+		assert(regno < 16);
+		rivainfo->con_cmap.cfb32[regno] =
+		    ((red & 0xff00) << 8) |
+		    ((green & 0xff00)) | ((blue & 0xff00) >> 8);
+		break;
+#endif /* FBCON_HAS_CFB32 */
+	default:
+		/* do nothing */
+		break;
 	}
+
 	return 0;
 }
-#endif				/* !MODULE */
-
-    /*
-     *  Initialization
-     */
 
-/* ------------------------------------------------------------------------- */
 
 
-    /*
-     *  Frame buffer operations
-     */
+/* ------------------------------------------------------------------------- *
+ *
+ * framebuffer operations
+ *
+ * ------------------------------------------------------------------------- */
 
-static int rivafb_get_fix (struct fb_fix_screeninfo *fix, int con,
-		    struct fb_info *info)
+static int rivafb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			  struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 	struct display *p;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (fix != NULL);
-	assert (info != NULL);
-	assert (rivainfo->drvr_name && rivainfo->drvr_name[0]);
-	assert (rivainfo->fb_base_phys > 0);
-	assert (rivainfo->ram_amount > 0);
+	assert(fix != NULL);
+	assert(info != NULL);
+	assert(rivainfo->drvr_name && rivainfo->drvr_name[0]);
+	assert(rivainfo->fb_base_phys > 0);
+	assert(rivainfo->ram_amount > 0);
 
 	p = (con < 0) ? rivainfo->info.disp : &fb_display[con];
 
-	memset (fix, 0, sizeof (struct fb_fix_screeninfo));
-	sprintf (fix->id, "Riva %s", rivainfo->drvr_name);
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	sprintf(fix->id, "nVidia %s", rivainfo->drvr_name);
 
 	fix->smem_start = rivainfo->fb_base_phys;
 	fix->smem_len = rivainfo->ram_amount;
@@ -730,71 +1298,70 @@
 
 	fix->line_length = p->line_length;
 
-	/* FIXME: set up MMIO region, export via FB_ACCEL_xxx */
-	fix->mmio_start = 0;
-	fix->mmio_len = 0;
-	fix->accel = FB_ACCEL_NONE;
+	fix->mmio_start = rivainfo->ctrl_base_phys;
+	fix->mmio_len = rivainfo->base0_region_size;
+	fix->smem_start = rivainfo->fb_base_phys;
+	fix->smem_len = rivainfo->base1_region_size;
+
+	switch (rivainfo->riva.Architecture) {
+	case NV_ARCH_03:
+		fix->accel = FB_ACCEL_NV3;
+		break;
+	case NV_ARCH_04:	/* riva_hw.c now doesn't distinguish between TNT & TNT2 */
+		fix->accel = FB_ACCEL_NV4;
+		break;
+	case NV_ARCH_10:	/* FIXME: ID for GeForce */
+		fix->accel = FB_ACCEL_NV4;
+		break;
+
+	}
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 
 	return 0;
 }
 
-
-static int rivafb_get_var (struct fb_var_screeninfo *var, int con,
-		    struct fb_info *info)
+static int rivafb_get_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (info != NULL);
-	assert (var != NULL);
+	assert(info != NULL);
+	assert(var != NULL);
 
 	*var = (con < 0) ? rivainfo->disp.var : fb_display[con].var;
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 
 	return 0;
 }
 
-
-
-static int rivafb_set_var (struct fb_var_screeninfo *var, int con,
-		    struct fb_info *info)
+static int rivafb_set_var(struct fb_var_screeninfo *var, int con,
+			  struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 	struct display *dsp;
 	struct fb_var_screeninfo v;
 	int nom, den;		/* translating from pixels->bytes */
-	int i;
+	int accel;
 	unsigned chgvar = 0;
-	static struct {
-		int xres, yres;
-	} modes[] = {
-		{
-		1600, 1280}, {
-		1280, 1024}, {
-		1024, 768}, {
-		800, 600}, {
-		640, 480}, {
-		-1, -1}
-	};
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (info != NULL);
-	assert (var != NULL);
+	assert(info != NULL);
+	assert(var != NULL);
 
-	DPRINTK ("Requested: %dx%dx%d\n", var->xres, var->yres,
-		 var->bits_per_pixel);
-	DPRINTK ("  virtual: %dx%d\n", var->xres_virtual,
-		 var->yres_virtual);
-	DPRINTK ("   offset: (%d,%d)\n", var->xoffset, var->yoffset);
-	DPRINTK ("grayscale: %d\n", var->grayscale);
+	DPRINTK("Requested: %dx%dx%d\n", var->xres, var->yres,
+		var->bits_per_pixel);
+	DPRINTK("  virtual: %dx%d\n", var->xres_virtual,
+		var->yres_virtual);
+	DPRINTK("   offset: (%d,%d)\n", var->xoffset, var->yoffset);
+	DPRINTK("grayscale: %d\n", var->grayscale);
 
 	dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
-	assert (dsp != NULL);
+	assert(dsp != NULL);
 
 	/* if var has changed, we should call changevar() later */
 	if (con >= 0) {
@@ -802,135 +1369,84 @@
 			  (dsp->var.yres != var->yres) ||
 			  (dsp->var.xres_virtual != var->xres_virtual) ||
 			  (dsp->var.yres_virtual != var->yres_virtual) ||
+			  (dsp->var.accel_flags != var->accel_flags) ||
 			  (dsp->var.bits_per_pixel != var->bits_per_pixel)
-			  || memcmp (&dsp->var.red, &var->red,
-				     sizeof (var->red))
-			  || memcmp (&dsp->var.green, &var->green,
-				     sizeof (var->green))
-			  || memcmp (&dsp->var.blue, &var->blue,
-				     sizeof (var->blue)));
+			  || memcmp(&dsp->var.red, &var->red,
+				    sizeof(var->red))
+			  || memcmp(&dsp->var.green, &var->green,
+				    sizeof(var->green))
+			  || memcmp(&dsp->var.blue, &var->blue,
+				    sizeof(var->blue)));
 	}
 
-	memcpy (&v, var, sizeof (v));
+	memcpy(&v, var, sizeof(v));
 
-	switch (v.bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
-	case 1:
-		dsp->dispsw = &fbcon_mfb;
-		dsp->line_length = v.xres_virtual / 8;
-		dsp->visual = FB_VISUAL_MONO10;
-		nom = 4;
-		den = 8;
-		break;
-#endif
+	accel = v.accel_flags & FB_ACCELF_TEXT;
 
+	switch (v.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
-	case 2 ... 8:
+	case 1 ... 8:
 		v.bits_per_pixel = 8;
-		dsp->dispsw = &fbcon_cfb8;
 		nom = 1;
 		den = 1;
-		dsp->line_length = v.xres_virtual;
-		dsp->visual = FB_VISUAL_PSEUDOCOLOR;
 		v.red.offset = 0;
-		v.red.length = 6;
+		v.red.length = 8;
 		v.green.offset = 0;
-		v.green.length = 6;
+		v.green.length = 8;
 		v.blue.offset = 0;
-		v.blue.length = 6;
+		v.blue.length = 8;
 		break;
 #endif
-
 #ifdef FBCON_HAS_CFB16
-	case 9 ... 16:
+	case 9 ... 15:
+		v.green.length = 5;
+		/* fall through */
+	case 16:
 		v.bits_per_pixel = 16;
-		dsp->dispsw = &fbcon_cfb16;
-		dsp->dispsw_data = &rivainfo->con_cmap.cfb16;
 		nom = 2;
 		den = 1;
-		dsp->line_length = v.xres_virtual * 2;
-		dsp->visual = FB_VISUAL_DIRECTCOLOR;
-#ifdef CONFIG_PREP
-		v.red.offset = 2;
-		v.green.offset = -3;
-		v.blue.offset = 8;
-#else
-		v.red.offset = 10;
-		v.green.offset = 5;
-		v.blue.offset = 0;
-#endif
-		v.red.length = 5;
-		v.green.length = 5;
-		v.blue.length = 5;
+		if (v.green.length == 5) {
+			/* 0rrrrrgg gggbbbbb */
+			v.red.offset = 10;
+			v.green.offset = 5;
+			v.blue.offset = 0;
+			v.red.length = 5;
+			v.green.length = 5;
+			v.blue.length = 5;
+		} else {
+			/* rrrrrggg gggbbbbb */
+			v.red.offset = 11;
+			v.green.offset = 5;
+			v.blue.offset = 0;
+			v.red.length = 5;
+			v.green.length = 6;
+			v.blue.length = 5;
+		}
 		break;
 #endif
-
 #ifdef FBCON_HAS_CFB32
 	case 17 ... 32:
 		v.bits_per_pixel = 32;
-		dsp->dispsw = &fbcon_cfb32;
-		dsp->dispsw_data = rivainfo->con_cmap.cfb32;
 		nom = 4;
 		den = 1;
-		dsp->line_length = v.xres_virtual * 4;
-		dsp->visual = FB_VISUAL_DIRECTCOLOR;
-#ifdef CONFIG_PREP
-		v.red.offset = 8;
-		v.green.offset = 16;
-		v.blue.offset = 24;
-#else
 		v.red.offset = 16;
 		v.green.offset = 8;
 		v.blue.offset = 0;
-#endif
 		v.red.length = 8;
 		v.green.length = 8;
 		v.blue.length = 8;
 		break;
 #endif
-
 	default:
-		printk (KERN_ERR PFX
-			"mode %dx%dx%d rejected...color depth not supported.\n",
-			var->xres, var->yres, var->bits_per_pixel);
-		DPRINTK ("EXIT, returning -EINVAL\n");
+		printk(KERN_ERR PFX
+		       "mode %dx%dx%d rejected...color depth not supported.\n",
+		       var->xres, var->yres, var->bits_per_pixel);
+		DPRINTK("EXIT, returning -EINVAL\n");
 		return -EINVAL;
 	}
 
-	if (v.xres * nom / den * v.yres > rivainfo->ram_amount) {
-		printk (KERN_ERR PFX
-			"mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
-			var->xres, var->yres, var->bits_per_pixel);
-		DPRINTK ("EXIT - EINVAL error\n");
+	if (rivafb_do_maximize(rivainfo, var, &v, nom, den) < 0)
 		return -EINVAL;
-	}
-
-	/* use highest possible virtual resolution */
-	if (v.xres_virtual == -1 && v.yres_virtual == -1) {
-		printk (KERN_WARNING PFX
-			"using maximum available virtual resolution\n");
-		for (i = 0; modes[i].xres != -1; i++) {
-			if (modes[i].xres * nom / den * modes[i].yres <
-			    rivainfo->ram_amount / 2)
-				break;
-		}
-		if (modes[i].xres == -1) {
-			printk (KERN_ERR PFX
-				"could not find a virtual resolution that fits into video memory!!\n");
-			DPRINTK ("EXIT - EINVAL error\n");
-			return -EINVAL;
-		}
-		v.xres_virtual = modes[i].xres;
-		v.yres_virtual = modes[i].yres;
-
-		printk (KERN_INFO PFX
-			"virtual resolution set to maximum of %dx%d\n",
-			v.xres_virtual, v.yres_virtual);
-	} else if (v.xres_virtual == -1) {
-		/* FIXME: maximize X virtual resolution only */
-	} else if (v.yres_virtual == -1) {
-		/* FIXME: maximize Y virtual resolution only */
-	}
 
 	if (v.xoffset < 0)
 		v.xoffset = 0;
@@ -951,103 +1467,107 @@
 
 	switch (v.activate & FB_ACTIVATE_MASK) {
 	case FB_ACTIVATE_TEST:
-		DPRINTK ("EXIT - FB_ACTIVATE_TEST\n");
+		DPRINTK("EXIT - FB_ACTIVATE_TEST\n");
 		return 0;
 	case FB_ACTIVATE_NXTOPEN:	/* ?? */
 	case FB_ACTIVATE_NOW:
 		break;		/* continue */
 	default:
-		DPRINTK ("EXIT - unknown activation type\n");
+		DPRINTK("EXIT - unknown activation type\n");
 		return -EINVAL;	/* unknown */
 	}
 
-	dsp->type = FB_TYPE_PACKED_PIXELS;
-
-	/* FIXME: verify that the above code sets dsp->* fields correctly */
-
-	memcpy (&dsp->var, &v, sizeof (v));
+	memcpy(&dsp->var, &v, sizeof(v));
+	if (chgvar) {
+		riva_set_dispsw(rivainfo, dsp);
+
+		if (accel) {
+			if (nomove)
+				dsp->scrollmode = SCROLL_YNOMOVE;
+			else
+				dsp->scrollmode = 0;
+		} else
+			dsp->scrollmode = SCROLL_YREDRAW;
+
+		if (info && info->changevar)
+			info->changevar(con);
+	}
+
+	rivafb_create_cursor(rivainfo, fontwidth(dsp), fontheight(dsp));
+	riva_load_video_mode(rivainfo, &v);
+	if (accel) riva_setup_accel(rivainfo);
 
-	riva_load_video_mode (rivainfo, &v);
-
-	if (chgvar && info && info->changevar)
-		info->changevar (con);
-
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 	return 0;
 }
 
-
-
-static int rivafb_get_cmap (struct fb_cmap *cmap, int kspc, int con,
-		     struct fb_info *info)
+static int rivafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 	struct display *dsp;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (rivainfo != NULL);
-	assert (cmap != NULL);
+	assert(rivainfo != NULL);
+	assert(cmap != NULL);
 
 	dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
 
 	if (con == rivainfo->currcon) {	/* current console? */
-		int rc = fb_get_cmap (cmap, kspc, riva_getcolreg, info);
-		DPRINTK ("EXIT - returning %d\n", rc);
+		int rc = fb_get_cmap(cmap, kspc, riva_getcolreg, info);
+		DPRINTK("EXIT - returning %d\n", rc);
 		return rc;
 	} else if (dsp->cmap.len)	/* non default colormap? */
-		fb_copy_cmap (&dsp->cmap, cmap, kspc ? 0 : 2);
+		fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2);
 	else
-		fb_copy_cmap (fb_default_cmap
-			      (riva_get_cmap_len (&dsp->var)), cmap,
-			      kspc ? 0 : 2);
+		fb_copy_cmap(fb_default_cmap
+			     (riva_get_cmap_len(&dsp->var)), cmap,
+			     kspc ? 0 : 2);
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 
 	return 0;
 }
 
-
-static int rivafb_set_cmap (struct fb_cmap *cmap, int kspc, int con,
-		     struct fb_info *info)
+static int rivafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			   struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 	struct display *dsp;
 	unsigned int cmap_len;
 
-	DPRINTK ("ENTER\n");
-
-	assert (rivainfo != NULL);
-	assert (cmap != NULL);
+	DPRINTK("ENTER\n");
+	
+	assert(rivainfo != NULL);
+	assert(cmap != NULL);
 
 	dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
 
-	cmap_len = riva_get_cmap_len (&dsp->var);
+	cmap_len = riva_get_cmap_len(&dsp->var);
 	if (dsp->cmap.len != cmap_len) {
-		int err = fb_alloc_cmap (&dsp->cmap, cmap_len, 0);
+		int err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0);
 		if (err) {
-			DPRINTK ("EXIT - returning %d\n", err);
+			DPRINTK("EXIT - returning %d\n", err);
 			return err;
 		}
 	}
 	if (con == rivainfo->currcon) {	/* current console? */
-		int rc = fb_set_cmap (cmap, kspc, riva_setcolreg, info);
-		DPRINTK ("EXIT - returning %d\n", rc);
+		int rc = fb_set_cmap(cmap, kspc, riva_setcolreg, info);
+		DPRINTK("EXIT - returning %d\n", rc);
 		return rc;
 	} else
-		fb_copy_cmap (cmap, &dsp->cmap, kspc ? 0 : 1);
+		fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 
 	return 0;
 }
 
-
-
 /**
  * rivafb_pan_display
  * @var: standard kernel fb changeable data
- * @con:
+ * @con: TODO
  * @info: pointer to rivafb_info object containing info for current riva board
  *
  * DESCRIPTION:
@@ -1057,17 +1577,16 @@
  *
  * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
  */
-
-static int rivafb_pan_display (struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
+static int rivafb_pan_display(struct fb_var_screeninfo *var, int con,
+			      struct fb_info *info)
 {
 	unsigned int base;
 	struct display *dsp;
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (rivainfo != NULL);
+	assert(rivainfo != NULL);
 
 	if (var->xoffset > (var->xres_virtual - var->xres))
 		return -EINVAL;
@@ -1089,7 +1608,7 @@
 	base = var->yoffset * dsp->line_length + var->xoffset;
 
 	if (con == rivainfo->currcon) {
-		rivainfo->riva.SetStartAddress (&rivainfo->riva, base);
+		rivainfo->riva.SetStartAddress(&rivainfo->riva, base);
 	}
 
 	dsp->var.xoffset = var->xoffset;
@@ -1100,606 +1619,512 @@
 	else
 		dsp->var.vmode &= ~FB_VMODE_YWRAP;
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 
 	return 0;
 }
 
-
-static int rivafb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-		  unsigned long arg, int con, struct fb_info *info)
+static int rivafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+			unsigned long arg, int con, struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	assert (rivainfo != NULL);
+	assert(rivainfo != NULL);
 
 	/* no rivafb-specific ioctls */
 
-	DPRINTK ("EXIT, returning -EINVAL\n");
+	DPRINTK("EXIT, returning -EINVAL\n");
 
 	return -EINVAL;
 }
 
+static int rivafb_rasterimg(struct fb_info *info, int start)
+{
+	struct rivafb_info *rinfo = (struct rivafb_info *)info;
+
+	wait_for_idle(rinfo);
+
+	return 0;
+}
 
-static int rivafb_switch (int con, struct fb_info *info)
+static int rivafb_switch(int con, struct fb_info *info)
 {
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
+	struct rivafb_info *rivainfo = (struct rivafb_info *)info;
 	struct fb_cmap *cmap;
 	struct display *dsp;
-
-	DPRINTK ("ENTER\n");
-
-	assert (rivainfo != NULL);
+	
+	DPRINTK("ENTER\n");
+	
+	assert(rivainfo != NULL);
 
 	dsp = (con < 0) ? rivainfo->info.disp : &fb_display[con];
 
 	if (rivainfo->currcon >= 0) {
 		/* Do we have to save the colormap? */
 		cmap = &(rivainfo->currcon_display->cmap);
-		DPRINTK ("switch1: con = %d, cmap.len = %d\n",
+		DPRINTK("switch1: con = %d, cmap.len = %d\n",
 			 rivainfo->currcon, cmap->len);
 
 		if (cmap->len) {
-			DPRINTK ("switch1a: %p %p %p %p\n", cmap->red,
+			DPRINTK("switch1a: %p %p %p %p\n", cmap->red,
 				 cmap->green, cmap->blue, cmap->transp);
-			fb_get_cmap (cmap, 1, riva_getcolreg, info);
-#ifdef DEBUG
-			if (cmap->red) {
-				DPRINTK ("switch1r: %X\n", cmap->red[0]);
-			}
-#endif
+			fb_get_cmap(cmap, 1, riva_getcolreg, info);
 		}
 	}
 	rivainfo->currcon = con;
 	rivainfo->currcon_display = dsp;
-	dsp->var.activate = FB_ACTIVATE_NOW;
-
-#ifdef riva_DEBUG
-	cmap = &dsp->cmap;
-	DPRINTK ("switch2: con = %d, cmap.len = %d\n", con, cmap->len);
-	DPRINTK ("switch2a: %p %p %p %p\n", cmap->red, cmap->green,
-		 cmap->blue, cmap->transp);
-	if (dsp->cmap.red) {
-		DPRINTK ("switch2r: %X\n", cmap->red[0]);
-	}
-#endif
 
-	rivafb_set_var (&dsp->var, con, info);
-
-#ifdef riva_DEBUG
-	DPRINTK ("switch3: con = %d, cmap.len = %d\n", con, cmap->len);
-	DPRINTK ("switch3a: %p %p %p %p\n", cmap->red, cmap->green,
-		 cmap->blue, cmap->transp);
-	if (dsp->cmap.red) {
-		DPRINTK ("switch3r: %X\n", cmap->red[0]);
-	}
-#endif
+	rivafb_set_var(&dsp->var, con, info);
+	riva_set_dispsw(rivainfo, dsp);
 
-	DPRINTK ("EXIT, returning 0\n");
+	DPRINTK("EXIT, returning 0\n");
 	return 0;
 }
 
-static int rivafb_updatevar (int con, struct fb_info *info)
+static int rivafb_updatevar(int con, struct fb_info *info)
 {
 	int rc;
 
-	DPRINTK ("ENTER\n");
+	DPRINTK("ENTER\n");
 
-	rc = (con <
-		0) ? -EINVAL : rivafb_pan_display (&fb_display[con].var,
-						   con, info);
-	DPRINTK ("EXIT, returning %d\n", rc);
+	rc = (con < 0) ? -EINVAL : rivafb_pan_display(&fb_display[con].var,
+						      con, info);
+	DPRINTK("EXIT, returning %d\n", rc);
 	return rc;
 }
 
-
-static void rivafb_blank (int blank, struct fb_info *info)
+static void rivafb_blank(int blank, struct fb_info *info)
 {
-	unsigned char tmp;
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
-
-	DPRINTK ("ENTER\n");
-
-	assert (rivainfo != NULL);
-
-	tmp = vga_io_rseq (VGA_SEQ_CLOCK_MODE) & ~VGA_SR01_SCREEN_OFF;
-
-	if (blank)
-		tmp |= VGA_SR01_SCREEN_OFF;
-
-	vga_io_wseq (VGA_SEQ_CLOCK_MODE, tmp);
-
-	DPRINTK ("EXIT\n");
-}
-
-
-/* -------------------------------------------------------------------------
- *
- * internal fb_ops helper functions
- *
- * -------------------------------------------------------------------------
- */
-
-
-/**
- * riva_get_cmap_len
- * @var:
- *
- * DESCRIPTION:
- */
+	unsigned char tmp, vesa;
+	struct rivafb_info *rinfo = (struct rivafb_info *)info;
 
-static int riva_get_cmap_len (const struct fb_var_screeninfo *var)
-{
-	int rc = 16;		/* reasonable default */
+	DPRINTK("ENTER\n");
 
-	assert (var != NULL);
+	assert(rinfo != NULL);
 
-	switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
-	case 4:
-		rc = 16;	/* pseudocolor... 16 entries HW palette */
-		break;
-#endif
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		rc = 256;	/* pseudocolor... 256 entries HW palette */
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		rc = 16;	/* directcolor... 16 entries SW palette */
-		break;		/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		rc = 16;	/* directcolor... 16 entries SW palette */
-		break;		/* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
-#endif
-	default:
-		assert (0);
-		/* should not occur */
-		break;
+	tmp = SEQin(rinfo, 0x01) & ~0x20;	/* screen on/off */
+	vesa = CRTCin(rinfo, 0x1a) & ~0xc0;	/* sync on/off */
+
+	if (blank) {
+		tmp |= 0x20;
+		switch (blank - 1) {
+		case VESA_NO_BLANKING:
+			break;
+		case VESA_VSYNC_SUSPEND:
+			vesa |= 0x80;
+			break;
+		case VESA_HSYNC_SUSPEND:
+			vesa |= 0x40;
+			break;
+		case VESA_POWERDOWN:
+			vesa |= 0xc0;
+			break;
+		}
 	}
 
-	return rc;
-}
-
-
-/**
- * riva_getcolreg
- * @regno:
- * @red:
- * @green:
- * @blue:
- * @transp:
- * @info: pointer to rivafb_info object containing info for current riva board
- *
- * DESCRIPTION:
- * Read a single color register and split it into colors/transparent.
- * The return values must have a 16 bit magnitude.
- * Return != 0 for invalid regno.
- *
- * CALLED FROM:
- * fbcmap.c:fb_get_cmap()
- *	fbgen.c:fbgen_get_cmap()
- *	fbgen.c:fbgen_switch()
- */
-
-static int riva_getcolreg (unsigned regno, unsigned *red, unsigned *green,
-			   unsigned *blue, unsigned *transp,
-			   struct fb_info *info)
-{
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
-
-	if (regno >= riva_get_cmap_len(&rivainfo->currcon_display->var))
-		return 1;
-
-	*red = rivainfo->palette[regno].red;
-	*green = rivainfo->palette[regno].green;
-	*blue = rivainfo->palette[regno].blue;
-	*transp = 0;
+	SEQout(rinfo, 0x01, tmp);
+	CRTCout(rinfo, 0x1a, vesa);
 
-	return 0;
+	DPRINTK("EXIT\n");
 }
 
 
-/**
- * riva_setcolreg
- * @regno:
- * @red:
- * @green:
- * @blue:
- * @transp:
- * @info: pointer to rivafb_info object containing info for current riva board
+
+/* ------------------------------------------------------------------------- *
  *
- * DESCRIPTION:
- * Set a single color register. The values supplied have a 16 bit
- * magnitude.
- * Return != 0 for invalid regno.
+ * initialization helper functions
  *
- * CALLED FROM:
- * fbcmap.c:fb_set_cmap()
- *	fbgen.c:fbgen_get_cmap()
- *	fbgen.c:fbgen_install_cmap()
- *		fbgen.c:fbgen_set_var()
- *		fbgen.c:fbgen_switch()
- *		fbgen.c:fbgen_blank()
- *	fbgen.c:fbgen_blank()
- */
-
-static int riva_setcolreg (unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   struct fb_info *info)
-{
-	struct rivafb_info *rivainfo = (struct rivafb_info *) info;
-	struct display *p;
-	unsigned shift = 8;
-
-	DPRINTK ("ENTER\n");
-
-	assert (rivainfo != NULL);
-	assert (rivainfo->currcon_display != NULL);
-
-	p = rivainfo->currcon_display;
-
-	if (regno >= riva_get_cmap_len(&p->var))
-		return -EINVAL;
-
-	rivainfo->palette[regno].red = red;
-	rivainfo->palette[regno].green = green;
-	rivainfo->palette[regno].blue = blue;
-
-	if (p->var.grayscale) {
-		/* gray = 0.30*R + 0.59*G + 0.11*B */
-		red = green = blue =
-		    (red * 77 + green * 151 + blue * 28) >> 8;
-	}
-
-	switch (rivainfo->riva.Architecture) {
-	case 3:
-		shift = 10;
-		break;
-	case 4:
-	case 5:
-		shift = 8;
-		break;
-	}
-
-	switch (p->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		/* "transparent" stuff is completely ignored. */
-		riva_wclut (regno, red >> shift, green >> shift, blue >> shift);
-		break;
-#endif				/* FBCON_HAS_CFB8 */
-
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		assert (regno < 16);
-#ifdef CONFIG_PREP
-		rivainfo->con_cmap.cfb16[regno] =
-		    ((red & 0xf800) >> 9) |
-		    ((green & 0xf800) >> 14) |
-		    ((green & 0xf800) << 2) | ((blue & 0xf800) >> 3);
-#else
-		rivainfo->con_cmap.cfb16[regno] =
-		    ((red & 0xf800) >> 1) |
-		    ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
-#endif
-		break;
-#endif				/* FBCON_HAS_CFB16 */
-
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		assert (regno < 16);
-#ifdef CONFIG_PREP
-		rivainfo->con_cmap.cfb32[regno] =
-		    ((red & 0xff00)) |
-		    ((green & 0xff00) << 8) | ((blue & 0xff00) << 16);
-#else
-		rivainfo->con_cmap.cfb32[regno] =
-		    ((red & 0xff00) << 8) |
-		    ((green & 0xff00)) | ((blue & 0xff00) >> 8);
-#endif
-		break;
-#endif				/* FBCON_HAS_CFB32 */
+ * ------------------------------------------------------------------------- */
 
-	default:
-		/* do nothing */
-		break;
-	}
+/* kernel interface */
+static struct fb_ops riva_fb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	rivafb_get_fix,
+	fb_get_var:	rivafb_get_var,
+	fb_set_var:	rivafb_set_var,
+	fb_get_cmap:	rivafb_get_cmap,
+	fb_set_cmap:	rivafb_set_cmap,
+	fb_pan_display:	rivafb_pan_display,
+	fb_ioctl:	rivafb_ioctl,
+	fb_rasterimg:	rivafb_rasterimg,
+};
 
+static int __devinit riva_init_disp_var(struct rivafb_info *rinfo)
+{
+#ifndef MODULE
+	if (mode_option)
+		fb_find_mode(&rinfo->disp.var, &rinfo->info, mode_option,
+			     NULL, 0, NULL, 8);
+#endif
 	return 0;
 }
 
+static int __devinit riva_init_disp(struct rivafb_info *rinfo)
+{
+	struct fb_info *info;
+	struct display *disp;
 
+	DPRINTK("ENTER\n");
 
-/*
- * riva_load_video_mode()
- *
- * calculate some timings and then send em off to riva_load_state()
- */
+	assert(rinfo != NULL);
 
-static void riva_load_video_mode (struct rivafb_info *rinfo,
-				  struct fb_var_screeninfo *video_mode)
-{
-	struct riva_regs newmode;
-	int bpp, width, hDisplaySize, hDisplay, hStart,
-	    hEnd, hTotal, height, vDisplay, vStart, vEnd, vTotal, dotClock;
+	info = &rinfo->info;
+	disp = &rinfo->disp;
 
-	/* time to calculate */
+	disp->var = rivafb_default_var;
+	
+	if (noaccel)
+		disp->var.accel_flags &= ~FB_ACCELF_TEXT;
+	else
+		disp->var.accel_flags |= FB_ACCELF_TEXT;
+	
+	info->disp = disp;
 
-	bpp = video_mode->bits_per_pixel;
-	width = hDisplaySize = video_mode->xres;
-	hDisplay = (hDisplaySize / 8) - 1;
-	hStart = (hDisplaySize + video_mode->right_margin) / 8 + 2;
-	hEnd = (hDisplaySize + video_mode->right_margin +
-		video_mode->hsync_len) / 8 - 1;
-	hTotal = (hDisplaySize + video_mode->right_margin +
-		  video_mode->hsync_len + video_mode->left_margin) / 8 - 1;
-	height = video_mode->yres;
-	vDisplay = video_mode->yres - 1;
-	vStart = video_mode->yres + video_mode->lower_margin - 1;
-	vEnd = video_mode->yres + video_mode->lower_margin +
-	    video_mode->vsync_len - 1;
-	vTotal = video_mode->yres + video_mode->lower_margin +
-	    video_mode->vsync_len + video_mode->upper_margin + 2;
-	dotClock = 1000000000 / video_mode->pixclock;
+	/* FIXME: assure that disp->cmap is completely filled out */
 
-	memcpy (&newmode, &reg_template, sizeof (struct riva_regs));
+	rinfo->currcon_display = disp;
 
-	newmode.crtc[0x0] = Set8Bits (hTotal - 4);
-	newmode.crtc[0x1] = Set8Bits (hDisplay);
-	newmode.crtc[0x2] = Set8Bits (hDisplay);
-	newmode.crtc[0x3] = SetBitField (hTotal, 4: 0, 4:0) | SetBit (7);
-	newmode.crtc[0x4] = Set8Bits (hStart);
-	newmode.crtc[0x5] = SetBitField (hTotal, 5: 5, 7:7)
-		| SetBitField (hEnd, 4: 0, 4:0);
-	newmode.crtc[0x6] = SetBitField (vTotal, 7: 0, 7:0);
-	newmode.crtc[0x7] = SetBitField (vTotal, 8: 8, 0:0)
-		| SetBitField (vDisplay, 8: 8, 1:1)
-		| SetBitField (vStart, 8: 8, 2:2)
-		| SetBitField (vDisplay, 8: 8, 3:3)
-		| SetBit (4)
-		| SetBitField (vTotal, 9: 9, 5:5)
-		| SetBitField (vDisplay, 9: 9, 6:6)
-		| SetBitField (vStart, 9: 9, 7:7);
-	newmode.crtc[0x9] = SetBitField (vDisplay, 9: 9, 5:5)
-		| SetBit (6);
-	newmode.crtc[0x10] = Set8Bits (vStart);
-	newmode.crtc[0x11] = SetBitField (vEnd, 3: 0, 3:0)
-		| SetBit (5);
-	newmode.crtc[0x12] = Set8Bits (vDisplay);
-	newmode.crtc[0x13] = ((width / 8) * (bpp / 8)) & 0xFF;
-	newmode.crtc[0x15] = Set8Bits (vDisplay);
-	newmode.crtc[0x16] = Set8Bits (vTotal + 1);
+	if ((riva_init_disp_var(rinfo)) < 0) {
+		DPRINTK("EXIT, returning -1\n");
+		return -1;
+	}
 
-	newmode.ext.bpp = bpp;
-	newmode.ext.width = width;
-	newmode.ext.height = height;
+	riva_set_dispsw(rinfo, disp);
 
-	rinfo->riva.CalcStateExt (&rinfo->riva, &newmode.ext, bpp, width,
-				  hDisplaySize, hDisplay, hStart, hEnd,
-				  hTotal, height, vDisplay, vStart, vEnd,
-				  vTotal, dotClock);
+	DPRINTK("EXIT, returning 0\n");
+	return 0;
 
-	rinfo->initial_state = newmode;
-	riva_load_state (rinfo, &newmode);
 }
 
+static int __devinit riva_set_fbinfo(struct rivafb_info *rinfo)
+{
+	struct fb_info *info;
 
-/* ------------------------------------------------------------------------- */
+	assert(rinfo != NULL);
 
+	info = &rinfo->info;
 
-    /*
-     *  Modularization
-     */
+	strcpy(info->modename, rinfo->drvr_name);
+	info->node = -1;
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->fbops = &riva_fb_ops;
 
-static struct pci_driver rivafb_driver = {
-	name:		"rivafb",
-	id_table:	rivafb_pci_tbl,
-	probe:		rivafb_init_one,
-	remove:		rivafb_remove_one,
-};
+	/* FIXME: set monspecs to what??? */
 
+	info->display_fg = NULL;
+	strncpy(info->fontname, fontname, sizeof(info->fontname));
+	info->fontname[sizeof(info->fontname) - 1] = 0;
 
-int __init rivafb_init (void)
-{
-	return pci_module_init (&rivafb_driver);
-}
+	info->changevar = NULL;
+	info->switch_con = rivafb_switch;
+	info->updatevar = rivafb_updatevar;
+	info->blank = rivafb_blank;
 
+	if (riva_init_disp(rinfo) < 0)	/* must be done last */
+		return -1;
 
-static void __exit rivafb_exit (void)
-{
-	pci_unregister_driver (&rivafb_driver);
+	return 0;
 }
 
 
-#ifdef MODULE
-module_init(rivafb_init);
-#endif				/* MODULE */
-module_exit(rivafb_exit);
-
-MODULE_AUTHOR("Ani Joshi, maintainer");
-MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2");
 
+/* ------------------------------------------------------------------------- *
+ *
+ * PCI bus
+ *
+ * ------------------------------------------------------------------------- */
 
-/* from GGI */
-static void riva_save_state (struct rivafb_info *rinfo, struct riva_regs *regs)
+static int __devinit rivafb_init_one(struct pci_dev *pd,
+				     const struct pci_device_id *ent)
 {
-	int i;
+	struct rivafb_info *rinfo;
+	struct riva_chip_info *rci = &riva_chip_info[ent->driver_data];
 
-	outb (rinfo->riva.LockUnlockIndex, rinfo->riva.LockUnlockIO);
-	outb (0x57, rinfo->riva.LockUnlockIO + 1);
+	assert(pd != NULL);
+	assert(rci != NULL);
 
-	rinfo->riva.UnloadStateExt (&rinfo->riva, &regs->ext);
+	rinfo = kmalloc(sizeof(struct rivafb_info), GFP_KERNEL);
+	if (!rinfo)
+		goto err_out;
 
-	regs->misc_output = io_in8 (0x3CC);
+	memset(rinfo, 0, sizeof(struct rivafb_info));
 
-	for (i = 0; i < NUM_CRT_REGS; i++) {
-		io_out8 (i, 0x3D4);
-		regs->crtc[i] = io_in8 (0x3D5);
-	}
+	rinfo->drvr_name = rci->name;
+	rinfo->riva.Architecture = rci->arch_rev;
 
-	for (i = 0; i < NUM_ATC_REGS; i++) {
-		io_out8 (i, 0x3C0);
-		regs->attr[i] = io_in8 (0x3C1);
+	rinfo->pd = pd;
+	rinfo->base0_region_size = pci_resource_len(pd, 0);
+	rinfo->base1_region_size = pci_resource_len(pd, 1);
+
+	assert(rinfo->base0_region_size >= 0x00800000);	/* from GGI */
+	assert(rinfo->base1_region_size >= 0x01000000);	/* from GGI */
+
+	rinfo->ctrl_base_phys = pci_resource_start(rinfo->pd, 0);
+	rinfo->fb_base_phys = pci_resource_start(rinfo->pd, 1);
+
+	if (!request_mem_region(rinfo->ctrl_base_phys,
+				rinfo->base0_region_size, "rivafb")) {
+		printk(KERN_ERR PFX "cannot reserve MMIO region\n");
+		goto err_out_kfree;
 	}
 
-	for (i = 0; i < NUM_GRC_REGS; i++) {
-		io_out8 (i, 0x3CE);
-		regs->gra[i] = io_in8 (0x3CF);
+	if (!request_mem_region(rinfo->fb_base_phys,
+				rinfo->base1_region_size, "rivafb")) {
+		printk(KERN_ERR PFX "cannot reserve FB region\n");
+		goto err_out_free_base0;
+	}
+	
+	rinfo->ctrl_base = ioremap(rinfo->ctrl_base_phys,
+				   rinfo->base0_region_size);
+	if (!rinfo->ctrl_base) {
+		printk(KERN_ERR PFX "cannot ioremap MMIO base\n");
+		goto err_out_free_base1;
+	}
+	
+	rinfo->fb_base = ioremap(rinfo->fb_base_phys,
+				 rinfo->base1_region_size);
+	if (!rinfo->fb_base) {
+		printk(KERN_ERR PFX "cannot ioremap FB base\n");
+		goto err_out_iounmap_ctrl;
+	}
+	
+#ifdef CONFIG_MTRR
+	if (!nomtrr) {
+		rinfo->mtrr.vram = mtrr_add(rinfo->fb_base_phys,
+					    rinfo->base1_region_size, MTRR_TYPE_WRCOMB, 1);
+		if (rinfo->mtrr.vram < 0) {
+			printk(KERN_ERR PFX "unable to setup MTRR\n");
+		} else {
+			rinfo->mtrr.vram_valid = 1;
+			/* let there be speed */
+			printk(KERN_INFO PFX "RIVA MTRR set to ON\n");
+		}
 	}
+#endif /* CONFIG_MTRR */
 
+	rinfo->riva.EnableIRQ = 0;
+	rinfo->riva.PRAMDAC = (unsigned *)(rinfo->ctrl_base + 0x00680000);
+	rinfo->riva.PFB = (unsigned *)(rinfo->ctrl_base + 0x00100000);
+	rinfo->riva.PFIFO = (unsigned *)(rinfo->ctrl_base + 0x00002000);
+	rinfo->riva.PGRAPH = (unsigned *)(rinfo->ctrl_base + 0x00400000);
+	rinfo->riva.PEXTDEV = (unsigned *)(rinfo->ctrl_base + 0x00101000);
+	rinfo->riva.PTIMER = (unsigned *)(rinfo->ctrl_base + 0x00009000);
+	rinfo->riva.PMC = (unsigned *)(rinfo->ctrl_base + 0x00000000);
+	rinfo->riva.FIFO = (unsigned *)(rinfo->ctrl_base + 0x00800000);
+
+	rinfo->riva.PCIO = (U008 *)(rinfo->ctrl_base + 0x00601000);
+	rinfo->riva.PDIO = (U008 *)(rinfo->ctrl_base + 0x00681000);
+	rinfo->riva.PVIO = (U008 *)(rinfo->ctrl_base + 0x000C0000);
 
-	for (i = 0; i < NUM_SEQ_REGS; i++) {
-		io_out8 (i, 0x3C4);
-		regs->seq[i] = io_in8 (0x3C5);
+	rinfo->riva.IO = (MISCin(rinfo) & 0x01) ? 0x3D0 : 0x3B0;
+
+	switch (rinfo->riva.Architecture) {
+	case NV_ARCH_03:
+		rinfo->riva.PRAMIN = (unsigned *)(rinfo->fb_base + 0x00C00000);
+		break;
+	case NV_ARCH_04:
+	case NV_ARCH_10:
+		rinfo->riva.PCRTC = (unsigned *)(rinfo->ctrl_base + 0x00600000);
+		rinfo->riva.PRAMIN = (unsigned *)(rinfo->ctrl_base + 0x00710000);
+		break;
 	}
-}
 
+	RivaGetConfig(&rinfo->riva);
 
-/* from GGI */
-static
-void riva_load_state (struct rivafb_info *rinfo, struct riva_regs *regs)
-{
-	int i;
-	RIVA_HW_STATE *state = &regs->ext;
+	/* back to normal */
 
-	io_out8 (0x11, 0x3D4);
-	io_out8 (0x00, 0x3D5);
+	assert(rinfo->pd != NULL);
 
-	outb (rinfo->riva.LockUnlockIndex, rinfo->riva.LockUnlockIO);
-	outb (0x57, rinfo->riva.LockUnlockIO + 1);
+	/* unlock io */
+	CRTCout(rinfo, 0x11, 0xFF);	/* vgaHWunlock() + riva unlock (0x7F) */
+	rinfo->riva.LockUnlock(&rinfo->riva, 0);
 
-	rinfo->riva.LoadStateExt (&rinfo->riva, state);
+	riva_save_state(rinfo, &rinfo->initial_state);
 
-	io_out8 (regs->misc_output, 0x3C2);
+	rinfo->ram_amount = rinfo->riva.RamAmountKBytes * 1024;
+	rinfo->dclk_max = rinfo->riva.MaxVClockFreqKHz * 1000;
 
-	for (i = 0; i < NUM_CRT_REGS; i++) {
-		if (i < 0x19) {
-			io_out8 (i, 0x3D4);
-			io_out8 (regs->crtc[i], 0x3D5);
-		} else {
-			switch (i) {
-			case 0x19:
-			case 0x20:
-			case 0x21:
-			case 0x22:
-			case 0x23:
-			case 0x24:
-			case 0x25:
-			case 0x26:
-			case 0x27:
-			case 0x28:
-			case 0x29:
-			case 0x2a:
-			case 0x2b:
-			case 0x2c:
-			case 0x2d:
-			case 0x2e:
-			case 0x2f:
-			case 0x30:
-			case 0x31:
-			case 0x32:
-			case 0x33:
-			case 0x34:
-			case 0x35:
-			case 0x36:
-			case 0x37:
-			case 0x38:
-			case 0x39:
-			case 0x3a:
-			case 0x3b:
-			case 0x3c:
-			case 0x3d:
-			case 0x3e:
-			case 0x3f:
-			case 0x40:
-				break;
-			default:
-				io_out8 (i, 0x3D4);
-				io_out8 (regs->crtc[i], 0x3D5);
-			}
-		}
-	}
+	if (!nohwcursor) rinfo->cursor = rivafb_init_cursor(rinfo);
 
-	for (i = 0; i < NUM_ATC_REGS; i++) {
-		io_out8 (i, 0x3C0);
-		io_out8 (regs->attr[i], 0x3C0);
+	if (riva_set_fbinfo(rinfo) < 0) {
+		printk(KERN_ERR PFX "error setting initial video mode\n");
+		goto err_out_cursor;
 	}
 
-	for (i = 0; i < NUM_GRC_REGS; i++) {
-		io_out8 (i, 0x3CE);
-		io_out8 (regs->gra[i], 0x3CF);
+	if (register_framebuffer((struct fb_info *)rinfo) < 0) {
+		printk(KERN_ERR PFX
+			"error registering riva framebuffer\n");
+		goto err_out_load_state;
 	}
 
-	for (i = 0; i < NUM_SEQ_REGS; i++) {
-		io_out8 (i, 0x3C4);
-		io_out8 (regs->seq[i], 0x3C5);
-	}
+	riva_boards = riva_board_list_add(riva_boards, rinfo);
+
+	pci_set_drvdata(pd, rinfo);
+
+	printk(KERN_INFO PFX
+		"PCI nVidia NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n",
+		rinfo->riva.Architecture,
+		RIVAFB_VERSION,
+		rinfo->drvr_name,
+		rinfo->ram_amount / (1024 * 1024),
+		rinfo->fb_base_phys);
+
+	return 0;
+
+err_out_load_state:
+	riva_load_state(rinfo, &rinfo->initial_state);
+err_out_cursor:
+	rivafb_exit_cursor(rinfo);
+/* err_out_iounmap_fb: */
+	iounmap(rinfo->fb_base);
+err_out_iounmap_ctrl:
+	iounmap(rinfo->ctrl_base);
+err_out_free_base1:
+	release_mem_region(rinfo->fb_base_phys, rinfo->base1_region_size);
+err_out_free_base0:
+	release_mem_region(rinfo->ctrl_base_phys, rinfo->base0_region_size);
+err_out_kfree:
+	kfree(rinfo);
+err_out:
+	return -ENODEV;
 }
 
+static void __devexit rivafb_remove_one(struct pci_dev *pd)
+{
+	struct rivafb_info *board = pci_get_drvdata(pd);
+	
+	if (!board)
+		return;
+
+	riva_boards = riva_board_list_del(riva_boards, board);
 
+	riva_load_state(board, &board->initial_state);
 
+	unregister_framebuffer((struct fb_info *)board);
 
-/**
- * riva_board_list_add
- * @board_list: Root node of list of boards
- * @new_node: New node to be added
+	rivafb_exit_cursor(board);
+
+#ifdef CONFIG_MTRR
+	if (board->mtrr.vram_valid)
+		mtrr_del(board->mtrr.vram, board->fb_base_phys,
+			 board->base1_region_size);
+#endif /* CONFIG_MTRR */
+
+	iounmap(board->ctrl_base);
+	iounmap(board->fb_base);
+
+	release_mem_region(board->ctrl_base_phys,
+			   board->base0_region_size);
+	release_mem_region(board->fb_base_phys,
+			   board->base1_region_size);
+
+	kfree(board);
+
+	pci_set_drvdata(pd, NULL);
+}
+
+
+
+/* ------------------------------------------------------------------------- *
  *
- * DESCRIPTION:
- * Adds @new_node to the list referenced by @board_list
+ * initialization
  *
- * RETURNS:
- * New root node
- */
-static
-struct rivafb_info *riva_board_list_add (struct rivafb_info *board_list,
-					 struct rivafb_info *new_node)
+ * ------------------------------------------------------------------------- */
+
+#ifndef MODULE
+int __init rivafb_setup(char *options)
 {
-	struct rivafb_info *i_p = board_list;
+	char *this_opt;
 
-	new_node->next = NULL;
+	if (!options || !*options)
+		return 0;
 
-	if (board_list == NULL)
-		return new_node;
+	for (this_opt = strtok(options, ","); this_opt;
+	     this_opt = strtok(NULL, ",")) {
+		if (!strncmp(this_opt, "font:", 5)) {
+			char *p;
+			int i;
 
-	while (i_p->next != NULL)
-		i_p = i_p->next;
-	i_p->next = new_node;
+			p = this_opt + 5;
+			for (i = 0; i < sizeof(fontname) - 1; i++)
+				if (!*p || *p == ' ' || *p == ',')
+					break;
+			memcpy(fontname, this_opt + 5, i);
+			fontname[i] = 0;
 
-	return board_list;
+		} else if (!strncmp(this_opt, "noblink", 7)) {
+			noblink = 1;
+		} else if (!strncmp(this_opt, "noaccel", 7)) {
+			noaccel = 1;
+		} else if (!strncmp(this_opt, "nomove", 6)) {
+			nomove = 1;
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			nomtrr = 1;
+#endif
+		} else if (!strncmp(this_opt, "nohwcursor", 10)) {
+			nohwcursor = 1;
+		} else
+			mode_option = this_opt;
+	}
+	return 0;
 }
+#endif /* !MODULE */
+
+static struct pci_driver rivafb_driver = {
+	name:		"rivafb",
+	id_table:	rivafb_pci_tbl,
+	probe:		rivafb_init_one,
+	remove:		rivafb_remove_one,
+};
 
 
 
-/**
- * riva_board_list_del
- * @board_list: Root node of list of boards
- * @del_node: Node to be removed
+/* ------------------------------------------------------------------------- *
  *
- * DESCRIPTION:
- * Removes @del_node from the list referenced by @board_list
+ * modularization
  *
- * RETURNS:
- * New root node
- */
-static
-struct rivafb_info *riva_board_list_del (struct rivafb_info *board_list,
-					 struct rivafb_info *del_node)
-{
-	struct rivafb_info *i_p = board_list;
+ * ------------------------------------------------------------------------- */
 
-	if (board_list == del_node)
-		return del_node->next;
+int __init rivafb_init(void)
+{
+	int err;
+#ifdef MODULE
+	if (font) strncpy(fontname, font, sizeof(fontname)-1);
+#endif
+	err = pci_module_init(&rivafb_driver);
+	if (err)
+		return err;
+	return 0;
+}
 
-	while (i_p->next != del_node)
-		i_p = i_p->next;
-	i_p->next = del_node->next;
 
-	return board_list;
+#ifdef MODULE
+static void __exit rivafb_exit(void)
+{
+	pci_unregister_driver(&rivafb_driver);
 }
 
+module_init(rivafb_init);
+module_exit(rivafb_exit);
+
+MODULE_PARM(font, "s");
+MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (default=none)");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Disables hardware acceleration (0 or 1=disabled) (default=0)");
+MODULE_PARM(nomove, "i");
+MODULE_PARM_DESC(nomove, "Enables YSCROLL_NOMOVE (0 or 1=enabled) (default=0)");
+MODULE_PARM(nohwcursor, "i");
+MODULE_PARM_DESC(nohwcursor, "Disables hardware cursor (0 or 1=disabled) (default=0)");
+MODULE_PARM(noblink, "i");
+MODULE_PARM_DESC(noblink, "Disables hardware cursor blinking (0 or 1=disabled) (default=0)");
+#ifdef CONFIG_MTRR
+MODULE_PARM(nomtrr, "i");
+MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) (default=0)");
+#endif
+#endif /* MODULE */
+
+MODULE_AUTHOR("Ani Joshi, maintainer");
+MODULE_DESCRIPTION("Framebuffer driver for nVidia Riva 128, TNT, TNT2");

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