1
2
3
4
5
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
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
430
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
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
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