diff options
Diffstat (limited to 'usr.bin/doscmd/tty.c')
-rw-r--r-- | usr.bin/doscmd/tty.c | 2193 |
1 files changed, 2193 insertions, 0 deletions
diff --git a/usr.bin/doscmd/tty.c b/usr.bin/doscmd/tty.c new file mode 100644 index 0000000..c7b78c0 --- /dev/null +++ b/usr.bin/doscmd/tty.c @@ -0,0 +1,2193 @@ +/* + * Copyright (c) 1992, 1993, 1996 + * Berkeley Software Design, Inc. All rights reserved. + * + * 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 Berkeley Software + * Design, Inc. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI tty.c,v 2.4 1996/04/08 22:03:27 prb Exp + * + * $Id: tty.c,v 1.4 1996/09/22 15:43:00 miff Exp $ + */ + +#ifndef NO_X +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/keysym.h> +#endif + +#include <stdio.h> +#include <termios.h> +#include <limits.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/time.h> +#ifdef __FreeBSD__ +# include <machine/console.h> +#else +# ifdef __NetBSD__ +# include "machine/pccons.h" +# else /* BSD/OS */ +# include "/sys/i386/isa/pcconsioctl.h" +# endif +#endif +#include <sys/mman.h> +#include <ctype.h> +#include "doscmd.h" +#include "mouse.h" +#include "video.h" +#include "font.h" + +static struct termios save = { 0 }; +static struct termios raw = { 0 }; +static int flags = 0; +static int mode = -1; +#define vmem ((u_short *)0xB8000) +static int blink = 1; +int flipdelete = 1; /* Flip meaning of delete and backspace */ +extern int capture_fd; +static u_short break_code = 0x00; +static u_short scan_code = 0x00; + +#ifndef NO_X +static Display *dpy = 0; +static Window win; +static XFontStruct *font; +static unsigned long black; +static unsigned long white; +static unsigned long pixels[16]; +static char *color_names[16] = { + "black", + "medium blue", + "olive drab", + "turquoise3", + "red1", + "maroon", + "goldenrod4", + "gray80", + "gray50", + "sky blue", + "spring green", + "PaleTurquoise2", + "pink", + "violet red", + "yellow1", + "white", +}; + +static int FW, FH, FD; +static GC gc; +static GC cgc; +static int xfd; +#endif + +int kbd_fd = -1; +int kbd_read = 0; +static int vattr = 0x0700; + +static int width = 80; +static int height = 25; +static struct termios tty_cook, tty_raw; + +typedef struct TextLine { + u_short *data; + u_char max_length; /* Not used, but here for future use */ + u_char changed:1; +} TextLine; +static TextLine *lines; + +/* + * 0040:0050 is a list of 16 bytes, 2 for each page, which contains + * the column and row of each page + */ +#define row BIOSDATA[0x51] +#define col BIOSDATA[0x50] + +u_char *VREG; + +inline SetVREGCur() +{ + int cp = row * width + col; + VREG[MVC_CurHigh] = cp >> 8; + VREG[MVC_CurLow] = cp & 0xff; +} + +/* + * 0040:0060 contains the start and end of the cursor + */ +#define curs_end BIOSDATA[0x60] +#define curs_start BIOSDATA[0x61] + +#define video_pate BISODATA[0x62] + +#define IBMFONT "vga" /* font supplied */ + +char *xfont = 0; + +void video_async_event(); +void debug_event(); +int video_event(); +void tty_cooked(); +void video_update(); +unsigned char video_inb(int); +unsigned char inb_port60(int); +void video_outb(int, unsigned char); +void kbd_event(int fd, REGISTERS); +u_short read_raw_kbd(int fd, u_short *code); + +#define PEEKSZ 16 + +#define K_NEXT *(u_short *)0x41a +#define K_FREE *(u_short *)0x41c +#define K_BUFSTARTP *(u_short *)0x480 +#define K_BUFENDP *(u_short *)0x482 +#define K_BUFSTART ((u_short *)(0x400 + *(u_short *)0x480)) +#define K_BUFEND ((u_short *)(0x400 + *(u_short *)0x482)) + +#define K1_STATUS BIOSDATA[0x17] +#define K1_RSHIFT 0x01 +#define K1_LSHIFT 0x02 +#define K1_SHIFT 0x03 +#define K1_CTRL 0x04 +#define K1_ALT 0x08 +#define K1_SLOCK 0x10 /* Active */ +#define K1_NLOCK 0x20 /* Active */ +#define K1_CLOCK 0x40 /* Active */ +#define K1_INSERT 0x80 /* Active */ + +#define K2_STATUS BIOSDATA[0x18] +#define K2_LCTRL 0x01 +#define K2_LALT 0x02 +#define K2_SYSREQ 0x04 +#define K2_PAUSE 0x08 +#define K2_SLOCK 0x10 /* Actually held down */ +#define K2_NLOCK 0x20 /* Actually held down */ +#define K2_CLOCK 0x40 /* Actually held down */ +#define K2_INSERT 0x80 /* Actually held down */ + +#define K3_STATUS BIOSDATA[0x96] +#define K3_E1 0x01 /* Last code read was e1 */ +#define K3_E2 0x02 /* Last code read was e2 */ +#define K3_RCTRL 0x04 +#define K3_RALT 0x08 +#define K3_ENHANCED 0x10 +#define K3_FORCENLOCK 0x20 +#define K3_TWOBYTE 0x40 /* last code was first of 2 */ +#define K3_READID 0x80 /* read ID in progress */ + +#define K4_STATUS BIOSDATA[0x97] +#define K4_SLOCK_LED 0x01 +#define K4_NLOCK_LED 0x02 +#define K4_CLOCK_LED 0x04 +#define K4_ACK 0x10 /* ACK recieved from keyboard */ +#define K4_RESEND 0x20 /* RESEND recieved from keyboard */ +#define K4_LED 0x40 /* LED update in progress */ +#define K4_ERROR 0x80 + +struct VideoSavePointerTable { + u_short video_parameter_tabel[2]; + u_short parameter_dynamic_save_area[2]; /* Not used */ + u_short alphanumeric_character_set_override[2]; /* Not used */ + u_short graphics_character_set_override[2]; /* Not used */ + u_short secondary_save_pointer_table[2]; /* Not used */ + u_short mbz[4]; +}; + +struct SecondaryVideoSavePointerTable { + u_short length; + u_short display_combination_code_table[2]; + u_short alphanumeric_character_set_override[2]; /* Not used */ + u_short user_palette_profile_table[2]; /* Not used */ + u_short mbz[6]; +}; + +int KbdEmpty(); +void KbdWrite(u_short code); +void KbdRepl(u_short code); +u_short KbdRead(); +u_short KbdPeek(); + +int redirect0; +int redirect1; +int redirect2; + +static void +Failure() +{ + fprintf(stderr, "X Connection shutdown\n"); + quit(1); +} + +struct VideoSavePointerTable *vsp; +struct SecondaryVideoSavePointerTable *svsp; + +#include "vparams.h" + +static void +console_denit(void *arg) +{ + int fd = *(int *)arg; + +#ifdef __FreeBSD__ + if (ioctl(fd, KDSKBMODE, K_XLATE)) + perror("KDSKBMODE/K_XLATE"); +#else +# ifdef __NetBSD__ + if (ioctl(fd, CONSOLE_X_MODE_OFF, 0)) + perror("CONSOLE_X_MODE_OFF"); +# else /* BSD/OS */ + if (ioctl(fd, PCCONIOCCOOK, 0)) + perror("PCCONIOCCOOK"); +# endif +#endif + if (tcsetattr(fd, TCSANOW, &tty_cook)) + perror("tcsetattr"); +} + +void +_kbd_event(int fd, REGISTERS) +{ + printf("_kbd_event: fd=%d\n", fd); + kbd_read = 1; +} + +void +console_init() +{ + int fd; + caddr_t addr; + + if ((fd = open("/dev/vga", 2)) < 0) { + perror("/dev/vga"); + quit(1); + } + addr = mmap((caddr_t)0xA0000, 5 * 64 * 1024, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED, + fd, 0); + if (addr != (caddr_t)0xA0000) { + perror("mmap"); + quit(1); + } + +#if 0 + addr = mmap((caddr_t)0x100000 - 0x1000, 0x1000, + PROT_EXEC | PROT_READ | PROT_WRITE, + MAP_FILE | MAP_FIXED | MAP_INHERIT | MAP_SHARED, + fd, 0); + if (addr != (caddr_t)(0x100000 - 0x1000)) { + perror("mmap"); + quit(1); + } +#endif + + if ((fd = open("/dev/console", 2)) < 0) { + perror("/dev/console"); + quit(1); + } + + fd = squirrel_fd(fd); + kbd_fd = fd; + +#ifdef __FreeBSD__ + if (ioctl(fd, KDSKBMODE, K_RAW)) { + perror("KDSKBMODE/K_RAW"); + quit(1); + } +#else +# ifdef __NetBSD__ + if (ioctl(fd, CONSOLE_X_MODE_ON, 0)) { + perror("CONSOLE_X_MODE_ON"); + quit(1); + } +# else /* BSD/OS */ + if (ioctl(fd, PCCONIOCRAW, 0)) { + perror("PCCONIOCRAW"); + quit(1); + } +# endif +#endif + + call_on_quit(console_denit, &kbd_fd); + + if (fcntl(fd, F_SETFL, O_NDELAY|O_ASYNC) < 0) { + perror("fcntl"); + quit(1); + } + if (tcgetattr(fd, &tty_cook)) { + perror("tcgetattr"); + quit(1); + } + tty_raw = tty_cook; + cfmakeraw(&tty_raw); + if (tcsetattr(fd, TCSANOW, &tty_raw)) { + perror("tcsetattr"); + quit(1); + } + +#if 0 + _RegisterIO(0, debug_event, 0, Failure); + _RegisterIO(fd, kbd_event, fd, Failure); +#endif + _RegisterIO(fd, _kbd_event, fd, Failure); +} + +void +video_setborder(int color) +{ +#ifndef NO_X + _BlockIO(); + XSetWindowBackground(dpy, win, pixels[color & 0xf]); + _UnblockIO(); +#endif +} +void +video_blink(int mode) +{ + blink = mode; +} + +static int show = 1; + +setgc(u_short attr) +{ +#ifndef NO_X + XGCValues v; + if (blink && !show && (attr & 0x8000)) + v.foreground = pixels[(attr >> 12) & 0x07]; + else + v.foreground = pixels[(attr >> 8) & 0x0f]; + + v.background = pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)]; +#if 0 + if (v.foreground == v.background) { + v.foreground = pixels[15]; + v.background = pixels[0]; + } +#endif + XChangeGC(dpy, gc, GCForeground|GCBackground, &v); +#endif +} + +void +video_update(REGISTERS) +{ +#ifndef NO_X + static int or = -1; + static int oc = -1; + + static int icnt = 4; + + static char buf[256]; + int r, c; + int attr = vmem[0] & 0xff00; + XGCValues v; + + if (kbd_read) + kbd_event(kbd_fd, sc); + + if (--icnt == 0) { + + icnt = 4; + + lpt_poll(); /* Handle timeout on lpt code */ + + if (xmode) { + wakeup_poll(); /* Wake up anyone waiting on kbd poll */ + + show ^= 1; + + setgc(attr); + + for (r = 0; r < height; ++r) { + int cc = 0; + + if (!lines[r].changed) { + if ((r == or || r == row) && (or != row || oc != col)) + lines[r].changed = 1; + else { + for (c = 0; c < width; ++c) { + if (lines[r].data[c] != vmem[r * width + c]) { + lines[r].changed = 1; + break; + } + if (blink && lines[r].data[c] & 0x8000) { + lines[r].changed = 1; + break; + } + } + } + } + + if (!lines[r].changed) + continue; + + reset_poll(); + lines[r].changed = 0; + memcpy(lines[r].data, + &vmem[r * width], sizeof(u_short) * width); + + for (c = 0; c < width; ++c) { + int cv = vmem[r * width + c]; + if ((cv & 0xff00) != attr) { + if (cc < c) + XDrawImageString(dpy, win, gc, + 2 + cc * FW, + 2 + (r + 1) * FH, + buf + cc, c - cc); + cc = c; + attr = cv & 0xff00; + setgc(attr); + } + buf[c] = (cv & 0xff) ? cv & 0xff : ' '; + } + if (cc < c) { + XDrawImageString(dpy, win, gc, + 2 + cc * FW, + 2 + (r + 1) * FH, + buf + cc, c - cc); + } + } + or = row; + oc = col; + + if (curs_start <= curs_end && curs_end <= FH && + show && row < height && col < width) { + int start, end; + + attr = vmem[row * width + col] & 0xff00; + v.foreground = pixels[(attr >> 8) & 0x0f] ^ + pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)]; + if (v.foreground) { + v.function = GXxor; + } else { + v.foreground = pixels[7]; + v.function = GXcopy; + } + XChangeGC(dpy, cgc, GCForeground | GCFunction, &v); + start = curs_start * FH / 8; + end = curs_end * FH / 8; + XFillRectangle(dpy, win, cgc, + 2 + col * FW, + 2 + row * FH + start + FD, + FW, end + 1 - start); + } + + if (mouse_status.installed && mouse_status.show) { + c = mouse_status.x / mouse_status.hmickey; + r = mouse_status.y / mouse_status.vmickey; + + lines[r].changed = 1; + attr = vmem[r * width + c] & 0xff00; + v.foreground = pixels[(attr >> 8) & 0x0f] ^ + pixels[(attr >> 12) & 0x0f]; + if (v.foreground) { + v.function = GXxor; + } else { + v.foreground = pixels[7]; + v.function = GXcopy; + } + XChangeGC(dpy, cgc, GCForeground | GCFunction, &v); + XFillRectangle(dpy, win, cgc, + 2 + c * FW, + 2 + r * FH + 2, + FW, FH); + } + + XFlush(dpy); + } + } + + if (!booting) { + *(u_long *)&BIOSDATA[0x6c] += 1; /* Timer ticks since midnight... */ + while (*(u_long *)&BIOSDATA[0x6c] >= 24*60*6*182) { + *(u_long *)&BIOSDATA[0x6c] -= 24*60*6*182; + BIOSDATA[0x70]++; /* BIOSDATA[0x70] # times past mn */ + } + } +#endif +} + +static u_short Ascii2Scan[] = { + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0x000e, 0x000f, 0xffff, 0xffff, 0xffff, 0x001c, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0x0001, 0xffff, 0xffff, 0xffff, 0xffff, + 0x0039, 0x0102, 0x0128, 0x0104, 0x0105, 0x0106, 0x0108, 0x0028, + 0x010a, 0x010b, 0x0109, 0x010d, 0x0033, 0x000c, 0x0034, 0x0035, + 0x000b, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000a, 0x0127, 0x0027, 0x0133, 0x000d, 0x0134, 0x0135, + 0x0103, 0x011e, 0x0130, 0x012e, 0x0120, 0x0112, 0x0121, 0x0122, + 0x0123, 0x0117, 0x0124, 0x0125, 0x0126, 0x0132, 0x0131, 0x0118, + 0x0119, 0x0110, 0x0113, 0x011f, 0x0114, 0x0116, 0x012f, 0x0111, + 0x012d, 0x0115, 0x012c, 0x001a, 0x002b, 0x001b, 0x0107, 0x010c, + 0x0029, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, + 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 0x0032, 0x0031, 0x0018, + 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, + 0x002d, 0x0015, 0x002c, 0x011a, 0x012b, 0x011b, 0x0129, 0xffff, +}; + +struct { + u_short base; + u_short shift; + u_short ctrl; + u_short alt; +} ScanCodes[] = { + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 0 */ + { 0x011b, 0x011b, 0x011b, 0xffff }, /* key 1 - Escape key */ + { 0x0231, 0x0221, 0xffff, 0x7800 }, /* key 2 - '1' */ + { 0x0332, 0x0340, 0x0300, 0x7900 }, /* key 3 - '2' - special handling */ + { 0x0433, 0x0423, 0xffff, 0x7a00 }, /* key 4 - '3' */ + { 0x0534, 0x0524, 0xffff, 0x7b00 }, /* key 5 - '4' */ + { 0x0635, 0x0625, 0xffff, 0x7c00 }, /* key 6 - '5' */ + { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* key 7 - '6' */ + { 0x0837, 0x0826, 0xffff, 0x7e00 }, /* key 8 - '7' */ + { 0x0938, 0x092a, 0xffff, 0x7f00 }, /* key 9 - '8' */ + { 0x0a39, 0x0a28, 0xffff, 0x8000 }, /* key 10 - '9' */ + { 0x0b30, 0x0b29, 0xffff, 0x8100 }, /* key 11 - '0' */ + { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* key 12 - '-' */ + { 0x0d3d, 0x0d2b, 0xffff, 0x8300 }, /* key 13 - '=' */ + { 0x0e08, 0x0e08, 0x0e7f, 0xffff }, /* key 14 - backspace */ + { 0x0f09, 0xffff, 0xffff, 0xffff }, /* key 15 - tab */ + { 0x1071, 0x1051, 0x1011, 0x1000 }, /* key 16 - 'Q' */ + { 0x1177, 0x1157, 0x1117, 0x1100 }, /* key 17 - 'W' */ + { 0x1265, 0x1245, 0x1205, 0x1200 }, /* key 18 - 'E' */ + { 0x1372, 0x1352, 0x1312, 0x1300 }, /* key 19 - 'R' */ + { 0x1474, 0x1454, 0x1414, 0x1400 }, /* key 20 - 'T' */ + { 0x1579, 0x1559, 0x1519, 0x1500 }, /* key 21 - 'Y' */ + { 0x1675, 0x1655, 0x1615, 0x1600 }, /* key 22 - 'U' */ + { 0x1769, 0x1749, 0x1709, 0x1700 }, /* key 23 - 'I' */ + { 0x186f, 0x184f, 0x180f, 0x1800 }, /* key 24 - 'O' */ + { 0x1970, 0x1950, 0x1910, 0x1900 }, /* key 25 - 'P' */ + { 0x1a5b, 0x1a7b, 0x1a1b, 0xffff }, /* key 26 - '[' */ + { 0x1b5d, 0x1b7d, 0x1b1d, 0xffff }, /* key 27 - ']' */ + { 0x1c0d, 0x1c0d, 0x1c0a, 0xffff }, /* key 28 - CR */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 29 - control */ + { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* key 30 - 'A' */ + { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* key 31 - 'S' */ + { 0x2064, 0x2044, 0x2004, 0x2000 }, /* key 32 - 'D' */ + { 0x2166, 0x2146, 0x2106, 0x2100 }, /* key 33 - 'F' */ + { 0x2267, 0x2247, 0x2207, 0x2200 }, /* key 34 - 'G' */ + { 0x2368, 0x2348, 0x2308, 0x2300 }, /* key 35 - 'H' */ + { 0x246a, 0x244a, 0x240a, 0x2400 }, /* key 36 - 'J' */ + { 0x256b, 0x254b, 0x250b, 0x2500 }, /* key 37 - 'K' */ + { 0x266c, 0x264c, 0x260c, 0x2600 }, /* key 38 - 'L' */ + { 0x273b, 0x273a, 0xffff, 0xffff }, /* key 39 - ';' */ + { 0x2827, 0x2822, 0xffff, 0xffff }, /* key 40 - ''' */ + { 0x2960, 0x297e, 0xffff, 0xffff }, /* key 41 - '`' */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 42 - left shift */ + { 0x2b5c, 0x2b7c, 0x2b1c, 0xffff }, /* key 43 - '' */ + { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* key 44 - 'Z' */ + { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* key 45 - 'X' */ + { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* key 46 - 'C' */ + { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* key 47 - 'V' */ + { 0x3062, 0x3042, 0x3002, 0x3000 }, /* key 48 - 'B' */ + { 0x316e, 0x314e, 0x310e, 0x3100 }, /* key 49 - 'N' */ + { 0x326d, 0x324d, 0x320d, 0x3200 }, /* key 50 - 'M' */ + { 0x332c, 0x333c, 0xffff, 0xffff }, /* key 51 - ',' */ + { 0x342e, 0x343e, 0xffff, 0xffff }, /* key 52 - '.' */ + { 0x352f, 0x353f, 0xffff, 0xffff }, /* key 53 - '/' */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 54 - right shift - */ + { 0x372a, 0xffff, 0x3772, 0xffff }, /* key 55 - prt-scr - */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 56 - Alt - */ + { 0x3920, 0x3920, 0x3920, 0x3920 }, /* key 57 - space bar */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 58 - caps-lock - */ + { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* key 59 - F1 */ + { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* key 60 - F2 */ + { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* key 61 - F3 */ + { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* key 62 - F4 */ + { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* key 63 - F5 */ + { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* key 64 - F6 */ + { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* key 65 - F7 */ + { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* key 66 - F8 */ + { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* key 67 - F9 */ + { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* key 68 - F10 */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 69 - num-lock - */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 70 - scroll-lock - */ + { 0x4700, 0x4737, 0x7700, 0xffff }, /* key 71 - home */ + { 0x4800, 0x4838, 0xffff, 0xffff }, /* key 72 - cursor up */ + { 0x4900, 0x4939, 0x8400, 0xffff }, /* key 73 - page up */ + { 0x2d00, 0x4a2d, 0xffff, 0xffff }, /* key 74 - minus sign */ + { 0x4b00, 0x4b34, 0x7300, 0xffff }, /* key 75 - cursor left */ + { 0xffff, 0x4c35, 0xffff, 0xffff }, /* key 76 - center key */ + { 0x4d00, 0x4d36, 0x7400, 0xffff }, /* key 77 - cursor right */ + { 0x2b00, 0x4e2b, 0xffff, 0xffff }, /* key 78 - plus sign */ + { 0x4f00, 0x4f31, 0x7500, 0xffff }, /* key 79 - end */ + { 0x5000, 0x5032, 0xffff, 0xffff }, /* key 80 - cursor down */ + { 0x5100, 0x5133, 0x7600, 0xffff }, /* key 81 - page down */ + { 0x5200, 0x5230, 0xffff, 0xffff }, /* key 82 - insert */ + { 0x5300, 0x532e, 0xffff, 0xffff }, /* key 83 - delete */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 84 - sys key */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 85 */ + { 0xffff, 0xffff, 0xffff, 0xffff }, /* key 86 */ + { 0x8500, 0x5787, 0x8900, 0x8b00 }, /* key 87 - F11 */ + { 0x8600, 0x5888, 0x8a00, 0x8c00 }, /* key 88 - F12 */ +}; + +void +debug_event(int fd, REGISTERS) +{ + static char ibuf[1024]; + static char icnt = 0; + static u_short ds = 0; + static u_short di = 0; + static u_short cnt = 16 * 8; + char *ep; + + int r; + + r = read(0, ibuf + icnt, sizeof(ibuf) - icnt); + if (r <= 0) + return; + + icnt += r; + + ibuf[icnt] = 0; + while (ep = strchr(ibuf, '\n')) { + int ac; + char *_av[16]; + char **av; + + *ep++ = 0; + ac = ParseBuffer(ibuf, av = _av, 16); + + if (ac > 0) { + if (!strcasecmp(av[0], "dump")) { + if (ac > 1) { + char *c; + if (c = strchr(av[1], ':')) { + ds = strtol(av[1], 0, 16); + di = strtol(c+1, 0, 16); + } else + di = strtol(av[1], 0, 16); + } + if (ac > 2) + cnt = strtol(av[2], 0, 0); + cnt = (cnt + 0xf) & ~0xf; + if (cnt == 0) + cnt = 0x10; + di &= ~0xf; + + for (r = 0; r < cnt; r += 0x10, di = (di + 0x10) & 0xffff) { + int i; + u_char *ap = (u_char *)(((u_long)ds << 4) + di); + + printf("%04x:%04x:", ds, di); + for (i = 0; i < 8; ++i) + printf(" %02x", ap[i]); + printf(" "); + for (i = 8; i < 16; ++i) + printf(" %02x", ap[i]); + printf(": "); + for (i = 0; i < 8; ++i) + printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]); + printf(" "); + for (i = 8; i < 16; ++i) + printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]); + printf("\n"); + } + } else if (!strcasecmp(av[0], "dis")) { + int r; + u_char *ap = (u_char *)(((u_long)ds << 4) + di); + + if (ac > 1) { + char *c; + if (c = strchr(av[1], ':')) { + ds = strtol(av[1], 0, 16); + di = strtol(c+1, 0, 16); + } else + di = strtol(av[1], 0, 16); + } + if (ac > 2) + cnt = strtol(av[2], 0, 0); + + for (r = 0; r < cnt; ++r) { + char buf[16]; + int c = i386dis(ds, di, ap, buf, 0); + printf("%04x:%04x %s\n", ds, di, buf); + di += c; + ap += c; + } + } else if (!strcasecmp(av[0], "regs")) { + dump_regs(sc); + } else if (!strcasecmp(av[0], "force")) { + char *p = av[1]; + + while (p = *++av) { + while (*p) { + if (*p >= ' ' && *p <= '~') + KbdWrite(ScanCodes[Ascii2Scan[*p] & 0xff].base); + ++p; + } + } + KbdWrite(ScanCodes[28].base); + } else if (!strcasecmp(av[0], "bell")) { +#ifndef NO_X + XBell(dpy, 0); + XFlush(dpy); +#endif + } else { + fprintf(stderr, "%s: unknown command\n", av[0]); + } + } + + if (ep < ibuf + icnt) { + char *f = ep; + char *t = ibuf; + icnt -= ep - ibuf; + while (icnt--) + *t++ = *f++; + } else + icnt = 0; + ibuf[icnt] = 0; + } +} + +unsigned char +inb_port60(int port) +{ + int r = break_code; + break_code = 0; + scan_code = 0xffff; + return(r); +} + +void +kbd_event(int fd, REGISTERS) +{ + kbd_read = 0; + + printf("kbd_event: fd=%d\n", fd); + if ((break_code = read_raw_kbd(fd, &scan_code)) != 0xffff) + hardint(0x09); +} + +void +int09(REGISTERS) +{ + if (raw_kbd) { + if (scan_code != 0xffff) { + KbdWrite(scan_code); + break_code = 0; + scan_code = 0xffff; +#if 0 + kbd_event(kbd_fd, sc); +#endif + } + } +} + +u_short +read_raw_kbd(int fd, u_short *code) +{ + unsigned char c; + unsigned char oldled = K4_STATUS & 0x7; + + *code = 0xffff; + + if (read(fd, &c, 1) == 1) { + if (c == 0xe0) { + K3_STATUS |= K3_TWOBYTE; + return(c); + } + switch (c) { + case 29: /* Control */ + K1_STATUS |= K1_CTRL; + if (K3_STATUS & K3_TWOBYTE) + K3_STATUS |= K3_RCTRL; + else + K2_STATUS |= K2_LCTRL; + break; + case 29 | 0x80: /* Control */ + K1_STATUS &= ~K1_CTRL; + if (K3_STATUS & K3_TWOBYTE) + K3_STATUS &= ~K3_RCTRL; + else + K2_STATUS &= ~K2_LCTRL; + break; + + case 42: /* left shift */ + K1_STATUS |= K1_LSHIFT; + break; + case 42 | 0x80: /* left shift */ + K1_STATUS &= ~K1_LSHIFT; + break; + + case 54: /* right shift */ + K1_STATUS |= K1_RSHIFT; + break; + case 54 | 0x80: /* right shift */ + K1_STATUS &= ~K1_RSHIFT; + break; + + case 56: /* Alt */ + K1_STATUS |= K1_ALT; + if (K3_STATUS & K3_TWOBYTE) + K3_STATUS |= K3_RALT; + else + K2_STATUS |= K2_LALT; + break; + case 56 | 0x80: /* Alt */ + K1_STATUS &= ~K1_ALT; + if (K3_STATUS & K3_TWOBYTE) + K3_STATUS &= ~K3_RALT; + else + K2_STATUS &= ~K2_LALT; + break; + + case 58: /* caps-lock */ + K1_STATUS ^= K1_CLOCK; + if (K1_STATUS & K1_CLOCK) + K4_STATUS |= K4_CLOCK_LED; + else + K4_STATUS &= ~K4_CLOCK_LED; + K2_STATUS |= K2_CLOCK; + break; + case 58 | 0x80: /* caps-lock */ + K2_STATUS &= ~K2_CLOCK; + break; + + case 69: /* num-lock */ + K1_STATUS ^= K1_NLOCK; + if (K1_STATUS & K1_NLOCK) + K4_STATUS |= K4_NLOCK_LED; + else + K4_STATUS &= ~K4_NLOCK_LED; + K2_STATUS |= K2_NLOCK; + break; + case 69 | 0x80: /* num-lock */ + K2_STATUS &= ~K2_NLOCK; + break; + + case 70: /* scroll-lock */ + K1_STATUS ^= K1_SLOCK; + if (K1_STATUS & K1_SLOCK) + K4_STATUS |= K4_SLOCK_LED; + else + K4_STATUS &= ~K4_SLOCK_LED; + K2_STATUS |= K2_SLOCK; + break; + case 70 | 0x80: /* scroll-lock */ + K2_STATUS &= ~K2_SLOCK; + break; + + case 82: /* insert */ + K1_STATUS ^= K1_INSERT; + K2_STATUS |= K2_INSERT; + break; + case 82 | 0x80: /* insert */ + K2_STATUS &= ~K2_INSERT; + break; + + } + +#if 0 /*XXXXX*/ + if ((K4_STATUS & 0x07) != oldled) { + oldled = K4_STATUS & 0x07; + ioctl (fd, PCCONIOCSETLED, &oldled); + } +#endif + + if (c == 83 && (K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) + quit(0); + + if (c < 89) { + u_short scode; + + if (K1_STATUS & K1_ALT) { + scode = ScanCodes[c].alt; + } else if (K1_STATUS & K1_CTRL) { + scode = ScanCodes[c].ctrl; + } else if (K1_STATUS & K1_SHIFT) { + scode = ScanCodes[c].shift; + } else { + scode = ScanCodes[c].base; + if (K1_STATUS & K1_CLOCK) { + if (islower(scode & 0xff)) { + scode = (scode & 0xff00) | toupper(scode & 0xff); + } + } + if ((K1_STATUS & K1_NLOCK) && (K3_STATUS & K3_TWOBYTE) == 0) { + switch (c) { + case 71: /* home */ + case 72: /* cursor up */ + case 73: /* page up */ + case 75: /* cursor left */ + case 76: /* center key */ + case 77: /* cursor right */ + case 79: /* end */ + case 80: /* cursor down */ + case 81: /* page down */ + case 82: /* insert */ + case 83: /* delete */ + scode = ScanCodes[c].shift; + break; + } + } + } + *code = scode; + } + K3_STATUS &= ~K3_TWOBYTE; + if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) { + switch (c) { + case 0x13: /* R */ + kill(getpid(), SIGALRM); /* force redraw */ +printf("FORCED REDRAW\n"); + return(0xffff); + case 0x14: /* T */ + tmode ^= 1; + if (!tmode) + resettrace(&saved_sigframe->sf_sc); + return(0xffff); + case 0x53: /* DEL */ + quit(0); + } + } + return(c); + } else { + return(0xffff); + } +} + +void +video_async_event(int fd, regcontext_t *REGS) +{ +#ifndef NO_X + int int09 = 0; + + for (;;) { + int x; + fd_set fdset; + XEvent ev; + static struct timeval tv = { 0 }; + + /* + * Handle any events just sitting around... + */ + XFlush(dpy); + while (QLength(dpy) > 0) { + XNextEvent(dpy, &ev); + int09 |= video_event(&ev); + } + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + x = select(FD_SETSIZE, &fdset, 0, 0, &tv); + + switch (x) { + case -1: + /* + * Errno might be wrong, so we just select again. + * This could cause a problem is something really + * was wrong with select.... + */ + perror("select"); + return; + case 0: + XFlush(dpy); + if (int09) + hardint(0x09); + return; + default: + if (FD_ISSET(fd, &fdset)) { + do { + XNextEvent(dpy, &ev); + int09 |= video_event(&ev); + } while (QLength(dpy)); + } + break; + } + } +#endif +} + +void +kbd_async_event(int fd, REGISTERS) +{ + unsigned char c; + + unsigned char oldled = K4_STATUS & 0x7; + + while (read(fd, &c, 1) == 1) { + switch (c) { + case 29: /* Control */ + K1_STATUS |= K1_CTRL; + K2_STATUS |= K2_LCTRL; + break; + case 29 | 0x80: /* Control */ + K1_STATUS &= ~K1_CTRL; + K2_STATUS &= ~K2_LCTRL; + break; + + case 42: /* left shift */ + K1_STATUS |= K1_LSHIFT; + break; + case 42 | 0x80: /* left shift */ + K1_STATUS &= ~K1_LSHIFT; + break; + + case 54: /* right shift */ + K1_STATUS |= K1_RSHIFT; + break; + case 54 | 0x80: /* right shift */ + K1_STATUS &= ~K1_RSHIFT; + break; + + case 56: /* Alt */ + K1_STATUS |= K1_ALT; + K2_STATUS |= K2_LALT; + break; + case 56 | 0x80: /* Alt */ + K1_STATUS &= ~K1_ALT; + K2_STATUS &= ~K2_LALT; + break; + + case 58: /* caps-lock */ + if (K1_STATUS ^= K1_CLOCK) + K4_STATUS &= ~K4_CLOCK_LED; + else + K4_STATUS |= K4_CLOCK_LED; + K2_STATUS |= K2_CLOCK; + break; + case 58 | 0x80: /* caps-lock */ + K2_STATUS &= ~K2_CLOCK; + break; + + case 69: /* num-lock */ + if (K1_STATUS ^= K1_CLOCK) + K4_STATUS &= ~K4_NLOCK_LED; + else + K4_STATUS |= K4_NLOCK_LED; + K2_STATUS |= K2_NLOCK; + break; + case 69 | 0x80: /* num-lock */ + K2_STATUS &= ~K2_NLOCK; + break; + + case 70: /* scroll-lock */ + if (K1_STATUS ^= K1_SLOCK) + K4_STATUS &= ~K4_SLOCK_LED; + else + K4_STATUS |= K4_SLOCK_LED; + K2_STATUS |= K2_SLOCK; + break; + case 70 | 0x80: /* scroll-lock */ + K2_STATUS &= ~K2_SLOCK; + break; + + case 82: /* insert */ + K1_STATUS ^= K1_INSERT; + K2_STATUS |= K2_INSERT; + break; + case 82 | 0x80: /* insert */ + K2_STATUS &= ~K2_INSERT; + break; + + } + + } + +#if 0 /*XXXXX*/ + if ((K4_STATUS & 0x07) != oldled) { + oldled = K4_STATUS & 0x07; + ioctl (fd, PCCONIOCSETLED, &oldled); + } +#endif +} + +#ifndef NO_X +int +video_event(XEvent *ev) +{ + switch (ev->type) { + case MotionNotify: { + XMotionEvent *me = (XMotionEvent *)ev; + me->x -= 2; + me->y -= 2; + + mouse_status.x = (me->x < mouse_status.range.x) + ? mouse_status.range.x + : (me->x > mouse_status.range.w) + ? mouse_status.range.w : me->x; + mouse_status.y = (me->y < mouse_status.range.y) + ? mouse_status.range.y + : (me->y > mouse_status.range.h) + ? mouse_status.range.h : me->y; + break; + } + case ButtonRelease: { + XButtonEvent *be = (XButtonEvent *)ev; + be->x -= 2; + be->y -= 2; + + if (be->button < 3) + mouse_status.ups[be->button]++; + + mouse_status.x = (be->x < mouse_status.range.x) + ? mouse_status.range.x + : (be->x > mouse_status.range.w) + ? mouse_status.range.w : be->x; + mouse_status.y = (be->y < mouse_status.range.y) + ? mouse_status.range.y + : (be->y > mouse_status.range.h) + ? mouse_status.range.h : be->y; + break; + } + case ButtonPress: { + XButtonEvent *be = (XButtonEvent *)ev; + be->x -= 2; + be->y -= 2; + + if (be->button < 3) + mouse_status.downs[be->button]++; + + mouse_status.x = (be->x < mouse_status.range.x) + ? mouse_status.range.x + : (be->x > mouse_status.range.w) + ? mouse_status.range.w : be->x; + mouse_status.y = (be->y < mouse_status.range.y) + ? mouse_status.range.y + : (be->y > mouse_status.range.h) + ? mouse_status.range.h : be->y; + + if ((K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) { + quit(0); + } + break; + } + case NoExpose: + break; + case GraphicsExpose: + case Expose: { + int r; + for (r = 0; r < height; ++r) + lines[r].changed = 1; + break; + } + case KeyRelease: { + static char buf[128]; + KeySym ks; + int n; + + break_code |= 0x80; + + if (!(ev->xkey.state & ShiftMask)) { + K1_STATUS &= ~K1_LSHIFT; + K1_STATUS &= ~K1_RSHIFT; + } + if (!(ev->xkey.state & ControlMask)) { + K1_STATUS &= ~K1_CTRL; + K2_STATUS &= ~K2_LCTRL; + K3_STATUS &= ~K3_RCTRL; + } + if (!(ev->xkey.state & Mod1Mask)) { + K1_STATUS &= ~K1_ALT; + K2_STATUS &= ~K2_LALT; + K3_STATUS &= ~K3_RALT; + } + if (!(ev->xkey.state & LockMask)) { + K2_STATUS &= ~K2_CLOCK; + } + + XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0); + switch (ks) { + case XK_Shift_L: + K1_STATUS &= ~K1_LSHIFT; + break; + case XK_Shift_R: + K1_STATUS &= ~K1_RSHIFT; + break; + case XK_Control_L: + K1_STATUS &= ~K1_CTRL; + K2_STATUS &= ~K2_LCTRL; + break; + case XK_Control_R: + K1_STATUS &= ~K1_CTRL; + K3_STATUS &= ~K3_RCTRL; + break; + case XK_Alt_L: + K1_STATUS &= ~K1_ALT; + K2_STATUS &= ~K2_LALT; + break; + case XK_Alt_R: + K1_STATUS &= ~K1_ALT; + K3_STATUS &= ~K3_RALT; + break; + case XK_Scroll_Lock: + K2_STATUS &= ~K2_SLOCK; + break; + case XK_Num_Lock: + K2_STATUS &= ~K2_NLOCK; + break; + case XK_Caps_Lock: + K2_STATUS &= ~K2_CLOCK; + break; + case XK_Insert: + K2_STATUS &= ~K2_INSERT; + break; + } + return(1); + } + case KeyPress: { + static char buf[128]; + KeySym ks; + int n; + int nlock = 0; + u_short scan = 0xffff; + + if (!(ev->xkey.state & ShiftMask)) { + K1_STATUS &= ~K1_LSHIFT; + K1_STATUS &= ~K1_RSHIFT; + } + if (!(ev->xkey.state & ControlMask)) { + K1_STATUS &= ~K1_CTRL; + K2_STATUS &= ~K2_LCTRL; + K3_STATUS &= ~K3_RCTRL; + } + if (!(ev->xkey.state & Mod1Mask)) { + K1_STATUS &= ~K1_ALT; + K2_STATUS &= ~K2_LALT; + K3_STATUS &= ~K3_RALT; + } + if (!(ev->xkey.state & LockMask)) { + K2_STATUS &= ~K2_CLOCK; + } + + n = XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0); + + switch (ks) { + case XK_Shift_L: + K1_STATUS |= K1_LSHIFT; + break; + case XK_Shift_R: + K1_STATUS |= K1_RSHIFT; + break; + case XK_Control_L: + K1_STATUS |= K1_CTRL; + K2_STATUS |= K2_LCTRL; + break; + case XK_Control_R: + K1_STATUS |= K1_CTRL; + K3_STATUS |= K3_RCTRL; + break; + case XK_Alt_L: + K1_STATUS |= K1_ALT; + K2_STATUS |= K2_LALT; + break; + case XK_Alt_R: + K1_STATUS |= K1_ALT; + K3_STATUS |= K3_RALT; + break; + case XK_Scroll_Lock: + K1_STATUS ^= K1_SLOCK; + K2_STATUS |= K2_SLOCK; + break; + case XK_Num_Lock: + K1_STATUS ^= K1_NLOCK; + K2_STATUS |= K2_NLOCK; + break; + case XK_Caps_Lock: + K1_STATUS ^= K1_CLOCK; + K2_STATUS |= K2_CLOCK; + break; + case XK_Insert: + K1_STATUS ^= K1_INSERT; + K2_STATUS |= K2_INSERT; + scan = 82; + goto docode; + + case XK_Escape: + scan = 1; + goto docode; + + case XK_Tab: + scan = 15; + goto docode; + + case XK_Return: + case XK_KP_Enter: + scan = 28; + goto docode; + + case XK_Print: + scan = 55; + goto docode; + + case XK_F1: + case XK_F2: + case XK_F3: + case XK_F4: + case XK_F5: + case XK_F6: + case XK_F7: + case XK_F8: + case XK_F9: + case XK_F10: + scan = ks - XK_F1 + 59; + goto docode; + + case XK_KP_7: + nlock = 1; + case XK_Home: + scan = 71; + goto docode; + case XK_KP_8: + nlock = 1; + case XK_Up: + scan = 72; + goto docode; + case XK_KP_9: + nlock = 1; + case XK_Prior: + scan = 73; + goto docode; + case XK_KP_Subtract: + scan = 74; + goto docode; + case XK_KP_4: + nlock = 1; + case XK_Left: + scan = 75; + goto docode; + case XK_KP_5: + nlock = 1; + case XK_Begin: + scan = 76; + goto docode; + case XK_KP_6: + nlock = 1; + case XK_Right: + scan = 77; + goto docode; + case XK_KP_Add: + scan = 78; + goto docode; + case XK_KP_1: + nlock = 1; + case XK_End: + scan = 79; + goto docode; + case XK_KP_2: + nlock = 1; + case XK_Down: + scan = 80; + goto docode; + case XK_KP_3: + nlock = 1; + case XK_Next: + scan = 81; + goto docode; + case XK_KP_0: + nlock = 1; + /* case XK_Insert: This is above */ + scan = 82; + goto docode; + + case XK_KP_Decimal: + nlock = 1; + scan = 83; + goto docode; + + case XK_Delete: + scan = flipdelete ? 14 : 83; + goto docode; + + case XK_BackSpace: + scan = flipdelete ? 83 : 14; + goto docode; + + case XK_F11: + scan = 87; + goto docode; + case XK_F12: + scan = 88; + goto docode; + + + case XK_KP_Divide: + scan = Ascii2Scan['/']; + goto docode; + + case XK_KP_Multiply: + scan = Ascii2Scan['*']; + goto docode; + + default: + if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) { + if (ks == 'T' || ks == 't') { + tmode ^= 1; + if (!tmode) + resettrace(&saved_sigframe->sf_sc); + break; + } + if (ks == 'R' || ks == 'r') { + kill(getpid(), SIGALRM); /* redraw */ + break; + } + } + if (ks < ' ' || ks > '~') + break; + scan = Ascii2Scan[ks]; + docode: + if (nlock) + scan |= 0x100; + + if ((scan & ~0x100) > 88) { + scan = 0xffff; + break; + } + + if ((K1_STATUS & K1_SHIFT) || (scan & 0x100)) { + scan = ScanCodes[scan & 0xff].shift; + } else if (K1_STATUS & K1_CTRL) { + scan = ScanCodes[scan & 0xff].ctrl; + } else if (K1_STATUS & K1_ALT) { + scan = ScanCodes[scan & 0xff].alt; + } else + scan = ScanCodes[scan & 0xff].base; + + break; + } + if (scan != 0xffff) { + break_code = scan >> 8; + KbdWrite(scan); + } + return(1); + } + default: + break; + } + return(0); +} +#endif + +#define R03D4 BIOSDATA[0x65] +static u_char R03BA = 0; +static u_char R03DA = 0; + +unsigned char +video_inb(int port) +{ + switch(port) { + case CGA_Status: + R03DA += 1; /* Just cylce throught the values */ + return(R03DA &= 0x0f); + case 0x03c2: /* Misc */ + case 0x03cc: /* Misc */ + return(0xc3); + case CVC_Data: + if (R03D4 < 0x10) { + return(VREG[R03D4]); + } + break; + } +} + +void +video_outb(int port, unsigned char value) +{ + int cp; + + switch(port) { + case 0x03cc: + case 0x03c2: + if ((value & 0x1) == 0) /* Trying to request monochrome */ + break; + return; + case CGA_Control: + if (value & 0x22) /* Trying to select graphics */ + break; + return; + case CVC_Address: + R03D4 = value & 0x1f; + return; + case CVC_Data: + if (R03D4 > 0x0f) + break; + VREG[R03D4] = value; + switch (R03D4) { + case MVC_CurHigh: + cp = row * width + col; + cp &= 0xff; + cp |= (value << 8) & 0xff00; + row = cp / width; + col = cp % width; + break; + case MVC_CurLow: + cp = row * width + col; + cp &= 0xff00; + cp |= value & 0xff; + row = cp / width; + col = cp % width; + break; + } + return; + } +} + +void +tty_move(int r, int c) +{ + row = r; + col = c; + SetVREGCur(); +} + +void +tty_report(int *r, int *c) +{ + *r = row; + *c = col; +} + +void +tty_flush() +{ + K_NEXT = K_FREE = 0; +} + +void +tty_index() +{ + int i; + + if (row > (height - 1)) + row = 0; + else if (++row >= height) { + row = height - 1; + memcpy(vmem, &vmem[width], 2 * width * (height - 1)); + for (i = 0; i < width; ++i) + vmem[(height - 1) * width + i] = vattr | ' '; + } + SetVREGCur(); +} + +void +tty_write(int c, int attr) +{ + if (attr == TTYF_REDIRECT) { + if (redirect1) { + char tc = c; + write(1, &c, 1); + return; + } + attr = -1; + } + if (capture_fd >= 0) { + char cc = c; + write(capture_fd, &cc, 1); + } + c &= 0xff; + switch (c) { + case 0x07: + if (xmode) { +#ifndef NO_X + XBell(dpy, 0); +#endif + } else + write(1, "\007", 1); + break; + case 0x08: + if (row > (height - 1) || col > width) + break; + if (col > 0) + --col; + vmem[row * width + col] &= 0xff00; + break; + case '\t': + if (row > (height - 1)) + row = 0; + col = (col + 8) & ~0x07; + if (col > width) { + col = 0; + tty_index(); + } + break; + case '\r': + col = 0; + break; + case '\n': + tty_index(); + break; + default: + if (col >= width) { + col = 0; + tty_index(); + } + if (row > (height - 1)) + row = 0; + if (attr >= 0) + vmem[row * width + col] = attr & 0xff00; + else + vmem[row * width + col] &= 0xff00; + vmem[row * width + col++] |= c; + break; + } + SetVREGCur(); +} + +void +tty_rwrite(int n, int c, int attr) +{ + u_char srow, scol; + c &= 0xff; + + srow = row; + scol = col; + while (n--) { + if (col >= width) { + col = 0; + tty_index(); + } + if (row > (height - 1)) + row = 0; + if (attr >= 0) + vmem[row * width + col] = attr & 0xff00; + else + vmem[row * width + col] &= 0xff00; + vmem[row * width + col++] |= c; + } + row = srow; + col = scol; + SetVREGCur(); +} + +void +tty_pause() +{ + sigset_t set; + + sigprocmask(0, 0, &set); + sigdelset(&set, SIGIO); + sigdelset(&set, SIGALRM); + sigsuspend(&set); +} + +static int nextchar = 0; + +int +tty_read(REGISTERS, int flag) +{ + int r; + + if (r = nextchar) { + nextchar = 0; + return(r & 0xff); + } + + if ((flag & TTYF_REDIRECT) && redirect0) { + char c; + if (read(0, &c, 1) != 1) + return(-1); + if (c == '\n') + c = '\r'; + return(c); + } + + if (KbdEmpty()) { + if (flag & TTYF_BLOCK) { + while (KbdEmpty()) + tty_pause(); + } else { + return(-1); + } + } + + r = KbdRead(); + if ((r & 0xff) == 0) + nextchar = r >> 8; + r &= 0xff; + if (flag & TTYF_CTRL) { + if (r == 3) { + /* + * XXX - Not quite sure where we should return, maybe not + * all the way to the user, but... + */ + if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) { + fake_int(sc, 0x23); + SET16(sc->sc_eip, GET16(sc->sc_eip) - 2); + return(-2); + } + } + } + if (flag & TTYF_ECHO) { + if ((flag & TTYF_ECHONL) && (r == '\n' || r == '\r')) { + tty_write('\r', -1); + tty_write('\n', -1); + } else + tty_write(r, -1); + } + return(r & 0xff); +} + +int +tty_peek(REGISTERS, int flag) +{ + int c; + + if (c == nextchar) + return(nextchar & 0xff); + + if (KbdEmpty()) { + if (flag & TTYF_POLL) { + sleep_poll(); + if (KbdEmpty()) + return(0); + } else if (flag & TTYF_BLOCK) { + while (KbdEmpty()) + tty_pause(); + } else + return(0); + } + c = KbdPeek(); + if ((c & 0xff) == 3) { + /* + * XXX - Not quite sure where we should return, maybe not + * all the way to the user, but... + */ + if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) { + fake_int(sc, 0x23); + SET16(sc->sc_eip, GET16(sc->sc_eip) - 2); + return(-2); + } + } + return(0xff); +} + +int +tty_state() +{ + return(K1_STATUS); +} + +tty_estate() +{ + int state = 0; + if (K2_STATUS & K2_SYSREQ) + state |= 0x80; + if (K2_STATUS & K2_CLOCK) + state |= 0x40; + if (K2_STATUS & K2_NLOCK) + state |= 0x20; + if (K2_STATUS & K2_SLOCK) + state |= 0x10; + if (K3_STATUS & K3_RALT) + state |= 0x08; + if (K3_STATUS & K3_RCTRL) + state |= 0x04; + if (K2_STATUS & K2_LALT) + state |= 0x02; + if (K2_STATUS & K2_LCTRL) + state |= 0x01; + return(state); +} + +inline int +inrange(int a, int n, int x) +{ + return(a < n ? n : a > x ? x : a); +} + +void +tty_scroll(int sr, int sc, int er, int ec, int n, int attr) +{ + int i, j; + + sr = inrange(sr, 0, height); + er = inrange(er, 0, height); + sc = inrange(sc, 0, width); + ec = inrange(ec, 0, width); + if (sr > er || sc > ec) + return; + ++er; + ++ec; + + attr &= 0xff00; + attr |= ' '; + + if (n > 0 && n < er - sr) { + for (j = sr; j < er - n; ) { + memcpy(&vmem[j * width + sc], + &vmem[(j + n) * width + sc], + sizeof(vmem[0]) * (ec - sc)); + ++j; + } + } else + n = er - sr; + for (j = er - n; j < er; ) { + for (i = sc; i < ec; ++i) + vmem[j * width + i] = attr; + ++j; + } +} + +void +tty_rscroll(int sr, int sc, int er, int ec, int n, int attr) +{ + int i, j; + + sr = inrange(sr, 0, height); + er = inrange(er, 0, height); + sc = inrange(sc, 0, width); + ec = inrange(ec, 0, width); + if (sr > er || sc > ec) + return; + ++er; + ++ec; + + attr &= 0xff00; + attr |= ' '; + + if (n > 0 && n < er - sr) { + for (j = er; j > sr + n; ) { + --j; + memcpy(&vmem[j * width + sc], + &vmem[(j - n) * width + sc], + sizeof(vmem[0]) * (ec - sc)); + } + } else + n = er - sr; + for (j = sr + n; j > sr; ) { + --j; + for (i = sc; i < ec; ++i) + vmem[j * width + i] = attr; + } +} + +int +tty_char(int r, int c) +{ + if (r == -1) + r = row; + if (c == -1) + c = col; + r = inrange(r, 0, height); + c = inrange(c, 0, width); + return(vmem[r * width + c]); +} + +int +KbdEmpty() +{ + return(K_NEXT == K_FREE); +} + +void +KbdWrite(u_short code) +{ + int klen = K_BUFEND - K_BUFSTART; + int kf = (K_FREE + 1) % klen; + if (kf == K_NEXT) { +#ifndef NO_X + XBell(dpy, 0); +#endif + return; + } + K_BUFSTART[K_FREE] = code; + K_FREE = kf; +} + +void +KbdRepl(u_short code) +{ + K_BUFSTART[K_NEXT] = code; +} + +u_short +KbdRead() +{ + int klen = K_BUFEND - K_BUFSTART; + int kf = K_NEXT; + K_NEXT = (K_NEXT + 1) % klen; + return(K_BUFSTART[kf]); +} + +u_short +KbdPeek() +{ + return(K_BUFSTART[K_NEXT]); +} + +void int10(REGISTERS); + +void +video_init() +{ + u_long vec; +#ifndef NO_X + XSizeHints sh; + XGCValues gcv; + XColor ccd, rgb; +#endif + unsigned long mask; + int level; + int i, j; + + VREG = (u_char *)malloc(32); + + /* + * Define all known I/O port handlers + */ + define_input_port_handler(0x60, inb_port60); + + if (!raw_kbd) { + define_input_port_handler(CGA_Status, video_inb); + define_input_port_handler(0x03c2, video_inb); + define_input_port_handler(0x03cc, video_inb); + define_input_port_handler(CVC_Data, video_inb); + define_output_port_handler(CGA_Control, video_outb); + define_output_port_handler(0x03c2, video_outb); + define_output_port_handler(0x03cc, video_outb); + define_output_port_handler(CVC_Address, video_outb); + define_output_port_handler(CVC_Data, video_outb); + } + + redirect0 = isatty(0) == 0 || !xmode ; + redirect1 = isatty(1) == 0 || !xmode ; + redirect2 = isatty(2) == 0 || !xmode ; + + K_BUFSTARTP = 0x1e; /* Start of keyboard buffer */ + K_BUFENDP = 0x3e; /* End of keyboard buffer */ + K_NEXT = K_FREE = 0x00; + + vec = insert_hardint_trampoline(); + ivec[0x09] = vec; + register_callback(vec, int09, "int 09"); + + /* + * Initialize video memory with black background, white foreground + */ + for (i = 0; i < height * width; ++i) + vmem[i] = vattr; + + if (!xmode) + return; + +#ifndef NO_X + if (!(lines = (TextLine *)malloc(sizeof(TextLine) * height))) { + fprintf(stderr, "Could not allocate data structure for text lines\n"); + quit(1); + } + for (i = 0; i < height; ++i) { + lines[i].max_length = width; + if (!(lines[i].data = (u_short *)malloc(width * sizeof(u_short)))) { + fprintf(stderr, + "Could not allocate data structure for text lines\n"); + quit(1); + } + lines[i].changed = 1; + } + + + { + /* + * Arg... I can no longer change X's fd out from under it. + * Open up all the available fd's, leave 3 behind for X + * to play with, open X and then release all the other fds + */ + int nfds = sysconf(_SC_OPEN_MAX); + int *fds = malloc(sizeof(int) * nfds); + i = 0; + if (fds) + for (i = 0; i < nfds && (i == 0 || fds[i-1] < 63); ++i) + if ((fds[i] = open("/dev/null", 0)) < 0) + break; + /* + * Leave 3 fds behind for X to play with + */ + if (i > 0) close(fds[--i]); + if (i > 0) close(fds[--i]); + if (i > 0) close(fds[--i]); + + dpy = XOpenDisplay(NULL); + + while (i > 0) + close(fds[--i]); + } + + if (dpy == NULL) { + fprintf(stderr, "Could not open display ``%s''\n", + XDisplayName(NULL)); + quit(1); + } + xfd = ConnectionNumber(dpy); + + _RegisterIO(xfd, video_async_event, xfd, Failure); + if (debug_flags & D_DEBUGIN) + _RegisterIO(0, debug_event, 0, Failure); + _BlockIO(); + + pixels[0] = BlackPixel(dpy, DefaultScreen(dpy)); + pixels[15] = WhitePixel(dpy, DefaultScreen(dpy)); + for (i = 0; i < 15; ++i) { + if (XAllocNamedColor(dpy, + DefaultColormap(dpy, DefaultScreen(dpy)), + color_names[i], &ccd, &rgb)) { + pixels[i] = ccd.pixel; + } else if (i < 7) + pixels[i] = pixels[0]; + else + pixels[i] = pixels[15]; + } + + if (!xfont) + xfont = IBMFONT; + + font = XLoadQueryFont(dpy, xfont); + + if (font == NULL) + font = XLoadQueryFont(dpy, IBMFONT); + + if (font == NULL) { + fprintf(stderr, "Could not open font ``%s''\n", xfont); + quit(1); + } + + FW = font->max_bounds.width; + FH = font->max_bounds.ascent + font->max_bounds.descent; + FD = font->max_bounds.descent; + + curs_start = 6; + curs_end = 7; + + sh.width = FW * width + 4; + sh.height = FH * height + 4; + + sh.width += 4; + sh.height += 4; + + sh.min_width = sh.max_width = sh.width; + sh.min_height = sh.max_height = sh.height; + + sh.flags = USSize | PMinSize | PMaxSize | PSize; + + win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, + sh.width, sh.height, 2, black, black); + if (win == NULL) { + fprintf(stderr, "Could not create window\n"); + quit(1); + } + + gcv.foreground = white; + gcv.background = black; + gcv.font = font->fid; + + mask = GCForeground | GCBackground | GCFont; + + gc = XCreateGC(dpy, win, mask, &gcv); + + gcv.foreground = 1; + gcv.background = 0; + gcv.function = GXxor; + cgc = XCreateGC(dpy, win, GCForeground|GCBackground|GCFunction, &gcv); + + XSetNormalHints(dpy, win, &sh); + if (raw_kbd) { + XSelectInput(dpy, win, ExposureMask | ButtonPressMask + | ButtonReleaseMask | PointerMotionMask ); + } else { + XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask | + ExposureMask | ButtonPressMask + | ButtonReleaseMask | PointerMotionMask ); + } + + XMapWindow(dpy, win); + XFlush(dpy); + + _UnblockIO(); +#endif +} + +void +video_bios_init() +{ + u_char *p; + u_long vec; + + if (raw_kbd) + return; + + /* + * Put the Video Save Pointer table @ C000:0000 + * Put the Secondary Video Save Pointer table @ C000:0020 + * Put the Display Combination code table @ C000:0040 + * Put the Video Parameter table @ C000:1000 - C000:2FFF + * Put the default Font @ C000:3000 - C000:3FFF + */ + + *(u_long *)&BIOSDATA[0xA8] = 0xC0000000; /* 0040:00A8 points to us */ + + vsp = (struct VideoSavePointerTable *)0xC0000L; + memset(vsp, 0, sizeof(struct VideoSavePointerTable)); + svsp = (struct SecondaryVideoSavePointerTable *)0xC0020L; + + vsp->video_parameter_tabel[0] = 0x1000; + vsp->video_parameter_tabel[1] = 0xC000; + + vsp->secondary_save_pointer_table[0] = 0x0020; + vsp->secondary_save_pointer_table[1] = 0xC000; + + svsp->display_combination_code_table[0] = 0x0040; + svsp->display_combination_code_table[1] = 0xC000; + + p = (u_char *)0xC0040; + *p++ = 2; /* Only support 2 combinations currently */ + *p++ = 1; /* Version # */ + *p++ = 8; /* We wont use more than type 8 */ + *p++ = 0; /* Resereved */ + *p++ = 0; *p++ = 0; /* No Display No Display */ + *p++ = 0; *p++ = 8; /* No Display VGA Color */ + + memcpy((void *)0xC1000, videoparams, sizeof(videoparams)); + + ivec[0x1d] = 0xC0001000L; /* Video Parameter Table */ + ivec[0x1e] = 0xC0003000L; + ivec[0x42] = ivec[0x10]; /* Copy of video interrupt */ + memcpy((void *)0xC3000L, ascii_font, sizeof(ascii_font)); + + BIOSDATA[0x49] = 3; /* Video Mode */ + *(u_short *)&BIOSDATA[0x4a] = 80; /* Columns on Screen */ + *(u_short *)&BIOSDATA[0x4c] = 0; /* Page */ + *(u_short *)&BIOSDATA[0x4e] = 0; /* Offset into video memory */ + *(u_short *)&BIOSDATA[0x63] = 0x03d4; /* controller base reg */ + BIOSDATA[0x84] = 24; /* Rows on screen */ + *(u_short *)&BIOSDATA[0x85] = 16; /* font height */ + BIOSDATA[0x87] = 0; /* video ram etc. */ + BIOSDATA[0x88] = 0xf9; /* video switches */ + BIOSDATA[0x89] = 0x11; /* video stats */ + BIOSDATA[0x8a] = 1; /* Index into DCC table */ + BIOSDATA[0x96] = 0x10; + K1_STATUS = 0; + K2_STATUS = 0; + K3_STATUS = 0; + K4_STATUS = 0; + + vec = insert_softint_trampoline(); + ivec[0x10] = vec; + register_callback(vec, int10, "int 10"); +} |