wsemul_sun.c revision 1.12 1 /* $NetBSD: wsemul_sun.c,v 1.12 2001/02/21 23:12:58 jdolecek Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christopher G. Demetriou
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* XXX DESCRIPTION/SOURCE OF INFORMATION */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: wsemul_sun.c,v 1.12 2001/02/21 23:12:58 jdolecek Exp $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/time.h>
41 #include <sys/malloc.h>
42 #include <sys/fcntl.h>
43
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wscons/wsdisplayvar.h>
46 #include <dev/wscons/wsemulvar.h>
47 #include <dev/wscons/wsksymdef.h>
48 #include <dev/wscons/ascii.h>
49
50 #include "opt_wskernattr.h"
51
52 void *wsemul_sun_cnattach __P((const struct wsscreen_descr *, void *,
53 int, int, long));
54 void *wsemul_sun_attach __P((int console, const struct wsscreen_descr *,
55 void *, int, int, void *, long));
56 void wsemul_sun_output __P((void *cookie, const u_char *data, u_int count,
57 int));
58 int wsemul_sun_translate __P((void *cookie, keysym_t, char **));
59 void wsemul_sun_detach __P((void *cookie, u_int *crowp, u_int *ccolp));
60 void wsemul_sun_resetop __P((void *, enum wsemul_resetops));
61
62 const struct wsemul_ops wsemul_sun_ops = {
63 "sun",
64 wsemul_sun_cnattach,
65 wsemul_sun_attach,
66 wsemul_sun_output,
67 wsemul_sun_translate,
68 wsemul_sun_detach,
69 wsemul_sun_resetop
70 };
71
72 #define SUN_EMUL_STATE_NORMAL 0 /* normal processing */
73 #define SUN_EMUL_STATE_HAVEESC 1 /* seen start of ctl seq */
74 #define SUN_EMUL_STATE_CONTROL 2 /* processing ctl seq */
75
76 #define SUN_EMUL_NARGS 2 /* max # of args to a command */
77
78 struct wsemul_sun_emuldata {
79 const struct wsdisplay_emulops *emulops;
80 void *emulcookie;
81 void *cbcookie;
82 int scrcapabilities;
83 u_int nrows, ncols, crow, ccol;
84
85 u_int state; /* processing state */
86 u_int args[SUN_EMUL_NARGS]; /* command args, if CONTROL */
87 u_int scrolldist; /* distance to scroll */
88 long defattr; /* default attribute (rendition) */
89 long bowattr; /* attribute for reversed mode */
90 int rendflags;
91 #define REND_BOW 1
92 #define REND_SO 2
93 long curattr; /* currently used attribute */
94 long kernattr; /* attribute for kernel output */
95 #ifdef DIAGNOSTIC
96 int console;
97 #endif
98 };
99
100 static u_int wsemul_sun_output_normal __P((struct wsemul_sun_emuldata *,
101 u_char, int));
102 static u_int wsemul_sun_output_haveesc __P((struct wsemul_sun_emuldata *,
103 u_char));
104 static u_int wsemul_sun_output_control __P((struct wsemul_sun_emuldata *,
105 u_char));
106 static void wsemul_sun_control __P((struct wsemul_sun_emuldata *, u_char));
107
108 struct wsemul_sun_emuldata wsemul_sun_console_emuldata;
109
110 /* some useful utility macros */
111 #define ARG(n) (edp->args[(n)])
112 #define NORMALIZE_ARG(n) (ARG(n) ? ARG(n) : 1)
113 #define COLS_LEFT (edp->ncols - edp->ccol - 1)
114 #define ROWS_LEFT (edp->nrows - edp->crow - 1)
115
116 void *
117 wsemul_sun_cnattach(type, cookie, ccol, crow, defattr)
118 const struct wsscreen_descr *type;
119 void *cookie;
120 int ccol, crow;
121 long defattr;
122 {
123 struct wsemul_sun_emuldata *edp;
124 int res;
125
126 edp = &wsemul_sun_console_emuldata;
127
128 edp->emulops = type->textops;
129 edp->emulcookie = cookie;
130 edp->scrcapabilities = type->capabilities;
131 edp->nrows = type->nrows;
132 edp->ncols = type->ncols;
133 edp->crow = crow;
134 edp->ccol = ccol;
135 edp->curattr = edp->defattr = defattr;
136 #if defined(WS_KERNEL_FG) || defined(WS_KERNEL_BG) || \
137 defined(WS_KERNEL_COLATTR) || defined(WS_KERNEL_MONOATTR)
138 #ifndef WS_KERNEL_FG
139 #define WS_KERNEL_FG WSCOL_WHITE
140 #endif
141 #ifndef WS_KERNEL_BG
142 #define WS_KERNEL_BG WSCOL_BLACK
143 #endif
144 #ifndef WS_KERNEL_COLATTR
145 #define WS_KERNEL_COLATTR 0
146 #endif
147 #ifndef WS_KERNEL_MONOATTR
148 #define WS_KERNEL_MONOATTR 0
149 #endif
150 if (type->capabilities & WSSCREEN_WSCOLORS)
151 res = (*edp->emulops->alloc_attr)(cookie,
152 WS_KERNEL_FG, WS_KERNEL_BG,
153 WS_KERNEL_COLATTR | WSATTR_WSCOLORS,
154 &edp->kernattr);
155 else
156 res = (*edp->emulops->alloc_attr)(cookie, 0, 0,
157 WS_KERNEL_MONOATTR,
158 &edp->kernattr);
159 if (res)
160 #else
161 res = 0; /* XXX gcc */
162 #endif
163 edp->kernattr = defattr;
164
165 edp->cbcookie = NULL;
166
167 edp->state = SUN_EMUL_STATE_NORMAL;
168 edp->scrolldist = 1;
169 #ifdef DIAGNOSTIC
170 edp->console = 1;
171 #endif
172 return (edp);
173 }
174
175 void *
176 wsemul_sun_attach(console, type, cookie, ccol, crow, cbcookie, defattr)
177 int console;
178 const struct wsscreen_descr *type;
179 void *cookie;
180 int ccol, crow;
181 void *cbcookie;
182 long defattr;
183 {
184 struct wsemul_sun_emuldata *edp;
185
186 if (console) {
187 edp = &wsemul_sun_console_emuldata;
188 #ifdef DIAGNOSTIC
189 KASSERT(edp->console == 1);
190 #endif
191 } else {
192 edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
193
194 edp->emulops = type->textops;
195 edp->emulcookie = cookie;
196 edp->scrcapabilities = type->capabilities;
197 edp->nrows = type->nrows;
198 edp->ncols = type->ncols;
199 edp->crow = crow;
200 edp->ccol = ccol;
201 edp->defattr = defattr;
202
203 edp->state = SUN_EMUL_STATE_NORMAL;
204 edp->scrolldist = 1;
205 #ifdef DIAGNOSTIC
206 edp->console = 0;
207 #endif
208 }
209
210 edp->cbcookie = cbcookie;
211
212 /* XXX This assumes that the default attribute is wob. */
213 if ((!(edp->scrcapabilities & WSSCREEN_WSCOLORS) ||
214 (*edp->emulops->alloc_attr)(edp->emulcookie,
215 WSCOL_BLACK, WSCOL_WHITE,
216 WSATTR_WSCOLORS,
217 &edp->bowattr)) &&
218 (!(edp->scrcapabilities & WSSCREEN_REVERSE) ||
219 (*edp->emulops->alloc_attr)(edp->emulcookie, 0, 0,
220 WSATTR_REVERSE,
221 &edp->bowattr)))
222 edp->bowattr = edp->defattr;
223
224 edp->curattr = edp->defattr;
225 edp->rendflags = 0;
226
227 return (edp);
228 }
229
230 static inline u_int
231 wsemul_sun_output_normal(edp, c, kernel)
232 struct wsemul_sun_emuldata *edp;
233 u_char c;
234 int kernel;
235 {
236 u_int newstate = SUN_EMUL_STATE_NORMAL;
237 u_int n;
238
239 switch (c) {
240 case ASCII_BEL: /* "Bell (BEL)" */
241 wsdisplay_emulbell(edp->cbcookie);
242 break;
243
244 case ASCII_BS: /* "Backspace (BS)" */
245 if (edp->ccol > 0)
246 edp->ccol--;
247 break;
248
249 case ASCII_CR: /* "Return (CR)" */
250 edp->ccol = 0;
251 break;
252
253 case ASCII_HT: /* "Tab (TAB)" */
254 n = min(8 - (edp->ccol & 7), COLS_LEFT);
255 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
256 edp->ccol, n,
257 kernel ? edp->kernattr : edp->curattr);
258 edp->ccol += n;
259 break;
260
261 case ASCII_FF: /* "Form Feed (FF)" */
262 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows,
263 kernel ? edp->kernattr : edp->curattr);
264 /* XXX possible in kernel output? */
265 edp->ccol = 0;
266 edp->crow = 0;
267 break;
268
269 case ASCII_VT: /* "Reverse Line Feed" */
270 if (edp->crow > 0)
271 edp->crow--;
272 break;
273
274 case ASCII_ESC: /* "Escape (ESC)" */
275 if (kernel) {
276 printf("wsemul_sun_output_normal: ESC in kernel output ignored\n");
277 break; /* ignore the ESC */
278 }
279
280 if (edp->state == SUN_EMUL_STATE_NORMAL) {
281 newstate = SUN_EMUL_STATE_HAVEESC;
282 break;
283 }
284 /* special case: fall through, we're printing one out */
285 /* FALLTHRU */
286
287 default: /* normal character */
288 (*edp->emulops->putchar)(edp->emulcookie, edp->crow, edp->ccol,
289 c, kernel ? edp->kernattr : edp->curattr);
290 edp->ccol++;
291
292 /* if cur col is still on cur line, done. */
293 if (edp->ccol < edp->ncols)
294 break;
295
296 /* wrap the column around. */
297 edp->ccol = 0;
298
299 /* FALLTHRU */
300
301 case ASCII_LF: /* "Line Feed (LF)" */
302 /* if the cur line isn't the last, incr and leave. */
303 if (edp->crow < edp->nrows - 1) {
304 edp->crow++;
305 break;
306 }
307
308 /*
309 * if we're in wrap-around mode, go to the first
310 * line and clear it.
311 */
312 if (edp->scrolldist == 0) {
313 edp->crow = 0;
314 (*edp->emulops->eraserows)(edp->emulcookie, 0, 1,
315 edp->curattr);
316 break;
317 }
318
319 /* scroll by the scrolling distance. */
320 (*edp->emulops->copyrows)(edp->emulcookie, edp->scrolldist, 0,
321 edp->nrows - edp->scrolldist);
322 (*edp->emulops->eraserows)(edp->emulcookie,
323 edp->nrows - edp->scrolldist, edp->scrolldist,
324 edp->curattr);
325 edp->crow -= edp->scrolldist - 1;
326 break;
327 }
328
329 return (newstate);
330 }
331
332 static inline u_int
333 wsemul_sun_output_haveesc(edp, c)
334 struct wsemul_sun_emuldata *edp;
335 u_char c;
336 {
337 u_int newstate;
338
339 switch (c) {
340 case '[': /* continuation of multi-char sequence */
341 memset(edp->args, 0, sizeof (edp->args));
342 newstate = SUN_EMUL_STATE_CONTROL;
343 break;
344
345 default:
346 /* spit out the escape char (???), then the new character */
347 wsemul_sun_output_normal(edp, ASCII_ESC, 0); /* ??? */
348 newstate = wsemul_sun_output_normal(edp, c, 0);
349 break;
350 }
351
352 return (newstate);
353 }
354
355 static inline void
356 wsemul_sun_control(edp, c)
357 struct wsemul_sun_emuldata *edp;
358 u_char c;
359 {
360 u_int n, src, dst;
361
362 switch (c) {
363 case '@': /* "Insert Character (ICH)" */
364 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1);
365 src = edp->ccol;
366 dst = edp->ccol + n;
367 if (dst < edp->ncols) {
368 (*edp->emulops->copycols)(edp->emulcookie, edp->crow,
369 src, dst, edp->ncols - dst);
370 }
371 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
372 src, dst - src, edp->curattr);
373 break;
374
375 case 'A': /* "Cursor Up (CUU)" */
376 edp->crow -= min(NORMALIZE_ARG(0), edp->crow);
377 break;
378
379 case 'E': /* "Cursor Next Line (CNL)" */
380 edp->ccol = 0;
381 /* FALLTHRU */
382 case 'B': /* "Cursor Down (CUD)" */
383 edp->crow += min(NORMALIZE_ARG(0), ROWS_LEFT);
384 break;
385
386 case 'C': /* "Cursor Forward (CUF)" */
387 edp->ccol += min(NORMALIZE_ARG(0), COLS_LEFT);
388 break;
389
390 case 'D': /* "Cursor Backward (CUB)" */
391 edp->ccol -= min(NORMALIZE_ARG(0), edp->ccol);
392 break;
393
394 case 'f': /* "Horizontal And Vertical Position (HVP)" */
395 case 'H': /* "Cursor Position (CUP)" */
396 edp->crow = min(NORMALIZE_ARG(1), edp->nrows) - 1;
397 edp->ccol = min(NORMALIZE_ARG(0), edp->ncols) - 1;
398 break;
399
400 case 'J': /* "Erase in Display (ED)" */
401 if (ROWS_LEFT > 0) {
402 (*edp->emulops->eraserows)(edp->emulcookie,
403 edp->crow + 1, ROWS_LEFT, edp->curattr);
404 }
405 /* FALLTHRU */
406 case 'K': /* "Erase in Line (EL)" */
407 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
408 edp->ccol, COLS_LEFT + 1, edp->curattr);
409 break;
410
411 case 'L': /* "Insert Line (IL)" */
412 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1);
413 src = edp->crow;
414 dst = edp->crow + n;
415 if (dst < edp->nrows) {
416 (*edp->emulops->copyrows)(edp->emulcookie,
417 src, dst, edp->nrows - dst);
418 }
419 (*edp->emulops->eraserows)(edp->emulcookie,
420 src, dst - src, edp->curattr);
421 break;
422
423 case 'M': /* "Delete Line (DL)" */
424 n = min(NORMALIZE_ARG(0), ROWS_LEFT + 1);
425 src = edp->crow + n;
426 dst = edp->crow;
427 if (src < edp->nrows) {
428 (*edp->emulops->copyrows)(edp->emulcookie,
429 src, dst, edp->nrows - src);
430 }
431 (*edp->emulops->eraserows)(edp->emulcookie,
432 dst + edp->nrows - src, src - dst, edp->curattr);
433 break;
434
435 case 'P': /* "Delete Character (DCH)" */
436 n = min(NORMALIZE_ARG(0), COLS_LEFT + 1);
437 src = edp->ccol + n;
438 dst = edp->ccol;
439 if (src < edp->ncols) {
440 (*edp->emulops->copycols)(edp->emulcookie, edp->crow,
441 src, dst, edp->ncols - src);
442 }
443 (*edp->emulops->erasecols)(edp->emulcookie, edp->crow,
444 dst + edp->ncols - src, src - dst, edp->curattr);
445 break;
446
447 case 'm': /* "Select Graphic Rendition (SGR)" */
448 if (ARG(0))
449 edp->rendflags |= REND_SO;
450 else
451 edp->rendflags &= ~REND_SO;
452 goto setattr;
453
454 case 'p': /* "Black On White (SUNBOW)" */
455 edp->rendflags |= REND_BOW;
456 goto setattr;
457
458 case 'q': /* "White On Black (SUNWOB)" */
459 edp->rendflags &= ~REND_BOW;
460 goto setattr;
461
462 case 'r': /* "Set Scrolling (SUNSCRL)" */
463 edp->scrolldist = min(ARG(0), edp->nrows);
464 break;
465
466 case 's': /* "Reset Terminal Emulator (SUNRESET)" */
467 edp->scrolldist = 1;
468 edp->rendflags = 0;
469 setattr:
470 if (((edp->rendflags & REND_BOW) != 0) ^
471 ((edp->rendflags & REND_SO) != 0))
472 edp->curattr = edp->bowattr;
473 else
474 edp->curattr = edp->defattr;
475 break;
476 }
477 }
478
479 static inline u_int
480 wsemul_sun_output_control(edp, c)
481 struct wsemul_sun_emuldata *edp;
482 u_char c;
483 {
484 u_int newstate = SUN_EMUL_STATE_CONTROL;
485 u_int i;
486
487 switch (c) {
488 case '0': case '1': case '2': case '3': case '4': /* argument digit */
489 case '5': case '6': case '7': case '8': case '9':
490 edp->args[0] = (edp->args[0] * 10) + (c - '0');
491 break;
492
493 case ';': /* argument terminator */
494 for (i = 1; i < SUN_EMUL_NARGS; i++)
495 edp->args[i] = edp->args[i - 1];
496 edp->args[0] = 0;
497 break;
498
499 default: /* end of escape sequence */
500 wsemul_sun_control(edp, c);
501 newstate = SUN_EMUL_STATE_NORMAL;
502 break;
503 }
504 return (newstate);
505 }
506
507 void
508 wsemul_sun_output(cookie, data, count, kernel)
509 void *cookie;
510 const u_char *data;
511 u_int count;
512 int kernel;
513 {
514 struct wsemul_sun_emuldata *edp = cookie;
515 u_int newstate;
516
517 #ifdef DIAGNOSTIC
518 if (kernel && !edp->console)
519 panic("wsemul_sun_output: kernel output, not console");
520 #endif
521
522 /* XXX */
523 (*edp->emulops->cursor)(edp->emulcookie, 0, edp->crow, edp->ccol);
524 for (; count > 0; data++, count--) {
525 if (kernel) {
526 wsemul_sun_output_normal(edp, *data, 1);
527 continue;
528 }
529 switch (edp->state) {
530 case SUN_EMUL_STATE_NORMAL:
531 /* XXX SCAN INPUT FOR NEWLINES, DO PRESCROLLING */
532 newstate = wsemul_sun_output_normal(edp, *data, 0);
533 break;
534 case SUN_EMUL_STATE_HAVEESC:
535 newstate = wsemul_sun_output_haveesc(edp, *data);
536 break;
537 case SUN_EMUL_STATE_CONTROL:
538 newstate = wsemul_sun_output_control(edp, *data);
539 break;
540 default:
541 #ifdef DIAGNOSTIC
542 panic("wsemul_sun: invalid state %d\n", edp->state);
543 #endif
544 /* try to recover, if things get screwed up... */
545 newstate = wsemul_sun_output_normal(edp, *data, 0);
546 break;
547 }
548 edp->state = newstate;
549 }
550 /* XXX */
551 (*edp->emulops->cursor)(edp->emulcookie, 1, edp->crow, edp->ccol);
552 }
553
554 static char *sun_fkeys[] = {
555 "\033[224z", /* F1 */
556 "\033[225z",
557 "\033[226z",
558 "\033[227z",
559 "\033[228z",
560 "\033[229z",
561 "\033[230z",
562 "\033[231z",
563 "\033[232z",
564 "\033[233z", /* F10 */
565 };
566
567 int
568 wsemul_sun_translate(cookie, in, out)
569 void *cookie;
570 keysym_t in;
571 char **out;
572 {
573 static char c;
574
575 if (KS_GROUP(in) == KS_GROUP_Keypad && (in & 0x80) == 0) {
576 c = in & 0xff; /* turn into ASCII */
577 *out = &c;
578 return (1);
579 }
580
581 if (in >= KS_f1 && in <= KS_f10) {
582 *out = sun_fkeys[in - KS_f1];
583 return (6);
584 }
585 if (in >= KS_F1 && in <= KS_F10) {
586 *out = sun_fkeys[in - KS_F1];
587 return (6);
588 }
589 if (in >= KS_KP_F1 && in <= KS_KP_F4) {
590 *out = sun_fkeys[in - KS_KP_F1];
591 return (6);
592 }
593
594 switch (in) {
595 case KS_Home:
596 case KS_KP_Home:
597 case KS_KP_Begin:
598 *out = "\033[214z";
599 return (6);
600 case KS_Prior:
601 case KS_KP_Prior:
602 *out = "\033[216z";
603 return (6);
604 case KS_Next:
605 case KS_KP_Next:
606 *out = "\033[222z";
607 return (6);
608 case KS_Up:
609 case KS_KP_Up:
610 *out = "\033[A";
611 return (3);
612 case KS_Down:
613 case KS_KP_Down:
614 *out = "\033[B";
615 return (3);
616 case KS_Left:
617 case KS_KP_Left:
618 *out = "\033[D";
619 return (3);
620 case KS_Right:
621 case KS_KP_Right:
622 *out = "\033[C";
623 return (3);
624 case KS_KP_Delete:
625 *out = "\177";
626 return (1);
627 }
628 return (0);
629 }
630
631 void
632 wsemul_sun_detach(cookie, crowp, ccolp)
633 void *cookie;
634 u_int *crowp, *ccolp;
635 {
636 struct wsemul_sun_emuldata *edp = cookie;
637
638 *crowp = edp->crow;
639 *ccolp = edp->ccol;
640 if (edp != &wsemul_sun_console_emuldata)
641 free(edp, M_DEVBUF);
642 }
643
644 void
645 wsemul_sun_resetop(cookie, op)
646 void *cookie;
647 enum wsemul_resetops op;
648 {
649 struct wsemul_sun_emuldata *edp = cookie;
650
651 switch (op) {
652 case WSEMUL_RESET:
653 edp->state = SUN_EMUL_STATE_NORMAL;
654 edp->scrolldist = 1;
655 edp->rendflags = 0;
656 edp->curattr = edp->defattr;
657 break;
658 case WSEMUL_CLEARSCREEN:
659 (*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows,
660 edp->defattr);
661 edp->ccol = edp->crow = 0;
662 (*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0);
663 break;
664 default:
665 break;
666 }
667 }
668