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 * 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 * 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 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 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 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 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