/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $ * Console driver utilizing PROM sun terminal emulation * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static short pw = 80 - 1, ph = 34 - 1; static short px, py; static unsigned long promcon_uni_pagedir[2]; extern u8 promfont_unicount[]; extern u16 promfont_unitable[]; #define PROMCON_COLOR 0 #if PROMCON_COLOR #define inverted(s) ((((s) & 0x7700) == 0x0700) ? 0 : 1) #else #define inverted(s) (((s) & 0x0800) ? 1 : 0) #endif static __inline__ void promcon_puts(char *buf, int cnt) { prom_printf("%*.*s", cnt, cnt, buf); } static int promcon_start(struct vc_data *conp, char *b) { unsigned short *s = (unsigned short *) (conp->vc_origin + py * conp->vc_size_row + (px << 1)); u16 cs; cs = scr_readw(s); if (px == pw) { unsigned short *t = s - 1; u16 ct = scr_readw(t); if (inverted(cs) && inverted(ct)) return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct); else if (inverted(cs)) return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct); else if (inverted(ct)) return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct); else return sprintf(b, "\b%c\b\033[@%c", cs, ct); } if (inverted(cs)) return sprintf(b, "\033[7m%c\033[m\b", cs); else return sprintf(b, "%c\b", cs); } static int promcon_end(struct vc_data *conp, char *b) { unsigned short *s = (unsigned short *) (conp->vc_origin + py * conp->vc_size_row + (px << 1)); char *p = b; u16 cs; b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); cs = scr_readw(s); if (px == pw) { unsigned short *t = s - 1; u16 ct = scr_readw(t); if (inverted(cs) && inverted(ct)) b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct); else if (inverted(cs)) b += sprintf(b, "\b%c\b\033[@%c", cs, ct); else if (inverted(ct)) b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct); else b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct); return b - p; } if (inverted(cs)) b += sprintf(b, "%c\b", cs); else b += sprintf(b, "\033[7m%c\033[m\b", cs); return b - p; } const char __init *promcon_startup(void) { const char *display_desc = "PROM"; int node; char buf[40]; node = prom_getchild(prom_root_node); node = prom_searchsiblings(node, "options"); if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) { pw = simple_strtoul(buf, NULL, 0); if (pw < 10 || pw > 256) pw = 80; pw--; } if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) { ph = simple_strtoul(buf, NULL, 0); if (ph < 10 || ph > 256) ph = 34; ph--; } promcon_puts("\033[H\033[J", 6); return display_desc; } static void __init promcon_init_unimap(struct vc_data *conp) { mm_segment_t old_fs = get_fs(); struct unipair *p, *p1; u16 *q; int i, j, k; p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL); if (!p) return; q = promfont_unitable; p1 = p; k = 0; for (i = 0; i < 256; i++) for (j = promfont_unicount[i]; j; j--) { p1->unicode = *q++; p1->fontpos = i; p1++; k++; } set_fs(KERNEL_DS); con_clear_unimap(conp->vc_num, NULL); con_set_unimap(conp->vc_num, k, p); con_protect_unimap(conp->vc_num, 1); set_fs(old_fs); kfree(p); } static void promcon_init(struct vc_data *conp, int init) { unsigned long p; conp->vc_can_do_color = PROMCON_COLOR; if (init) { conp->vc_cols = pw + 1; conp->vc_rows = ph + 1; } p = *conp->vc_uni_pagedir_loc; if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir || !--conp->vc_uni_pagedir_loc[1]) con_free_unimap(conp->vc_num); conp->vc_uni_pagedir_loc = promcon_uni_pagedir; promcon_uni_pagedir[1]++; if (!promcon_uni_pagedir[0] && p) { promcon_init_unimap(conp); } if (!init) { if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1) vc_resize_con(ph + 1, pw + 1, conp->vc_num); } } static void promcon_deinit(struct vc_data *conp) { /* When closing the last console, reset video origin */ if (!--promcon_uni_pagedir[1]) con_free_unimap(conp->vc_num); conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir; con_set_default_unimap(conp->vc_num); } static int promcon_switch(struct vc_data *conp) { return 1; } static unsigned short * promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp) { int cnt = pw + 1; int attr = -1; unsigned char *b = *bp; while (cnt--) { u16 c = scr_readw(s); if (attr != inverted(c)) { attr = inverted(c); if (attr) { strcpy (b, "\033[7m"); b += 4; } else { strcpy (b, "\033[m"); b += 3; } } *b++ = c; s++; if (b - buf >= 224) { promcon_puts(buf, b - buf); b = buf; } } *bp = b; return s; } static void promcon_putcs(struct vc_data *conp, const unsigned short *s, int count, int y, int x) { unsigned char buf[256], *b = buf; unsigned short attr = scr_readw(s); unsigned char save; int i, last = 0; if (console_blanked) return; if (count <= 0) return; b += promcon_start(conp, b); if (x + count >= pw + 1) { if (count == 1) { x -= 1; save = scr_readw((unsigned short *)(conp->vc_origin + y * conp->vc_size_row + (x << 1))); if (px != x || py != y) { b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); px = x; py = y; } if (inverted(attr)) b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++)); else b += sprintf(b, "%c", scr_readw(s++)); strcpy(b, "\b\033[@"); b += 4; if (inverted(save)) b += sprintf(b, "\033[7m%c\033[m", save); else b += sprintf(b, "%c", save); px++; b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } else { last = 1; count = pw - x - 1; } } if (inverted(attr)) { strcpy(b, "\033[7m"); b += 4; } if (px != x || py != y) { b += sprintf(b, "\033[%d;%dH", y + 1, x + 1); px = x; py = y; } for (i = 0; i < count; i++) { if (b - buf >= 224) { promcon_puts(buf, b - buf); b = buf; } *b++ = scr_readw(s++); } px += count; if (last) { save = scr_readw(s++); b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save); px++; } if (inverted(attr)) { strcpy(b, "\033[m"); b += 3; } b += promcon_end(conp, b); promcon_puts(buf, b - buf); } static void promcon_putc(struct vc_data *conp, int c, int y, int x) { unsigned short s; if (console_blanked) return; scr_writew(c, &s); promcon_putcs(conp, &s, 1, y, x); } static void promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width) { unsigned char buf[256], *b = buf; int i, j; if (console_blanked) return; b += promcon_start(conp, b); if (!sx && width == pw + 1) { if (!sy && height == ph + 1) { strcpy(b, "\033[H\033[J"); b += 6; b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } else if (sy + height == ph + 1) { b += sprintf(b, "\033[%dH\033[J", sy + 1); b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } b += sprintf(b, "\033[%dH", sy + 1); for (i = 1; i < height; i++) { strcpy(b, "\033[K\n"); b += 4; } strcpy(b, "\033[K"); b += 3; b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } else if (sx + width == pw + 1) { b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1); for (i = 1; i < height; i++) { strcpy(b, "\033[K\n"); b += 4; } strcpy(b, "\033[K"); b += 3; b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } for (i = sy + 1; i <= sy + height; i++) { b += sprintf(b, "\033[%d;%dH", i, sx + 1); for (j = 0; j < width; j++) *b++ = ' '; if (b - buf + width >= 224) { promcon_puts(buf, b - buf); b = buf; } } b += promcon_end(conp, b); promcon_puts(buf, b - buf); } static void promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, int height, int width) { char buf[256], *b = buf; if (console_blanked) return; b += promcon_start(conp, b); if (sy == dy && height == 1) { if (dx > sx && dx + width == conp->vc_cols) b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH", sy + 1, sx + 1, dx - sx, py + 1, px + 1); else if (dx < sx && sx + width == conp->vc_cols) b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH", dy + 1, dx + 1, sx - dx, py + 1, px + 1); b += promcon_end(conp, b); promcon_puts(buf, b - buf); return; } /* * FIXME: What to do here??? * Current console.c should not call it like that ever. */ prom_printf("\033[7mFIXME: bmove not handled\033[m\n"); } static void promcon_cursor(struct vc_data *conp, int mode) { char buf[32], *b = buf; switch (mode) { case CM_ERASE: break; case CM_MOVE: case CM_DRAW: b += promcon_start(conp, b); if (px != conp->vc_x || py != conp->vc_y) { px = conp->vc_x; py = conp->vc_y; b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); } promcon_puts(buf, b - buf); break; } } static int promcon_font_op(struct vc_data *conp, struct console_font_op *op) { return -ENOSYS; } static int promcon_blank(struct vc_data *conp, int blank) { if (blank) { promcon_puts("\033[H\033[J\033[7m \033[m\b", 15); return 0; } else { /* Let console.c redraw */ return 1; } } static int promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) { unsigned char buf[256], *p = buf; unsigned short *s; int i; if (console_blanked) return 0; p += promcon_start(conp, p); switch (dir) { case SM_UP: if (b == ph + 1) { p += sprintf(p, "\033[%dH\033[%dM", t + 1, count); px = 0; py = t; p += promcon_end(conp, p); promcon_puts(buf, p - buf); break; } s = (unsigned short *)(conp->vc_origin + (t + count) * conp->vc_size_row); p += sprintf(p, "\033[%dH", t + 1); for (i = t; i < b - count; i++) s = promcon_repaint_line(s, buf, &p); for (; i < b - 1; i++) { strcpy(p, "\033[K\n"); p += 4; if (p - buf >= 224) { promcon_puts(buf, p - buf); p = buf; } } strcpy(p, "\033[K"); p += 3; p += promcon_end(conp, p); promcon_puts(buf, p - buf); break; case SM_DOWN: if (b == ph + 1) { p += sprintf(p, "\033[%dH\033[%dL", t + 1, count); px = 0; py = t; p += promcon_end(conp, p); promcon_puts(buf, p - buf); break; } s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row); p += sprintf(p, "\033[%dH", t + 1); for (i = t; i < t + count; i++) { strcpy(p, "\033[K\n"); p += 4; if (p - buf >= 224) { promcon_puts(buf, p - buf); p = buf; } } for (; i < b; i++) s = promcon_repaint_line(s, buf, &p); p += promcon_end(conp, p); promcon_puts(buf, p - buf); break; } return 0; } #if !(PROMCON_COLOR) static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse) { return (_reverse) ? 0xf : 0x7; } #endif /* * The console 'switch' structure for the VGA based console */ static int promcon_dummy(void) { return 0; } #define DUMMY (void *) promcon_dummy const struct consw prom_con = { con_startup: promcon_startup, con_init: promcon_init, con_deinit: promcon_deinit, con_clear: promcon_clear, con_putc: promcon_putc, con_putcs: promcon_putcs, con_cursor: promcon_cursor, con_scroll: promcon_scroll, con_bmove: promcon_bmove, con_switch: promcon_switch, con_blank: promcon_blank, con_font_op: promcon_font_op, con_set_palette: DUMMY, con_scrolldelta: DUMMY, #if !(PROMCON_COLOR) con_build_attr: promcon_build_attr, #endif }; void __init prom_con_init(void) { #ifdef CONFIG_DUMMY_CONSOLE if (conswitchp == &dummy_con) take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1); else #endif if (conswitchp == &prom_con) promcon_init_unimap(vc_cons[fg_console].d); }