6f000118458ac536a30ddd500e849c0394a4a6d2
[dragonfly.git] / usr.bin / doscmd / tty.c
1 /*
2  * Copyright (c) 1992, 1993, 1996
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Berkeley Software
16  *      Design, Inc.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      BSDI tty.c,v 2.4 1996/04/08 22:03:27 prb Exp
31  *
32  * $FreeBSD: src/usr.bin/doscmd/tty.c,v 1.8.2.2 2002/04/25 11:04:51 tg Exp $
33  * $DragonFly: src/usr.bin/doscmd/tty.c,v 1.6 2004/01/26 18:16:18 drhodus Exp $
34  */
35
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/mman.h>
40 #include <ctype.h>
41 #include <err.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <paths.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <termios.h>
48 #include <unistd.h>
49 #ifdef __DragonFly__ 
50 # include <osreldate.h>
51 # include <machine/console.h>
52 #endif
53
54 #ifndef NO_X
55 #include <X11/Xlib.h>
56 #include <X11/Xutil.h>
57 #include <X11/keysym.h>
58 #endif
59
60 #include "doscmd.h"
61 #include "AsyncIO.h"
62 #include "font8x8.h"
63 #include "font8x14.h"
64 #include "font8x16.h"
65 #include "mouse.h"
66 #include "trap.h"
67 #include "tty.h"
68 #include "video.h"
69
70 #ifndef NO_X
71 static int show = 1;
72 #endif
73 static int blink = 1;
74 int flipdelete = 0;             /* Flip meaning of delete and backspace */
75 static u_short break_code = 0x00;
76 static u_short scan_code = 0x00;
77 int height;
78 int width;
79 int vattr;
80 const char *xfont = 0;
81
82 #ifndef NO_X
83 Display *dpy;
84 Window win;
85 XFontStruct *font;
86 XImage *xi = 0;
87 Visual *visual;
88 unsigned int depth;
89 unsigned long black;
90 unsigned long white;
91 int FW, FH, FD;
92 GC gc;
93 GC cgc;
94 int xfd;
95
96 /* LUT for the vram -> XImage conversion */
97 u_int8_t lut[4][256][8];
98
99 /* X pixel values for the RGB triples */
100 unsigned long pixels[16];
101 #endif
102
103 typedef struct TextLine {
104     u_short     *data;
105     u_char      max_length;     /* Not used, but here for future use */
106     u_char      changed:1;
107 } TextLine;
108 TextLine *lines = NULL;
109
110 int kbd_fd = -1;
111 int kbd_read = 0;
112
113 static struct termios tty_cook, tty_raw;
114
115 #define row (CursRow0)
116 #define col (CursCol0)
117
118 /* Local functions */
119 static void     _kbd_event(int, int, void *, regcontext_t *);
120 static void     Failure(void *);
121 static void     SetVREGCur(void);
122 static void     debug_event(int, int, void *, regcontext_t *);
123 static unsigned char    inb_port60(int);
124 static int      inrange(int, int, int);
125 static void     kbd_event(int, int, void *, regcontext_t *);
126 static u_short  read_raw_kbd(int, u_short *);
127 static void     setgc(u_short);
128 static void     video_async_event(int, int, void *, regcontext_t *);
129
130 #ifndef NO_X
131 static void     dac2rgb(XColor *, int);
132 static void     prepare_lut(void);
133 static void     putchar_graphics(int, int, int);
134 static void     tty_rwrite_graphics(int, int, int);
135 static int      video_event(XEvent *ev);
136 static void     video_update_graphics(void);
137 static void     video_update_text(void);
138 static void     vram2ximage(void);
139 #endif
140
141 #define PEEKSZ  16
142
143 #define K_NEXT          *(u_short *)0x41a
144 #define K_FREE          *(u_short *)0x41c
145 #define K_BUFSTARTP     *(u_short *)0x480
146 #define K_BUFENDP       *(u_short *)0x482
147 #define K_BUFSTART      ((u_short *)(0x400 + *(u_short *)0x480))
148 #define K_BUFEND        ((u_short *)(0x400 + *(u_short *)0x482))
149 #define K_BUF(i)        *((u_short *)((u_char *)0x400 + (i)))
150
151 #define K1_STATUS       BIOSDATA[0x17]
152 #define K1_RSHIFT       0x01
153 #define K1_LSHIFT       0x02
154 #define K1_SHIFT        0x03
155 #define K1_CTRL         0x04
156 #define K1_ALT          0x08
157 #define K1_SLOCK        0x10            /* Active */
158 #define K1_NLOCK        0x20            /* Active */
159 #define K1_CLOCK        0x40            /* Active */
160 #define K1_INSERT       0x80            /* Active */
161
162 #define K2_STATUS       BIOSDATA[0x18]
163 #define K2_LCTRL        0x01
164 #define K2_LALT         0x02
165 #define K2_SYSREQ       0x04
166 #define K2_PAUSE        0x08
167 #define K2_SLOCK        0x10            /* Actually held down */
168 #define K2_NLOCK        0x20            /* Actually held down */
169 #define K2_CLOCK        0x40            /* Actually held down */
170 #define K2_INSERT       0x80            /* Actually held down */
171
172 #define K3_STATUS       BIOSDATA[0x96]
173 #define K3_E1           0x01            /* Last code read was e1 */
174 #define K3_E2           0x02            /* Last code read was e2 */
175 #define K3_RCTRL        0x04
176 #define K3_RALT         0x08
177 #define K3_ENHANCED     0x10
178 #define K3_FORCENLOCK   0x20
179 #define K3_TWOBYTE      0x40            /* last code was first of 2 */
180 #define K3_READID       0x80            /* read ID in progress */
181
182 #define K4_STATUS       BIOSDATA[0x97]
183 #define K4_SLOCK_LED    0x01
184 #define K4_NLOCK_LED    0x02
185 #define K4_CLOCK_LED    0x04
186 #define K4_ACK          0x10            /* ACK recieved from keyboard */
187 #define K4_RESEND       0x20            /* RESEND recieved from keyboard */
188 #define K4_LED          0x40            /* LED update in progress */
189 #define K4_ERROR        0x80
190
191 static void
192 Failure(void *arg __unused)
193 {
194         fprintf(stderr, "X Connection shutdown\n");
195         quit(1);
196 }
197
198 static void
199 SetVREGCur(void)
200 {
201     int cp = row * width + col;
202     VGA_CRTC[CRTC_CurLocHi] = cp >> 8;
203     VGA_CRTC[CRTC_CurLocLo] = cp & 0xff;
204 }
205
206 static void
207 console_denit(void *arg)
208 {
209     int fd = *(int *)arg;
210
211 #if defined (__DragonFly__)
212     if (ioctl(fd, KDSKBMODE, K_XLATE))
213         perror("KDSKBMODE/K_XLATE");
214 #else
215 # ifdef __NetBSD__
216     if (ioctl(fd, CONSOLE_X_MODE_OFF, 0))
217         perror("CONSOLE_X_MODE_OFF");
218 # else /* BSD/OS */
219     if (ioctl(fd, PCCONIOCCOOK, 0))
220         perror("PCCONIOCCOOK");
221 # endif
222 #endif
223     if (tcsetattr(fd, TCSANOW, &tty_cook))
224         perror("tcsetattr");
225 }
226
227 void
228 _kbd_event(int fd, int cond, void *arg __unused, regcontext_t *REGS __unused)
229 {
230     if (!(cond & AS_RD))
231         return;
232     printf("_kbd_event: fd=%d\n", fd);
233     kbd_read = 1;
234 }
235
236 void
237 console_init(void)
238 {
239     int fd;
240     caddr_t addr;
241
242     if ((fd = open(_PATH_DEV "vga", 2)) < 0) {
243         perror(_PATH_DEV "vga");
244         quit(1);
245     }
246     addr = mmap((caddr_t)0xA0000, 5 * 64 * 1024,
247                 PROT_EXEC | PROT_READ | PROT_WRITE,
248                 MAP_FILE | MAP_FIXED | MAP_SHARED,
249                 fd, 0);
250     if (addr != (caddr_t)0xA0000) {
251         perror("mmap");
252         quit(1);
253     }
254
255 #if 0
256     addr = mmap((caddr_t)0x100000 - 0x1000, 0x1000,
257                 PROT_EXEC | PROT_READ | PROT_WRITE,
258                 MAP_FILE | MAP_FIXED | MAP_SHARED,
259                 fd, 0);
260     if (addr != (caddr_t)(0x100000 - 0x1000)) {
261         perror("mmap");
262         quit(1);
263     }
264 #endif
265
266     if ((fd = open(_PATH_CONSOLE, 2)) < 0) {
267         perror(_PATH_CONSOLE);
268         quit(1);
269     }
270
271     fd = squirrel_fd(fd);
272     kbd_fd = fd;
273
274 #if defined (__DragonFly__)
275     if (ioctl(fd, KDSKBMODE, K_RAW)) {
276         perror("KDSKBMODE/K_RAW");
277         quit(1);    
278     }
279 #else
280 # ifdef __NetBSD__
281     if (ioctl(fd, CONSOLE_X_MODE_ON, 0)) {
282         perror("CONSOLE_X_MODE_ON");
283         quit(1);    
284     }
285 # else /* BSD/OS */
286       if (ioctl(fd, PCCONIOCRAW, 0)) {
287         perror("PCCONIOCRAW");
288         quit(1);    
289       }
290 # endif
291 #endif
292
293     call_on_quit(console_denit, &kbd_fd);
294
295     if (fcntl(fd, F_SETFL, O_NDELAY|O_ASYNC) < 0) {
296         perror("fcntl");
297         quit(1);    
298     }
299     if (tcgetattr(fd, &tty_cook)) {
300         perror("tcgetattr");
301         quit(1);    
302     }
303     tty_raw = tty_cook;
304     cfmakeraw(&tty_raw);
305     if (tcsetattr(fd, TCSANOW, &tty_raw)) {
306         perror("tcsetattr");
307         quit(1);    
308     }
309
310 #if 0
311     _RegisterIO(STDIN_FILENO, debug_event, 0, Failure);
312     _RegisterIO(fd, kbd_event, 0, Failure);
313 #endif
314     _RegisterIO(fd, _kbd_event, 0, Failure);
315 }
316
317 void
318 video_setborder(int color)
319 {
320 #ifndef NO_X
321         XSetWindowBackground(dpy, win, pixels[color & 0xf]);
322 #endif
323 }
324 void
325 video_blink(int mode)
326 {
327         blink = mode;
328 }
329
330 static void
331 setgc(u_short attr)
332 {
333 #ifndef NO_X
334         XGCValues v;
335         if (blink && !show && (attr & 0x8000))
336                 v.foreground = pixels[(attr >> 12) & 0x07];
337         else
338                 v.foreground = pixels[(attr >> 8) & 0x0f];
339
340         v.background = pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)];
341         XChangeGC(dpy, gc, GCForeground|GCBackground, &v);
342 #endif
343 }
344
345 void
346 video_update(regcontext_t *REGS __unused)
347 {
348 #ifndef NO_X
349         static int icnt = 3;
350
351         if (kbd_read)
352             kbd_event(kbd_fd, AS_RD, 0, REGS);
353
354         if (--icnt == 0) {
355             icnt = 3;
356
357             lpt_poll();         /* Handle timeout on lpt code */
358
359             /* quick and dirty */
360             if (VGA_ATC[ATC_ModeCtrl] & 1)
361                 video_update_graphics();
362             else
363                 video_update_text();
364         }
365 #endif
366 }
367
368 #ifndef NO_X
369 static void
370 video_update_graphics(void)
371 {
372     vram2ximage();
373     
374     XPutImage(dpy, win, DefaultGC(dpy, DefaultScreen(dpy)),
375               xi, 0, 0, 0, 0, width, height);
376     XFlush(dpy);
377     
378     return;
379 }
380
381 static void
382 video_update_text(void)
383 {
384     static int or = -1;
385     static int oc = -1;
386
387
388     static char buf[256];
389     int r, c;
390     int attr = vmem[0] & 0xff00;
391     XGCValues v;
392
393     if (xmode) {
394         wakeup_poll();  /* Wake up anyone waiting on kbd poll */
395
396         show ^= 1;
397
398         setgc(attr);
399
400         for (r = 0; r < height; ++r) {
401             int cc = 0;
402
403             if (!lines[r].changed) {
404                 if ((r == or || r == row) && (or != row || oc != col))
405                     lines[r].changed = 1;
406                 else {
407                     for (c = 0; c < width; ++c) {
408                         if (lines[r].data[c] != vmem[r * width + c]) {
409                             lines[r].changed = 1;
410                             break;
411                         }
412                         if (blink && lines[r].data[c] & 0x8000) {
413                             lines[r].changed = 1;
414                             break;
415                         }
416                     }
417                 }
418             }
419
420             if (!lines[r].changed)
421                 continue;
422
423             reset_poll();
424             lines[r].changed = 0;
425             memcpy(lines[r].data,
426                    &vmem[r * width], sizeof(u_short) * width);
427
428             for (c = 0; c < width; ++c) {
429                 int cv = vmem[r * width + c];
430                 if ((cv & 0xff00) != attr) {
431                     if (cc < c)
432                         XDrawImageString(dpy, win, gc,
433                                          2 + cc * FW,
434                                          2 + (r + 1) * FH,
435                                          buf + cc, c - cc);
436                     cc = c;
437                     attr = cv  & 0xff00;
438                     setgc(attr);
439                 }
440                 buf[c] = (cv & 0xff) ? cv & 0xff : ' ';
441             }
442             if (cc < c) {
443                 XDrawImageString(dpy, win, gc,
444                                  2 + cc * FW,
445                                  2 + (r + 1) * FH,
446                                  buf + cc, c - cc);
447             }
448         }
449         or = row;
450         oc = col;
451
452         if (CursStart <= CursEnd && CursEnd <= FH &&
453             show && row < height && col < width) {
454
455             attr = vmem[row * width + col] & 0xff00;
456             v.foreground = pixels[(attr >> 8) & 0x0f] ^
457                 pixels[(attr >> 12) & (blink ? 0x07 : 0x0f)];
458             if (v.foreground) {
459                 v.function = GXxor;
460             } else {
461                 v.foreground = pixels[7];
462                 v.function = GXcopy;
463             }
464             XChangeGC(dpy, cgc, GCForeground | GCFunction, &v);
465             XFillRectangle(dpy, win, cgc,
466                            2 + col * FW,
467                            2 + row * FH + CursStart + FD,
468                            FW, CursEnd + 1 - CursStart);
469         }
470
471         if (mouse_status.installed && mouse_status.show) {
472             c = mouse_status.x / mouse_status.hmickey;
473             r = mouse_status.y / mouse_status.vmickey;
474
475             lines[r].changed = 1;
476             attr = vmem[r * width + c] & 0xff00;
477             v.foreground = pixels[(attr >> 8) & 0x0f] ^
478                 pixels[(attr >> 12) & 0x0f];
479             if (v.foreground) {
480                 v.function = GXxor;
481             } else {
482                 v.foreground = pixels[7];
483                 v.function = GXcopy;
484             }
485             XChangeGC(dpy, cgc, GCForeground | GCFunction, &v);
486             XFillRectangle(dpy, win, cgc,
487                            2 + c * FW,
488                            2 + r * FH + 2,
489                            FW, FH);
490         }
491                 
492         XFlush(dpy);
493     }
494 }
495
496 /* Convert the contents of the video RAM into an XImage.
497
498    Bugs: - The function is way too slow.
499          - It only works for the 16 color modes.
500          - It only works on 15/16-bit TrueColor visuals. */
501 static void
502 vram2ximage(void)
503 {
504     int i, x, y, yoffset;
505     u_int16_t *image = (u_int16_t *)xi->data;
506
507     yoffset = 0;
508     for (y = 0; y < height; y++) {
509         yoffset += width / 8;
510         for (x = 0; x < width; x += 8) {
511             int offset = yoffset + x / 8;
512             for (i = 0; i < 8; i++) {
513                 int color = lut[0][vplane0[offset]][i] |
514                     lut[1][vplane1[offset]][i] |
515                     lut[2][vplane2[offset]][i] |
516                     lut[3][vplane3[offset]][i];
517                 *image++ = (u_int16_t)pixels[color];
518             }       
519         }
520     }
521     
522     return;
523 }
524 #endif
525
526 static u_short Ascii2Scan[] = {
527  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
528  0x000e, 0x000f, 0xffff, 0xffff, 0xffff, 0x001c, 0xffff, 0xffff,
529  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
530  0xffff, 0xffff, 0xffff, 0x0001, 0xffff, 0xffff, 0xffff, 0xffff,
531  0x0039, 0x0102, 0x0128, 0x0104, 0x0105, 0x0106, 0x0108, 0x0028,
532  0x010a, 0x010b, 0x0109, 0x010d, 0x0033, 0x000c, 0x0034, 0x0035,
533  0x000b, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
534  0x0009, 0x000a, 0x0127, 0x0027, 0x0133, 0x000d, 0x0134, 0x0135,
535  0x0103, 0x011e, 0x0130, 0x012e, 0x0120, 0x0112, 0x0121, 0x0122,
536  0x0123, 0x0117, 0x0124, 0x0125, 0x0126, 0x0132, 0x0131, 0x0118,
537  0x0119, 0x0110, 0x0113, 0x011f, 0x0114, 0x0116, 0x012f, 0x0111,
538  0x012d, 0x0115, 0x012c, 0x001a, 0x002b, 0x001b, 0x0107, 0x010c,
539  0x0029, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022,
540  0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 0x0032, 0x0031, 0x0018,
541  0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011,
542  0x002d, 0x0015, 0x002c, 0x011a, 0x012b, 0x011b, 0x0129, 0xffff,
543 };
544
545 struct {
546     u_short     base;
547     u_short     shift;
548     u_short     ctrl;
549     u_short     alt;
550 } ScanCodes[] = {
551     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key  0 */
552     {   0x011b, 0x011b, 0x011b, 0xffff }, /* key  1 - Escape key */
553     {   0x0231, 0x0221, 0xffff, 0x7800 }, /* key  2 - '1' */
554     {   0x0332, 0x0340, 0x0300, 0x7900 }, /* key  3 - '2' - special handling */
555     {   0x0433, 0x0423, 0xffff, 0x7a00 }, /* key  4 - '3' */
556     {   0x0534, 0x0524, 0xffff, 0x7b00 }, /* key  5 - '4' */
557     {   0x0635, 0x0625, 0xffff, 0x7c00 }, /* key  6 - '5' */
558     {   0x0736, 0x075e, 0x071e, 0x7d00 }, /* key  7 - '6' */
559     {   0x0837, 0x0826, 0xffff, 0x7e00 }, /* key  8 - '7' */
560     {   0x0938, 0x092a, 0xffff, 0x7f00 }, /* key  9 - '8' */
561     {   0x0a39, 0x0a28, 0xffff, 0x8000 }, /* key 10 - '9' */
562     {   0x0b30, 0x0b29, 0xffff, 0x8100 }, /* key 11 - '0' */
563     {   0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* key 12 - '-' */
564     {   0x0d3d, 0x0d2b, 0xffff, 0x8300 }, /* key 13 - '=' */
565     {   0x0e08, 0x0e08, 0x0e7f, 0xffff }, /* key 14 - backspace */
566     {   0x0f09, 0x0f00, 0xffff, 0xffff }, /* key 15 - tab */
567     {   0x1071, 0x1051, 0x1011, 0x1000 }, /* key 16 - 'Q' */
568     {   0x1177, 0x1157, 0x1117, 0x1100 }, /* key 17 - 'W' */
569     {   0x1265, 0x1245, 0x1205, 0x1200 }, /* key 18 - 'E' */
570     {   0x1372, 0x1352, 0x1312, 0x1300 }, /* key 19 - 'R' */
571     {   0x1474, 0x1454, 0x1414, 0x1400 }, /* key 20 - 'T' */
572     {   0x1579, 0x1559, 0x1519, 0x1500 }, /* key 21 - 'Y' */
573     {   0x1675, 0x1655, 0x1615, 0x1600 }, /* key 22 - 'U' */
574     {   0x1769, 0x1749, 0x1709, 0x1700 }, /* key 23 - 'I' */
575     {   0x186f, 0x184f, 0x180f, 0x1800 }, /* key 24 - 'O' */
576     {   0x1970, 0x1950, 0x1910, 0x1900 }, /* key 25 - 'P' */
577     {   0x1a5b, 0x1a7b, 0x1a1b, 0xffff }, /* key 26 - '[' */
578     {   0x1b5d, 0x1b7d, 0x1b1d, 0xffff }, /* key 27 - ']' */
579     {   0x1c0d, 0x1c0d, 0x1c0a, 0xffff }, /* key 28 - CR */
580     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 29 - control */
581     {   0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* key 30 - 'A' */
582     {   0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* key 31 - 'S' */
583     {   0x2064, 0x2044, 0x2004, 0x2000 }, /* key 32 - 'D' */
584     {   0x2166, 0x2146, 0x2106, 0x2100 }, /* key 33 - 'F' */
585     {   0x2267, 0x2247, 0x2207, 0x2200 }, /* key 34 - 'G' */
586     {   0x2368, 0x2348, 0x2308, 0x2300 }, /* key 35 - 'H' */
587     {   0x246a, 0x244a, 0x240a, 0x2400 }, /* key 36 - 'J' */
588     {   0x256b, 0x254b, 0x250b, 0x2500 }, /* key 37 - 'K' */
589     {   0x266c, 0x264c, 0x260c, 0x2600 }, /* key 38 - 'L' */
590     {   0x273b, 0x273a, 0xffff, 0xffff }, /* key 39 - ';' */
591     {   0x2827, 0x2822, 0xffff, 0xffff }, /* key 40 - ''' */
592     {   0x2960, 0x297e, 0xffff, 0xffff }, /* key 41 - '`' */
593     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 42 - left shift */
594     {   0x2b5c, 0x2b7c, 0x2b1c, 0xffff }, /* key 43 - '' */
595     {   0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* key 44 - 'Z' */
596     {   0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* key 45 - 'X' */
597     {   0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* key 46 - 'C' */
598     {   0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* key 47 - 'V' */
599     {   0x3062, 0x3042, 0x3002, 0x3000 }, /* key 48 - 'B' */
600     {   0x316e, 0x314e, 0x310e, 0x3100 }, /* key 49 - 'N' */
601     {   0x326d, 0x324d, 0x320d, 0x3200 }, /* key 50 - 'M' */
602     {   0x332c, 0x333c, 0xffff, 0xffff }, /* key 51 - ',' */
603     {   0x342e, 0x343e, 0xffff, 0xffff }, /* key 52 - '.' */
604     {   0x352f, 0x353f, 0xffff, 0xffff }, /* key 53 - '/' */
605     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 54 - right shift - */
606     {   0x372a, 0xffff, 0x3772, 0xffff }, /* key 55 - prt-scr - */
607     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 56 - Alt - */
608     {   0x3920, 0x3920, 0x3920, 0x3920 }, /* key 57 - space bar */
609     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 58 - caps-lock -  */
610     {   0x3b00, 0x5400, 0x5e00, 0x6800 }, /* key 59 - F1 */
611     {   0x3c00, 0x5500, 0x5f00, 0x6900 }, /* key 60 - F2 */
612     {   0x3d00, 0x5600, 0x6000, 0x6a00 }, /* key 61 - F3 */
613     {   0x3e00, 0x5700, 0x6100, 0x6b00 }, /* key 62 - F4 */
614     {   0x3f00, 0x5800, 0x6200, 0x6c00 }, /* key 63 - F5 */
615     {   0x4000, 0x5900, 0x6300, 0x6d00 }, /* key 64 - F6 */
616     {   0x4100, 0x5a00, 0x6400, 0x6e00 }, /* key 65 - F7 */
617     {   0x4200, 0x5b00, 0x6500, 0x6f00 }, /* key 66 - F8 */
618     {   0x4300, 0x5c00, 0x6600, 0x7000 }, /* key 67 - F9 */
619     {   0x4400, 0x5d00, 0x6700, 0x7100 }, /* key 68 - F10 */
620     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 69 - num-lock - */
621     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 70 - scroll-lock -  */
622     {   0x4700, 0x4737, 0x7700, 0xffff }, /* key 71 - home */
623     {   0x4800, 0x4838, 0xffff, 0xffff }, /* key 72 - cursor up */
624     {   0x4900, 0x4939, 0x8400, 0xffff }, /* key 73 - page up */
625     {   0x4a2d, 0x4a2d, 0xffff, 0xffff }, /* key 74 - minus sign */
626     {   0x4b00, 0x4b34, 0x7300, 0xffff }, /* key 75 - cursor left */
627     {   0xffff, 0x4c35, 0xffff, 0xffff }, /* key 76 - center key */
628     {   0x4d00, 0x4d36, 0x7400, 0xffff }, /* key 77 - cursor right */
629     {   0x4e2b, 0x4e2b, 0xffff, 0xffff }, /* key 78 - plus sign */
630     {   0x4f00, 0x4f31, 0x7500, 0xffff }, /* key 79 - end */
631     {   0x5000, 0x5032, 0xffff, 0xffff }, /* key 80 - cursor down */
632     {   0x5100, 0x5133, 0x7600, 0xffff }, /* key 81 - page down */
633     {   0x5200, 0x5230, 0xffff, 0xffff }, /* key 82 - insert */
634     {   0x5300, 0x532e, 0xffff, 0xffff }, /* key 83 - delete */
635     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 84 - sys key */
636     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 85 */
637     {   0xffff, 0xffff, 0xffff, 0xffff }, /* key 86 */
638     {   0x8500, 0x5787, 0x8900, 0x8b00 }, /* key 87 - F11 */
639     {   0x8600, 0x5888, 0x8a00, 0x8c00 }, /* key 88 - F12 */
640 };
641
642 void
643 debug_event(int fd, int cond, void *arg, regcontext_t *REGS)
644 {
645     static char ibuf[1024];
646     static int icnt = 0;
647     static u_short ds = 0;
648     static u_short di = 0;
649     static u_short cnt = 16 * 8;
650     char *ep;
651     int r;
652     
653     if (!(cond & AS_RD))
654         return;
655
656     r = read(STDIN_FILENO, ibuf + icnt, sizeof(ibuf) - icnt);
657     if (r <= 0)
658         return;
659
660     icnt += r;
661
662     ibuf[icnt] = 0;
663     while ((ep = strchr(ibuf, '\n')) != 0) {
664         int ac;
665         char *_av[16];
666         char **av;
667
668         *ep++ = 0;
669         ac = ParseBuffer(ibuf, av = _av, 16);
670
671         if (ac > 0) {
672             if (!strcasecmp(av[0], "dump")) {
673                 if (ac > 1) {
674                     char *c;
675                     if ((c = strchr(av[1], ':')) != 0) {
676                         ds = strtol(av[1], 0, 16);
677                         di = strtol(c+1, 0, 16);
678                     } else
679                         di = strtol(av[1], 0, 16);
680                 }
681                 if (ac > 2)
682                     cnt = strtol(av[2], 0, 0);
683                 cnt = (cnt + 0xf) & ~0xf;
684                 if (cnt == 0)
685                     cnt = 0x10;
686                 di &= ~0xf;
687
688                 for (r = 0; r < cnt; r += 0x10, di = (di + 0x10) & 0xffff) {
689                     int i;
690                     u_char *ap = (u_char *)(((u_long)ds << 4) + di);
691
692                     printf("%04x:%04x:", ds, di);
693                     for (i = 0; i < 8; ++i)
694                         printf(" %02x", ap[i]);
695                     printf(" ");
696                     for (i = 8; i < 16; ++i)
697                         printf(" %02x", ap[i]);
698                     printf(": ");
699                     for (i = 0; i < 8; ++i)
700                         printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]);
701                     printf(" ");
702                     for (i = 8; i < 16; ++i)
703                         printf("%c",(ap[i] < ' ' || ap[i] > '~') ? '.' : ap[i]);
704                     printf("\n");
705                 }
706             } else if (!strcasecmp(av[0], "dis")) {
707                 u_char *ap = (u_char *)(((u_long)ds << 4) + di);
708
709                 if (ac > 1) {
710                     char *c;
711                     if ((c = strchr(av[1], ':')) != 0) {
712                         ds = strtol(av[1], 0, 16);
713                         di = strtol(c+1, 0, 16);
714                     } else
715                         di = strtol(av[1], 0, 16);
716                 }
717                 if (ac > 2)
718                     cnt = strtol(av[2], 0, 0);
719
720                 for (r = 0; r < cnt; ++r) {
721                     char buf[16];
722                     int c = i386dis(ds, di, ap, buf, 0);
723                     printf("%04x:%04x %s\n", ds, di, buf);
724                     di += c;
725                     ap += c;
726                 }
727             } else if (!strcasecmp(av[0], "regs")) {
728                 dump_regs(REGS);
729             } else if (!strcasecmp(av[0], "force")) {
730                 char *p = av[1];
731
732                 while ((p = *++av) != 0) {
733                     while (*p) {
734                         if (*p >= ' ' && *p <= '~')
735                             KbdWrite(ScanCodes[Ascii2Scan[(int)*p] & 0xff].base);
736                         ++p;
737                     }
738                 }
739                 KbdWrite(ScanCodes[28].base);
740             } else if (!strcasecmp(av[0], "bell")) {
741 #ifndef NO_X            
742                 XBell(dpy, 0);
743                 XFlush(dpy);
744 #endif
745             } else {
746                 fprintf(stderr, "%s: unknown command\n", av[0]);
747             }
748         }
749
750         if (ep < ibuf + icnt) {
751             char *f = ep;
752             char *t = ibuf;
753             icnt -= ep - ibuf;
754             while (icnt--)
755                 *t++ = *f++;
756         } else
757             icnt = 0;
758         ibuf[icnt] = 0;
759     }
760 }
761
762 unsigned char
763 inb_port60(int port __unused)
764 {       
765     int r = break_code;
766     break_code = 0;
767     scan_code = 0xffff;
768     return(r);
769 }       
770
771 void
772 kbd_event(int fd, int cond, void *arg, regcontext_t *REGS)
773 {
774     if (!(cond & AS_RD))
775        return;
776     
777     kbd_read = 0;
778
779     printf("kbd_event: fd=%d\n", fd);
780     if ((break_code = read_raw_kbd(fd, &scan_code)) != 0xffff)
781         hardint(0x01);
782 }
783
784 void
785 int09(REGISTERS __unused)
786 {
787     if (raw_kbd) {
788         if (scan_code != 0xffff) {
789             KbdWrite(scan_code);
790             break_code = 0;
791             scan_code = 0xffff;
792 #if 0
793             kbd_event(kbd_fd, 0, sc, REGS);
794 #endif
795         }
796     }
797     send_eoi();
798 }
799
800 u_short
801 read_raw_kbd(int fd, u_short *code)
802 {
803     unsigned char c;
804
805     *code = 0xffff;
806
807     if (read(fd, &c, 1) == 1) {
808         if (c == 0xe0) {
809             K3_STATUS |= K3_TWOBYTE;
810             return(c);
811         }
812         switch (c) {
813         case 29:        /* Control */
814             K1_STATUS |= K1_CTRL;
815             if (K3_STATUS & K3_TWOBYTE)
816                 K3_STATUS |= K3_RCTRL;
817             else
818                 K2_STATUS |= K2_LCTRL;
819             break;
820         case 29 | 0x80: /* Control */
821             K1_STATUS &= ~K1_CTRL;
822             if (K3_STATUS & K3_TWOBYTE)
823                 K3_STATUS &= ~K3_RCTRL;
824             else
825                 K2_STATUS &= ~K2_LCTRL;
826             break;
827
828         case 42:        /* left shift */
829             K1_STATUS |= K1_LSHIFT;
830             break;
831         case 42 | 0x80: /* left shift */
832             K1_STATUS &= ~K1_LSHIFT;
833             break;
834
835         case 54:        /* right shift */
836             K1_STATUS |= K1_RSHIFT;
837             break;
838         case 54 | 0x80: /* right shift */
839             K1_STATUS &= ~K1_RSHIFT;
840             break;
841
842         case 56:        /* Alt */
843             K1_STATUS |= K1_ALT;
844             if (K3_STATUS & K3_TWOBYTE)
845                 K3_STATUS |= K3_RALT;
846             else
847                 K2_STATUS |= K2_LALT;
848             break;
849         case 56 | 0x80: /* Alt */
850             K1_STATUS &= ~K1_ALT;
851             if (K3_STATUS & K3_TWOBYTE)
852                 K3_STATUS &= ~K3_RALT;
853             else
854                 K2_STATUS &= ~K2_LALT;
855             break;
856
857         case 58:        /* caps-lock */
858             K1_STATUS ^= K1_CLOCK;
859             if (K1_STATUS & K1_CLOCK)
860                 K4_STATUS |= K4_CLOCK_LED;
861             else
862                 K4_STATUS &= ~K4_CLOCK_LED;
863             K2_STATUS |= K2_CLOCK;
864             break;
865         case 58 | 0x80: /* caps-lock */
866             K2_STATUS &= ~K2_CLOCK;
867             break;
868
869         case 69:        /* num-lock */
870             K1_STATUS ^= K1_NLOCK;
871             if (K1_STATUS & K1_NLOCK)
872                 K4_STATUS |= K4_NLOCK_LED;
873             else
874                 K4_STATUS &= ~K4_NLOCK_LED;
875             K2_STATUS |= K2_NLOCK;
876             break;
877         case 69 | 0x80: /* num-lock */
878             K2_STATUS &= ~K2_NLOCK;
879             break;
880
881         case 70:        /* scroll-lock */
882             K1_STATUS ^= K1_SLOCK;
883             if (K1_STATUS & K1_SLOCK)
884                 K4_STATUS |= K4_SLOCK_LED;
885             else
886                 K4_STATUS &= ~K4_SLOCK_LED;
887             K2_STATUS |= K2_SLOCK;
888             break;
889         case 70 | 0x80: /* scroll-lock */
890             K2_STATUS &= ~K2_SLOCK;
891             break;
892
893         case 82:        /* insert */
894             K1_STATUS ^= K1_INSERT;
895             K2_STATUS |= K2_INSERT;
896             break;
897         case 82 | 0x80: /* insert */
898             K2_STATUS &= ~K2_INSERT;
899             break;
900
901         }
902
903 #if 0 /*XXXXX*/
904         if ((K4_STATUS & 0x07) != oldled) {
905             oldled = K4_STATUS & 0x07;
906             ioctl (fd, PCCONIOCSETLED, &oldled);
907         }
908 #endif
909
910         if (c == 83 && (K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL))
911             quit(0);
912
913         if (c < 89) {
914             u_short scode;
915
916             if (K1_STATUS & K1_ALT) {
917                 scode = ScanCodes[c].alt;
918             } else if (K1_STATUS & K1_CTRL) {
919                 scode = ScanCodes[c].ctrl;
920             } else if (K1_STATUS & K1_SHIFT) {
921                 scode = ScanCodes[c].shift;
922             } else {
923                 scode = ScanCodes[c].base;
924                 if (K1_STATUS & K1_CLOCK) {
925                     if (islower(scode & 0xff)) {
926                         scode = (scode & 0xff00) | toupper(scode & 0xff);
927                     }
928                 }
929                 if ((K1_STATUS & K1_NLOCK) && (K3_STATUS & K3_TWOBYTE) == 0) {
930                     switch (c) {
931                     case 71: /* home */
932                     case 72: /* cursor up */
933                     case 73: /* page up */
934                     case 75: /* cursor left */
935                     case 76: /* center key */
936                     case 77: /* cursor right */
937                     case 79: /* end */
938                     case 80: /* cursor down */
939                     case 81: /* page down */
940                     case 82: /* insert */
941                     case 83: /* delete */
942                         scode = ScanCodes[c].shift;
943                         break;
944                     }
945                 }
946             }
947             *code = scode;
948         }
949         K3_STATUS &= ~K3_TWOBYTE;
950         if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
951             switch (c) {
952             case 0x13:  /* R */
953                 kill(getpid(), SIGALRM);        /* force redraw */
954 printf("FORCED REDRAW\n");
955                 return(0xffff);
956             case 0x14:  /* T */
957                 tmode ^= 1;
958                 if (!tmode)
959                     resettrace((regcontext_t *)&saved_sigframe->
960                         sf_uc.uc_mcontext);
961                 return(0xffff);
962             case 0x53:  /* DEL */
963                 quit(0);
964             }
965         }
966         return(c);
967     } else {
968         return(0xffff);
969     }
970 }
971
972 void
973 video_async_event(int fd, int cond, void *arg, regcontext_t *REGS)
974 {
975 #ifndef NO_X
976         int int9 = 0;
977
978         if (!(cond & AS_RD))
979             return;
980         
981         for (;;) {
982                 int x;
983                 fd_set fdset;
984                 XEvent ev;  
985                 static struct timeval tv;
986  
987                 /*
988                  * Handle any events just sitting around...
989                  */
990                 XFlush(dpy);
991                 while (QLength(dpy) > 0) {
992                         XNextEvent(dpy, &ev);
993                         int9 |= video_event(&ev);
994                 }
995
996                 FD_ZERO(&fdset);
997                 FD_SET(fd, &fdset);
998
999                 x = select(FD_SETSIZE, &fdset, 0, 0, &tv);
1000
1001                 switch (x) {  
1002                 case -1:
1003                         /*
1004                          * Errno might be wrong, so we just select again.
1005                          * This could cause a problem is something really
1006                          * was wrong with select....
1007                          */
1008                         perror("select");
1009                         return;
1010                 case 0:
1011                         XFlush(dpy);
1012                         if (int9)
1013                             hardint(0x01);
1014                         return;
1015                 default:
1016                         if (FD_ISSET(fd, &fdset)) {
1017                                 do {
1018                                         XNextEvent(dpy, &ev);
1019                                         int9 |= video_event(&ev);
1020                                 } while (QLength(dpy));
1021                         }
1022                         break;
1023                 }
1024         }
1025 #endif
1026 }
1027
1028 #ifndef NO_X
1029 static int
1030 video_event(XEvent *ev)
1031 {
1032         switch (ev->type) {
1033         case MotionNotify: {
1034                 XMotionEvent *me = (XMotionEvent *)ev;
1035                 me->x -= 2;
1036                 me->y -= 2;
1037
1038                 mouse_status.x = (me->x < mouse_status.range.x)
1039                                     ? mouse_status.range.x
1040                                     : (me->x > mouse_status.range.w)
1041                                     ? mouse_status.range.w : me->x;
1042                 mouse_status.y = (me->y < mouse_status.range.y)
1043                                     ? mouse_status.range.y
1044                                     : (me->y > mouse_status.range.h)
1045                                     ? mouse_status.range.h : me->y;
1046                 break;
1047             }
1048         case ButtonRelease: {
1049                 XButtonEvent *be = (XButtonEvent *)ev;
1050                 be->x -= 2;
1051                 be->y -= 2;
1052
1053                 if (be->button < 3)
1054                     mouse_status.ups[be->button]++;
1055
1056                 mouse_status.x = (be->x < mouse_status.range.x)
1057                                     ? mouse_status.range.x
1058                                     : (be->x > mouse_status.range.w)
1059                                     ? mouse_status.range.w : be->x;
1060                 mouse_status.y = (be->y < mouse_status.range.y)
1061                                     ? mouse_status.range.y
1062                                     : (be->y > mouse_status.range.h)
1063                                     ? mouse_status.range.h : be->y;
1064                 break;
1065             }
1066         case ButtonPress: {
1067                 XButtonEvent *be = (XButtonEvent *)ev;
1068                 be->x -= 2;
1069                 be->y -= 2;
1070
1071                 if (be->button < 3)
1072                     mouse_status.downs[be->button]++;
1073
1074                 mouse_status.x = (be->x < mouse_status.range.x)
1075                                     ? mouse_status.range.x
1076                                     : (be->x > mouse_status.range.w)
1077                                     ? mouse_status.range.w : be->x;
1078                 mouse_status.y = (be->y < mouse_status.range.y)
1079                                     ? mouse_status.range.y
1080                                     : (be->y > mouse_status.range.h)
1081                                     ? mouse_status.range.h : be->y;
1082
1083                 if ((K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
1084                     quit(0);
1085                 }
1086                 break;
1087             }
1088         case NoExpose:
1089                 break;
1090         case GraphicsExpose:
1091         case Expose: {
1092                 int r;
1093                 for (r = 0; r < height; ++r)
1094                     lines[r].changed = 1;
1095                 break;
1096             }
1097         case KeyRelease: {
1098                 static char buf[128];
1099                 KeySym ks;
1100
1101                 break_code |= 0x80;
1102
1103                 if (!(ev->xkey.state & ShiftMask)) {
1104                     K1_STATUS &= ~K1_LSHIFT;
1105                     K1_STATUS &= ~K1_RSHIFT;
1106                 }
1107                 if (!(ev->xkey.state & ControlMask)) {
1108                         K1_STATUS &= ~K1_CTRL;
1109                         K2_STATUS &= ~K2_LCTRL;
1110                         K3_STATUS &= ~K3_RCTRL;
1111                 }
1112                 if (!(ev->xkey.state & Mod1Mask)) {
1113                         K1_STATUS &= ~K1_ALT;
1114                         K2_STATUS &= ~K2_LALT;
1115                         K3_STATUS &= ~K3_RALT;
1116                 }
1117                 if (!(ev->xkey.state & LockMask)) {
1118                         K2_STATUS &= ~K2_CLOCK;
1119                 }
1120
1121                 XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
1122                 switch (ks) {
1123                 case XK_Shift_L:
1124                         K1_STATUS &= ~K1_LSHIFT;
1125                         break;
1126                 case XK_Shift_R:
1127                         K1_STATUS &= ~K1_RSHIFT;
1128                         break;
1129                 case XK_Control_L:
1130                         K1_STATUS &= ~K1_CTRL;
1131                         K2_STATUS &= ~K2_LCTRL;
1132                         break;
1133                 case XK_Control_R:
1134                         K1_STATUS &= ~K1_CTRL;
1135                         K3_STATUS &= ~K3_RCTRL;
1136                         break;
1137                 case XK_Alt_L:
1138                         K1_STATUS &= ~K1_ALT;
1139                         K2_STATUS &= ~K2_LALT;
1140                         break;
1141                 case XK_Alt_R:
1142                         K1_STATUS &= ~K1_ALT;
1143                         K3_STATUS &= ~K3_RALT;
1144                         break;
1145                 case XK_Scroll_Lock:
1146                         K2_STATUS &= ~K2_SLOCK;
1147                         break;
1148                 case XK_Num_Lock:
1149                         K2_STATUS &= ~K2_NLOCK;
1150                         break;
1151                 case XK_Caps_Lock:
1152                         K2_STATUS &= ~K2_CLOCK;
1153                         break;
1154                 case XK_Insert:
1155                         K2_STATUS &= ~K2_INSERT;
1156                         break;
1157                 }
1158                 return(1);
1159             }
1160         case KeyPress: {
1161                 static char buf[128];
1162                 KeySym ks;
1163                 int n;
1164                 int nlock = 0;
1165                 u_short scan = 0xffff;
1166
1167                 if (!(ev->xkey.state & ShiftMask)) {
1168                     K1_STATUS &= ~K1_LSHIFT;
1169                     K1_STATUS &= ~K1_RSHIFT;
1170                 }
1171                 if (!(ev->xkey.state & ControlMask)) {
1172                         K1_STATUS &= ~K1_CTRL;
1173                         K2_STATUS &= ~K2_LCTRL;
1174                         K3_STATUS &= ~K3_RCTRL;
1175                 }
1176                 if (!(ev->xkey.state & Mod1Mask)) {
1177                         K1_STATUS &= ~K1_ALT;
1178                         K2_STATUS &= ~K2_LALT;
1179                         K3_STATUS &= ~K3_RALT;
1180                 }
1181                 if (!(ev->xkey.state & LockMask)) {
1182                         K2_STATUS &= ~K2_CLOCK;
1183                 }
1184
1185                 n = XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
1186
1187                 switch (ks) {
1188                 case XK_Shift_L:
1189                         K1_STATUS |= K1_LSHIFT;
1190                         break;
1191                 case XK_Shift_R:
1192                         K1_STATUS |= K1_RSHIFT;
1193                         break;
1194                 case XK_Control_L:
1195                         K1_STATUS |= K1_CTRL;
1196                         K2_STATUS |= K2_LCTRL;
1197                         break;
1198                 case XK_Control_R:
1199                         K1_STATUS |= K1_CTRL;
1200                         K3_STATUS |= K3_RCTRL;
1201                         break;
1202                 case XK_Alt_L:
1203                         K1_STATUS |= K1_ALT;
1204                         K2_STATUS |= K2_LALT;
1205                         break;
1206                 case XK_Alt_R:
1207                         K1_STATUS |= K1_ALT;
1208                         K3_STATUS |= K3_RALT;
1209                         break;
1210                 case XK_Scroll_Lock:
1211                         K1_STATUS ^= K1_SLOCK;
1212                         K2_STATUS |= K2_SLOCK;
1213                         break;
1214                 case XK_Num_Lock:
1215                         K1_STATUS ^= K1_NLOCK;
1216                         K2_STATUS |= K2_NLOCK;
1217                         break;
1218                 case XK_Caps_Lock:
1219                         K1_STATUS ^= K1_CLOCK;
1220                         K2_STATUS |= K2_CLOCK;
1221                         break;
1222                 case XK_Insert:
1223                 case XK_KP_Insert:
1224                         K1_STATUS ^= K1_INSERT;
1225                         K2_STATUS |= K2_INSERT;
1226                         scan = 82;
1227                         goto docode;
1228
1229                 case XK_Escape:
1230                         scan = 1;
1231                         goto docode;
1232
1233                 case XK_Tab:
1234                 case XK_ISO_Left_Tab:
1235                         scan = 15;
1236                         goto docode;
1237                         
1238                 case XK_Return:
1239                 case XK_KP_Enter:
1240                         scan = 28;
1241                         goto docode;
1242
1243                 case XK_Print:
1244                         scan = 55;
1245                         goto docode;
1246
1247                 case XK_F1:
1248                 case XK_F2:
1249                 case XK_F3:
1250                 case XK_F4:
1251                 case XK_F5:
1252                 case XK_F6:
1253                 case XK_F7:
1254                 case XK_F8:
1255                 case XK_F9:
1256                 case XK_F10:
1257                         scan = ks - XK_F1 + 59;
1258                         goto docode;
1259
1260                 case XK_KP_7:
1261                         nlock = 1;
1262                 case XK_Home:
1263                 case XK_KP_Home:
1264                         scan = 71;
1265                         goto docode;
1266                 case XK_KP_8:
1267                         nlock = 1;
1268                 case XK_Up:
1269                 case XK_KP_Up:
1270                         scan = 72;
1271                         goto docode;
1272                 case XK_KP_9:
1273                         nlock = 1;
1274                 case XK_Prior:
1275                 case XK_KP_Prior:
1276                         scan = 73;
1277                         goto docode;
1278                 case XK_KP_Subtract:
1279                         scan = 74;
1280                         goto docode;
1281                 case XK_KP_4:
1282                         nlock = 1;
1283                 case XK_Left:
1284                 case XK_KP_Left:
1285                         scan = 75;
1286                         goto docode;
1287                 case XK_KP_5:
1288                         nlock = 1;
1289                 case XK_Begin:
1290                 case XK_KP_Begin:
1291                         scan = 76;
1292                         goto docode;
1293                 case XK_KP_6:
1294                         nlock = 1;
1295                 case XK_Right:
1296                 case XK_KP_Right:
1297                         scan = 77;
1298                         goto docode;
1299                 case XK_KP_Add:
1300                         scan = 78;
1301                         goto docode;
1302                 case XK_KP_1:
1303                         nlock = 1;
1304                 case XK_End:
1305                 case XK_KP_End:
1306                         scan = 79;
1307                         goto docode;
1308                 case XK_KP_2:
1309                         nlock = 1;
1310                 case XK_Down:
1311                 case XK_KP_Down:
1312                         scan = 80;
1313                         goto docode;
1314                 case XK_KP_3:
1315                         nlock = 1;
1316                 case XK_Next:
1317                 case XK_KP_Next:
1318                         scan = 81;
1319                         goto docode;
1320                 case XK_KP_0:
1321                         nlock = 1;
1322                 /* case XK_Insert: This is above */
1323                         scan = 82;
1324                         goto docode;
1325
1326                 case XK_KP_Decimal:
1327                         nlock = 1;
1328                         scan = 83;
1329                         goto docode;
1330
1331                 case XK_Delete:
1332                 case XK_KP_Delete:
1333                         scan = flipdelete ? 14 : 83;
1334                         goto docode;
1335
1336                 case XK_BackSpace:
1337                         scan = flipdelete ? 83 : 14;
1338                         goto docode;
1339
1340                 case XK_F11:
1341                         scan = 87;
1342                         goto docode;
1343                 case XK_F12:
1344                         scan = 88;
1345                         goto docode;
1346
1347
1348                 case XK_KP_Divide:
1349                         scan = Ascii2Scan['/'];
1350                         goto docode;
1351
1352                 case XK_KP_Multiply:
1353                         scan = Ascii2Scan['*'];
1354                         goto docode;
1355
1356                 default:
1357                         if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
1358                                 if (ks == 'T' || ks == 't') {
1359                                     tmode ^= 1;
1360                                     if (!tmode)
1361                                             resettrace((regcontext_t *)&saved_sigframe->
1362                                                 sf_uc.uc_mcontext); 
1363                                     break;
1364                                 }
1365                                 if (ks == 'R' || ks == 'r') {
1366                                     kill(getpid(), SIGALRM);    /* redraw */
1367                                     break;
1368                                 }
1369                         }
1370                         if (ks < ' ' || ks > '~')
1371                                 break;
1372                         scan = Ascii2Scan[ks]; 
1373                 docode:
1374                         if (nlock)
1375                             scan |= 0x100;
1376
1377                         if ((scan & ~0x100) > 88) {
1378                             scan = 0xffff;
1379                             break;
1380                         }
1381
1382                         if ((K1_STATUS & K1_SHIFT) || (scan & 0x100)) {
1383                             scan = ScanCodes[scan & 0xff].shift;
1384                         } else if (K1_STATUS & K1_CTRL) {
1385                             scan = ScanCodes[scan & 0xff].ctrl;
1386                         } else if (K1_STATUS & K1_ALT) {
1387                             scan = ScanCodes[scan & 0xff].alt;
1388                         }  else
1389                             scan = ScanCodes[scan & 0xff].base;
1390
1391                         break;
1392                 }
1393                 if (scan != 0xffff) {
1394                         break_code = scan >> 8;
1395                         KbdWrite(scan);
1396                 }
1397                 return(1);
1398             }
1399         default:
1400                 break;
1401         }
1402         return(0);
1403 }
1404 #endif
1405
1406 void
1407 tty_move(int r, int c)
1408 {
1409         row = r;
1410         col = c;
1411         SetVREGCur();
1412 }
1413
1414 void
1415 tty_report(int *r, int *c)
1416 {
1417         *r = row;
1418         *c = col;
1419 }
1420
1421 void
1422 tty_flush(void)
1423 {
1424         K_NEXT = K_FREE = K_BUFSTARTP;
1425 }
1426
1427 void
1428 tty_index(int scroll)
1429 {
1430         int i;
1431
1432         if (row > (height - 1))
1433                 row = 0;
1434         else if (++row >= height) {
1435                 row = height - 1;
1436                 if (scroll) {
1437                         memcpy(vmem, &vmem[width], 2 * width * (height - 1));
1438                         for (i = 0; i < width; ++i)
1439                                 vmem[(height - 1) * width + i] = vattr | ' ';
1440                 }
1441         }
1442         SetVREGCur();
1443 }
1444
1445 void
1446 tty_write(int c, int attr)
1447 {
1448         if (attr == TTYF_REDIRECT) {
1449                 if (redirect1) {
1450                     write(1, &c, 1);
1451                     return;
1452                 }
1453                 attr = -1;
1454         }
1455         if (capture_fd >= 0) {
1456             char cc = c;
1457             write(capture_fd, &cc, 1);
1458         }
1459         c &= 0xff;
1460         switch (c) {
1461         case 0x07:
1462                 if (xmode) {
1463 #ifndef NO_X
1464                         XBell(dpy, 0);
1465 #endif
1466                 } else
1467                         write(1, "\007", 1);
1468                 break;
1469         case 0x08:
1470                 if (row > (height - 1) || col > width)
1471                         break;
1472                 if (col > 0)
1473                         --col;
1474                 vmem[row * width + col] &= 0xff00;
1475                 break;
1476         case '\t':
1477                 if (row > (height - 1))
1478                         row = 0;
1479                 col = (col + 8) & ~0x07;
1480                 if (col > width) {
1481                         col = 0;
1482                         tty_index(1);
1483                 }
1484                 break;
1485         case '\r':
1486                 col = 0;
1487                 break;
1488         case '\n':
1489                 tty_index(1);
1490                 break;
1491         default:
1492                 if (col >= width) {
1493                         col = 0;
1494                         tty_index(1);
1495                 }
1496                 if (row > (height - 1))
1497                         row = 0;
1498                 if (attr >= 0)
1499                         vmem[row * width + col] = attr & 0xff00;
1500                 else
1501                         vmem[row * width + col] &= 0xff00;
1502                 vmem[row * width + col++] |= c;
1503                 break;
1504         }
1505         SetVREGCur();
1506 }
1507
1508 void
1509 tty_rwrite(int n, int c, int attr)
1510 {
1511     u_char srow, scol;
1512     c &= 0xff;
1513
1514 #ifndef NO_X
1515     if (VGA_ATC[ATC_ModeCtrl] & 1) {
1516         tty_rwrite_graphics(n, c, attr);
1517         return;
1518     }
1519 #endif
1520     
1521     srow = row;
1522     scol = col;
1523     while (n--) {
1524         if (col >= width) {
1525             col = 0;
1526             tty_index(0);
1527         }
1528         if (row > (height - 1))
1529             row = 0;
1530         if (attr >= 0)
1531             vmem[row * width + col] = attr & 0xff00;
1532         else
1533             vmem[row * width + col] &= 0xff00;
1534         vmem[row * width + col++] |= c;
1535     }
1536     row = srow;
1537     col = scol;
1538     SetVREGCur();
1539 }
1540
1541 #ifndef NO_X
1542 /* Write a character in graphics mode. Note that the text is put at *text*
1543    coordinates. */
1544 static void
1545 tty_rwrite_graphics(int n, int c, int attr)
1546 {
1547     u_int8_t srow, scol;
1548     int ht = height / CharHeight;
1549     int wd = width / 8;
1550
1551     srow = row;
1552     scol = col;
1553
1554     while (n--) {
1555         if (col >= wd) {
1556             col = 0;
1557             /* tty_index(0); *//* scroll up if last line is filled */
1558         }
1559         if (row > (ht - 1))
1560             row = 0;
1561         putchar_graphics(row * wd * CharHeight + col, c, attr);
1562         col++;
1563     }
1564     row = srow;
1565     col = scol;
1566     SetVREGCur();
1567
1568     return;
1569 }
1570
1571 /* Put the character together from its pixel representation in 'font8xXX[]'
1572    and write it to 'vram'. The attribute byte gives the desired color; if bit
1573    7 is set, the pixels are XOR'd with the underlying color(s).
1574
1575    XXX This must be updated for the 256 color modes. */
1576 static void
1577 putchar_graphics(int xy, int c, int attr)
1578 {
1579     int i, j;
1580     u_int8_t cline;
1581     u_int8_t *cpos;
1582     
1583     /* get char position in the pixel representation */
1584     cpos = (u_int8_t *)(0xC3000 + c * CharHeight);
1585
1586     for (i = 0; i < CharHeight; i++) {
1587         cline = cpos[i];
1588         for (j = 0; j < 4; j++) {
1589             if (attr & 0x8000) {
1590                 /* XOR */
1591                 if (attr & (0x0100 << j))
1592                     vram[xy + i * width / 8 + j * 0x10000] ^= cline;
1593             } else {
1594                 /* replace */
1595                 if (attr & (0x0100 << j))
1596                     vram[xy + i * width / 8 + j * 0x10000] &= ~cline;
1597                 else
1598                     vram[xy + i * width / 8 + j * 0x10000] |= cline;
1599             }
1600         }
1601     }
1602
1603     return;
1604 }
1605 #endif
1606
1607 void tty_pause(void)
1608 {
1609     sigset_t set;
1610
1611     sigprocmask(0, 0, &set);
1612     sigdelset(&set, SIGIO);
1613     sigdelset(&set, SIGALRM);
1614     sigsuspend(&set);
1615 }
1616
1617 static int nextchar = 0;
1618
1619 int
1620 tty_read(REGISTERS, int flag)
1621 {
1622     int r;
1623
1624     if ((r = nextchar) != 0) {
1625         nextchar = 0;
1626         return(r & 0xff);
1627     }
1628
1629     if ((flag & TTYF_REDIRECT) && redirect0) {
1630         char c;
1631         if (read(STDIN_FILENO, &c, 1) != 1)
1632             return(-1);
1633         if (c == '\n')
1634             c = '\r';
1635         return(c);
1636     }
1637
1638     if (KbdEmpty()) {
1639         if (flag & TTYF_BLOCK) {
1640             while (KbdEmpty())
1641                 tty_pause();
1642         } else {
1643             return(-1);
1644         }
1645     }
1646
1647     r = KbdRead();
1648     if ((r & 0xff) == 0)
1649         nextchar = r >> 8;
1650     r &= 0xff;
1651     if (flag & TTYF_CTRL) {
1652         if (r == 3) {
1653             /*
1654              * XXX - Not quite sure where we should return, maybe not
1655              *       all the way to the user, but...
1656              */
1657             if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
1658                 fake_int(REGS, 0x23);
1659                 R_EIP = R_EIP - 2;
1660                 return(-2);
1661             }
1662         }
1663     }
1664     if (flag & TTYF_ECHO) {
1665         if ((flag & TTYF_ECHONL) && (r == '\n' || r == '\r')) { 
1666             tty_write('\r', -1);
1667             tty_write('\n', -1);
1668         } else
1669             tty_write(r, -1);
1670     }
1671     return(r & 0xff);
1672 }
1673
1674 int
1675 tty_peek(REGISTERS, int flag)
1676 {
1677         int c;
1678
1679         if (c == nextchar)
1680             return(nextchar & 0xff);
1681
1682         if (KbdEmpty()) {
1683                 if (flag & TTYF_POLL) {
1684                         sleep_poll();
1685                         if (KbdEmpty())
1686                                 return(0);
1687                 } else if (flag & TTYF_BLOCK) {
1688                         while (KbdEmpty())
1689                                 tty_pause();
1690                 } else
1691                         return(0);
1692         }
1693         c = KbdPeek();
1694         if ((c & 0xff) == 3) {
1695             /*
1696              * XXX - Not quite sure where we should return, maybe not
1697              *       all the way to the user, but...
1698              */
1699             if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
1700                 fake_int(REGS, 0x23);
1701                 R_EIP = R_EIP - 2;
1702                 return(-2);
1703             }
1704         }
1705         return(0xff);
1706 }
1707
1708 int
1709 tty_state(void)
1710 {
1711         return(K1_STATUS);
1712 }
1713
1714 int
1715 tty_estate(void)
1716 {
1717     int state = 0;
1718     if (K2_STATUS & K2_SYSREQ)
1719         state |= 0x80;
1720     if (K2_STATUS & K2_CLOCK)
1721         state |= 0x40;
1722     if (K2_STATUS & K2_NLOCK)
1723         state |= 0x20;
1724     if (K2_STATUS & K2_SLOCK)
1725         state |= 0x10;
1726     if (K3_STATUS & K3_RALT)
1727         state |= 0x08;
1728     if (K3_STATUS & K3_RCTRL)
1729         state |= 0x04;
1730     if (K2_STATUS & K2_LALT)
1731         state |= 0x02;
1732     if (K2_STATUS & K2_LCTRL)
1733         state |= 0x01;
1734     return(state);
1735 }
1736
1737 static int
1738 inrange(int a, int n, int x)
1739 {
1740         return(a < n ? n : a > x ? x : a);
1741 }
1742
1743 void
1744 tty_scroll(int sr, int sc, int er, int ec, int n, int attr)
1745 {
1746         int i, j;
1747
1748         sr = inrange(sr, 0, height);
1749         er = inrange(er, 0, height);
1750         sc = inrange(sc, 0, width);
1751         ec = inrange(ec, 0, width);
1752         if (sr > er || sc > ec)
1753                 return;
1754         ++er;
1755         ++ec;
1756
1757         attr &= 0xff00;
1758         attr |= ' ';
1759
1760         if (n > 0 && n < er - sr) {
1761                 for (j = sr; j < er - n; ) {
1762                         memcpy(&vmem[j * width + sc],
1763                                &vmem[(j + n) * width + sc],
1764                                sizeof(vmem[0]) * (ec - sc));
1765                         ++j;
1766                 }
1767         } else
1768                 n = er - sr;
1769         for (j = er - n; j < er; ) {
1770                 for (i = sc; i < ec; ++i)
1771                         vmem[j * width + i] = attr;
1772                 ++j;
1773         }
1774 }
1775
1776 void
1777 tty_rscroll(int sr, int sc, int er, int ec, int n, int attr)
1778 {
1779         int i, j;
1780
1781         sr = inrange(sr, 0, height);
1782         er = inrange(er, 0, height);
1783         sc = inrange(sc, 0, width);
1784         ec = inrange(ec, 0, width);
1785         if (sr > er || sc > ec)
1786                 return;
1787         ++er;
1788         ++ec;
1789
1790         attr &= 0xff00;
1791         attr |= ' ';
1792
1793         if (n > 0 && n < er - sr) {
1794                 for (j = er; j > sr + n; ) {
1795                         --j;
1796                         memcpy(&vmem[j * width + sc],
1797                                &vmem[(j - n) * width + sc],
1798                                sizeof(vmem[0]) * (ec - sc));
1799                 }
1800         } else
1801                 n = er - sr;
1802         for (j = sr + n; j > sr; ) {
1803                 --j;
1804                 for (i = sc; i < ec; ++i)
1805                         vmem[j * width + i] = attr;
1806         }
1807 }
1808
1809 int
1810 tty_char(int r, int c)
1811 {
1812         if (r == -1)
1813                 r = row;
1814         if (c == -1)
1815                 c = col;
1816         r = inrange(r, 0, height);
1817         c = inrange(c, 0, width);
1818         return(vmem[r * width + c]);
1819 }
1820
1821 int
1822 KbdEmpty(void)
1823 {
1824         return(K_NEXT == K_FREE);
1825 }
1826
1827 void
1828 KbdWrite(u_short code)
1829 {
1830         int kf;
1831
1832         kf = K_FREE + 2;
1833         if (kf == K_BUFENDP)
1834                 kf = K_BUFSTARTP;
1835
1836         if (kf == K_NEXT) {
1837 #ifndef NO_X
1838                 XBell(dpy, 0);
1839 #endif
1840                 return;
1841         }
1842         K_BUF(K_FREE) = code;
1843         K_FREE = kf;
1844 }
1845
1846 u_short
1847 KbdRead(void)
1848 {
1849         int kf = K_NEXT;
1850
1851         K_NEXT = K_NEXT + 2;
1852         if (K_NEXT == K_BUFENDP)
1853                 K_NEXT = K_BUFSTARTP;
1854
1855         return(K_BUF(kf));
1856 }
1857
1858 u_short
1859 KbdPeek(void)
1860 {
1861         return(K_BUF(K_NEXT));
1862 }
1863
1864 void
1865 kbd_init(void)
1866 {
1867         u_long vec;
1868         
1869         define_input_port_handler(0x60, inb_port60);
1870
1871         K_BUFSTARTP = 0x1e;     /* Start of keyboard buffer */
1872         K_BUFENDP = 0x3e;       /* End of keyboard buffer */
1873         K_NEXT = K_FREE = K_BUFSTARTP;
1874         
1875         vec = insert_hardint_trampoline();
1876         ivec[0x09] = vec;
1877         register_callback(vec, int09, "int 09");
1878
1879         return;
1880 }
1881
1882 void
1883 kbd_bios_init(void)
1884 {
1885         BIOSDATA[0x96] = 0x10;  /* MF II kbd, 101 keys */
1886         K1_STATUS = 0;
1887         K2_STATUS = 0;
1888         K3_STATUS = 0;
1889         K4_STATUS = 0;
1890 }
1891
1892 #ifndef NO_X
1893 /* Calculate 16 bit RGB values for X from the 6 bit DAC values and the
1894    palette. This works for 16 and 256 color modes, although we don't really
1895    support the latter yet. */
1896 static void
1897 dac2rgb(XColor *color, int i)
1898 {
1899     int n, m;
1900
1901     /* 256 colors are easy; just take the RGB values from the DAC and
1902        shift left. For the pedants: multiplication with 65535./63. and
1903        rounding makes a difference of less than two percent. */
1904     if (VGA_ATC[ATC_ModeCtrl] & 0x40) {
1905         color->red   = dac_rgb[i].red << 10;
1906         color->green = dac_rgb[i].green << 10;
1907         color->blue  = dac_rgb[i].blue << 10;
1908
1909         return;
1910     }
1911
1912     /* For the 16 color modes, check bit 7 of the Mode Control register in
1913        the ATC. If set, we take bits 0-3 of the Color Select register and
1914        bits 0-3 of the palette register 'i' to build the index into the
1915        DAC table; otherwise, bits 2 and 3 of the CS reg and bits 0-5 of
1916        the palette register are used. Note that the entries in 'palette[]'
1917        are supposed to be already masked to 6 bits. */
1918     if (VGA_ATC[ATC_ModeCtrl] & 0x80) {
1919         n = VGA_ATC[ATC_ColorSelect] & 0x0f;
1920         m = palette[i] & 0x0f;
1921     } else {
1922         n = VGA_ATC[ATC_ColorSelect] & 0x0c;
1923         m = palette[i];
1924     }
1925     color->red   = dac_rgb[16*n + m].red << 10;
1926     color->green = dac_rgb[16*n + m].green << 10;
1927     color->blue  = dac_rgb[16*n + m].blue << 10;
1928 }
1929 #endif
1930
1931 /* Get a connection to the X server and create the window. */
1932 void
1933 init_window(void)
1934 {
1935 #ifndef NO_X
1936     XGCValues gcv;
1937     int i;
1938
1939     {
1940         /*
1941          * Arg...  I can no longer change X's fd out from under it.
1942          * Open up all the available fd's, leave 3 behind for X
1943          * to play with, open X and then release all the other fds
1944          */
1945         int nfds = sysconf(_SC_OPEN_MAX);
1946         int *fds = malloc(sizeof(int) * nfds);
1947         i = 0;
1948         if (fds)
1949             for (i = 0; i < nfds && (i == 0 || fds[i-1] < 63); ++i)
1950                 if ((fds[i] = open(_PATH_DEVNULL, 0)) < 0)
1951                     break;
1952         /*
1953          * Leave 3 fds behind for X to play with
1954          */
1955         if (i > 0) close(fds[--i]);
1956         if (i > 0) close(fds[--i]);
1957         if (i > 0) close(fds[--i]);
1958                 
1959         dpy = XOpenDisplay(NULL);
1960                 
1961         while (i > 0)
1962             close(fds[--i]);
1963     }
1964     if (dpy == NULL)
1965         err(1, "Could not open display ``%s''\n", XDisplayName(NULL));
1966     xfd = ConnectionNumber(dpy);
1967
1968     _RegisterIO(xfd, video_async_event, 0, Failure);
1969     if (debug_flags & D_DEBUGIN)
1970         _RegisterIO(0, debug_event, 0, Failure);
1971
1972     /* Create window, but defer setting a size and GC. */
1973     win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
1974                               1, 1, 2, black, black);
1975
1976     gcv.foreground = white;
1977     gcv.background = black;
1978     gc = XCreateGC(dpy, win, GCForeground | GCBackground, &gcv);
1979
1980     gcv.foreground = 1;
1981     gcv.background = 0;
1982     gcv.function = GXxor;
1983     cgc = XCreateGC(dpy, win, GCForeground|GCBackground|GCFunction, &gcv);
1984
1985     if (raw_kbd) {
1986         XSelectInput(dpy, win, ExposureMask | ButtonPressMask
1987                      | ButtonReleaseMask | PointerMotionMask );
1988     } else {
1989         XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask |
1990                      ExposureMask | ButtonPressMask
1991                      | ButtonReleaseMask | PointerMotionMask );
1992     }
1993
1994     XStoreName(dpy, win, "DOS");
1995
1996     /* Get the default visual and depth for later use. */
1997     depth = DefaultDepth(dpy, DefaultScreen(dpy));
1998     visual = DefaultVisual(dpy, DefaultScreen(dpy));
1999
2000     prepare_lut();
2001
2002 #if 0
2003     /* While we are developing the graphics code ... */
2004     call_on_quit(write_vram, NULL);
2005 #endif
2006 #endif
2007 }
2008
2009 void
2010 load_font(void)
2011 {
2012 #ifndef NO_X
2013     XGCValues gcv;
2014     
2015     if (!xfont)
2016         xfont = FONTVGA;
2017
2018     font = XLoadQueryFont(dpy, xfont);
2019
2020     if (font == NULL)
2021         font = XLoadQueryFont(dpy, FONTVGA);
2022
2023     if (font == NULL)
2024         err(1, "Could not open font ``%s''\n", xfont);
2025
2026     gcv.font = font->fid;
2027     XChangeGC(dpy, gc, GCFont, &gcv);
2028     
2029     FW = font->max_bounds.width;
2030     FH = font->max_bounds.ascent + font->max_bounds.descent;
2031     FD = font->max_bounds.descent;
2032
2033     /* Put the pixel representation at c000:3000. */
2034     switch (CharHeight) {
2035     case 8:
2036         memcpy((void *)0xc3000, font8x8, sizeof(font8x8));
2037         break;
2038     case 14:
2039         memcpy((void *)0xc3000, font8x14, sizeof(font8x14));
2040         break;
2041     case 16:
2042         memcpy((void *)0xc3000, font8x16, sizeof(font8x16));
2043         break;
2044     default:
2045         err(1, "load_font: CharHeight = %d?", CharHeight);
2046     }
2047     
2048     return;
2049 #endif
2050 }
2051
2052 /* Get a new, or resize an old XImage as canvas for the graphics display. */
2053 void
2054 get_ximage(void)
2055 {
2056 #ifndef NO_X
2057     if (xi != NULL)
2058         XFree(xi);
2059     
2060     xi = XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL,
2061                       width, height, 32, 0);
2062     if (xi == NULL)
2063         err(1, "Could not get ximage");
2064
2065     xi->data = malloc(width * height * depth / 8);
2066     if (xi->data == NULL) {
2067         XDestroyImage(xi);
2068         err(1, "Could not get memory for ximage data");
2069     }
2070
2071     return;
2072 #endif
2073 }
2074
2075 /* Get memory for the text line buffer. */
2076 void
2077 get_lines(void)
2078 {
2079     int i;
2080     
2081     if (lines == NULL) {
2082         lines = (TextLine *)malloc(sizeof(TextLine) * height);
2083         if (lines == NULL)
2084             err(1, "Could not allocate data structure for text lines\n");
2085
2086         for (i = 0; i < height; ++i) {
2087             lines[i].max_length = width;
2088             lines[i].data = (u_short *)malloc(width * sizeof(u_short));
2089             if (lines[i].data == NULL)
2090                 err(1, "Could not allocate data structure for text lines\n");
2091             lines[i].changed = 1;
2092         }
2093     } else {
2094         lines = (TextLine *)realloc(lines, sizeof(TextLine) * height);
2095         if (lines == NULL)
2096             err(1, "Could not allocate data structure for text lines\n");
2097
2098         for (i = 0; i < height; ++i) {
2099             lines[i].max_length = width;
2100             lines[i].data = (u_short *)realloc(lines[i].data,
2101                                                width * sizeof(u_short));
2102             if (lines[i].data == NULL)
2103                 err(1, "Could not allocate data structure for text lines\n");
2104             lines[i].changed = 1;
2105         }
2106     }
2107 }
2108
2109 #ifndef NO_X
2110 /* Prepare the LUT for the VRAM -> XImage conversion. */
2111 static void
2112 prepare_lut(void)
2113 {
2114     int i, j, k;
2115
2116     for (i = 0; i < 4; i++) {
2117         for (j = 0; j < 256; j++) {
2118             for (k = 0; k < 8; k++) {
2119                 lut[i][j][7 - k] = ((j & (1 << k)) ? (1 << i) : 0);
2120             }
2121         }
2122     }
2123
2124     return;
2125 }
2126 #endif
2127
2128 /* Resize the window, using information from 'vga_status[]'. This function is
2129    called after a mode change. */
2130 void
2131 resize_window(void)
2132 {
2133 #ifndef NO_X
2134     XSizeHints *sh;
2135     vmode_t vmode;
2136     
2137     sh = XAllocSizeHints();
2138     if (sh == NULL)
2139         err(1, "Could not get XSizeHints structure");
2140 #endif
2141     
2142     width = DpyCols;
2143     height = DpyRows + 1;
2144
2145 #ifndef NO_X
2146     vmode = vmodelist[find_vmode(VideoMode)];
2147     if (vmode.type == TEXT) {
2148         sh->base_width = FW * width + 4;
2149         sh->base_height = FH * height + 4;
2150         sh->base_width += 4;
2151         sh->base_height += 4;
2152     } else {
2153         width *= 8;
2154         height *= CharHeight;
2155         sh->base_width = width;
2156         sh->base_height = height;
2157     }
2158     
2159     sh->min_width = sh->max_width = sh->base_width;
2160     sh->min_height = sh->max_height = sh->base_height;
2161     sh->flags = USSize | PMinSize | PMaxSize | PSize;
2162
2163     debug(D_VIDEO, "VGA: Set window size %dx%d\n",
2164           sh->base_width, sh->base_height);
2165     
2166     XSetWMNormalHints(dpy, win, sh);
2167     XResizeWindow(dpy, win, sh->base_width, sh->base_height);
2168     XMapWindow(dpy, win);
2169     XFlush(dpy);
2170     
2171     XFree(sh);
2172     
2173     return;
2174 #endif
2175 }
2176
2177 /* Calculate 'pixels[]' from the current DAC table and palette.
2178
2179    To do: do not use 'pixels[]', use an array of 'XColor's which we can
2180    allocate and free on demand. Install a private colormap if necessary. */
2181 void
2182 update_pixels(void)
2183 {
2184 #ifndef NO_X
2185     int i;
2186
2187     /* We support only 16 colors for now. */
2188     for (i = 0; i < 16; i++) {
2189         XColor color;
2190
2191         dac2rgb(&color, i);
2192         if (XAllocColor(dpy,
2193                         DefaultColormap(dpy, DefaultScreen(dpy)), &color)) {
2194             pixels[i] = color.pixel;
2195         } else if (i < 7)
2196             pixels[i] = BlackPixel(dpy, DefaultScreen(dpy));
2197         else
2198             pixels[i] = WhitePixel(dpy, DefaultScreen(dpy));
2199     }
2200 #endif
2201 }
2202
2203 void
2204 write_vram(void *arg __unused)
2205 {
2206     int fd;
2207
2208     if ((fd = open("vram", O_WRONLY | O_CREAT, 0644)) == -1)
2209         err(1, "Can't open vram file");
2210     (void)write(fd, (void *)vram, 256 * 1024);
2211
2212     return;
2213 }