1 /* $NetBSD: ite.c,v 1.75 2006/10/01 18:56:21 elad Exp $ */ 2 3 /* 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah Hdr: ite.c 1.1 90/07/09 36 * @(#)ite.c 7.6 (Berkeley) 5/16/91 37 */ 38 /* 39 * Copyright (c) 1988 University of Utah. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * the Systems Programming Group of the University of Utah Computer 43 * Science Department. 44 * 45 * Redistribution and use in source and binary forms, with or without 46 * modification, are permitted provided that the following conditions 47 * are met: 48 * 1. Redistributions of source code must retain the above copyright 49 * notice, this list of conditions and the following disclaimer. 50 * 2. Redistributions in binary form must reproduce the above copyright 51 * notice, this list of conditions and the following disclaimer in the 52 * documentation and/or other materials provided with the distribution. 53 * 3. All advertising materials mentioning features or use of this software 54 * must display the following acknowledgement: 55 * This product includes software developed by the University of 56 * California, Berkeley and its contributors. 57 * 4. Neither the name of the University nor the names of its contributors 58 * may be used to endorse or promote products derived from this software 59 * without specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 71 * SUCH DAMAGE. 72 * 73 * from: Utah Hdr: ite.c 1.1 90/07/09 74 * @(#)ite.c 7.6 (Berkeley) 5/16/91 75 */ 76 77 /* 78 * ite - bitmaped terminal. 79 * Supports VT200, a few terminal features will be unavailable until 80 * the system actually probes the device (i.e. not after consinit()) 81 */ 82 83 #include "opt_ddb.h" 84 85 #include <sys/cdefs.h> 86 __KERNEL_RCSID(0, "$NetBSD: ite.c,v 1.75 2006/10/01 18:56:21 elad Exp $"); 87 88 #include <sys/param.h> 89 #include <sys/kernel.h> 90 #include <sys/device.h> 91 #include <sys/fcntl.h> 92 #include <sys/malloc.h> 93 #include <sys/ioctl.h> 94 #include <sys/tty.h> 95 #include <sys/termios.h> 96 #include <sys/systm.h> 97 #include <sys/callout.h> 98 #include <sys/proc.h> 99 #include <dev/cons.h> 100 #include <sys/kauth.h> 101 #include <amiga/amiga/cc.h> 102 #include <amiga/amiga/color.h> /* DEBUG */ 103 #include <amiga/amiga/custom.h> /* DEBUG */ 104 #include <amiga/amiga/device.h> 105 #if defined(__m68k__) 106 #include <amiga/amiga/isr.h> 107 #endif 108 #include <amiga/dev/iteioctl.h> 109 #include <amiga/dev/itevar.h> 110 #include <amiga/dev/kbdmap.h> 111 #include <amiga/dev/grfioctl.h> 112 #include <amiga/dev/grfvar.h> 113 114 #include <machine/cpu.h> /* for is_draco() */ 115 116 #include <sys/conf.h> 117 118 #include "grfcc.h" 119 #include "ite.h" 120 121 /* 122 * XXX go ask sys/kern/tty.c:ttselect() 123 */ 124 125 #define ITEUNIT(dev) (minor(dev)) 126 127 #define SUBR_INIT(ip) (ip)->grf->g_iteinit(ip) 128 #define SUBR_DEINIT(ip) (ip)->grf->g_itedeinit(ip) 129 #define SUBR_PUTC(ip,c,dy,dx,m) (ip)->grf->g_iteputc(ip,c,dy,dx,m) 130 #define SUBR_CURSOR(ip,flg) (ip)->grf->g_itecursor(ip,flg) 131 #define SUBR_CLEAR(ip,sy,sx,h,w) (ip)->grf->g_iteclear(ip,sy,sx,h,w) 132 #define SUBR_SCROLL(ip,sy,sx,count,dir) \ 133 (ip)->grf->g_itescroll(ip,sy,sx,count,dir) 134 135 int start_repeat_timeo = 30; /* first repeat after x s/100 */ 136 int next_repeat_timeo = 10; /* next repeat after x s/100 */ 137 138 int ite_default_wrap = 1; /* you want vtxxx-nam, binpatch */ 139 140 struct ite_softc con_itesoftc; 141 u_char cons_tabs[MAX_TABS]; 142 143 struct ite_softc *kbd_ite; 144 145 /* audio bell stuff */ 146 u_int bvolume = 10; 147 u_int bpitch = 660; 148 u_int bmsec = 75; 149 150 static char *bsamplep; 151 static char sample[20] = { 152 0,39,75,103,121,127,121,103,75,39,0, 153 -39,-75,-103,-121,-127,-121,-103,-75,-39 154 }; 155 156 void iteputchar(int c, struct ite_softc *ip); 157 void ite_putstr(const char * s, int len, dev_t dev); 158 void iteattach(struct device *, struct device *, void *); 159 int itematch(struct device *, struct cfdata *, void *); 160 static void iteprecheckwrap(struct ite_softc *); 161 static void itecheckwrap(struct ite_softc *); 162 struct ite_softc *getitesp(dev_t); 163 void init_bell(void); 164 void ite_bell(void); 165 void itecnpollc(dev_t, int); 166 static void repeat_handler(void *); 167 inline static void ite_sendstr(const char *); 168 static void alignment_display(struct ite_softc *); 169 inline static void snap_cury(struct ite_softc *); 170 inline static void ite_dnchar(struct ite_softc *, int); 171 inline static void ite_inchar(struct ite_softc *, int); 172 inline static void ite_clrtoeol(struct ite_softc *); 173 inline static void ite_clrtobol(struct ite_softc *); 174 inline static void ite_clrline(struct ite_softc *); 175 inline static void ite_clrtoeos(struct ite_softc *); 176 inline static void ite_clrtobos(struct ite_softc *); 177 inline static void ite_clrscreen(struct ite_softc *); 178 inline static void ite_dnline(struct ite_softc *, int); 179 inline static void ite_inline(struct ite_softc *, int); 180 inline static void ite_lf(struct ite_softc *); 181 inline static void ite_crlf(struct ite_softc *); 182 inline static void ite_cr(struct ite_softc *); 183 inline static void ite_rlf(struct ite_softc *); 184 inline static int atoi(const char *); 185 inline static int ite_argnum(struct ite_softc *); 186 inline static int ite_zargnum(struct ite_softc *); 187 188 CFATTACH_DECL(ite, sizeof(struct ite_softc), 189 itematch, iteattach, NULL, NULL); 190 191 extern struct cfdriver ite_cd; 192 193 dev_type_open(iteopen); 194 dev_type_close(iteclose); 195 dev_type_read(iteread); 196 dev_type_write(itewrite); 197 dev_type_ioctl(iteioctl); 198 dev_type_tty(itetty); 199 dev_type_poll(itepoll); 200 201 const struct cdevsw ite_cdevsw = { 202 iteopen, iteclose, iteread, itewrite, iteioctl, 203 nostop, itetty, itepoll, nommap, ttykqfilter, D_TTY 204 }; 205 206 int 207 itematch(struct device *pdp, struct cfdata *cfp, void *auxp) 208 { 209 struct grf_softc *gp; 210 int maj; 211 212 gp = auxp; 213 214 /* 215 * XXX 216 * normally this would be done in attach, however 217 * during early init we do not have a device pointer 218 * and thus no unit number. 219 */ 220 maj = cdevsw_lookup_major(&ite_cdevsw); 221 gp->g_itedev = makedev(maj, cfp->cf_unit); 222 return(1); 223 } 224 225 void 226 iteattach(struct device *pdp, struct device *dp, void *auxp) 227 { 228 struct grf_softc *gp; 229 struct ite_softc *ip; 230 int s; 231 232 gp = (struct grf_softc *)auxp; 233 if (dp) { 234 ip = (struct ite_softc *)dp; 235 236 s = spltty(); 237 if (con_itesoftc.grf != NULL && 238 con_itesoftc.grf->g_unit == gp->g_unit) { 239 /* 240 * console reinit copy params over. 241 * and console always gets keyboard 242 */ 243 bcopy(&con_itesoftc.grf, &ip->grf, 244 (char *)&ip[1] - (char *)&ip->grf); 245 con_itesoftc.grf = NULL; 246 kbd_ite = ip; 247 } 248 ip->grf = gp; 249 splx(s); 250 251 alloc_sicallback(); 252 iteinit(gp->g_itedev); 253 printf(": rows %d cols %d", ip->rows, ip->cols); 254 printf(" repeat at (%d/100)s next at (%d/100)s", 255 start_repeat_timeo, next_repeat_timeo); 256 257 if (kbd_ite == NULL) 258 kbd_ite = ip; 259 if (kbd_ite == ip) 260 printf(" has keyboard"); 261 printf("\n"); 262 ip->flags |= ITE_ATTACHED; 263 } else { 264 if (con_itesoftc.grf != NULL && 265 con_itesoftc.grf->g_conpri > gp->g_conpri) 266 return; 267 con_itesoftc.grf = gp; 268 con_itesoftc.tabs = cons_tabs; 269 } 270 } 271 272 struct ite_softc * 273 getitesp(dev_t dev) 274 { 275 if (amiga_realconfig && con_itesoftc.grf == NULL) 276 return(ite_cd.cd_devs[ITEUNIT(dev)]); 277 278 if (con_itesoftc.grf == NULL) 279 panic("no ite_softc for console"); 280 return(&con_itesoftc); 281 } 282 283 /* 284 * cons.c entry points into ite device. 285 */ 286 287 /* 288 * Return a priority in consdev->cn_pri field highest wins. This function 289 * is called before any devices have been probed. 290 */ 291 void 292 itecnprobe(struct consdev *cd) 293 { 294 /* 295 * bring graphics layer up. 296 */ 297 config_console(); 298 299 /* 300 * return priority of the best ite (already picked from attach) 301 * or CN_DEAD. 302 */ 303 if (con_itesoftc.grf == NULL) 304 cd->cn_pri = CN_DEAD; 305 else { 306 cd->cn_pri = con_itesoftc.grf->g_conpri; 307 cd->cn_dev = con_itesoftc.grf->g_itedev; 308 } 309 } 310 311 /* audio bell stuff */ 312 void 313 init_bell(void) 314 { 315 if (bsamplep != NULL) 316 return; 317 bsamplep = alloc_chipmem(20); 318 if (bsamplep == NULL) 319 panic("no chipmem for ite_bell"); 320 321 bcopy(sample, bsamplep, 20); 322 } 323 324 void 325 ite_bell(void) 326 { 327 u_int clock; 328 u_int period; 329 u_int count; 330 331 clock = 3579545; /* PAL 3546895 */ 332 333 /* 334 * the number of clock ticks per sample byte must be > 124 335 * ergo bpitch must be < clock / 124*20 336 * i.e. ~1443, 1300 to be safe (PAL etc.). also not zero obviously 337 */ 338 period = clock / (bpitch * 20); 339 count = bmsec * bpitch / 1000; 340 341 play_sample(10, PREP_DMA_MEM(bsamplep), period, bvolume, 0x3, count); 342 } 343 344 void 345 itecninit(struct consdev *cd) 346 { 347 struct ite_softc *ip; 348 349 ip = getitesp(cd->cn_dev); 350 iteinit(cd->cn_dev); 351 ip->flags |= ITE_ACTIVE | ITE_ISCONS; 352 353 #ifdef DRACO 354 if (!is_draco()) 355 #endif 356 init_bell(); 357 } 358 359 /* 360 * ite_cnfinish() is called in ite_init() when the device is 361 * being probed in the normal fasion, thus we can finish setting 362 * up this ite now that the system is more functional. 363 */ 364 void 365 ite_cnfinish(struct ite_softc *ip) 366 { 367 static int done; 368 369 if (done) 370 return; 371 done = 1; 372 } 373 374 int 375 itecngetc(dev_t dev) 376 { 377 int c; 378 379 /* XXX this should be moved */ 380 kbdenable(); 381 do { 382 c = kbdgetcn(); 383 c = ite_cnfilter(c, ITEFILT_CONSOLE); 384 } while (c == -1); 385 return (c); 386 } 387 388 void 389 itecnputc(dev_t dev, int c) 390 { 391 static int paniced; 392 struct ite_softc *ip; 393 char ch; 394 395 ip = getitesp(dev); 396 ch = c; 397 398 if (panicstr && !paniced && 399 (ip->flags & (ITE_ACTIVE | ITE_INGRF)) != ITE_ACTIVE) { 400 ite_on(dev, 3); 401 paniced = 1; 402 } 403 iteputchar(ch, ip); 404 } 405 406 void 407 itecnpollc(dev_t dev, int on) 408 { 409 } 410 411 /* 412 * standard entry points to the device. 413 */ 414 415 /* 416 * iteinit() is the standard entry point for initialization of 417 * an ite device, it is also called from ite_cninit(). 418 * 419 */ 420 void 421 iteinit(dev_t dev) 422 { 423 struct ite_softc *ip; 424 static int kbdmap_loaded = 0; 425 426 ip = getitesp(dev); 427 if (ip->flags & ITE_INITED) 428 return; 429 if (kbdmap_loaded == 0) { 430 bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); 431 kbdmap_loaded = 1; 432 } 433 434 ip->cursorx = 0; 435 ip->cursory = 0; 436 SUBR_INIT(ip); 437 SUBR_CURSOR(ip, DRAW_CURSOR); 438 if (ip->tabs == NULL) 439 ip->tabs = malloc(MAX_TABS * sizeof(u_char),M_DEVBUF,M_WAITOK); 440 ite_reset(ip); 441 ip->flags |= ITE_INITED; 442 } 443 444 int 445 iteopen(dev_t dev, int mode, int devtype, struct lwp *l) 446 { 447 struct ite_softc *ip; 448 struct tty *tp; 449 int error, first, unit; 450 451 unit = ITEUNIT(dev); 452 first = 0; 453 454 if (unit >= ite_cd.cd_ndevs) 455 return ENXIO; 456 ip = getitesp(dev); 457 if (ip == NULL) 458 return ENXIO; 459 if ((ip->flags & ITE_ATTACHED) == 0) 460 return ENXIO; 461 462 if (ip->tp == NULL) { 463 tp = ip->tp = ttymalloc(); 464 tty_attach(tp); 465 } else 466 tp = ip->tp; 467 468 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 469 return (EBUSY); 470 471 if ((ip->flags & ITE_ACTIVE) == 0) { 472 ite_on(dev, 0); 473 first = 1; 474 } 475 tp->t_oproc = itestart; 476 tp->t_param = ite_param; 477 tp->t_dev = dev; 478 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 479 ttychars(tp); 480 tp->t_iflag = TTYDEF_IFLAG; 481 tp->t_oflag = TTYDEF_OFLAG; 482 tp->t_cflag = TTYDEF_CFLAG; 483 tp->t_lflag = TTYDEF_LFLAG; 484 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 485 tp->t_state = TS_CARR_ON; 486 ttsetwater(tp); 487 } 488 error = ttyopen(tp, 0, mode & O_NONBLOCK); 489 if (error) 490 goto bad; 491 492 error = tp->t_linesw->l_open(dev, tp); 493 if (error) 494 goto bad; 495 496 tp->t_winsize.ws_row = ip->rows; 497 tp->t_winsize.ws_col = ip->cols; 498 kbdenable(); 499 return (0); 500 bad: 501 if (first) 502 ite_off(dev, 0); 503 return (error); 504 } 505 506 int 507 iteclose(dev_t dev, int flag, int mode, struct lwp *l) 508 { 509 struct tty *tp; 510 511 tp = getitesp(dev)->tp; 512 513 KDASSERT(tp); 514 tp->t_linesw->l_close(tp, flag); 515 ttyclose(tp); 516 ite_off(dev, 0); 517 return (0); 518 } 519 520 int 521 iteread(dev_t dev, struct uio *uio, int flag) 522 { 523 struct tty *tp; 524 525 tp = getitesp(dev)->tp; 526 527 KDASSERT(tp); 528 return tp->t_linesw->l_read(tp, uio, flag); 529 } 530 531 int 532 itewrite(dev_t dev, struct uio *uio, int flag) 533 { 534 struct tty *tp; 535 536 tp = getitesp(dev)->tp; 537 538 KDASSERT(tp); 539 return tp->t_linesw->l_write(tp, uio, flag); 540 } 541 542 int 543 itepoll(dev_t dev, int events, struct lwp *l) 544 { 545 struct tty *tp; 546 547 tp = getitesp(dev)->tp; 548 549 KDASSERT(tp); 550 return ((*tp->t_linesw->l_poll)(tp, events, l)); 551 } 552 553 struct tty * 554 itetty(dev_t dev) 555 { 556 return (getitesp(dev)->tp); 557 } 558 559 int 560 iteioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct lwp *l) 561 { 562 struct iterepeat *irp; 563 struct ite_softc *ip; 564 struct itebell *ib; 565 struct tty *tp; 566 int error; 567 568 ip = getitesp(dev); 569 tp = ip->tp; 570 571 KDASSERT(tp); 572 573 error = tp->t_linesw->l_ioctl(tp, cmd, addr, flag, l); 574 if (error != EPASSTHROUGH) 575 return (error); 576 error = ttioctl(tp, cmd, addr, flag, l); 577 if (error != EPASSTHROUGH) 578 return (error); 579 580 switch (cmd) { 581 case ITEIOCGBELL: 582 ib = (struct itebell *)addr; 583 ib->volume = bvolume; 584 ib->pitch = bpitch; 585 ib->msec = bmsec; 586 return (0); 587 case ITEIOCSBELL: 588 ib = (struct itebell *)addr; 589 590 if (ib->pitch > MAXBPITCH || ib->pitch < MINBPITCH || 591 ib->volume > MAXBVOLUME || ib->msec > MAXBTIME) 592 return (EINVAL); 593 bvolume = ib->volume; 594 bpitch = ib->pitch; 595 bmsec = ib->msec; 596 return (0); 597 case ITEIOCSKMAP: 598 if (addr == 0) 599 return(EFAULT); 600 bcopy(addr, &kbdmap, sizeof(struct kbdmap)); 601 return(0); 602 case ITEIOCGKMAP: 603 if (addr == NULL) 604 return(EFAULT); 605 bcopy(&kbdmap, addr, sizeof(struct kbdmap)); 606 return(0); 607 case ITEIOCGREPT: 608 irp = (struct iterepeat *)addr; 609 irp->start = start_repeat_timeo; 610 irp->next = next_repeat_timeo; 611 return (0); 612 case ITEIOCSREPT: 613 irp = (struct iterepeat *)addr; 614 if (irp->start < ITEMINREPEAT && irp->next < ITEMINREPEAT) 615 return(EINVAL); 616 start_repeat_timeo = irp->start; 617 next_repeat_timeo = irp->next; 618 return(0); 619 } 620 #if NGRFCC > 0 621 /* XXX */ 622 if (minor(dev) == 0) { 623 error = ite_grf_ioctl(ip, cmd, addr, flag, l); 624 if (error >= 0) 625 return (error); 626 } 627 #endif 628 return (EPASSTHROUGH); 629 } 630 631 void 632 itestart(struct tty *tp) 633 { 634 struct clist *rbp; 635 struct ite_softc *ip; 636 u_char buf[ITEBURST]; 637 int s, len; 638 639 ip = getitesp(tp->t_dev); 640 641 KDASSERT(tp); 642 643 s = spltty(); { 644 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) 645 goto out; 646 647 tp->t_state |= TS_BUSY; 648 rbp = &tp->t_outq; 649 650 len = q_to_b(rbp, buf, ITEBURST); 651 } splx(s); 652 653 /* Here is a really good place to implement pre/jumpscroll() */ 654 ite_putstr(buf, len, tp->t_dev); 655 656 s = spltty(); { 657 tp->t_state &= ~TS_BUSY; 658 /* we have characters remaining. */ 659 if (rbp->c_cc) { 660 tp->t_state |= TS_TIMEOUT; 661 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp); 662 } 663 /* wakeup we are below */ 664 if (rbp->c_cc <= tp->t_lowat) { 665 if (tp->t_state & TS_ASLEEP) { 666 tp->t_state &= ~TS_ASLEEP; 667 wakeup((caddr_t) rbp); 668 } 669 selwakeup(&tp->t_wsel); 670 } 671 } 672 out: 673 splx(s); 674 } 675 676 void 677 ite_on(dev_t dev, int flag) 678 { 679 struct ite_softc *ip; 680 int unit; 681 682 unit = ITEUNIT(dev); 683 ip = getitesp(dev); 684 685 /* force ite active, overriding graphics mode */ 686 if (flag & 1) { 687 ip->flags |= ITE_ACTIVE; 688 ip->flags &= ~(ITE_INGRF | ITE_INITED); 689 } 690 /* leave graphics mode */ 691 if (flag & 2) { 692 ip->flags &= ~ITE_INGRF; 693 if ((ip->flags & ITE_ACTIVE) == 0) 694 return; 695 } 696 ip->flags |= ITE_ACTIVE; 697 if (ip->flags & ITE_INGRF) 698 return; 699 iteinit(dev); 700 } 701 702 void 703 ite_off(dev_t dev, int flag) 704 { 705 struct ite_softc *ip; 706 707 ip = getitesp(dev); 708 if (flag & 2) 709 ip->flags |= ITE_INGRF; 710 if ((ip->flags & ITE_ACTIVE) == 0) 711 return; 712 if ((flag & 1) || 713 (ip->flags & (ITE_INGRF | ITE_ISCONS | ITE_INITED)) == ITE_INITED) 714 SUBR_DEINIT(ip); 715 /* XXX hmm grfon() I think wants this to go inactive. */ 716 if ((flag & 2) == 0) 717 ip->flags &= ~ITE_ACTIVE; 718 } 719 720 /* XXX called after changes made in underlying grf layer. */ 721 /* I want to nuke this */ 722 void 723 ite_reinit(dev_t dev) 724 { 725 struct ite_softc *ip; 726 727 ip = getitesp(dev); 728 ip->flags &= ~ITE_INITED; 729 iteinit(dev); 730 } 731 732 int 733 ite_param(struct tty *tp, struct termios *t) 734 { 735 tp->t_ispeed = t->c_ispeed; 736 tp->t_ospeed = t->c_ospeed; 737 tp->t_cflag = t->c_cflag; 738 return (0); 739 } 740 741 void 742 ite_reset(struct ite_softc *ip) 743 { 744 int i; 745 746 ip->curx = 0; 747 ip->cury = 0; 748 ip->attribute = ATTR_NOR; 749 ip->save_curx = 0; 750 ip->save_cury = 0; 751 ip->save_attribute = ATTR_NOR; 752 ip->ap = ip->argbuf; 753 ip->emul_level = 0; 754 ip->eightbit_C1 = 0; 755 ip->top_margin = 0; 756 ip->bottom_margin = ip->rows - 1; 757 ip->inside_margins = 0; 758 ip->linefeed_newline = 0; 759 ip->auto_wrap = ite_default_wrap; 760 ip->cursor_appmode = 0; 761 ip->keypad_appmode = 0; 762 ip->imode = 0; 763 ip->key_repeat = 1; 764 bzero(ip->tabs, ip->cols); 765 for (i = 0; i < ip->cols; i++) 766 ip->tabs[i] = ((i & 7) == 0); 767 } 768 769 /* 770 * has to be global because of the shared filters. 771 */ 772 static u_char key_mod; 773 static u_char last_dead; 774 775 /* Used in console at startup only */ 776 int 777 ite_cnfilter(u_char c, enum caller caller) 778 { 779 struct key key; 780 u_char code, up, mask; 781 int s, i; 782 783 up = c & 0x80 ? 1 : 0; 784 c &= 0x7f; 785 code = 0; 786 787 s = spltty(); 788 789 i = (int)c - KBD_LEFT_SHIFT; 790 if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { 791 mask = 1 << i; 792 if (up) 793 key_mod &= ~mask; 794 else 795 key_mod |= mask; 796 splx(s); 797 return -1; 798 } 799 800 if (up) { 801 splx(s); 802 return -1; 803 } 804 805 /* translate modifiers */ 806 if (key_mod & KBD_MOD_SHIFT) { 807 if (key_mod & KBD_MOD_ALT) 808 key = kbdmap.alt_shift_keys[c]; 809 else 810 key = kbdmap.shift_keys[c]; 811 } else if (key_mod & KBD_MOD_ALT) 812 key = kbdmap.alt_keys[c]; 813 else { 814 key = kbdmap.keys[c]; 815 /* if CAPS and key is CAPable (no pun intended) */ 816 if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) 817 key = kbdmap.shift_keys[c]; 818 } 819 code = key.code; 820 821 /* if string return */ 822 if (key.mode & (KBD_MODE_STRING | KBD_MODE_KPAD)) { 823 splx(s); 824 return -1; 825 } 826 /* handle dead keys */ 827 if (key.mode & KBD_MODE_DEAD) { 828 /* if entered twice, send accent itself */ 829 if (last_dead == (key.mode & KBD_MODE_ACCMASK)) 830 last_dead = 0; 831 else { 832 last_dead = key.mode & KBD_MODE_ACCMASK; 833 splx(s); 834 return -1; 835 } 836 } 837 if (last_dead) { 838 /* can't apply dead flag to string-keys */ 839 if (code >= '@' && code < 0x7f) 840 code = 841 acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; 842 last_dead = 0; 843 } 844 if (key_mod & KBD_MOD_CTRL) 845 code &= 0x1f; 846 if (key_mod & KBD_MOD_META) 847 code |= 0x80; 848 849 /* do console mapping. */ 850 code = code == '\r' ? '\n' : code; 851 852 splx(s); 853 return (code); 854 } 855 856 /* And now the old stuff. */ 857 858 /* these are used to implement repeating keys.. */ 859 static u_char last_char; 860 static u_char tout_pending; 861 862 static struct callout repeat_ch = CALLOUT_INITIALIZER; 863 864 /*ARGSUSED*/ 865 static void 866 repeat_handler(void *arg) 867 { 868 tout_pending = 0; 869 if (last_char) 870 ite_filter(last_char, ITEFILT_REPEATER); 871 } 872 873 void 874 ite_filter(u_char c, enum caller caller) 875 { 876 struct tty *kbd_tty; 877 u_char code, *str, up, mask; 878 struct key key; 879 int s, i; 880 881 if (kbd_ite == NULL || kbd_ite->tp == NULL) 882 return; 883 884 kbd_tty = kbd_ite->tp; 885 886 /* have to make sure we're at spltty in here */ 887 s = spltty(); 888 889 /* 890 * keyboard interrupts come at priority 2, while softint 891 * generated keyboard-repeat interrupts come at level 1. So, 892 * to not allow a key-up event to get thru before a repeat for 893 * the key-down, we remove any outstanding callout requests.. 894 rem_sicallback(ite_sifilter); 895 */ 896 897 up = c & 0x80 ? 1 : 0; 898 c &= 0x7f; 899 code = 0; 900 901 i = (int)c - KBD_LEFT_SHIFT; 902 if (i >= 0 && i <= (KBD_RIGHT_META - KBD_LEFT_SHIFT)) { 903 mask = 1 << i; 904 if (up) 905 key_mod &= ~mask; 906 else 907 key_mod |= mask; 908 splx(s); 909 return; 910 } 911 /* stop repeating on up event */ 912 if (up) { 913 if (tout_pending) { 914 callout_stop(&repeat_ch); 915 tout_pending = 0; 916 last_char = 0; 917 } 918 splx(s); 919 return; 920 } else if (tout_pending && last_char != c) { 921 /* different character, stop also */ 922 callout_stop(&repeat_ch); 923 tout_pending = 0; 924 last_char = 0; 925 } 926 /* Safety button, switch back to ascii keymap. */ 927 if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x50) { 928 bcopy(&ascii_kbdmap, &kbdmap, sizeof(struct kbdmap)); 929 930 splx(s); 931 return; 932 #ifdef DDB 933 } else if (key_mod == (KBD_MOD_LALT | KBD_MOD_LMETA) && c == 0x59) { 934 Debugger(); 935 splx(s); 936 return; 937 #endif 938 } 939 /* translate modifiers */ 940 if (key_mod & KBD_MOD_SHIFT) { 941 if (key_mod & KBD_MOD_ALT) 942 key = kbdmap.alt_shift_keys[c]; 943 else 944 key = kbdmap.shift_keys[c]; 945 } else if (key_mod & KBD_MOD_ALT) 946 key = kbdmap.alt_keys[c]; 947 else { 948 key = kbdmap.keys[c]; 949 /* if CAPS and key is CAPable (no pun intended) */ 950 if ((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) 951 key = kbdmap.shift_keys[c]; 952 } 953 code = key.code; 954 955 /* 956 * arrange to repeat the keystroke. By doing this at the level 957 * of scan-codes, we can have function keys, and keys that 958 * send strings, repeat too. This also entitles an additional 959 * overhead, since we have to do the conversion each time, but 960 * I guess that's ok. 961 */ 962 if (!tout_pending && caller == ITEFILT_TTY && kbd_ite->key_repeat) { 963 tout_pending = 1; 964 last_char = c; 965 callout_reset(&repeat_ch, 966 start_repeat_timeo * hz / 100, repeat_handler, NULL); 967 } else if (!tout_pending && caller == ITEFILT_REPEATER && 968 kbd_ite->key_repeat) { 969 tout_pending = 1; 970 last_char = c; 971 callout_reset(&repeat_ch, 972 next_repeat_timeo * hz / 100, repeat_handler, NULL); 973 } 974 /* handle dead keys */ 975 if (key.mode & KBD_MODE_DEAD) { 976 /* if entered twice, send accent itself */ 977 if (last_dead == (key.mode & KBD_MODE_ACCMASK)) 978 last_dead = 0; 979 else { 980 last_dead = key.mode & KBD_MODE_ACCMASK; 981 splx(s); 982 return; 983 } 984 } 985 if (last_dead) { 986 /* can't apply dead flag to string-keys */ 987 if (!(key.mode & KBD_MODE_STRING) && code >= '@' && 988 code < 0x7f) 989 code = acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; 990 last_dead = 0; 991 } 992 /* if not string, apply META and CTRL modifiers */ 993 if (!(key.mode & KBD_MODE_STRING) 994 && (!(key.mode & KBD_MODE_KPAD) || 995 (kbd_ite && !kbd_ite->keypad_appmode))) { 996 if (key_mod & KBD_MOD_CTRL) 997 code &= 0x1f; 998 if (key_mod & KBD_MOD_META) 999 code |= 0x80; 1000 } else if ((key.mode & KBD_MODE_KPAD) && 1001 (kbd_ite && kbd_ite->keypad_appmode)) { 1002 static char in[] = { 1003 0x0f /* 0 */, 0x1d /* 1 */, 0x1e /* 2 */, 0x1f /* 3 */, 1004 0x2d /* 4 */, 0x2e /* 5 */, 0x2f /* 6 */, 0x3d /* 7 */, 1005 0x3e /* 8 */, 0x3f /* 9 */, 0x4a /* - */, 0x5e /* + */, 1006 0x3c /* . */, 0x43 /* e */, 0x5a /* ( */, 0x5b /* ) */, 1007 0x5c /* / */, 0x5d /* * */ 1008 }; 1009 static const char *out = "pqrstuvwxymlnMPQRS"; 1010 char *cp = strchr(in, c); 1011 1012 /* 1013 * keypad-appmode sends SS3 followed by the above 1014 * translated character 1015 */ 1016 kbd_tty->t_linesw->l_rint(27, kbd_tty); 1017 kbd_tty->t_linesw->l_rint('O', kbd_tty); 1018 kbd_tty->t_linesw->l_rint(out[cp - in], kbd_tty); 1019 splx(s); 1020 return; 1021 } else { 1022 /* *NO* I don't like this.... */ 1023 static u_char app_cursor[] = 1024 { 1025 3, 27, 'O', 'A', 1026 3, 27, 'O', 'B', 1027 3, 27, 'O', 'C', 1028 3, 27, 'O', 'D'}; 1029 1030 str = kbdmap.strings + code; 1031 /* 1032 * if this is a cursor key, AND it has the default 1033 * keymap setting, AND we're in app-cursor mode, switch 1034 * to the above table. This is *nasty* ! 1035 */ 1036 if (c >= 0x4c && c <= 0x4f && kbd_ite->cursor_appmode 1037 && !bcmp(str, "\x03\x1b[", 3) && 1038 strchr("ABCD", str[3])) 1039 str = app_cursor + 4 * (str[3] - 'A'); 1040 1041 /* 1042 * using a length-byte instead of 0-termination allows 1043 * to embed \0 into strings, although this is not used 1044 * in the default keymap 1045 */ 1046 for (i = *str++; i; i--) 1047 kbd_tty->t_linesw->l_rint(*str++, kbd_tty); 1048 splx(s); 1049 return; 1050 } 1051 kbd_tty->t_linesw->l_rint(code, kbd_tty); 1052 1053 splx(s); 1054 return; 1055 } 1056 1057 /* helper functions, makes the code below more readable */ 1058 inline static void 1059 ite_sendstr(const char *str) 1060 { 1061 struct tty *kbd_tty; 1062 1063 kbd_tty = kbd_ite->tp; 1064 KDASSERT(kbd_tty); 1065 while (*str) 1066 kbd_tty->t_linesw->l_rint(*str++, kbd_tty); 1067 } 1068 1069 static void 1070 alignment_display(struct ite_softc *ip) 1071 { 1072 int i, j; 1073 1074 for (j = 0; j < ip->rows; j++) 1075 for (i = 0; i < ip->cols; i++) 1076 SUBR_PUTC(ip, 'E', j, i, ATTR_NOR); 1077 attrclr(ip, 0, 0, ip->rows, ip->cols); 1078 SUBR_CURSOR(ip, DRAW_CURSOR); 1079 } 1080 1081 inline static void 1082 snap_cury(struct ite_softc *ip) 1083 { 1084 if (ip->inside_margins) 1085 { 1086 if (ip->cury < ip->top_margin) 1087 ip->cury = ip->top_margin; 1088 if (ip->cury > ip->bottom_margin) 1089 ip->cury = ip->bottom_margin; 1090 } 1091 } 1092 1093 inline static void 1094 ite_dnchar(struct ite_softc *ip, int n) 1095 { 1096 n = min(n, ip->cols - ip->curx); 1097 if (n < ip->cols - ip->curx) 1098 { 1099 SUBR_SCROLL(ip, ip->cury, ip->curx + n, n, SCROLL_LEFT); 1100 attrmov(ip, ip->cury, ip->curx + n, ip->cury, ip->curx, 1101 1, ip->cols - ip->curx - n); 1102 attrclr(ip, ip->cury, ip->cols - n, 1, n); 1103 } 1104 while (n-- > 0) 1105 SUBR_PUTC(ip, ' ', ip->cury, ip->cols - n - 1, ATTR_NOR); 1106 SUBR_CURSOR(ip, DRAW_CURSOR); 1107 } 1108 1109 inline static void 1110 ite_inchar(struct ite_softc *ip, int n) 1111 { 1112 n = min(n, ip->cols - ip->curx); 1113 if (n < ip->cols - ip->curx) 1114 { 1115 SUBR_SCROLL(ip, ip->cury, ip->curx, n, SCROLL_RIGHT); 1116 attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + n, 1117 1, ip->cols - ip->curx - n); 1118 attrclr(ip, ip->cury, ip->curx, 1, n); 1119 } 1120 while (n--) 1121 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); 1122 SUBR_CURSOR(ip, DRAW_CURSOR); 1123 } 1124 1125 inline static void 1126 ite_clrtoeol(struct ite_softc *ip) 1127 { 1128 int y = ip->cury, x = ip->curx; 1129 if (ip->cols - x > 0) 1130 { 1131 SUBR_CLEAR(ip, y, x, 1, ip->cols - x); 1132 attrclr(ip, y, x, 1, ip->cols - x); 1133 SUBR_CURSOR(ip, DRAW_CURSOR); 1134 } 1135 } 1136 1137 inline static void 1138 ite_clrtobol(struct ite_softc *ip) 1139 { 1140 int y = ip->cury, x = min(ip->curx + 1, ip->cols); 1141 SUBR_CLEAR(ip, y, 0, 1, x); 1142 attrclr(ip, y, 0, 1, x); 1143 SUBR_CURSOR(ip, DRAW_CURSOR); 1144 } 1145 1146 inline static void 1147 ite_clrline(struct ite_softc *ip) 1148 { 1149 int y = ip->cury; 1150 SUBR_CLEAR(ip, y, 0, 1, ip->cols); 1151 attrclr(ip, y, 0, 1, ip->cols); 1152 SUBR_CURSOR(ip, DRAW_CURSOR); 1153 } 1154 1155 1156 1157 inline static void 1158 ite_clrtoeos(struct ite_softc *ip) 1159 { 1160 ite_clrtoeol(ip); 1161 if (ip->cury < ip->rows - 1) 1162 { 1163 SUBR_CLEAR(ip, ip->cury + 1, 0, ip->rows - 1 - ip->cury, ip->cols); 1164 attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols); 1165 SUBR_CURSOR(ip, DRAW_CURSOR); 1166 } 1167 } 1168 1169 inline static void 1170 ite_clrtobos(struct ite_softc *ip) 1171 { 1172 ite_clrtobol(ip); 1173 if (ip->cury > 0) 1174 { 1175 SUBR_CLEAR(ip, 0, 0, ip->cury, ip->cols); 1176 attrclr(ip, 0, 0, ip->cury, ip->cols); 1177 SUBR_CURSOR(ip, DRAW_CURSOR); 1178 } 1179 } 1180 1181 inline static void 1182 ite_clrscreen(struct ite_softc *ip) 1183 { 1184 SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols); 1185 attrclr(ip, 0, 0, ip->rows, ip->cols); 1186 SUBR_CURSOR(ip, DRAW_CURSOR); 1187 } 1188 1189 1190 1191 inline static void 1192 ite_dnline(struct ite_softc *ip, int n) 1193 { 1194 /* interesting.. if the cursor is outside the scrolling 1195 region, this command is simply ignored.. */ 1196 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) 1197 return; 1198 1199 n = min(n, ip->bottom_margin + 1 - ip->cury); 1200 if (n <= ip->bottom_margin - ip->cury) 1201 { 1202 SUBR_SCROLL(ip, ip->cury + n, 0, n, SCROLL_UP); 1203 attrmov(ip, ip->cury + n, 0, ip->cury, 0, 1204 ip->bottom_margin + 1 - ip->cury - n, ip->cols); 1205 } 1206 SUBR_CLEAR(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); 1207 attrclr(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); 1208 SUBR_CURSOR(ip, DRAW_CURSOR); 1209 } 1210 1211 inline static void 1212 ite_inline(struct ite_softc *ip, int n) 1213 { 1214 /* interesting.. if the cursor is outside the scrolling 1215 region, this command is simply ignored.. */ 1216 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) 1217 return; 1218 1219 n = min(n, ip->bottom_margin + 1 - ip->cury); 1220 if (n <= ip->bottom_margin - ip->cury) 1221 { 1222 SUBR_SCROLL(ip, ip->cury, 0, n, SCROLL_DOWN); 1223 attrmov(ip, ip->cury, 0, ip->cury + n, 0, 1224 ip->bottom_margin + 1 - ip->cury - n, ip->cols); 1225 } 1226 SUBR_CLEAR(ip, ip->cury, 0, n, ip->cols); 1227 attrclr(ip, ip->cury, 0, n, ip->cols); 1228 SUBR_CURSOR(ip, DRAW_CURSOR); 1229 } 1230 1231 inline static void 1232 ite_lf(struct ite_softc *ip) 1233 { 1234 ++ip->cury; 1235 if ((ip->cury == ip->bottom_margin+1) || (ip->cury == ip->rows)) 1236 { 1237 ip->cury--; 1238 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 1239 ite_clrline(ip); 1240 } 1241 SUBR_CURSOR(ip, MOVE_CURSOR); 1242 clr_attr(ip, ATTR_INV); 1243 } 1244 1245 inline static void 1246 ite_crlf(struct ite_softc *ip) 1247 { 1248 ip->curx = 0; 1249 ite_lf (ip); 1250 } 1251 1252 inline static void 1253 ite_cr(struct ite_softc *ip) 1254 { 1255 if (ip->curx) 1256 { 1257 ip->curx = 0; 1258 SUBR_CURSOR(ip, MOVE_CURSOR); 1259 } 1260 } 1261 1262 inline static void 1263 ite_rlf(struct ite_softc *ip) 1264 { 1265 ip->cury--; 1266 if ((ip->cury < 0) || (ip->cury == ip->top_margin - 1)) 1267 { 1268 ip->cury++; 1269 SUBR_SCROLL(ip, ip->top_margin, 0, 1, SCROLL_DOWN); 1270 ite_clrline(ip); 1271 } 1272 SUBR_CURSOR(ip, MOVE_CURSOR); 1273 clr_attr(ip, ATTR_INV); 1274 } 1275 1276 inline static int 1277 atoi(const char *cp) 1278 { 1279 int n; 1280 1281 for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++) 1282 n = n * 10 + *cp - '0'; 1283 1284 return n; 1285 } 1286 1287 inline static int 1288 ite_argnum(struct ite_softc *ip) 1289 { 1290 char ch; 1291 int n; 1292 1293 /* convert argument string into number */ 1294 if (ip->ap == ip->argbuf) 1295 return 1; 1296 ch = *ip->ap; 1297 *ip->ap = 0; 1298 n = atoi (ip->argbuf); 1299 *ip->ap = ch; 1300 1301 return n; 1302 } 1303 1304 inline static int 1305 ite_zargnum(struct ite_softc *ip) 1306 { 1307 char ch; 1308 int n; 1309 1310 /* convert argument string into number */ 1311 if (ip->ap == ip->argbuf) 1312 return 0; 1313 ch = *ip->ap; 1314 *ip->ap = 0; 1315 n = atoi (ip->argbuf); 1316 *ip->ap = ch; 1317 1318 return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */ 1319 } 1320 1321 void 1322 ite_putstr(const char *s, int len, dev_t dev) 1323 { 1324 struct ite_softc *ip; 1325 int i; 1326 1327 ip = getitesp(dev); 1328 1329 /* XXX avoid problems */ 1330 if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) 1331 return; 1332 1333 SUBR_CURSOR(ip, START_CURSOROPT); 1334 for (i = 0; i < len; i++) 1335 if (s[i]) 1336 iteputchar(s[i], ip); 1337 SUBR_CURSOR(ip, END_CURSOROPT); 1338 } 1339 1340 static void 1341 iteprecheckwrap(struct ite_softc *ip) 1342 { 1343 if (ip->auto_wrap && ip->curx == ip->cols) { 1344 ip->curx = 0; 1345 clr_attr(ip, ATTR_INV); 1346 if (++ip->cury >= ip->bottom_margin + 1) { 1347 ip->cury = ip->bottom_margin; 1348 SUBR_CURSOR(ip, MOVE_CURSOR); 1349 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 1350 ite_clrtoeol(ip); 1351 } else 1352 SUBR_CURSOR(ip, MOVE_CURSOR); 1353 } 1354 } 1355 1356 static void 1357 itecheckwrap(struct ite_softc *ip) 1358 { 1359 #if 0 1360 if (++ip->curx == ip->cols) { 1361 if (ip->auto_wrap) { 1362 ip->curx = 0; 1363 clr_attr(ip, ATTR_INV); 1364 if (++ip->cury >= ip->bottom_margin + 1) { 1365 ip->cury = ip->bottom_margin; 1366 SUBR_CURSOR(ip, MOVE_CURSOR); 1367 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); 1368 ite_clrtoeol(ip); 1369 return; 1370 } 1371 } else 1372 /* stay there if no autowrap.. */ 1373 ip->curx--; 1374 } 1375 #else 1376 if (ip->curx < ip->cols) { 1377 ip->curx++; 1378 SUBR_CURSOR(ip, MOVE_CURSOR); 1379 } 1380 #endif 1381 } 1382 1383 void 1384 iteputchar(register int c, struct ite_softc *ip) 1385 { 1386 struct tty *kbd_tty; 1387 int n, x, y; 1388 char *cp; 1389 1390 if (kbd_ite == NULL) 1391 kbd_tty = NULL; 1392 else 1393 kbd_tty = kbd_ite->tp; 1394 1395 if (ip->escape) { 1396 switch (ip->escape) { 1397 case ESC: 1398 switch (c) { 1399 /* 1400 * first 7bit equivalents for the 1401 * 8bit control characters 1402 */ 1403 case 'D': 1404 c = IND; 1405 ip->escape = 0; 1406 break; 1407 /* 1408 * and fall into the next 1409 * switch below (same for all `break') 1410 */ 1411 case 'E': 1412 c = NEL; 1413 ip->escape = 0; 1414 break; 1415 case 'H': 1416 c = HTS; 1417 ip->escape = 0; 1418 break; 1419 case 'M': 1420 c = RI; 1421 ip->escape = 0; 1422 break; 1423 case 'N': 1424 c = SS2; 1425 ip->escape = 0; 1426 break; 1427 case 'O': 1428 c = SS3; 1429 ip->escape = 0; 1430 break; 1431 case 'P': 1432 c = DCS; 1433 ip->escape = 0; 1434 break; 1435 case '[': 1436 c = CSI; 1437 ip->escape = 0; 1438 break; 1439 case '\\': 1440 c = ST; 1441 ip->escape = 0; 1442 break; 1443 case ']': 1444 c = OSC; 1445 ip->escape = 0; 1446 break; 1447 case '^': 1448 c = PM; 1449 ip->escape = 0; 1450 break; 1451 case '_': 1452 c = APC; 1453 ip->escape = 0; 1454 break; 1455 /* introduces 7/8bit control */ 1456 case ' ': 1457 /* can be followed by either F or G */ 1458 ip->escape = ' '; 1459 break; 1460 /* 1461 * a lot of character set selections, not yet 1462 * used... 94-character sets: 1463 */ 1464 case '(': /* G0 */ 1465 case ')': /* G1 */ 1466 ip->escape = c; 1467 return; 1468 case '*': /* G2 */ 1469 case '+': /* G3 */ 1470 case 'B': /* ASCII */ 1471 case 'A': /* ISO latin 1 */ 1472 case '<': /* user preferred suplemental */ 1473 case '0': /* dec special graphics */ 1474 /* 1475 * 96-character sets: 1476 */ 1477 case '-': /* G1 */ 1478 case '.': /* G2 */ 1479 case '/': /* G3 */ 1480 /* 1481 * national character sets: 1482 */ 1483 case '4': /* dutch */ 1484 case '5': 1485 case 'C': /* finnish */ 1486 case 'R': /* french */ 1487 case 'Q': /* french canadian */ 1488 case 'K': /* german */ 1489 case 'Y': /* italian */ 1490 case '6': /* norwegian/danish */ 1491 /* 1492 * note: %5 and %6 are not supported (two 1493 * chars..) 1494 */ 1495 ip->escape = 0; 1496 /* just ignore for now */ 1497 return; 1498 /* 1499 * locking shift modes (as you might guess, not 1500 * yet supported..) 1501 */ 1502 case '`': 1503 ip->GR = ip->G1; 1504 ip->escape = 0; 1505 return; 1506 case 'n': 1507 ip->GL = ip->G2; 1508 ip->escape = 0; 1509 return; 1510 case '}': 1511 ip->GR = ip->G2; 1512 ip->escape = 0; 1513 return; 1514 case 'o': 1515 ip->GL = ip->G3; 1516 ip->escape = 0; 1517 return; 1518 case '|': 1519 ip->GR = ip->G3; 1520 ip->escape = 0; 1521 return; 1522 case '#': 1523 /* font width/height control */ 1524 ip->escape = '#'; 1525 return; 1526 case 'c': 1527 /* hard terminal reset .. */ 1528 ite_reset(ip); 1529 SUBR_CURSOR(ip, MOVE_CURSOR); 1530 ip->escape = 0; 1531 return; 1532 case '7': 1533 ip->save_curx = ip->curx; 1534 ip->save_cury = ip->cury; 1535 ip->save_attribute = ip->attribute; 1536 ip->escape = 0; 1537 return; 1538 case '8': 1539 ip->curx = ip->save_curx; 1540 ip->cury = ip->save_cury; 1541 ip->attribute = ip->save_attribute; 1542 SUBR_CURSOR(ip, MOVE_CURSOR); 1543 ip->escape = 0; 1544 return; 1545 case '=': 1546 ip->keypad_appmode = 1; 1547 ip->escape = 0; 1548 return; 1549 case '>': 1550 ip->keypad_appmode = 0; 1551 ip->escape = 0; 1552 return; 1553 case 'Z': /* request ID */ 1554 /* XXX not clean */ 1555 if (ip->emul_level == EMUL_VT100) 1556 ite_sendstr("\033[?61;0c"); 1557 else 1558 ite_sendstr("\033[?63;0c"); 1559 ip->escape = 0; 1560 return; 1561 default: 1562 /* 1563 * default catch all for not recognized ESC 1564 * sequences 1565 */ 1566 ip->escape = 0; 1567 return; 1568 } 1569 break; 1570 case '(': 1571 case ')': 1572 ip->escape = 0; 1573 return; 1574 case ' ': 1575 switch (c) { 1576 case 'F': 1577 ip->eightbit_C1 = 0; 1578 ip->escape = 0; 1579 return; 1580 case 'G': 1581 ip->eightbit_C1 = 1; 1582 ip->escape = 0; 1583 return; 1584 default: 1585 /* not supported */ 1586 ip->escape = 0; 1587 return; 1588 } 1589 break; 1590 case '#': 1591 switch (c) { 1592 case '5': 1593 /* single height, single width */ 1594 ip->escape = 0; 1595 return; 1596 case '6': 1597 /* double width, single height */ 1598 ip->escape = 0; 1599 return; 1600 case '3': 1601 /* top half */ 1602 ip->escape = 0; 1603 return; 1604 case '4': 1605 /* bottom half */ 1606 ip->escape = 0; 1607 return; 1608 case '8': 1609 /* screen alignment pattern... */ 1610 alignment_display(ip); 1611 ip->escape = 0; 1612 return; 1613 default: 1614 ip->escape = 0; 1615 return; 1616 } 1617 break; 1618 case CSI: 1619 /* the biggie... */ 1620 switch (c) { 1621 case '0': 1622 case '1': 1623 case '2': 1624 case '3': 1625 case '4': 1626 case '5': 1627 case '6': 1628 case '7': 1629 case '8': 1630 case '9': 1631 case ';': 1632 case '\"': 1633 case '$': 1634 case '>': 1635 if (ip->ap < ip->argbuf + MAX_ARGSIZE) 1636 *ip->ap++ = c; 1637 return; 1638 case BS: 1639 /* 1640 * you wouldn't believe such perversion is 1641 * possible? it is.. BS is allowed in between 1642 * cursor sequences (at least), according to 1643 * vttest.. 1644 */ 1645 if (--ip->curx < 0) 1646 ip->curx = 0; 1647 else 1648 SUBR_CURSOR(ip, MOVE_CURSOR); 1649 break; 1650 case 'p': 1651 *ip->ap = 0; 1652 if (!strncmp(ip->argbuf, "61\"", 3)) 1653 ip->emul_level = EMUL_VT100; 1654 else if (!strncmp(ip->argbuf, "63;1\"", 5) 1655 || !strncmp(ip->argbuf, "62;1\"", 5)) 1656 ip->emul_level = EMUL_VT300_7; 1657 else 1658 ip->emul_level = EMUL_VT300_8; 1659 ip->escape = 0; 1660 return; 1661 case '?': 1662 *ip->ap = 0; 1663 ip->escape = '?'; 1664 ip->ap = ip->argbuf; 1665 return; 1666 case 'c': 1667 *ip->ap = 0; 1668 if (ip->argbuf[0] == '>') { 1669 ite_sendstr("\033[>24;0;0;0c"); 1670 } else 1671 switch (ite_zargnum(ip)) { 1672 case 0: 1673 /* 1674 * primary DA request, send 1675 * primary DA response 1676 */ 1677 if (ip->emul_level 1678 == EMUL_VT100) 1679 ite_sendstr( 1680 "\033[?1;1c"); 1681 else 1682 ite_sendstr( 1683 "\033[?63;1c"); 1684 break; 1685 } 1686 ip->escape = 0; 1687 return; 1688 case 'n': 1689 switch (ite_zargnum(ip)) { 1690 case 5: 1691 /* no malfunction */ 1692 ite_sendstr("\033[0n"); 1693 break; 1694 case 6: 1695 /* cursor position report */ 1696 sprintf(ip->argbuf, "\033[%d;%dR", 1697 ip->cury + 1, ip->curx + 1); 1698 ite_sendstr(ip->argbuf); 1699 break; 1700 } 1701 ip->escape = 0; 1702 return; 1703 case 'x': 1704 switch (ite_zargnum(ip)) { 1705 case 0: 1706 /* Fake some terminal parameters. */ 1707 ite_sendstr("\033[2;1;1;112;112;1;0x"); 1708 break; 1709 case 1: 1710 ite_sendstr("\033[3;1;1;112;112;1;0x"); 1711 break; 1712 } 1713 ip->escape = 0; 1714 return; 1715 case 'g': 1716 switch (ite_zargnum(ip)) { 1717 case 0: 1718 if (ip->curx < ip->cols) 1719 ip->tabs[ip->curx] = 0; 1720 break; 1721 case 3: 1722 for (n = 0; n < ip->cols; n++) 1723 ip->tabs[n] = 0; 1724 break; 1725 } 1726 ip->escape = 0; 1727 return; 1728 case 'h': 1729 case 'l': 1730 n = ite_zargnum(ip); 1731 switch (n) { 1732 case 4: 1733 /* insert/replace mode */ 1734 ip->imode = (c == 'h'); 1735 break; 1736 case 20: 1737 ip->linefeed_newline = (c == 'h'); 1738 break; 1739 } 1740 ip->escape = 0; 1741 return; 1742 case 'M': 1743 ite_dnline(ip, ite_argnum(ip)); 1744 ip->escape = 0; 1745 return; 1746 case 'L': 1747 ite_inline(ip, ite_argnum(ip)); 1748 ip->escape = 0; 1749 return; 1750 case 'P': 1751 ite_dnchar(ip, ite_argnum(ip)); 1752 ip->escape = 0; 1753 return; 1754 case '@': 1755 ite_inchar(ip, ite_argnum(ip)); 1756 ip->escape = 0; 1757 return; 1758 case 'G': 1759 /* 1760 * this one was *not* in my vt320 manual but in 1761 * a vt320 termcap entry.. who is right? It's 1762 * supposed to set the horizontal cursor 1763 * position. 1764 */ 1765 *ip->ap = 0; 1766 x = atoi(ip->argbuf); 1767 if (x) 1768 x--; 1769 ip->curx = min(x, ip->cols - 1); 1770 ip->escape = 0; 1771 SUBR_CURSOR(ip, MOVE_CURSOR); 1772 clr_attr(ip, ATTR_INV); 1773 return; 1774 case 'd': 1775 /* 1776 * same thing here, this one's for setting the 1777 * absolute vertical cursor position. Not 1778 * documented... 1779 */ 1780 *ip->ap = 0; 1781 y = atoi(ip->argbuf); 1782 if (y) 1783 y--; 1784 if (ip->inside_margins) 1785 y += ip->top_margin; 1786 ip->cury = min(y, ip->rows - 1); 1787 ip->escape = 0; 1788 snap_cury(ip); 1789 SUBR_CURSOR(ip, MOVE_CURSOR); 1790 clr_attr(ip, ATTR_INV); 1791 return; 1792 case 'H': 1793 case 'f': 1794 *ip->ap = 0; 1795 y = atoi(ip->argbuf); 1796 x = 0; 1797 cp = strchr(ip->argbuf, ';'); 1798 if (cp) 1799 x = atoi(cp + 1); 1800 if (x) 1801 x--; 1802 if (y) 1803 y--; 1804 if (ip->inside_margins) 1805 y += ip->top_margin; 1806 ip->cury = min(y, ip->rows - 1); 1807 ip->curx = min(x, ip->cols - 1); 1808 ip->escape = 0; 1809 snap_cury(ip); 1810 SUBR_CURSOR(ip, MOVE_CURSOR); 1811 clr_attr(ip, ATTR_INV); 1812 return; 1813 case 'A': 1814 n = ite_argnum(ip); 1815 n = ip->cury - (n ? n : 1); 1816 if (n < 0) 1817 n = 0; 1818 if (ip->inside_margins) 1819 n = max(ip->top_margin, n); 1820 else if (n == ip->top_margin - 1) 1821 /* 1822 * allow scrolling outside region, but 1823 * don't scroll out of active region 1824 * without explicit CUP 1825 */ 1826 n = ip->top_margin; 1827 ip->cury = n; 1828 ip->escape = 0; 1829 SUBR_CURSOR(ip, MOVE_CURSOR); 1830 clr_attr(ip, ATTR_INV); 1831 return; 1832 case 'B': 1833 n = ite_argnum(ip); 1834 n = ip->cury + (n ? n : 1); 1835 n = min(ip->rows - 1, n); 1836 if (ip->inside_margins) 1837 n = min(ip->bottom_margin, n); 1838 else if (n == ip->bottom_margin + 1) 1839 /* 1840 * allow scrolling outside region, but 1841 * don't scroll out of active region 1842 * without explicit CUP 1843 */ 1844 n = ip->bottom_margin; 1845 ip->cury = n; 1846 ip->escape = 0; 1847 SUBR_CURSOR(ip, MOVE_CURSOR); 1848 clr_attr(ip, ATTR_INV); 1849 return; 1850 case 'C': 1851 n = ite_argnum(ip); 1852 n = n ? n : 1; 1853 ip->curx = min(ip->curx + n, ip->cols - 1); 1854 ip->escape = 0; 1855 SUBR_CURSOR(ip, MOVE_CURSOR); 1856 clr_attr(ip, ATTR_INV); 1857 return; 1858 case 'D': 1859 n = ite_argnum(ip); 1860 n = n ? n : 1; 1861 n = ip->curx - n; 1862 ip->curx = n >= 0 ? n : 0; 1863 ip->escape = 0; 1864 SUBR_CURSOR(ip, MOVE_CURSOR); 1865 clr_attr(ip, ATTR_INV); 1866 return; 1867 case 'J': 1868 *ip->ap = 0; 1869 n = ite_zargnum(ip); 1870 if (n == 0) 1871 ite_clrtoeos(ip); 1872 else if (n == 1) 1873 ite_clrtobos(ip); 1874 else if (n == 2) 1875 ite_clrscreen(ip); 1876 ip->escape = 0; 1877 return; 1878 case 'K': 1879 n = ite_zargnum(ip); 1880 if (n == 0) 1881 ite_clrtoeol(ip); 1882 else if (n == 1) 1883 ite_clrtobol(ip); 1884 else if (n == 2) 1885 ite_clrline(ip); 1886 ip->escape = 0; 1887 return; 1888 case 'X': 1889 n = ite_argnum(ip) - 1; 1890 n = min(n, ip->cols - 1 - ip->curx); 1891 for (; n >= 0; n--) { 1892 attrclr(ip, ip->cury, ip->curx + n, 1, 1); 1893 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); 1894 } 1895 ip->escape = 0; 1896 return; 1897 case '}': 1898 case '`': 1899 /* status line control */ 1900 ip->escape = 0; 1901 return; 1902 case 'r': 1903 *ip->ap = 0; 1904 x = atoi(ip->argbuf); 1905 x = x ? x : 1; 1906 y = ip->rows; 1907 cp = strchr(ip->argbuf, ';'); 1908 if (cp) { 1909 y = atoi(cp + 1); 1910 y = y ? y : ip->rows; 1911 } 1912 if (y - x < 2) { 1913 /* 1914 * if illegal scrolling region, reset 1915 * to defaults 1916 */ 1917 x = 1; 1918 y = ip->rows; 1919 } 1920 x--; 1921 y--; 1922 ip->top_margin = min(x, ip->rows - 1); 1923 ip->bottom_margin = min(y, ip->rows - 1); 1924 if (ip->inside_margins) { 1925 ip->cury = ip->top_margin; 1926 ip->curx = 0; 1927 SUBR_CURSOR(ip, MOVE_CURSOR); 1928 } 1929 ip->escape = 0; 1930 return; 1931 case 'm': 1932 /* big attribute setter/resetter */ 1933 { char *_cp; 1934 *ip->ap = 0; 1935 /* kludge to make CSIm work (== CSI0m) */ 1936 if (ip->ap == ip->argbuf) 1937 ip->ap++; 1938 for (_cp = ip->argbuf; _cp < ip->ap;) { 1939 switch (*_cp) { 1940 case 0: 1941 case '0': 1942 clr_attr(ip, ATTR_ALL); 1943 _cp++; 1944 break; 1945 1946 case '1': 1947 set_attr(ip, ATTR_BOLD); 1948 _cp++; 1949 break; 1950 1951 case '2': 1952 switch (_cp[1]) { 1953 case '2': 1954 clr_attr(ip, ATTR_BOLD); 1955 _cp += 2; 1956 break; 1957 1958 case '4': 1959 clr_attr(ip, ATTR_UL); 1960 _cp += 2; 1961 break; 1962 1963 case '5': 1964 clr_attr(ip, ATTR_BLINK); 1965 _cp += 2; 1966 break; 1967 1968 case '7': 1969 clr_attr(ip, ATTR_INV); 1970 _cp += 2; 1971 break; 1972 1973 default: 1974 _cp++; 1975 break; 1976 } 1977 break; 1978 1979 case '4': 1980 set_attr(ip, ATTR_UL); 1981 _cp++; 1982 break; 1983 1984 case '5': 1985 set_attr(ip, ATTR_BLINK); 1986 _cp++; 1987 break; 1988 1989 case '7': 1990 set_attr(ip, ATTR_INV); 1991 _cp++; 1992 break; 1993 1994 default: 1995 _cp++; 1996 break; 1997 } 1998 } 1999 ip->escape = 0; 2000 return; } 2001 case 'u': 2002 /* DECRQTSR */ 2003 ite_sendstr("\033P\033\\"); 2004 ip->escape = 0; 2005 return; 2006 default: 2007 ip->escape = 0; 2008 return; 2009 } 2010 break; 2011 case '?': /* CSI ? */ 2012 switch (c) { 2013 case '0': 2014 case '1': 2015 case '2': 2016 case '3': 2017 case '4': 2018 case '5': 2019 case '6': 2020 case '7': 2021 case '8': 2022 case '9': 2023 case ';': 2024 case '\"': 2025 case '$': 2026 /* 2027 * Don't fill the last character; 2028 * it's needed. 2029 * XXX yeah, where ?? 2030 */ 2031 if (ip->ap < ip->argbuf + MAX_ARGSIZE - 1) 2032 *ip->ap++ = c; 2033 return; 2034 case 'n': 2035 *ip->ap = 0; 2036 if (ip->ap == &ip->argbuf[2]) { 2037 if (!strncmp(ip->argbuf, "15", 2)) 2038 /* printer status: no printer */ 2039 ite_sendstr("\033[13n"); 2040 2041 else if (!strncmp(ip->argbuf, "25", 2)) 2042 /* udk status */ 2043 ite_sendstr("\033[20n"); 2044 2045 else if (!strncmp(ip->argbuf, "26", 2)) 2046 /* keyboard dialect: US */ 2047 ite_sendstr("\033[27;1n"); 2048 } 2049 ip->escape = 0; 2050 return; 2051 case 'h': 2052 case 'l': 2053 n = ite_zargnum(ip); 2054 switch (n) { 2055 case 1: 2056 ip->cursor_appmode = (c == 'h'); 2057 break; 2058 case 3: 2059 /* 132/80 columns (132 == 'h') */ 2060 break; 2061 case 4: /* smooth scroll */ 2062 break; 2063 case 5: 2064 /* 2065 * light background (=='h') /dark 2066 * background(=='l') 2067 */ 2068 break; 2069 case 6: /* origin mode */ 2070 ip->inside_margins = (c == 'h'); 2071 ip->curx = 0; 2072 ip->cury = ip->inside_margins ? 2073 ip->top_margin : 0; 2074 SUBR_CURSOR(ip, MOVE_CURSOR); 2075 break; 2076 case 7: /* auto wraparound */ 2077 ip->auto_wrap = (c == 'h'); 2078 break; 2079 case 8: /* keyboard repeat */ 2080 ip->key_repeat = (c == 'h'); 2081 break; 2082 case 20: /* newline mode */ 2083 ip->linefeed_newline = (c == 'h'); 2084 break; 2085 case 25: /* cursor on/off */ 2086 SUBR_CURSOR(ip, (c == 'h') ? 2087 DRAW_CURSOR : ERASE_CURSOR); 2088 break; 2089 } 2090 ip->escape = 0; 2091 return; 2092 default: 2093 ip->escape = 0; 2094 return; 2095 } 2096 break; 2097 default: 2098 ip->escape = 0; 2099 return; 2100 } 2101 } 2102 switch (c) { 2103 case VT: /* VT is treated like LF */ 2104 case FF: /* so is FF */ 2105 case LF: 2106 /* 2107 * cr->crlf distinction is done here, on output, not on input! 2108 */ 2109 if (ip->linefeed_newline) 2110 ite_crlf(ip); 2111 else 2112 ite_lf(ip); 2113 break; 2114 case CR: 2115 ite_cr(ip); 2116 break; 2117 case BS: 2118 if (--ip->curx < 0) 2119 ip->curx = 0; 2120 else 2121 SUBR_CURSOR(ip, MOVE_CURSOR); 2122 break; 2123 case HT: 2124 for (n = ip->curx + 1; n < ip->cols; n++) { 2125 if (ip->tabs[n]) { 2126 ip->curx = n; 2127 SUBR_CURSOR(ip, MOVE_CURSOR); 2128 break; 2129 } 2130 } 2131 break; 2132 case BEL: 2133 if (kbd_tty && kbd_ite && kbd_ite->tp == kbd_tty 2134 #ifdef DRACO 2135 && !is_draco() 2136 #endif 2137 ) 2138 ite_bell(); 2139 break; 2140 case SO: 2141 ip->GL = ip->G1; 2142 break; 2143 case SI: 2144 ip->GL = ip->G0; 2145 break; 2146 case ENQ: 2147 /* send answer-back message !! */ 2148 break; 2149 case CAN: 2150 ip->escape = 0; /* cancel any escape sequence in progress */ 2151 break; 2152 case SUB: 2153 ip->escape = 0; /* dito, but see below */ 2154 /* should also display a reverse question mark!! */ 2155 break; 2156 case ESC: 2157 ip->escape = ESC; 2158 break; 2159 /* 2160 * now it gets weird.. 8bit control sequences.. 2161 */ 2162 case IND: 2163 /* index: move cursor down, scroll */ 2164 ite_lf(ip); 2165 break; 2166 case NEL: 2167 /* next line. next line, first pos. */ 2168 ite_crlf(ip); 2169 break; 2170 case HTS: 2171 /* set horizontal tab */ 2172 if (ip->curx < ip->cols) 2173 ip->tabs[ip->curx] = 1; 2174 break; 2175 case RI: 2176 /* reverse index */ 2177 ite_rlf(ip); 2178 break; 2179 case SS2: 2180 /* go into G2 for one character */ 2181 /* not yet supported */ 2182 break; 2183 case SS3: 2184 /* go into G3 for one character */ 2185 break; 2186 case DCS: 2187 /* device control string introducer */ 2188 ip->escape = DCS; 2189 ip->ap = ip->argbuf; 2190 break; 2191 case CSI: 2192 /* control sequence introducer */ 2193 ip->escape = CSI; 2194 ip->ap = ip->argbuf; 2195 break; 2196 case ST: 2197 /* string terminator */ 2198 /* ignore, if not used as terminator */ 2199 break; 2200 case OSC: 2201 /* 2202 * introduces OS command. Ignore everything 2203 * upto ST 2204 */ 2205 ip->escape = OSC; 2206 break; 2207 case PM: 2208 /* privacy message, ignore everything upto ST */ 2209 ip->escape = PM; 2210 break; 2211 case APC: 2212 /* 2213 * application program command, ignore * everything upto ST 2214 */ 2215 ip->escape = APC; 2216 break; 2217 default: 2218 if ((c & 0x7f) < ' ' || c == DEL) 2219 break; 2220 if (ip->imode) 2221 ite_inchar(ip, 1); 2222 iteprecheckwrap(ip); 2223 #ifdef DO_WEIRD_ATTRIBUTES 2224 if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) { 2225 attrset(ip, ATTR_INV); 2226 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_INV); 2227 } else 2228 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_NOR); 2229 #else 2230 SUBR_PUTC(ip, c, ip->cury, ip->curx, ip->attribute); 2231 #endif 2232 SUBR_CURSOR(ip, DRAW_CURSOR); 2233 itecheckwrap(ip); 2234 break; 2235 } 2236 } 2237 2238