patch-2.4.10 linux/drivers/video/newport_con.c

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

diff -u --recursive --new-file v2.4.9/linux/drivers/video/newport_con.c linux/drivers/video/newport_con.c
@@ -20,6 +20,7 @@
 #include <linux/vt_kern.h>
 #include <linux/mm.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -38,6 +39,14 @@
 
 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
 
+/* borrowed from fbcon.c */
+#define REFCOUNT(fd)	(((int *)(fd))[-1])
+#define FNTSIZE(fd)	(((int *)(fd))[-2])
+#define FNTCHARCNT(fd)	(((int *)(fd))[-3])
+#define FONT_EXTRA_WORDS 3
+
+static unsigned char *font_data[MAX_NR_CONSOLES];
+
 extern struct newport_regs *npregs;
 
 static int logo_active;
@@ -65,114 +74,117 @@
 static inline void newport_render_background(int xstart, int ystart,
 					     int xend, int yend, int ci)
 {
-    newport_wait();
-    npregs->set.wrmask = 0xffffffff;
-    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
-			     NPORT_DMODE0_STOPY);
-    npregs->set.colori = ci;
-    npregs->set.xystarti = (xstart << 16) | ((ystart + topscan) & 0x3ff);
-    npregs->go.xyendi = ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff);
+	newport_wait();
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.colori = ci;
+	npregs->set.xystarti =
+	    (xstart << 16) | ((ystart + topscan) & 0x3ff);
+	npregs->go.xyendi =
+	    ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff);
 }
 
 static inline void newport_init_cmap(void)
 {
-    unsigned short i;
-    
-    for(i = 0; i < 16; i++) {
-	newport_bfwait();
-	newport_cmap_setaddr(npregs, color_table[i]);
-	newport_cmap_setrgb(npregs,
-			    default_red[i],
-			    default_grn[i],
-			    default_blu[i]);
-    }
+	unsigned short i;
+
+	for (i = 0; i < 16; i++) {
+		newport_bfwait();
+		newport_cmap_setaddr(npregs, color_table[i]);
+		newport_cmap_setrgb(npregs,
+				    default_red[i],
+				    default_grn[i], default_blu[i]);
+	}
 }
 
 static inline void newport_show_logo(void)
 {
-    unsigned long i;
+	unsigned long i;
 
-    for(i = 0; i < LINUX_LOGO_COLORS; i++) {
-	newport_bfwait();
-	newport_cmap_setaddr(npregs, i + 0x20);
-	newport_cmap_setrgb(npregs,
-			    linux_logo_red[i],
-			    linux_logo_green[i],
-			    linux_logo_blue[i]);
-    }
-
-    newport_wait();
-    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_CHOST);
-    
-    npregs->set.xystarti = ((newport_xsize - LOGO_W) << 16) | (0);
-    npregs->set.xyendi = ((newport_xsize - 1) << 16);
-    newport_wait();
+	for (i = 0; i < LINUX_LOGO_COLORS; i++) {
+		newport_bfwait();
+		newport_cmap_setaddr(npregs, i + 0x20);
+		newport_cmap_setrgb(npregs,
+				    linux_logo_red[i],
+				    linux_logo_green[i],
+				    linux_logo_blue[i]);
+	}
+
+	newport_wait();
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_CHOST);
 
