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