Date: Mon, 10 Feb 1997 10:06:34 +0100 (MET)
From: Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
To: Linux/m68k <linux-m68k@phil.uni-sb.de>
Subject: L68K: Palette support for abstract console
Sender: owner-linux-m68k@phil.uni-sb.de
Reply-To: linux-m68k@phil.uni-sb.de


This patch adds support for the GIO_CMAP (get console palette) and PIO_CMAP
(set console palette) ioctls of the console driver for frame buffer based
consoles. It should be applied _after_ my abstract console patch.

Caveat: the changes to arch/m68k/atari/atafb.c and arch/m68k/amiga/cyberfb.c
are untested.

I also included a self-written example program. It dumps the current console
palette and tries to change it using the 0-16 numerical (dec/hex/oct)
arguments.

--- arch/m68k/amiga/amifb.c.orig	Mon Jan 20 20:02:51 1997
+++ arch/m68k/amiga/amifb.c	Thu Feb  6 23:11:14 1997
@@ -1242,6 +1242,7 @@
 static int amifbcon_switch(int con);
 static int amifbcon_updatevar(int con);
 static void amifbcon_blank(int blank);
+static int amifbcon_setcmap(struct fb_cmap *cmap, int con);
 
 	/*
 	 * Internal routines
@@ -1957,6 +1958,7 @@
 	fb_info.switch_con = &amifbcon_switch;
 	fb_info.updatevar = &amifbcon_updatevar;
 	fb_info.blank = &amifbcon_blank;
+	fb_info.setcmap = &amifbcon_setcmap;
 
 	amiga_fb_set_var(&amiga_fb_predefined[0], 0);
 
@@ -1993,6 +1995,15 @@
 static void amifbcon_blank(int blank)
 {
 	do_blank = blank ? blank : -1;
+}
+
+	/*
+	 * Set the colormap
+	 */
+
+static int amifbcon_setcmap(struct fb_cmap *cmap, int con)
+{
+	return(amiga_fb_set_cmap(cmap, 1, con));
 }
 
 /* ---------------------------- Generic routines ---------------------------- */
--- arch/m68k/amiga/cyberfb.c.orig	Thu Jan  9 21:03:01 1997
+++ arch/m68k/amiga/cyberfb.c	Sun Feb  9 20:07:58 1997
@@ -235,6 +235,7 @@
 static int Cyberfb_switch(int con);
 static int Cyberfb_updatevar(int con);
 static void Cyberfb_blank(int blank);
+static int Cyberfb_setcmap(struct fb_cmap *cmap, int con);
 
 
    /*
@@ -1179,6 +1182,7 @@
    fb_info.switch_con = &Cyberfb_switch;
    fb_info.updatevar = &Cyberfb_updatevar;
    fb_info.blank = &Cyberfb_blank;
+   fb_info.setcmap = &Cyberfb_setcmap;
 
    do_fb_set_var(&Cyber_fb_predefined[0], 1);
    Cyber_fb_get_var(&disp[0].var, -1);
@@ -1222,6 +1226,16 @@
 static void Cyberfb_blank(int blank)
 {
    fbhw->blank(blank);
+}
+
+
+   /*
+    *    Set the colormap
+    */
+
+static int Cyberfb_setcmap(struct fb_cmap *cmap, int con)
+{
+   return(Cyber_fb_set_cmap(cmap, 1, con));
 }
 
 
--- arch/m68k/atari/atafb.c.orig	Thu Jan  9 21:03:02 1997
+++ arch/m68k/atari/atafb.c	Sun Feb  9 20:05:31 1997
@@ -2905,6 +2905,12 @@
 		do_install_cmap(currcon);
 }
 
+static void
+atafb_setcmap(struct fb_cmap *cmap, int con)
+{
+	return(atari_fb_set_cmap(cmap, 1, con));
+}
+
 struct fb_info *
 atari_fb_init(long *mem_start)
 {
@@ -2999,6 +3005,7 @@
 	fb_info.switch_con=&atafb_switch;
 	fb_info.updatevar=&fb_update_var;
 	fb_info.blank=&atafb_blank;
+	fb_info.setcmap=&atafb_setcmap;
 	var=atari_fb_predefined+default_par-1;
 	do_fb_set_var(var,1);
 	strcat(fb_info.modename,fb_var_names[default_par-1][0]);
--- arch/m68k/console/fbcon.c.orig	Wed Jan 22 20:28:23 1997
+++ arch/m68k/console/fbcon.c	Sun Feb  9 20:19:42 1997
@@ -241,6 +241,7 @@
 static int fbcon_blank(int blank);
 static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data);
