]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/pc98/cbus/scterm-sck.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / pc98 / cbus / scterm-sck.c
1 /*-
2  * Copyright (c) 1999 FreeBSD(98) Porting Team.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include "opt_syscons.h"
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/consio.h>
36
37 #include <machine/pc/display.h>
38
39 #include <dev/syscons/syscons.h>
40 #include <pc98/cbus/sctermvar.h>
41
42 #define MAX_ESC_PAR     5
43
44 #ifdef KANJI
45 #define IS_KTYPE_ASCII_or_HANKAKU(A)    (!((A) & 0xee))
46 #define IS_KTYPE_KANA(A)                ((A) & 0x11)
47 #define KTYPE_MASK_CTRL(A)              ((A) &= 0xF0)
48 #endif /* KANJI */
49
50 /* attribute flags */
51 typedef struct {
52         u_short         fg;                     /* foreground color */
53         u_short         bg;                     /* background color */
54 } color_t;
55
56 typedef struct {
57         int             flags;
58 #define SCTERM_BUSY     (1 << 0)
59         int             esc;
60         int             num_param;
61         int             last_param;
62         int             param[MAX_ESC_PAR];
63         int             saved_xpos;
64         int             saved_ypos;
65
66 #ifdef KANJI
67         u_char          kanji_1st_char;
68         u_char          kanji_type;
69 #define KTYPE_ASCII     0                       /* ASCII */
70 #define KTYPE_KANA      1                       /* HANKAKU */
71 #define KTYPE_JKANA     0x10                    /* JIS HANKAKU */
72 #define KTYPE_7JIS      0x20                    /* JIS */
73 #define KTYPE_SJIS      2                       /* Shift JIS */
74 #define KTYPE_UJIS      4                       /* UJIS */
75 #define KTYPE_SUKANA    3                       /* Shift JIS or UJIS HANKAKU */
76 #define KTYPE_SUJIS     6                       /* SHift JIS or UJIS */
77 #define KTYPE_KANIN     0x80                    /* Kanji Invoke sequence */
78 #define KTYPE_ASCIN     0x40                    /* ASCII Invoke sequence */
79 #endif /* KANJI */
80
81         int             attr_mask;              /* current logical attr mask */
82 #define NORMAL_ATTR     0x00
83 #define BLINK_ATTR      0x01
84 #define BOLD_ATTR       0x02
85 #define UNDERLINE_ATTR  0x04
86 #define REVERSE_ATTR    0x08
87 #define FG_CHANGED      0x10
88 #define BG_CHANGED      0x20
89         int             cur_attr;               /* current hardware attr word */
90         color_t         cur_color;              /* current hardware color */
91         color_t         std_color;              /* normal hardware color */
92         color_t         rev_color;              /* reverse hardware color */
93         color_t         dflt_std_color;         /* default normal color */
94         color_t         dflt_rev_color;         /* default reverse color */
95 } term_stat;
96
97 static sc_term_init_t   scterm_init;
98 static sc_term_term_t   scterm_term;
99 static sc_term_puts_t   scterm_puts;
100 static sc_term_ioctl_t  scterm_ioctl;
101 static sc_term_reset_t  scterm_reset;
102 static sc_term_default_attr_t   scterm_default_attr;
103 static sc_term_clear_t  scterm_clear;
104 static sc_term_notify_t scterm_notify;
105 static sc_term_input_t  scterm_input;
106
107 static sc_term_sw_t sc_term_sc = {
108         { NULL, NULL },
109         "sck",                                  /* emulator name */
110         "syscons kanji terminal",               /* description */
111         "*",                                    /* matching renderer, any :-) */
112         sizeof(term_stat),                      /* softc size */
113         0,
114         scterm_init,
115         scterm_term,
116         scterm_puts,
117         scterm_ioctl,
118         scterm_reset,
119         scterm_default_attr,
120         scterm_clear,
121         scterm_notify,
122         scterm_input,
123 };
124
125 SCTERM_MODULE(sc, sc_term_sc);
126
127 static term_stat        reserved_term_stat;
128 static int              default_kanji = UJIS;
129 static void             scterm_scan_esc(scr_stat *scp, term_stat *tcp,
130                                         u_char c);
131 static int              mask2attr(term_stat *tcp);
132
133 #ifdef KANJI
134 __inline static u_char
135 iskanji1(u_char mode, u_char c)
136 {
137         if (c > 0x80) {
138                 if ((c >= 0xa1) && (c <= 0xdf)) {
139                         if (default_kanji == UJIS) {
140                                 /* UJIS */
141                                 return KTYPE_UJIS;
142                         }
143                         if (default_kanji == SJIS) {
144                                 /* SJIS HANKAKU */
145                                 return KTYPE_KANA;
146                         }
147                 }
148
149                 if (c <= 0x9f) {
150                         if (c == 0x8e) {
151                                 /* SJIS or UJIS HANKAKU */
152                                 return KTYPE_SUKANA;
153                         }
154
155                         /* SJIS */
156                         default_kanji = SJIS;
157                         return KTYPE_SJIS;
158                 }
159
160                 if ((c >= 0xe0) && (c <= 0xef)) {
161                         /* SJIS or UJIS */
162                         return KTYPE_SUJIS;
163                 }
164
165                 if ((c >= 0xf0) && (c <= 0xfe)) {
166                         /* UJIS */
167                         default_kanji = UJIS;
168                         return KTYPE_UJIS;
169                 }
170         } else {
171                 if ((mode == KTYPE_7JIS) && (c >= 0x21) && (c <= 0x7e)) {
172                         /* JIS */
173                         default_kanji = UJIS;
174                         return KTYPE_7JIS;
175                 }
176
177                 if ((mode == KTYPE_JKANA) && (c >= 0x21) && (c <= 0x5f)) {
178                         /* JIS HANKAKU */
179                         default_kanji = UJIS;
180                         return KTYPE_JKANA;
181                 }
182         }
183
184         return KTYPE_ASCII;
185 }
186
187 __inline static u_char
188 iskanji2(u_char mode, u_char c)
189 {
190         switch (mode) {
191         case KTYPE_7JIS:
192                 if ((c >= 0x21) && (c <= 0x7e)) {
193                         /* JIS */
194                         return KTYPE_7JIS;
195                 }
196                 break;
197         case KTYPE_SJIS:
198                 if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
199                         /* SJIS */
200                         return KTYPE_SJIS;
201                 }
202                 break;
203         case KTYPE_UJIS:
204                 if ((c >= 0xa1) && (c <= 0xfe)) {
205                         /* UJIS */
206                         return KTYPE_UJIS;
207                 }
208                 break;
209         case KTYPE_SUKANA:
210                 if ((c >= 0xa1) && (c <= 0xdf) && (default_kanji == UJIS)) {
211                         /* UJIS HANKAKU */
212                         return KTYPE_KANA;
213                 }
214                 if ((c >= 0x40) && (c <= 0xfc) && (c != 0x7f)) {
215                         /* SJIS */
216                         default_kanji = SJIS;
217                         return KTYPE_SJIS;
218                 }
219                 break;
220         case KTYPE_SUJIS:
221                 if ((c >= 0x40) && (c <= 0xa0) && (c != 0x7f)) {
222                         /* SJIS */
223                         default_kanji = SJIS;
224                         return KTYPE_SJIS;
225                 }
226                 if ((c == 0xfd) || (c == 0xfe)) {
227                         /* UJIS */
228                         default_kanji = UJIS;
229                         return KTYPE_UJIS;
230                 }
231                 if ((c >= 0xa1) && (c <= 0xfc)) {
232                         if (default_kanji == SJIS)
233                                 return KTYPE_SJIS;
234                         if (default_kanji == UJIS)
235                                 return KTYPE_UJIS;
236                 }
237                 break;
238         }
239
240         return KTYPE_ASCII;
241 }
242
243 /*
244  * JIS X0208-83 keisen conversion table
245  */
246 static u_short keiConv[32] = {
247         0x240c, 0x260c, 0x300c, 0x340c, 0x3c0c, 0x380c, 0x400c, 0x500c,
248         0x480c, 0x580c, 0x600c, 0x250c, 0x270c, 0x330c, 0x370c, 0x3f0c,
249         0x3b0c, 0x470c, 0x570c, 0x4f0c, 0x5f0c, 0x6f0c, 0x440c, 0x530c,
250         0x4c0c, 0x5b0c, 0x630c, 0x410c, 0x540c, 0x490c, 0x5c0c, 0x660c
251 };
252
253 static u_short
254 kanji_convert(u_char mode, u_char h, u_char l)
255 {
256         u_short tmp, high, low, c;
257
258         high = (u_short) h;
259         low  = (u_short) l;
260
261         switch (mode) {
262         case KTYPE_SJIS: /* SHIFT JIS */
263                 if (low >= 0xe0) {
264                         low -= 0x40;
265                 }
266                 low = (low - 0x81) * 2 + 0x21;
267                 if (high > 0x7f) {
268                         high--;
269                 }
270                 if (high > 0x9d) {
271                         low++;
272                         high -= 0x9e - 0x21;
273                 } else {
274                         high -= 0x40 - 0x21;
275                 }
276                 high &= 0x7F;
277                 low  &= 0x7F;
278                 tmp = ((high << 8) | low) - 0x20;
279                 break;
280         case KTYPE_7JIS: /* JIS */
281         case KTYPE_UJIS: /* UJIS */
282                 high &= 0x7F;
283                 low &= 0x7F;
284                 tmp = ((high << 8) | low) - 0x20;
285                 break;
286         default:
287                 tmp = 0;
288                 break;
289         }
290
291         /* keisen */
292         c = ((tmp & 0xff) << 8) | (tmp >> 8);
293         /* 0x2821 .. 0x2840 */
294         if (0x0821 <= c && c <= 0x0840)
295                 tmp = keiConv[c - 0x0821];
296
297         return (tmp);
298 }
299 #endif /* KANJI */
300
301 static int
302 scterm_init(scr_stat *scp, void **softc, int code)
303 {
304         term_stat *tcp;
305
306         if (*softc == NULL) {
307                 if (reserved_term_stat.flags & SCTERM_BUSY)
308                         return EINVAL;
309                 *softc = &reserved_term_stat;
310         }
311         tcp = *softc;
312
313         switch (code) {
314         case SC_TE_COLD_INIT:
315                 bzero(tcp, sizeof(*tcp));
316                 tcp->flags = SCTERM_BUSY;
317                 tcp->esc = 0;
318                 tcp->saved_xpos = -1;
319                 tcp->saved_ypos = -1;
320 #ifdef KANJI
321                 tcp->kanji_1st_char = 0;
322                 tcp->kanji_type = KTYPE_ASCII;
323 #endif
324                 tcp->attr_mask = NORMAL_ATTR;
325                 /* XXX */
326                 tcp->dflt_std_color.fg = SC_NORM_ATTR & 0x0f;
327                 tcp->dflt_std_color.bg = (SC_NORM_ATTR >> 4) & 0x0f;
328                 tcp->dflt_rev_color.fg = SC_NORM_REV_ATTR & 0x0f;
329                 tcp->dflt_rev_color.bg = (SC_NORM_REV_ATTR >> 4) & 0x0f;
330                 tcp->std_color = tcp->dflt_std_color;
331                 tcp->rev_color = tcp->dflt_rev_color;
332                 tcp->cur_color = tcp->std_color;
333                 tcp->cur_attr = mask2attr(tcp);
334                 ++sc_term_sc.te_refcount;
335                 break;
336
337         case SC_TE_WARM_INIT:
338                 tcp->esc = 0;
339                 tcp->saved_xpos = -1;
340                 tcp->saved_ypos = -1;
341 #if 0
342                 tcp->std_color = tcp->dflt_std_color;
343                 tcp->rev_color = tcp->dflt_rev_color;
344 #endif
345                 tcp->cur_color = tcp->std_color;
346                 tcp->cur_attr = mask2attr(tcp);
347                 break;
348         }
349
350         return 0;
351 }
352
353 static int
354 scterm_term(scr_stat *scp, void **softc)
355 {
356         if (*softc == &reserved_term_stat) {
357                 *softc = NULL;
358                 bzero(&reserved_term_stat, sizeof(reserved_term_stat));
359         }
360         --sc_term_sc.te_refcount;
361         return 0;
362 }
363
364 static void
365 scterm_scan_esc(scr_stat *scp, term_stat *tcp, u_char c)
366 {
367         static u_char ansi_col[16] = {
368                 FG_BLACK,     FG_RED,          FG_GREEN,      FG_BROWN,
369                 FG_BLUE,      FG_MAGENTA,      FG_CYAN,       FG_LIGHTGREY,
370                 FG_DARKGREY,  FG_LIGHTRED,     FG_LIGHTGREEN, FG_YELLOW,
371                 FG_LIGHTBLUE, FG_LIGHTMAGENTA, FG_LIGHTCYAN,  FG_WHITE
372         };
373         static int cattrs[] = {
374                 0,                                      /* block */
375                 CONS_BLINK_CURSOR,                      /* blinking block */
376                 CONS_CHAR_CURSOR,                       /* underline */
377                 CONS_CHAR_CURSOR | CONS_BLINK_CURSOR,   /* blinking underline */
378                 CONS_RESET_CURSOR,                      /* reset to default */
379                 CONS_HIDDEN_CURSOR,                     /* hide cursor */
380         };
381         static int tcattrs[] = {
382                 CONS_RESET_CURSOR | CONS_LOCAL_CURSOR,  /* normal */
383                 CONS_HIDDEN_CURSOR | CONS_LOCAL_CURSOR, /* invisible */
384                 CONS_BLINK_CURSOR | CONS_LOCAL_CURSOR,  /* very visible */
385         };
386         sc_softc_t *sc;
387         int v0, v1, v2;
388         int i, n;
389
390         i = n = 0;
391         sc = scp->sc; 
392         if (tcp->esc == 1) {    /* seen ESC */
393 #ifdef KANJI
394                 switch (tcp->kanji_type) {
395                 case KTYPE_KANIN:       /* Kanji Invoke sequence */
396                         switch (c) {
397                         case 'B':
398                         case '@':
399                                 tcp->kanji_type = KTYPE_7JIS;
400                                 tcp->esc = 0;
401                                 tcp->kanji_1st_char = 0;
402                                 return;
403                         default:
404                                 tcp->kanji_type = KTYPE_ASCII;
405                                 tcp->esc = 0;
406                                 break;
407                         }
408                         break;
409                 case KTYPE_ASCIN:       /* Ascii Invoke sequence */
410                         switch (c) {
411                         case 'J':
412                         case 'B':
413                         case 'H':
414                                 tcp->kanji_type = KTYPE_ASCII;
415                                 tcp->esc = 0;
416                                 tcp->kanji_1st_char = 0;
417                                 return;
418                         case 'I':
419                                 tcp->kanji_type = KTYPE_JKANA;
420                                 tcp->esc = 0;
421                                 tcp->kanji_1st_char = 0;
422                                 return;
423                         default:
424                                 tcp->kanji_type = KTYPE_ASCII;
425                                 tcp->esc = 0;
426                                 break;
427                         }
428                         break;
429                 default:
430                         break;
431                 }
432 #endif
433                 switch (c) {
434
435                 case '7':       /* Save cursor position */
436                         tcp->saved_xpos = scp->xpos;
437                         tcp->saved_ypos = scp->ypos;
438                         break;
439
440                 case '8':       /* Restore saved cursor position */
441                         if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
442                                 sc_move_cursor(scp, tcp->saved_xpos,
443                                                tcp->saved_ypos);
444                         break;
445
446                 case '[':       /* Start ESC [ sequence */
447                         tcp->esc = 2;
448                         tcp->last_param = -1;
449                         for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
450                                 tcp->param[i] = 1;
451                         tcp->num_param = 0;
452                         return;
453
454 #ifdef KANJI
455                 case '$':       /* Kanji Invoke sequence */
456                         tcp->kanji_type = KTYPE_KANIN;
457                         return;
458 #endif
459
460                 case 'M':       /* Move cursor up 1 line, scroll if at top */
461                         sc_term_up_scroll(scp, 1, sc->scr_map[0x20],
462                                           tcp->cur_attr, 0, 0);
463                         break;
464 #ifdef notyet
465                 case 'Q':
466                         tcp->esc = 4;
467                         return;
468 #endif
469                 case 'c':       /* reset */
470                         tcp->attr_mask = NORMAL_ATTR;
471                         tcp->cur_color = tcp->std_color
472                                        = tcp->dflt_std_color;
473                         tcp->rev_color = tcp->dflt_rev_color;
474                         tcp->cur_attr = mask2attr(tcp);
475                         sc_change_cursor_shape(scp,
476                             CONS_RESET_CURSOR | CONS_LOCAL_CURSOR, -1, -1);
477                         sc_clear_screen(scp);
478                         break;
479
480                 case '(':       /* iso-2022: designate 94 character set to G0 */
481 #ifdef KANJI
482                         tcp->kanji_type = KTYPE_ASCIN;
483 #else
484                         tcp->esc = 5;
485 #endif
486                         return;
487                 }
488         } else if (tcp->esc == 2) {     /* seen ESC [ */
489                 if (c >= '0' && c <= '9') {
490                         if (tcp->num_param < MAX_ESC_PAR) {
491                                 if (tcp->last_param != tcp->num_param) {
492                                         tcp->last_param = tcp->num_param;
493                                         tcp->param[tcp->num_param] = 0;
494                                 } else {
495                                         tcp->param[tcp->num_param] *= 10;
496                                 }
497                                 tcp->param[tcp->num_param] += c - '0';
498                                 return;
499                         }
500                 }
501                 tcp->num_param = tcp->last_param + 1;
502                 switch (c) {
503
504                 case ';':
505                         if (tcp->num_param < MAX_ESC_PAR)
506                                 return;
507                         break;
508
509                 case '=':
510                         tcp->esc = 3;
511                         tcp->last_param = -1;
512                         for (i = tcp->num_param; i < MAX_ESC_PAR; i++)
513                                 tcp->param[i] = 1;
514                         tcp->num_param = 0;
515                         return;
516
517                 case 'A':       /* up n rows */
518                         sc_term_up(scp, tcp->param[0], 0);
519                         break;
520
521                 case 'B':       /* down n rows */
522                         sc_term_down(scp, tcp->param[0], 0);
523                         break;
524
525                 case 'C':       /* right n columns */
526                         sc_term_right(scp, tcp->param[0]);
527                         break;
528
529                 case 'D':       /* left n columns */
530                         sc_term_left(scp, tcp->param[0]);
531                         break;
532
533                 case 'E':       /* cursor to start of line n lines down */
534                         n = tcp->param[0];
535                         if (n < 1)
536                                 n = 1;
537                         sc_move_cursor(scp, 0, scp->ypos + n);
538                         break;
539
540                 case 'F':       /* cursor to start of line n lines up */
541                         n = tcp->param[0];
542                         if (n < 1)
543                                 n = 1;
544                         sc_move_cursor(scp, 0, scp->ypos - n);
545                         break;
546
547                 case 'f':       /* Cursor move */
548                 case 'H':
549                         if (tcp->num_param == 0)
550                                 sc_move_cursor(scp, 0, 0);
551                         else if (tcp->num_param == 2)
552                                 sc_move_cursor(scp, tcp->param[1] - 1,
553                                                tcp->param[0] - 1);
554                         break;
555
556                 case 'J':       /* Clear all or part of display */
557                         if (tcp->num_param == 0)
558                                 n = 0;
559                         else
560                                 n = tcp->param[0];
561                         sc_term_clr_eos(scp, n, sc->scr_map[0x20],
562                                         tcp->cur_attr);
563                         break;
564
565                 case 'K':       /* Clear all or part of line */
566                         if (tcp->num_param == 0)
567                                 n = 0;
568                         else
569                                 n = tcp->param[0];
570                         sc_term_clr_eol(scp, n, sc->scr_map[0x20],
571                                         tcp->cur_attr);
572                         break;
573
574                 case 'L':       /* Insert n lines */
575                         sc_term_ins_line(scp, scp->ypos, tcp->param[0],
576                                          sc->scr_map[0x20], tcp->cur_attr, 0);
577                         break;
578
579                 case 'M':       /* Delete n lines */
580                         sc_term_del_line(scp, scp->ypos, tcp->param[0],
581                                          sc->scr_map[0x20], tcp->cur_attr, 0);
582                         break;
583
584                 case 'P':       /* Delete n chars */
585                         sc_term_del_char(scp, tcp->param[0],
586                                          sc->scr_map[0x20], tcp->cur_attr);
587                         break;
588
589                 case '@':       /* Insert n chars */
590                         sc_term_ins_char(scp, tcp->param[0],
591                                          sc->scr_map[0x20], tcp->cur_attr);
592                         break;
593
594                 case 'S':       /* scroll up n lines */
595                         sc_term_del_line(scp, 0, tcp->param[0],
596                                          sc->scr_map[0x20], tcp->cur_attr, 0);
597                         break;
598
599                 case 'T':       /* scroll down n lines */
600                         sc_term_ins_line(scp, 0, tcp->param[0],
601                                          sc->scr_map[0x20], tcp->cur_attr, 0);
602                         break;
603
604                 case 'X':       /* erase n characters in line */
605                         n = tcp->param[0];
606                         if (n < 1)
607                                 n = 1;
608                         if (n > scp->xsize - scp->xpos)
609                                 n = scp->xsize - scp->xpos;
610                         sc_vtb_erase(&scp->vtb, scp->cursor_pos, n,
611                                      sc->scr_map[0x20], tcp->cur_attr);
612                         mark_for_update(scp, scp->cursor_pos);
613                         mark_for_update(scp, scp->cursor_pos + n - 1);
614                         break;
615
616                 case 'Z':       /* move n tabs backwards */
617                         sc_term_backtab(scp, tcp->param[0]);
618                         break;
619
620                 case '`':       /* move cursor to column n */
621                         sc_term_col(scp, tcp->param[0]);
622                         break;
623
624                 case 'a':       /* move cursor n columns to the right */
625                         sc_term_right(scp, tcp->param[0]);
626                         break;
627
628                 case 'd':       /* move cursor to row n */
629                         sc_term_row(scp, tcp->param[0]);
630                         break;
631
632                 case 'e':       /* move cursor n rows down */
633                         sc_term_down(scp, tcp->param[0], 0);
634                         break;
635
636                 case 'm':       /* change attribute */
637                         if (tcp->num_param == 0) {
638                                 tcp->attr_mask = NORMAL_ATTR;
639                                 tcp->cur_color = tcp->std_color;
640                                 tcp->cur_attr = mask2attr(tcp);
641                                 break;
642                         }
643                         for (i = 0; i < tcp->num_param; i++) {
644                                 switch (n = tcp->param[i]) {
645                                 case 0: /* back to normal */
646                                         tcp->attr_mask = NORMAL_ATTR;
647                                         tcp->cur_color = tcp->std_color;
648                                         tcp->cur_attr = mask2attr(tcp);
649                                         break;
650                                 case 1: /* bold */
651                                         tcp->attr_mask |= BOLD_ATTR;
652                                         tcp->cur_attr = mask2attr(tcp);
653                                         break;
654                                 case 4: /* underline */
655                                         tcp->attr_mask |= UNDERLINE_ATTR;
656                                         tcp->cur_attr = mask2attr(tcp);
657                                         break;
658                                 case 5: /* blink */
659                                         tcp->attr_mask |= BLINK_ATTR;
660                                         tcp->cur_attr = mask2attr(tcp);
661                                         break;
662                                 case 7: /* reverse */
663                                         tcp->attr_mask |= REVERSE_ATTR;
664                                         tcp->cur_attr = mask2attr(tcp);
665                                         break;
666                                 case 22: /* remove bold (or dim) */
667                                         tcp->attr_mask &= ~BOLD_ATTR;
668                                         tcp->cur_attr = mask2attr(tcp);
669                                         break;
670                                 case 24: /* remove underline */
671                                         tcp->attr_mask &= ~UNDERLINE_ATTR;
672                                         tcp->cur_attr = mask2attr(tcp);
673                                         break;
674                                 case 25: /* remove blink */
675                                         tcp->attr_mask &= ~BLINK_ATTR;
676                                         tcp->cur_attr = mask2attr(tcp);
677                                         break;
678                                 case 27: /* remove reverse */
679                                         tcp->attr_mask &= ~REVERSE_ATTR;
680                                         tcp->cur_attr = mask2attr(tcp);
681                                         break;
682                                 case 30: case 31: /* set ansi fg color */
683                                 case 32: case 33: case 34:
684                                 case 35: case 36: case 37:
685                                         tcp->attr_mask |= FG_CHANGED;
686                                         tcp->cur_color.fg = ansi_col[n - 30];
687                                         tcp->cur_attr = mask2attr(tcp);
688                                         break;
689                                 case 39: /* restore fg color back to normal */
690                                         tcp->attr_mask &= ~(FG_CHANGED|BOLD_ATTR);
691                                         tcp->cur_color.fg = tcp->std_color.fg;
692                                         tcp->cur_attr = mask2attr(tcp);
693                                         break;
694                                 case 40: case 41: /* set ansi bg color */
695                                 case 42: case 43: case 44:
696                                 case 45: case 46: case 47:
697                                         tcp->attr_mask |= BG_CHANGED;
698                                         tcp->cur_color.bg = ansi_col[n - 40];
699                                         tcp->cur_attr = mask2attr(tcp);
700                                         break;
701                                 case 49: /* restore bg color back to normal */
702                                         tcp->attr_mask &= ~BG_CHANGED;
703                                         tcp->cur_color.bg = tcp->std_color.bg;
704                                         tcp->cur_attr = mask2attr(tcp);
705                                         break;
706                                 }
707                         }
708                         break;
709
710                 case 's':       /* Save cursor position */
711                         tcp->saved_xpos = scp->xpos;
712                         tcp->saved_ypos = scp->ypos;
713                         break;
714
715                 case 'u':       /* Restore saved cursor position */
716                         if (tcp->saved_xpos >= 0 && tcp->saved_ypos >= 0)
717                                 sc_move_cursor(scp, tcp->saved_xpos,
718                                                tcp->saved_ypos);
719                         break;
720
721                 case 'x':
722                         if (tcp->num_param == 0)
723                                 n = 0;
724                         else
725                                 n = tcp->param[0];
726                         switch (n) {
727                         case 0: /* reset colors and attributes back to normal */
728                                 tcp->attr_mask = NORMAL_ATTR;
729                                 tcp->cur_color = tcp->std_color
730                                                = tcp->dflt_std_color;
731                                 tcp->rev_color = tcp->dflt_rev_color;
732                                 tcp->cur_attr = mask2attr(tcp);
733                                 break;
734                         case 1: /* set ansi background */
735                                 tcp->attr_mask &= ~BG_CHANGED;
736                                 tcp->cur_color.bg = tcp->std_color.bg
737                                                   = ansi_col[tcp->param[1] & 0x0f];
738                                 tcp->cur_attr = mask2attr(tcp);
739                                 break;
740                         case 2: /* set ansi foreground */
741                                 tcp->attr_mask &= ~FG_CHANGED;
742                                 tcp->cur_color.fg = tcp->std_color.fg
743                                                   = ansi_col[tcp->param[1] & 0x0f];
744                                 tcp->cur_attr = mask2attr(tcp);
745                                 break;
746                         case 3: /* set adapter attribute directly */
747                                 tcp->attr_mask &= ~(FG_CHANGED | BG_CHANGED);
748                                 tcp->cur_color.fg = tcp->std_color.fg
749                                                   = tcp->param[1] & 0x0f;
750                                 tcp->cur_color.bg = tcp->std_color.bg
751                                                   = (tcp->param[1] >> 4) & 0x0f;
752                                 tcp->cur_attr = mask2attr(tcp);
753                                 break;
754                         case 5: /* set ansi reverse background */
755                                 tcp->rev_color.bg = ansi_col[tcp->param[1] & 0x0f];
756                                 tcp->cur_attr = mask2attr(tcp);
757                                 break;
758                         case 6: /* set ansi reverse foreground */
759                                 tcp->rev_color.fg = ansi_col[tcp->param[1] & 0x0f];
760                                 tcp->cur_attr = mask2attr(tcp);
761                                 break;
762                         case 7: /* set adapter reverse attribute directly */
763                                 tcp->rev_color.fg = tcp->param[1] & 0x0f;
764                                 tcp->rev_color.bg = (tcp->param[1] >> 4) & 0x0f;
765                                 tcp->cur_attr = mask2attr(tcp);
766                                 break;
767                         }
768                         break;
769
770                 case 'z':       /* switch to (virtual) console n */
771                         if (tcp->num_param == 1)
772                                 sc_switch_scr(sc, tcp->param[0]);
773                         break;
774                 }
775         } else if (tcp->esc == 3) {     /* seen ESC [0-9]+ = */
776                 if (c >= '0' && c <= '9') {
777                         if (tcp->num_param < MAX_ESC_PAR) {
778                                 if (tcp->last_param != tcp->num_param) {
779                                         tcp->last_param = tcp->num_param;
780                                         tcp->param[tcp->num_param] = 0;
781                                 } else {
782                                         tcp->param[tcp->num_param] *= 10;
783                                 }
784                                 tcp->param[tcp->num_param] += c - '0';
785                                 return;
786                         }
787                 }
788                 tcp->num_param = tcp->last_param + 1;
789                 switch (c) {
790
791                 case ';':
792                         if (tcp->num_param < MAX_ESC_PAR)
793                                 return;
794                         break;
795
796                 case 'A':   /* set display border color */
797                         if (tcp->num_param == 1) {
798                                 scp->border=tcp->param[0] & 0xff;
799                                 if (scp == sc->cur_scp)
800                                         sc_set_border(scp, scp->border);
801                         }
802                         break;
803
804                 case 'B':   /* set bell pitch and duration */
805                         if (tcp->num_param == 2) {
806                                 scp->bell_pitch = tcp->param[0];
807                                 scp->bell_duration = 
808                                     (tcp->param[1] * hz + 99) / 100;
809                         }
810                         break;
811
812                 case 'C':   /* set global/parmanent cursor type & shape */
813                         i = spltty();
814                         n = tcp->num_param;
815                         v0 = tcp->param[0];
816                         v1 = tcp->param[1];
817                         v2 = tcp->param[2];
818                         switch (n) {
819                         case 1: /* flags only */
820                                 if (v0 < sizeof(cattrs)/sizeof(cattrs[0]))
821                                         v0 = cattrs[v0];
822                                 else    /* backward compatibility */
823                                         v0 = cattrs[v0 & 0x3];
824                                 sc_change_cursor_shape(scp, v0, -1, -1);
825                                 break;
826                         case 2:
827                                 v2 = 0;
828                                 v0 &= 0x1f;     /* backward compatibility */
829                                 v1 &= 0x1f;
830                                 /* FALL THROUGH */
831                         case 3: /* base and height */
832                                 if (v2 == 0)    /* count from top */
833                                         sc_change_cursor_shape(scp, -1,
834                                             scp->font_size - v1 - 1,
835                                             v1 - v0 + 1);
836                                 else if (v2 == 1) /* count from bottom */
837                                         sc_change_cursor_shape(scp, -1,
838                                             v0, v1 - v0 + 1);
839                                 break;
840                         }
841                         splx(i);
842                         break;
843
844                 case 'F':   /* set adapter foreground */
845                         if (tcp->num_param == 1) {
846                                 tcp->attr_mask &= ~FG_CHANGED;
847                                 tcp->cur_color.fg = tcp->std_color.fg
848                                                   = tcp->param[0] & 0x0f;
849                                 tcp->cur_attr = mask2attr(tcp);
850                         }
851                         break;
852
853                 case 'G':   /* set adapter background */
854                         if (tcp->num_param == 1) {
855                                 tcp->attr_mask &= ~BG_CHANGED;
856                                 tcp->cur_color.bg = tcp->std_color.bg
857                                                   = tcp->param[0] & 0x0f;
858                                 tcp->cur_attr = mask2attr(tcp);
859                         }
860                         break;
861
862                 case 'H':   /* set adapter reverse foreground */
863                         if (tcp->num_param == 1) {
864                                 tcp->rev_color.fg = tcp->param[0] & 0x0f;
865                                 tcp->cur_attr = mask2attr(tcp);
866                         }
867                         break;
868
869                 case 'I':   /* set adapter reverse background */
870                         if (tcp->num_param == 1) {
871                                 tcp->rev_color.bg = tcp->param[0] & 0x0f;
872                                 tcp->cur_attr = mask2attr(tcp);
873                         }
874                         break;
875
876                 case 'S':   /* set local/temporary cursor type & shape */
877                         i = spltty();
878                         n = tcp->num_param;
879                         v0 = tcp->param[0];
880                         switch (n) {
881                         case 0:
882                                 v0 = 0;
883                                 /* FALL THROUGH */
884                         case 1:
885                                 if (v0 < sizeof(tcattrs)/sizeof(tcattrs[0]))
886                                         sc_change_cursor_shape(scp,
887                                             tcattrs[v0], -1, -1);
888                                 break;
889                         }
890                         splx(i);
891                         break;
892                 }
893 #ifdef notyet
894         } else if (tcp->esc == 4) {     /* seen ESC Q */
895                 /* to be filled */
896 #endif
897         } else if (tcp->esc == 5) {     /* seen ESC ( */
898                 switch (c) {
899                 case 'B':   /* iso-2022: desginate ASCII into G0 */
900                         break;
901                 /* other items to be filled */
902                 default:
903                         break;
904                 }
905         }
906         tcp->esc = 0;
907 }
908
909 static void
910 scterm_puts(scr_stat *scp, u_char *buf, int len, int kernel)
911 {
912         term_stat *tcp;
913         u_char *ptr;
914 #ifdef KANJI
915         u_short kanji_code;
916 #endif
917         color_t backup;
918
919         tcp = scp->ts;
920         ptr = buf;
921 outloop:
922         scp->sc->write_in_progress++;
923         backup = tcp->cur_color;
924         if (kernel) {
925                 tcp->cur_color.fg = SC_KERNEL_CONS_ATTR & 0x0f;
926                 tcp->cur_color.bg = (SC_KERNEL_CONS_ATTR >> 4) & 0x0f;
927         }
928
929         if (tcp->esc) {
930                 scterm_scan_esc(scp, tcp, *ptr++);
931                 len--;
932         } else if (PRINTABLE(*ptr)) {     /* Print only printables */
933                 vm_offset_t p;
934                 u_char *map;
935                 int attr;
936                 int i;
937                 int cnt;
938 #ifdef KANJI
939                 u_char c;
940 #endif
941
942                 p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
943                 map = scp->sc->scr_map;
944                 attr = tcp->cur_attr;
945
946 #ifdef KANJI
947                 c = *ptr;
948                 if (tcp->kanji_1st_char == 0) {
949                     tcp->kanji_type = iskanji1(tcp->kanji_type, c);
950                     if (!IS_KTYPE_ASCII_or_HANKAKU(tcp->kanji_type)) {
951                         /* not Ascii & not HANKAKU */
952                         tcp->kanji_1st_char = c;
953                         goto kanji_end;
954                     } else if (tcp->kanji_type == KTYPE_ASCII) {
955                         cnt = imin(len, scp->xsize - scp->xpos);
956                         i = cnt;
957                         do {
958                             p = sc_vtb_putchar(&scp->vtb, p, map[c], attr);
959                             c = *++ptr;
960                             --i;
961                         } while (i > 0 && PRINTABLE(c) &&
962                                  iskanji1(tcp->kanji_type, c) == KTYPE_ASCII);
963
964                         len -= cnt - i;
965                         mark_for_update(scp, scp->cursor_pos);
966                         scp->cursor_pos += cnt - i;
967                         mark_for_update(scp, scp->cursor_pos - 1);
968                         scp->xpos += cnt - i;
969                         KTYPE_MASK_CTRL(tcp->kanji_type);
970                         goto ascii_end;
971                     }
972                 } else {
973                     if ((tcp->kanji_type =
974                          iskanji2(tcp->kanji_type, c)) & 0xee) {
975                         /* print kanji on TEXT VRAM */
976                         kanji_code = kanji_convert(tcp->kanji_type, c,
977                                                    tcp->kanji_1st_char);
978                         mark_for_update(scp, scp->cursor_pos);
979                         for (i = 0; i < 2; i++) {
980                             /* *cursor_pos = (kanji_code | (i*0x80)); */
981                             p = sc_vtb_putchar(&scp->vtb, p,
982                                kanji_code | ((i == 0) ? 0x00 : 0x80), attr);
983                             ++scp->cursor_pos;
984                             if (++scp->xpos >= scp->xsize) {
985                                 scp->xpos = 0;
986                                 scp->ypos++;
987                             }
988                         }
989                         mark_for_update(scp, scp->cursor_pos - 1);
990                         KTYPE_MASK_CTRL(tcp->kanji_type);
991                         tcp->kanji_1st_char = 0;
992                         goto kanji_end;
993                     } else {
994                         tcp->kanji_1st_char = 0;
995                     }
996                 }                               
997                 if (IS_KTYPE_KANA(tcp->kanji_type))
998                     c |= 0x80;
999                 KTYPE_MASK_CTRL(tcp->kanji_type);
1000                 sc_vtb_putchar(&scp->vtb, p, map[c], attr);
1001                 mark_for_update(scp, scp->cursor_pos);
1002                 mark_for_update(scp, scp->cursor_pos);
1003                 ++scp->cursor_pos;
1004                 ++scp->xpos;
1005 kanji_end:
1006                 ++ptr;
1007                 --len;
1008 ascii_end:
1009 #else /* !KANJI */
1010                 cnt = imin(len, scp->xsize - scp->xpos);
1011                 i = cnt;
1012                 do {
1013                     /*
1014                      * gcc-2.6.3 generates poor (un)sign extension code.
1015                      * Casting the pointers in the following to volatile should
1016                      * have no effect, but in fact speeds up this inner loop
1017                      * from 26 to 18 cycles (+ cache misses) on i486's.
1018                      */
1019 #define UCVP(ucp)       ((u_char volatile *)(ucp))
1020                     p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)],
1021                                        attr);
1022                     ++ptr;
1023                     --i;
1024                 } while (i > 0 && PRINTABLE(*ptr));
1025
1026                 len -= cnt - i;
1027                 mark_for_update(scp, scp->cursor_pos);
1028                 scp->cursor_pos += cnt - i;
1029                 mark_for_update(scp, scp->cursor_pos - 1);
1030                 scp->xpos += cnt - i;
1031 #endif /* !KANJI */
1032
1033                 if (scp->xpos >= scp->xsize) {
1034                         scp->xpos = 0;
1035                         scp->ypos++;
1036                 }
1037         } else {
1038                 switch (*ptr) {
1039                 case 0x07:
1040                         sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1041                         break;
1042
1043                 case 0x08:      /* non-destructive backspace */
1044                         if (scp->cursor_pos > 0) {
1045                                 mark_for_update(scp, scp->cursor_pos);
1046                                 scp->cursor_pos--;
1047                                 mark_for_update(scp, scp->cursor_pos);
1048                                 if (scp->xpos > 0)
1049                                         scp->xpos--;
1050                                 else {
1051                                         scp->xpos += scp->xsize - 1;
1052                                         scp->ypos--;
1053                                 }
1054                         }
1055                         break;
1056
1057                 case 0x09:      /* non-destructive tab */
1058                         mark_for_update(scp, scp->cursor_pos);
1059                         scp->cursor_pos += (8 - scp->xpos % 8u);
1060                         scp->xpos += (8 - scp->xpos % 8u);
1061                         if (scp->xpos >= scp->xsize) {
1062                                 scp->xpos = 0;
1063                                 scp->ypos++;
1064                                 scp->cursor_pos = scp->xsize * scp->ypos;
1065                         }
1066                         mark_for_update(scp, scp->cursor_pos);
1067                         break;
1068
1069                 case 0x0a:      /* newline, same pos */
1070                         mark_for_update(scp, scp->cursor_pos);
1071                         scp->cursor_pos += scp->xsize;
1072                         mark_for_update(scp, scp->cursor_pos);
1073                         scp->ypos++;
1074                         break;
1075
1076                 case 0x0c:      /* form feed, clears screen */
1077                         sc_clear_screen(scp);
1078                         break;
1079
1080                 case 0x0d:      /* return, return to pos 0 */
1081                         mark_for_update(scp, scp->cursor_pos);
1082                         scp->cursor_pos -= scp->xpos;
1083                         mark_for_update(scp, scp->cursor_pos);
1084                         scp->xpos = 0;
1085                         break;
1086
1087                 case 0x0e:      /* ^N */
1088                         tcp->kanji_type = KTYPE_JKANA;
1089                         tcp->esc = 0;
1090                         tcp->kanji_1st_char = 0;
1091                         break;
1092
1093                 case 0x0f:      /* ^O */
1094                         tcp->kanji_type = KTYPE_ASCII;
1095                         tcp->esc = 0;
1096                         tcp->kanji_1st_char = 0;
1097                         break;
1098
1099                 case 0x1b:      /* start escape sequence */
1100                         tcp->esc = 1;
1101                         tcp->num_param = 0;
1102                         break;
1103                 }
1104                 ptr++;
1105                 len--;
1106         }
1107
1108         sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
1109
1110         if (kernel)
1111                 tcp->cur_color = backup;
1112         scp->sc->write_in_progress--;
1113         if (len)
1114                 goto outloop;
1115 }
1116
1117 static int
1118 scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
1119              struct thread *td)
1120 {
1121         term_stat *tcp = scp->ts;
1122         vid_info_t *vi;
1123
1124         switch (cmd) {
1125         case GIO_ATTR:          /* get current attributes */
1126                 /* FIXME: */
1127                 *(int*)data = (tcp->cur_attr >> 8) & 0xff;
1128                 return 0;
1129         case CONS_GETINFO:      /* get current (virtual) console info */
1130                 vi = (vid_info_t *)data;
1131                 if (vi->size != sizeof(struct vid_info))
1132                         return EINVAL;
1133                 vi->mv_norm.fore = tcp->std_color.fg;
1134                 vi->mv_norm.back = tcp->std_color.bg;
1135                 vi->mv_rev.fore = tcp->rev_color.fg;
1136                 vi->mv_rev.back = tcp->rev_color.bg;
1137                 /*
1138                  * The other fields are filled by the upper routine. XXX
1139                  */
1140                 return ENOIOCTL;
1141         }
1142         return ENOIOCTL;
1143 }
1144
1145 static int
1146 scterm_reset(scr_stat *scp, int code)
1147 {
1148         /* FIXME */
1149         return 0;
1150 }
1151
1152 static void
1153 scterm_default_attr(scr_stat *scp, int color, int rev_color)
1154 {
1155         term_stat *tcp = scp->ts;
1156
1157         tcp->dflt_std_color.fg = color & 0x0f;
1158         tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
1159         tcp->dflt_rev_color.fg = rev_color & 0x0f;
1160         tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
1161         tcp->std_color = tcp->dflt_std_color;
1162         tcp->rev_color = tcp->dflt_rev_color;
1163         tcp->cur_color = tcp->std_color;
1164         tcp->cur_attr = mask2attr(tcp);
1165 }
1166
1167 static void
1168 scterm_clear(scr_stat *scp)
1169 {
1170         term_stat *tcp = scp->ts;
1171
1172         sc_move_cursor(scp, 0, 0);
1173         sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
1174         mark_all(scp);
1175 }
1176
1177 static void
1178 scterm_notify(scr_stat *scp, int event)
1179 {
1180         switch (event) {
1181         case SC_TE_NOTIFY_VTSWITCH_IN:
1182                 break;
1183         case SC_TE_NOTIFY_VTSWITCH_OUT:
1184                 break;
1185         }
1186 }
1187
1188 static int
1189 scterm_input(scr_stat *scp, int c, struct tty *tp)
1190 {
1191         return FALSE;
1192 }
1193
1194 /*
1195  * Calculate hardware attributes word using logical attributes mask and
1196  * hardware colors
1197  */
1198
1199 /* FIXME */
1200 static int
1201 mask2attr(term_stat *tcp)
1202 {
1203         int attr, mask = tcp->attr_mask;
1204
1205         if (mask & REVERSE_ATTR) {
1206                 attr = ((mask & FG_CHANGED) ?
1207                         tcp->cur_color.bg : tcp->rev_color.fg) |
1208                         (((mask & BG_CHANGED) ?
1209                         tcp->cur_color.fg : tcp->rev_color.bg) << 4);
1210         } else
1211                 attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
1212
1213         /* XXX: underline mapping for Hercules adapter can be better */
1214         if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
1215                 attr ^= 0x08;
1216         if (mask & BLINK_ATTR)
1217                 attr ^= 0x80;
1218
1219         return (attr << 8);
1220 }