1/* $Id: promcon.c,v 1.1.1.1 2007/08/03 18:53:03 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 prom_printf("\033[7mFIXME: bmove not handled\033[m\n"); 429} 430 431static void 432promcon_cursor(struct vc_data *conp, int mode) 433{ 434 char buf[32], *b = buf; 435 436 switch (mode) { 437 case CM_ERASE: 438 break; 439 440 case CM_MOVE: 441 case CM_DRAW: 442 b += promcon_start(conp, b); 443 if (px != conp->vc_x || py != conp->vc_y) { 444 px = conp->vc_x; 445 py = conp->vc_y; 446 b += sprintf(b, "\033[%d;%dH", py + 1, px + 1); 447 } 448 promcon_puts(buf, b - buf); 449 break; 450 } 451} 452 453static int 454promcon_blank(struct vc_data *conp, int blank, int mode_switch) 455{ 456 if (blank) { 457 promcon_puts("\033[H\033[J\033[7m \033[m\b", 15); 458 return 0; 459 } else { 460 /* Let console.c redraw */ 461 return 1; 462 } 463} 464 465static int 466promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) 467{ 468 unsigned char buf[256], *p = buf; 469 unsigned short *s; 470 int i; 471 472 if (console_blanked) 473 return 0; 474 475 p += promcon_start(conp, p); 476 477 switch (dir) { 478 case SM_UP: 479 if (b == ph + 1) { 480 p += sprintf(p, "\033[%dH\033[%dM", t + 1, count); 481 px = 0; 482 py = t; 483 p += promcon_end(conp, p); 484 promcon_puts(buf, p - buf); 485 break; 486 } 487 488 s = (unsigned short *)(conp->vc_origin 489 + (t + count) * conp->vc_size_row); 490 491 p += sprintf(p, "\033[%dH", t + 1); 492 493 for (i = t; i < b - count; i++) 494 s = promcon_repaint_line(s, buf, &p); 495 496 for (; i < b - 1; i++) { 497 strcpy(p, "\033[K\n"); 498 p += 4; 499 if (p - buf >= 224) { 500 promcon_puts(buf, p - buf); 501 p = buf; 502 } 503 } 504 505 strcpy(p, "\033[K"); 506 p += 3; 507 508 p += promcon_end(conp, p); 509 promcon_puts(buf, p - buf); 510 break; 511 512 case SM_DOWN: 513 if (b == ph + 1) { 514 p += sprintf(p, "\033[%dH\033[%dL", t + 1, count); 515 px = 0; 516 py = t; 517 p += promcon_end(conp, p); 518 promcon_puts(buf, p - buf); 519 break; 520 } 521 522 s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row); 523 524 p += sprintf(p, "\033[%dH", t + 1); 525 526 for (i = t; i < t + count; i++) { 527 strcpy(p, "\033[K\n"); 528 p += 4; 529 if (p - buf >= 224) { 530 promcon_puts(buf, p - buf); 531 p = buf; 532 } 533 } 534 535 for (; i < b; i++) 536 s = promcon_repaint_line(s, buf, &p); 537 538 p += promcon_end(conp, p); 539 promcon_puts(buf, p - buf); 540 break; 541 } 542 543 return 0; 544} 545 546#if !PROMCON_COLOR 547static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, 548 u8 _blink, u8 _underline, u8 _reverse, u8 _italic) 549{ 550 return (_reverse) ? 0xf : 0x7; 551} 552#endif 553 554/* 555 * The console 'switch' structure for the VGA based console 556 */ 557 558static int promcon_dummy(void) 559{ 560 return 0; 561} 562 563#define DUMMY (void *) promcon_dummy 564 565const struct consw prom_con = { 566 .owner = THIS_MODULE, 567 .con_startup = promcon_startup, 568 .con_init = promcon_init, 569 .con_deinit = promcon_deinit, 570 .con_clear = promcon_clear, 571 .con_putc = promcon_putc, 572 .con_putcs = promcon_putcs, 573 .con_cursor = promcon_cursor, 574 .con_scroll = promcon_scroll, 575 .con_bmove = promcon_bmove, 576 .con_switch = promcon_switch, 577 .con_blank = promcon_blank, 578 .con_set_palette = DUMMY, 579 .con_scrolldelta = DUMMY, 580#if !PROMCON_COLOR 581 .con_build_attr = promcon_build_attr, 582#endif 583}; 584 585void __init prom_con_init(void) 586{ 587#ifdef CONFIG_DUMMY_CONSOLE 588 if (conswitchp == &dummy_con) 589 take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1); 590 else 591#endif 592 if (conswitchp == &prom_con) 593 promcon_init_unimap(vc_cons[fg_console].d); 594} 595