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