parisc/sticon: Add user font support
authorHelge Deller <deller@gmx.de>
Mon, 12 Oct 2020 08:44:52 +0000 (10:44 +0200)
committerHelge Deller <deller@gmx.de>
Thu, 15 Oct 2020 06:12:59 +0000 (08:12 +0200)
This is a major rework of the sticon (parisc text console) driver in
order to support user font support.

Usually one want to use the stifb (parisc framebuffer driver) which is
based on fbcon and does support fonts and colors, but some old machines
(e.g. HP 730 workstations) don't provide a supported stifb graphic card,
and for those user fonts are preferred.

This patch drops unused code for software cursor and scrollback,
enhances the debug output and adds better documentation.

The code was tested on various machines with byte-mode and word-mode
graphic cards on GSC- and PCI-busses.

Signed-off-by: Helge Deller <deller@gmx.de>
drivers/video/console/Kconfig
drivers/video/console/sticon.c
drivers/video/console/sticore.c
drivers/video/fbdev/sticore.h

index 39deb22..ee33b8e 100644 (file)
@@ -119,6 +119,7 @@ config STI_CONSOLE
        bool "STI text console"
        depends on PARISC && HAS_IOMEM
        select FONT_SUPPORT
+       select CRC32
        default y
        help
          The STI console is the builtin display/keyboard on HP-PARISC
index 7c1dcd5..1b45116 100644 (file)
@@ -2,7 +2,7 @@
  *  linux/drivers/video/console/sticon.c - console driver using HP's STI firmware
  *
  *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *     Copyright (C) 2002 Helge Deller <deller@gmx.de>
+ *     Copyright (C) 2002-2020 Helge Deller <deller@gmx.de>
  *
  *  Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,
  *  which were
@@ -43,6 +43,9 @@
 #include <linux/kd.h>
 #include <linux/selection.h>
 #include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/font.h>
+#include <linux/crc32.h>
 
 #include <asm/io.h>
 
 #define BLANK 0
 static int vga_is_gfx;
 
-/* this is the sti_struct used for this console */
-static struct sti_struct *sticon_sti;
-
-/* Software scrollback */
-static unsigned long softback_buf, softback_curr;
-static unsigned long softback_in;
-static unsigned long /* softback_top, */ softback_end;
-static int softback_lines;
-
-/* software cursor */
-static int cursor_drawn;
-#define CURSOR_DRAW_DELAY              (1)
-#define DEFAULT_CURSOR_BLINK_RATE      (20)
+#define STI_DEF_FONT   sticon_sti->font
 
-static int vbl_cursor_cnt;
+/* borrowed from fbcon.c */
+#define FNTREFCOUNT(fd)        (fd->refcount)
+#define FNTCRC(fd)     (fd->crc)
+static struct sti_cooked_font *font_data[MAX_NR_CONSOLES];
 
-static inline void cursor_undrawn(void)
-{
-    vbl_cursor_cnt = 0;
-    cursor_drawn = 0;
-}
+/* this is the sti_struct used for this console */
+static struct sti_struct *sticon_sti;
 
 static const char *sticon_startup(void)
 {
@@ -81,61 +72,43 @@ static const char *sticon_startup(void)
 
 static void sticon_putc(struct vc_data *conp, int c, int ypos, int xpos)
 {
-    int redraw_cursor = 0;
-
     if (vga_is_gfx || console_blanked)
            return;
 
     if (conp->vc_mode != KD_TEXT)
            return;
-#if 0
-    if ((p->cursor_x == xpos) && (p->cursor_y == ypos)) {
-           cursor_undrawn();
-           redraw_cursor = 1;
-    }
-#endif
-
-    sti_putc(sticon_sti, c, ypos, xpos);
 
-    if (redraw_cursor)
-           vbl_cursor_cnt = CURSOR_DRAW_DELAY;
+    sti_putc(sticon_sti, c, ypos, xpos, font_data[conp->vc_num]);
 }
 
 static void sticon_putcs(struct vc_data *conp, const unsigned short *s,
                         int count, int ypos, int xpos)
 {
-    int redraw_cursor = 0;
-
     if (vga_is_gfx || console_blanked)
            return;
 
     if (conp->vc_mode != KD_TEXT)
            return;
 
-#if 0
-    if ((p->cursor_y == ypos) && (xpos <= p->cursor_x) &&
-       (p->cursor_x < (xpos + count))) {
-           cursor_undrawn();
-           redraw_cursor = 1;
-    }
-#endif
-
     while (count--) {
-       sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++);
+       sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++,
+                font_data[conp->vc_num]);
     }
-
-    if (redraw_cursor)
-           vbl_cursor_cnt = CURSOR_DRAW_DELAY;
 }
 
 static void sticon_cursor(struct vc_data *conp, int mode)
 {
     unsigned short car1;
 
+    /* no cursor update if screen is blanked */
+    if (vga_is_gfx || console_blanked)
+       return;
+
     car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];
     switch (mode) {
     case CM_ERASE:
-       sti_putc(sticon_sti, car1, conp->state.y, conp->state.x);
+       sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,
+                font_data[conp->vc_num]);
        break;
     case CM_MOVE:
     case CM_DRAW:
