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