Import 2.3.18pre1
[davej-history.git] / drivers / video / promcon.c
blobe58d32ed16722a6a3f1d84f4951d844ccf01f857
1 /* $Id: promcon.c,v 1.16 1999/08/10 15:56:22 davem Exp $
2 * Console driver utilizing PROM sun terminal emulation
4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
5 * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
6 */
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/malloc.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>
25 #include <asm/oplib.h>
26 #include <asm/uaccess.h>
28 static short pw = 80 - 1, ph = 34 - 1;
29 static short px, py;
30 static unsigned long promcon_uni_pagedir[2];
32 extern u8 promfont_unicount[];
33 extern u16 promfont_unitable[];
35 #define PROMCON_COLOR 0
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
43 static __inline__ void
44 promcon_puts(char *buf, int cnt)
46 prom_printf("%*.*s", cnt, cnt, buf);
49 static int
50 promcon_start(struct vc_data *conp, char *b)
52 unsigned short *s = (unsigned short *)
53 (conp->vc_origin + py * conp->vc_size_row + (px << 1));
55 if (px == pw) {
56 unsigned short *t = s - 1;
58 if (inverted(*s) && inverted(*t))
59 return sprintf(b, "\b\033[7m%c\b\033[@%c\033[m",
60 *s, *t);
61 else if (inverted(*s))
62 return sprintf(b, "\b\033[7m%c\033[m\b\033[@%c",
63 *s, *t);
64 else if (inverted(*t))
65 return sprintf(b, "\b%c\b\033[@\033[7m%c\033[m",
66 *s, *t);
67 else
68 return sprintf(b, "\b%c\b\033[@%c", *s, *t);
71 if (inverted(*s))
72 return sprintf(b, "\033[7m%c\033[m\b", *s);
73 else
74 return sprintf(b, "%c\b", *s);
77 static int
78 promcon_end(struct vc_data *conp, char *b)
80 unsigned short *s = (unsigned short *)
81 (conp->vc_origin + py * conp->vc_size_row + (px << 1));
82 char *p = b;
84 b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
86 if (px == pw) {
87 unsigned short *t = s - 1;
89 if (inverted(*s) && inverted(*t))
90 b += sprintf(b, "\b%c\b\033[@\033[7m%c\033[m", *s, *t);
91 else if (inverted(*s))
92 b += sprintf(b, "\b%c\b\033[@%c", *s, *t);
93 else if (inverted(*t))
94 b += sprintf(b, "\b\033[7m%c\b\033[@%c\033[m", *s, *t);
95 else
96 b += sprintf(b, "\b\033[7m%c\033[m\b\033[@%c", *s, *t);
97 return b - p;
100 if (inverted(*s))
101 b += sprintf(b, "%c\b", *s);
102 else
103 b += sprintf(b, "\033[7m%c\033[m\b", *s);
104 return b - p;
107 const char __init *promcon_startup(void)
109 const char *display_desc = "PROM";
110 int node;
111 char buf[40];
113 node = prom_getchild(prom_root_node);
114 node = prom_searchsiblings(node, "options");
115 if (prom_getproperty(node, "screen-#columns", buf, 40) != -1) {
116 pw = simple_strtoul(buf, NULL, 0);
117 if (pw < 10 || pw > 256)
118 pw = 80;
119 pw--;
121 if (prom_getproperty(node, "screen-#rows", buf, 40) != -1) {
122 ph = simple_strtoul(buf, NULL, 0);
123 if (ph < 10 || ph > 256)
124 ph = 34;
125 ph--;
127 promcon_puts("\033[H\033[J", 6);
128 return display_desc;
131 static void __init
132 promcon_init_unimap(struct vc_data *conp)
134 mm_segment_t old_fs = get_fs();
135 struct unipair *p, *p1;
136 u16 *q;
137 int i, j, k;
139 p = kmalloc(256*sizeof(struct unipair), GFP_KERNEL);
140 if (!p) return;
142 q = promfont_unitable;
143 p1 = p;
144 k = 0;
145 for (i = 0; i < 256; i++)
146 for (j = promfont_unicount[i]; j; j--) {
147 p1->unicode = *q++;
148 p1->fontpos = i;
149 p1++;
150 k++;
152 set_fs(KERNEL_DS);
153 con_clear_unimap(conp->vc_num, NULL);
154 con_set_unimap(conp->vc_num, k, p);
155 con_protect_unimap(conp->vc_num, 1);
156 set_fs(old_fs);
157 kfree(p);
160 static void
161 promcon_init(struct vc_data *conp, int init)
163 unsigned long p;
165 conp->vc_can_do_color = PROMCON_COLOR;
166 if (init) {
167 conp->vc_cols = pw + 1;
168 conp->vc_rows = ph + 1;
170 p = *conp->vc_uni_pagedir_loc;
171 if (conp->vc_uni_pagedir_loc == &conp->vc_uni_pagedir ||
172 !--conp->vc_uni_pagedir_loc[1])
173 con_free_unimap(conp->vc_num);
174 conp->vc_uni_pagedir_loc = promcon_uni_pagedir;
175 promcon_uni_pagedir[1]++;
176 if (!promcon_uni_pagedir[0] && p) {
177 promcon_init_unimap(conp);
179 if (!init) {
180 if (conp->vc_cols != pw + 1 || conp->vc_rows != ph + 1)
181 vc_resize_con(ph + 1, pw + 1, conp->vc_num);
185 static void
186 promcon_deinit(struct vc_data *conp)
188 /* When closing the last console, reset video origin */
189 if (!--promcon_uni_pagedir[1])
190 con_free_unimap(conp->vc_num);
191 conp->vc_uni_pagedir_loc = &conp->vc_uni_pagedir;
192 con_set_default_unimap(conp->vc_num);
195 static int
196 promcon_switch(struct vc_data *conp)
198 return 1;
201 static unsigned short *
202 promcon_repaint_line(unsigned short *s, unsigned char *buf, unsigned char **bp)
204 int cnt = pw + 1;
205 int attr = -1;
206 unsigned char *b = *bp;
208 while (cnt--) {
209 if (attr != inverted(*s)) {
210 attr = inverted(*s);
211 if (attr) {
212 strcpy (b, "\033[7m");
213 b += 4;
214 } else {
215 strcpy (b, "\033[m");
216 b += 3;
219 *b++ = *s++;
220 if (b - buf >= 224) {
221 promcon_puts(buf, b - buf);
222 b = buf;
225 *bp = b;
226 return s;
229 static void
230 promcon_putcs(struct vc_data *conp, const unsigned short *s,
231 int count, int y, int x)
233 unsigned char buf[256], *b = buf;
234 unsigned short attr = scr_readw(s);
235 unsigned char save;
236 int i, last = 0;
238 if (console_blanked)
239 return;
241 if (count <= 0)
242 return;
244 b += promcon_start(conp, b);
246 if (x + count >= pw + 1) {
247 if (count == 1) {
248 x -= 1;
249 save = *(unsigned short *)(conp->vc_origin
250 + y * conp->vc_size_row
251 + (x << 1));
253 if (px != x || py != y) {
254 b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
255 px = x;
256 py = y;
259 if (inverted(attr))
260 b += sprintf(b, "\033[7m%c\033[m", scr_readw(s++));
261 else
262 b += sprintf(b, "%c", scr_readw(s++));
264 strcpy(b, "\b\033[@");
265 b += 4;
267 if (inverted(save))
268 b += sprintf(b, "\033[7m%c\033[m", save);
269 else
270 b += sprintf(b, "%c", save);
272 px++;
274 b += promcon_end(conp, b);
275 promcon_puts(buf, b - buf);
276 return;
277 } else {
278 last = 1;
279 count = pw - x - 1;
283 if (inverted(attr)) {
284 strcpy(b, "\033[7m");
285 b += 4;
288 if (px != x || py != y) {
289 b += sprintf(b, "\033[%d;%dH", y + 1, x + 1);
290 px = x;
291 py = y;
294 for (i = 0; i < count; i++) {
295 if (b - buf >= 224) {
296 promcon_puts(buf, b - buf);
297 b = buf;
299 *b++ = scr_readw(s++);
302 px += count;
304 if (last) {
305 save = scr_readw(s++);
306 b += sprintf(b, "%c\b\033[@%c", scr_readw(s++), save);
307 px++;
310 if (inverted(attr)) {
311 strcpy(b, "\033[m");
312 b += 3;
315 b += promcon_end(conp, b);
316 promcon_puts(buf, b - buf);
319 static void
320 promcon_putc(struct vc_data *conp, int c, int y, int x)
322 unsigned short s;
324 if (console_blanked)
325 return;
327 scr_writew(c, &s);
328 promcon_putcs(conp, &s, 1, y, x);
331 static void
332 promcon_clear(struct vc_data *conp, int sy, int sx, int height, int width)
334 unsigned char buf[256], *b = buf;
335 int i, j;
337 if (console_blanked)
338 return;
340 b += promcon_start(conp, b);
342 if (!sx && width == pw + 1) {
344 if (!sy && height == ph + 1) {
345 strcpy(b, "\033[H\033[J");
346 b += 6;
347 b += promcon_end(conp, b);
348 promcon_puts(buf, b - buf);
349 return;
350 } else if (sy + height == ph + 1) {
351 b += sprintf(b, "\033[%dH\033[J", sy + 1);
352 b += promcon_end(conp, b);
353 promcon_puts(buf, b - buf);
354 return;
357 b += sprintf(b, "\033[%dH", sy + 1);
358 for (i = 1; i < height; i++) {
359 strcpy(b, "\033[K\n");
360 b += 4;
363 strcpy(b, "\033[K");
364 b += 3;
366 b += promcon_end(conp, b);
367 promcon_puts(buf, b - buf);
368 return;
370 } else if (sx + width == pw + 1) {
372 b += sprintf(b, "\033[%d;%dH", sy + 1, sx + 1);
373 for (i = 1; i < height; i++) {
374 strcpy(b, "\033[K\n");
375 b += 4;
378 strcpy(b, "\033[K");
379 b += 3;
381 b += promcon_end(conp, b);
382 promcon_puts(buf, b - buf);
383 return;
386 for (i = sy + 1; i <= sy + height; i++) {
387 b += sprintf(b, "\033[%d;%dH", i, sx + 1);
388 for (j = 0; j < width; j++)
389 *b++ = ' ';
390 if (b - buf + width >= 224) {
391 promcon_puts(buf, b - buf);
392 b = buf;
396 b += promcon_end(conp, b);
397 promcon_puts(buf, b - buf);
400 static void
401 promcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx,
402 int height, int width)
404 char buf[256], *b = buf;
406 if (console_blanked)
407 return;
409 b += promcon_start(conp, b);
410 if (sy == dy && height == 1) {
411 if (dx > sx && dx + width == conp->vc_cols)
412 b += sprintf(b, "\033[%d;%dH\033[%d@\033[%d;%dH",
413 sy + 1, sx + 1, dx - sx, py + 1, px + 1);
414 else if (dx < sx && sx + width == conp->vc_cols)
415 b += sprintf(b, "\033[%d;%dH\033[%dP\033[%d;%dH",
416 dy + 1, dx + 1, sx - dx, py + 1, px + 1);
418 b += promcon_end(conp, b);
419 promcon_puts(buf, b - buf);
420 return;
424 * FIXME: What to do here???
425 * Current console.c should not call it like that ever.
427 prom_printf("\033[7mFIXME: bmove not handled\033[m\n");
430 static void
431 promcon_cursor(struct vc_data *conp, int mode)
433 char buf[32], *b = buf;
435 switch (mode) {
436 case CM_ERASE:
437 break;
439 case CM_MOVE:
440 case CM_DRAW:
441 b += promcon_start(conp, b);
442 if (px != conp->vc_x || py != conp->vc_y) {
443 px = conp->vc_x;
444 py = conp->vc_y;
445 b += sprintf(b, "\033[%d;%dH", py + 1, px + 1);
447 promcon_puts(buf, b - buf);
448 break;
452 static int
453 promcon_font_op(struct vc_data *conp, struct console_font_op *op)
455 return -ENOSYS;
458 static int
459 promcon_blank(struct vc_data *conp, int blank)
461 if (blank) {
462 promcon_puts("\033[H\033[J\033[7m \033[m\b", 15);
463 return 0;
464 } else {
465 /* Let console.c redraw */
466 return 1;
470 static int
471 promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
473 unsigned char buf[256], *p = buf;
474 unsigned short *s;
475 int i;
477 if (console_blanked)
478 return 0;
480 p += promcon_start(conp, p);
482 switch (dir) {
483 case SM_UP:
484 if (b == ph + 1) {
485 p += sprintf(p, "\033[%dH\033[%dM", t + 1, count);
486 px = 0;
487 py = t;
488 p += promcon_end(conp, p);
489 promcon_puts(buf, p - buf);
490 break;
493 s = (unsigned short *)(conp->vc_origin
494 + (t + count) * conp->vc_size_row);
496 p += sprintf(p, "\033[%dH", t + 1);
498 for (i = t; i < b - count; i++)
499 s = promcon_repaint_line(s, buf, &p);
501 for (; i < b - 1; i++) {
502 strcpy(p, "\033[K\n");
503 p += 4;
504 if (p - buf >= 224) {
505 promcon_puts(buf, p - buf);
506 p = buf;
510 strcpy(p, "\033[K");
511 p += 3;
513 p += promcon_end(conp, p);
514 promcon_puts(buf, p - buf);
515 break;
517 case SM_DOWN:
518 if (b == ph + 1) {
519 p += sprintf(p, "\033[%dH\033[%dL", t + 1, count);
520 px = 0;
521 py = t;
522 p += promcon_end(conp, p);
523 promcon_puts(buf, p - buf);
524 break;
527 s = (unsigned short *)(conp->vc_origin + t * conp->vc_size_row);
529 p += sprintf(p, "\033[%dH", t + 1);
531 for (i = t; i < t + count; i++) {
532 strcpy(p, "\033[K\n");
533 p += 4;
534 if (p - buf >= 224) {
535 promcon_puts(buf, p - buf);
536 p = buf;
540 for (; i < b; i++)
541 s = promcon_repaint_line(s, buf, &p);
543 p += promcon_end(conp, p);
544 promcon_puts(buf, p - buf);
545 break;
548 return 0;
551 #if !(PROMCON_COLOR)
552 static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
554 return (_reverse) ? 0xf : 0x7;
556 #endif
559 * The console 'switch' structure for the VGA based console
562 static int promcon_dummy(void)
564 return 0;
567 #define DUMMY (void *) promcon_dummy
569 struct consw prom_con = {
570 con_startup: promcon_startup,
571 con_init: promcon_init,
572 con_deinit: promcon_deinit,
573 con_clear: promcon_clear,
574 con_putc: promcon_putc,
575 con_putcs: promcon_putcs,
576 con_cursor: promcon_cursor,
577 con_scroll: promcon_scroll,
578 con_bmove: promcon_bmove,
579 con_switch: promcon_switch,
580 con_blank: promcon_blank,
581 con_font_op: promcon_font_op,
582 con_set_palette: DUMMY,
583 con_scrolldelta: DUMMY,
584 con_set_origin: NULL,
585 con_save_screen: NULL,
586 #if PROMCON_COLOR
587 con_build_attr: NULL,
588 #else
589 con_build_attr: promcon_build_attr,
590 #endif
591 con_invert_region: NULL,
594 void __init prom_con_init(void)
596 #ifdef CONFIG_DUMMY_CONSOLE
597 if (conswitchp == &dummy_con)
598 take_over_console(&prom_con, 0, MAX_NR_CONSOLES-1, 1);
599 else
600 #endif
601 if (conswitchp == &prom_con)
602 promcon_init_unimap(vc_cons[fg_console].d);