Subject: newport console can do set_font

From: Michl Ladislav <[email-masked]>
Date: Wed, 28 Mar 2001 21:18:59 +0200 (CEST)

hi all,

i hope this is the right place to send this. comments and corrections are
welcome.

regards,
ladis

Index: drivers/video/newport_con.c
===================================================================
RCS file: /cvs/linux/drivers/video/newport_con.c,v
retrieving revision 1.23
diff -a -u -r1.23 newport_con.c
--- drivers/video/newport_con.c	2000/11/23 02:00:54	1.23
+++ drivers/video/newport_con.c	2001/03/28 19:12:34
@@ -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;
@@ -274,6 +283,7 @@
 static const char * __init newport_startup(void)
 #endif
 {
+    int i;
     struct newport_regs *p;

     npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
@@ -289,11 +299,14 @@
 	return NULL;
     }

+    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);
+    /* gfx_init (display_desc); */

     return "SGI Newport";
 }
@@ -329,7 +342,7 @@
 {
     unsigned char *p;

-    p = &FONT_DATA[(charattr & 0xff) << 4];
+    p = &font_data[vc->vc_num][(charattr & 0xff) << 4];
     charattr = (charattr >> 8) & 0xff;
     xpos <<= 3;
     ypos <<= 4;
@@ -378,7 +391,7 @@
 			     NPORT_DMODE0_L32);

     for (i = 0; i < count; i++, xpos += 8) {
-	p = &FONT_DATA[(s[i] & 0xff) << 4];
+	p = &font_data[vc->vc_num][(s[i] & 0xff) << 4];

 	newport_wait();

@@ -446,11 +459,82 @@
     return 1;
 }

-static int newport_font_op(struct vc_data *vc, struct console_font_op *f)
+static int newport_set_font(int unit, struct console_font_op *op)
 {
-    return -ENOSYS;
+	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 *op)
+{
+	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;
@@ -594,21 +678,21 @@
 };

 #ifdef MODULE
-
-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;
+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;
 }

-int cleanup_module(void) {
-    printk("Unloading SGI Newport Console Driver\n");
-    return 0;
+int cleanup_module(void)
+{
+	printk("Unloading SGI Newport Console Driver\n");
+	return 0;
 }

 #endif

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 29 Mar 2001 00:56:42 +0200

> i hope this is the right place to send this. comments and corrections are

Seems like some MTA / MUA or maybe just your editor tampered with whitespace
in the patch so I can no longer apply it automatically.  No problem as this
was a small patch but for future patches please try to ensure this doesn't
happen again.  Patch looks good.

Thanks,

  Ralf