+static int fbcon_set_palette(struct vc_data *conp, unsigned char *table);
 
 
    /*
@@ -1859,6 +1860,38 @@
 	return( 0 );
 }
 
+static unsigned short palette_red[16];
+static unsigned short palette_green[16];
+static unsigned short palette_blue[16];
+
+static struct fb_cmap palette_cmap  = {
+    0, 16, palette_red, palette_green, palette_blue, NULL
+};
+
+static int fbcon_set_palette(struct vc_data *conp, unsigned char *table)
+{
+    int unit = conp->vc_num;
+    struct display *p = &disp[unit];
+    int i, j, k;
+    u_char val;
+
+    if (!conp->vc_can_do_color || (!p->can_soft_blank && console_blanked))
+	return(-EINVAL);
+    for (i = j = 0; i < 16; i++) {
+	k = table[i];
+	val = conp->vc_palette[j++];
+	palette_red[k] = (val<<8)|val;
+	val = conp->vc_palette[j++];
+	palette_green[k] = (val<<8)|val;
+	val = conp->vc_palette[j++];
+	palette_blue[k] = (val<<8)|val;
+    }
+    palette_cmap.len = 1<<p->var.bits_per_pixel;
+    if (palette_cmap.len > 16)
+	palette_cmap.len = 16;
+    return(fb_info->setcmap(&palette_cmap, unit));
+}
+
 
 /* ====================================================================== */
 
@@ -3779,5 +3812,5 @@
 struct consw fb_con = {
    fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc,
    fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch,
-   fbcon_blank, fbcon_get_font, fbcon_set_font
+   fbcon_blank, fbcon_get_font, fbcon_set_font, fbcon_set_palette
 };
--- arch/m68k/console/txtcon.c.orig	Wed Jan 22 20:28:42 1997
+++ arch/m68k/console/txtcon.c	Thu Feb  6 22:43:56 1997
@@ -38,6 +38,7 @@
 static int txtcon_blank(int blank);
 static int txtcon_get_font(struct vc_data *conp, int *w, int *h, char *data);
 static int txtcon_set_font(struct vc_data *conp, int w, int h, char *data);
+static int txtcon_set_palette(struct vc_data *conp, unsigned char *table);
 
 
 static u_long txtcon_startup(u_long kmem_start, const char **display_desc)
@@ -125,6 +126,10 @@
    return(0);
 }
 
+static int txtcon_set_palette(struct vc_data *conp, unsigned char *table)
+{
+    return(0);
+}
 
 /* ====================================================================== */
 
@@ -135,6 +140,6 @@
 struct consw txt_con = {
    txtcon_startup, txtcon_init, txtcon_deinit, txtcon_clear, txtcon_putc,
    txtcon_putcs, txtcon_cursor, txtcon_scroll, txtcon_bmove, txtcon_switch,
-   txtcon_blank, txtcon_get_font, txtcon_set_font
+   txtcon_blank, txtcon_get_font, txtcon_set_font, txtcon_set_palette
 };
 
--- drivers/char/abscon.c.orig	Wed Jan 22 20:37:58 1997
+++ drivers/char/abscon.c	Thu Feb  6 23:15:33 1997
@@ -34,6 +34,7 @@
  *	int con_blank(int blank)
  *	int con_get_font(struct vc_data *conp, int *w, int *h, char *data)
  *	int con_set_font(struct vc_data *conp, int w, int h, char *data)
+ *	int con_set_palette(struct vc_data *conp, unsigned char *table)
  *
  *  Currently the abstract console driver is used by:
  *
@@ -55,7 +56,6 @@
 /*
  *  TODO:
  *
- *     - add a palette interface to struct consw
  *     - scrollback support
  */
 
