rcons_subr.c revision 1.6 1 /* $NetBSD: rcons_subr.c,v 1.6 1999/08/26 20:48:09 thorpej 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 /* Initalize 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 }
104
105 /* Output (or at least handle) a string sent to the console */
106 void
107 rcons_puts(rc, str, n)
108 struct rconsole *rc;
109 unsigned char *str;
110 int n;
111 {
112 int c, i, j;
113 unsigned char *cp;
114
115 /* Jump scroll */
116 /* XXX maybe this should be an option? */
117 if ((rc->rc_bits & FB_INESC) == 0) {
118 /* Count newlines up to an escape sequence */
119 i = 0;
120 j = 0;
121 for (cp = str; j++ < n && *cp != '\033'; ++cp) {
122 if (*cp == '\n')
123 ++i;
124 else if (*cp == '\013')
125 --i;
126 }
127
128 /* Only jump scroll two or more rows */
129 if (rc->rc_row + i > rc->rc_maxrow + 1) {
130 /* Erase the cursor (if necessary) */
131 if (rc->rc_bits & FB_CURSOR)
132 rcons_cursor(rc);
133
134 rcons_scroll(rc, i);
135 }
136 }
137
138 /* Process characters */
139 while (--n >= 0) {
140 c = *str;
141 if (c == '\033') {
142 /* Start an escape (perhaps aborting one in progress) */
143 rc->rc_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
144 rc->rc_bits &= ~(FB_P0 | FB_P1);
145
146 /* Most parameters default to 1 */
147 rc->rc_p0 = rc->rc_p1 = 1;
148 } else if (rc->rc_bits & FB_INESC) {
149 rcons_esc(rc, c);
150 } else {
151 /* Erase the cursor (if necessary) */
152 if (rc->rc_bits & FB_CURSOR)
153 rcons_cursor(rc);
154
155 /* Display the character */
156 if (RCONS_ISPRINT(c)) {
157 /* Try to output as much as possible */
158 j = rc->rc_maxcol - rc->rc_col;
159 if (j > n)
160 j = n;
161 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
162 continue;
163 rcons_text(rc, str, i);
164 --i;
165 str += i;
166 n -= i;
167 } else
168 rcons_pctrl(rc, c);
169 }
170 ++str;
171 }
172 /* Redraw the cursor (if necessary) */
173 if ((rc->rc_bits & FB_CURSOR) == 0)
174 rcons_cursor(rc);
175 }
176
177
178 /* Handle a control character sent to the console */
179 void
180 rcons_pctrl(rc, c)
181 struct rconsole *rc;
182 int c;
183 {
184
185 switch (c) {
186 case '\r': /* Carriage return */
187 rc->rc_col = 0;
188 break;
189
190 case '\b': /* Backspace */
191 if (rc->rc_col > 0)
192 (rc->rc_col)--;
193 break;
194
195 case '\v': /* Vertical tab */
196 if (rc->rc_row > 0)
197 (rc->rc_row)--;
198 break;
199
200 case '\f': /* Formfeed */
201 rc->rc_row = rc->rc_col = 0;
202 rcons_clear2eop(rc);
203 break;
204
205 case '\n': /* Linefeed */
206 (rc->rc_row)++;
207 if (rc->rc_row >= rc->rc_maxrow)
208 rcons_scroll(rc, 1);
209 break;
210
211 case '\a': /* Bell */
212 rcons_bell(rc);
213 break;
214
215 case '\t': /* Horizontal tab */
216 rc->rc_col = (rc->rc_col + 8) & ~7;
217 if (rc->rc_col >= rc->rc_maxcol)
218 rc->rc_col = rc->rc_maxcol;
219 break;
220 }
221 }
222
223 /* Handle the next character in an escape sequence */
224 void
225 rcons_esc(rc, c)
226 struct rconsole *rc;
227 int c;
228 {
229
230 if (c == '[') {
231 /* Parameter 0 */
232 rc->rc_bits &= ~FB_P1;
233 rc->rc_bits |= FB_P0;
234 } else if (c == ';') {
235 /* Parameter 1 */
236 rc->rc_bits &= ~FB_P0;
237 rc->rc_bits |= FB_P1;
238 } else if (RCONS_ISDIGIT(c)) {
239 /* Add a digit to a parameter */
240 if (rc->rc_bits & FB_P0) {
241 /* Parameter 0 */
242 if (rc->rc_bits & FB_P0_DEFAULT) {
243 rc->rc_bits &= ~FB_P0_DEFAULT;
244 rc->rc_p0 = 0;
245 }
246 rc->rc_p0 *= 10;
247 rc->rc_p0 += c - '0';
248 } else if (rc->rc_bits & FB_P1) {
249 /* Parameter 1 */
250 if (rc->rc_bits & FB_P1_DEFAULT) {
251 rc->rc_bits &= ~FB_P1_DEFAULT;
252 rc->rc_p1 = 0;
253 }
254 rc->rc_p1 *= 10;
255 rc->rc_p1 += c - '0';
256 }
257 } else {
258 /* Erase the cursor (if necessary) */
259 if (rc->rc_bits & FB_CURSOR)
260 rcons_cursor(rc);
261
262 /* Process the completed escape sequence */
263 rcons_doesc(rc, c);
264 rc->rc_bits &= ~FB_INESC;
265 }
266 }
267
268
269 /* Handle an SGR (Select Graphic Rendition) escape */
270 void
271 rcons_sgresc(rc, c)
272 struct rconsole *rc;
273 int c;
274 {
275
276 switch (c) {
277 /* Clear all attributes || End underline */
278 case 0:
279 rc->rc_wsflg = 0;
280 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
281 break;
282
283 /* ANSI foreground color */
284 case 30: case 31: case 32: case 33:
285 case 34: case 35: case 36: case 37:
286 rcons_setcolor(rc, c - 30, rc->rc_bgcolor);
287 break;
288
289 /* ANSI background color */
290 case 40: case 41: case 42: case 43:
291 case 44: case 45: case 46: case 47:
292 rcons_setcolor(rc, rc->rc_fgcolor, c - 40);
293 break;
294
295 /* Begin reverse */
296 case 7:
297 rc->rc_wsflg |= WSATTR_REVERSE;
298 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
299 break;
300
301 /* Begin bold */
302 case 1:
303 rc->rc_wsflg |= WSATTR_HILIT;
304 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
305 break;
306
307 /* Begin underline */
308 case 4:
309 rc->rc_wsflg |= WSATTR_UNDERLINE;
310 rcons_setcolor(rc, rc->rc_fgcolor, rc->rc_bgcolor);
311 break;
312 }
313 }
314
315
316 /* Process a complete escape sequence */
317 void
318 rcons_doesc(rc, c)
319 struct rconsole *rc;
320 int c;
321 {
322
323 #ifdef notdef
324 /* XXX add escape sequence to enable visual (and audible) bell */
325 rc->rc_bits = FB_VISBELL;
326 #endif
327
328 switch (c) {
329
330 case '@':
331 /* Insert Character (ICH) */
332 rcons_insertchar(rc, rc->rc_p0);
333 break;
334
335 case 'A':
336 /* Cursor Up (CUU) */
337 rc->rc_row -= rc->rc_p0;
338 if (rc->rc_row < 0)
339 rc->rc_row = 0;
340 break;
341
342 case 'B':
343 /* Cursor Down (CUD) */
344 rc->rc_row += rc->rc_p0;
345 if (rc->rc_row >= rc->rc_maxrow)
346 rc->rc_row = rc->rc_maxrow - 1;
347 break;
348
349 case 'C':
350 /* Cursor Forward (CUF) */
351 rc->rc_col += rc->rc_p0;
352 if (rc->rc_col >= rc->rc_maxcol)
353 rc->rc_col = rc->rc_maxcol - 1;
354 break;
355
356 case 'D':
357 /* Cursor Backward (CUB) */
358 rc->rc_col -= rc->rc_p0;
359 if (rc->rc_col < 0)
360 rc->rc_col = 0;
361 break;
362
363 case 'E':
364 /* Cursor Next Line (CNL) */
365 rc->rc_col = 0;
366 rc->rc_row += rc->rc_p0;
367 if (rc->rc_row >= rc->rc_maxrow)
368 rc->rc_row = rc->rc_maxrow - 1;
369 break;
370
371 case 'f':
372 /* Horizontal And Vertical Position (HVP) */
373 case 'H':
374 /* Cursor Position (CUP) */
375 rc->rc_col = rc->rc_p1 - 1;
376 if (rc->rc_col < 0)
377 rc->rc_col = 0;
378 else if (rc->rc_col >= rc->rc_maxcol)
379 rc->rc_col = rc->rc_maxcol - 1;
380
381 rc->rc_row = rc->rc_p0 - 1;
382 if (rc->rc_row < 0)
383 rc->rc_row = 0;
384 else if (rc->rc_row >= rc->rc_maxrow)
385 rc->rc_row = rc->rc_maxrow - 1;
386 break;
387
388 case 'J':
389 /* Erase in Display (ED) */
390 rcons_clear2eop(rc);
391 break;
392
393 case 'K':
394 /* Erase in Line (EL) */
395 rcons_clear2eol(rc);
396 break;
397
398 case 'L':
399 /* Insert Line (IL) */
400 rcons_insertline(rc, rc->rc_p0);
401 break;
402
403 case 'M':
404 /* Delete Line (DL) */
405 rcons_delline(rc, rc->rc_p0);
406 break;
407
408 case 'P':
409 /* Delete Character (DCH) */
410 rcons_delchar(rc, rc->rc_p0);
411 break;
412
413 case 'm':
414 /* Select Graphic Rendition (SGR) */
415 /* (defaults to zero) */
416 if (rc->rc_bits & FB_P0_DEFAULT)
417 rc->rc_p0 = 0;
418
419 if (rc->rc_bits & FB_P1_DEFAULT)
420 rc->rc_p1 = 0;
421
422 rcons_sgresc(rc, rc->rc_p0);
423
424 if (rc->rc_bits & FB_P1)
425 rcons_sgresc(rc, rc->rc_p1);
426
427 break;
428
429 case 'p':
430 /* Black On White (SUNBOW) */
431 rcons_invert(rc, 0);
432 break;
433
434 case 'q':
435 /* White On Black (SUNWOB) */
436 rcons_invert(rc, 1);
437 break;
438
439 case 'r':
440 /* Set scrolling (SUNSCRL) */
441 /* (defaults to zero) */
442 if (rc->rc_bits & FB_P0_DEFAULT)
443 rc->rc_p0 = 0;
444 /* XXX not implemented yet */
445 rc->rc_scroll = rc->rc_p0;
446 break;
447
448 case 's':
449 /* Reset terminal emulator (SUNRESET) */
450 rc->rc_wsflg = 0;
451 rc->rc_scroll = 0;
452 rc->rc_bits &= ~FB_NO_CURSOR;
453 rcons_setcolor(rc, rc->rc_deffgcolor, rc->rc_defbgcolor);
454
455 if (rc->rc_bits & FB_INVERT)
456 rcons_invert(rc, 0);
457 break;
458 #ifdef notyet
459 /*
460 * XXX following two read \E[?25h and \E[?25l. rcons
461 * can't currently handle the '?'.
462 */
463 case 'h':
464 /* Normal/very visible cursor */
465 if (rc->rc_p0 == 25) {
466 rc->rc_bits &= ~FB_NO_CURSOR;
467
468 if (rc->rc_bits & FB_CURSOR) {
469 rc->rc_bits ^= FB_CURSOR;
470 rcons_cursor(rc);
471 }
472 }
473 break;
474
475 case 'l':
476 /* Invisible cursor */
477 if (rc->rc_p0 == 25 && (rc->rc_bits & FB_NO_CURSOR) == 0) {
478 if (rc->rc_bits & FB_CURSOR)
479 rcons_cursor(rc);
480
481 rc->rc_bits |= FB_NO_CURSOR;
482 }
483 break;
484 #endif
485 }
486 }
487
488 /* Set ANSI colors */
489 void
490 rcons_setcolor(rc, fg, bg)
491 struct rconsole *rc;
492 int fg, bg;
493 {
494 int flg;
495
496 if (fg > WSCOL_WHITE || fg < 0)
497 return;
498
499 if (bg > WSCOL_WHITE || bg < 0)
500 return;
501
502 #ifdef RASTERCONS_WONB
503 flg = bg;
504 bg = fg;
505 fg = flg;
506 #endif
507
508 /* Emulate WSATTR_REVERSE attribute if it's not supported */
509 if ((rc->rc_wsflg & WSATTR_REVERSE) &&
510 !(rc->rc_supwsflg & WSATTR_REVERSE)) {
511 flg = bg;
512 bg = fg;
513 fg = flg;
514 }
515
516 /* Mask out unsupported flags and get attribute */
517 flg = rc->rc_wsflg & rc->rc_supwsflg;
518 rc->rc_bgcolor = bg;
519 rc->rc_fgcolor = fg;
520 rc->rc_ops->alloc_attr(rc->rc_cookie, fg, bg, flg, &rc->rc_attr);
521 }
522
523
524 /* Actually write a string to the frame buffer */
525 void
526 rcons_text(rc, str, n)
527 struct rconsole *rc;
528 unsigned char *str;
529 int n;
530 {
531 u_int uc;
532
533 while (n--) {
534 uc = rc->rc_charmap[*str++ & 255];
535 rc->rc_ops->putchar(rc->rc_cookie, rc->rc_row, rc->rc_col++,
536 uc, rc->rc_attr);
537 }
538
539 if (rc->rc_col >= rc->rc_maxcol) {
540 rc->rc_col = 0;
541 rc->rc_row++;
542 }
543
544 if (rc->rc_row >= rc->rc_maxrow)
545 rcons_scroll(rc, 1);
546 }
547
548 /* Paint (or unpaint) the cursor */
549 void
550 rcons_cursor(rc)
551 struct rconsole *rc;
552 {
553 rc->rc_bits ^= FB_CURSOR;
554
555 if (rc->rc_bits & FB_NO_CURSOR)
556 return;
557
558 rc->rc_ops->cursor(rc->rc_cookie, rc->rc_bits & FB_CURSOR,
559 rc->rc_row, rc->rc_col);
560 }
561
562 /* Possibly change to SUNWOB or SUNBOW mode */
563 void
564 rcons_invert(rc, wob)
565 struct rconsole *rc;
566 int wob;
567 {
568
569 rc->rc_bits ^= FB_INVERT;
570 /* XXX how do we do we invert the framebuffer?? */
571 }
572
573 /* Clear to the end of the page */
574 void
575 rcons_clear2eop(rc)
576 struct rconsole *rc;
577 {
578 if (rc->rc_col || rc->rc_row) {
579 rcons_clear2eol(rc);
580
581 if (rc->rc_row < (rc->rc_maxrow - 1))
582 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row + 1,
583 rc->rc_maxrow, rc->rc_attr);
584 } else
585 rc->rc_ops->eraserows(rc->rc_cookie, 0, rc->rc_maxrow,
586 rc->rc_attr);
587 }
588
589 /* Clear to the end of the line */
590 void
591 rcons_clear2eol(rc)
592 struct rconsole *rc;
593 {
594 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
595 rc->rc_maxcol - rc->rc_col, rc->rc_attr);
596 }
597
598
599 /* Scroll up */
600 void
601 rcons_scroll(rc, n)
602 struct rconsole *rc;
603 int n;
604 {
605 /* Can't scroll more than the whole screen */
606 if (n > rc->rc_maxrow)
607 n = rc->rc_maxrow;
608
609 /* Calculate new row */
610 rc->rc_row -= n;
611
612 if (rc->rc_row < 0)
613 rc->rc_row = 0;
614
615 rc->rc_ops->copyrows(rc->rc_cookie, n, 0, rc->rc_maxrow - n);
616 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n, rc->rc_attr);
617 }
618
619 /* Delete characters */
620 void
621 rcons_delchar(rc, n)
622 struct rconsole *rc;
623 int n;
624 {
625 /* Can't delete more chars than there are */
626 if (n > rc->rc_maxcol - rc->rc_col)
627 n = rc->rc_maxcol - rc->rc_col;
628
629 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col + n,
630 rc->rc_col, rc->rc_maxcol - rc->rc_col - n);
631
632 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row,
633 rc->rc_maxcol - n, n, rc->rc_attr);
634 }
635
636 /* Delete a number of lines */
637 void
638 rcons_delline(rc, n)
639 struct rconsole *rc;
640 int n;
641 {
642 /* Can't delete more lines than there are */
643 if (n > rc->rc_maxrow - rc->rc_row)
644 n = rc->rc_maxrow - rc->rc_row;
645
646 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row + n, rc->rc_row,
647 rc->rc_maxrow - rc->rc_row - n);
648
649 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_maxrow - n, n,
650 rc->rc_attr);
651 }
652
653 /* Insert some characters */
654 void
655 rcons_insertchar(rc, n)
656 struct rconsole *rc;
657 int n;
658 {
659 /* Can't insert more chars than can fit */
660 if (n > rc->rc_maxcol - rc->rc_col)
661 n = rc->rc_maxcol - rc->rc_col - 1;
662
663 rc->rc_ops->copycols(rc->rc_cookie, rc->rc_row, rc->rc_col,
664 rc->rc_col + n, rc->rc_maxcol - rc->rc_col - n - 1);
665
666 rc->rc_ops->erasecols(rc->rc_cookie, rc->rc_row, rc->rc_col,
667 n, rc->rc_attr);
668 }
669
670 /* Insert some lines */
671 void
672 rcons_insertline(rc, n)
673 struct rconsole *rc;
674 int n;
675 {
676 /* Can't insert more lines than can fit */
677 if (n > rc->rc_maxrow - rc->rc_row)
678 n = rc->rc_maxrow - rc->rc_row;
679
680 rc->rc_ops->copyrows(rc->rc_cookie, rc->rc_row, rc->rc_row + n,
681 rc->rc_maxrow - rc->rc_row - n);
682
683 rc->rc_ops->eraserows(rc->rc_cookie, rc->rc_row, n,
684 rc->rc_attr);
685 }
686
687 /* end of rcons_subr.c */
688