xref: /openbsd/sys/dev/wscons/wsemul_dumb.c (revision e0c3e559)
1*e0c3e559Sjsg /* $OpenBSD: wsemul_dumb.c,v 1.14 2020/05/25 09:55:49 jsg Exp $ */
277b1f4eeSmickey /* $NetBSD: wsemul_dumb.c,v 1.7 2000/01/05 11:19:36 drochner Exp $ */
377b1f4eeSmickey 
477b1f4eeSmickey /*
577b1f4eeSmickey  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
677b1f4eeSmickey  *
777b1f4eeSmickey  * Redistribution and use in source and binary forms, with or without
877b1f4eeSmickey  * modification, are permitted provided that the following conditions
977b1f4eeSmickey  * are met:
1077b1f4eeSmickey  * 1. Redistributions of source code must retain the above copyright
1177b1f4eeSmickey  *    notice, this list of conditions and the following disclaimer.
1277b1f4eeSmickey  * 2. Redistributions in binary form must reproduce the above copyright
1377b1f4eeSmickey  *    notice, this list of conditions and the following disclaimer in the
1477b1f4eeSmickey  *    documentation and/or other materials provided with the distribution.
1577b1f4eeSmickey  * 3. All advertising materials mentioning features or use of this software
1677b1f4eeSmickey  *    must display the following acknowledgement:
1777b1f4eeSmickey  *      This product includes software developed by Christopher G. Demetriou
1877b1f4eeSmickey  *	for the NetBSD Project.
1977b1f4eeSmickey  * 4. The name of the author may not be used to endorse or promote products
2077b1f4eeSmickey  *    derived from this software without specific prior written permission
2177b1f4eeSmickey  *
2277b1f4eeSmickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2377b1f4eeSmickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2477b1f4eeSmickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2577b1f4eeSmickey  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2677b1f4eeSmickey  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2777b1f4eeSmickey  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2877b1f4eeSmickey  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2977b1f4eeSmickey  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3077b1f4eeSmickey  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3177b1f4eeSmickey  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3277b1f4eeSmickey  */
3377b1f4eeSmickey 
3477b1f4eeSmickey #include <sys/param.h>
3577b1f4eeSmickey #include <sys/systm.h>
3677b1f4eeSmickey #include <sys/time.h>
3777b1f4eeSmickey #include <sys/malloc.h>
3877b1f4eeSmickey #include <sys/fcntl.h>
3977b1f4eeSmickey 
4077b1f4eeSmickey #include <dev/wscons/wsconsio.h>
4177b1f4eeSmickey #include <dev/wscons/wsdisplayvar.h>
4277b1f4eeSmickey #include <dev/wscons/wsemulvar.h>
4377b1f4eeSmickey #include <dev/wscons/ascii.h>
4477b1f4eeSmickey 
45c4071fd1Smillert void	*wsemul_dumb_cnattach(const struct wsscreen_descr *, void *,
46*e0c3e559Sjsg 				   int, int, uint32_t);
47345431b5Smiod void	*wsemul_dumb_attach(int, const struct wsscreen_descr *,
48*e0c3e559Sjsg 				 void *, int, int, void *, uint32_t);
490ba8d49cSmiod u_int	wsemul_dumb_output(void *, const u_char *, u_int, int);
50ae56ac94Smiod int	wsemul_dumb_translate(void *, kbd_t, keysym_t, const u_char **);
510ba8d49cSmiod void	wsemul_dumb_detach(void *, u_int *, u_int *);
52c4071fd1Smillert void	wsemul_dumb_resetop(void *, enum wsemul_resetops);
5377b1f4eeSmickey 
5477b1f4eeSmickey const struct wsemul_ops wsemul_dumb_ops = {
5577b1f4eeSmickey 	"dumb",
5677b1f4eeSmickey 	wsemul_dumb_cnattach,
5777b1f4eeSmickey 	wsemul_dumb_attach,
5877b1f4eeSmickey 	wsemul_dumb_output,
5977b1f4eeSmickey 	wsemul_dumb_translate,
6077b1f4eeSmickey 	wsemul_dumb_detach,
6177b1f4eeSmickey 	wsemul_dumb_resetop
6277b1f4eeSmickey };
6377b1f4eeSmickey 
6477b1f4eeSmickey struct wsemul_dumb_emuldata {
6577b1f4eeSmickey 	const struct wsdisplay_emulops *emulops;
66345431b5Smiod 	struct wsemul_abortstate abortstate;
6777b1f4eeSmickey 	void *emulcookie;
6877b1f4eeSmickey 	void *cbcookie;
69d45e5b12Smiod 	int crippled;
7077b1f4eeSmickey 	u_int nrows, ncols, crow, ccol;
71*e0c3e559Sjsg 	uint32_t defattr;
7277b1f4eeSmickey };
7377b1f4eeSmickey 
7477b1f4eeSmickey struct wsemul_dumb_emuldata wsemul_dumb_console_emuldata;
7577b1f4eeSmickey 
7677b1f4eeSmickey void *
wsemul_dumb_cnattach(const struct wsscreen_descr * type,void * cookie,int ccol,int crow,uint32_t defattr)7799a59237Smiod wsemul_dumb_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol,
78*e0c3e559Sjsg     int crow, uint32_t defattr)
7977b1f4eeSmickey {
8077b1f4eeSmickey 	struct wsemul_dumb_emuldata *edp;
81d45e5b12Smiod 	const struct wsdisplay_emulops *emulops;
8277b1f4eeSmickey 
8377b1f4eeSmickey 	edp = &wsemul_dumb_console_emuldata;
8477b1f4eeSmickey 
85d45e5b12Smiod 	edp->emulops = emulops = type->textops;
8677b1f4eeSmickey 	edp->emulcookie = cookie;
8777b1f4eeSmickey 	edp->nrows = type->nrows;
8877b1f4eeSmickey 	edp->ncols = type->ncols;
8977b1f4eeSmickey 	edp->crow = crow;
9077b1f4eeSmickey 	edp->ccol = ccol;
9177b1f4eeSmickey 	edp->defattr = defattr;
9277b1f4eeSmickey 	edp->cbcookie = NULL;
93d45e5b12Smiod 	edp->crippled = emulops->cursor == NULL ||
94d45e5b12Smiod 	    emulops->copycols == NULL || emulops->copyrows == NULL ||
95d45e5b12Smiod 	    emulops->erasecols == NULL || emulops->eraserows == NULL;
96345431b5Smiod 	wsemul_reset_abortstate(&edp->abortstate);
9777b1f4eeSmickey 
9877b1f4eeSmickey 	return (edp);
9977b1f4eeSmickey }
10077b1f4eeSmickey 
10177b1f4eeSmickey void *
wsemul_dumb_attach(int console,const struct wsscreen_descr * type,void * cookie,int ccol,int crow,void * cbcookie,uint32_t defattr)10299a59237Smiod wsemul_dumb_attach(int console, const struct wsscreen_descr *type, void *cookie,
103*e0c3e559Sjsg     int ccol, int crow, void *cbcookie, uint32_t defattr)
10477b1f4eeSmickey {
10577b1f4eeSmickey 	struct wsemul_dumb_emuldata *edp;
10677b1f4eeSmickey 
10777b1f4eeSmickey 	if (console)
10877b1f4eeSmickey 		edp = &wsemul_dumb_console_emuldata;
10977b1f4eeSmickey 	else {
11077b1f4eeSmickey 		edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
11177b1f4eeSmickey 
11277b1f4eeSmickey 		edp->emulops = type->textops;
11377b1f4eeSmickey 		edp->emulcookie = cookie;
11477b1f4eeSmickey 		edp->nrows = type->nrows;
11577b1f4eeSmickey 		edp->ncols = type->ncols;
11677b1f4eeSmickey 		edp->crow = crow;
11777b1f4eeSmickey 		edp->ccol = ccol;
11877b1f4eeSmickey 		edp->defattr = defattr;
119345431b5Smiod 		wsemul_reset_abortstate(&edp->abortstate);
12077b1f4eeSmickey 	}
12177b1f4eeSmickey 
12277b1f4eeSmickey 	edp->cbcookie = cbcookie;
12377b1f4eeSmickey 
12477b1f4eeSmickey 	return (edp);
12577b1f4eeSmickey }
12677b1f4eeSmickey 
1270ba8d49cSmiod u_int
wsemul_dumb_output(void * cookie,const u_char * data,u_int count,int kernel)12899a59237Smiod wsemul_dumb_output(void *cookie, const u_char *data, u_int count, int kernel)
12977b1f4eeSmickey {
13077b1f4eeSmickey 	struct wsemul_dumb_emuldata *edp = cookie;
1310ba8d49cSmiod 	u_int processed = 0;
13277b1f4eeSmickey 	u_char c;
13377b1f4eeSmickey 	int n;
134345431b5Smiod 	int rc = 0;
13577b1f4eeSmickey 
136d45e5b12Smiod 	if (edp->crippled) {
137d45e5b12Smiod 		while (count-- > 0) {
138345431b5Smiod 			wsemul_resume_abort(&edp->abortstate);
139d45e5b12Smiod 
140345431b5Smiod 			c = *data++;
141d45e5b12Smiod 			if (c == ASCII_BEL)
142d45e5b12Smiod 				wsdisplay_emulbell(edp->cbcookie);
143345431b5Smiod 			else {
144345431b5Smiod 				WSEMULOP(rc, edp, &edp->abortstate, putchar,
145345431b5Smiod 				    (edp->emulcookie, 0, 0, c, 0));
146345431b5Smiod 				if (rc != 0)
147345431b5Smiod 					break;
148345431b5Smiod 			}
1490ba8d49cSmiod 			processed++;
150d45e5b12Smiod 		}
151345431b5Smiod 		if (rc != 0)
152345431b5Smiod 			wsemul_abort_other(&edp->abortstate);
1530ba8d49cSmiod 		return processed;
154d45e5b12Smiod 	}
155d45e5b12Smiod 
156345431b5Smiod 	switch (edp->abortstate.state) {
157345431b5Smiod 	case ABORT_FAILED_CURSOR:
158345431b5Smiod 		/*
159345431b5Smiod 		 * If we could not display the cursor back, we pretended not
160345431b5Smiod 		 * having been able to display the last character. But this
161345431b5Smiod 		 * is a lie, so compensate here.
162345431b5Smiod 		 */
163345431b5Smiod 		data++, count--;
164345431b5Smiod 		processed++;
165345431b5Smiod 		wsemul_reset_abortstate(&edp->abortstate);
166345431b5Smiod 		break;
167345431b5Smiod 	case ABORT_OK:
168345431b5Smiod 		/* remove cursor image */
169345431b5Smiod 		rc = (*edp->emulops->cursor)
170345431b5Smiod 		    (edp->emulcookie, 0, edp->crow, edp->ccol);
171345431b5Smiod 		if (rc != 0)
172345431b5Smiod 			return 0;
173345431b5Smiod 		break;
174345431b5Smiod 	default:
175345431b5Smiod 		break;
176345431b5Smiod 	}
177d45e5b12Smiod 
178345431b5Smiod 	while (count-- > 0) {
179345431b5Smiod 		wsemul_resume_abort(&edp->abortstate);
180345431b5Smiod 
181345431b5Smiod 		c = *data++;
18277b1f4eeSmickey 		switch (c) {
18377b1f4eeSmickey 		case ASCII_BEL:
18477b1f4eeSmickey 			wsdisplay_emulbell(edp->cbcookie);
18577b1f4eeSmickey 			break;
18677b1f4eeSmickey 
18777b1f4eeSmickey 		case ASCII_BS:
18877b1f4eeSmickey 			if (edp->ccol > 0)
18977b1f4eeSmickey 				edp->ccol--;
19077b1f4eeSmickey 			break;
19177b1f4eeSmickey 
19277b1f4eeSmickey 		case ASCII_CR:
19377b1f4eeSmickey 			edp->ccol = 0;
19477b1f4eeSmickey 			break;
19577b1f4eeSmickey 
19677b1f4eeSmickey 		case ASCII_HT:
19777b1f4eeSmickey 			n = min(8 - (edp->ccol & 7),
19877b1f4eeSmickey 			    edp->ncols - edp->ccol - 1);
199345431b5Smiod 			WSEMULOP(rc, edp, &edp->abortstate, erasecols,
200345431b5Smiod 			     (edp->emulcookie, edp->crow, edp->ccol, n,
201345431b5Smiod 			      edp->defattr));
202345431b5Smiod 			if (rc != 0)
203345431b5Smiod 				break;
20477b1f4eeSmickey 			edp->ccol += n;
20577b1f4eeSmickey 			break;
20677b1f4eeSmickey 
20777b1f4eeSmickey 		case ASCII_FF:
208345431b5Smiod 			WSEMULOP(rc, edp, &edp->abortstate, eraserows,
209345431b5Smiod 			    (edp->emulcookie, 0, edp->nrows, edp->defattr));
210345431b5Smiod 			if (rc != 0)
211345431b5Smiod 				break;
21277b1f4eeSmickey 			edp->ccol = 0;
21377b1f4eeSmickey 			edp->crow = 0;
21477b1f4eeSmickey 			break;
21577b1f4eeSmickey 
21677b1f4eeSmickey 		case ASCII_VT:
21777b1f4eeSmickey 			if (edp->crow > 0)
21877b1f4eeSmickey 				edp->crow--;
21977b1f4eeSmickey 			break;
22077b1f4eeSmickey 
22177b1f4eeSmickey 		default:
222345431b5Smiod 			WSEMULOP(rc, edp, &edp->abortstate, putchar,
223345431b5Smiod 			    (edp->emulcookie, edp->crow, edp->ccol, c,
224345431b5Smiod 			     edp->defattr));
225345431b5Smiod 			if (rc != 0)
226345431b5Smiod 				break;
22777b1f4eeSmickey 			edp->ccol++;
22877b1f4eeSmickey 
22977b1f4eeSmickey 			/* if cur col is still on cur line, done. */
23077b1f4eeSmickey 			if (edp->ccol < edp->ncols)
23177b1f4eeSmickey 				break;
23277b1f4eeSmickey 
23377b1f4eeSmickey 			/* wrap the column around. */
23477b1f4eeSmickey 			edp->ccol = 0;
23577b1f4eeSmickey 
236341cd9feSjsg                 	/* FALLTHROUGH */
23777b1f4eeSmickey 
23877b1f4eeSmickey 		case ASCII_LF:
23977b1f4eeSmickey 	                /* if the cur line isn't the last, incr and leave. */
24077b1f4eeSmickey 			if (edp->crow < edp->nrows - 1) {
24177b1f4eeSmickey 				edp->crow++;
24277b1f4eeSmickey 				break;
24377b1f4eeSmickey 			}
24477b1f4eeSmickey 			n = 1;		/* number of lines to scroll */
245345431b5Smiod 			WSEMULOP(rc, edp, &edp->abortstate, copyrows,
246345431b5Smiod 			    (edp->emulcookie, n, 0, edp->nrows - n));
247345431b5Smiod 			if (rc == 0)
248345431b5Smiod 				WSEMULOP(rc, edp, &edp->abortstate, eraserows,
249345431b5Smiod 				    (edp->emulcookie, edp->nrows - n, n,
250345431b5Smiod 				     edp->defattr));
251345431b5Smiod 			if (rc != 0) {
252345431b5Smiod 				/* undo wrap-at-eol processing if necessary */
253345431b5Smiod 				if (c != ASCII_LF)
254345431b5Smiod 					edp->ccol = edp->ncols - 1;
255345431b5Smiod 				break;
256345431b5Smiod 			}
25777b1f4eeSmickey 			edp->crow -= n - 1;
25877b1f4eeSmickey 			break;
25977b1f4eeSmickey 		}
260345431b5Smiod 		if (rc != 0)
261345431b5Smiod 			break;
2620ba8d49cSmiod 		processed++;
26377b1f4eeSmickey 	}
264345431b5Smiod 
265345431b5Smiod 	if (rc != 0)
266345431b5Smiod 		wsemul_abort_other(&edp->abortstate);
267345431b5Smiod 	else {
268345431b5Smiod 		/* put cursor image back */
269345431b5Smiod 		rc = (*edp->emulops->cursor)
270345431b5Smiod 		    (edp->emulcookie, 1, edp->crow, edp->ccol);
271345431b5Smiod 		if (rc != 0) {
272345431b5Smiod 			/*
273345431b5Smiod 			 * Fail the last character output, remembering that
274345431b5Smiod 			 * only the cursor operation really needs to be done.
275345431b5Smiod 			 */
276345431b5Smiod 			wsemul_abort_cursor(&edp->abortstate);
277345431b5Smiod 			processed--;
278345431b5Smiod 		}
279345431b5Smiod 	}
280345431b5Smiod 
281345431b5Smiod 	if (rc == 0)
282345431b5Smiod 		wsemul_reset_abortstate(&edp->abortstate);
2830ba8d49cSmiod 
2840ba8d49cSmiod 	return processed;
28577b1f4eeSmickey }
28677b1f4eeSmickey 
28777b1f4eeSmickey int
wsemul_dumb_translate(void * cookie,kbd_t layout,keysym_t in,const u_char ** out)288ae56ac94Smiod wsemul_dumb_translate(void *cookie, kbd_t layout, keysym_t in,
289ae56ac94Smiod     const u_char **out)
29077b1f4eeSmickey {
29177b1f4eeSmickey 	return (0);
29277b1f4eeSmickey }
29377b1f4eeSmickey 
29477b1f4eeSmickey void
wsemul_dumb_detach(void * cookie,u_int * crowp,u_int * ccolp)29599a59237Smiod wsemul_dumb_detach(void *cookie, u_int *crowp, u_int *ccolp)
29677b1f4eeSmickey {
29777b1f4eeSmickey 	struct wsemul_dumb_emuldata *edp = cookie;
29877b1f4eeSmickey 
29977b1f4eeSmickey 	*crowp = edp->crow;
30077b1f4eeSmickey 	*ccolp = edp->ccol;
30177b1f4eeSmickey 	if (edp != &wsemul_dumb_console_emuldata)
302bae2bd50Sderaadt 		free(edp, M_DEVBUF, sizeof *edp);
30377b1f4eeSmickey }
30477b1f4eeSmickey 
30577b1f4eeSmickey void
wsemul_dumb_resetop(void * cookie,enum wsemul_resetops op)30699a59237Smiod wsemul_dumb_resetop(void *cookie, enum wsemul_resetops op)
30777b1f4eeSmickey {
30877b1f4eeSmickey 	struct wsemul_dumb_emuldata *edp = cookie;
30977b1f4eeSmickey 
310d45e5b12Smiod 	if (edp->crippled)
311d45e5b12Smiod 		return;
312d45e5b12Smiod 
31377b1f4eeSmickey 	switch (op) {
31477b1f4eeSmickey 	case WSEMUL_CLEARSCREEN:
31577b1f4eeSmickey 		(*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows,
31677b1f4eeSmickey 					   edp->defattr);
31777b1f4eeSmickey 		edp->ccol = edp->crow = 0;
31877b1f4eeSmickey 		(*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0);
31977b1f4eeSmickey 		break;
32003820d6eSmiod 	case WSEMUL_CLEARCURSOR:
32103820d6eSmiod 		(*edp->emulops->cursor)(edp->emulcookie, 0,
32203820d6eSmiod 		    edp->crow, edp->ccol);
32303820d6eSmiod 		break;
32477b1f4eeSmickey 	default:
32577b1f4eeSmickey 		break;
32677b1f4eeSmickey 	}
32777b1f4eeSmickey }
328