-    for (i = 0; i < LOGO_W * LOGO_H; i++)
-	npregs->go.hostrw0 = linux_logo[i] << 24;
+	npregs->set.xystarti = ((newport_xsize - LOGO_W) << 16) | (0);
+	npregs->set.xyendi = ((newport_xsize - 1) << 16);
+	newport_wait();
+
+	for (i = 0; i < LOGO_W * LOGO_H; i++)
+		npregs->go.hostrw0 = linux_logo[i] << 24;
 }
 
 static inline void newport_clear_screen(int xstart, int ystart, int xend,
-					int yend, int ci) {
-    if (logo_active)
-	return;
-
-    newport_wait();
-    npregs->set.wrmask = 0xffffffff;
-    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
-			     NPORT_DMODE0_STOPY);
-    npregs->set.colori = ci;
-    npregs->set.xystarti = (xstart << 16) | ystart;
-    npregs->go.xyendi = (xend << 16) | yend;
+					int yend, int ci)
+{
+	if (logo_active)
+		return;
+
+	newport_wait();
+	npregs->set.wrmask = 0xffffffff;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.colori = ci;
+	npregs->set.xystarti = (xstart << 16) | ystart;
+	npregs->go.xyendi = (xend << 16) | yend;
 }
 
 static inline void newport_clear_lines(int ystart, int yend, int ci)
 {
-    ystart = ((ystart << 4) + topscan) & 0x3ff;
-    yend = ((yend << 4) + topscan + 15) & 0x3ff;    
-    newport_clear_screen (0, ystart, 1280+63, yend, ci);
-}
-
-void newport_reset (void)
-{
-    unsigned short treg;    
-    int i;
-    
-    newport_wait();
-    treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-    newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EVIDEO));
-
-    treg = newport_vc2_get(npregs, VC2_IREG_CENTRY);
-    newport_vc2_set(npregs, VC2_IREG_RADDR, treg);
-    npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
-			   NPORT_DMODE_W2 | VC2_PROTOCOL);
-    for(i = 0; i < 128; i++) {
-	newport_bfwait();
-	if (i == 92 || i == 94)
-	    npregs->set.dcbdata0.byshort.s1 = 0xff00;
-	else
-	    npregs->set.dcbdata0.byshort.s1 = 0x0000;
-    }
+	ystart = ((ystart << 4) + topscan) & 0x3ff;
+	yend = ((yend << 4) + topscan + 15) & 0x3ff;
+	newport_clear_screen(0, ystart, 1280 + 63, yend, ci);
+}
+
+void newport_reset(void)
+{
+	unsigned short treg;
+	int i;
+
+	newport_wait();
+	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+	newport_vc2_set(npregs, VC2_IREG_CONTROL,
+			(treg | VC2_CTRL_EVIDEO));
+
+	treg = newport_vc2_get(npregs, VC2_IREG_CENTRY);
+	newport_vc2_set(npregs, VC2_IREG_RADDR, treg);
+	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			       NPORT_DMODE_W2 | VC2_PROTOCOL);
+	for (i = 0; i < 128; i++) {
+		newport_bfwait();
+		if (i == 92 || i == 94)
+			npregs->set.dcbdata0.byshort.s1 = 0xff00;
+		else
+			npregs->set.dcbdata0.byshort.s1 = 0x0000;
+	}
 
-    newport_init_cmap();
+	newport_init_cmap();
 
-    /* turn off popup plane */
-    npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
-                           XM9_CRS_CONFIG | NPORT_DMODE_W1);
-    npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
-    npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL |
-                           XM9_CRS_CONFIG | NPORT_DMODE_W1);
-    npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
-    
-    topscan = 0;
-    npregs->cset.topscan = 0x3ff;
-    npregs->cset.xywin = (4096 << 16) | 4096;
+	/* turn off popup plane */
+	npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_CONFIG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
+	npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_CONFIG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 &= ~XM9_PUPMODE;
+
+	topscan = 0;
+	npregs->cset.topscan = 0x3ff;
+	npregs->cset.xywin = (4096 << 16) | 4096;
 
-    /* Clear the screen. */
-    newport_clear_screen(0,0,1280+63,1024,0);
+	/* Clear the screen. */
+	newport_clear_screen(0, 0, 1280 + 63, 1024, 0);
 }
 
 /*
@@ -181,395 +193,508 @@
  */
 void newport_get_screensize(void)
 {
-    int i,cols;
-    unsigned short ventry,treg;
-    unsigned short linetable[128]; /* should be enough */
-
-    ventry = newport_vc2_get (npregs, VC2_IREG_VENTRY);
-    newport_vc2_set(npregs, VC2_IREG_RADDR, ventry);
-    npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
-			   NPORT_DMODE_W2 | VC2_PROTOCOL);
-    for(i = 0; i < 128; i++) {
-	newport_bfwait();
-	linetable[i] = npregs->set.dcbdata0.byshort.s1;
-    }
-
-    newport_xsize = newport_ysize = 0;
-    for (i = 0; linetable[i+1] && (i < sizeof(linetable)); i+=2) {
-	cols = 0;
-        newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]);
-        npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+	int i, cols;
+	unsigned short ventry, treg;
+	unsigned short linetable[128];	/* should be enough */
+
+	ventry = newport_vc2_get(npregs, VC2_IREG_VENTRY);
+	newport_vc2_set(npregs, VC2_IREG_RADDR, ventry);
+	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
 			       NPORT_DMODE_W2 | VC2_PROTOCOL);
