123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599 |
- /* $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 <linux/config.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/mm.h>
- #include <linux/tty.h>
- #include <linux/slab.h>
- #include <linux/delay.h>
- #include <linux/console.h>
- #include <linux/vt_kern.h>
- #include <linux/selection.h>
- #include <linux/fb.h>
- #include <linux/init.h>
- #include <linux/kd.h>
- #include <asm/oplib.h>
- #include <asm/uaccess.h>
- 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, NULL);
- con_set_unimap(conp, k, p);
- con_protect_unimap(conp, 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);
- 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(conp, pw + 1, ph + 1);
- }
- }
- 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);
- conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
- con_set_default_unimap(conp);
- }
- 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_blank(struct vc_data *conp, int blank, int mode_switch)
- {
- 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 = {
- .owner = THIS_MODULE,
- .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_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);
- }
|