@@ -207,7 +207,7 @@
 
 int con_adjust_height(unsigned long fontheight)
 {
-    unsigned int currcons = fg_console;
+    int currcons = fg_console;
     /* ++Geert: Always assume that the number of lines did change? */
     return video_num_lines;
 }
@@ -230,10 +230,39 @@
 
 void set_palette(void)
 {
-    /* Nothing yet */
+    if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+	return;
+
+    conswitchp->con_set_palette(vc_cons[fg_console].d, color_table);
 }
 
 int set_get_cmap(unsigned char *arg, int set)
 {
-	return -EINVAL;
+    int i, j, k;
+
+    i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+    if (i)
+	return i;
+
+    for (i = 0; i < 16; i++)
+	if (set) {
+	    get_user(default_red[i], arg++);
+	    get_user(default_grn[i], arg++);
+	    get_user(default_blu[i], arg++);
+	} else {
+	    put_user (default_red[i], arg++);
+	    put_user (default_grn[i], arg++);
+	    put_user (default_blu[i], arg++);
+	}
+    if (set) {
+	for (i = 0; i < MAX_NR_CONSOLES; i++)
+	    if (vc_cons_allocated(i))
+		for (j = k = 0; j < 16; j++) {
+		    vc_cons[i].d->vc_palette[k++] = default_red[j];
+		    vc_cons[i].d->vc_palette[k++] = default_grn[j];
+		    vc_cons[i].d->vc_palette[k++] = default_blu[j];
+		}
+	set_palette();
+    }
+    return 0;
 }
--- include/linux/console.h.orig	Wed Jan 22 22:30:06 1997
+++ include/linux/console.h	Thu Feb  6 22:40:41 1997
@@ -126,6 +126,7 @@
     int    (*con_blank)(int);
     int    (*con_get_font)(struct vc_data *, int *, int *, char *);
     int    (*con_set_font)(struct vc_data *, int, int, char *);
+    int    (*con_set_palette)(struct vc_data *, unsigned char *);
 };
 
 extern struct consw *conswitchp;
--- include/linux/fb.h.orig	Mon Jan 20 20:41:27 1997
+++ include/linux/fb.h	Thu Feb  6 23:06:25 1997
@@ -205,6 +205,7 @@
    int (*switch_con)(int);          /* tell fb to switch consoles */
    int (*updatevar)(int);           /* tell fb to update the vars */
    void (*blank)(int);              /* tell fb to (un)blank the screen */
+   int (*setcmap)(struct fb_cmap *, int); /* tell fb to set the colormap */
 };
 
 #endif /* __KERNEL__ */

#include <sys/types.h>
#include <sys/stat.h>
#include <linux/kd.h>
#include <stdarg.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void Die(const char *fmt, ...)
{
    va_list ap;

    fflush(stdout);
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    exit(1);
}

u_char palette[48];

int main(int argc, char *argv[])
{
    int fd, i;

    if ((fd = open("/dev/tty0", O_RDONLY)) == -1)
	Die("open %s: %s\n", "/dev/tty0", strerror(errno));
    if (ioctl(fd, GIO_CMAP, palette) == -1)
	Die("ioctl GIO_CMAP: %s\n", strerror(errno));
    for (i = 0; i < 16; i++)
	printf("%2d: %02x%02x%02x\n", i, palette[3*i], palette[3*i+1],
	       palette[3*i+2]);
    i = 0;
    while (argc > 1 && i < 48) {
	u_long val;
	val = strtoul(argv[1], NULL, 0);
	palette[i++] = (val>>16)&0xff;
	palette[i++] = (val>>8)&0xff;
	palette[i++] = val&0xff;
	argc--;
	argv++;
    }
    if (ioctl(fd, PIO_CMAP, palette) == -1)
	Die("ioctl PIO_CMAP: %s\n", strerror(errno));
    close(fd);
}

Greetings,

						Geert

--
Geert Uytterhoeven                     Geert.Uytterhoeven@cs.kuleuven.ac.be
Wavelets, Linux/m68k on Amiga          http://www.cs.kuleuven.ac.be/~geert/
Department of Computer Science -- Katholieke Universiteit Leuven -- Belgium

