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