-	do {
-	    newport_bfwait();
-	    treg = npregs->set.dcbdata0.byshort.s1;
-	    if ((treg & 1) == 0)
-		cols += (treg >> 7) & 0xfe;
-	    if ((treg & 0x80) == 0) {
+	for (i = 0; i < 128; i++) {
 		newport_bfwait();
-		treg = npregs->set.dcbdata0.byshort.s1;
-	    } 
-	} while ((treg & 0x8000) == 0);
-	if (cols) {
-	    if (cols > newport_xsize)
-		newport_xsize = cols;
-	    newport_ysize += linetable[i+1];
+		linetable[i] = npregs->set.dcbdata0.byshort.s1;
 	}
-    }
-    printk ("NG1: Screensize %dx%d\n",newport_xsize,newport_ysize);
+
+	newport_xsize = newport_ysize = 0;
+	for (i = 0; linetable[i + 1] && (i < sizeof(linetable)); i += 2) {
+		cols = 0;
+		newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]);
+		npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+				       NPORT_DMODE_W2 | VC2_PROTOCOL);
+		do {
+			newport_bfwait();
+			treg = npregs->set.dcbdata0.byshort.s1;
+			if ((treg & 1) == 0)
+				cols += (treg >> 7) & 0xfe;
+			if ((treg & 0x80) == 0) {
+				newport_bfwait();
+				treg = npregs->set.dcbdata0.byshort.s1;
+			}
+		} while ((treg & 0x8000) == 0);
+		if (cols) {
+			if (cols > newport_xsize)
+				newport_xsize = cols;
+			newport_ysize += linetable[i + 1];
+		}
+	}
+	printk("NG1: Screensize %dx%d\n", newport_xsize, newport_ysize);
 }
 
 static void newport_get_revisions(void)
 {
-    unsigned int tmp;
-    unsigned int board_rev;
-    unsigned int rex3_rev;
-    unsigned int vc2_rev;
-    unsigned int cmap_rev;
-    unsigned int xmap9_rev;
-    unsigned int bt445_rev;
-    unsigned int bitplanes;
-
-    rex3_rev = npregs->cset.status & NPORT_STAT_VERS;
-
-    npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL |
-                           NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
-    tmp = npregs->set.dcbdata0.bybytes.b3;
-    cmap_rev = tmp & 7;
-    board_rev = (tmp >> 4) & 7;
-    bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24; 
-
-    npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL |
-                           NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
-    tmp = npregs->set.dcbdata0.bybytes.b3;
-    if ((tmp & 7) < cmap_rev)
-	cmap_rev = (tmp & 7);
-
-    vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7;
-
-    npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
-                           XM9_CRS_REVISION | NPORT_DMODE_W1);
-    xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7;
-
-    npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
-                           BT445_CSR_ADDR_REG | NPORT_DMODE_W1);
-    npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG;
-    npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
-                           BT445_CSR_REVISION | NPORT_DMODE_W1);
-    bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a;
+	unsigned int tmp;
+	unsigned int board_rev;
+	unsigned int rex3_rev;
+	unsigned int vc2_rev;
+	unsigned int cmap_rev;
+	unsigned int xmap9_rev;
+	unsigned int bt445_rev;
+	unsigned int bitplanes;
+
+	rex3_rev = npregs->cset.status & NPORT_STAT_VERS;
+
+	npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL |
+			       NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+	tmp = npregs->set.dcbdata0.bybytes.b3;
+	cmap_rev = tmp & 7;
+	board_rev = (tmp >> 4) & 7;
+	bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24;
+
+	npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL |
+			       NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+	tmp = npregs->set.dcbdata0.bybytes.b3;
+	if ((tmp & 7) < cmap_rev)
+		cmap_rev = (tmp & 7);
+
+	vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7;
+
+	npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+			       XM9_CRS_REVISION | NPORT_DMODE_W1);
+	xmap9_rev = npregs->set.dcbdata0.bybytes.b3 & 7;
+
+	npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+			       BT445_CSR_ADDR_REG | NPORT_DMODE_W1);
+	npregs->set.dcbdata0.bybytes.b3 = BT445_REVISION_REG;
+	npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+			       BT445_CSR_REVISION | NPORT_DMODE_W1);
+	bt445_rev = (npregs->set.dcbdata0.bybytes.b3 >> 4) - 0x0a;
 
 #define L(a)     (char)('A'+(a))
