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