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