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