diff options
Diffstat (limited to 'drivers/video/console/sticon.c')
-rw-r--r-- | drivers/video/console/sticon.c | 282 |
1 files changed, 163 insertions, 119 deletions
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 7c1dcd526600..1b451165311c 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -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> @@ -52,27 +55,15 @@ #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, |