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