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