linux/drivers/video/console/promcon.c
<<
>>
Prefs
   1/* $Id: promcon.c,v 1.17 2000/07/26 23:02:52 davem Exp $
   2 * Console driver utilizing PROM sun terminal emulation
   3 *
   4 * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
   5 * Copyright (C) 1998  Jakub Jelinek  (jj@ultra.linux.cz)
   6 */
   7
   8#include <linux/module.h>
   9#include <linux/kernel.h>
  10#include <linux/errno.h>
  11#include <linux/string.h>
  12#include <linux/mm.h>
  13#include <linux/slab.h>
  14#include <linux/delay.h>
  15#include <linux/console.h>
  16#include <linux/vt_kern.h>
  17#include <linux/selection.h>
  18#include <linux/fb.h>
  19#include <linux/init.h>
  20#include <linux/kd.h>
  21
  22#include <asm/oplib.h>
  23#include <asm/uaccess.h>
  24
  25static short pw = 80 - 1, ph = 34 - 1;
  26static short px, py;
  27static unsigned long promcon_uni_pagedir[2];
  28
  29extern u8 promfont_unicount[];
  30extern u16 promfont_unitable[];
  31
  32#define PROMCON_COLOR 0
  33
  34#if PROMCON_COLOR
  35#define inverted(s)     ((((s) & 0x7700) == 0x0700) ? 0 : 1)
  36#else
  37#define inverted(s)     (((s) & 0x0800) ? 1 : 0)
  38#endif
  39
  40static __inline__ void
  41promcon_puts(char *buf, int cnt)
  42{
  43        prom_printf("%*.*s", cnt, cnt, buf);
  44}
  45
  46static int
  47promcon_start(struct vc_data *conp, char *b)
  48{
  49        unsigned short *s = (unsigned short *)
  50                        (conp->vc_origin + py * conp->vc_size_row + (px << 1));
  51        u16 cs;
  52
  53        cs = scr_readw(s);
  54        if (px == pw) {
  55                unsigned short *t = s - 1;
  56                u16 ct = scr_readw(t);
  57
  58                if (inverted(cs) && inverted(ct))
  59                        return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs,
  60                                       ct);
  61                else if (inverted(cs))
  62                        return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs,
  63                                       ct);
  64                else if (inverted(ct))
  65                        return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs,
  66                                       ct);
  67                else
  68                        return sprintf(b, "\b%c\b\033[@%c", cs, ct);
  69        }
  70
  71        if (inverted(cs))
  72                return sprintf(b, "\033[7m%c\033[m\b", cs);
  73        else
  74                return sprintf(b, "%c\b", cs);
  75}
  76
  77static int
  78promcon_end(struct vc_data *conp, char *b)
  79{
  80        unsigned short *s = (unsigned short *)
  81                        (conp->vc_origin + py * conp->vc_size_row + (px << 1));
  82        char *p = b;
  83        u16 cs;
  84
  85        b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
  86
  87        cs = scr_readw(s);
  88        if (px == pw) {
  89                unsigned short *t = s - 1;
  90                u16 ct = scr_readw(t);
  91
  92                if (inverted(cs) && inverted(ct))
  93                        b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", cs, ct);
  94                else if (inverted(cs))
  95                        b += sprintf(b, "\b%c\b\033[@%c", cs, ct);
  96                else if (inverted(ct))
  97                        b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", cs, ct);
  98                else
  99                        b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", cs, ct);
 100                return b - p;
 101        }
 102
 103        if (inverted(cs))
 104                b += sprintf(b, "%c\b", cs);
 105        else
 106                b += sprintf(b, "\033[7m%c\033[m\b", cs);
 107        return b - p;
 108}
 109
 110const char *promcon_startup(void)
 111{
 112        const char *display_desc = "PROM";
 113        int node;
 114        char buf[40];
 115        
 116        node = prom_getchild(prom_root_node);
 117        node = prom_searchsiblings(node, "options");
 118        if (prom_getproperty(node,  "screen-#columns", buf, 40) != -1) {
 119                pw = simple_strtoul(buf, NULL, 0);
 120                if (pw < 10 || pw > 256)
 121                        pw = 80;
 122                pw--;
 123        }
 124        if (prom_getproperty(node,  "screen-#rows", buf, 40) != -1) {
 125                ph = simple_strtoul(buf, NULL, 0);
 126                if (ph < 10 || ph > 256)
 127                        ph = 34;
 128                ph--;
 129        }
 130        promcon_puts("\033[H\033[J", 6);
 131        return display_desc;
 132}
 133
 134static void
 135promcon_init_unimap(struct vc_data *conp)
 136{
 137        mm_segment_t old_fs = get_fs();
 138        struct unipair *p, *p1;
 139        u16 *q;
 140        int i, j, k;
 141        
 142        p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
 143        if (!p) return;
 144        
 145        q = promfont_unitable;
 146        p1 = p;
 147        k = 0;
 148        for (i = 0; i < 256; i++)
 149                for (j = promfont_unicount[i]; j; j--) {
 150                        p1->unicode = *q++;
 151                        p1->fontpos = i;
 152                        p1++;
 153                        k++;
 154                }
 155        set_fs(KERNEL_DS);
 156        con_clear_unimap(conp, NULL);
 157        con_set_unimap(conp, k, p);
 158        con_protect_unimap(conp, 1);
 159        set_fs(old_fs);
 160        kfree(p);
 161}
 162
 163static void
 164promcon_init(struct vc_data *conp, int init)
 165{
 166        unsigned long p;
 167        
 168        conp->vc_can_do_color = PROMCON_COLOR;
 169        if (init) {
 170                conp->vc_cols = pw + 1;
 171                conp->vc_rows = ph + 1;
 172        }
 173        p = *conp->vc_uni_pagedir_loc;
 174        if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
 175            !--conp->vc_uni_pagedir_loc[1])
 176                con_free_unimap(conp);
 177        conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
 178        promcon_uni_pagedir[1]++;
 179        if (!promcon_uni_pagedir[0] && p) {
 180                promcon_init_unimap(conp);
 181        }
 182        if (!init) {
 183                if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
 184                        vc_resize(conp, pw + 1, ph + 1);
 185        }
 186}
 187
 188static void
 189promcon_deinit(struct vc_data *conp)
 190{
 191        /* When closing the last console, reset video origin */
 192        if (!--promcon_uni_pagedir[1])
 193                con_free_unimap(conp);
 194        conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
 195        con_set_default_unimap(conp);
 196}
 197
 198static int
 199promcon_switch(struct vc_data *conp)
 200{
 201        return 1;
 202}
 203
 204static unsigned short *
 205promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp)
 206{
 207        int cnt = pw + 1;
 208        int attr = -1;
 209        unsigned char *b = *bp;
 210
 211        while (cnt--) {
 212                u16 c = scr_readw(s);
 213                if (attr != inverted(c)) {
 214                        attr = inverted(c);
 215                        if (attr) {
 216                                strcpy (b, "\033[7m");
 217                                b += 4;
 218                        } else {
 219                                strcpy (b, "\033[m");
 220                                b += 3;
 221                        }
 222                }
 223                *b++ = c;
 224                s++;
 225                if (b - buf >= 224) {
 226                        promcon_puts(buf, b - buf);
 227                        b = buf;
 228                }
 229        }
 230        *bp = b;
 231        return s;
 232}
 233
 234static void
 235promcon_putcs(struct vc_data *conp, const unsigned short *s,
 236              int count, int y, int x)
 237{
 238        unsigned char buf[256], *b = buf;
 239        unsigned short attr = scr_readw(s);
 240        unsigned char save;
 241        int i, last = 0;
 242
 243        if (console_blanked)
 244                return;
 245        
 246        if (count <= 0)
 247                return;
 248
 249        b += promcon_start(conp, b);
 250
 251        if (x + count >= pw + 1) {
 252                if (count == 1) {
 253                        x -= 1;
 254                        save = scr_readw((unsigned short *)(conp->vc_origin
 255                                                   + y * conp->vc_size_row
 256                                                   + (x << 1)));
 257
 258                        if (px != x || py != y) {
 259                                b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
 260                                px = x;
 261                                py = y;
 262                        }
 263
 264                        if (inverted(attr))
 265                                b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++));
 266                        else
 267                                b += sprintf(b, "%c", scr_readw(s++));
 268
 269                        strcpy(b, "\b\033[@");
 270                        b += 4;
 271
 272                        if (inverted(save))
 273                                b += sprintf(b, "\033[7m%c\033[m", save);
 274                        else
 275                                b += sprintf(b, "%c", save);
 276
 277                        px++;
 278
 279                        b += promcon_end(conp, b);
 280                        promcon_puts(buf, b - buf);
 281                        return;
 282                } else {
 283                        last = 1;
 284                        count = pw - x - 1;
 285                }
 286        }
 287
 288        if (inverted(attr)) {
 289                strcpy(b, "\033[7m");
 290                b += 4;
 291        }
 292
 293        if (px != x || py != y) {
 294                b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
 295                px = x;
 296                py = y;
 297        }
 298
 299        for (i = 0; i < count; i++) {
 300                if (b - buf >= 224) {
 301                        promcon_puts(buf, b - buf);
 302                        b = buf;
 303                }
 304                *b++ = scr_readw(s++);
 305        }
 306
 307        px += count;
 308
 309        if (last) {
 310                save = scr_readw(s++);
 311                b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save);
 312                px++;
 313        }
 314
 315        if (inverted(attr)) {
 316                strcpy(b, "\033[m");
 317                b += 3;
 318        }
 319
 320        b += promcon_end(conp, b);
 321        promcon_puts(buf, b - buf);
 322}
 323
 324static void
 325promcon_putc(struct vc_data *conp, int c, int y, int x)
 326{
 327        unsigned short s;
 328
 329        if (console_blanked)
 330                return;
 331        
 332        scr_writew(c, &s);
 333        promcon_putcs(conp, &s, 1, y, x);
 334}
 335
 336static void
 337promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width)
 338{
 339        unsigned char buf[256], *b = buf;
 340        int i, j;
 341
 342        if (console_blanked)
 343                return;
 344        
 345        b += promcon_start(conp, b);
 346
 347        if (!sx && width == pw + 1) {
 348
 349                if (!sy && height == ph + 1) {
 350                        strcpy(b, "\033[H\033[J");
 351                        b += 6;
 352                        b += promcon_end(conp, b);
 353                        promcon_puts(buf, b - buf);
 354                        return;
 355                } else if (sy + height == ph + 1) {
 356                        b += sprintf(b, "\033[%dH\033[J", sy + 1);
 357                        b += promcon_end(conp, b);
 358                        promcon_puts(buf, b - buf);
 359                        return;
 360                }
 361
 362                b += sprintf(b, "\033[%dH", sy + 1);
 363                for (i = 1; i < height; i++) {
 364                        strcpy(b, "\033[K\n");
 365                        b += 4;
 366                }
 367
 368                strcpy(b, "\033[K");
 369                b += 3;
 370
 371                b += promcon_end(conp, b);
 372                promcon_puts(buf, b - buf);
 373                return;
 374
 375        } else if (sx + width == pw + 1) {
 376
 377                b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1);
 378                for (i = 1; i < height; i++) {
 379                        strcpy(b, "\033[K\n");
 380                        b += 4;
 381                }
 382
 383                strcpy(b, "\033[K");
 384                b += 3;
 385
 386                b += promcon_end(conp, b);
 387                promcon_puts(buf, b - buf);
 388                return;
 389        }
 390
 391        for (i = sy + 1; i <= sy + height; i++) {
 392                b += sprintf(b, "\033[%d;%dH", i, sx + 1);
 393                for (j = 0; j < width; j++)
 394                        *b++ = ' ';
 395                if (b - buf + width >= 224) {
 396                        promcon_puts(buf, b - buf);
 397                        b = buf;
 398                }
 399        }
 400
 401        b += promcon_end(conp, b);
 402        promcon_puts(buf, b - buf);
 403}
 404                        
 405static void
 406promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
 407              int height, int width)
 408{
 409        char buf[256], *b = buf;
 410
 411        if (console_blanked)
 412                return;
 413        
 414        b += promcon_start(conp, b);
 415        if (sy == dy && height == 1) {
 416                if (dx > sx && dx + width == conp->vc_cols)
 417                        b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH",
 418                                     sy + 1, sx + 1, dx - sx, py + 1, px + 1);
 419                else if (dx < sx && sx + width == conp->vc_cols)
 420                        b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH",
 421                                     dy + 1, dx + 1, sx - dx, py + 1, px + 1);
 422
 423                b += promcon_end(conp, b);
 424                promcon_puts(buf, b - buf);
 425                return;
 426        }
 427
 428        /*
 429         * FIXME: What to do here???
 430         * Current console.c should not call it like that ever.
 431         */
 432        prom_printf("\033[7mFIXME: bmove not handled\033[m\n");
 433}
 434
 435static void
 436promcon_cursor(struct vc_data *conp, int mode)
 437{
 438        char buf[32], *b = buf;
 439
 440        switch (mode) {
 441        case CM_ERASE:
 442                break;
 443
 444        case CM_MOVE:
 445        case CM_DRAW:
 446                b += promcon_start(conp, b);
 447                if (px != conp->vc_x || py != conp->vc_y) {
 448                        px = conp->vc_x;
 449                        py = conp->vc_y;
 450                        b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
 451                }
 452                promcon_puts(buf, b - buf);
 453                break;
 454        }
 455}
 456
 457static int
 458promcon_blank(struct vc_data *conp, int blank, int mode_switch)
 459{
 460        if (blank) {
 461                promcon_puts("\033[H\033[J\033[7m \033[m\b", 15);
 462                return 0;
 463        } else {
 464                /* Let console.c redraw */
 465                return 1;
 466        }
 467}
 468
 469static int
 470promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
 471{
 472        unsigned char buf[256], *p = buf;
 473        unsigned short *s;
 474        int i;
 475
 476        if (console_blanked)
 477                return 0;
 478        
 479        p += promcon_start(conp, p);
 480
 481        switch (dir) {
 482        case SM_UP:
 483                if (b == ph + 1) {
 484                        p += sprintf(p, "\033[%dH\033[%dM", t + 1, count);
 485                        px = 0;
 486                        py = t;
 487                        p += promcon_end(conp, p);
 488                        promcon_puts(buf, p - buf);
 489                        break;
 490                }
 491
 492                s = (unsigned short *)(conp->vc_origin
 493                                       + (t + count) * conp->vc_size_row);
 494
 495                p += sprintf(p, "\033[%dH", t + 1);
 496
 497                for (i = t; i < b - count; i++)
 498                        s = promcon_repaint_line(s, buf, &p);
 499
 500                for (; i < b - 1; i++) {
 501                        strcpy(p, "\033[K\n");
 502                        p += 4;
 503                        if (p - buf >= 224) {
 504                                promcon_puts(buf, p - buf);
 505                                p = buf;
 506                        }
 507                }
 508
 509                strcpy(p, "\033[K");
 510                p += 3;
 511
 512                p += promcon_end(conp, p);
 513                promcon_puts(buf, p - buf);
 514                break;
 515
 516        case SM_DOWN:
 517                if (b == ph + 1) {
 518                        p += sprintf(p, "\033[%dH\033[%dL", t + 1, count);
 519                        px = 0;
 520                        py = t;
 521                        p += promcon_end(conp, p);
 522                        promcon_puts(buf, p - buf);
 523                        break;
 524                }
 525
 526                s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
 527
 528                p += sprintf(p, "\033[%dH", t + 1);
 529
 530                for (i = t; i < t + count; i++) {
 531                        strcpy(p, "\033[K\n");
 532                        p += 4;
 533                        if (p - buf >= 224) {
 534                                promcon_puts(buf, p - buf);
 535                                p = buf;
 536                        }
 537                }
 538
 539                for (; i < b; i++)
 540                        s = promcon_repaint_line(s, buf, &p);
 541
 542                p += promcon_end(conp, p);
 543                promcon_puts(buf, p - buf);
 544                break;
 545        }
 546
 547        return 0;
 548}
 549
 550#if !(PROMCON_COLOR)
 551static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity,
 552    u8 _blink, u8 _underline, u8 _reverse, u8 _italic)
 553{
 554        return (_reverse) ? 0xf : 0x7;
 555}
 556#endif
 557
 558/*
 559 *  The console 'switch' structure for the VGA based console
 560 */
 561
 562static int promcon_dummy(void)
 563{
 564        return 0;
 565}
 566
 567#define DUMMY (void *) promcon_dummy
 568
 569const struct consw prom_con = {
 570        .owner =                THIS_MODULE,
 571        .con_startup =          promcon_startup,
 572        .con_init =             promcon_init,
 573        .con_deinit =           promcon_deinit,
 574        .con_clear =            promcon_clear,
 575        .con_putc =             promcon_putc,
 576        .con_putcs =            promcon_putcs,
 577        .con_cursor =           promcon_cursor,
 578        .con_scroll =           promcon_scroll,
 579        .con_bmove =            promcon_bmove,
 580        .con_switch =           promcon_switch,
 581        .con_blank =            promcon_blank,
 582        .con_set_palette =      DUMMY,
 583        .con_scrolldelta =      DUMMY,
 584#if !(PROMCON_COLOR)
 585        .con_build_attr =       promcon_build_attr,
 586#endif
 587};
 588
 589void __init prom_con_init(void)
 590{
 591#ifdef CONFIG_DUMMY_CONSOLE
 592        if (conswitchp == &dummy_con)
 593                take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
 594        else
 595#endif
 596        if (conswitchp == &prom_con)
 597                promcon_init_unimap(vc_cons[fg_console].d);
 598}
 599