Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / x68k / dev / ite.c
blobb2f5c5ce671c8128a1baa5a61938ace3585e4157
1 /* $NetBSD: ite.c,v 1.56 2009/01/17 09:20:46 isaki Exp $ */
3 /*
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * from: Utah $Hdr: ite.c 1.1 90/07/09$
37 * @(#)ite.c 7.6 (Berkeley) 5/16/91
40 * Copyright (c) 1988 University of Utah.
42 * This code is derived from software contributed to Berkeley by
43 * the Systems Programming Group of the University of Utah Computer
44 * Science Department.
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by the University of
57 * California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
74 * from: Utah $Hdr: ite.c 1.1 90/07/09$
76 * @(#)ite.c 7.6 (Berkeley) 5/16/91
80 * ite - bitmaped terminal.
81 * Supports VT200, a few terminal features will be unavailable until
82 * the system actually probes the device (i.e. not after consinit())
85 #include <sys/cdefs.h>
86 __KERNEL_RCSID(0, "$NetBSD: ite.c,v 1.56 2009/01/17 09:20:46 isaki Exp $");
88 #include "ite.h"
89 #if NITE > 0
91 #include "bell.h"
92 #include "kbd.h"
94 #include "opt_ite.h"
96 #include <sys/param.h>
97 #include <sys/conf.h>
98 #include <sys/proc.h>
99 #include <sys/ioctl.h>
100 #include <sys/tty.h>
101 #include <sys/systm.h>
102 #include <sys/device.h>
103 #include <sys/malloc.h>
104 #include <sys/kauth.h>
106 #include <machine/cpu.h>
107 #include <machine/kbio.h>
108 #include <machine/bus.h>
109 #include <machine/autoconf.h>
110 #include <machine/grfioctl.h>
111 #include <machine/iteioctl.h>
113 #include <arch/x68k/dev/grfvar.h>
114 #include <arch/x68k/dev/itevar.h>
115 #include <arch/x68k/dev/kbdmap.h>
116 #include <arch/x68k/dev/mfp.h>
117 #if NBELL > 0
118 void opm_bell(void);
119 #endif
121 #define SUBR_INIT(ip) ip->isw->ite_init(ip)
122 #define SUBR_DEINIT(ip) ip->isw->ite_deinit(ip)
123 #define SUBR_PUTC(ip,c,dy,dx,m) ip->isw->ite_putc(ip,c,dy,dx,m)
124 #define SUBR_CURSOR(ip,flg) ip->isw->ite_cursor(ip,flg)
125 #define SUBR_CLEAR(ip,sy,sx,h,w) ip->isw->ite_clear(ip,sy,sx,h,w)
126 #define SUBR_SCROLL(ip,sy,sx,count,dir) \
127 ip->isw->ite_scroll(ip,sy,sx,count,dir)
129 struct consdev;
131 inline static void itesendch(int);
132 inline static void alignment_display(struct ite_softc *);
133 inline static void snap_cury(struct ite_softc *);
134 inline static void ite_dnchar(struct ite_softc *, int);
135 static void ite_inchar(struct ite_softc *, int);
136 inline static void ite_clrtoeol(struct ite_softc *);
137 inline static void ite_clrtobol(struct ite_softc *);
138 inline static void ite_clrline(struct ite_softc *);
139 inline static void ite_clrtoeos(struct ite_softc *);
140 inline static void ite_clrtobos(struct ite_softc *);
141 inline static void ite_clrscreen(struct ite_softc *);
142 inline static void ite_dnline(struct ite_softc *, int);
143 inline static void ite_inline(struct ite_softc *, int);
144 inline static void ite_index(struct ite_softc *);
145 inline static void ite_lf(struct ite_softc *);
146 inline static void ite_crlf(struct ite_softc *);
147 inline static void ite_cr(struct ite_softc *);
148 inline static void ite_rlf(struct ite_softc *);
149 static void iteprecheckwrap(struct ite_softc *);
150 static void itecheckwrap(struct ite_softc *);
151 static int ite_argnum(struct ite_softc *);
152 static int ite_zargnum(struct ite_softc *);
153 static void ite_sendstr(struct ite_softc *, const char *);
154 inline static int atoi(const char *);
155 void ite_reset(struct ite_softc *);
156 struct ite_softc *getitesp(dev_t);
157 int iteon(dev_t, int);
158 void iteoff(dev_t, int);
160 struct itesw itesw[] = {
161 {0, tv_init, tv_deinit, 0,
162 0, 0, 0}
166 * # of chars are output in a single itestart() call.
167 * If this is too big, user processes will be blocked out for
168 * long periods of time while we are emptying the queue in itestart().
169 * If it is too small, console output will be very ragged.
171 #define ITEBURST 64
173 struct tty *ite_tty[NITE];
174 struct ite_softc *kbd_ite = NULL;
175 struct ite_softc con_itesoftc;
177 struct tty *kbd_tty = NULL;
179 int start_repeat_timeo = 20; /* /100: initial timeout till pressed key repeats */
180 int next_repeat_timeo = 3; /* /100: timeout when repeating for next char */
182 u_char cons_tabs[MAX_TABS];
184 void itestart(struct tty *);
186 void iteputchar(int, struct ite_softc *);
187 void ite_putstr(const u_char *, int, dev_t);
189 int itematch(device_t, cfdata_t, void *);
190 void iteattach(device_t, device_t, void *);
192 CFATTACH_DECL_NEW(ite, sizeof(struct ite_softc),
193 itematch, iteattach, NULL, NULL);
195 extern struct cfdriver ite_cd;
197 dev_type_open(iteopen);
198 dev_type_close(iteclose);
199 dev_type_read(iteread);
200 dev_type_write(itewrite);
201 dev_type_ioctl(iteioctl);
202 dev_type_tty(itetty);
203 dev_type_poll(itepoll);
205 const struct cdevsw ite_cdevsw = {
206 iteopen, iteclose, iteread, itewrite, iteioctl,
207 nostop, itetty, itepoll, nommap, ttykqfilter, D_TTY
211 itematch(device_t pdp, cfdata_t cdp, void *auxp)
213 struct grf_softc *gp;
215 gp = auxp;
216 if (cdp->cf_loc[GRFCF_GRFADDR] != gp->g_cfaddr)
217 return 0;
219 return 1;
223 * iteinit() is the standard entry point for initialization of
224 * an ite device, it is also called from ite_cninit().
226 void
227 iteattach(device_t pdp, device_t dp, void *auxp)
229 struct ite_softc *ip;
230 struct grf_softc *gp;
232 gp = (struct grf_softc *)auxp;
233 ip = device_private(dp);
234 if(con_itesoftc.grf != NULL
235 /*&& con_itesoftc.grf->g_unit == gp->g_unit*/) {
237 * console reinit copy params over.
238 * and console always gets keyboard
240 memcpy(&ip->grf, &con_itesoftc.grf,
241 (char *)&ip[1] - (char *)&ip->grf);
242 con_itesoftc.grf = NULL;
243 kbd_ite = ip;
245 ip->grf = gp;
246 iteinit(device_unit(&ip->device)); /* XXX */
247 aprint_normal(": rows %d cols %d", ip->rows, ip->cols);
248 if (kbd_ite == NULL)
249 kbd_ite = ip;
250 aprint_normal("\n");
253 struct ite_softc *
254 getitesp(dev_t dev)
257 if (x68k_realconfig && con_itesoftc.grf == NULL)
258 return device_lookup_private(&ite_cd, UNIT(dev));
260 if (con_itesoftc.grf == NULL)
261 panic("no ite_softc for console");
262 return(&con_itesoftc);
265 void
266 iteinit(dev_t dev)
268 struct ite_softc *ip;
270 ip = getitesp(dev);
272 if (ip->flags & ITE_INITED)
273 return;
274 memcpy(&kbdmap, &ascii_kbdmap, sizeof(struct kbdmap));
276 ip->curx = 0;
277 ip->cury = 0;
278 ip->cursorx = 0;
279 ip->cursory = 0;
281 ip->isw = &itesw[device_unit(&ip->device)]; /* XXX */
282 SUBR_INIT(ip);
283 SUBR_CURSOR(ip, DRAW_CURSOR);
284 if (!ip->tabs)
285 ip->tabs = malloc(MAX_TABS*sizeof(u_char), M_DEVBUF, M_WAITOK);
286 ite_reset(ip);
287 ip->flags |= ITE_INITED;
290 void
291 ite_config_console(void)
293 struct grf_softc *gp = &congrf;
295 if (con_itesoftc.grf != NULL)
296 return;
297 con_itesoftc.grf = gp;
298 con_itesoftc.tabs = cons_tabs;
302 * Perform functions necessary to setup device as a terminal emulator.
305 iteon(dev_t dev, int flag)
307 int unit = UNIT(dev);
308 struct ite_softc *ip;
310 if (unit < 0 || unit >= ite_cd.cd_ndevs ||
311 (ip = getitesp(unit)) == NULL || (ip->flags&ITE_ALIVE) == 0)
312 return(ENXIO);
313 /* force ite active, overriding graphics mode */
314 if (flag & 1) {
315 ip->flags |= ITE_ACTIVE;
316 ip->flags &= ~(ITE_INGRF|ITE_INITED);
318 /* leave graphics mode */
319 if (flag & 2) {
320 ip->flags &= ~ITE_INGRF;
321 if ((ip->flags & ITE_ACTIVE) == 0)
322 return(0);
324 ip->flags |= ITE_ACTIVE;
325 if (ip->flags & ITE_INGRF)
326 return(0);
327 iteinit(dev);
328 if (flag & 2)
329 ite_reset(ip);
330 #if NKBD > 0
331 mfp_send_usart(0x49); /* XXX */
332 #endif
333 return(0);
337 * "Shut down" device as terminal emulator.
338 * Note that we do not deinit the console device unless forced.
339 * Deinit'ing the console every time leads to a very active
340 * screen when processing /etc/rc.
342 void
343 iteoff(dev_t dev, int flag)
345 int unit = UNIT(dev);
346 struct ite_softc *ip;
348 /* XXX check whether when call from grf.c */
349 if (unit < 0 || unit >= ite_cd.cd_ndevs ||
350 (ip = getitesp(unit)) == NULL || (ip->flags&ITE_ALIVE) == 0)
351 return;
352 if (flag & 2)
353 ip->flags |= ITE_INGRF;
355 if ((ip->flags & ITE_ACTIVE) == 0)
356 return;
357 if ((flag & 1) ||
358 (ip->flags & (ITE_INGRF|ITE_ISCONS|ITE_INITED)) == ITE_INITED)
359 SUBR_DEINIT(ip);
362 * XXX When the system is rebooted with "reboot", init(8)
363 * kills the last process to have the console open.
364 * If we don't revent the ITE_ACTIVE bit from being
365 * cleared, we will never see messages printed during
366 * the process of rebooting.
368 if ((flag & 2) == 0 && (ip->flags & ITE_ISCONS) == 0) {
369 ip->flags &= ~ITE_ACTIVE;
370 #if NKBD > 0
371 mfp_send_usart(0x48); /* XXX */
372 #endif
377 * standard entry points to the device.
380 /* ARGSUSED */
382 iteopen(dev_t dev, int mode, int devtype, struct lwp *l)
384 int unit = UNIT(dev);
385 struct tty *tp;
386 struct ite_softc *ip;
387 int error;
388 int first = 0;
390 if (unit >= ite_cd.cd_ndevs || (ip = getitesp(dev)) == NULL)
391 return (ENXIO);
392 if (!ite_tty[unit]) {
393 tp = ite_tty[unit] = ttymalloc();
394 tty_attach(tp);
395 } else
396 tp = ite_tty[unit];
397 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
398 return (EBUSY);
399 if ((ip->flags & ITE_ACTIVE) == 0) {
400 error = iteon(dev, 0);
401 if (error)
402 return (error);
403 first = 1;
405 tp->t_oproc = itestart;
406 tp->t_param = NULL;
407 tp->t_dev = dev;
408 if ((tp->t_state&TS_ISOPEN) == 0) {
409 ttychars(tp);
410 tp->t_iflag = TTYDEF_IFLAG;
411 tp->t_oflag = TTYDEF_OFLAG;
412 tp->t_cflag = TTYDEF_CFLAG;
413 tp->t_lflag = TTYDEF_LFLAG;
414 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
415 tp->t_state = TS_ISOPEN|TS_CARR_ON;
416 ttsetwater(tp);
418 error = (*tp->t_linesw->l_open)(dev, tp);
419 if (error == 0) {
420 tp->t_winsize.ws_row = ip->rows;
421 tp->t_winsize.ws_col = ip->cols;
422 } else if (first)
423 iteoff(dev, 0);
424 return (error);
427 /*ARGSUSED*/
429 iteclose(dev_t dev, int flag, int mode, struct lwp *l)
431 struct tty *tp = ite_tty[UNIT(dev)];
433 (*tp->t_linesw->l_close)(tp, flag);
434 ttyclose(tp);
435 iteoff(dev, 0);
436 #if 0
437 ttyfree(tp);
438 ite_tty[UNIT(dev)] = (struct tty *)0;
439 #endif
440 return(0);
444 iteread(dev_t dev, struct uio *uio, int flag)
446 struct tty *tp = ite_tty[UNIT(dev)];
448 return ((*tp->t_linesw->l_read)(tp, uio, flag));
452 itewrite(dev_t dev, struct uio *uio, int flag)
454 struct tty *tp = ite_tty[UNIT(dev)];
456 return ((*tp->t_linesw->l_write)(tp, uio, flag));
460 itepoll(dev_t dev, int events, struct lwp *l)
462 struct tty *tp = ite_tty[UNIT(dev)];
464 return ((*tp->t_linesw->l_poll)(tp, events, l));
467 struct tty *
468 itetty(dev_t dev)
471 return (ite_tty[UNIT(dev)]);
475 iteioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
477 struct iterepeat *irp;
478 struct tty *tp = ite_tty[UNIT(dev)];
479 int error;
481 error = (*tp->t_linesw->l_ioctl)(tp, cmd, addr, flag, l);
482 if (error != EPASSTHROUGH)
483 return (error);
485 error = ttioctl(tp, cmd, addr, flag, l);
486 if (error != EPASSTHROUGH)
487 return (error);
489 switch (cmd) {
490 case ITEIOCSKMAP:
491 if (addr == 0)
492 return(EFAULT);
493 memcpy(&kbdmap, addr, sizeof(struct kbdmap));
494 return(0);
496 case ITEIOCGKMAP:
497 if (addr == NULL)
498 return(EFAULT);
499 memcpy(addr, &kbdmap, sizeof(struct kbdmap));
500 return(0);
502 case ITEIOCGREPT:
503 irp = (struct iterepeat *)addr;
504 irp->start = start_repeat_timeo;
505 irp->next = next_repeat_timeo;
507 case ITEIOCSREPT:
508 irp = (struct iterepeat *)addr;
509 if (irp->start < ITEMINREPEAT && irp->next < ITEMINREPEAT)
510 return(EINVAL);
511 start_repeat_timeo = irp->start;
512 next_repeat_timeo = irp->next;
513 #if x68k
514 case ITELOADFONT:
515 if (addr) {
516 memcpy(kern_font, addr, 4096 /*sizeof(kernel_font)*/);
517 ite_set_glyph();
518 return 0;
519 } else
520 return EFAULT;
522 case ITETVCTRL:
523 if (addr && *(u_int8_t *)addr < 0x40) {
524 return mfp_send_usart(* (u_int8_t *)addr);
525 } else {
526 return EFAULT;
528 #endif
530 return (EPASSTHROUGH);
533 void
534 itestart(struct tty *tp)
536 struct clist *rbp;
537 struct ite_softc *ip;
538 u_char buf[ITEBURST];
539 int s, len;
541 ip = getitesp(tp->t_dev);
543 * (Potentially) lower priority. We only need to protect ourselves
544 * from keyboard interrupts since that is all that can affect the
545 * state of our tty (kernel printf doesn't go through this routine).
547 s = spltty();
548 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
549 goto out;
550 tp->t_state |= TS_BUSY;
551 rbp = &tp->t_outq;
552 len = q_to_b(rbp, buf, ITEBURST);
553 /*splx(s);*/
555 /* Here is a really good place to implement pre/jumpscroll() */
556 ite_putstr(buf, len, tp->t_dev);
558 /*s = spltty();*/
559 tp->t_state &= ~TS_BUSY;
560 /* we have characters remaining. */
561 if (ttypull(tp)) {
562 tp->t_state |= TS_TIMEOUT;
563 callout_schedule(&tp->t_rstrt_ch, 1);
565 out:
566 splx(s);
569 /* XXX called after changes made in underlying grf layer. */
570 /* I want to nuke this */
571 void
572 ite_reinit(dev_t dev)
574 struct ite_softc *ip;
575 int unit = UNIT(dev);
577 /* XXX check whether when call from grf.c */
578 if (unit < 0 || unit >= ite_cd.cd_ndevs ||
579 (ip = getitesp(unit)) == NULL)
580 return;
582 ip->flags &= ~ITE_INITED;
583 iteinit(dev);
586 void
587 ite_reset(struct ite_softc *ip)
589 int i;
591 ip->curx = 0;
592 ip->cury = 0;
593 ip->attribute = 0;
594 ip->save_curx = 0;
595 ip->save_cury = 0;
596 ip->save_attribute = 0;
597 ip->ap = ip->argbuf;
598 ip->emul_level = EMUL_VT300_8;
599 ip->eightbit_C1 = 0;
600 ip->top_margin = 0;
601 ip->bottom_margin = ip->rows - 1;
602 ip->inside_margins = 0; /* origin mode == absolute */
603 ip->linefeed_newline = 0;
604 ip->auto_wrap = 1;
605 ip->cursor_appmode = 0;
606 ip->keypad_appmode = 0;
607 ip->imode = 0;
608 ip->key_repeat = 1;
609 ip->G0 = CSET_ASCII;
610 ip->G1 = CSET_JIS1983;
611 ip->G2 = CSET_JISKANA;
612 ip->G3 = CSET_JIS1990;
613 ip->GL = &ip->G0;
614 ip->GR = &ip->G1;
615 ip->save_GL = 0;
616 ip->save_char = 0;
617 ip->fgcolor = 7;
618 ip->bgcolor = 0;
619 for (i = 0; i < ip->cols; i++)
620 ip->tabs[i] = ((i & 7) == 0);
621 /* XXX clear screen */
622 SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols);
623 attrclr(ip, 0, 0, ip->rows, ip->cols);
626 /* Used in console at startup only */
628 ite_cnfilter(u_char c)
630 static u_char mod = 0;
631 struct key key;
632 u_char code, up, mask;
633 int s;
635 up = c & 0x80 ? 1 : 0;
636 c &= 0x7f;
637 code = 0;
639 s = spltty();
641 mask = 0;
642 if (c >= KBD_LEFT_ALT && !(c >= 0x63 && c <= 0x6c)) { /* 0x63: F1, 0x6c:F10 */
643 switch (c) {
644 case KBD_LEFT_SHIFT:
645 mask = KBD_MOD_SHIFT;
646 break;
648 case KBD_LEFT_ALT:
649 mask = KBD_MOD_LALT;
650 break;
652 case KBD_RIGHT_ALT:
653 mask = KBD_MOD_RALT;
654 break;
656 case KBD_LEFT_META:
657 mask = KBD_MOD_LMETA;
658 break;
660 case KBD_RIGHT_META:
661 mask = KBD_MOD_RMETA;
662 break;
664 case KBD_CAPS_LOCK:
666 * capslock already behaves `right', don't need to
667 * keep track of the state in here.
669 mask = KBD_MOD_CAPS;
670 break;
672 case KBD_CTRL:
673 mask = KBD_MOD_CTRL;
674 break;
676 case KBD_RECONNECT:
677 /* ite got 0xff */
678 if (up)
679 kbd_setLED();
680 break;
682 if (mask & KBD_MOD_CAPS) {
683 if (!up) {
684 mod ^= KBD_MOD_CAPS;
685 kbdled ^= LED_CAPS_LOCK;
686 kbd_setLED();
688 } else if (up)
689 mod &= ~mask;
690 else mod |= mask;
691 splx(s);
692 return -1;
695 if (up) {
696 splx(s);
697 return -1;
700 /* translate modifiers */
701 if (mod & KBD_MOD_SHIFT) {
702 if (mod & KBD_MOD_ALT)
703 key = kbdmap.alt_shift_keys[c];
704 else
705 key = kbdmap.shift_keys[c];
706 } else if (mod & KBD_MOD_ALT)
707 key = kbdmap.alt_keys[c];
708 else {
709 key = kbdmap.keys[c];
710 /* if CAPS and key is CAPable (no pun intended) */
711 if ((mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS))
712 key = kbdmap.shift_keys[c];
714 code = key.code;
716 /* if string return */
717 if (key.mode & (KBD_MODE_STRING | KBD_MODE_KPAD)) {
718 splx(s);
719 return -1;
721 /* handle dead keys */
722 if (key.mode & KBD_MODE_DEAD) {
723 splx(s);
724 return -1;
726 if (mod & KBD_MOD_CTRL)
727 code &= 0x1f;
728 if (mod & KBD_MOD_META)
729 code |= 0x80;
731 /* do console mapping. */
732 code = code == '\r' ? '\n' : code;
734 splx(s);
735 return (code);
738 /* And now the old stuff. */
739 inline static void
740 itesendch(int ch)
742 (*kbd_tty->t_linesw->l_rint)(ch, kbd_tty);
746 void
747 ite_filter(u_char c)
749 static u_short mod = 0;
750 unsigned char code, *str;
751 u_short up, mask;
752 struct key key;
753 int s, i;
755 if (!kbd_ite || !(kbd_tty = ite_tty[device_unit(&kbd_ite->device)]))
756 return;
758 /* have to make sure we're at spltty in here */
759 s = spltty();
761 up = c & 0x80 ? 1 : 0;
762 c &= 0x7f;
763 code = 0;
765 mask = 0;
766 if (c >= KBD_LEFT_ALT &&
767 !(c >= 0x63 && c <= 0x6c)) { /* 0x63: F1, 0x6c:F10 */
768 switch (c) {
769 case KBD_LEFT_SHIFT:
770 mask = KBD_MOD_SHIFT;
771 break;
773 case KBD_LEFT_ALT:
774 mask = KBD_MOD_LALT;
775 break;
777 case KBD_RIGHT_ALT:
778 mask = KBD_MOD_RALT;
779 break;
781 case KBD_LEFT_META:
782 mask = KBD_MOD_LMETA;
783 break;
785 case KBD_RIGHT_META:
786 mask = KBD_MOD_RMETA;
787 break;
789 case KBD_CAPS_LOCK:
791 * capslock already behaves `right', don't need to keep
792 * track of the state in here.
794 mask = KBD_MOD_CAPS;
795 break;
797 case KBD_CTRL:
798 mask = KBD_MOD_CTRL;
799 break;
801 case KBD_OPT1:
802 mask = KBD_MOD_OPT1;
803 break;
805 case KBD_OPT2:
806 mask = KBD_MOD_OPT2;
807 break;
809 case KBD_RECONNECT:
810 if (up) { /* ite got 0xff */
811 kbd_setLED();
813 break;
816 if (mask & KBD_MOD_CAPS) {
817 if (!up) {
818 mod ^= KBD_MOD_CAPS;
819 kbdled ^= LED_CAPS_LOCK;
820 kbd_setLED();
822 } else if (up) {
823 mod &= ~mask;
824 } else mod |= mask;
827 * return even if it wasn't a modifier key, the other
828 * codes up here are either special (like reset warning),
829 * or not yet defined
831 splx(s);
832 return;
835 if (up) {
836 splx(s);
837 return;
841 * intercept LAlt-LMeta-F1 here to switch back to original ascii-keymap.
842 * this should probably be configurable..
844 if (mod == (KBD_MOD_LALT|KBD_MOD_LMETA) && c == 0x63) {
845 memcpy(&kbdmap, &ascii_kbdmap, sizeof(struct kbdmap));
846 splx(s);
847 return;
850 /* translate modifiers */
851 if (mod & KBD_MOD_SHIFT) {
852 if (mod & KBD_MOD_ALT)
853 key = kbdmap.alt_shift_keys[c];
854 else
855 key = kbdmap.shift_keys[c];
856 } else if (mod & KBD_MOD_ALT)
857 key = kbdmap.alt_keys[c];
858 else {
859 key = kbdmap.keys[c];
860 /* if CAPS and key is CAPable (no pun intended) */
861 if ((mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS))
862 key = kbdmap.shift_keys[c];
863 else if ((mod & KBD_MOD_OPT2) && (key.mode & KBD_MODE_KPAD))
864 key = kbdmap.shift_keys[c];
866 code = key.code;
868 /* handle dead keys */
869 if (key.mode & KBD_MODE_DEAD) {
870 splx(s);
871 return;
873 /* if not string, apply META and CTRL modifiers */
874 if (! (key.mode & KBD_MODE_STRING)
875 && (!(key.mode & KBD_MODE_KPAD) ||
876 (kbd_ite && !kbd_ite->keypad_appmode))) {
877 if ((mod & KBD_MOD_CTRL) &&
878 (code == ' ' || (code >= '@' && code <= 'z')))
879 code &= 0x1f;
880 if (mod & KBD_MOD_META)
881 code |= 0x80;
882 } else if ((key.mode & KBD_MODE_KPAD) &&
883 (kbd_ite && kbd_ite->keypad_appmode)) {
884 static const char * const in = "0123456789-+.\r()/*";
885 static const char * const out = "pqrstuvwxymlnMPQRS";
886 char *cp = strchr(in, code);
889 * keypad-appmode sends SS3 followed by the above
890 * translated character
892 (*kbd_tty->t_linesw->l_rint)(27, kbd_tty);
893 (*kbd_tty->t_linesw->l_rint)('O', kbd_tty);
894 (*kbd_tty->t_linesw->l_rint)(out[cp - in], kbd_tty);
895 splx(s);
896 return;
897 } else {
898 /* *NO* I don't like this.... */
899 static u_char app_cursor[] =
901 3, 27, 'O', 'A',
902 3, 27, 'O', 'B',
903 3, 27, 'O', 'C',
904 3, 27, 'O', 'D'};
906 str = kbdmap.strings + code;
908 * if this is a cursor key, AND it has the default
909 * keymap setting, AND we're in app-cursor mode, switch
910 * to the above table. This is *nasty* !
912 if (c >= 0x3b && c <= 0x3e && kbd_ite->cursor_appmode
913 && !memcmp(str, "\x03\x1b[", 3) &&
914 strchr("ABCD", str[3]))
915 str = app_cursor + 4 * (str[3] - 'A');
918 * using a length-byte instead of 0-termination allows
919 * to embed \0 into strings, although this is not used
920 * in the default keymap
922 for (i = *str++; i; i--)
923 (*kbd_tty->t_linesw->l_rint)(*str++, kbd_tty);
924 splx(s);
925 return;
927 (*kbd_tty->t_linesw->l_rint)(code, kbd_tty);
929 splx(s);
930 return;
933 /* helper functions, makes the code below more readable */
934 inline static void
935 ite_sendstr(struct ite_softc *ip, const char *str)
937 while (*str)
938 itesendch(*str++);
941 inline static void
942 alignment_display(struct ite_softc *ip)
944 int i, j;
946 for (j = 0; j < ip->rows; j++)
947 for (i = 0; i < ip->cols; i++)
948 SUBR_PUTC(ip, 'E', j, i, ATTR_NOR);
949 attrclr(ip, 0, 0, ip->rows, ip->cols);
952 inline static void
953 snap_cury(struct ite_softc *ip)
955 if (ip->inside_margins) {
956 if (ip->cury < ip->top_margin)
957 ip->cury = ip->top_margin;
958 if (ip->cury > ip->bottom_margin)
959 ip->cury = ip->bottom_margin;
963 inline static void
964 ite_dnchar(struct ite_softc *ip, int n)
966 n = min(n, ip->cols - ip->curx);
967 if (n < ip->cols - ip->curx) {
968 SUBR_SCROLL(ip, ip->cury, ip->curx + n, n, SCROLL_LEFT);
969 attrmov(ip, ip->cury, ip->curx + n, ip->cury, ip->curx,
970 1, ip->cols - ip->curx - n);
971 attrclr(ip, ip->cury, ip->cols - n, 1, n);
973 while (n-- > 0)
974 SUBR_PUTC(ip, ' ', ip->cury, ip->cols - n - 1, ATTR_NOR);
977 static void
978 ite_inchar(struct ite_softc *ip, int n)
980 int c = ip->save_char;
981 ip->save_char = 0;
982 n = min(n, ip->cols - ip->curx);
983 if (n < ip->cols - ip->curx) {
984 SUBR_SCROLL(ip, ip->cury, ip->curx, n, SCROLL_RIGHT);
985 attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + n,
986 1, ip->cols - ip->curx - n);
987 attrclr(ip, ip->cury, ip->curx, 1, n);
989 while (n--)
990 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR);
991 ip->save_char = c;
994 inline static void
995 ite_clrtoeol(struct ite_softc *ip)
997 int y = ip->cury, x = ip->curx;
998 if (ip->cols - x > 0) {
999 SUBR_CLEAR(ip, y, x, 1, ip->cols - x);
1000 attrclr(ip, y, x, 1, ip->cols - x);
1004 inline static void
1005 ite_clrtobol(struct ite_softc *ip)
1007 int y = ip->cury, x = min(ip->curx + 1, ip->cols);
1008 SUBR_CLEAR(ip, y, 0, 1, x);
1009 attrclr(ip, y, 0, 1, x);
1012 inline static void
1013 ite_clrline(struct ite_softc *ip)
1015 int y = ip->cury;
1016 SUBR_CLEAR(ip, y, 0, 1, ip->cols);
1017 attrclr(ip, y, 0, 1, ip->cols);
1020 inline static void
1021 ite_clrtoeos(struct ite_softc *ip)
1023 ite_clrtoeol(ip);
1024 if (ip->cury < ip->rows - 1) {
1025 SUBR_CLEAR(ip, ip->cury + 1, 0, ip->rows - 1 - ip->cury, ip->cols);
1026 attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols);
1030 inline static void
1031 ite_clrtobos(struct ite_softc *ip)
1033 ite_clrtobol(ip);
1034 if (ip->cury > 0) {
1035 SUBR_CLEAR(ip, 0, 0, ip->cury, ip->cols);
1036 attrclr(ip, 0, 0, ip->cury, ip->cols);
1040 inline static void
1041 ite_clrscreen(struct ite_softc *ip)
1043 SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols);
1044 attrclr(ip, 0, 0, ip->rows, ip->cols);
1049 inline static void
1050 ite_dnline(struct ite_softc *ip, int n)
1053 * interesting.. if the cursor is outside the scrolling
1054 * region, this command is simply ignored..
1056 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin)
1057 return;
1059 n = min(n, ip->bottom_margin + 1 - ip->cury);
1060 if (n <= ip->bottom_margin - ip->cury) {
1061 SUBR_SCROLL(ip, ip->cury + n, 0, n, SCROLL_UP);
1062 attrmov(ip, ip->cury + n, 0, ip->cury, 0,
1063 ip->bottom_margin + 1 - ip->cury - n, ip->cols);
1065 SUBR_CLEAR(ip, ip->bottom_margin - n + 1, 0, n, ip->cols);
1066 attrclr(ip, ip->bottom_margin - n + 1, 0, n, ip->cols);
1069 inline static void
1070 ite_inline(struct ite_softc *ip, int n)
1073 * interesting.. if the cursor is outside the scrolling
1074 * region, this command is simply ignored..
1076 if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin)
1077 return;
1079 if (n <= 0)
1080 n = 1;
1081 else n = min(n, ip->bottom_margin + 1 - ip->cury);
1082 if (n <= ip->bottom_margin - ip->cury) {
1083 SUBR_SCROLL(ip, ip->cury, 0, n, SCROLL_DOWN);
1084 attrmov(ip, ip->cury, 0, ip->cury + n, 0,
1085 ip->bottom_margin + 1 - ip->cury - n, ip->cols);
1087 SUBR_CLEAR(ip, ip->cury, 0, n, ip->cols);
1088 attrclr(ip, ip->cury, 0, n, ip->cols);
1089 ip->curx = 0;
1092 inline static void
1093 ite_index(struct ite_softc *ip)
1095 ++ip->cury;
1096 if ((ip->cury == ip->bottom_margin+1) || (ip->cury == ip->rows)) {
1097 ip->cury--;
1098 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP);
1099 ite_clrline(ip);
1101 /*clr_attr(ip, ATTR_INV);*/
1104 inline static void
1105 ite_lf(struct ite_softc *ip)
1107 ++ip->cury;
1108 if (ip->cury > ip->bottom_margin) {
1109 ip->cury--;
1110 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP);
1111 ite_clrline(ip);
1113 /* SUBR_CURSOR(ip, MOVE_CURSOR);*/
1114 /*clr_attr(ip, ATTR_INV);*/
1115 /* reset character set ... thanks for mohta. */
1116 ip->G0 = CSET_ASCII;
1117 ip->G1 = CSET_JIS1983;
1118 ip->G2 = CSET_JISKANA;
1119 ip->G3 = CSET_JIS1990;
1120 ip->GL = &ip->G0;
1121 ip->GR = &ip->G1;
1122 ip->save_GL = 0;
1123 ip->save_char = 0;
1126 inline static void
1127 ite_crlf(struct ite_softc *ip)
1129 ip->curx = 0;
1130 ite_lf (ip);
1133 inline static void
1134 ite_cr(struct ite_softc *ip)
1136 if (ip->curx) {
1137 ip->curx = 0;
1141 inline static void
1142 ite_rlf(struct ite_softc *ip)
1144 ip->cury--;
1145 if ((ip->cury < 0) || (ip->cury == ip->top_margin - 1)) {
1146 ip->cury++;
1147 SUBR_SCROLL(ip, ip->top_margin, 0, 1, SCROLL_DOWN);
1148 ite_clrline(ip);
1150 clr_attr(ip, ATTR_INV);
1153 inline static int
1154 atoi(const char *cp)
1156 int n;
1158 for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++)
1159 n = n * 10 + *cp - '0';
1160 return n;
1163 inline static int
1164 ite_argnum(struct ite_softc *ip)
1166 char ch;
1167 int n;
1169 /* convert argument string into number */
1170 if (ip->ap == ip->argbuf)
1171 return 1;
1172 ch = *ip->ap;
1173 *ip->ap = 0;
1174 n = atoi(ip->argbuf);
1175 *ip->ap = ch;
1177 return n;
1180 inline static int
1181 ite_zargnum(struct ite_softc *ip)
1183 char ch;
1184 int n;
1186 /* convert argument string into number */
1187 if (ip->ap == ip->argbuf)
1188 return 0;
1189 ch = *ip->ap;
1190 *ip->ap = 0; /* terminate string */
1191 n = atoi(ip->argbuf);
1192 *ip->ap = ch;
1194 return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */
1197 void
1198 ite_putstr(const u_char *s, int len, dev_t dev)
1200 struct ite_softc *ip;
1201 int i;
1203 ip = getitesp(dev);
1205 /* XXX avoid problems */
1206 if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE)
1207 return;
1209 SUBR_CURSOR(ip, START_CURSOROPT);
1210 for (i = 0; i < len; i++)
1211 if (s[i])
1212 iteputchar(s[i], ip);
1213 SUBR_CURSOR(ip, END_CURSOROPT);
1216 void
1217 iteputchar(int c, struct ite_softc *ip)
1219 int n, x, y;
1220 char *cp;
1222 if (c >= 0x20 && ip->escape) {
1223 switch (ip->escape) {
1225 case ESC:
1226 switch (c) {
1227 /* first 7bit equivalents for the 8bit control characters */
1229 case 'D':
1230 c = IND;
1231 ip->escape = 0;
1232 break; /* and fall into the next switch below (same for all `break') */
1234 case 'E':
1235 /* next line */
1236 c = NEL;
1237 ip->escape = 0;
1238 break;
1240 case 'H':
1241 /* set TAB at current col */
1242 c = HTS;
1243 ip->escape = 0;
1244 break;
1246 case 'M':
1247 /* reverse index */
1248 c = RI;
1249 ip->escape = 0;
1250 break;
1252 case 'N':
1253 /* single shift G2 */
1254 c = SS2;
1255 ip->escape = 0;
1256 break;
1258 case 'O':
1259 /* single shift G3 */
1260 c = SS3;
1261 ip->escape = 0;
1262 break;
1264 case 'P':
1265 /* DCS detected */
1266 c = DCS;
1267 ip->escape = 0;
1268 break;
1270 case '[':
1271 c = CSI;
1272 ip->escape = 0;
1273 break;
1275 case '\\':
1276 /* String Terminator */
1277 c = ST;
1278 ip->escape = 0;
1279 break;
1281 case ']':
1282 c = OSC;
1283 ip->escape = 0;
1284 break;
1286 case '^':
1287 c = PM;
1288 ip->escape = 0;
1289 break;
1291 case '_':
1292 c = APC;
1293 ip->escape = 0;
1294 break;
1297 /* introduces 7/8bit control */
1298 case ' ':
1299 /* can be followed by either F or G */
1300 ip->escape = ' ';
1301 break;
1304 /* a lot of character set selections, not yet used...
1305 94-character sets: */
1306 case '(': /* G0 */
1307 case ')': /* G1 */
1308 ip->escape = c;
1309 return;
1311 case '*': /* G2 */
1312 case '+': /* G3 */
1313 case 'B': /* ASCII */
1314 case 'A': /* ISO latin 1 */
1315 case '<': /* user preferred suplemental */
1316 case '0': /* dec special graphics */
1318 /* 96-character sets: */
1319 case '-': /* G1 */
1320 case '.': /* G2 */
1321 case '/': /* G3 */
1323 /* national character sets: */
1324 case '4': /* dutch */
1325 case '5':
1326 case 'C': /* finnish */
1327 case 'R': /* french */
1328 case 'Q': /* french canadian */
1329 case 'K': /* german */
1330 case 'Y': /* italian */
1331 case '6': /* norwegian/danish */
1332 /* note: %5 and %6 are not supported (two chars..) */
1334 ip->escape = 0;
1335 /* just ignore for now */
1336 return;
1338 /* 94-multibyte character sets designate */
1339 case '$':
1340 ip->escape = '$';
1341 return;
1343 /* locking shift modes */
1344 case '`':
1345 ip->GR = &ip->G1;
1346 ip->escape = 0;
1347 return;
1349 case 'n':
1350 ip->GL = &ip->G2;
1351 ip->escape = 0;
1352 return;
1354 case '}':
1355 ip->GR = &ip->G2;
1356 ip->escape = 0;
1357 return;
1359 case 'o':
1360 ip->GL = &ip->G3;
1361 ip->escape = 0;
1362 return;
1364 case '|':
1365 ip->GR = &ip->G3;
1366 ip->escape = 0;
1367 return;
1369 case '~':
1370 ip->GR = &ip->G1;
1371 ip->escape = 0;
1372 return;
1374 /* font width/height control */
1375 case '#':
1376 ip->escape = '#';
1377 return;
1379 case 'c':
1380 /* hard terminal reset .. */
1381 ite_reset(ip);
1382 SUBR_CURSOR(ip, MOVE_CURSOR);
1383 ip->escape = 0;
1384 return;
1387 case '7':
1388 /* save cursor */
1389 ip->save_curx = ip->curx;
1390 ip->save_cury = ip->cury;
1391 ip->save_attribute = ip->attribute;
1392 ip->sc_om = ip->inside_margins;
1393 ip->sc_G0 = ip->G0;
1394 ip->sc_G1 = ip->G1;
1395 ip->sc_G2 = ip->G2;
1396 ip->sc_G3 = ip->G3;
1397 ip->sc_GL = ip->GL;
1398 ip->sc_GR = ip->GR;
1399 ip->escape = 0;
1400 return;
1402 case '8':
1403 /* restore cursor */
1404 ip->curx = ip->save_curx;
1405 ip->cury = ip->save_cury;
1406 ip->attribute = ip->save_attribute;
1407 ip->inside_margins = ip->sc_om;
1408 ip->G0 = ip->sc_G0;
1409 ip->G1 = ip->sc_G1;
1410 ip->G2 = ip->sc_G2;
1411 ip->G3 = ip->sc_G3;
1412 ip->GL = ip->sc_GL;
1413 ip->GR = ip->sc_GR;
1414 SUBR_CURSOR(ip, MOVE_CURSOR);
1415 ip->escape = 0;
1416 return;
1418 case '=':
1419 /* keypad application mode */
1420 ip->keypad_appmode = 1;
1421 ip->escape = 0;
1422 return;
1424 case '>':
1425 /* keypad numeric mode */
1426 ip->keypad_appmode = 0;
1427 ip->escape = 0;
1428 return;
1430 case 'Z': /* request ID */
1431 if (ip->emul_level == EMUL_VT100)
1432 ite_sendstr(ip, "\033[61;0c"); /* XXX not clean */
1433 else
1434 ite_sendstr(ip, "\033[63;0c"); /* XXX not clean */
1435 ip->escape = 0;
1436 return;
1438 /* default catch all for not recognized ESC sequences */
1439 default:
1440 ip->escape = 0;
1441 return;
1443 break;
1446 case '(': /* designate G0 */
1447 switch (c) {
1448 case 'B': /* USASCII */
1449 ip->G0 = CSET_ASCII;
1450 ip->escape = 0;
1451 return;
1452 case 'I':
1453 ip->G0 = CSET_JISKANA;
1454 ip->escape = 0;
1455 return;
1456 case 'J':
1457 ip->G0 = CSET_JISROMA;
1458 ip->escape = 0;
1459 return;
1460 case 'A': /* British or ISO-Latin-1 */
1461 case 'H': /* Swedish */
1462 case 'K': /* German */
1463 case 'R': /* French */
1464 case 'Y': /* Italian */
1465 case 'Z': /* Spanish */
1466 default:
1467 /* not supported */
1468 ip->escape = 0;
1469 return;
1472 case ')': /* designate G1 */
1473 ip->escape = 0;
1474 return;
1476 case '$': /* 94-multibyte character set */
1477 switch (c) {
1478 case '@':
1479 ip->G0 = CSET_JIS1978;
1480 ip->escape = 0;
1481 return;
1482 case 'B':
1483 ip->G0 = CSET_JIS1983;
1484 ip->escape = 0;
1485 return;
1486 case 'D':
1487 ip->G0 = CSET_JIS1990;
1488 ip->escape = 0;
1489 return;
1490 default:
1491 /* not supported */
1492 ip->escape = 0;
1493 return;
1496 case ' ':
1497 switch (c) {
1498 case 'F':
1499 ip->eightbit_C1 = 0;
1500 ip->escape = 0;
1501 return;
1503 case 'G':
1504 ip->eightbit_C1 = 1;
1505 ip->escape = 0;
1506 return;
1508 default:
1509 /* not supported */
1510 ip->escape = 0;
1511 return;
1513 break;
1515 case '#':
1516 switch (c) {
1517 case '5':
1518 /* single height, single width */
1519 ip->escape = 0;
1520 return;
1522 case '6':
1523 /* double width, single height */
1524 ip->escape = 0;
1525 return;
1527 case '3':
1528 /* top half */
1529 ip->escape = 0;
1530 return;
1532 case '4':
1533 /* bottom half */
1534 ip->escape = 0;
1535 return;
1537 case '8':
1538 /* screen alignment pattern... */
1539 alignment_display(ip);
1540 ip->escape = 0;
1541 return;
1543 default:
1544 ip->escape = 0;
1545 return;
1547 break;
1551 case CSI:
1552 /* the biggie... */
1553 switch (c) {
1554 case '0': case '1': case '2': case '3': case '4':
1555 case '5': case '6': case '7': case '8': case '9':
1556 case ';': case '\"': case '$': case '>':
1557 if (ip->ap < ip->argbuf + MAX_ARGSIZE)
1558 *ip->ap++ = c;
1559 return;
1561 case 'p':
1562 *ip->ap = 0;
1563 if (!strncmp(ip->argbuf, "61\"", 3))
1564 ip->emul_level = EMUL_VT100;
1565 else if (!strncmp(ip->argbuf, "63;1\"", 5)
1566 || !strncmp(ip->argbuf, "62;1\"", 5))
1567 ip->emul_level = EMUL_VT300_7;
1568 else
1569 ip->emul_level = EMUL_VT300_8;
1570 ip->escape = 0;
1571 return;
1574 case '?':
1575 *ip->ap = 0;
1576 ip->escape = '?';
1577 ip->ap = ip->argbuf;
1578 return;
1581 case 'c':
1582 /* device attributes */
1583 *ip->ap = 0;
1584 if (ip->argbuf[0] == '>') {
1585 ite_sendstr(ip, "\033[>24;0;0;0c");
1586 } else
1587 switch (ite_zargnum(ip)) {
1588 case 0:
1589 /* primary DA request, send primary DA response */
1590 if (ip->emul_level == EMUL_VT100)
1591 ite_sendstr(ip, "\033[?1;1c");
1592 else
1593 ite_sendstr(ip, "\033[63;0c");
1594 break;
1596 ip->escape = 0;
1597 return;
1599 case 'n':
1600 switch (ite_zargnum(ip)) {
1601 case 5:
1602 ite_sendstr(ip, "\033[0n"); /* no malfunction */
1603 break;
1604 case 6:
1605 /* cursor position report */
1606 sprintf(ip->argbuf, "\033[%d;%dR",
1607 ip->cury + 1, ip->curx + 1);
1608 ite_sendstr(ip, ip->argbuf);
1609 break;
1611 ip->escape = 0;
1612 return;
1615 case 'x':
1616 switch (ite_zargnum(ip)) {
1617 case 0:
1618 /* Fake some terminal parameters. */
1619 ite_sendstr(ip, "\033[2;1;1;112;112;1;0x");
1620 break;
1621 case 1:
1622 ite_sendstr(ip, "\033[3;1;1;112;112;1;0x");
1623 break;
1625 ip->escape = 0;
1626 return;
1629 case 'g':
1630 /* clear tabs */
1631 switch (ite_zargnum(ip)) {
1632 case 0:
1633 if (ip->curx < ip->cols)
1634 ip->tabs[ip->curx] = 0;
1635 break;
1636 case 3:
1637 for (n = 0; n < ip->cols; n++)
1638 ip->tabs[n] = 0;
1639 break;
1641 default:
1642 /* ignore */
1643 break;
1645 ip->escape = 0;
1646 return;
1649 case 'h': /* set mode */
1650 case 'l': /* reset mode */
1651 n = ite_zargnum(ip);
1652 switch (n) {
1653 case 4:
1654 ip->imode = (c == 'h'); /* insert/replace mode */
1655 break;
1656 case 20:
1657 ip->linefeed_newline = (c == 'h');
1658 break;
1660 ip->escape = 0;
1661 return;
1664 case 'M':
1665 /* delete line */
1666 ite_dnline(ip, ite_argnum(ip));
1667 ip->escape = 0;
1668 return;
1671 case 'L':
1672 /* insert line */
1673 ite_inline(ip, ite_argnum(ip));
1674 ip->escape = 0;
1675 return;
1678 case 'P':
1679 /* delete char */
1680 ite_dnchar(ip, ite_argnum(ip));
1681 ip->escape = 0;
1682 return;
1685 case '@':
1686 /* insert char(s) */
1687 ite_inchar(ip, ite_argnum(ip));
1688 ip->escape = 0;
1689 return;
1691 case '!':
1692 /* soft terminal reset */
1693 ip->escape = 0; /* XXX */
1694 return;
1696 case 'G':
1697 /* this one was *not* in my vt320 manual but in
1698 a vt320 termcap entry.. who is right?
1699 It's supposed to set the horizontal cursor position. */
1700 *ip->ap = 0;
1701 x = atoi(ip->argbuf);
1702 if (x)
1703 x--;
1704 ip->curx = min(x, ip->cols - 1);
1705 ip->escape = 0;
1706 SUBR_CURSOR(ip, MOVE_CURSOR);
1707 clr_attr(ip, ATTR_INV);
1708 return;
1711 case 'd':
1712 /* same thing here, this one's for setting the absolute
1713 vertical cursor position. Not documented... */
1714 *ip->ap = 0;
1715 y = atoi(ip->argbuf);
1716 if (y)
1717 y--;
1718 if (ip->inside_margins)
1719 y += ip->top_margin;
1720 ip->cury = min(y, ip->rows - 1);
1721 ip->escape = 0;
1722 snap_cury(ip);
1723 SUBR_CURSOR(ip, MOVE_CURSOR);
1724 clr_attr(ip, ATTR_INV);
1725 return;
1728 case 'H':
1729 case 'f':
1730 *ip->ap = 0;
1731 y = atoi(ip->argbuf);
1732 x = 0;
1733 cp = strchr(ip->argbuf, ';');
1734 if (cp)
1735 x = atoi(cp + 1);
1736 if (x)
1737 x--;
1738 if (y)
1739 y--;
1740 if (ip->inside_margins)
1741 y += ip->top_margin;
1742 ip->cury = min(y, ip->rows - 1);
1743 ip->curx = min(x, ip->cols - 1);
1744 ip->escape = 0;
1745 snap_cury(ip);
1746 SUBR_CURSOR(ip, MOVE_CURSOR);
1747 /*clr_attr(ip, ATTR_INV);*/
1748 return;
1750 case 'A':
1751 /* cursor up */
1752 n = ite_argnum(ip);
1753 n = ip->cury - (n ? n : 1);
1754 if (n < 0)
1755 n = 0;
1756 if (ip->inside_margins)
1757 n = max(ip->top_margin, n);
1758 else if (n == ip->top_margin - 1)
1759 /* allow scrolling outside region, but don't scroll out
1760 of active region without explicit CUP */
1761 n = ip->top_margin;
1762 ip->cury = n;
1763 ip->escape = 0;
1764 SUBR_CURSOR(ip, MOVE_CURSOR);
1765 clr_attr(ip, ATTR_INV);
1766 return;
1768 case 'B':
1769 /* cursor down */
1770 n = ite_argnum(ip);
1771 n = ip->cury + (n ? n : 1);
1772 n = min(ip->rows - 1, n);
1773 #if 0
1774 if (ip->inside_margins)
1775 #endif
1776 n = min(ip->bottom_margin, n);
1777 #if 0
1778 else if (n == ip->bottom_margin + 1)
1779 /* allow scrolling outside region, but don't scroll out
1780 of active region without explicit CUP */
1781 n = ip->bottom_margin;
1782 #endif
1783 ip->cury = n;
1784 ip->escape = 0;
1785 SUBR_CURSOR(ip, MOVE_CURSOR);
1786 clr_attr(ip, ATTR_INV);
1787 return;
1789 case 'C':
1790 /* cursor forward */
1791 n = ite_argnum(ip);
1792 n = n ? n : 1;
1793 ip->curx = min(ip->curx + n, ip->cols - 1);
1794 ip->escape = 0;
1795 SUBR_CURSOR(ip, MOVE_CURSOR);
1796 clr_attr(ip, ATTR_INV);
1797 return;
1799 case 'D':
1800 /* cursor backward */
1801 n = ite_argnum(ip);
1802 n = n ? n : 1;
1803 n = ip->curx - n;
1804 ip->curx = n >= 0 ? n : 0;
1805 ip->escape = 0;
1806 SUBR_CURSOR(ip, MOVE_CURSOR);
1807 clr_attr(ip, ATTR_INV);
1808 return;
1811 case 'J':
1812 /* erase screen */
1813 *ip->ap = 0;
1814 n = ite_zargnum(ip);
1815 if (n == 0)
1816 ite_clrtoeos(ip);
1817 else if (n == 1)
1818 ite_clrtobos(ip);
1819 else if (n == 2)
1820 ite_clrscreen(ip);
1821 ip->escape = 0;
1822 return;
1825 case 'K':
1826 /* erase line */
1827 n = ite_zargnum(ip);
1828 if (n == 0)
1829 ite_clrtoeol(ip);
1830 else if (n == 1)
1831 ite_clrtobol(ip);
1832 else if (n == 2)
1833 ite_clrline(ip);
1834 ip->escape = 0;
1835 return;
1837 case 'S':
1838 /* scroll up */
1839 n = ite_zargnum(ip);
1840 if (n <= 0)
1841 n = 1;
1842 else if (n > ip->rows-1)
1843 n = ip->rows-1;
1844 SUBR_SCROLL(ip, ip->rows-1, 0, n, SCROLL_UP);
1845 ip->escape = 0;
1846 return;
1848 case 'T':
1849 /* scroll down */
1850 n = ite_zargnum(ip);
1851 if (n <= 0)
1852 n = 1;
1853 else if (n > ip->rows-1)
1854 n = ip->rows-1;
1855 SUBR_SCROLL(ip, 0, 0, n, SCROLL_DOWN);
1856 ip->escape = 0;
1857 return;
1859 case 'X':
1860 /* erase character */
1861 n = ite_argnum(ip) - 1;
1862 n = min(n, ip->cols - 1 - ip->curx);
1863 for (; n >= 0; n--) {
1864 attrclr(ip, ip->cury, ip->curx + n, 1, 1);
1865 SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR);
1867 ip->escape = 0;
1868 return;
1871 case '}': case '`':
1872 /* status line control */
1873 ip->escape = 0;
1874 return;
1876 case 'r':
1877 /* set scrolling region */
1878 ip->escape = 0;
1879 *ip->ap = 0;
1880 x = atoi(ip->argbuf);
1881 x = x ? x : 1;
1882 y = ip->rows;
1883 cp = strchr(ip->argbuf, ';');
1884 if (cp) {
1885 y = atoi(cp + 1);
1886 y = y ? y : ip->rows;
1888 if (y <= x)
1889 return;
1890 x--;
1891 y--;
1892 ip->top_margin = min(x, ip->rows - 2);
1893 ip->bottom_margin = min(y, ip->rows - 1);
1894 if (ip->inside_margins) {
1895 ip->cury = ip->top_margin;
1896 } else
1897 ip->cury = 0;
1898 ip->curx = 0;
1899 return;
1902 case 'm':
1903 /* big attribute setter/resetter */
1905 char *c_p;
1906 *ip->ap = 0;
1907 /* kludge to make CSIm work (== CSI0m) */
1908 if (ip->ap == ip->argbuf)
1909 ip->ap++;
1910 for (c_p = ip->argbuf; c_p < ip->ap; ) {
1911 switch (*c_p) {
1912 case 0:
1913 case '0':
1914 clr_attr(ip, ATTR_ALL);
1915 ip->fgcolor = 7;
1916 ip->bgcolor = 0;
1917 c_p++;
1918 break;
1920 case '1':
1921 set_attr(ip, ATTR_BOLD);
1922 c_p++;
1923 break;
1925 case '2':
1926 switch (c_p[1]) {
1927 case '2':
1928 clr_attr(ip, ATTR_BOLD);
1929 c_p += 2;
1930 break;
1932 case '4':
1933 clr_attr(ip, ATTR_UL);
1934 c_p += 2;
1935 break;
1937 case '5':
1938 clr_attr(ip, ATTR_BLINK);
1939 c_p += 2;
1940 break;
1942 case '7':
1943 clr_attr(ip, ATTR_INV);
1944 c_p += 2;
1945 break;
1947 default:
1948 c_p++;
1949 break;
1951 break;
1953 case '3':
1954 switch (c_p[1]) {
1955 case '0': case '1': case '2': case '3':
1956 case '4': case '5': case '6': case '7':
1957 /* foreground colors */
1958 ip->fgcolor = c_p[1] - '0';
1959 c_p += 2;
1960 break;
1961 default:
1962 c_p++;
1963 break;
1965 break;
1967 case '4':
1968 switch (c_p[1]) {
1969 case '0': case '1': case '2': case '3':
1970 case '4': case '5': case '6': case '7':
1971 /* background colors */
1972 ip->bgcolor = c_p[1] - '0';
1973 c_p += 2;
1974 break;
1975 default:
1976 set_attr(ip, ATTR_UL);
1977 c_p++;
1978 break;
1980 break;
1982 case '5':
1983 set_attr(ip, ATTR_BLINK);
1984 c_p++;
1985 break;
1987 case '7':
1988 set_attr(ip, ATTR_INV);
1989 c_p++;
1990 break;
1992 default:
1993 c_p++;
1994 break;
1999 ip->escape = 0;
2000 return;
2003 case 'u':
2004 /* DECRQTSR */
2005 ite_sendstr(ip, "\033P\033\\");
2006 ip->escape = 0;
2007 return;
2009 default:
2010 ip->escape = 0;
2011 return;
2013 break;
2017 case '?': /* CSI ? */
2018 switch (c) {
2019 case '0': case '1': case '2': case '3': case '4':
2020 case '5': case '6': case '7': case '8': case '9':
2021 case ';': case '\"': case '$':
2022 /* Don't fill the last character; it's needed. */
2023 /* XXX yeah, where ?? */
2024 if (ip->ap < ip->argbuf + MAX_ARGSIZE - 1)
2025 *ip->ap++ = c;
2026 return;
2029 case 'n':
2030 /* Terminal Reports */
2031 *ip->ap = 0;
2032 if (ip->ap == &ip->argbuf[2]) {
2033 if (!strncmp(ip->argbuf, "15", 2))
2034 /* printer status: no printer */
2035 ite_sendstr(ip, "\033[13n");
2037 else if (!strncmp(ip->argbuf, "25", 2))
2038 /* udk status */
2039 ite_sendstr(ip, "\033[20n");
2041 else if (!strncmp(ip->argbuf, "26", 2))
2042 /* keyboard dialect: US */
2043 ite_sendstr(ip, "\033[27;1n");
2045 ip->escape = 0;
2046 return;
2049 case 'h': /* set dec private modes */
2050 case 'l': /* reset dec private modes */
2051 n = ite_zargnum(ip);
2052 switch (n) {
2053 case 1:
2054 /* CKM - cursor key mode */
2055 ip->cursor_appmode = (c == 'h');
2056 break;
2058 case 3:
2059 /* 132/80 columns (132 == 'h') */
2060 break;
2062 case 4: /* smooth scroll */
2063 break;
2065 case 5:
2066 /* light background (=='h') /dark background(=='l') */
2067 break;
2069 case 6: /* origin mode */
2070 ip->inside_margins = (c == 'h');
2071 #if 0
2072 ip->curx = 0;
2073 ip->cury = ip->inside_margins ? ip->top_margin : 0;
2074 SUBR_CURSOR(ip, MOVE_CURSOR);
2075 #endif
2076 break;
2078 case 7: /* auto wraparound */
2079 ip->auto_wrap = (c == 'h');
2080 break;
2082 case 8: /* keyboard repeat */
2083 ip->key_repeat = (c == 'h');
2084 break;
2086 case 20: /* newline mode */
2087 ip->linefeed_newline = (c == 'h');
2088 break;
2090 case 25: /* cursor on/off */
2091 SUBR_CURSOR(ip, (c == 'h') ? DRAW_CURSOR : ERASE_CURSOR);
2092 break;
2094 ip->escape = 0;
2095 return;
2097 case 'K':
2098 /* selective erase in line */
2099 case 'J':
2100 /* selective erase in display */
2102 default:
2103 ip->escape = 0;
2104 return;
2106 break;
2109 default:
2110 ip->escape = 0;
2111 return;
2115 switch (c) {
2116 case 0x00: /* NUL */
2117 case 0x01: /* SOH */
2118 case 0x02: /* STX */
2119 case 0x03: /* ETX */
2120 case 0x04: /* EOT */
2121 case 0x05: /* ENQ */
2122 case 0x06: /* ACK */
2123 break;
2125 case BEL:
2126 #if NBELL > 0
2127 if (kbd_ite && ite_tty[device_unit(&kbd_ite->device)])
2128 opm_bell();
2129 #endif
2130 break;
2132 case BS:
2133 if (--ip->curx < 0)
2134 ip->curx = 0;
2135 else
2136 SUBR_CURSOR(ip, MOVE_CURSOR);
2137 break;
2139 case HT:
2140 for (n = ip->curx + 1; n < ip->cols; n++) {
2141 if (ip->tabs[n]) {
2142 ip->curx = n;
2143 SUBR_CURSOR(ip, MOVE_CURSOR);
2144 break;
2147 break;
2149 case VT: /* VT is treated like LF */
2150 case FF: /* so is FF */
2151 case LF:
2152 /* cr->crlf distinction is done here, on output,
2153 not on input! */
2154 if (ip->linefeed_newline)
2155 ite_crlf(ip);
2156 else
2157 ite_lf(ip);
2158 break;
2160 case CR:
2161 ite_cr(ip);
2162 break;
2165 case SO:
2166 ip->GL = &ip->G1;
2167 break;
2169 case SI:
2170 ip->GL = &ip->G0;
2171 break;
2173 case 0x10: /* DLE */
2174 case 0x11: /* DC1/XON */
2175 case 0x12: /* DC2 */
2176 case 0x13: /* DC3/XOFF */
2177 case 0x14: /* DC4 */
2178 case 0x15: /* NAK */
2179 case 0x16: /* SYN */
2180 case 0x17: /* ETB */
2181 break;
2183 case CAN:
2184 ip->escape = 0; /* cancel any escape sequence in progress */
2185 break;
2187 case 0x19: /* EM */
2188 break;
2190 case SUB:
2191 ip->escape = 0; /* dito, but see below */
2192 /* should also display a reverse question mark!! */
2193 break;
2195 case ESC:
2196 ip->escape = ESC;
2197 break;
2199 case 0x1c: /* FS */
2200 case 0x1d: /* GS */
2201 case 0x1e: /* RS */
2202 case 0x1f: /* US */
2203 break;
2205 /* now it gets weird.. 8bit control sequences.. */
2206 case IND: /* index: move cursor down, scroll */
2207 ite_index(ip);
2208 break;
2210 case NEL: /* next line. next line, first pos. */
2211 ite_crlf(ip);
2212 break;
2214 case HTS: /* set horizontal tab */
2215 if (ip->curx < ip->cols)
2216 ip->tabs[ip->curx] = 1;
2217 break;
2219 case RI: /* reverse index */
2220 ite_rlf(ip);
2221 break;
2223 case SS2: /* go into G2 for one character */
2224 ip->save_GL = ip->GR; /* GL XXX EUC */
2225 ip->GR = &ip->G2; /* GL XXX */
2226 break;
2228 case SS3: /* go into G3 for one character */
2229 ip->save_GL = ip->GR; /* GL XXX EUC */
2230 ip->GR = &ip->G3; /* GL XXX */
2231 break;
2233 case DCS: /* device control string introducer */
2234 ip->escape = DCS;
2235 ip->ap = ip->argbuf;
2236 break;
2238 case CSI: /* control sequence introducer */
2239 ip->escape = CSI;
2240 ip->ap = ip->argbuf;
2241 break;
2243 case ST: /* string terminator */
2244 /* ignore, if not used as terminator */
2245 break;
2247 case OSC: /* introduces OS command. Ignore everything upto ST */
2248 ip->escape = OSC;
2249 break;
2251 case PM: /* privacy message, ignore everything upto ST */
2252 ip->escape = PM;
2253 break;
2255 case APC: /* application program command, ignore everything upto ST */
2256 ip->escape = APC;
2257 break;
2259 case DEL:
2260 break;
2262 default:
2263 if (!ip->save_char && (*((c & 0x80) ? ip->GR : ip->GL) & CSET_MULTI)) {
2264 ip->save_char = c;
2265 break;
2267 if (ip->imode)
2268 ite_inchar(ip, ip->save_char ? 2 : 1);
2269 iteprecheckwrap(ip);
2270 #ifdef DO_WEIRD_ATTRIBUTES
2271 if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) {
2272 attrset(ip, ATTR_INV);
2273 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_INV);
2275 else
2276 SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_NOR);
2277 #else
2278 SUBR_PUTC(ip, c, ip->cury, ip->curx, ip->attribute);
2279 #endif
2280 /* SUBR_CURSOR(ip, DRAW_CURSOR);*/
2281 itecheckwrap(ip);
2282 if (ip->save_char) {
2283 itecheckwrap(ip);
2284 ip->save_char = 0;
2286 if (ip->save_GL) {
2288 * reset single shift
2290 ip->GR = ip->save_GL;
2291 ip->save_GL = 0;
2293 break;
2297 static void
2298 iteprecheckwrap(struct ite_softc *ip)
2300 if (ip->auto_wrap && ip->curx + (ip->save_char ? 1 : 0) == ip->cols) {
2301 ip->curx = 0;
2302 clr_attr(ip, ATTR_INV);
2303 if (++ip->cury >= ip->bottom_margin + 1) {
2304 ip->cury = ip->bottom_margin;
2305 /*SUBR_CURSOR(ip, MOVE_CURSOR);*/
2306 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP);
2307 ite_clrtoeol(ip);
2308 } /*else
2309 SUBR_CURSOR(ip, MOVE_CURSOR);*/
2313 static void
2314 itecheckwrap(struct ite_softc *ip)
2316 #if 0
2317 if (++ip->curx == ip->cols) {
2318 if (ip->auto_wrap) {
2319 ip->curx = 0;
2320 clr_attr(ip, ATTR_INV);
2321 if (++ip->cury >= ip->bottom_margin + 1) {
2322 ip->cury = ip->bottom_margin;
2323 SUBR_CURSOR(ip, MOVE_CURSOR);
2324 SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP);
2325 ite_clrtoeol(ip);
2326 return;
2328 } else
2329 /* stay there if no autowrap.. */
2330 ip->curx--;
2332 #else
2333 if (ip->curx < ip->cols) {
2334 ip->curx++;
2335 /*SUBR_CURSOR(ip, MOVE_CURSOR);*/
2337 #endif
2340 #endif
2342 #if NITE > 0 && NKBD > 0
2345 * Console functions
2347 #include <dev/cons.h>
2348 extern void kbdenable(int);
2349 extern int kbdcngetc(void);
2352 * Return a priority in consdev->cn_pri field highest wins. This function
2353 * is called before any devices have been probed.
2355 void
2356 itecnprobe(struct consdev *cd)
2358 int maj;
2360 /* locate the major number */
2361 maj = cdevsw_lookup_major(&ite_cdevsw);
2364 * return priority of the best ite (already picked from attach)
2365 * or CN_DEAD.
2367 if (con_itesoftc.grf == NULL)
2368 cd->cn_pri = CN_DEAD;
2369 else {
2370 con_itesoftc.flags = (ITE_ALIVE|ITE_CONSOLE);
2372 * hardcode the minor number.
2373 * currently we support only one ITE, it is enough for now.
2375 con_itesoftc.isw = &itesw[0];
2376 cd->cn_pri = CN_INTERNAL;
2377 cd->cn_dev = makedev(maj, 0);
2382 void
2383 itecninit(struct consdev *cd)
2385 struct ite_softc *ip;
2387 ip = getitesp(cd->cn_dev);
2388 iteinit(cd->cn_dev); /* init console unit */
2389 ip->flags |= ITE_ACTIVE | ITE_ISCONS;
2390 kbdenable(0);
2391 mfp_send_usart(0x49);
2395 * itecnfinish() is called in ite_init() when the device is
2396 * being probed in the normal fasion, thus we can finish setting
2397 * up this ite now that the system is more functional.
2399 void
2400 itecnfinish(struct ite_softc *ip)
2402 static int done;
2404 if (done)
2405 return;
2406 done = 1;
2409 /*ARGSUSED*/
2411 itecngetc(dev_t dev)
2413 int c;
2415 do {
2416 c = kbdcngetc();
2417 c = ite_cnfilter(c);
2418 } while (c == -1);
2419 return (c);
2422 void
2423 itecnputc(dev_t dev, int c)
2425 static int paniced = 0;
2426 struct ite_softc *ip = getitesp(dev);
2427 char ch = c;
2428 #ifdef ITE_KERNEL_ATTR
2429 short save_attribute;
2430 #endif
2432 if (panicstr && !paniced &&
2433 (ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) {
2434 (void) iteon(dev, 3);
2435 paniced = 1;
2437 #ifdef ITE_KERNEL_ATTR
2438 save_attribute = ip->attribute;
2439 ip->attribute = ITE_KERNEL_ATTR;
2440 #endif
2441 ite_putstr(&ch, 1, dev);
2442 #ifdef ITE_KERNEL_ATTR
2443 ip->attribute = save_attribute;
2444 #endif
2446 #endif