xref: /openbsd/sys/dev/wscons/wsemul_dumb.c (revision e0c3e559)
1 /* $OpenBSD: wsemul_dumb.c,v 1.14 2020/05/25 09:55:49 jsg Exp $ */
2 /* $NetBSD: wsemul_dumb.c,v 1.7 2000/01/05 11:19:36 drochner Exp $ */
3 
4 /*
5  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Christopher G. Demetriou
18  *	for the NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/time.h>
37 #include <sys/malloc.h>
38 #include <sys/fcntl.h>
39 
40 #include <dev/wscons/wsconsio.h>
41 #include <dev/wscons/wsdisplayvar.h>
42 #include <dev/wscons/wsemulvar.h>
43 #include <dev/wscons/ascii.h>
44 
45 void	*wsemul_dumb_cnattach(const struct wsscreen_descr *, void *,
46 				   int, int, uint32_t);
47 void	*wsemul_dumb_attach(int, const struct wsscreen_descr *,
48 				 void *, int, int, void *, uint32_t);
49 u_int	wsemul_dumb_output(void *, const u_char *, u_int, int);
50 int	wsemul_dumb_translate(void *, kbd_t, keysym_t, const u_char **);
51 void	wsemul_dumb_detach(void *, u_int *, u_int *);
52 void	wsemul_dumb_resetop(void *, enum wsemul_resetops);
53 
54 const struct wsemul_ops wsemul_dumb_ops = {
55 	"dumb",
56 	wsemul_dumb_cnattach,
57 	wsemul_dumb_attach,
58 	wsemul_dumb_output,
59 	wsemul_dumb_translate,
60 	wsemul_dumb_detach,
61 	wsemul_dumb_resetop
62 };
63 
64 struct wsemul_dumb_emuldata {
65 	const struct wsdisplay_emulops *emulops;
66 	struct wsemul_abortstate abortstate;
67 	void *emulcookie;
68 	void *cbcookie;
69 	int crippled;
70 	u_int nrows, ncols, crow, ccol;
71 	uint32_t defattr;
72 };
73 
74 struct wsemul_dumb_emuldata wsemul_dumb_console_emuldata;
75 
76 void *
wsemul_dumb_cnattach(const struct wsscreen_descr * type,void * cookie,int ccol,int crow,uint32_t defattr)77 wsemul_dumb_cnattach(const struct wsscreen_descr *type, void *cookie, int ccol,
78     int crow, uint32_t defattr)
79 {
80 	struct wsemul_dumb_emuldata *edp;
81 	const struct wsdisplay_emulops *emulops;
82 
83 	edp = &wsemul_dumb_console_emuldata;
84 
85 	edp->emulops = emulops = type->textops;
86 	edp->emulcookie = cookie;
87 	edp->nrows = type->nrows;
88 	edp->ncols = type->ncols;
89 	edp->crow = crow;
90 	edp->ccol = ccol;
91 	edp->defattr = defattr;
92 	edp->cbcookie = NULL;
93 	edp->crippled = emulops->cursor == NULL ||
94 	    emulops->copycols == NULL || emulops->copyrows == NULL ||
95 	    emulops->erasecols == NULL || emulops->eraserows == NULL;
96 	wsemul_reset_abortstate(&edp->abortstate);
97 
98 	return (edp);
99 }
100 
101 void *
wsemul_dumb_attach(int console,const struct wsscreen_descr * type,void * cookie,int ccol,int crow,void * cbcookie,uint32_t defattr)102 wsemul_dumb_attach(int console, const struct wsscreen_descr *type, void *cookie,
103     int ccol, int crow, void *cbcookie, uint32_t defattr)
104 {
105 	struct wsemul_dumb_emuldata *edp;
106 
107 	if (console)
108 		edp = &wsemul_dumb_console_emuldata;
109 	else {
110 		edp = malloc(sizeof *edp, M_DEVBUF, M_WAITOK);
111 
112 		edp->emulops = type->textops;
113 		edp->emulcookie = cookie;
114 		edp->nrows = type->nrows;
115 		edp->ncols = type->ncols;
116 		edp->crow = crow;
117 		edp->ccol = ccol;
118 		edp->defattr = defattr;
119 		wsemul_reset_abortstate(&edp->abortstate);
120 	}
121 
122 	edp->cbcookie = cbcookie;
123 
124 	return (edp);
125 }
126 
127 u_int
wsemul_dumb_output(void * cookie,const u_char * data,u_int count,int kernel)128 wsemul_dumb_output(void *cookie, const u_char *data, u_int count, int kernel)
129 {
130 	struct wsemul_dumb_emuldata *edp = cookie;
131 	u_int processed = 0;
132 	u_char c;
133 	int n;
134 	int rc = 0;
135 
136 	if (edp->crippled) {
137 		while (count-- > 0) {
138 			wsemul_resume_abort(&edp->abortstate);
139 
140 			c = *data++;
141 			if (c == ASCII_BEL)
142 				wsdisplay_emulbell(edp->cbcookie);
143 			else {
144 				WSEMULOP(rc, edp, &edp->abortstate, putchar,
145 				    (edp->emulcookie, 0, 0, c, 0));
146 				if (rc != 0)
147 					break;
148 			}
149 			processed++;
150 		}
151 		if (rc != 0)
152 			wsemul_abort_other(&edp->abortstate);
153 		return processed;
154 	}
155 
156 	switch (edp->abortstate.state) {
157 	case ABORT_FAILED_CURSOR:
158 		/*
159 		 * If we could not display the cursor back, we pretended not
160 		 * having been able to display the last character. But this
161 		 * is a lie, so compensate here.
162 		 */
163 		data++, count--;
164 		processed++;
165 		wsemul_reset_abortstate(&edp->abortstate);
166 		break;
167 	case ABORT_OK:
168 		/* remove cursor image */
169 		rc = (*edp->emulops->cursor)
170 		    (edp->emulcookie, 0, edp->crow, edp->ccol);
171 		if (rc != 0)
172 			return 0;
173 		break;
174 	default:
175 		break;
176 	}
177 
178 	while (count-- > 0) {
179 		wsemul_resume_abort(&edp->abortstate);
180 
181 		c = *data++;
182 		switch (c) {
183 		case ASCII_BEL:
184 			wsdisplay_emulbell(edp->cbcookie);
185 			break;
186 
187 		case ASCII_BS:
188 			if (edp->ccol > 0)
189 				edp->ccol--;
190 			break;
191 
192 		case ASCII_CR:
193 			edp->ccol = 0;
194 			break;
195 
196 		case ASCII_HT:
197 			n = min(8 - (edp->ccol & 7),
198 			    edp->ncols - edp->ccol - 1);
199 			WSEMULOP(rc, edp, &edp->abortstate, erasecols,
200 			     (edp->emulcookie, edp->crow, edp->ccol, n,
201 			      edp->defattr));
202 			if (rc != 0)
203 				break;
204 			edp->ccol += n;
205 			break;
206 
207 		case ASCII_FF:
208 			WSEMULOP(rc, edp, &edp->abortstate, eraserows,
209 			    (edp->emulcookie, 0, edp->nrows, edp->defattr));
210 			if (rc != 0)
211 				break;
212 			edp->ccol = 0;
213 			edp->crow = 0;
214 			break;
215 
216 		case ASCII_VT:
217 			if (edp->crow > 0)
218 				edp->crow--;
219 			break;
220 
221 		default:
222 			WSEMULOP(rc, edp, &edp->abortstate, putchar,
223 			    (edp->emulcookie, edp->crow, edp->ccol, c,
224 			     edp->defattr));
225 			if (rc != 0)
226 				break;
227 			edp->ccol++;
228 
229 			/* if cur col is still on cur line, done. */
230 			if (edp->ccol < edp->ncols)
231 				break;
232 
233 			/* wrap the column around. */
234 			edp->ccol = 0;
235 
236                 	/* FALLTHROUGH */
237 
238 		case ASCII_LF:
239 	                /* if the cur line isn't the last, incr and leave. */
240 			if (edp->crow < edp->nrows - 1) {
241 				edp->crow++;
242 				break;
243 			}
244 			n = 1;		/* number of lines to scroll */
245 			WSEMULOP(rc, edp, &edp->abortstate, copyrows,
246 			    (edp->emulcookie, n, 0, edp->nrows - n));
247 			if (rc == 0)
248 				WSEMULOP(rc, edp, &edp->abortstate, eraserows,
249 				    (edp->emulcookie, edp->nrows - n, n,
250 				     edp->defattr));
251 			if (rc != 0) {
252 				/* undo wrap-at-eol processing if necessary */
253 				if (c != ASCII_LF)
254 					edp->ccol = edp->ncols - 1;
255 				break;
256 			}
257 			edp->crow -= n - 1;
258 			break;
259 		}
260 		if (rc != 0)
261 			break;
262 		processed++;
263 	}
264 
265 	if (rc != 0)
266 		wsemul_abort_other(&edp->abortstate);
267 	else {
268 		/* put cursor image back */
269 		rc = (*edp->emulops->cursor)
270 		    (edp->emulcookie, 1, edp->crow, edp->ccol);
271 		if (rc != 0) {
272 			/*
273 			 * Fail the last character output, remembering that
274 			 * only the cursor operation really needs to be done.
275 			 */
276 			wsemul_abort_cursor(&edp->abortstate);
277 			processed--;
278 		}
279 	}
280 
281 	if (rc == 0)
282 		wsemul_reset_abortstate(&edp->abortstate);
283 
284 	return processed;
285 }
286 
287 int
wsemul_dumb_translate(void * cookie,kbd_t layout,keysym_t in,const u_char ** out)288 wsemul_dumb_translate(void *cookie, kbd_t layout, keysym_t in,
289     const u_char **out)
290 {
291 	return (0);
292 }
293 
294 void
wsemul_dumb_detach(void * cookie,u_int * crowp,u_int * ccolp)295 wsemul_dumb_detach(void *cookie, u_int *crowp, u_int *ccolp)
296 {
297 	struct wsemul_dumb_emuldata *edp = cookie;
298 
299 	*crowp = edp->crow;
300 	*ccolp = edp->ccol;
301 	if (edp != &wsemul_dumb_console_emuldata)
302 		free(edp, M_DEVBUF, sizeof *edp);
303 }
304 
305 void
wsemul_dumb_resetop(void * cookie,enum wsemul_resetops op)306 wsemul_dumb_resetop(void *cookie, enum wsemul_resetops op)
307 {
308 	struct wsemul_dumb_emuldata *edp = cookie;
309 
310 	if (edp->crippled)
311 		return;
312 
313 	switch (op) {
314 	case WSEMUL_CLEARSCREEN:
315 		(*edp->emulops->eraserows)(edp->emulcookie, 0, edp->nrows,
316 					   edp->defattr);
317 		edp->ccol = edp->crow = 0;
318 		(*edp->emulops->cursor)(edp->emulcookie, 1, 0, 0);
319 		break;
320 	case WSEMUL_CLEARCURSOR:
321 		(*edp->emulops->cursor)(edp->emulcookie, 0,
322 		    edp->crow, edp->ccol);
323 		break;
324 	default:
325 		break;
326 	}
327 }
328