@@ -146,7 +119,7 @@ static void sticon_cursor(struct vc_data *conp, int mode)
        case CUR_TWO_THIRDS:
        case CUR_BLOCK:
            sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),
-                    conp->state.y, conp->state.x);
+                    conp->state.y, conp->state.x, font_data[conp->vc_num]);
            break;
        }
        break;
@@ -165,42 +138,164 @@ static bool sticon_scroll(struct vc_data *conp, unsigned int t,
 
     switch (dir) {
     case SM_UP:
-       sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
-       sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+       sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols,
+                 font_data[conp->vc_num]);
+       sti_clear(sti, b - count, 0, count, conp->vc_cols,
+                 conp->vc_video_erase_char, font_data[conp->vc_num]);
        break;
 
     case SM_DOWN:
-       sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
-       sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+       sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols,
+                 font_data[conp->vc_num]);
+       sti_clear(sti, t, 0, count, conp->vc_cols,
+                 conp->vc_video_erase_char, font_data[conp->vc_num]);
        break;
     }
 
     return false;
 }
 
+static int sticon_set_def_font(int unit, struct console_font *op)
+{
+       if (font_data[unit] != STI_DEF_FONT) {
+               if (--FNTREFCOUNT(font_data[unit]) == 0) {
+                       kfree(font_data[unit]->raw_ptr);
+                       kfree(font_data[unit]);
+               }
+               font_data[unit] = STI_DEF_FONT;
+       }
+
+       return 0;
+}
+
+static int sticon_set_font(struct vc_data *vc, struct console_font *op)
+{
+       struct sti_struct *sti = sticon_sti;
+       int vc_cols, vc_rows, vc_old_cols, vc_old_rows;
+       int unit = vc->vc_num;
+       int w = op->width;
+       int h = op->height;
+       int size, i, bpc, pitch;
+       struct sti_rom_font *new_font;
+       struct sti_cooked_font *cooked_font;
+       unsigned char *data = op->data, *p;
+
+       if ((w < 6) || (h < 6) || (w > 32) || (h > 32)
+           || (op->charcount != 256 && op->charcount != 512))
+               return -EINVAL;
+       pitch = ALIGN(w, 8) / 8;
+       bpc = pitch * h;
+       size = bpc * op->charcount;
+
+       new_font = kmalloc(sizeof(*new_font) + size, STI_LOWMEM);
+       if (!new_font)
+               return -ENOMEM;
+
+       new_font->first_char = 0;
+       new_font->last_char = op->charcount - 1;
+       new_font->width = w;
+       new_font->height = h;
+       new_font->font_type = STI_FONT_HPROMAN8;
+       new_font->bytes_per_char = bpc;
+       new_font->underline_height = 0;
+       new_font->underline_pos = 0;
+
+       cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);
+       if (!cooked_font) {
+               kfree(new_font);
+               return -ENOMEM;
+       }
+       cooked_font->raw = new_font;
+       cooked_font->raw_ptr = new_font;
+       cooked_font->width = w;
+       cooked_font->height = h;
+       FNTREFCOUNT(cooked_font) = 0;   /* usage counter */
+
+       p = (unsigned char *) new_font;
+       p += sizeof(*new_font);
+       for (i = 0; i < op->charcount; i++) {
+               memcpy(p, data, bpc);
+               data += pitch*32;
+               p += bpc;
+       }
+       FNTCRC(cooked_font) = crc32(0, new_font, size + sizeof(*new_font));
+       sti_font_convert_bytemode(sti, cooked_font);
+       new_font = cooked_font->raw_ptr;
+
+       /* check if font is already used by other console */
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (font_data[i] != STI_DEF_FONT
+                   && (FNTCRC(font_data[i]) == FNTCRC(cooked_font))) {
+                       kfree(new_font);
+                       kfree(cooked_font);
+                       /* current font is the same as the new one */
+                       if (i == unit)
+                               return 0;
+                       cooked_font = font_data[i];
+                       new_font = cooked_font->raw_ptr;
+                       break;
+               }
+       }
+
+       /* clear screen with old font: we now may have less rows */
+       vc_old_rows = vc->vc_rows;
+       vc_old_cols = vc->vc_cols;
+       sti_clear(sticon_sti, 0, 0, vc_old_rows, vc_old_cols,
+                 vc->vc_video_erase_char, font_data[vc->vc_num]);
+
+       /* delete old font in case it is a user font */
+       sticon_set_def_font(unit, NULL);
+
+       FNTREFCOUNT(cooked_font)++;
+       font_data[unit] = cooked_font;
+
+       vc_cols = sti_onscreen_x(sti) / cooked_font->width;
+       vc_rows = sti_onscreen_y(sti) / cooked_font->height;
+       vc_resize(vc, vc_cols, vc_rows);
+
+       /* need to repaint screen if cols & rows are same as old font */
+       if (vc_cols == vc_old_cols && vc_rows == vc_old_rows)
+               update_screen(vc);
+
+       return 0;
+}
+
+static int sticon_font_default(struct vc_data *vc, struct console_font *op, char *name)
+{
+       return sticon_set_def_font(vc->vc_num, op);
+}
+
+static int sticon_font_set(struct vc_data *vc, struct console_font *font,
+                          unsigned int flags)
+{
+       return sticon_set_font(vc, font);
+}
+
 static void sticon_init(struct vc_data *c, int init)
 {
     struct sti_struct *sti = sticon_sti;
     int vc_cols, vc_rows;
 
     sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);
