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