/* $NetBSD: ite.c,v 1.11 1995/03/26 15:52:21 briggs Exp $ */ /* * Copyright (c) 1988 University of Utah. * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: ite.c 1.28 92/12/20$ * * @(#)ite.c 8.2 (Berkeley) 1/12/94 */ /* * ite.c * * The ite module handles the system console; that is, stuff printed * by the kernel and by user programs while "desktop" and X aren't * running. Some (very small) parts are based on hp300's 4.4 ite.c, * hence the above copyright. * * -- Brad and Lawrence, June 26th, 1994 * */ #include #include #include #include #include #include #include #include #include #include "../mac68k/via.h" #include #include #define KEYBOARD_ARRAY #include #include #include #include "6x10.h" #define CHARWIDTH 6 #define CHARHEIGHT 10 #define dprintf if (0) printf #define ATTR_NONE 0 #define ATTR_BOLD 1 #define ATTR_UNDER 2 #define ATTR_REVERSE 4 enum vt100state_e { ESnormal, /* Nothing yet */ ESesc, /* Got ESC */ ESsquare, /* Got ESC [ */ ESgetpars, /* About to get or getting the parameters */ ESgotpars, /* Finished getting the parameters */ ESfunckey, /* Function key */ EShash, /* DEC-specific stuff (screen align, etc.) */ ESsetG0, /* Specify the G0 character set */ ESsetG1, /* Specify the G1 character set */ ESignore /* Ignore this sequence */ } vt100state = ESnormal; /* Received from MacBSDBoot, stored by Locore: */ long videoaddr; long videorowbytes; long videobitdepth; unsigned long videosize; /* Calculated in itecninit(): */ static int width, height, scrrows, scrcols; static void (*putpixel)(int x, int y, int *c, int num); static void (*reversepixel)(int x, int y, int num); /* VT100 state: */ #define MAXPARS 16 static int x = 0, y = 0, savex, savey; static int par[MAXPARS], numpars, hanging_cursor, attr; /* Our tty: */ struct tty *ite_tty; /* For polled ADB mode: */ static int polledkey; extern int adb_polling; /* Misc */ void itestart(); static void ite_putchar (char ch); /* * Bitmap handling functions */ static inline void putpixel1(int xx, int yy, int *c, int num) { unsigned int i, mask; unsigned char *sc; sc = (unsigned char *)videoaddr; i = 7 - (xx & 7); mask = ~(1 << i); sc += yy * videorowbytes + (xx >> 3); while (num--) { *sc &= mask; *sc |= (*c++ & 1) << i; sc += videorowbytes; } } static void putpixel2(int xx, int yy, int *c, int num) { unsigned int i, mask; unsigned char *sc; sc = (unsigned char *)videoaddr; i = 6 - ((xx & 3) << 1); mask = ~(3 << i); sc += yy * videorowbytes + (xx >> 2); while (num--) { *sc &= mask; *sc |= (*c++ & 3) << i; sc += videorowbytes; } } static void putpixel4(int xx, int yy, int *c, int num) { unsigned int i, mask; unsigned char *sc; sc = (unsigned char *)videoaddr; i = 4 - ((xx & 1) << 2); mask = ~(15 << i); sc += yy * videorowbytes + (xx >> 1); while (num--) { *sc &= mask; *sc |= (*c++ & 15) << i; sc += videorowbytes; } } static void putpixel8(int xx, int yy, int *c, int num) { unsigned char *sc; sc = (unsigned char *)videoaddr; sc += yy * videorowbytes + xx; while (num--) { *sc = *c++ & 0xff; sc += videorowbytes; } } static void reversepixel1(int xx, int yy, int num) { unsigned int mask; unsigned char *sc; sc = (unsigned char *)videoaddr; mask = 0; /* Get rid of warning from compiler */ switch (videobitdepth) { case 1: mask = 1 << (7 - (xx & 7)); sc += yy * videorowbytes + (xx >> 3); break; case 2: mask = 3 << (6 - ((xx & 3) << 1)); sc += yy * videorowbytes + (xx >> 2); break; case 4: mask = 15 << (4 - ((xx & 1) << 2)); sc += yy * videorowbytes + (xx >> 1); break; case 8: mask = 255; sc += yy * videorowbytes + xx; break; default: panic ("reversepixel(): unsupported bit depth"); } while (num--) { *sc ^= mask; sc += videorowbytes; } } static void writechar (char ch, int x, int y, int attr) { int i, j, mask, rev, col[CHARHEIGHT]; unsigned char *c; ch &= 0x7F; x *= CHARWIDTH; y *= CHARHEIGHT; rev = (attr & ATTR_REVERSE) ? 255 : 0; c = &Font6x10[ch * CHARHEIGHT]; switch (videobitdepth) { case 1: for (j = 0; j < CHARWIDTH; j++) { mask = 1 << (CHARWIDTH - 1 - j); for (i = 0; i < CHARHEIGHT; i++) { col[i] = ((c[i] & mask) ? 255 : 0) ^ rev; } putpixel1 (x + j, y, col, CHARHEIGHT); } if (attr & ATTR_UNDER) { col[0] = 255; for (j = 0; j < CHARWIDTH; j++) { putpixel1 (x + j, y + CHARHEIGHT - 1, col, 1); } } break; case 2: case 4: case 8: for (j = 0; j < CHARWIDTH; j++) { mask = 1 << (CHARWIDTH - 1 - j); for (i = 0; i < CHARHEIGHT; i++) { col[i] = ((c[i] & mask) ? 255 : 0) ^ rev; } putpixel (x + j, y, col, CHARHEIGHT); } if (attr & ATTR_UNDER) { col[0] = 255; for (j = 0; j < CHARWIDTH; j++) { putpixel (x + j, y + CHARHEIGHT - 1, col, 1); } } break; } } static void drawcursor (void) { int j, X, Y; X = x * CHARWIDTH; Y = y * CHARHEIGHT; for (j = 0; j < CHARWIDTH; j++) { reversepixel (X + j, Y, CHARHEIGHT); } } static void erasecursor (void) { int j, X, Y; X = x * CHARWIDTH; Y = y * CHARHEIGHT; for (j = 0; j < CHARWIDTH; j++) { reversepixel (X + j, Y, CHARHEIGHT); } } static void scrollup (void) { unsigned long *from, *to; int i, linelongs, tocopy, copying; linelongs = videorowbytes * CHARHEIGHT / 4; to = (unsigned long *)videoaddr; from = to + linelongs; tocopy = (scrrows - 1) * linelongs; while (tocopy > 0) { copying = (tocopy > 16383) ? 16383 : tocopy; bcopy (from, to, copying*4); from += copying; to += copying; tocopy -= copying; } to = (unsigned long *)videoaddr; bzero (to + (scrrows - 1) * linelongs, linelongs * sizeof (long)); } static void scrolldown (void) { unsigned long *from, *to; int i, linelongs; linelongs = videorowbytes * CHARHEIGHT / 4; to = (unsigned long *)videoaddr + linelongs * scrrows; from = to - linelongs; for (i = (scrrows - 1) * linelongs; i > 0; i--) { *--to = *--from; } for (i = linelongs; i > 0; i--) { *--to = 0; } } static void clear_screen (int which) { unsigned long *p; int i, linelongs; p = (unsigned long *)videoaddr; linelongs = videorowbytes * CHARHEIGHT / 4; switch (which) { case 0: /* To end of screen */ p += y * linelongs; i = (scrrows - y) * linelongs; break; case 1: /* To start of screen */ i = y * linelongs; break; case 2: /* Whole screen */ i = scrrows * linelongs; break; } bzero (p, i * sizeof (long)); } static void clear_line (int which) { int start, end, i; /* * This routine runs extremely slowly. I don't think it's * used all that often, except for To end of line. I'll go * back and speed this up when I speed up the whole ite * module. --LK */ switch (which) { case 0: /* To end of line */ start = x; end = scrcols; break; case 1: /* To start of line */ start = 0; end = x; break; case 2: /* Whole line */ start = 0; end = scrcols; break; } for (i = start; i < end; i++) { writechar (' ', i, y, ATTR_NONE); } } static void putc_normal (char ch) { switch (ch) { case '\a': /* Beep */ asc_ringbell(); break; case 127: /* Delete */ case '\b': /* Backspace */ if (hanging_cursor) { hanging_cursor = 0; } else if (x > 0) { x--; } break; case '\t': /* Tab */ do { ite_putchar (' '); } while (x % 8 != 0); break; case '\n': /* Line feed */ y++; if (y >= scrrows) { scrollup (); y = scrrows - 1; } break; case '\r': /* Carriage return */ x = 0; hanging_cursor = 0; break; case '\e': /* Escape */ vt100state = ESesc; hanging_cursor = 0; break; default: if (ch >= ' ') { if (hanging_cursor) { x = 0; y++; if (y >= scrrows) { scrollup (); y = scrrows - 1; } hanging_cursor = 0; } writechar (ch, x, y, attr); if (x == scrcols - 1) { hanging_cursor = 1; } else { x++; } if (x >= scrcols) { x = 0; y++; } } break; } } static void putc_esc (char ch) { vt100state = ESnormal; switch (ch) { case '[': vt100state = ESsquare; break; case 'D': /* Line feed */ y++; break; case 'H': /* Set tab stop */ /* Not supported */ break; case 'M': /* Cursor up */ if (y == 0) { scrolldown (); } else { y--; } break; case '7': /* Save cursor */ savex = x; savey = y; break; case '8': /* Restore cursor */ x = savex; y = savey; break; default: /* Rest not supported */ break; } } static void putc_gotpars (char ch) { int i; vt100state = ESnormal; switch (ch) { case 'A': /* Up */ y--; break; case 'B': /* Down */ y++; break; case 'C': /* Right */ x++; break; case 'D': /* Left */ x--; break; case 'H': /* Set cursor position */ x = par[1] - 1; y = par[0] - 1; hanging_cursor = 0; break; case 'J': /* Clear part of screen */ clear_screen (par[0]); break; case 'K': /* Clear part of line */ clear_line (par[0]); break; case 'g': /* Clear tab stops */ /* Not supported */ break; case 'm': /* Set attribute */ for (i = 0; i < numpars; i++) { switch (par[i]) { case 0: attr = ATTR_NONE; break; case 1: attr |= ATTR_BOLD; break; case 4: attr |= ATTR_UNDER; break; case 7: attr |= ATTR_REVERSE; break; } } break; case 'r': /* Set scroll region */ /* Not supported */ break; } } static void putc_getpars (char ch) { if (ch == '?') { /* Not supported */ return; } if (ch == '[') { vt100state = ESnormal; /* Not supported */ return; } if (ch == ';' && numpars < MAXPARS - 1) { numpars++; } else if (ch >= '0' && ch <= '9') { par[numpars] *= 10; par[numpars] += ch - '0'; } else { numpars++; vt100state = ESgotpars; putc_gotpars (ch); } } static void putc_square (char ch) { int i; for (i = 0; i < MAXPARS; i++) { par[i] = 0; } numpars = 0; vt100state = ESgetpars; putc_getpars (ch); } static void ite_putchar (char ch) { switch (vt100state) { default: vt100state = ESnormal; /* FALLTHROUGH */ case ESnormal: putc_normal (ch); break; case ESesc: putc_esc (ch); break; case ESsquare: putc_square (ch); break; case ESgetpars: putc_getpars (ch); break; case ESgotpars: putc_gotpars (ch); break; } if (x >= scrcols) { x = scrcols - 1; } if (x < 0) { x = 0; } if (y >= scrrows) { y = scrrows - 1; } if (y < 0) { y = 0; } } /* * Keyboard support functions */ static int ite_dopollkey(int key) { polledkey = key; return 0; } static int ite_pollforchar(void) { int s; register int intbits; s = splhigh(); polledkey = -1; adb_polling = 1; /* pretend we're VIA interrupt dispatcher */ while (polledkey == -1) { intbits = via_reg(VIA1, vIFR); if (intbits & V1IF_ADBRDY) { mrg_adbintr(); via_reg(VIA1, vIFR) = V1IF_ADBRDY; } if (intbits & 0x10) { mrg_pmintr(); via_reg(VIA1, vIFR) = 0x10; } } adb_polling = 0; splx(s); return polledkey; } /* * Tty handling functions */ static void iteattach (struct device *parent, struct device *dev, void *aux) { printf (" (minimal console)\n"); } extern int matchbyname(); struct cfdriver itecd = { NULL, "ite", matchbyname, iteattach, DV_TTY, sizeof(struct device), NULL, 0 }; iteopen(dev_t dev, int mode, int devtype, struct proc *p, struct file *fp) { register struct tty *tp; register int error; int first = 0; dprintf ("iteopen(): enter(0x%x)\n",(int)dev); if (ite_tty == NULL) tp = ite_tty = ttymalloc(); else tp = ite_tty; if ((tp->t_state&(TS_ISOPEN|TS_XCLUDE)) == (TS_ISOPEN|TS_XCLUDE) && p->p_ucred->cr_uid != 0) return (EBUSY); tp->t_oproc = itestart; tp->t_param = NULL; tp->t_dev = dev; if ((tp->t_state & TS_ISOPEN) == 0) { ttychars(tp); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_cflag = CS8|CREAD; tp->t_lflag = TTYDEF_LFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; tp->t_state = TS_ISOPEN|TS_CARR_ON; ttsetwater(tp); } error = (*linesw[tp->t_line].l_open)(dev, tp); tp->t_winsize.ws_row = scrrows; tp->t_winsize.ws_col = scrcols; dprintf ("iteopen(): exit(%d)\n", error); return (error); } iteclose(dev_t dev, int flag, int mode, struct proc *p) { dprintf ("iteclose: enter (%d)\n", (int)dev); (*linesw[ite_tty->t_line].l_close)(ite_tty, flag); ttyclose (ite_tty); #if 0 ttyfree (ite_tty); ite_tty = (struct tty *)0; #endif dprintf ("iteclose: exit\n"); return 0; } iteread(dev_t dev, struct uio *uio, int flag) { dprintf ("iteread: enter\n"); return (*linesw[ite_tty->t_line].l_read)(ite_tty, uio, flag); dprintf ("iteread: exit\n"); } itewrite(dev_t dev, struct uio *uio, int flag) { dprintf ("itewrite: enter\n"); return (*linesw[ite_tty->t_line].l_write)(ite_tty, uio, flag); dprintf ("itewrite: exit\n"); } iteioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) { register struct tty *tp = ite_tty; int error; dprintf ("iteioctl: enter(%d, 0x%x)\n", cmd, cmd); error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr, flag, p); if (error >= 0) { dprintf ("iteioctl: exit(%d)\n", error); return (error); } error = ttioctl(tp, cmd, addr, flag, p); if (error >= 0) { dprintf ("iteioctl: exit(%d)\n", error); return (error); } switch (cmd) { case ITEIOC_RINGBELL: { asc_ringbell(); return (0); } case ITEIOC_SETBELL: { struct bellparams *bp = (void *) addr; asc_setbellparams(bp->freq, bp->len, bp->vol); return (0); } case ITEIOC_GETBELL: { struct bellparams *bp = (void *) addr; asc_getbellparams(&bp->freq, &bp->len, &bp->vol); return (0); } } dprintf ("iteioctl: exit(ENOTTY)\n"); return (ENOTTY); } void itestart (register struct tty *tp) { register int cc, s; int hiwat = 0, hadcursor = 0; s = spltty(); if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) { splx(s); return; } tp->t_state |= TS_BUSY; cc = tp->t_outq.c_cc; splx(s); erasecursor (); while (cc-- > 0) { ite_putchar (getc (&tp->t_outq)); } drawcursor (); s = spltty(); tp->t_state &= ~TS_BUSY; splx(s); } void itestop (struct tty *tp, int flag) { int s; s = spltty (); if (tp->t_state & TS_BUSY) { if ((tp->t_state & TS_TTSTOP) == 0) { tp->t_state |= TS_FLUSH; } } splx(s); } ite_intr (adb_event_t *event) { static int shift = 0, control = 0; int key, press, val, state; char str[10], *s; key = event->u.k.key; press = ADBK_PRESS (key); val = ADBK_KEYVAL (key); if (val == ADBK_SHIFT) { shift = press; } else if (val == ADBK_CONTROL) { control = press; } else if (press) { switch (val) { case ADBK_UP: str[0] = '\e'; str[1] = 'O'; str[2] = 'A'; str[3] = '\0'; break; case ADBK_DOWN: str[0] = '\e'; str[1] = 'O'; str[2] = 'B'; str[3] = '\0'; break; case ADBK_RIGHT: str[0] = '\e'; str[1] = 'O'; str[2] = 'C'; str[3] = '\0'; break; case ADBK_LEFT: str[0] = '\e'; str[1] = 'O'; str[2] = 'D'; str[3] = '\0'; break; default: state = 0; if (shift) { state = 1; } if (control) { state = 2; } str[0] = keyboard[val][state]; str[1] = '\0'; break; } if (adb_polling) { polledkey = str[0]; } else { for (s = str; *s; s++) { (*linesw[ite_tty->t_line].l_rint)(*s, ite_tty); } } } } /* * Console functions */ itecnprobe(struct consdev *cp) { int maj, unit; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) { if (cdevsw[maj].d_open == iteopen) { break; } } if (maj == nchrdev) { panic ("itecnprobe(): did not find iteopen()."); } unit = 0; /* hardcode first device as console. */ /* initialize required fields */ cp->cn_dev = makedev (maj, unit); cp->cn_pri = CN_INTERNAL; } itecninit(struct consdev *cp) { width = videosize & 0xffff; height = (videosize >> 16) & 0xffff; scrrows = height / CHARHEIGHT; scrcols = width / CHARWIDTH; switch (videobitdepth) { default: case 1: putpixel = putpixel2; reversepixel = reversepixel1; break; case 2: putpixel = putpixel2; reversepixel = reversepixel1; break; case 4: putpixel = putpixel4; reversepixel = reversepixel1; break; case 8: putpixel = putpixel8; reversepixel = reversepixel1; break; } iteon(cp->cn_dev, 0); } iteon(dev_t dev, int flags) { erasecursor (); clear_screen (2); drawcursor (); } iteoff(dev_t dev, int flags) { erasecursor (); clear_screen (2); } itecngetc(dev_t dev) { /* Oh, man... */ return ite_pollforchar (); } itecnputc(dev_t dev, int c) { extern dev_t mac68k_serdev; int s; /* s = splhigh (); */ erasecursor (); ite_putchar (c); drawcursor (); if (mac68k_machine.serial_boot_echo) sercnputc(mac68k_serdev, c); /* splx (s); */ }