Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.30-rc4 598 lines 12 kB view raw
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}