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