-    printk ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
-	    board_rev,bitplanes,L(rex3_rev),L(vc2_rev), L(xmap9_rev),
-	    L(cmap_rev ? (cmap_rev+1):0),L(bt445_rev));
+	printk
+	    ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
+	     board_rev, bitplanes, L(rex3_rev), L(vc2_rev), L(xmap9_rev),
+	     L(cmap_rev ? (cmap_rev + 1) : 0), L(bt445_rev));
 #undef L
 
-    if (board_rev == 3) /* I don't know all affected revisions */
-	xcurs_correction = 21;
+	if (board_rev == 3)	/* I don't know all affected revisions */
+		xcurs_correction = 21;
 }
 
 #ifdef MODULE
 static const char *newport_startup(void)
 #else
-static const char * __init newport_startup(void)
+static const char *__init newport_startup(void)
 #endif
 {
-    struct newport_regs *p;
+	int i;
+	struct newport_regs *p;
+
+	npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
+
+	p = npregs;
+	p->cset.config = NPORT_CFG_GD0;
+
+	if (newport_wait()) {
+		return NULL;
+	}
+
+	p->set.xstarti = TESTVAL;
+	if (p->set._xstart.word != XSTI_TO_FXSTART(TESTVAL))
+		return NULL;
 
-    npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
-	
-    p = npregs;
-    p->cset.config = NPORT_CFG_GD0;
-
-    if(newport_wait()) {
-	return NULL;
-    }
-
-    p->set.xstarti = TESTVAL; if(p->set._xstart.word != XSTI_TO_FXSTART(TESTVAL)) {
-	return NULL;
-    }
-
-    newport_reset ();
-    newport_get_revisions();
-    newport_get_screensize();
-
-    // gfx_init (display_desc);
-    
-    return "SGI Newport";
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		font_data[i] = FONT_DATA;
+
+	newport_reset();
+	newport_get_revisions();
+	newport_get_screensize();
+
+	/* gfx_init (display_desc); */
+
+	return "SGI Newport";
 }
 
 static void newport_init(struct vc_data *vc, int init)
 {
-    vc->vc_cols = newport_xsize / 8;
-    vc->vc_rows = newport_ysize / 16;
-    vc->vc_can_do_color = 1;
-}
-
-static void newport_clear(struct vc_data *vc, int sy, int sx, int height, int width)
-{
-    int xend = ((sx + width) << 3) - 1;
-    int ystart = ((sy << 4) + topscan) & 0x3ff;
-    int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
-
-    if (logo_active)
-	return;
-    
-    if (ystart < yend) {
-	newport_clear_screen(sx << 3, ystart, xend, yend,
-			     (vc->vc_color & 0xf0) >> 4);
-    } else {
-	newport_clear_screen(sx << 3, ystart, xend, 1023,
-			     (vc->vc_color & 0xf0) >> 4);
-	newport_clear_screen(sx << 3, 0, xend, yend,
-			     (vc->vc_color & 0xf0) >> 4);
-    }
-}
-
-static void newport_putc(struct vc_data *vc, int charattr, int ypos, int xpos)
-{
-    unsigned char *p;
-    
-    p = &FONT_DATA[(charattr & 0xff) << 4];
-    charattr = (charattr >> 8) & 0xff;
-    xpos <<= 3;
-    ypos <<= 4;
-
-    newport_render_background(xpos, ypos, xpos, ypos, (charattr & 0xf0) >> 4);
-    
-    /* Set the color and drawing mode. */
-    newport_wait();
-    npregs->set.colori = charattr & 0xf;
-    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-			     NPORT_DMODE0_L32);
-    
-    /* Set coordinates for bitmap operation. */
-    npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
-    npregs->set.xyendi = ((xpos + 7) << 16);
-    newport_wait();
-    
-    /* Go, baby, go... */
-    RENDER(npregs, p);
+	vc->vc_cols = newport_xsize / 8;
+	vc->vc_rows = newport_ysize / 16;
+	vc->vc_can_do_color = 1;
 }
 
