Deleted Added
full compact
scterm-sck.c (181905) scterm-sck.c (186681)
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 *
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: head/sys/pc98/cbus/scterm-sck.c 181905 2008-08-20 08:31:58Z ed $
26 * $FreeBSD: head/sys/pc98/cbus/scterm-sck.c 186681 2009-01-01 13:26:53Z ed $
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>
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 <dev/syscons/sctermvar.h>
40#include <pc98/cbus/sctermvar.h>
41
41
42#ifndef SC_DUMB_TERMINAL
43
44#define MAX_ESC_PAR 5
45
46#ifdef KANJI
47#define IS_KTYPE_ASCII_or_HANKAKU(A) (!((A) & 0xee))
48#define IS_KTYPE_KANA(A) ((A) & 0x11)
49#define KTYPE_MASK_CTRL(A) ((A) &= 0xF0)
50#endif /* KANJI */
51
52/* attribute flags */
53typedef struct {
54 u_short fg; /* foreground color */
55 u_short bg; /* background color */
56} color_t;
57
58typedef struct {
59 int flags;
60#define SCTERM_BUSY (1 << 0)
61 int esc;
62 int num_param;
63 int last_param;
64 int param[MAX_ESC_PAR];
65 int saved_xpos;
66 int saved_ypos;
67
68#ifdef KANJI
69 u_char kanji_1st_char;
70 u_char kanji_type;
71#define KTYPE_ASCII 0 /* ASCII */
72#define KTYPE_KANA 1 /* HANKAKU */
73#define KTYPE_JKANA 0x10 /* JIS HANKAKU */
74#define KTYPE_7JIS 0x20 /* JIS */
75#define KTYPE_SJIS 2 /* Shift JIS */
76#define KTYPE_UJIS 4 /* UJIS */
77#define KTYPE_SUKANA 3 /* Shift JIS or UJIS HANKAKU */
78#define KTYPE_SUJIS 6 /* SHift JIS or UJIS */
79#define KTYPE_KANIN 0x80 /* Kanji Invoke sequence */
80#define KTYPE_ASCIN 0x40 /* ASCII Invoke sequence */
81#endif /* KANJI */
82
83 int attr_mask; /* current logical attr mask */
84#define NORMAL_ATTR 0x00
85#define BLINK_ATTR 0x01
86#define BOLD_ATTR 0x02
87#define UNDERLINE_ATTR 0x04
88#define REVERSE_ATTR 0x08
89#define FG_CHANGED 0x10
90#define BG_CHANGED 0x20
91 int cur_attr; /* current hardware attr word */
92 color_t cur_color; /* current hardware color */
93 color_t std_color; /* normal hardware color */
94 color_t rev_color; /* reverse hardware color */
95 color_t dflt_std_color; /* default normal color */
96 color_t dflt_rev_color; /* default reverse color */
97} term_stat;
98
99static sc_term_init_t scterm_init;
100static sc_term_term_t scterm_term;
101static sc_term_puts_t scterm_puts;
102static sc_term_ioctl_t scterm_ioctl;
103static sc_term_reset_t scterm_reset;
104static sc_term_default_attr_t scterm_default_attr;
105static sc_term_clear_t scterm_clear;
106static sc_term_notify_t scterm_notify;
107static sc_term_input_t scterm_input;
108
109static sc_term_sw_t sc_term_sc = {
110 { NULL, NULL },
111 "sck", /* emulator name */
112 "syscons kanji terminal", /* description */
113 "*", /* matching renderer, any :-) */
114 sizeof(term_stat), /* softc size */
115 0,
116 scterm_init,
117 scterm_term,
118 scterm_puts,
119 scterm_ioctl,
120 scterm_reset,
121 scterm_default_attr,
122 scterm_clear,
123 scterm_notify,
124 scterm_input,
125};
126
127SCTERM_MODULE(sc, sc_term_sc);
128
129static term_stat reserved_term_stat;
130static int default_kanji = UJIS;
131static void scterm_scan_esc(scr_stat *scp, term_stat *tcp,
132 u_char c);
133static int mask2attr(term_stat *tcp);
134
135#ifdef KANJI
136__inline static u_char
137iskanji1(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__inline static u_char
190iskanji2(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 */
248static 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
255static u_short
256kanji_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
303static int
304scterm_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
355static int
356scterm_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
366static void
367scterm_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
911static void
912scterm_puts(scr_stat *scp, u_char *buf, int len)
913{
914 term_stat *tcp;
915 u_char *ptr;
916#ifdef KANJI
917 u_short kanji_code;
918#endif
919
920 tcp = scp->ts;
921 ptr = buf;
922outloop:
923 scp->sc->write_in_progress++;
924
925 if (tcp->esc) {
926 scterm_scan_esc(scp, tcp, *ptr++);
927 len--;
928 } else if (PRINTABLE(*ptr)) { /* Print only printables */
929 vm_offset_t p;
930 u_char *map;
931 int attr;
932 int i;
933 int cnt;
934#ifdef KANJI
935 u_char c;
936#endif
937
938 p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
939 map = scp->sc->scr_map;
940 attr = tcp->cur_attr;
941
942#ifdef KANJI
943 c = *ptr;
944 if (tcp->kanji_1st_char == 0) {
945 tcp->kanji_type = iskanji1(tcp->kanji_type, c);
946 if (!IS_KTYPE_ASCII_or_HANKAKU(tcp->kanji_type)) {
947 /* not Ascii & not HANKAKU */
948 tcp->kanji_1st_char = c;
949 goto kanji_end;
950 } else if (tcp->kanji_type == KTYPE_ASCII) {
951 cnt = imin(len, scp->xsize - scp->xpos);
952 i = cnt;
953 do {
954 p = sc_vtb_putchar(&scp->vtb, p, map[c], attr);
955 c = *++ptr;
956 --i;
957 } while (i > 0 && PRINTABLE(c) &&
958 iskanji1(tcp->kanji_type, c) == KTYPE_ASCII);
959
960 len -= cnt - i;
961 mark_for_update(scp, scp->cursor_pos);
962 scp->cursor_pos += cnt - i;
963 mark_for_update(scp, scp->cursor_pos - 1);
964 scp->xpos += cnt - i;
965 KTYPE_MASK_CTRL(tcp->kanji_type);
966 goto ascii_end;
967 }
968 } else {
969 if ((tcp->kanji_type =
970 iskanji2(tcp->kanji_type, c)) & 0xee) {
971 /* print kanji on TEXT VRAM */
972 kanji_code = kanji_convert(tcp->kanji_type, c,
973 tcp->kanji_1st_char);
974 mark_for_update(scp, scp->cursor_pos);
975 for (i = 0; i < 2; i++) {
976 /* *cursor_pos = (kanji_code | (i*0x80)); */
977 p = sc_vtb_putchar(&scp->vtb, p,
978 kanji_code | ((i == 0) ? 0x00 : 0x80), attr);
979 ++scp->cursor_pos;
980 if (++scp->xpos >= scp->xsize) {
981 scp->xpos = 0;
982 scp->ypos++;
983 }
984 }
985 mark_for_update(scp, scp->cursor_pos - 1);
986 KTYPE_MASK_CTRL(tcp->kanji_type);
987 tcp->kanji_1st_char = 0;
988 goto kanji_end;
989 } else {
990 tcp->kanji_1st_char = 0;
991 }
992 }
993 if (IS_KTYPE_KANA(tcp->kanji_type))
994 c |= 0x80;
995 KTYPE_MASK_CTRL(tcp->kanji_type);
996 sc_vtb_putchar(&scp->vtb, p, map[c], attr);
997 mark_for_update(scp, scp->cursor_pos);
998 mark_for_update(scp, scp->cursor_pos);
999 ++scp->cursor_pos;
1000 ++scp->xpos;
1001kanji_end:
1002 ++ptr;
1003 --len;
1004ascii_end:
1005#else /* !KANJI */
1006 cnt = imin(len, scp->xsize - scp->xpos);
1007 i = cnt;
1008 do {
1009 /*
1010 * gcc-2.6.3 generates poor (un)sign extension code.
1011 * Casting the pointers in the following to volatile should
1012 * have no effect, but in fact speeds up this inner loop
1013 * from 26 to 18 cycles (+ cache misses) on i486's.
1014 */
1015#define UCVP(ucp) ((u_char volatile *)(ucp))
1016 p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)],
1017 attr);
1018 ++ptr;
1019 --i;
1020 } while (i > 0 && PRINTABLE(*ptr));
1021
1022 len -= cnt - i;
1023 mark_for_update(scp, scp->cursor_pos);
1024 scp->cursor_pos += cnt - i;
1025 mark_for_update(scp, scp->cursor_pos - 1);
1026 scp->xpos += cnt - i;
1027#endif /* !KANJI */
1028
1029 if (scp->xpos >= scp->xsize) {
1030 scp->xpos = 0;
1031 scp->ypos++;
1032 }
1033 } else {
1034 switch (*ptr) {
1035 case 0x07:
1036 sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1037 break;
1038
1039 case 0x08: /* non-destructive backspace */
1040 if (scp->cursor_pos > 0) {
1041 mark_for_update(scp, scp->cursor_pos);
1042 scp->cursor_pos--;
1043 mark_for_update(scp, scp->cursor_pos);
1044 if (scp->xpos > 0)
1045 scp->xpos--;
1046 else {
1047 scp->xpos += scp->xsize - 1;
1048 scp->ypos--;
1049 }
1050 }
1051 break;
1052
1053 case 0x09: /* non-destructive tab */
1054 mark_for_update(scp, scp->cursor_pos);
1055 scp->cursor_pos += (8 - scp->xpos % 8u);
1056 scp->xpos += (8 - scp->xpos % 8u);
1057 if (scp->xpos >= scp->xsize) {
1058 scp->xpos = 0;
1059 scp->ypos++;
1060 scp->cursor_pos = scp->xsize * scp->ypos;
1061 }
1062 mark_for_update(scp, scp->cursor_pos);
1063 break;
1064
1065 case 0x0a: /* newline, same pos */
1066 mark_for_update(scp, scp->cursor_pos);
1067 scp->cursor_pos += scp->xsize;
1068 mark_for_update(scp, scp->cursor_pos);
1069 scp->ypos++;
1070 break;
1071
1072 case 0x0c: /* form feed, clears screen */
1073 sc_clear_screen(scp);
1074 break;
1075
1076 case 0x0d: /* return, return to pos 0 */
1077 mark_for_update(scp, scp->cursor_pos);
1078 scp->cursor_pos -= scp->xpos;
1079 mark_for_update(scp, scp->cursor_pos);
1080 scp->xpos = 0;
1081 break;
1082
1083 case 0x0e: /* ^N */
1084 tcp->kanji_type = KTYPE_JKANA;
1085 tcp->esc = 0;
1086 tcp->kanji_1st_char = 0;
1087 break;
1088
1089 case 0x0f: /* ^O */
1090 tcp->kanji_type = KTYPE_ASCII;
1091 tcp->esc = 0;
1092 tcp->kanji_1st_char = 0;
1093 break;
1094
1095 case 0x1b: /* start escape sequence */
1096 tcp->esc = 1;
1097 tcp->num_param = 0;
1098 break;
1099 }
1100 ptr++;
1101 len--;
1102 }
1103
1104 sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
1105
1106 scp->sc->write_in_progress--;
1107 if (len)
1108 goto outloop;
1109}
1110
1111static int
1112scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
1113 struct thread *td)
1114{
1115 term_stat *tcp = scp->ts;
1116 vid_info_t *vi;
1117
1118 switch (cmd) {
1119 case GIO_ATTR: /* get current attributes */
1120 /* FIXME: */
1121 *(int*)data = (tcp->cur_attr >> 8) & 0xff;
1122 return 0;
1123 case CONS_GETINFO: /* get current (virtual) console info */
1124 vi = (vid_info_t *)data;
1125 if (vi->size != sizeof(struct vid_info))
1126 return EINVAL;
1127 vi->mv_norm.fore = tcp->std_color.fg;
1128 vi->mv_norm.back = tcp->std_color.bg;
1129 vi->mv_rev.fore = tcp->rev_color.fg;
1130 vi->mv_rev.back = tcp->rev_color.bg;
1131 /*
1132 * The other fields are filled by the upper routine. XXX
1133 */
1134 return ENOIOCTL;
1135 }
1136 return ENOIOCTL;
1137}
1138
1139static int
1140scterm_reset(scr_stat *scp, int code)
1141{
1142 /* FIXME */
1143 return 0;
1144}
1145
1146static void
1147scterm_default_attr(scr_stat *scp, int color, int rev_color)
1148{
1149 term_stat *tcp = scp->ts;
1150
1151 tcp->dflt_std_color.fg = color & 0x0f;
1152 tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
1153 tcp->dflt_rev_color.fg = rev_color & 0x0f;
1154 tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
1155 tcp->std_color = tcp->dflt_std_color;
1156 tcp->rev_color = tcp->dflt_rev_color;
1157 tcp->cur_color = tcp->std_color;
1158 tcp->cur_attr = mask2attr(tcp);
1159}
1160
1161static void
1162scterm_clear(scr_stat *scp)
1163{
1164 term_stat *tcp = scp->ts;
1165
1166 sc_move_cursor(scp, 0, 0);
1167 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
1168 mark_all(scp);
1169}
1170
1171static void
1172scterm_notify(scr_stat *scp, int event)
1173{
1174 switch (event) {
1175 case SC_TE_NOTIFY_VTSWITCH_IN:
1176 break;
1177 case SC_TE_NOTIFY_VTSWITCH_OUT:
1178 break;
1179 }
1180}
1181
1182static int
1183scterm_input(scr_stat *scp, int c, struct tty *tp)
1184{
1185 return FALSE;
1186}
1187
1188/*
1189 * Calculate hardware attributes word using logical attributes mask and
1190 * hardware colors
1191 */
1192
1193/* FIXME */
1194static int
1195mask2attr(term_stat *tcp)
1196{
1197 int attr, mask = tcp->attr_mask;
1198
1199 if (mask & REVERSE_ATTR) {
1200 attr = ((mask & FG_CHANGED) ?
1201 tcp->cur_color.bg : tcp->rev_color.fg) |
1202 (((mask & BG_CHANGED) ?
1203 tcp->cur_color.fg : tcp->rev_color.bg) << 4);
1204 } else
1205 attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
1206
1207 /* XXX: underline mapping for Hercules adapter can be better */
1208 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
1209 attr ^= 0x08;
1210 if (mask & BLINK_ATTR)
1211 attr ^= 0x80;
1212
1213 return (attr << 8);
1214}
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 */
51typedef struct {
52 u_short fg; /* foreground color */
53 u_short bg; /* background color */
54} color_t;
55
56typedef 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
97static sc_term_init_t scterm_init;
98static sc_term_term_t scterm_term;
99static sc_term_puts_t scterm_puts;
100static sc_term_ioctl_t scterm_ioctl;
101static sc_term_reset_t scterm_reset;
102static sc_term_default_attr_t scterm_default_attr;
103static sc_term_clear_t scterm_clear;
104static sc_term_notify_t scterm_notify;
105static sc_term_input_t scterm_input;
106
107static 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
125SCTERM_MODULE(sc, sc_term_sc);
126
127static term_stat reserved_term_stat;
128static int default_kanji = UJIS;
129static void scterm_scan_esc(scr_stat *scp, term_stat *tcp,
130 u_char c);
131static int mask2attr(term_stat *tcp);
132
133#ifdef KANJI
134__inline static u_char
135iskanji1(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
188iskanji2(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 */
246static 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
253static u_short
254kanji_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
301static int
302scterm_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
353static int
354scterm_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
364static void
365scterm_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
909static void
910scterm_puts(scr_stat *scp, u_char *buf, int len)
911{
912 term_stat *tcp;
913 u_char *ptr;
914#ifdef KANJI
915 u_short kanji_code;
916#endif
917
918 tcp = scp->ts;
919 ptr = buf;
920outloop:
921 scp->sc->write_in_progress++;
922
923 if (tcp->esc) {
924 scterm_scan_esc(scp, tcp, *ptr++);
925 len--;
926 } else if (PRINTABLE(*ptr)) { /* Print only printables */
927 vm_offset_t p;
928 u_char *map;
929 int attr;
930 int i;
931 int cnt;
932#ifdef KANJI
933 u_char c;
934#endif
935
936 p = sc_vtb_pointer(&scp->vtb, scp->cursor_pos);
937 map = scp->sc->scr_map;
938 attr = tcp->cur_attr;
939
940#ifdef KANJI
941 c = *ptr;
942 if (tcp->kanji_1st_char == 0) {
943 tcp->kanji_type = iskanji1(tcp->kanji_type, c);
944 if (!IS_KTYPE_ASCII_or_HANKAKU(tcp->kanji_type)) {
945 /* not Ascii & not HANKAKU */
946 tcp->kanji_1st_char = c;
947 goto kanji_end;
948 } else if (tcp->kanji_type == KTYPE_ASCII) {
949 cnt = imin(len, scp->xsize - scp->xpos);
950 i = cnt;
951 do {
952 p = sc_vtb_putchar(&scp->vtb, p, map[c], attr);
953 c = *++ptr;
954 --i;
955 } while (i > 0 && PRINTABLE(c) &&
956 iskanji1(tcp->kanji_type, c) == KTYPE_ASCII);
957
958 len -= cnt - i;
959 mark_for_update(scp, scp->cursor_pos);
960 scp->cursor_pos += cnt - i;
961 mark_for_update(scp, scp->cursor_pos - 1);
962 scp->xpos += cnt - i;
963 KTYPE_MASK_CTRL(tcp->kanji_type);
964 goto ascii_end;
965 }
966 } else {
967 if ((tcp->kanji_type =
968 iskanji2(tcp->kanji_type, c)) & 0xee) {
969 /* print kanji on TEXT VRAM */
970 kanji_code = kanji_convert(tcp->kanji_type, c,
971 tcp->kanji_1st_char);
972 mark_for_update(scp, scp->cursor_pos);
973 for (i = 0; i < 2; i++) {
974 /* *cursor_pos = (kanji_code | (i*0x80)); */
975 p = sc_vtb_putchar(&scp->vtb, p,
976 kanji_code | ((i == 0) ? 0x00 : 0x80), attr);
977 ++scp->cursor_pos;
978 if (++scp->xpos >= scp->xsize) {
979 scp->xpos = 0;
980 scp->ypos++;
981 }
982 }
983 mark_for_update(scp, scp->cursor_pos - 1);
984 KTYPE_MASK_CTRL(tcp->kanji_type);
985 tcp->kanji_1st_char = 0;
986 goto kanji_end;
987 } else {
988 tcp->kanji_1st_char = 0;
989 }
990 }
991 if (IS_KTYPE_KANA(tcp->kanji_type))
992 c |= 0x80;
993 KTYPE_MASK_CTRL(tcp->kanji_type);
994 sc_vtb_putchar(&scp->vtb, p, map[c], attr);
995 mark_for_update(scp, scp->cursor_pos);
996 mark_for_update(scp, scp->cursor_pos);
997 ++scp->cursor_pos;
998 ++scp->xpos;
999kanji_end:
1000 ++ptr;
1001 --len;
1002ascii_end:
1003#else /* !KANJI */
1004 cnt = imin(len, scp->xsize - scp->xpos);
1005 i = cnt;
1006 do {
1007 /*
1008 * gcc-2.6.3 generates poor (un)sign extension code.
1009 * Casting the pointers in the following to volatile should
1010 * have no effect, but in fact speeds up this inner loop
1011 * from 26 to 18 cycles (+ cache misses) on i486's.
1012 */
1013#define UCVP(ucp) ((u_char volatile *)(ucp))
1014 p = sc_vtb_putchar(&scp->vtb, p, UCVP(map)[*UCVP(ptr)],
1015 attr);
1016 ++ptr;
1017 --i;
1018 } while (i > 0 && PRINTABLE(*ptr));
1019
1020 len -= cnt - i;
1021 mark_for_update(scp, scp->cursor_pos);
1022 scp->cursor_pos += cnt - i;
1023 mark_for_update(scp, scp->cursor_pos - 1);
1024 scp->xpos += cnt - i;
1025#endif /* !KANJI */
1026
1027 if (scp->xpos >= scp->xsize) {
1028 scp->xpos = 0;
1029 scp->ypos++;
1030 }
1031 } else {
1032 switch (*ptr) {
1033 case 0x07:
1034 sc_bell(scp, scp->bell_pitch, scp->bell_duration);
1035 break;
1036
1037 case 0x08: /* non-destructive backspace */
1038 if (scp->cursor_pos > 0) {
1039 mark_for_update(scp, scp->cursor_pos);
1040 scp->cursor_pos--;
1041 mark_for_update(scp, scp->cursor_pos);
1042 if (scp->xpos > 0)
1043 scp->xpos--;
1044 else {
1045 scp->xpos += scp->xsize - 1;
1046 scp->ypos--;
1047 }
1048 }
1049 break;
1050
1051 case 0x09: /* non-destructive tab */
1052 mark_for_update(scp, scp->cursor_pos);
1053 scp->cursor_pos += (8 - scp->xpos % 8u);
1054 scp->xpos += (8 - scp->xpos % 8u);
1055 if (scp->xpos >= scp->xsize) {
1056 scp->xpos = 0;
1057 scp->ypos++;
1058 scp->cursor_pos = scp->xsize * scp->ypos;
1059 }
1060 mark_for_update(scp, scp->cursor_pos);
1061 break;
1062
1063 case 0x0a: /* newline, same pos */
1064 mark_for_update(scp, scp->cursor_pos);
1065 scp->cursor_pos += scp->xsize;
1066 mark_for_update(scp, scp->cursor_pos);
1067 scp->ypos++;
1068 break;
1069
1070 case 0x0c: /* form feed, clears screen */
1071 sc_clear_screen(scp);
1072 break;
1073
1074 case 0x0d: /* return, return to pos 0 */
1075 mark_for_update(scp, scp->cursor_pos);
1076 scp->cursor_pos -= scp->xpos;
1077 mark_for_update(scp, scp->cursor_pos);
1078 scp->xpos = 0;
1079 break;
1080
1081 case 0x0e: /* ^N */
1082 tcp->kanji_type = KTYPE_JKANA;
1083 tcp->esc = 0;
1084 tcp->kanji_1st_char = 0;
1085 break;
1086
1087 case 0x0f: /* ^O */
1088 tcp->kanji_type = KTYPE_ASCII;
1089 tcp->esc = 0;
1090 tcp->kanji_1st_char = 0;
1091 break;
1092
1093 case 0x1b: /* start escape sequence */
1094 tcp->esc = 1;
1095 tcp->num_param = 0;
1096 break;
1097 }
1098 ptr++;
1099 len--;
1100 }
1101
1102 sc_term_gen_scroll(scp, scp->sc->scr_map[0x20], tcp->cur_attr);
1103
1104 scp->sc->write_in_progress--;
1105 if (len)
1106 goto outloop;
1107}
1108
1109static int
1110scterm_ioctl(scr_stat *scp, struct tty *tp, u_long cmd, caddr_t data,
1111 struct thread *td)
1112{
1113 term_stat *tcp = scp->ts;
1114 vid_info_t *vi;
1115
1116 switch (cmd) {
1117 case GIO_ATTR: /* get current attributes */
1118 /* FIXME: */
1119 *(int*)data = (tcp->cur_attr >> 8) & 0xff;
1120 return 0;
1121 case CONS_GETINFO: /* get current (virtual) console info */
1122 vi = (vid_info_t *)data;
1123 if (vi->size != sizeof(struct vid_info))
1124 return EINVAL;
1125 vi->mv_norm.fore = tcp->std_color.fg;
1126 vi->mv_norm.back = tcp->std_color.bg;
1127 vi->mv_rev.fore = tcp->rev_color.fg;
1128 vi->mv_rev.back = tcp->rev_color.bg;
1129 /*
1130 * The other fields are filled by the upper routine. XXX
1131 */
1132 return ENOIOCTL;
1133 }
1134 return ENOIOCTL;
1135}
1136
1137static int
1138scterm_reset(scr_stat *scp, int code)
1139{
1140 /* FIXME */
1141 return 0;
1142}
1143
1144static void
1145scterm_default_attr(scr_stat *scp, int color, int rev_color)
1146{
1147 term_stat *tcp = scp->ts;
1148
1149 tcp->dflt_std_color.fg = color & 0x0f;
1150 tcp->dflt_std_color.bg = (color >> 4) & 0x0f;
1151 tcp->dflt_rev_color.fg = rev_color & 0x0f;
1152 tcp->dflt_rev_color.bg = (rev_color >> 4) & 0x0f;
1153 tcp->std_color = tcp->dflt_std_color;
1154 tcp->rev_color = tcp->dflt_rev_color;
1155 tcp->cur_color = tcp->std_color;
1156 tcp->cur_attr = mask2attr(tcp);
1157}
1158
1159static void
1160scterm_clear(scr_stat *scp)
1161{
1162 term_stat *tcp = scp->ts;
1163
1164 sc_move_cursor(scp, 0, 0);
1165 sc_vtb_clear(&scp->vtb, scp->sc->scr_map[0x20], tcp->cur_attr);
1166 mark_all(scp);
1167}
1168
1169static void
1170scterm_notify(scr_stat *scp, int event)
1171{
1172 switch (event) {
1173 case SC_TE_NOTIFY_VTSWITCH_IN:
1174 break;
1175 case SC_TE_NOTIFY_VTSWITCH_OUT:
1176 break;
1177 }
1178}
1179
1180static int
1181scterm_input(scr_stat *scp, int c, struct tty *tp)
1182{
1183 return FALSE;
1184}
1185
1186/*
1187 * Calculate hardware attributes word using logical attributes mask and
1188 * hardware colors
1189 */
1190
1191/* FIXME */
1192static int
1193mask2attr(term_stat *tcp)
1194{
1195 int attr, mask = tcp->attr_mask;
1196
1197 if (mask & REVERSE_ATTR) {
1198 attr = ((mask & FG_CHANGED) ?
1199 tcp->cur_color.bg : tcp->rev_color.fg) |
1200 (((mask & BG_CHANGED) ?
1201 tcp->cur_color.fg : tcp->rev_color.bg) << 4);
1202 } else
1203 attr = tcp->cur_color.fg | (tcp->cur_color.bg << 4);
1204
1205 /* XXX: underline mapping for Hercules adapter can be better */
1206 if (mask & (BOLD_ATTR | UNDERLINE_ATTR))
1207 attr ^= 0x08;
1208 if (mask & BLINK_ATTR)
1209 attr ^= 0x80;
1210
1211 return (attr << 8);
1212}
1215
1216#endif /* SC_DUMB_TERMINAL */