396 lines · c
1/*2 * linux/drivers/video/console/sticon.c - console driver using HP's STI firmware3 *4 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>5 * Copyright (C) 2002-2020 Helge Deller <deller@gmx.de>6 *7 * Based on linux/drivers/video/vgacon.c and linux/drivers/video/fbcon.c,8 * which were9 *10 * Created 28 Sep 1997 by Geert Uytterhoeven11 * Rewritten by Martin Mares <mj@ucw.cz>, July 199812 * Copyright (C) 1991, 1992 Linus Torvalds13 * 1995 Jay Estabrook14 * Copyright (C) 1995 Geert Uytterhoeven15 * Copyright (C) 1993 Bjoern Brauel16 * Roman Hodek17 * Copyright (C) 1993 Hamish Macdonald18 * Greg Harp19 * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk]20 *21 * with work by William Rucklidge (wjr@cs.cornell.edu)22 * Geert Uytterhoeven23 * Jes Sorensen (jds@kom.auc.dk)24 * Martin Apel25 * with work by Guenther Kelleter26 * Martin Schaller27 * Andreas Schwab28 * Emmanuel Marty (core@ggi-project.org)29 * Jakub Jelinek (jj@ultra.linux.cz)30 * Martin Mares <mj@ucw.cz>31 *32 * This file is subject to the terms and conditions of the GNU General Public33 * License. See the file COPYING in the main directory of this archive for34 * more details.35 *36 */37 38#include <linux/init.h>39#include <linux/kernel.h>40#include <linux/console.h>41#include <linux/errno.h>42#include <linux/vt_kern.h>43#include <linux/kd.h>44#include <linux/selection.h>45#include <linux/module.h>46#include <linux/slab.h>47#include <linux/font.h>48#include <linux/crc32.h>49#include <linux/fb.h>50 51#include <asm/io.h>52 53#include <video/sticore.h>54 55/* switching to graphics mode */56#define BLANK 057static int vga_is_gfx;58 59#define STI_DEF_FONT sticon_sti->font60 61/* borrowed from fbcon.c */62#define FNTREFCOUNT(fd) (fd->refcount)63#define FNTCRC(fd) (fd->crc)64static struct sti_cooked_font *font_data[MAX_NR_CONSOLES];65 66/* this is the sti_struct used for this console */67static struct sti_struct *sticon_sti;68 69static const char *sticon_startup(void)70{71 return "STI console";72}73 74static void sticon_putcs(struct vc_data *conp, const u16 *s, unsigned int count,75 unsigned int ypos, unsigned int xpos)76{77 if (vga_is_gfx || console_blanked)78 return;79 80 if (conp->vc_mode != KD_TEXT)81 return;82 83 while (count--) {84 sti_putc(sticon_sti, scr_readw(s++), ypos, xpos++,85 font_data[conp->vc_num]);86 }87}88 89static void sticon_cursor(struct vc_data *conp, bool enable)90{91 unsigned short car1;92 93 /* no cursor update if screen is blanked */94 if (vga_is_gfx || console_blanked)95 return;96 97 car1 = conp->vc_screenbuf[conp->state.x + conp->state.y * conp->vc_cols];98 if (!enable) {99 sti_putc(sticon_sti, car1, conp->state.y, conp->state.x,100 font_data[conp->vc_num]);101 return;102 }103 104 switch (CUR_SIZE(conp->vc_cursor_type)) {105 case CUR_UNDERLINE:106 case CUR_LOWER_THIRD:107 case CUR_LOWER_HALF:108 case CUR_TWO_THIRDS:109 case CUR_BLOCK:110 sti_putc(sticon_sti, (car1 & 255) + (0 << 8) + (7 << 11),111 conp->state.y, conp->state.x, font_data[conp->vc_num]);112 break;113 }114}115 116static bool sticon_scroll(struct vc_data *conp, unsigned int t,117 unsigned int b, enum con_scroll dir, unsigned int count)118{119 struct sti_struct *sti = sticon_sti;120 121 if (vga_is_gfx)122 return false;123 124 sticon_cursor(conp, false);125 126 switch (dir) {127 case SM_UP:128 sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols,129 font_data[conp->vc_num]);130 sti_clear(sti, b - count, 0, count, conp->vc_cols,131 conp->vc_video_erase_char, font_data[conp->vc_num]);132 break;133 134 case SM_DOWN:135 sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols,136 font_data[conp->vc_num]);137 sti_clear(sti, t, 0, count, conp->vc_cols,138 conp->vc_video_erase_char, font_data[conp->vc_num]);139 break;140 }141 142 return false;143}144 145static void sticon_set_def_font(int unit)146{147 if (font_data[unit] != STI_DEF_FONT) {148 if (--FNTREFCOUNT(font_data[unit]) == 0) {149 kfree(font_data[unit]->raw_ptr);150 kfree(font_data[unit]);151 }152 font_data[unit] = STI_DEF_FONT;153 }154}155 156static int sticon_set_font(struct vc_data *vc, const struct console_font *op,157 unsigned int vpitch)158{159 struct sti_struct *sti = sticon_sti;160 int vc_cols, vc_rows, vc_old_cols, vc_old_rows;161 int unit = vc->vc_num;162 int w = op->width;163 int h = op->height;164 int size, i, bpc, pitch;165 struct sti_rom_font *new_font;166 struct sti_cooked_font *cooked_font;167 unsigned char *data = op->data, *p;168 169 if ((w < 6) || (h < 6) || (w > 32) || (h > 32) || (vpitch != 32)170 || (op->charcount != 256 && op->charcount != 512))171 return -EINVAL;172 pitch = ALIGN(w, 8) / 8;173 bpc = pitch * h;174 size = bpc * op->charcount;175 176 new_font = kmalloc(sizeof(*new_font) + size, STI_LOWMEM);177 if (!new_font)178 return -ENOMEM;179 180 new_font->first_char = 0;181 new_font->last_char = op->charcount - 1;182 new_font->width = w;183 new_font->height = h;184 new_font->font_type = STI_FONT_HPROMAN8;185 new_font->bytes_per_char = bpc;186 new_font->underline_height = 0;187 new_font->underline_pos = 0;188 189 cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);190 if (!cooked_font) {191 kfree(new_font);192 return -ENOMEM;193 }194 cooked_font->raw = new_font;195 cooked_font->raw_ptr = new_font;196 cooked_font->width = w;197 cooked_font->height = h;198 FNTREFCOUNT(cooked_font) = 0; /* usage counter */199 200 p = (unsigned char *) new_font;201 p += sizeof(*new_font);202 for (i = 0; i < op->charcount; i++) {203 memcpy(p, data, bpc);204 data += pitch*32;205 p += bpc;206 }207 FNTCRC(cooked_font) = crc32(0, new_font, size + sizeof(*new_font));208 sti_font_convert_bytemode(sti, cooked_font);209 new_font = cooked_font->raw_ptr;210 211 /* check if font is already used by other console */212 for (i = 0; i < MAX_NR_CONSOLES; i++) {213 if (font_data[i] != STI_DEF_FONT214 && (FNTCRC(font_data[i]) == FNTCRC(cooked_font))) {215 kfree(new_font);216 kfree(cooked_font);217 /* current font is the same as the new one */218 if (i == unit)219 return 0;220 cooked_font = font_data[i];221 new_font = cooked_font->raw_ptr;222 break;223 }224 }225 226 /* clear screen with old font: we now may have less rows */227 vc_old_rows = vc->vc_rows;228 vc_old_cols = vc->vc_cols;229 sti_clear(sticon_sti, 0, 0, vc_old_rows, vc_old_cols,230 vc->vc_video_erase_char, font_data[vc->vc_num]);231 232 /* delete old font in case it is a user font */233 sticon_set_def_font(unit);234 235 FNTREFCOUNT(cooked_font)++;236 font_data[unit] = cooked_font;237 238 vc_cols = sti_onscreen_x(sti) / cooked_font->width;239 vc_rows = sti_onscreen_y(sti) / cooked_font->height;240 vc_resize(vc, vc_cols, vc_rows);241 242 /* need to repaint screen if cols & rows are same as old font */243 if (vc_cols == vc_old_cols && vc_rows == vc_old_rows)244 update_screen(vc);245 246 return 0;247}248 249static int sticon_font_default(struct vc_data *vc, struct console_font *op,250 const char *name)251{252 sticon_set_def_font(vc->vc_num);253 254 return 0;255}256 257static int sticon_font_set(struct vc_data *vc, const struct console_font *font,258 unsigned int vpitch, unsigned int flags)259{260 return sticon_set_font(vc, font, vpitch);261}262 263static void sticon_init(struct vc_data *c, bool init)264{265 struct sti_struct *sti = sticon_sti;266 int vc_cols, vc_rows;267 268 sti_set(sti, 0, 0, sti_onscreen_y(sti), sti_onscreen_x(sti), 0);269 vc_cols = sti_onscreen_x(sti) / sti->font->width;270 vc_rows = sti_onscreen_y(sti) / sti->font->height;271 c->vc_can_do_color = 1;272 273 if (init) {274 c->vc_cols = vc_cols;275 c->vc_rows = vc_rows;276 } else {277 vc_resize(c, vc_cols, vc_rows);278 }279}280 281static void sticon_deinit(struct vc_data *c)282{283 int i;284 285 /* free memory used by user font */286 for (i = 0; i < MAX_NR_CONSOLES; i++)287 sticon_set_def_font(i);288}289 290static void sticon_clear(struct vc_data *conp, unsigned int sy, unsigned int sx,291 unsigned int width)292{293 sti_clear(sticon_sti, sy, sx, 1, width,294 conp->vc_video_erase_char, font_data[conp->vc_num]);295}296 297static bool sticon_switch(struct vc_data *conp)298{299 return true; /* needs refreshing */300}301 302static bool sticon_blank(struct vc_data *c, enum vesa_blank_mode blank,303 bool mode_switch)304{305 if (blank == VESA_NO_BLANKING) {306 if (mode_switch)307 vga_is_gfx = 0;308 return true;309 }310 sti_clear(sticon_sti, 0, 0, c->vc_rows, c->vc_cols, BLANK,311 font_data[c->vc_num]);312 if (mode_switch)313 vga_is_gfx = 1;314 315 return true;316}317 318static u8 sticon_build_attr(struct vc_data *conp, u8 color,319 enum vc_intensity intens,320 bool blink, bool underline, bool reverse,321 bool italic)322{323 u8 fg = color & 7;324 u8 bg = (color & 0x70) >> 4;325 326 if (reverse)327 return (fg << 3) | bg;328 else329 return (bg << 3) | fg;330}331 332static void sticon_invert_region(struct vc_data *conp, u16 *p, int count)333{334 int col = 1; /* vga_can_do_color; */335 336 while (count--) {337 u16 a = scr_readw(p);338 339 if (col)340 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);341 else342 a = ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;343 344 scr_writew(a, p++);345 }346}347 348static const struct consw sti_con = {349 .owner = THIS_MODULE,350 .con_startup = sticon_startup,351 .con_init = sticon_init,352 .con_deinit = sticon_deinit,353 .con_clear = sticon_clear,354 .con_putcs = sticon_putcs,355 .con_cursor = sticon_cursor,356 .con_scroll = sticon_scroll,357 .con_switch = sticon_switch,358 .con_blank = sticon_blank,359 .con_font_set = sticon_font_set,360 .con_font_default = sticon_font_default,361 .con_build_attr = sticon_build_attr,362 .con_invert_region = sticon_invert_region,363};364 365 366 367static int __init sticonsole_init(void)368{369 int err, i;370 371 /* already initialized ? */372 if (sticon_sti)373 return 0;374 375 sticon_sti = sti_get_rom(0);376 if (!sticon_sti)377 return -ENODEV;378 379 for (i = 0; i < MAX_NR_CONSOLES; i++)380 font_data[i] = STI_DEF_FONT;381 382 pr_info("sticon: Initializing STI text console on %s at [%s]\n",383 sticon_sti->sti_data->inq_outptr.dev_name,384 sticon_sti->pa_path);385 console_lock();386 err = do_take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1,387 PAGE0->mem_cons.cl_class != CL_DUPLEX);388 console_unlock();389 390 return err;391}392 393module_init(sticonsole_init);394MODULE_DESCRIPTION("HP STI console driver");395MODULE_LICENSE("GPL");396