-static void newport_putcs(struct vc_data *vc, const unsigned short *s,
-			  int count, int ypos, int xpos)
+static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
+			  int width)
 {
-    int i;
-    int charattr;
-    unsigned char *p; 
-
-    charattr = (*s >> 8) & 0xff;
-
-    xpos <<= 3;
-    ypos <<= 4;
-
-    if (!logo_active)
-	/* Clear the area behing the string */
-	newport_render_background(xpos, ypos, xpos + ((count-1) << 3), ypos,
-				  (charattr & 0xf0) >> 4);
+	int xend = ((sx + width) << 3) - 1;
+	int ystart = ((sy << 4) + topscan) & 0x3ff;
+	int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
 
-    newport_wait();
+	if (logo_active)
+		return;
 
-    /* Set the color and drawing mode. */
-    npregs->set.colori = charattr & 0xf;
-    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-			     NPORT_DMODE0_L32);
-    
-    for (i = 0; i < count; i++, xpos += 8) {
-	p = &FONT_DATA[(s[i] & 0xff) << 4];
+	if (ystart < yend) {
+		newport_clear_screen(sx << 3, ystart, xend, yend,
+				     (vc->vc_color & 0xf0) >> 4);
+	} else {
+		newport_clear_screen(sx << 3, ystart, xend, 1023,
+				     (vc->vc_color & 0xf0) >> 4);
+		newport_clear_screen(sx << 3, 0, xend, yend,
+				     (vc->vc_color & 0xf0) >> 4);
+	}
+}
 
+static void newport_putc(struct vc_data *vc, int charattr, int ypos,
+			 int xpos)
+{
+	unsigned char *p;
+
+	p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
+	charattr = (charattr >> 8) & 0xff;
+	xpos <<= 3;
+	ypos <<= 4;
+
+	newport_render_background(xpos, ypos, xpos, ypos,
+				  (charattr & 0xf0) >> 4);
+
+	/* Set the color and drawing mode. */
 	newport_wait();
+	npregs->set.colori = charattr & 0xf;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+				 NPORT_DMODE0_L32);
 
 	/* Set coordinates for bitmap operation. */
 	npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
 	npregs->set.xyendi = ((xpos + 7) << 16);
+	newport_wait();
 
 	/* Go, baby, go... */
 	RENDER(npregs, p);
-    }
+}
+
+static void newport_putcs(struct vc_data *vc, const unsigned short *s,
+			  int count, int ypos, int xpos)
+{
+	int i;
+	int charattr;
+	unsigned char *p;
+
+	charattr = (*s >> 8) & 0xff;
+
+	xpos <<= 3;
+	ypos <<= 4;
+
+	if (!logo_active)
+		/* Clear the area behing the string */
+		newport_render_background(xpos, ypos,
+					  xpos + ((count - 1) << 3), ypos,
+					  (charattr & 0xf0) >> 4);
+
+	newport_wait();
+
+	/* Set the color and drawing mode. */
+	npregs->set.colori = charattr & 0xf;
+	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+				 NPORT_DMODE0_L32);
+
+	for (i = 0; i < count; i++, xpos += 8) {
+		p = &font_data[vc->vc_num][(s[i] & 0xff) << 4];
+
+		newport_wait();
+
+		/* Set coordinates for bitmap operation. */
+		npregs->set.xystarti =
+		    (xpos << 16) | ((ypos + topscan) & 0x3ff);
+		npregs->set.xyendi = ((xpos + 7) << 16);
+
+		/* Go, baby, go... */
+		RENDER(npregs, p);
+	}
 }
 
 static void newport_cursor(struct vc_data *vc, int mode)
 {
-    unsigned short treg;
-    int xcurs, ycurs;
-    
-    switch (mode) {
-     case CM_ERASE:
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP)));
-	break;
+	unsigned short treg;
+	int xcurs, ycurs;
 
