Commit 7ff3f14d authored by Helge Deller's avatar Helge Deller
Browse files

parisc/sticon: Add user font support



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: default avatarHelge Deller <deller@gmx.de>
parent 58a5c67a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+163 −119
Original line number Diff line number Diff line
@@ -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,
+149 −135

File changed.

Preview size limit exceeded, changes collapsed.

+13 −14
Original line number Diff line number Diff line
@@ -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);
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 */