-    vc_cols = sti_onscreen_x(sti) / sti->font_width;
-    vc_rows = sti_onscreen_y(sti) / sti->font_height;
+    vc_cols = sti_onscreen_x(sti) / sti->font->width;
+    vc_rows = sti_onscreen_y(sti) / sti->font->height;
     c->vc_can_do_color = 1;
     
     if (init) {
        c->vc_cols = vc_cols;
        c->vc_rows = vc_rows;
     } else {
-       /* vc_rows = (c->vc_rows > vc_rows) ? vc_rows : c->vc_rows; */
-       /* vc_cols = (c->vc_cols > vc_cols) ? vc_cols : c->vc_cols; */
        vc_resize(c, vc_cols, vc_rows);
-/*     vc_resize_con(vc_rows, vc_cols, c->vc_num); */
     }
 }
 
 static void sticon_deinit(struct vc_data *c)
 {
+    int i;
+
+    /* free memory used by user font */
+    for (i = 0; i < MAX_NR_CONSOLES; i++)
+       sticon_set_def_font(i, NULL);
 }
 
 static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
@@ -209,7 +304,8 @@ static void sticon_clear(struct vc_data *conp, int sy, int sx, int height,
     if (!height || !width)
        return;
 
-    sti_clear(sticon_sti, sy, sx, height, width, conp->vc_video_erase_char);
+    sti_clear(sticon_sti, sy, sx, height, width,
+             conp->vc_video_erase_char, font_data[conp->vc_num]);
 }
 
 static int sticon_switch(struct vc_data *conp)
@@ -224,64 +320,13 @@ static int sticon_blank(struct vc_data *c, int blank, int mode_switch)
            vga_is_gfx = 0;
        return 1;
     }
-    sti_clear(sticon_sti, 0,0, c->vc_rows, c->vc_cols, BLANK);
+    sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,
+             font_data[c->vc_num]);
     if (mode_switch)
        vga_is_gfx = 1;
     return 1;
 }
 
-static u16 *sticon_screen_pos(const struct vc_data *conp, int offset)
-{
-    int line;
-    unsigned long p;
-
-    if (conp->vc_num != fg_console || !softback_lines)
-       return (u16 *)(conp->vc_origin + offset);
-    line = offset / conp->vc_size_row;
-    if (line >= softback_lines)
-       return (u16 *)(conp->vc_origin + offset - softback_lines * conp->vc_size_row);
-    p = softback_curr + offset;
-    if (p >= softback_end)
-       p += softback_buf - softback_end;
-    return (u16 *)p;
-}
-
-static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
-                                 int *px, int *py)
-{
-    int x, y;
-    unsigned long ret;
-    if (pos >= conp->vc_origin && pos < conp->vc_scr_end) {
-       unsigned long offset = (pos - conp->vc_origin) / 2;
-       
-       x = offset % conp->vc_cols;
-       y = offset / conp->vc_cols;
-       if (conp->vc_num == fg_console)
-           y += softback_lines;
-       ret = pos + (conp->vc_cols - x) * 2;
-    } else if (conp->vc_num == fg_console && softback_lines) {
-       unsigned long offset = pos - softback_curr;
-       
-       if (pos < softback_curr)
-           offset += softback_end - softback_buf;
-       offset /= 2;
-       x = offset % conp->vc_cols;
-       y = offset / conp->vc_cols;
-       ret = pos + (conp->vc_cols - x) * 2;
-       if (ret == softback_end)
-           ret = softback_buf;
-       if (ret == softback_in)
-           ret = conp->vc_origin;
-    } else {
-       /* Should not happen */
-       x = y = 0;
-       ret = conp->vc_origin;
-    }
-    if (px) *px = x;
-    if (py) *py = y;
-    return ret;
-}
-
 static u8 sticon_build_attr(struct vc_data *conp, u8 color,
                            enum vc_intensity intens,
                            bool blink, bool underline, bool reverse,
@@ -312,10 +357,6 @@ static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)
     }
 }
 
