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