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