xref: /original-bsd/sys/sparc/rcons/rcons_subr.c (revision 6471873a)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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