1 /*
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *
9 * All advertising materials mentioning features or use of this software
10 * must display the following acknowledgement:
11 * This product includes software developed by the University of
12 * California, Lawrence Berkeley Laboratory.
13 *
14 * %sccs.include.redist.c%
15 *
16 * @(#)rcons_subr.c 8.1 (Berkeley) 06/11/93
17 *
18 * from: $Header: rcons_subr.c,v 1.38 93/04/20 11:15:39 torek Exp $
19 */
20
21 #ifdef KERNEL
22 #include <sys/param.h>
23 #include <sys/fbio.h>
24 #include <sys/device.h>
25 #include <machine/fbvar.h>
26 #else
27 #include <sys/types.h>
28 #include "myfbdevice.h"
29 #endif
30
31 #include <sparc/rcons/raster.h>
32
33 void rcons_text(struct fbdevice *, char *, int);
34 void rcons_pctrl(struct fbdevice *, int);
35 void rcons_esc(struct fbdevice *, int);
36 void rcons_doesc(struct fbdevice *, int);
37 void rcons_cursor(struct fbdevice *);
38 void rcons_invert(struct fbdevice *, int);
39 void rcons_clear2eop(struct fbdevice *);
40 void rcons_clear2eol(struct fbdevice *);
41 void rcons_scroll(struct fbdevice *, int);
42 void rcons_delchar(struct fbdevice *, int);
43 void rcons_delline(struct fbdevice *, int);
44 void rcons_insertchar(struct fbdevice *, int);
45 void rcons_insertline(struct fbdevice *, int);
46
47 extern void rcons_bell(struct fbdevice *);
48
49 #define RCONS_ISPRINT(c) ((c) >= ' ' && (c) <= '~')
50 #define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
51
52 /* Output (or at least handle) a string sent to the console */
53 void
rcons_puts(fb,str,n)54 rcons_puts(fb, str, n)
55 register struct fbdevice *fb;
56 register char *str;
57 register int n;
58 {
59 register int c, i, j;
60 register char *cp;
61
62 /* Jump scroll */
63 /* XXX maybe this should be an option? */
64 if ((fb->fb_bits & FB_INESC) == 0) {
65 /* Count newlines up to an escape sequence */
66 i = 0;
67 j = 0;
68 for (cp = str; j++ < n && *cp != '\033'; ++cp) {
69 if (*cp == '\n')
70 ++i;
71 else if (*cp == '\013')
72 --i;
73 }
74
75 /* Only jump scroll two or more rows */
76 if (*fb->fb_row + i >= fb->fb_maxrow + 1) {
77 /* Erase the cursor (if necessary) */
78 if (fb->fb_bits & FB_CURSOR)
79 rcons_cursor(fb);
80
81 rcons_scroll(fb, i);
82 }
83 }
84
85 /* Process characters */
86 while (--n >= 0) {
87 c = *str;
88 if (c == '\033') {
89 /* Start an escape (perhaps aborting one in progress) */
90 fb->fb_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
91 fb->fb_bits &= ~(FB_P0 | FB_P1);
92
93 /* Most parameters default to 1 */
94 fb->fb_p0 = fb->fb_p1 = 1;
95 } else if (fb->fb_bits & FB_INESC) {
96 rcons_esc(fb, c);
97 } else {
98 /* Erase the cursor (if necessary) */
99 if (fb->fb_bits & FB_CURSOR)
100 rcons_cursor(fb);
101
102 /* Display the character */
103 if (RCONS_ISPRINT(c)) {
104 /* Try to output as much as possible */
105 j = fb->fb_maxcol - (*fb->fb_col + 1);
106 if (j > n)
107 j = n;
108 for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
109 continue;
110 rcons_text(fb, str, i);
111 --i;
112 str += i;
113 n -= i;
114 } else
115 rcons_pctrl(fb, c);
116 }
117 ++str;
118 }
119 /* Redraw the cursor (if necessary) */
120 if ((fb->fb_bits & FB_CURSOR) == 0)
121 rcons_cursor(fb);
122 }
123
124 /* Actually write a string to the frame buffer */
125 void
rcons_text(fb,str,n)126 rcons_text(fb, str, n)
127 register struct fbdevice *fb;
128 register char *str;
129 register int n;
130 {
131 register int x, y, op;
132
133 x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
134 y = *fb->fb_row * fb->fb_font->height +
135 fb->fb_font_ascent + fb->fb_yorigin;
136 op = RAS_SRC;
137 if (((fb->fb_bits & FB_STANDOUT) != 0) ^
138 ((fb->fb_bits & FB_INVERT) != 0))
139 op = RAS_NOT(op);
140 raster_textn(fb->fb_sp, x, y, op, fb->fb_font, str, n);
141 *fb->fb_col += n;
142 if (*fb->fb_col >= fb->fb_maxcol) {
143 *fb->fb_col = 0;
144 (*fb->fb_row)++;
145 }
146 if (*fb->fb_row >= fb->fb_maxrow)
147 rcons_scroll(fb, 1);
148 }
149
150 /* Handle a control character sent to the console */
151 void
rcons_pctrl(fb,c)152 rcons_pctrl(fb, c)
153 register struct fbdevice *fb;
154 register int c;
155 {
156
157 switch (c) {
158
159 case '\r': /* Carriage return */
160 *fb->fb_col = 0;
161 break;
162
163 case '\b': /* Backspace */
164 if (*fb->fb_col > 0)
165 (*fb->fb_col)--;
166 break;
167
168 case '\013': /* Vertical tab */
169 if (*fb->fb_row > 0)
170 (*fb->fb_row)--;
171 break;
172
173 case '\f': /* Formfeed */
174 *fb->fb_row = *fb->fb_col = 0;
175 rcons_clear2eop(fb);
176 break;
177
178 case '\n': /* Linefeed */
179 (*fb->fb_row)++;
180 if (*fb->fb_row >= fb->fb_maxrow)
181 rcons_scroll(fb, 1);
182 break;
183
184 case '\007': /* Bell */
185 rcons_bell(fb);
186 break;
187
188 case '\t': /* Horizontal tab */
189 *fb->fb_col = (*fb->fb_col + 8) & ~7;
190 if (*fb->fb_col >= fb->fb_maxcol)
191 *fb->fb_col = fb->fb_maxcol - 1;
192 break;
193 }
194 }
195
196 /* Handle the next character in an escape sequence */
197 void
rcons_esc(fb,c)198 rcons_esc(fb, c)
199 register struct fbdevice *fb;
200 register int c;
201 {
202
203 if (c == '[') {
204 /* Parameter 0 */
205 fb->fb_bits &= ~FB_P1;
206 fb->fb_bits |= FB_P0;
207 } else if (c == ';') {
208 /* Parameter 1 */
209 fb->fb_bits &= ~FB_P0;
210 fb->fb_bits |= FB_P1;
211 } else if (RCONS_ISDIGIT(c)) {
212 /* Add a digit to a parameter */
213 if (fb->fb_bits & FB_P0) {
214 /* Parameter 0 */
215 if (fb->fb_bits & FB_P0_DEFAULT) {
216 fb->fb_bits &= ~FB_P0_DEFAULT;
217 fb->fb_p0 = 0;
218 }
219 fb->fb_p0 *= 10;
220 fb->fb_p0 += c - '0';
221 } else if (fb->fb_bits & FB_P1) {
222 /* Parameter 1 */
223 if (fb->fb_bits & FB_P1_DEFAULT) {
224 fb->fb_bits &= ~FB_P1_DEFAULT;
225 fb->fb_p1 = 0;
226 }
227 fb->fb_p1 *= 10;
228 fb->fb_p1 += c - '0';
229 }
230 } else {
231 /* Erase the cursor (if necessary) */
232 if (fb->fb_bits & FB_CURSOR)
233 rcons_cursor(fb);
234
235 /* Process the completed escape sequence */
236 rcons_doesc(fb, c);
237 fb->fb_bits &= ~FB_INESC;
238 }
239 }
240
241 /* Process a complete escape sequence */
242 void
rcons_doesc(fb,c)243 rcons_doesc(fb, c)
244 register struct fbdevice *fb;
245 register int c;
246 {
247
248 #ifdef notdef
249 /* XXX add escape sequence to enable visual (and audible) bell */
250 fb->fb_bits = FB_VISBELL;
251 #endif
252
253 switch (c) {
254
255 case '@':
256 /* Insert Character (ICH) */
257 rcons_insertchar(fb, fb->fb_p0);
258 break;
259
260 case 'A':
261 /* Cursor Up (CUU) */
262 *fb->fb_row -= fb->fb_p0;
263 if (*fb->fb_row < 0)
264 *fb->fb_row = 0;
265 break;
266
267 case 'B':
268 /* Cursor Down (CUD) */
269 *fb->fb_row += fb->fb_p0;
270 if (*fb->fb_row >= fb->fb_maxrow)
271 *fb->fb_row = fb->fb_maxrow - 1;
272 break;
273
274 case 'C':
275 /* Cursor Forward (CUF) */
276 *fb->fb_col += fb->fb_p0;
277 if (*fb->fb_col >= fb->fb_maxcol)
278 *fb->fb_col = fb->fb_maxcol - 1;
279 break;
280
281 case 'D':
282 /* Cursor Backward (CUB) */
283 *fb->fb_col -= fb->fb_p0;
284 if (*fb->fb_col < 0)
285 *fb->fb_col = 0;
286 break;
287
288 case 'E':
289 /* Cursor Next Line (CNL) */
290 *fb->fb_col = 0;
291 *fb->fb_row += fb->fb_p0;
292 if (*fb->fb_row >= fb->fb_maxrow)
293 *fb->fb_row = fb->fb_maxrow - 1;
294 break;
295
296 case 'f':
297 /* Horizontal And Vertical Position (HVP) */
298 case 'H':
299 /* Cursor Position (CUP) */
300 *fb->fb_col = fb->fb_p1 - 1;
301 if (*fb->fb_col < 0)
302 *fb->fb_col = 0;
303 else if (*fb->fb_col >= fb->fb_maxcol)
304 *fb->fb_col = fb->fb_maxcol - 1;
305
306 *fb->fb_row = fb->fb_p0 - 1;
307 if (*fb->fb_row < 0)
308 *fb->fb_row = 0;
309 else if (*fb->fb_row >= fb->fb_maxrow)
310 *fb->fb_row = fb->fb_maxrow - 1;
311 break;
312
313 case 'J':
314 /* Erase in Display (ED) */
315 rcons_clear2eop(fb);
316 break;
317
318 case 'K':
319 /* Erase in Line (EL) */
320 rcons_clear2eol(fb);
321 break;
322
323 case 'L':
324 /* Insert Line (IL) */
325 rcons_insertline(fb, fb->fb_p0);
326 break;
327
328 case 'M':
329 /* Delete Line (DL) */
330 rcons_delline(fb, fb->fb_p0);
331 break;
332
333 case 'P':
334 /* Delete Character (DCH) */
335 rcons_delchar(fb, fb->fb_p0);
336 break;
337
338 case 'm':
339 /* Select Graphic Rendition (SGR); */
340 /* (defaults to zero) */
341 if (fb->fb_bits & FB_P0_DEFAULT)
342 fb->fb_p0 = 0;
343 if (fb->fb_p0)
344 fb->fb_bits |= FB_STANDOUT;
345 else
346 fb->fb_bits &= ~FB_STANDOUT;
347 break;
348
349 case 'p':
350 /* Black On White (SUNBOW) */
351 rcons_invert(fb, 0);
352 break;
353
354 case 'q':
355 /* White On Black (SUNWOB) */
356 rcons_invert(fb, 1);
357 break;
358
359 case 'r':
360 /* Set scrolling (SUNSCRL) */
361 /* (defaults to zero) */
362 if (fb->fb_bits & FB_P0_DEFAULT)
363 fb->fb_p0 = 0;
364 /* XXX not implemented yet */
365 fb->fb_scroll = fb->fb_p0;
366 break;
367
368 case 's':
369 /* Reset terminal emulator (SUNRESET) */
370 fb->fb_bits &= ~FB_STANDOUT;
371 fb->fb_scroll = 0;
372 if (fb->fb_bits & FB_INVERT)
373 rcons_invert(fb, 0);
374 break;
375 }
376 }
377
378 /* Paint (or unpaint) the cursor */
379 void
rcons_cursor(fb)380 rcons_cursor(fb)
381 register struct fbdevice *fb;
382 {
383 register int x, y;
384
385 x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
386 y = *fb->fb_row * fb->fb_font->height + fb->fb_yorigin;
387 raster_op(fb->fb_sp, x, y,
388 #ifdef notdef
389 /* XXX This is the right way but too slow */
390 fb->fb_font->chars[(int)' '].r->width,
391 fb->fb_font->chars[(int)' '].r->height,
392 #else
393 fb->fb_font->width, fb->fb_font->height,
394 #endif
395 RAS_INVERT, (struct raster *) 0, 0, 0);
396 fb->fb_bits ^= FB_CURSOR;
397 }
398
399 /* Possibly change to SUNWOB or SUNBOW mode */
400 void
rcons_invert(fb,wob)401 rcons_invert(fb, wob)
402 struct fbdevice *fb;
403 int wob;
404 {
405 if (((fb->fb_bits & FB_INVERT) != 0) ^ wob) {
406 /* Invert the display */
407 raster_op(fb->fb_sp, 0, 0, fb->fb_sp->width, fb->fb_sp->height,
408 RAS_INVERT, (struct raster *) 0, 0, 0);
409
410 /* Swap things around */
411 fb->fb_ras_blank = RAS_NOT(fb->fb_ras_blank);
412 fb->fb_bits ^= FB_INVERT;
413 }
414 }
415
416 /* Clear to the end of the page */
417 void
rcons_clear2eop(fb)418 rcons_clear2eop(fb)
419 register struct fbdevice *fb;
420 {
421 register int y;
422
423 if (*fb->fb_col == 0 && *fb->fb_row == 0) {
424 /* Clear the entire frame buffer */
425 raster_op(fb->fb_sp, 0, 0,
426 fb->fb_sp->width, fb->fb_sp->height,
427 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
428 } else {
429 /* Only clear what needs to be cleared */
430 rcons_clear2eol(fb);
431 y = (*fb->fb_row + 1) * fb->fb_font->height;
432
433 raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin + y,
434 fb->fb_emuwidth, fb->fb_emuheight - y,
435 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
436 }
437 }
438
439 /* Clear to the end of the line */
440 void
rcons_clear2eol(fb)441 rcons_clear2eol(fb)
442 register struct fbdevice *fb;
443 {
444 register int x;
445
446 x = *fb->fb_col * fb->fb_font->width;
447
448 raster_op(fb->fb_sp,
449 fb->fb_xorigin + x,
450 *fb->fb_row * fb->fb_font->height + fb->fb_yorigin,
451 fb->fb_emuwidth - x, fb->fb_font->height,
452 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
453 }
454
455 /* Scroll up one line */
456 void
rcons_scroll(fb,n)457 rcons_scroll(fb, n)
458 register struct fbdevice *fb;
459 register int n;
460 {
461 register int ydiv;
462
463 /* Can't scroll more than the whole screen */
464 if (n > fb->fb_maxrow)
465 n = fb->fb_maxrow;
466
467 /* Calculate new row */
468 *fb->fb_row -= n;
469 if (*fb->fb_row < 0)
470 *fb->fb_row = 0;
471
472 /* Calculate number of pixels to scroll */
473 ydiv = fb->fb_font->height * n;
474
475 raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin,
476 fb->fb_emuwidth, fb->fb_emuheight - ydiv,
477 RAS_SRC, fb->fb_sp, fb->fb_xorigin, ydiv + fb->fb_yorigin);
478
479 raster_op(fb->fb_sp,
480 fb->fb_xorigin, fb->fb_yorigin + fb->fb_emuheight - ydiv,
481 fb->fb_emuwidth, ydiv, fb->fb_ras_blank, (struct raster *) 0, 0, 0);
482 }
483
484 /* Delete characters */
485 void
rcons_delchar(fb,n)486 rcons_delchar(fb, n)
487 register struct fbdevice *fb;
488 register int n;
489 {
490 register int tox, fromx, y, width;
491
492 /* Can't delete more chars than there are */
493 if (n > fb->fb_maxcol - *fb->fb_col)
494 n = fb->fb_maxcol - *fb->fb_col;
495
496 fromx = (*fb->fb_col + n) * fb->fb_font->width;
497 tox = *fb->fb_col * fb->fb_font->width;
498 y = *fb->fb_row * fb->fb_font->height;
499 width = n * fb->fb_font->width;
500
501 raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
502 fb->fb_emuwidth - fromx, fb->fb_font->height,
503 RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
504
505 raster_op(fb->fb_sp,
506 fb->fb_emuwidth - width + fb->fb_xorigin, y + fb->fb_yorigin,
507 width, fb->fb_font->height,
508 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
509 }
510
511 /* Delete a number of lines */
512 void
rcons_delline(fb,n)513 rcons_delline(fb, n)
514 register struct fbdevice *fb;
515 register int n;
516 {
517 register int fromy, toy, height;
518
519 /* Can't delete more lines than there are */
520 if (n > fb->fb_maxrow - *fb->fb_row)
521 n = fb->fb_maxrow - *fb->fb_row;
522
523 fromy = (*fb->fb_row + n) * fb->fb_font->height;
524 toy = *fb->fb_row * fb->fb_font->height;
525 height = fb->fb_font->height * n;
526
527 raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
528 fb->fb_emuwidth, fb->fb_emuheight - fromy, RAS_SRC,
529 fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
530
531 raster_op(fb->fb_sp,
532 fb->fb_xorigin, fb->fb_emuheight - height + fb->fb_yorigin,
533 fb->fb_emuwidth, height,
534 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
535 }
536
537 /* Insert some characters */
538 void
rcons_insertchar(fb,n)539 rcons_insertchar(fb, n)
540 register struct fbdevice *fb;
541 register int n;
542 {
543 register int tox, fromx, y;
544
545 /* Can't insert more chars than can fit */
546 if (n > fb->fb_maxcol - *fb->fb_col)
547 n = fb->fb_maxcol - *fb->fb_col;
548
549 tox = (*fb->fb_col + n) * fb->fb_font->width;
550 fromx = *fb->fb_col * fb->fb_font->width;
551 y = *fb->fb_row * fb->fb_font->height;
552
553 raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
554 fb->fb_emuwidth - tox, fb->fb_font->height,
555 RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
556
557 raster_op(fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin,
558 fb->fb_font->width * n, fb->fb_font->height,
559 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
560 }
561
562 /* Insert some lines */
563 void
rcons_insertline(fb,n)564 rcons_insertline(fb, n)
565 register struct fbdevice *fb;
566 register int n;
567 {
568 register int fromy, toy;
569
570 /* Can't insert more lines than can fit */
571 if (n > fb->fb_maxrow - *fb->fb_row)
572 n = fb->fb_maxrow - *fb->fb_row;
573
574 toy = (*fb->fb_row + n) * fb->fb_font->height;
575 fromy = *fb->fb_row * fb->fb_font->height;
576
577 raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
578 fb->fb_emuwidth, fb->fb_emuheight - toy,
579 RAS_SRC, fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
580
581 raster_op(fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin,
582 fb->fb_emuwidth, fb->fb_font->height * n,
583 fb->fb_ras_blank, (struct raster *) 0, 0, 0);
584 }
585