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