-static void sticon_save_screen(struct vc_data *conp)
-{
-}
-
 static const struct consw sti_con = {
        .owner                  = THIS_MODULE,
        .con_startup            = sticon_startup,
@@ -328,18 +369,18 @@ static const struct consw sti_con = {
        .con_scroll             = sticon_scroll,
        .con_switch             = sticon_switch,
        .con_blank              = sticon_blank,
-       .con_save_screen        = sticon_save_screen, 
+       .con_font_set           = sticon_font_set,
+       .con_font_default       = sticon_font_default,
        .con_build_attr         = sticon_build_attr,
        .con_invert_region      = sticon_invert_region, 
-       .con_screen_pos         = sticon_screen_pos,
-       .con_getxy              = sticon_getxy,
 };
 
 
 
 static int __init sticonsole_init(void)
 {
-    int err;
+    int err, i;
+
     /* already initialized ? */
     if (sticon_sti)
         return 0;
@@ -348,6 +389,9 @@ static int __init sticonsole_init(void)
     if (!sticon_sti)
        return -ENODEV;
 
+    for (i = 0; i < MAX_NR_CONSOLES; i++)
+       font_data[i] = STI_DEF_FONT;
+
     pr_info("sticon: Initializing STI text console.\n");
     console_lock();
     err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1,
index 84c3ca3..6a26a36 100644 (file)
@@ -4,7 +4,7 @@
  *     core code for console driver using HP's STI firmware
  *
  *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *     Copyright (C) 2001-2013 Helge Deller <deller@gmx.de>
+ *     Copyright (C) 2001-2020 Helge Deller <deller@gmx.de>
  *     Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
  * 
  * TODO:
@@ -14,6 +14,8 @@
  * 
  */
 
+#define pr_fmt(fmt) "%s: " fmt, KBUILD_MODNAME
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -133,16 +135,17 @@ static const struct sti_font_flags default_font_flags = {
 };
 
 void
-sti_putc(struct sti_struct *sti, int c, int y, int x)
+sti_putc(struct sti_struct *sti, int c, int y, int x,
+        struct sti_cooked_font *font)
 {
        struct sti_font_inptr *inptr = &sti->sti_data->font_inptr;
        struct sti_font_inptr inptr_default = {
-               .font_start_addr= STI_PTR(sti->font->raw),
+               .font_start_addr = STI_PTR(font->raw),
                .index          = c_index(sti, c),
                .fg_color       = c_fg(sti, c),
                .bg_color       = c_bg(sti, c),
-               .dest_x         = x * sti->font_width,
-               .dest_y         = y * sti->font_height,
+               .dest_x         = x * font->width,
+               .dest_y         = y * font->height,
        };
        struct sti_font_outptr *outptr = &sti->sti_data->font_outptr;
        s32 ret;
@@ -193,18 +196,18 @@ sti_set(struct sti_struct *sti, int src_y, int src_x,
 
 void
 sti_clear(struct sti_struct *sti, int src_y, int src_x,
-         int height, int width, int c)
+         int height, int width, int c, struct sti_cooked_font *font)
 {
        struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr;
        struct sti_blkmv_inptr inptr_default = {
                .fg_color       = c_fg(sti, c),
                .bg_color       = c_bg(sti, c),
-               .src_x          = src_x * sti->font_width,
-               .src_y          = src_y * sti->font_height,
-               .dest_x         = src_x * sti->font_width,
-               .dest_y         = src_y * sti->font_height,
-               .width          = width * sti->font_width,
-               .height         = height* sti->font_height,
+               .src_x          = src_x * font->width,
+               .src_y          = src_y * font->height,
+               .dest_x         = src_x * font->width,
+               .dest_y         = src_y * font->height,
+               .width          = width * font->width,
+               .height         = height * font->height,
        };
        struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr;
        s32 ret;
@@ -225,16 +228,17 @@ static const struct sti_blkmv_flags default_blkmv_flags = {
 
 void
 sti_bmove(struct sti_struct *sti, int src_y, int src_x,
-         int dst_y, int dst_x, int height, int width)
+         int dst_y, int dst_x, int height, int width,
+         struct sti_cooked_font *font)
 {
        struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr;
        struct sti_blkmv_inptr inptr_default = {
-               .src_x          = src_x * sti->font_width,
-               .src_y          = src_y * sti->font_height,
-               .dest_x         = dst_x * sti->font_width,
-               .dest_y         = dst_y * sti->font_height,
-               .width          = width * sti->font_width,
-               .height         = height* sti->font_height,
+               .src_x          = src_x * font->width,
+               .src_y          = src_y * font->height,
+               .dest_x         = dst_x * font->width,
+               .dest_y         = dst_y * font->height,
+               .width          = width * font->width,
+               .height         = height * font->height,
        };
        struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr;
        s32 ret;
@@ -301,36 +305,32 @@ __setup("sti=", sti_setup);
 
 
 
-static char *font_name[MAX_STI_ROMS];
-static int font_index[MAX_STI_ROMS],
-          font_height[MAX_STI_ROMS],
-          font_width[MAX_STI_ROMS];
+static char *font_name;
+static int font_index,
+          font_height,
+          font_width;
 #ifndef MODULE
 static int sti_font_setup(char *str)
 {
-       char *x;
-       int i = 0;
+       /*
+        * The default font can be selected in various ways.
+        * a) sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 selects
+        *    an built-in Linux framebuffer font.
+        * b) sti_font=<index>, where index is (1..x) with 1 selecting
+        *    the first HP STI ROM built-in font..
+        */
 
-       /* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
-        * or sti_font=7 style command lines. */
+       if (*str >= '0' && *str <= '9') {
+               char *x;
 
-       while (i<MAX_STI_ROMS && str && *str) {
-               if (*str>='0' && *str<='9') {
-                       if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
-                               font_height[i] = simple_strtoul(str, NULL, 0);
-                               font_width[i] = simple_strtoul(x+1, NULL, 0);
-                       } else {
-                               font_index[i] = simple_strtoul(str, NULL, 0);
-                       }
+               if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
+                       font_height = simple_strtoul(str, NULL, 0);
+                       font_width = simple_strtoul(x+1, NULL, 0);
                } else {
-                       font_name[i] = str;     /* fb font name */
+                       font_index = simple_strtoul(str, NULL, 0);
                }
-
-               if ((x = strchr(str, ',')))
-                       *x++ = 0;
-               str = x;
-
-               i++;
+       } else {
+               font_name = str;        /* fb font name */
        }
 
        return 1;
@@ -344,7 +344,7 @@ static int sti_font_setup(char *str)
  *             framebuffer font names (e.g. VGA8x16, SUN22x18). 
  *             This is only available if the fonts have been statically compiled 
  *             in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
- *     - sti_font=<number>
+ *     - sti_font=<number>     (<number> = 1,2,3,...)
  *             most STI ROMs have built-in HP specific fonts, which can be selected
  *             by giving the desired number to the sticon driver. 
  *             NOTE: This number is machine and STI ROM dependend.
@@ -364,8 +364,7 @@ static void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg,
 {
        struct sti_glob_cfg_ext *cfg;
        
-       DPRINTK((KERN_INFO
-               "%d text planes\n"
+       pr_debug("%d text planes\n"
                "%4d x %4d screen resolution\n"
                "%4d x %4d offscreen\n"
                "%4d x %4d layout\n"
@@ -382,12 +381,11 @@ static void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg,
                glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
                glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
                glob_cfg->reent_lvl,
-               glob_cfg->save_addr));
+               glob_cfg->save_addr);
 
        /* dump extended cfg */ 
        cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
-       DPRINTK(( KERN_INFO
-               "monitor %d\n"
+       pr_debug("monitor %d\n"
                "in friendly mode: %d\n"
                "power consumption %d watts\n"
                "freq ref %d\n"
@@ -396,20 +394,19 @@ static void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg,
                cfg->friendly_boot,
                cfg->power,
                cfg->freq_ref,
-               cfg->sti_mem_addr, sti_mem_request));
+               cfg->sti_mem_addr, sti_mem_request);
 }
 
 static void sti_dump_outptr(struct sti_struct *sti)
 {
-       DPRINTK((KERN_INFO
-               "%d bits per pixel\n"
+       pr_debug("%d bits per pixel\n"
                "%d used bits\n"
                "%d planes\n"
                "attributes %08x\n",
                 sti->sti_data->inq_outptr.bits_per_pixel,
                 sti->sti_data->inq_outptr.bits_used,
                 sti->sti_data->inq_outptr.planes,
-                sti->sti_data->inq_outptr.attributes));
+                sti->sti_data->inq_outptr.attributes);
 }
 
 static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
@@ -448,8 +445,7 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
                        if (offs != PCI_ROM_ADDRESS &&
                            (offs < PCI_BASE_ADDRESS_0 ||
                             offs > PCI_BASE_ADDRESS_5)) {
-                               printk (KERN_WARNING
-                                       "STI pci region mapping for region %d (%02x) can't be mapped\n",
+                               pr_warn("STI pci region mapping for region %d (%02x) can't be mapped\n",
                                        i,sti->rm_entry[i]);
                                continue;
                        }
@@ -464,14 +460,14 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
                if (len)
                        glob_cfg->region_ptrs[i] = sti->regions_phys[i];
                
-               DPRINTK(("region #%d: phys %08lx, region_ptr %08x, len=%lukB, "
+               pr_debug("region #%d: phys %08lx, region_ptr %08x, len=%lukB, "
                         "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
                        i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
                        len/1024,
                        sti->regions[i].region_desc.btlb,
                        sti->regions[i].region_desc.sys_only,
                        sti->regions[i].region_desc.cache, 
-                       sti->regions[i].region_desc.last));
+                       sti->regions[i].region_desc.last);
 
                /* last entry reached ? */
                if (sti->regions[i].region_desc.last)
@@ -479,8 +475,8 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
        }
 
        if (++i<8 && sti->regions[i].region)
-               printk(KERN_WARNING "%s: *future ptr (0x%8x) not yet supported !\n",
-                               __FILE__, sti->regions[i].region);
+               pr_warn("future ptr (0x%8x) not yet supported !\n",
+                       sti->regions[i].region);
 
        glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
 
@@ -538,6 +534,7 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
        }
        
        cooked_font->raw = nf;
+       cooked_font->raw_ptr = nf;
        cooked_font->next_font = NULL;
 
        cooked_rom->font_start = cooked_font;
@@ -552,24 +549,38 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
 }
 #endif
 
-static struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom,
-               int (*search_font_fnc)(struct sti_cooked_rom *, int, int))
+static int sti_search_font(struct sti_cooked_rom *rom, int height, int width)
+{
+       struct sti_cooked_font *font;
+       int i = 0;
+
+       for (font = rom->font_start; font; font = font->next_font, i++) {
+               if ((font->raw->width == width) &&
+                   (font->raw->height == height))
+                       return i;
+       }
+       return 0;
+}
+
+static struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom)
 {
        struct sti_cooked_font *font;
        int i;
-       int index = num_sti_roms;
 
        /* check for framebuffer-font first */
-       if ((font = sti_select_fbfont(rom, font_name[index])))
-               return font;
+       if (!font_index) {
+               font = sti_select_fbfont(rom, font_name);
+               if (font)
+                       return font;
+       }
 
-       if (font_width[index] && font_height[index])
-               font_index[index] = search_font_fnc(rom, 
-                               font_height[index], font_width[index]);
+       if (font_width && font_height)
+               font_index = sti_search_font(rom,
+                               font_height, font_width);
 
-       for (font = rom->font_start, i = font_index[index];
-           font && (i > 0);
-           font = font->next_font, i--);
+       for (font = rom->font_start, i = font_index - 1;
+               font && (i > 0);
+               font = font->next_font, i--);
 
        if (font)
                return font;
@@ -578,20 +589,35 @@ static struct sti_cooked_font *sti_select_font(struct sti_cooked_rom *rom,
 }
 
 
-static void sti_dump_rom(struct sti_rom *rom)
+static void sti_dump_rom(struct sti_struct *sti)
 {
-       printk(KERN_INFO "    id %04x-%04x, conforms to spec rev. %d.%02x\n",
+       struct sti_rom *rom = sti->rom->raw;
+       struct sti_cooked_font *font_start;
+       int nr;
+
+       pr_info("  id %04x-%04x, conforms to spec rev. %d.%02x\n",
                rom->graphics_id[0], 
                rom->graphics_id[1],
                rom->revno[0] >> 4, 
                rom->revno[0] & 0x0f);
-       DPRINTK(("      supports %d monitors\n", rom->num_mons));
-       DPRINTK(("      font start %08x\n", rom->font_start));
-       DPRINTK(("      region list %08x\n", rom->region_list));
-       DPRINTK(("      init_graph %08x\n", rom->init_graph));
-       DPRINTK(("      bus support %02x\n", rom->bus_support));
-       DPRINTK(("      ext bus support %02x\n", rom->ext_bus_support));
-       DPRINTK(("      alternate code type %d\n", rom->alt_code_type));
+       pr_debug("  supports %d monitors\n", rom->num_mons);
+       pr_debug("  font start %08x\n", rom->font_start);
+       pr_debug("  region list %08x\n", rom->region_list);
+       pr_debug("  init_graph %08x\n", rom->init_graph);
+       pr_debug("  bus support %02x\n", rom->bus_support);
+       pr_debug("  ext bus support %02x\n", rom->ext_bus_support);
+       pr_debug("  alternate code type %d\n", rom->alt_code_type);
+
+       font_start = sti->rom->font_start;
+       nr = 0;
+       while (font_start) {
+               struct sti_rom_font *f = font_start->raw;
+
+               pr_info("    built-in font #%d: size %dx%d, chars %d-%d, bpc %d\n", ++nr,
+                       f->width, f->height,
+                       f->first_char, f->last_char, f->bytes_per_char);
+               font_start = font_start->next_font;
+       }
 }
 
 
@@ -628,39 +654,34 @@ static int sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
        return 1;
 }
 
-
-static int sti_search_font(struct sti_cooked_rom *rom, int height, int width)
-{
-       struct sti_cooked_font *font;
-       int i = 0;
-       
-       for (font = rom->font_start; font; font = font->next_font, i++) {
-               if ((font->raw->width == width) &&
-                   (font->raw->height == height))
-                       return i;
-       }
-       return 0;
-}
-
 #define BMODE_RELOCATE(offset)         offset = (offset) / 4;
 #define BMODE_LAST_ADDR_OFFS           0x50
 
-static void *sti_bmode_font_raw(struct sti_cooked_font *f)
+void sti_font_convert_bytemode(struct sti_struct *sti, struct sti_cooked_font *f)
 {
        unsigned char *n, *p, *q;
-       int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
-       
+       int size = f->raw->bytes_per_char * 256 + sizeof(struct sti_rom_font);
+       struct sti_rom_font *old_font;
+
+       if (sti->wordmode)
+               return;
+
+       old_font = f->raw_ptr;
        n = kcalloc(4, size, STI_LOWMEM);
+       f->raw_ptr = n;
        if (!n)
-               return NULL;
+               return;
        p = n + 3;
-       q = (unsigned char *)f->raw;
+       q = (unsigned char *) f->raw;
        while (size--) {
                *p = *q++;
-               p+=4;
+               p += 4;
        }
-       return n + 3;
+       /* store new ptr to byte-mode font and delete old font */
+       f->raw = (struct sti_rom_font *) (n + 3);
+       kfree(old_font);
 }
+EXPORT_SYMBOL(sti_font_convert_bytemode);
 
 static void sti_bmode_rom_copy(unsigned long base, unsigned long count,
                               void *dest)
@@ -747,7 +768,7 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti,
                goto out_err;
 
        if (!sti_cook_fonts(cooked, raw)) {
-               printk(KERN_ERR "No font found for STI at %08lx\n", address);
+               pr_warn("No font found for STI at %08lx\n", address);
                goto out_err;
        }
 
@@ -756,7 +777,8 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti,
 
        address = (unsigned long) STI_PTR(raw);
 
-       pr_info("STI ROM supports 32 %sbit firmware functions.\n",
+       pr_info("STI %s ROM supports 32 %sbit firmware functions.\n",
+               wordmode ? "word mode" : "byte mode",
                raw->alt_code_type == ALT_CODE_TYPE_PA_RISC_64
                ? "and 64 " : "");
 
@@ -767,18 +789,17 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti,
 
        sti->rom = cooked;
        sti->rom->raw = raw;
-       
-       sti->font = sti_select_font(sti->rom, sti_search_font);
-       sti->font_width = sti->font->raw->width;
-       sti->font_height = sti->font->raw->height;
-       if (!wordmode)
-               sti->font->raw = sti_bmode_font_raw(sti->font);
+       sti_dump_rom(sti);
+
+       sti->wordmode = wordmode;
+       sti->font = sti_select_font(sti->rom);
+       sti->font->width = sti->font->raw->width;
+       sti->font->height = sti->font->raw->height;
+       sti_font_convert_bytemode(sti, sti->font);
 
        sti->sti_mem_request = raw->sti_mem_req;
        sti->graphics_id[0] = raw->graphics_id[0];
        sti->graphics_id[1] = raw->graphics_id[1];
-       
-       sti_dump_rom(raw);
 
        /* check if the ROM routines in this card are compatible */
        if (wordmode || sti->graphics_id[1] != 0x09A02587)
@@ -804,9 +825,9 @@ ok:
        return 1;
 
 msg_not_supported:
-       printk(KERN_ERR "Sorry, this GSC/STI card is not yet supported.\n");
-       printk(KERN_ERR "Please see http://parisc-linux.org/faq/"
-                       "graphics-howto.html for more info.\n");
+       pr_warn("Sorry, this GSC/STI card is not yet supported.\n");
+       pr_warn("Please see https://parisc.wiki.kernel.org/"
+               "index.php/Graphics_howto for more info.\n");
        /* fall through */
 out_err:
        kfree(raw);
@@ -823,7 +844,7 @@ static struct sti_struct *sti_try_rom_generic(unsigned long address,
        u32 sig;
 
        if (num_sti_roms >= MAX_STI_ROMS) {
-               printk(KERN_WARNING "maximum number of STI ROMS reached !\n");
+               pr_warn("maximum number of STI ROMS reached !\n");
                return NULL;
        }
        
@@ -849,16 +870,15 @@ test_rom:
                if (i != 1) {
                        /* The ROM could have multiple architecture 
                         * dependent images (e.g. i386, parisc,...) */
-                       printk(KERN_WARNING 
-                               "PCI ROM is not a STI ROM type image (0x%8x)\n", i);
+                       pr_warn("PCI ROM is not a STI ROM type image (0x%8x)\n", i);
                        goto out_err;
                }
                
                sti->pd = pd;
 
                i = gsc_readl(address+0x0c);
-               DPRINTK(("PCI ROM size (from header) = %d kB\n",
-                       le16_to_cpu(i>>16)*512/1024));
+               pr_debug("PCI ROM size (from header) = %d kB\n",
+                       le16_to_cpu(i>>16)*512/1024);
                rm_offset = le16_to_cpu(i & 0xffff);
                if (rm_offset) { 
                        /* read 16 bytes from the pci region mapper array */
@@ -867,29 +887,24 @@ test_rom:
                        *rm++ = gsc_readl(address+rm_offset+0x04);
                        *rm++ = gsc_readl(address+rm_offset+0x08);
                        *rm++ = gsc_readl(address+rm_offset+0x0c);
-                       DPRINTK(("PCI region Mapper offset = %08x: ",
-                               rm_offset));
-                       for (i=0; i<16; i++)
-                               DPRINTK(("%02x ", sti->rm_entry[i]));
-                       DPRINTK(("\n"));
                }
 
                address += le32_to_cpu(gsc_readl(address+8));
-               DPRINTK(("sig %04x, PCI STI ROM at %08lx\n", sig, address));
+               pr_debug("sig %04x, PCI STI ROM at %08lx\n", sig, address);
                goto test_rom;
        }
        
        ok = 0;
        
        if ((sig & 0xff) == 0x01) {
-               DPRINTK(("    byte mode ROM at %08lx, hpa at %08lx\n",
-                      address, hpa));
+               pr_debug("    byte mode ROM at %08lx, hpa at %08lx\n",
+                      address, hpa);
                ok = sti_read_rom(0, sti, address);
        }
 
        if ((sig & 0xffff) == 0x0303) {
-               DPRINTK(("    word mode ROM at %08lx, hpa at %08lx\n",
-                      address, hpa));
+               pr_debug("    word mode ROM at %08lx, hpa at %08lx\n",
+                      address, hpa);
                ok = sti_read_rom(1, sti, address);
        }
 
@@ -906,7 +921,7 @@ test_rom:
                unsigned long rom_base;
                rom_base = pci_resource_start(sti->pd, PCI_ROM_RESOURCE);       
                pci_write_config_dword(sti->pd, PCI_ROM_ADDRESS, rom_base & ~PCI_ROM_ADDRESS_ENABLE);
-               DPRINTK((KERN_DEBUG "STI PCI ROM disabled\n"));
+               pr_debug("STI PCI ROM disabled\n");
        }
 
        if (sti_init_graph(sti))
@@ -981,14 +996,14 @@ static int sticore_pci_init(struct pci_dev *pd, const struct pci_device_id *ent)
        rom_len = pci_resource_len(pd, PCI_ROM_RESOURCE);
        if (rom_base) {
                pci_write_config_dword(pd, PCI_ROM_ADDRESS, rom_base | PCI_ROM_ADDRESS_ENABLE);
-               DPRINTK((KERN_DEBUG "STI PCI ROM enabled at 0x%08lx\n", rom_base));
+               pr_debug("STI PCI ROM enabled at 0x%08lx\n", rom_base);
        }
 
-       printk(KERN_INFO "STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n",
+       pr_info("STI PCI graphic ROM found at %08lx (%u kB), fb at %08lx (%u MB)\n",
                rom_base, rom_len/1024, fb_base, fb_len/1024/1024);
 
-       DPRINTK((KERN_DEBUG "Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n",
-                   rom_base, fb_base));
+       pr_debug("Trying PCI STI ROM at %08lx, PCI hpa at %08lx\n",
+                   rom_base, fb_base);
 
        sti = sti_try_rom_generic(rom_base, fb_base, pd);
        if (sti) {
@@ -998,8 +1013,7 @@ static int sticore_pci_init(struct pci_dev *pd, const struct pci_device_id *ent)
        }
        
        if (!sti) {
-               printk(KERN_WARNING "Unable to handle STI device '%s'\n",
-                       pci_name(pd));
+               pr_warn("Unable to handle STI device '%s'\n", pci_name(pd));
                return -ENODEV;
        }
 #endif /* CONFIG_PCI */
@@ -1058,7 +1072,7 @@ static void sti_init_roms(void)
 
        sticore_initialized = 1;
 
-       printk(KERN_INFO "STI GSC/PCI core graphics driver "
+       pr_info("STI GSC/PCI core graphics driver "
                        STI_DRIVERVERSION "\n");
 
        /* Register drivers for native & PCI cards */
index fb8f58f..c338f78 100644 (file)
@@ -4,12 +4,6 @@
 
 /* generic STI structures & functions */
 
-#if 0
-#define DPRINTK(x)     printk x
-#else
-#define DPRINTK(x) 
-#endif
-
 #define MAX_STI_ROMS 4         /* max no. of ROMs which this driver handles */
 
 #define STI_REGION_MAX 8       /* hardcoded STI constants */
@@ -246,8 +240,12 @@ struct sti_rom_font {
 /* sticore internal font handling */
 
 struct sti_cooked_font {
-        struct sti_rom_font *raw;
+       struct sti_rom_font *raw;       /* native ptr for STI functions */
+       void *raw_ptr;                  /* kmalloc'ed font data */
        struct sti_cooked_font *next_font;
+       int height, width;
+       int refcount;
+       u32 crc;
 };
 
 struct sti_cooked_rom {
@@ -341,9 +339,6 @@ struct sti_all_data {
 struct sti_struct {
        spinlock_t lock;
                
-       /* the following fields needs to be filled in by the word/byte routines */
-       int font_width; 
-       int font_height;
        /* char **mon_strings; */
        int sti_mem_request;
        u32 graphics_id[2];
@@ -362,6 +357,7 @@ struct sti_struct {
 
        struct sti_glob_cfg *glob_cfg;  /* points into sti_all_data */
 
+       int wordmode;
        struct sti_cooked_font *font;   /* ptr to selected font (cooked) */
 
        struct pci_dev *pd;
@@ -380,6 +376,7 @@ struct sti_struct {
 /* sticore interface functions */
 
 struct sti_struct *sti_get_rom(unsigned int index); /* 0: default sti */
+void sti_font_convert_bytemode(struct sti_struct *sti, struct sti_cooked_font *f);
 
 
 /* sticore main function to call STI firmware */
@@ -391,12 +388,14 @@ int sti_call(const struct sti_struct *sti, unsigned long func,
 
 /* functions to call the STI ROM directly */
 
-void sti_putc(struct sti_struct *sti, int c, int y, int x);
+void sti_putc(struct sti_struct *sti, int c, int y, int x,
+               struct sti_cooked_font *font);
 void sti_set(struct sti_struct *sti, int src_y, int src_x,
-            int height, int width, u8 color);
+               int height, int width, u8 color);
 void sti_clear(struct sti_struct *sti, int src_y, int src_x,
-              int height, int width, int c);
+               int height, int width, int c, struct sti_cooked_font *font);
 void sti_bmove(struct sti_struct *sti, int src_y, int src_x,
-              int dst_y, int dst_x, int height, int width);
+               int dst_y, int dst_x, int height, int width,
+               struct sti_cooked_font *font);
 
 #endif /* STICORE_H */