rcons_subr.c revision 1.8 1 /* $NetBSD: rcons_subr.c,v 1.8 2001/09/18 18:15:53 wiz Exp $ */
2
3 /*
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * @(#)rcons_subr.c 8.1 (Berkeley) 6/11/93
45 */
46
47 #ifdef _KERNEL
48 #include <sys/param.h>
49 #include <sys/device.h>
50 #include <sys/systm.h>
51 #else
52 #include <sys/types.h>
53 #include "myfbdevice.h"
54 #endif
55
56 #include <dev/rcons/rcons.h>
57 #include <dev/wscons/wsdisplayvar.h>
58
59 extern void rcons_bell(struct rconsole *);
60
61 #if 0
62 #define RCONS_ISPRINT(c) ((((c) >= ' ') && ((c) <= '~')) || ((c) > 160))
63 #else
64 #define RCONS_ISPRINT(c) (((((c) >= ' ') && ((c) <= '~'))) || ((c) > 127))
65 #endif
66 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
67
68 /* Initialize our operations set */
69 void
70 rcons_init_ops(rc)
71 struct rconsole *rc;
72 {
73 long tmp;
74 int i, m;
75
76 m = sizeof(rc->rc_charmap) / sizeof(rc->rc_charmap[0]);
77
78 for (i = 0; i < m; i++)
79 rc->rc_ops->mapchar(rc->rc_cookie, i, rc->rc_charmap + i);
80
81 /* Determine which attributes the device supports. */
82 #ifdef RASTERCONSOLE_FGCOL
83 rc->rc_deffgcolor = RASTERCONSOLE_FGCOL;
84 #endif
85 #ifdef RASTERCONSOLE_BGCOL
86 rc->rc_defbgcolor = RASTERCONSOLE_BGCOL;
87 #endif
88 rc->rc_fgcolor = rc->rc_deffgcolor;
89 rc->rc_bgcolor = rc->rc_defbgcolor;
90 rc->rc_supwsflg = 0;
91
92 for (i = 1; i < 256; i <<= 1)
93 if (rc->rc_ops->alloc_attr(rc->rc_cookie, 0, 0, i, &tmp) == 0)
94 rc->rc_supwsflg |= i;
95
96 /* Allocate kernel output attribute */
97 rc->rc_wsflg = WSATTR_HILIT;
98 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
99 rc->rc_kern_attr = rc->rc_attr;
100
101 rc->rc_wsflg = 0;
102 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
103 rc->rc_defattr = rc->rc_attr;
104 }
105
106 /* Output (or at least handle) a string sent to the console */
107 void
108 rcons_puts(rc, str, n)
109 struct rconsole *rc;
110 unsigned char *str;
111 int n;
112 {
113 int c, i, j;
114 unsigned char *cp;
115
116 /* Jump scroll */
117 /* XXX maybe this should be an option? */
118 if ((rc->rc_bits & FB_INESC) == 0) {
119 /* Count newlines up to an escape sequence */
120 i = 0;
121 j = 0;
122 for (cp = str; j++ < n && *cp != '\033'; ++cp) {
123 if (*cp == '\n')
124 ++i;
125 else if (*cp == '\013')
126 --i;
127 }
128
129 /* Only jump scroll two or more rows */
130 if (rc->rc_row + i > rc->rc_maxrow + 1) {
131 /* Erase the cursor (if necessary) */
132 if (rc->rc_bits & FB_CURSOR)
133 rcons_cursor(rc);
134
135 rcons_scroll(rc, i);
136 }
137 }
138
139 /* Process characters */
140 while (--n >= 0) {
141 c = *str;
142 if (c == '\033') {
143 /* Start an escape (perhaps aborting one in progress) */
144 rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
145 rc->rc_bits &= ~(FB_P0 | FB_P1);
146
147 /* Most parameters default to 1 */
148 rc->rc_p0 = rc->rc_p1 = 1;
149 } else if (rc->rc_bits & FB_INESC) {
150 rcons_esc(rc, c);
151 } else {
152 /* Erase the cursor (if necessary) */
153 if (rc->rc_bits & FB_CURSOR)
154 rcons_cursor(rc);
155
156 /* Display the character */
157 if (RCONS_ISPRINT(c)) {
158 /* Try to output as much as possible */
159 j = rc->rc_maxcol - rc->rc_col;
160 if (j > n)
161 j = n;
162 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
163 continue;
164 rcons_text(rc, str, i);
165 --i;
166 str += i;
167 n -= i;
168 } else
169 rcons_pctrl(rc, c);
170 }
171 ++str;
172 }
173 /* Redraw the cursor (if necessary) */
174 if ((rc->rc_bits & FB_CURSOR) == 0)
175 rcons_cursor(rc);
176 }
177
178
179 /* Handle a control character sent to the console */
180 void
181 rcons_pctrl(rc, c)
182 struct rconsole *rc;
183 int c;
184 {
185
186 switch (c) {
187 case '\r': /* Carriage return */
188 rc->rc_col = 0;
189 break;
190
191 case '\b': /* Backspace */
192 if (rc->rc_col > 0)
193 (rc->rc_col)--;
194 break;
195
196 case '\v': /* Vertical tab */
197 if (rc->rc_row > 0)
198 (rc->rc_row)--;
199 break;
200
201 case '\f': /* Formfeed */
202 rc->rc_row = rc->rc_col = 0;
203 rcons_clear2eop(rc);
204 break;
205
206 case '\n': /* Linefeed */
207 (rc->rc_row)++;
208 if (rc->rc_row >= rc->rc_maxrow)
209 rcons_scroll(rc, 1);
210 break;
211
212 case '\a': /* Bell */
213 rcons_bell(rc);
214 break;
215
216 case '\t': /* Horizontal tab */
217 rc->rc_col = (rc->rc_col + 8) & ~7;
218 if (rc->rc_col >= rc->rc_maxcol)
219 rc->rc_col = rc->rc_maxcol;
220 break;
221 }
222 }
223
224 /* Handle the next character in an escape sequence */
225 void
226 rcons_esc(rc, c)
227 struct rconsole *rc;
228 int c;
229 {
230
231 if (c == '[') {
232 /* Parameter 0 */
233 rc->rc_bits &= ~FB_P1;
234 rc->rc_bits |= FB_P0;
235 } else if (c == ';') {
236 /* Parameter 1 */
237 rc->rc_bits &= ~FB_P0;
238 rc->rc_bits |= FB_P1;
239 } else if (RCONS_ISDIGIT(c)) {
240 /* Add a digit to a parameter */
241 if (rc->rc_bits & FB_P0) {
242 /* Parameter 0 */
243 if (rc->rc_bits & FB_P0_DEFAULT) {
244 rc->rc_bits &= ~FB_P0_DEFAULT;
245 rc->rc_p0 = 0;
246 }
247 rc->rc_p0 *= 10;
248 rc->rc_p0 += c - '0';
249 } else if (rc->rc_bits & FB_P1) {
250 /* Parameter 1 */
251 if (rc->rc_bits & FB_P1_DEFAULT) {
252 rc->rc_bits &= ~FB_P1_DEFAULT;
253 rc->rc_p1 = 0;
254 }
255 rc->rc_p1 *= 10;
256 rc->rc_p1 += c - '0';
257 }
258 } else {
259 /* Erase the cursor (if necessary) */
260 if (rc->rc_bits & FB_CURSOR)
261 rcons_cursor(rc);
262
263 /* Process the completed escape sequence */
264 rcons_doesc(rc, c);
265 rc->rc_bits &= ~FB_INESC;
266 }
267 }
268
269
270 /* Handle an SGR (Select Graphic Rendition) escape */
271 void
272 rcons_sgresc(rc, c)
273 struct rconsole *rc;
274 int c;
275 {
276
277 switch (c) {
278 /* Clear all attributes || End underline */
279 case 0:
280 rc->rc_wsflg = 0;
281 rc->rc_fgcolor = rc->rc_deffgcolor;
282 rc->rc_bgcolor = rc->rc_defbgcolor;
283 rc->rc_attr = rc->rc_defattr;
284 break;
285
286 /* ANSI foreground color */
287 case 30: case 31: case 32: case 33:
288 case 34: case 35: case 36: case 37:
289 rcons_setcolor(rc, c - 30, rc->rc_bgcolor);
290 break;
291
292 /* ANSI background color */
293 case 40: case 41: case 42: case 43:
294 case 44: case 45: case 46: case 47:
295 rcons_setcolor(rc, rc->rc_fgcolor, c - 40);
296 break;
297
298 /* Begin reverse */
299 case 7:
300 rc->rc_wsflg |= WSATTR_REVERSE;
301 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
302 break;
303
304 /* Begin bold */
305 case 1:
306 rc->rc_wsflg |= WSATTR_HILIT;
307 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
308 break;
309
310 /* Begin underline */
311 case 4:
312 rc->rc_wsflg |= WSATTR_UNDERLINE;
313 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
314 break;
315 }
316 }
317
318
319 /* Process a complete escape sequence */
320 void
321 rcons_doesc(rc, c)
322 struct rconsole *rc;
323 int c;
324 {
325
326 #ifdef notdef
327 /* XXX add escape sequence to enable visual (and audible) bell */
328 rc->rc_bits = FB_VISBELL;
329 #endif
330
331 switch (c) {
332
333 case '@':
334 /* Insert Character (ICH) */
335 rcons_insertchar(rc, rc->rc_p0);
336 break;
337
338 case 'A':
339 /* Cursor Up (CUU) */
340 rc->rc_row -= rc->rc_p0;
341 if (rc->rc_row < 0)
342 rc->rc_row = 0;
343 break;
344
345 case 'B':
346 /* Cursor Down (CUD) */
347 rc->rc_row += rc->rc_p0;
348 if (rc->rc_row >= rc->rc_maxrow)
349 rc->rc_row = rc->rc_maxrow - 1;
350 break;
351
352 case 'C':
353 /* Cursor Forward (CUF) */
354 rc->rc_col += rc->rc_p0;
355 if (rc->rc_col >= rc->rc_maxcol)
356 rc->rc_col = rc->rc_maxcol - 1;
357 break;
358
359 case 'D':
360 /* Cursor Backward (CUB) */
361 rc->rc_col -= rc->rc_p0;
362 if (rc->rc_col < 0)
363 rc->rc_col = 0;
364 break;
365
366 case 'E':
367 /* Cursor Next Line (CNL) */
368 rc->rc_col = 0;
369 rc->rc_row += rc->rc_p0;
370 if (rc->rc_row >= rc->rc_maxrow)
371 rc->rc_row = rc->rc_maxrow - 1;
372 break;
373
374 case 'f':
375 /* Horizontal And Vertical Position (HVP) */
376 case 'H':
377 /* Cursor Position (CUP) */
378 rc->rc_col = rc->rc_p1 - 1;
379 if (rc->rc_col < 0)
380 rc->rc_col = 0;
381 else if (rc->rc_col >= rc->rc_maxcol)
382 rc->rc_col = rc->rc_maxcol - 1;
383
384 rc->rc_row = rc->rc_p0 - 1;
385 if (rc->rc_row < 0)
386 rc->rc_row = 0;
387 else if (rc->rc_row >= rc->rc_maxrow)
388 rc->rc_row = rc->rc_maxrow - 1;
389 break;
390
391 case 'J':
392 /* Erase in Display (ED) */
393 rcons_clear2eop(rc);
394 break;
395
396 case 'K':
397 /* Erase in Line (EL) */
398 rcons_clear2eol(rc);
399 break;
400
401 case 'L':
402 /* Insert Line (IL) */
403 rcons_insertline(rc, rc->rc_p0);
404 break;
405
406 case 'M':
407 /* Delete Line (DL) */
408 rcons_delline(rc, rc->rc_p0);
409 break;
410
411 case 'P':
412 /* Delete Character (DCH) */
413 rcons_delchar(rc, rc->rc_p0);
414 break;
415
416 case 'm':
417 /* Select Graphic Rendition (SGR) */
418 /* (defaults to zero) */
419 if (rc->rc_bits & FB_P0_DEFAULT)
420 rc->rc_p0 = 0;
421
422 if (rc->rc_bits & FB_P1_DEFAULT)
423 rc->rc_p1 = 0;
424
425 rcons_sgresc(rc, rc->rc_p0);
426
427 if (rc->rc_bits & FB_P1)
428 rcons_sgresc(rc, rc->rc_p1);
429
430 break;
431
432 /*
433 * XXX: setting SUNBOW and SUNWOB should probably affect
434 * deffgcolor, defbgcolor and defattr too.
435 */
436 case 'p':
437 /* Black On White (SUNBOW) */
438 rcons_setcolor(rc, WSCOL_BLACK, WSCOL_WHITE);
439 break;
440
441 case 'q':
442 /* White On Black (SUNWOB) */
443 rcons_setcolor(rc, WSCOL_WHITE, WSCOL_BLACK);
444 break;
445
446 case 'r':
447 /* Set scrolling (SUNSCRL) */
448 /* (defaults to zero) */
449 if (rc->rc_bits & FB_P0_DEFAULT)
450 rc->rc_p0 = 0;
451 /* XXX not implemented yet */
452 rc->rc_scroll = rc->rc_p0;
453 break;
454
455 case 's':
456 /* Reset terminal emulator (SUNRESET) */
457 rc->rc_wsflg = 0;
458 rc->rc_scroll = 0;
459 rc->rc_bits &= ~FB_NO_CURSOR;
460 rc->rc_fgcolor = rc->rc_deffgcolor;
461 rc->rc_bgcolor = rc->rc_defbgcolor;
462 rc->rc_attr = rc->rc_defattr;
463
464 if (rc->rc_bits & FB_INVERT)
465 rcons_invert(rc, 0);
466 break;
467 #ifdef notyet
468 /*
469 * XXX following two read \E[?25h and \E[?25l. rcons
470 * can't currently handle the '?'.
471 */
472 case 'h':
473 /* Normal/very visible cursor */
474 if (rc->rc_p0 == 25) {
475 rc->rc_bits &= ~FB_NO_CURSOR;
476
477 if (rc->rc_bits & FB_CURSOR) {
478 rc->rc_bits ^= FB_CURSOR;
479 rcons_cursor(rc);
480 }
481 }
482 break;
483
484 case 'l':
485 /* Invisible cursor */
486 if (rc->rc_p0 == 25 && (rc->rc_bits & FB_NO_CURSOR) == 0) {
487 if (rc->rc_bits & FB_CURSOR)
488 rcons_cursor(rc);
489
490 rc->rc_bits |= FB_NO_CURSOR;
491 }
492 break;
493 #endif
494 }
495 }
496
497 /* Set ANSI colors */
498 void
499 rcons_setcolor(rc, fg, bg)
500 struct rconsole *rc;
501 int fg, bg;
502 {
503 int flg;
504
505 if (fg > WSCOL_WHITE || fg < 0)
506 return;
507
508 if (bg > WSCOL_WHITE || bg < 0)
509 return;
510
511 #ifdef RASTERCONS_WONB
512 flg = bg;
513 bg = fg;
514 fg = flg;
515 #endif
516
517 /* Emulate WSATTR_REVERSE attribute if it's not supported */
518 if ((rc->rc_wsflg & WSATTR_REVERSE) &&
519 !(rc->rc_supwsflg & WSATTR_REVERSE)) {
520 flg = bg;
521 bg = fg;
522 fg = flg;
523 }
524
525 /*
526 * Mask out unsupported flags and get attribute
527 * XXX - always ask for WSCOLORS if supported (why shouldn't we?)
528 */
529 flg = (rc->rc_wsflg | WSATTR_WSCOLORS) & rc->rc_supwsflg;
530 rc->rc_bgcolor = bg;
531 rc->rc_fgcolor = fg;
532 rc->rc_ops->alloc_attr(rc->rc_cookie, fg, bg, flg, &rc->rc_attr);
533 }
534
535
536 /* Actually write a string to the frame buffer */
537 void
538 rcons_text(rc, str, n)
539 struct rconsole *rc;
540 unsigned char *str;
541 int n;
542 {
543 u_int uc;
544
545 while (n--) {
546 uc = rc->rc_charmap[*str++ & 255];
547 rc->rc_ops->putchar(rc->rc_cookie, rc->rc_row, rc->rc_col++,
548 uc, rc->rc_attr);
549 }
550
551 if (rc->rc_col >= rc->rc_maxcol) {
552 rc->rc_col = 0;
553 rc->rc_row++;
554 }
555
556 if (rc->rc_row >= rc->rc_maxrow)
557 rcons_scroll(rc, 1);
558 }
559
560 /* Paint (or unpaint) the cursor */
561 void
562 rcons_cursor(rc)
563 struct rconsole *rc;
564 {
565 rc->rc_bits ^= FB_CURSOR;
566
567 if (rc->rc_bits & FB_NO_CURSOR)
568 return;
569
570 rc->rc_ops->cursor(rc->rc_cookie, rc->rc_bits & FB_CURSOR,
571 rc->rc_row, rc->rc_col);
572 }
573
574 /* Possibly change to SUNWOB or SUNBOW mode */
575 void
576 rcons_invert(rc, wob)
577 struct rconsole *rc;
578 int wob;
579 {
580
581 rc->rc_bits ^= FB_INVERT;
582 /* XXX how do we do we invert the framebuffer?? */
583 }
584
585 /* Clear to the end of the page */
586 void
587 rcons_clear2eop(rc)
588 struct rconsole *rc;
589 {
590 if (rc->rc_col || rc->rc_row) {
591 rcons_clear2eol(rc);
592
593 if (rc->rc_row < (rc->rc_maxrow - 1))
594 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row + 1,
595 rc->rc_maxrow, rc->rc_attr);
596 } else
597 rc->rc_ops->eraserows(rc->rc_cookie, 0, rc->rc_maxrow,
598 rc->rc_attr);
599 }
600
601 /* Clear to the end of the line */
602 void
603 rcons_clear2eol(rc)
604 struct rconsole *rc;
605 {
606 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
607 rc->rc_maxcol - rc->rc_col, rc->rc_attr);
608 }
609
610
611 /* Scroll up */
612 void
613 rcons_scroll(rc, n)
614 struct rconsole *rc;
615 int n;
616 {
617 /* Can't scroll more than the whole screen */
618 if (n > rc->rc_maxrow)
619 n = rc->rc_maxrow;
620
621 /* Calculate new row */
622 rc->rc_row -= n;
623
624 if (rc->rc_row < 0)
625 rc->rc_row = 0;
626
627 rc->rc_ops->copyrows(rc->rc_cookie, n, 0, rc->rc_maxrow - n);
628 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, rc->rc_attr);
629 }
630
631 /* Delete characters */
632 void
633 rcons_delchar(rc, n)
634 struct rconsole *rc;
635 int n;
636 {
637 /* Can't delete more chars than there are */
638 if (n > rc->rc_maxcol - rc->rc_col)
639 n = rc->rc_maxcol - rc->rc_col;
640
641 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col + n,
642 rc->rc_col, rc->rc_maxcol - rc->rc_col - n);
643
644 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row,
645 rc->rc_maxcol - n, n, rc->rc_attr);
646 }
647
648 /* Delete a number of lines */
649 void
650 rcons_delline(rc, n)
651 struct rconsole *rc;
652 int n;
653 {
654 /* Can't delete more lines than there are */
655 if (n > rc->rc_maxrow - rc->rc_row)
656 n = rc->rc_maxrow - rc->rc_row;
657
658 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row + n, rc->rc_row,
659 rc->rc_maxrow - rc->rc_row - n);
660
661 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n,
662 rc->rc_attr);
663 }
664
665 /* Insert some characters */
666 void
667 rcons_insertchar(rc, n)
668 struct rconsole *rc;
669 int n;
670 {
671 /* Can't insert more chars than can fit */
672 if (n > rc->rc_maxcol - rc->rc_col)
673 n = rc->rc_maxcol - rc->rc_col - 1;
674
675 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col,
676 rc->rc_col + n, rc->rc_maxcol - rc->rc_col - n - 1);
677
678 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
679 n, rc->rc_attr);
680 }
681
682 /* Insert some lines */
683 void
684 rcons_insertline(rc, n)
685 struct rconsole *rc;
686 int n;
687 {
688 /* Can't insert more lines than can fit */
689 if (n > rc->rc_maxrow - rc->rc_row)
690 n = rc->rc_maxrow - rc->rc_row;
691
692 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row, rc->rc_row + n,
693 rc->rc_maxrow - rc->rc_row - n);
694
695 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row, n,
696 rc->rc_attr);
697 }
698
699 /* end of rcons_subr.c */
700