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