-     case CM_MOVE:
-     case CM_DRAW:
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
-	xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
-	ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
-	xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
-	newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
-	newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
-    }
+	switch (mode) {
+	case CM_ERASE:
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg & ~(VC2_CTRL_ECDISP)));
+		break;
+
+	case CM_MOVE:
+	case CM_DRAW:
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg | VC2_CTRL_ECDISP));
+		xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
+		ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
+		xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
+		newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
+		newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
+	}
 }
 
 static int newport_switch(struct vc_data *vc)
 {
-    static int logo_drawn = 0;
+	static int logo_drawn = 0;
 
-    topscan = 0;
-    npregs->cset.topscan = 0x3ff;
+	topscan = 0;
+	npregs->cset.topscan = 0x3ff;
 
-    if (!logo_drawn) {
-	newport_show_logo();
-	logo_drawn = 1;
-	logo_active = 1;
-    }
+	if (!logo_drawn) {
+		newport_show_logo();
+		logo_drawn = 1;
+		logo_active = 1;
+	}
 
-    return 1;
+	return 1;
 }
 
 static int newport_blank(struct vc_data *c, int blank)
 {
-    unsigned short treg;
-    
-    if (blank == 0) {
-	/* unblank console */
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EDISP));
-    } else {
-	/* blank console */
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EDISP)));
-    }
-    return 1;
+	unsigned short treg;
+
+	if (blank == 0) {
+		/* unblank console */
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg | VC2_CTRL_EDISP));
+	} else {
+		/* blank console */
+		treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+		newport_vc2_set(npregs, VC2_IREG_CONTROL,
+				(treg & ~(VC2_CTRL_EDISP)));
+	}
+	return 1;
+}
+
+static int newport_set_font(int unit, struct console_font_op *op)
+{
+	int w = op->width;
+	int h = op->height;
+	int size = h * op->charcount;
+	int i;
+	unsigned char *new_data, *data = op->data, *p;
+
+	/* ladis: when I grow up, there will be a day... and more sizes will
+	 * be supported ;-) */
+	if ((w != 8) || (h != 16)
+	    || (op->charcount != 256 && op->charcount != 512))
+		return -EINVAL;
+
+	if (!(new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size,
+	     GFP_USER))) return -ENOMEM;
+
+	new_data += FONT_EXTRA_WORDS * sizeof(int);
+	FNTSIZE(new_data) = size;
+	FNTCHARCNT(new_data) = op->charcount;
+	REFCOUNT(new_data) = 0;	/* usage counter */
+
+	p = new_data;
+	for (i = 0; i < op->charcount; i++) {
+		memcpy(p, data, h);
+		data += 32;
+		p += h;
+	}
+
+	/* check if font is already used by other console */
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		if (font_data[i] != FONT_DATA
+		    && FNTSIZE(font_data[i]) == size
+		    && !memcmp(font_data[i], new_data, size)) {
+			kfree(new_data - FONT_EXTRA_WORDS * sizeof(int));
+			/* current font is the same as the new one */
+			if (i == unit)
+				return 0;
+			new_data = font_data[i];
+			break;
+		}
+	}
+	/* old font is user font */
+	if (font_data[unit] != FONT_DATA) {
+		if (--REFCOUNT(font_data[unit]) == 0)
+			kfree(font_data[unit] -
+			      FONT_EXTRA_WORDS * sizeof(int));
+	}
+	REFCOUNT(new_data)++;
+	font_data[unit] = new_data;
+
+	return 0;
+}
+
+static int newport_set_def_font(int unit, struct console_font_op *op)
+{
+	if (font_data[unit] != FONT_DATA) {
+		if (--REFCOUNT(font_data[unit]) == 0)
+			kfree(font_data[unit] -
+			      FONT_EXTRA_WORDS * sizeof(int));
+		font_data[unit] = FONT_DATA;
+	}
+
+	return 0;
 }
 
-static int newport_font_op(struct vc_data *vc, struct console_font_op *f)
+static int newport_font_op(struct vc_data *vc, struct console_font_op *op)
 {
-    return -ENOSYS;
+	int unit = vc->vc_num;
+
+	switch (op->op) {
+	case KD_FONT_OP_SET:
+		return newport_set_font(unit, op);
+	case KD_FONT_OP_SET_DEFAULT:
+		return newport_set_def_font(unit, op);
+	default:
+		return -ENOSYS;
+	}
 }
 
 static int newport_set_palette(struct vc_data *vc, unsigned char *table)
 {
-    return -EINVAL;
+	return -EINVAL;
 }
 
 static int newport_scrolldelta(struct vc_data *vc, int lines)
 {
-    /* there is (nearly) no off-screen memory, so we can't scroll back */
-    return 0;
+	/* there is (nearly) no off-screen memory, so we can't scroll back */
+	return 0;
 }
 
-static int newport_scroll(struct vc_data *vc, int t, int b, int dir, int lines)
+static int newport_scroll(struct vc_data *vc, int t, int b, int dir,
+			  int lines)
 {
-    int count,x,y;
-    unsigned short *s, *d;
-    unsigned short chattr;
-
-    logo_active = 0;	/* it's time to disable the logo now.. */
+	int count, x, y;
+	unsigned short *s, *d;
+	unsigned short chattr;
+
+	logo_active = 0;	/* it's time to disable the logo now.. */
+
+	if (t == 0 && b == vc->vc_rows) {
+		if (dir == SM_UP) {
+			topscan = (topscan + (lines << 4)) & 0x3ff;
+			newport_clear_lines(vc->vc_rows - lines,
+					    vc->vc_rows - 1,
+					    (vc->vc_color & 0xf0) >> 4);
+		} else {
+			topscan = (topscan + (-lines << 4)) & 0x3ff;
+			newport_clear_lines(0, lines - 1,
+					    (vc->vc_color & 0xf0) >> 4);
+		}
+		npregs->cset.topscan = (topscan - 1) & 0x3ff;
+		return 0;
+	}
 
-    if (t == 0 && b == vc->vc_rows) {
+	count = (b - t - lines) * vc->vc_cols;
 	if (dir == SM_UP) {
-	    topscan = (topscan + (lines << 4)) & 0x3ff;
-	    newport_clear_lines (vc->vc_rows-lines,vc->vc_rows-1,
-				 (vc->vc_color & 0xf0) >> 4);
+		x = 0;
+		y = t;
+		s = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (t + lines));
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * t);
+		while (count--) {
+			chattr = scr_readw(s++);
+			if (chattr != scr_readw(d)) {
+				newport_putc(vc, chattr, y, x);
+				scr_writew(chattr, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (b - lines));
+		x = 0;
+		y = b - lines;
+		for (count = 0; count < (lines * vc->vc_cols); count++) {
+			if (scr_readw(d) != vc->vc_video_erase_char) {
+				newport_putc(vc, vc->vc_video_erase_char,
+					     y, x);
+				scr_writew(vc->vc_video_erase_char, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
 	} else {
-	    topscan = (topscan + (-lines << 4)) & 0x3ff;
-	    newport_clear_lines (0,lines-1, (vc->vc_color & 0xf0) >> 4);
+		x = vc->vc_cols - 1;
+		y = b - 1;
+		s = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * (b - lines) - 2);
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * b - 2);
+		while (count--) {
+			chattr = scr_readw(s--);
+			if (chattr != scr_readw(d)) {
+				newport_putc(vc, chattr, y, x);
+				scr_writew(chattr, d);
+			}
+			d--;
+			if (x-- == 0) {
+				x = vc->vc_cols - 1;
+				y--;
+			}
+		}
+		d = (unsigned short *) (vc->vc_origin +
+					vc->vc_size_row * t);
+		x = 0;
+		y = t;
+		for (count = 0; count < (lines * vc->vc_cols); count++) {
+			if (scr_readw(d) != vc->vc_video_erase_char) {
+				newport_putc(vc, vc->vc_video_erase_char,
+					     y, x);
+				scr_writew(vc->vc_video_erase_char, d);
+			}
+			d++;
+			if (++x == vc->vc_cols) {
+				x = 0;
+				y++;
+			}
+		}
 	}
-	npregs->cset.topscan = (topscan - 1) & 0x3ff;
-	return 0;
-    }
-    
-    count = (b-t-lines) * vc->vc_cols;
-    if (dir == SM_UP) {
-	x = 0; y = t;
-	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row*(t+lines));
-	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row*t);
-	while (count--) {
-	    chattr = scr_readw (s++);
-	    if (chattr != scr_readw(d)) {
-		newport_putc (vc, chattr, y, x);
-		scr_writew (chattr, d);
-	    }
-	    d++;
-	    if (++x == vc->vc_cols) {
-		x = 0; y++;
-	    }
-	}
-	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row*(b-lines));
-	x = 0; y = b-lines;
-	for (count = 0; count < (lines * vc->vc_cols); count++) {
-	    if (scr_readw(d) != vc->vc_video_erase_char) {
-		newport_putc (vc, vc->vc_video_erase_char, y, x);
-		scr_writew (vc->vc_video_erase_char, d);
-	    }
-	    d++;
-	    if (++x == vc->vc_cols) {
-		x = 0; y++;
-	    }
-	}
-    } else {
-	x = vc->vc_cols-1; y = b-1;
-	s = (unsigned short *)(vc->vc_origin + vc->vc_size_row*(b-lines)-2);
-	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row*b-2);
-	while (count--) {
-	    chattr = scr_readw (s--);
-	    if (chattr != scr_readw(d)) {
-		newport_putc (vc, chattr, y, x);
-		scr_writew (chattr, d);
-	    }
-	    d--;
-	    if (x-- == 0) {
-		x = vc->vc_cols-1; y--;
-	    }
-	}
-	d = (unsigned short *)(vc->vc_origin + vc->vc_size_row*t);
-	x = 0; y = t;
-	for (count = 0; count < (lines * vc->vc_cols); count++) {
-	    if (scr_readw(d) != vc->vc_video_erase_char) {
-		newport_putc (vc, vc->vc_video_erase_char, y, x);
-		scr_writew (vc->vc_video_erase_char, d);
-	    }
-	    d++;
-	    if (++x == vc->vc_cols) {
-		x = 0; y++;
-	    }
-	}
-    }
-    return 1;
-}
-
-static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, int h, int w)
-{
-    short xs, ys, xe, ye, xoffs, yoffs, tmp;
-
-    xs = sx << 3; xe = ((sx+w) << 3)-1;
-    /*
-     * as bmove is only used to move stuff around in the same line
-     * (h == 1), we don't care about wrap arounds caused by topscan != 0
-     */
-    ys = ((sy << 4) + topscan) & 0x3ff; ye = (((sy+h) << 4)-1+topscan) & 0x3ff;
-    xoffs = (dx - sx) << 3;
-    yoffs = (dy - sy) << 4;
-    if (xoffs > 0) {
-	/* move to the right, exchange starting points */
-	tmp = xe; xe = xs; xs = tmp;
-    }
-    newport_wait();
-    npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
-			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
-			     NPORT_DMODE0_STOPY);
-    npregs->set.xystarti = (xs << 16) | ys;
-    npregs->set.xyendi = (xe << 16) | ye;
-    npregs->go.xymove = (xoffs << 16) | yoffs;
+	return 1;
+}
+
+static void newport_bmove(struct vc_data *vc, int sy, int sx, int dy,
+			  int dx, int h, int w)
+{
+	short xs, ys, xe, ye, xoffs, yoffs, tmp;
+
+	xs = sx << 3;
+	xe = ((sx + w) << 3) - 1;
+	/*
+	 * as bmove is only used to move stuff around in the same line
+	 * (h == 1), we don't care about wrap arounds caused by topscan != 0
+	 */
+	ys = ((sy << 4) + topscan) & 0x3ff;
+	ye = (((sy + h) << 4) - 1 + topscan) & 0x3ff;
+	xoffs = (dx - sx) << 3;
+	yoffs = (dy - sy) << 4;
+	if (xoffs > 0) {
+		/* move to the right, exchange starting points */
+		tmp = xe;
+		xe = xs;
+		xs = tmp;
+	}
+	newport_wait();
+	npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
+				 NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+				 | NPORT_DMODE0_STOPY);
+	npregs->set.xystarti = (xs << 16) | ys;
+	npregs->set.xyendi = (xe << 16) | ye;
+	npregs->go.xymove = (xoffs << 16) | yoffs;
 }
 
 static int newport_dummy(struct vc_data *c)
 {
-    return 0;
+	return 0;
 }
 
 #define DUMMY (void *) newport_dummy
@@ -590,25 +715,32 @@
     con_set_palette:	newport_set_palette,
     con_scrolldelta:	newport_scrolldelta,
     con_set_origin:	DUMMY,
-    con_save_screen:	DUMMY,
+    con_save_screen:	DUMMY
 };
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 
-int init_module(void) {
-    if (!newport_startup()) 
-       printk("Error loading SGI Newport Console driver\n");
-    else 
-       printk("Loading SGI Newport Console Driver\n");
-
-    take_over_console(&newport_con,0,MAX_NR_CONSOLES-1,1);
+int init_module(void)
+{
+	if (!newport_startup())
+		printk("Error loading SGI Newport Console driver\n");
+	else
+		printk("Loading SGI Newport Console Driver\n");
+	take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
 
-    return 0;
+	return 0;
 }
 
-int cleanup_module(void) {
-    printk("Unloading SGI Newport Console Driver\n");
-    return 0;
-}
+int cleanup_module(void)
+{
+	int i;
 
+	printk("Unloading SGI Newport Console Driver\n");
+	/* free memory used by user font */
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+		newport_set_def_font(i, NULL);
+
+	return 0;
+}
 #endif

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