Merge branch 'vendor/GDB'
[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 __unused, int cond, void *arg __unused, 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 __unused, regcontext_t *REGS __unused)
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 __unused,
974     regcontext_t *REGS __unused)
975 {
976 #ifndef NO_X
977         int int9 = 0;
978
979         if (!(cond & AS_RD))
980             return;
981         
982         for (;;) {
983                 int x;
984                 fd_set fdset;
985                 XEvent ev;  
986                 static struct timeval tv;
987  
988                 /*
989                  * Handle any events just sitting around...
990                  */
991                 XFlush(dpy);
992                 while (QLength(dpy) > 0) {
993                         XNextEvent(dpy, &ev);
994                         int9 |= video_event(&ev);
995                 }
996
997                 FD_ZERO(&fdset);
998                 FD_SET(fd, &fdset);
999
1000                 x = select(FD_SETSIZE, &fdset, 0, 0, &tv);
1001
1002                 switch (x) {  
1003                 case -1:
1004                         /*
1005                          * Errno might be wrong, so we just select again.
1006                          * This could cause a problem is something really
1007                          * was wrong with select....
1008                          */
1009                         perror("select");
1010                         return;
1011                 case 0:
1012                         XFlush(dpy);
1013                         if (int9)
1014                             hardint(0x01);
1015                         return;
1016                 default:
1017                         if (FD_ISSET(fd, &fdset)) {
1018                                 do {
1019                                         XNextEvent(dpy, &ev);
1020                                         int9 |= video_event(&ev);
1021                                 } while (QLength(dpy));
1022                         }
1023                         break;
1024                 }
1025         }
1026 #endif
1027 }
1028
1029 #ifndef NO_X
1030 static int
1031 video_event(XEvent *ev)
1032 {
1033         switch (ev->type) {
1034         case MotionNotify: {
1035                 XMotionEvent *me = (XMotionEvent *)ev;
1036                 me->x -= 2;
1037                 me->y -= 2;
1038
1039                 mouse_status.x = (me->x < mouse_status.range.x)
1040                                     ? mouse_status.range.x
1041                                     : (me->x > mouse_status.range.w)
1042                                     ? mouse_status.range.w : me->x;
1043                 mouse_status.y = (me->y < mouse_status.range.y)
1044                                     ? mouse_status.range.y
1045                                     : (me->y > mouse_status.range.h)
1046                                     ? mouse_status.range.h : me->y;
1047                 break;
1048             }
1049         case ButtonRelease: {
1050                 XButtonEvent *be = (XButtonEvent *)ev;
1051                 be->x -= 2;
1052                 be->y -= 2;
1053
1054                 if (be->button < 3)
1055                     mouse_status.ups[be->button]++;
1056
1057                 mouse_status.x = (be->x < mouse_status.range.x)
1058                                     ? mouse_status.range.x
1059                                     : (be->x > mouse_status.range.w)
1060                                     ? mouse_status.range.w : be->x;
1061                 mouse_status.y = (be->y < mouse_status.range.y)
1062                                     ? mouse_status.range.y
1063                                     : (be->y > mouse_status.range.h)
1064                                     ? mouse_status.range.h : be->y;
1065                 break;
1066             }
1067         case ButtonPress: {
1068                 XButtonEvent *be = (XButtonEvent *)ev;
1069                 be->x -= 2;
1070                 be->y -= 2;
1071
1072                 if (be->button < 3)
1073                     mouse_status.downs[be->button]++;
1074
1075                 mouse_status.x = (be->x < mouse_status.range.x)
1076                                     ? mouse_status.range.x
1077                                     : (be->x > mouse_status.range.w)
1078                                     ? mouse_status.range.w : be->x;
1079                 mouse_status.y = (be->y < mouse_status.range.y)
1080                                     ? mouse_status.range.y
1081                                     : (be->y > mouse_status.range.h)
1082                                     ? mouse_status.range.h : be->y;
1083
1084                 if ((K1_STATUS & (K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
1085                     quit(0);
1086                 }
1087                 break;
1088             }
1089         case NoExpose:
1090                 break;
1091         case GraphicsExpose:
1092         case Expose: {
1093                 int r;
1094                 for (r = 0; r < height; ++r)
1095                     lines[r].changed = 1;
1096                 break;
1097             }
1098         case KeyRelease: {
1099                 static char buf[128];
1100                 KeySym ks;
1101
1102                 break_code |= 0x80;
1103
1104                 if (!(ev->xkey.state & ShiftMask)) {
1105                     K1_STATUS &= ~K1_LSHIFT;
1106                     K1_STATUS &= ~K1_RSHIFT;
1107                 }
1108                 if (!(ev->xkey.state & ControlMask)) {
1109                         K1_STATUS &= ~K1_CTRL;
1110                         K2_STATUS &= ~K2_LCTRL;
1111                         K3_STATUS &= ~K3_RCTRL;
1112                 }
1113                 if (!(ev->xkey.state & Mod1Mask)) {
1114                         K1_STATUS &= ~K1_ALT;
1115                         K2_STATUS &= ~K2_LALT;
1116                         K3_STATUS &= ~K3_RALT;
1117                 }
1118                 if (!(ev->xkey.state & LockMask)) {
1119                         K2_STATUS &= ~K2_CLOCK;
1120                 }
1121
1122                 XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
1123                 switch (ks) {
1124                 case XK_Shift_L:
1125                         K1_STATUS &= ~K1_LSHIFT;
1126                         break;
1127                 case XK_Shift_R:
1128                         K1_STATUS &= ~K1_RSHIFT;
1129                         break;
1130                 case XK_Control_L:
1131                         K1_STATUS &= ~K1_CTRL;
1132                         K2_STATUS &= ~K2_LCTRL;
1133                         break;
1134                 case XK_Control_R:
1135                         K1_STATUS &= ~K1_CTRL;
1136                         K3_STATUS &= ~K3_RCTRL;
1137                         break;
1138                 case XK_Alt_L:
1139                         K1_STATUS &= ~K1_ALT;
1140                         K2_STATUS &= ~K2_LALT;
1141                         break;
1142                 case XK_Alt_R:
1143                         K1_STATUS &= ~K1_ALT;
1144                         K3_STATUS &= ~K3_RALT;
1145                         break;
1146                 case XK_Scroll_Lock:
1147                         K2_STATUS &= ~K2_SLOCK;
1148                         break;
1149                 case XK_Num_Lock:
1150                         K2_STATUS &= ~K2_NLOCK;
1151                         break;
1152                 case XK_Caps_Lock:
1153                         K2_STATUS &= ~K2_CLOCK;
1154                         break;
1155                 case XK_Insert:
1156                         K2_STATUS &= ~K2_INSERT;
1157                         break;
1158                 }
1159                 return(1);
1160             }
1161         case KeyPress: {
1162                 static char buf[128];
1163                 KeySym ks;
1164                 int n;
1165                 int nlock = 0;
1166                 u_short scan = 0xffff;
1167
1168                 if (!(ev->xkey.state & ShiftMask)) {
1169                     K1_STATUS &= ~K1_LSHIFT;
1170                     K1_STATUS &= ~K1_RSHIFT;
1171                 }
1172                 if (!(ev->xkey.state & ControlMask)) {
1173                         K1_STATUS &= ~K1_CTRL;
1174                         K2_STATUS &= ~K2_LCTRL;
1175                         K3_STATUS &= ~K3_RCTRL;
1176                 }
1177                 if (!(ev->xkey.state & Mod1Mask)) {
1178                         K1_STATUS &= ~K1_ALT;
1179                         K2_STATUS &= ~K2_LALT;
1180                         K3_STATUS &= ~K3_RALT;
1181                 }
1182                 if (!(ev->xkey.state & LockMask)) {
1183                         K2_STATUS &= ~K2_CLOCK;
1184                 }
1185
1186                 n = XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &ks, 0);
1187
1188                 switch (ks) {
1189                 case XK_Shift_L:
1190                         K1_STATUS |= K1_LSHIFT;
1191                         break;
1192                 case XK_Shift_R:
1193                         K1_STATUS |= K1_RSHIFT;
1194                         break;
1195                 case XK_Control_L:
1196                         K1_STATUS |= K1_CTRL;
1197                         K2_STATUS |= K2_LCTRL;
1198                         break;
1199                 case XK_Control_R:
1200                         K1_STATUS |= K1_CTRL;
1201                         K3_STATUS |= K3_RCTRL;
1202                         break;
1203                 case XK_Alt_L:
1204                         K1_STATUS |= K1_ALT;
1205                         K2_STATUS |= K2_LALT;
1206                         break;
1207                 case XK_Alt_R:
1208                         K1_STATUS |= K1_ALT;
1209                         K3_STATUS |= K3_RALT;
1210                         break;
1211                 case XK_Scroll_Lock:
1212                         K1_STATUS ^= K1_SLOCK;
1213                         K2_STATUS |= K2_SLOCK;
1214                         break;
1215                 case XK_Num_Lock:
1216                         K1_STATUS ^= K1_NLOCK;
1217                         K2_STATUS |= K2_NLOCK;
1218                         break;
1219                 case XK_Caps_Lock:
1220                         K1_STATUS ^= K1_CLOCK;
1221                         K2_STATUS |= K2_CLOCK;
1222                         break;
1223                 case XK_Insert:
1224                 case XK_KP_Insert:
1225                         K1_STATUS ^= K1_INSERT;
1226                         K2_STATUS |= K2_INSERT;
1227                         scan = 82;
1228                         goto docode;
1229
1230                 case XK_Escape:
1231                         scan = 1;
1232                         goto docode;
1233
1234                 case XK_Tab:
1235                 case XK_ISO_Left_Tab:
1236                         scan = 15;
1237                         goto docode;
1238                         
1239                 case XK_Return:
1240                 case XK_KP_Enter:
1241                         scan = 28;
1242                         goto docode;
1243
1244                 case XK_Print:
1245                         scan = 55;
1246                         goto docode;
1247
1248                 case XK_F1:
1249                 case XK_F2:
1250                 case XK_F3:
1251                 case XK_F4:
1252                 case XK_F5:
1253                 case XK_F6:
1254                 case XK_F7:
1255                 case XK_F8:
1256                 case XK_F9:
1257                 case XK_F10:
1258                         scan = ks - XK_F1 + 59;
1259                         goto docode;
1260
1261                 case XK_KP_7:
1262                         nlock = 1;
1263                 case XK_Home:
1264                 case XK_KP_Home:
1265                         scan = 71;
1266                         goto docode;
1267                 case XK_KP_8:
1268                         nlock = 1;
1269                 case XK_Up:
1270                 case XK_KP_Up:
1271                         scan = 72;
1272                         goto docode;
1273                 case XK_KP_9:
1274                         nlock = 1;
1275                 case XK_Prior:
1276                 case XK_KP_Prior:
1277                         scan = 73;
1278                         goto docode;
1279                 case XK_KP_Subtract:
1280                         scan = 74;
1281                         goto docode;
1282                 case XK_KP_4:
1283                         nlock = 1;
1284                 case XK_Left:
1285                 case XK_KP_Left:
1286                         scan = 75;
1287                         goto docode;
1288                 case XK_KP_5:
1289                         nlock = 1;
1290                 case XK_Begin:
1291                 case XK_KP_Begin:
1292                         scan = 76;
1293                         goto docode;
1294                 case XK_KP_6:
1295                         nlock = 1;
1296                 case XK_Right:
1297                 case XK_KP_Right:
1298                         scan = 77;
1299                         goto docode;
1300                 case XK_KP_Add:
1301                         scan = 78;
1302                         goto docode;
1303                 case XK_KP_1:
1304                         nlock = 1;
1305                 case XK_End:
1306                 case XK_KP_End:
1307                         scan = 79;
1308                         goto docode;
1309                 case XK_KP_2:
1310                         nlock = 1;
1311                 case XK_Down:
1312                 case XK_KP_Down:
1313                         scan = 80;
1314                         goto docode;
1315                 case XK_KP_3:
1316                         nlock = 1;
1317                 case XK_Next:
1318                 case XK_KP_Next:
1319                         scan = 81;
1320                         goto docode;
1321                 case XK_KP_0:
1322                         nlock = 1;
1323                 /* case XK_Insert: This is above */
1324                         scan = 82;
1325                         goto docode;
1326
1327                 case XK_KP_Decimal:
1328                         nlock = 1;
1329                         scan = 83;
1330                         goto docode;
1331
1332                 case XK_Delete:
1333                 case XK_KP_Delete:
1334                         scan = flipdelete ? 14 : 83;
1335                         goto docode;
1336
1337                 case XK_BackSpace:
1338                         scan = flipdelete ? 83 : 14;
1339                         goto docode;
1340
1341                 case XK_F11:
1342                         scan = 87;
1343                         goto docode;
1344                 case XK_F12:
1345                         scan = 88;
1346                         goto docode;
1347
1348
1349                 case XK_KP_Divide:
1350                         scan = Ascii2Scan['/'];
1351                         goto docode;
1352
1353                 case XK_KP_Multiply:
1354                         scan = Ascii2Scan['*'];
1355                         goto docode;
1356
1357                 default:
1358                         if ((K1_STATUS&(K1_ALT|K1_CTRL)) == (K1_ALT|K1_CTRL)) {
1359                                 if (ks == 'T' || ks == 't') {
1360                                     tmode ^= 1;
1361                                     if (!tmode)
1362                                             resettrace((regcontext_t *)&saved_sigframe->
1363                                                 sf_uc.uc_mcontext); 
1364                                     break;
1365                                 }
1366                                 if (ks == 'R' || ks == 'r') {
1367                                     kill(getpid(), SIGALRM);    /* redraw */
1368                                     break;
1369                                 }
1370                         }
1371                         if (ks < ' ' || ks > '~')
1372                                 break;
1373                         scan = Ascii2Scan[ks]; 
1374                 docode:
1375                         if (nlock)
1376                             scan |= 0x100;
1377
1378                         if ((scan & ~0x100) > 88) {
1379                             scan = 0xffff;
1380                             break;
1381                         }
1382
1383                         if ((K1_STATUS & K1_SHIFT) || (scan & 0x100)) {
1384                             scan = ScanCodes[scan & 0xff].shift;
1385                         } else if (K1_STATUS & K1_CTRL) {
1386                             scan = ScanCodes[scan & 0xff].ctrl;
1387                         } else if (K1_STATUS & K1_ALT) {
1388                             scan = ScanCodes[scan & 0xff].alt;
1389                         }  else
1390                             scan = ScanCodes[scan & 0xff].base;
1391
1392                         break;
1393                 }
1394                 if (scan != 0xffff) {
1395                         break_code = scan >> 8;
1396                         KbdWrite(scan);
1397                 }
1398                 return(1);
1399             }
1400         default:
1401                 break;
1402         }
1403         return(0);
1404 }
1405 #endif
1406
1407 void
1408 tty_move(int r, int c)
1409 {
1410         row = r;
1411         col = c;
1412         SetVREGCur();
1413 }
1414
1415 void
1416 tty_report(int *r, int *c)
1417 {
1418         *r = row;
1419         *c = col;
1420 }
1421
1422 void
1423 tty_flush(void)
1424 {
1425         K_NEXT = K_FREE = K_BUFSTARTP;
1426 }
1427
1428 void
1429 tty_index(int scroll)
1430 {
1431         int i;
1432
1433         if (row > (height - 1))
1434                 row = 0;
1435         else if (++row >= height) {
1436                 row = height - 1;
1437                 if (scroll) {
1438                         memcpy(vmem, &vmem[width], 2 * width * (height - 1));
1439                         for (i = 0; i < width; ++i)
1440                                 vmem[(height - 1) * width + i] = vattr | ' ';
1441                 }
1442         }
1443         SetVREGCur();
1444 }
1445
1446 void
1447 tty_write(int c, int attr)
1448 {
1449         if (attr == TTYF_REDIRECT) {
1450                 if (redirect1) {
1451                     write(1, &c, 1);
1452                     return;
1453                 }
1454                 attr = -1;
1455         }
1456         if (capture_fd >= 0) {
1457             char cc = c;
1458             write(capture_fd, &cc, 1);
1459         }
1460         c &= 0xff;
1461         switch (c) {
1462         case 0x07:
1463                 if (xmode) {
1464 #ifndef NO_X
1465                         XBell(dpy, 0);
1466 #endif
1467                 } else
1468                         write(1, "\007", 1);
1469                 break;
1470         case 0x08:
1471                 if (row > (height - 1) || col > width)
1472                         break;
1473                 if (col > 0)
1474                         --col;
1475                 vmem[row * width + col] &= 0xff00;
1476                 break;
1477         case '\t':
1478                 if (row > (height - 1))
1479                         row = 0;
1480                 col = (col + 8) & ~0x07;
1481                 if (col > width) {
1482                         col = 0;
1483                         tty_index(1);
1484                 }
1485                 break;
1486         case '\r':
1487                 col = 0;
1488                 break;
1489         case '\n':
1490                 tty_index(1);
1491                 break;
1492         default:
1493                 if (col >= width) {
1494                         col = 0;
1495                         tty_index(1);
1496                 }
1497                 if (row > (height - 1))
1498                         row = 0;
1499                 if (attr >= 0)
1500                         vmem[row * width + col] = attr & 0xff00;
1501                 else
1502                         vmem[row * width + col] &= 0xff00;
1503                 vmem[row * width + col++] |= c;
1504                 break;
1505         }
1506         SetVREGCur();
1507 }
1508
1509 void
1510 tty_rwrite(int n, int c, int attr)
1511 {
1512     u_char srow, scol;
1513     c &= 0xff;
1514
1515 #ifndef NO_X
1516     if (VGA_ATC[ATC_ModeCtrl] & 1) {
1517         tty_rwrite_graphics(n, c, attr);
1518         return;
1519     }
1520 #endif
1521     
1522     srow = row;
1523     scol = col;
1524     while (n--) {
1525         if (col >= width) {
1526             col = 0;
1527             tty_index(0);
1528         }
1529         if (row > (height - 1))
1530             row = 0;
1531         if (attr >= 0)
1532             vmem[row * width + col] = attr & 0xff00;
1533         else
1534             vmem[row * width + col] &= 0xff00;
1535         vmem[row * width + col++] |= c;
1536     }
1537     row = srow;
1538     col = scol;
1539     SetVREGCur();
1540 }
1541
1542 #ifndef NO_X
1543 /* Write a character in graphics mode. Note that the text is put at *text*
1544    coordinates. */
1545 static void
1546 tty_rwrite_graphics(int n, int c, int attr)
1547 {
1548     u_int8_t srow, scol;
1549     int ht = height / CharHeight;
1550     int wd = width / 8;
1551
1552     srow = row;
1553     scol = col;
1554
1555     while (n--) {
1556         if (col >= wd) {
1557             col = 0;
1558             /* tty_index(0); *//* scroll up if last line is filled */
1559         }
1560         if (row > (ht - 1))
1561             row = 0;
1562         putchar_graphics(row * wd * CharHeight + col, c, attr);
1563         col++;
1564     }
1565     row = srow;
1566     col = scol;
1567     SetVREGCur();
1568
1569     return;
1570 }
1571
1572 /* Put the character together from its pixel representation in 'font8xXX[]'
1573    and write it to 'vram'. The attribute byte gives the desired color; if bit
1574    7 is set, the pixels are XOR'd with the underlying color(s).
1575
1576    XXX This must be updated for the 256 color modes. */
1577 static void
1578 putchar_graphics(int xy, int c, int attr)
1579 {
1580     int i, j;
1581     u_int8_t cline;
1582     u_int8_t *cpos;
1583     
1584     /* get char position in the pixel representation */
1585     cpos = (u_int8_t *)(0xC3000 + c * CharHeight);
1586
1587     for (i = 0; i < CharHeight; i++) {
1588         cline = cpos[i];
1589         for (j = 0; j < 4; j++) {
1590             if (attr & 0x8000) {
1591                 /* XOR */
1592                 if (attr & (0x0100 << j))
1593                     vram[xy + i * width / 8 + j * 0x10000] ^= cline;
1594             } else {
1595                 /* replace */
1596                 if (attr & (0x0100 << j))
1597                     vram[xy + i * width / 8 + j * 0x10000] &= ~cline;
1598                 else
1599                     vram[xy + i * width / 8 + j * 0x10000] |= cline;
1600             }
1601         }
1602     }
1603
1604     return;
1605 }
1606 #endif
1607
1608 void tty_pause(void)
1609 {
1610     sigset_t set;
1611
1612     sigprocmask(0, 0, &set);
1613     sigdelset(&set, SIGIO);
1614     sigdelset(&set, SIGALRM);
1615     sigsuspend(&set);
1616 }
1617
1618 static int nextchar = 0;
1619
1620 int
1621 tty_read(REGISTERS, int flag)
1622 {
1623     int r;
1624
1625     if ((r = nextchar) != 0) {
1626         nextchar = 0;
1627         return(r & 0xff);
1628     }
1629
1630     if ((flag & TTYF_REDIRECT) && redirect0) {
1631         char c;
1632         if (read(STDIN_FILENO, &c, 1) != 1)
1633             return(-1);
1634         if (c == '\n')
1635             c = '\r';
1636         return(c);
1637     }
1638
1639     if (KbdEmpty()) {
1640         if (flag & TTYF_BLOCK) {
1641             while (KbdEmpty())
1642                 tty_pause();
1643         } else {
1644             return(-1);
1645         }
1646     }
1647
1648     r = KbdRead();
1649     if ((r & 0xff) == 0)
1650         nextchar = r >> 8;
1651     r &= 0xff;
1652     if (flag & TTYF_CTRL) {
1653         if (r == 3) {
1654             /*
1655              * XXX - Not quite sure where we should return, maybe not
1656              *       all the way to the user, but...
1657              */
1658             if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
1659                 fake_int(REGS, 0x23);
1660                 R_EIP = R_EIP - 2;
1661                 return(-2);
1662             }
1663         }
1664     }
1665     if (flag & TTYF_ECHO) {
1666         if ((flag & TTYF_ECHONL) && (r == '\n' || r == '\r')) { 
1667             tty_write('\r', -1);
1668             tty_write('\n', -1);
1669         } else
1670             tty_write(r, -1);
1671     }
1672     return(r & 0xff);
1673 }
1674
1675 int
1676 tty_peek(REGISTERS, int flag)
1677 {
1678         int c = 0;
1679
1680         if (c == nextchar)
1681             return(nextchar & 0xff);
1682
1683         if (KbdEmpty()) {
1684                 if (flag & TTYF_POLL) {
1685                         sleep_poll();
1686                         if (KbdEmpty())
1687                                 return(0);
1688                 } else if (flag & TTYF_BLOCK) {
1689                         while (KbdEmpty())
1690                                 tty_pause();
1691                 } else
1692                         return(0);
1693         }
1694         c = KbdPeek();
1695         if ((c & 0xff) == 3) {
1696             /*
1697              * XXX - Not quite sure where we should return, maybe not
1698              *       all the way to the user, but...
1699              */
1700             if (ivec[0x23] && (ivec[0x23] >> 16) != 0xF000) {
1701                 fake_int(REGS, 0x23);
1702                 R_EIP = R_EIP - 2;
1703                 return(-2);
1704             }
1705         }
1706         return(0xff);
1707 }
1708
1709 int
1710 tty_state(void)
1711 {
1712         return(K1_STATUS);
1713 }
1714
1715 int
1716 tty_estate(void)
1717 {
1718     int state = 0;
1719     if (K2_STATUS & K2_SYSREQ)
1720         state |= 0x80;
1721     if (K2_STATUS & K2_CLOCK)
1722         state |= 0x40;
1723     if (K2_STATUS & K2_NLOCK)
1724         state |= 0x20;
1725     if (K2_STATUS & K2_SLOCK)
1726         state |= 0x10;
1727     if (K3_STATUS & K3_RALT)
1728         state |= 0x08;
1729     if (K3_STATUS & K3_RCTRL)
1730         state |= 0x04;
1731     if (K2_STATUS & K2_LALT)
1732         state |= 0x02;
1733     if (K2_STATUS & K2_LCTRL)
1734         state |= 0x01;
1735     return(state);
1736 }
1737
1738 static int
1739 inrange(int a, int n, int x)
1740 {
1741         return(a < n ? n : a > x ? x : a);
1742 }
1743
1744 void
1745 tty_scroll(int sr, int sc, int er, int ec, int n, int attr)
1746 {
1747         int i, j;
1748
1749         sr = inrange(sr, 0, height);
1750         er = inrange(er, 0, height);
1751         sc = inrange(sc, 0, width);
1752         ec = inrange(ec, 0, width);
1753         if (sr > er || sc > ec)
1754                 return;
1755         ++er;
1756         ++ec;
1757
1758         attr &= 0xff00;
1759         attr |= ' ';
1760
1761         if (n > 0 && n < er - sr) {
1762                 for (j = sr; j < er - n; ) {
1763                         memcpy(&vmem[j * width + sc],
1764                                &vmem[(j + n) * width + sc],
1765                                sizeof(vmem[0]) * (ec - sc));
1766                         ++j;
1767                 }
1768         } else
1769                 n = er - sr;
1770         for (j = er - n; j < er; ) {
1771                 for (i = sc; i < ec; ++i)
1772                         vmem[j * width + i] = attr;
1773                 ++j;
1774         }
1775 }
1776
1777 void
1778 tty_rscroll(int sr, int sc, int er, int ec, int n, int attr)
1779 {
1780         int i, j;
1781
1782         sr = inrange(sr, 0, height);
1783         er = inrange(er, 0, height);
1784         sc = inrange(sc, 0, width);
1785         ec = inrange(ec, 0, width);
1786         if (sr > er || sc > ec)
1787                 return;
1788         ++er;
1789         ++ec;
1790
1791         attr &= 0xff00;
1792         attr |= ' ';
1793
1794         if (n > 0 && n < er - sr) {
1795                 for (j = er; j > sr + n; ) {
1796                         --j;
1797                         memcpy(&vmem[j * width + sc],
1798                                &vmem[(j - n) * width + sc],
1799                                sizeof(vmem[0]) * (ec - sc));
1800                 }
1801         } else
1802                 n = er - sr;
1803         for (j = sr + n; j > sr; ) {
1804                 --j;
1805                 for (i = sc; i < ec; ++i)
1806                         vmem[j * width + i] = attr;
1807         }
1808 }
1809
1810 int
1811 tty_char(int r, int c)
1812 {
1813         if (r == -1)
1814                 r = row;
1815         if (c == -1)
1816                 c = col;
1817         r = inrange(r, 0, height);
1818         c = inrange(c, 0, width);
1819         return(vmem[r * width + c]);
1820 }
1821
1822 int
1823 KbdEmpty(void)
1824 {
1825         return(K_NEXT == K_FREE);
1826 }
1827
1828 void
1829 KbdWrite(u_short code)
1830 {
1831         int kf;
1832
1833         kf = K_FREE + 2;
1834         if (kf == K_BUFENDP)
1835                 kf = K_BUFSTARTP;
1836
1837         if (kf == K_NEXT) {
1838 #ifndef NO_X
1839                 XBell(dpy, 0);
1840 #endif
1841                 return;
1842         }
1843         K_BUF(K_FREE) = code;
1844         K_FREE = kf;
1845 }
1846
1847 u_short
1848 KbdRead(void)
1849 {
1850         int kf = K_NEXT;
1851
1852         K_NEXT = K_NEXT + 2;
1853         if (K_NEXT == K_BUFENDP)
1854                 K_NEXT = K_BUFSTARTP;
1855
1856         return(K_BUF(kf));
1857 }
1858
1859 u_short
1860 KbdPeek(void)
1861 {
1862         return(K_BUF(K_NEXT));
1863 }
1864
1865 void
1866 kbd_init(void)
1867 {
1868         u_long vec;
1869         
1870         define_input_port_handler(0x60, inb_port60);
1871
1872         K_BUFSTARTP = 0x1e;     /* Start of keyboard buffer */
1873         K_BUFENDP = 0x3e;       /* End of keyboard buffer */
1874         K_NEXT = K_FREE = K_BUFSTARTP;
1875         
1876         vec = insert_hardint_trampoline();
1877         ivec[0x09] = vec;
1878         register_callback(vec, int09, "int 09");
1879
1880         return;
1881 }
1882
1883 void
1884 kbd_bios_init(void)
1885 {
1886         BIOSDATA[0x96] = 0x10;  /* MF II kbd, 101 keys */
1887         K1_STATUS = 0;
1888         K2_STATUS = 0;
1889         K3_STATUS = 0;
1890         K4_STATUS = 0;
1891 }
1892
1893 #ifndef NO_X
1894 /* Calculate 16 bit RGB values for X from the 6 bit DAC values and the
1895    palette. This works for 16 and 256 color modes, although we don't really
1896    support the latter yet. */
1897 static void
1898 dac2rgb(XColor *color, int i)
1899 {
1900     int n, m;
1901
1902     /* 256 colors are easy; just take the RGB values from the DAC and
1903        shift left. For the pedants: multiplication with 65535./63. and
1904        rounding makes a difference of less than two percent. */
1905     if (VGA_ATC[ATC_ModeCtrl] & 0x40) {
1906         color->red   = dac_rgb[i].red << 10;
1907         color->green = dac_rgb[i].green << 10;
1908         color->blue  = dac_rgb[i].blue << 10;
1909
1910         return;
1911     }
1912
1913     /* For the 16 color modes, check bit 7 of the Mode Control register in
1914        the ATC. If set, we take bits 0-3 of the Color Select register and
1915        bits 0-3 of the palette register 'i' to build the index into the
1916        DAC table; otherwise, bits 2 and 3 of the CS reg and bits 0-5 of
1917        the palette register are used. Note that the entries in 'palette[]'
1918        are supposed to be already masked to 6 bits. */
1919     if (VGA_ATC[ATC_ModeCtrl] & 0x80) {
1920         n = VGA_ATC[ATC_ColorSelect] & 0x0f;
1921         m = palette[i] & 0x0f;
1922     } else {
1923         n = VGA_ATC[ATC_ColorSelect] & 0x0c;
1924         m = palette[i];
1925     }
1926     color->red   = dac_rgb[16*n + m].red << 10;
1927     color->green = dac_rgb[16*n + m].green << 10;
1928     color->blue  = dac_rgb[16*n + m].blue << 10;
1929 }
1930 #endif
1931
1932 /* Get a connection to the X server and create the window. */
1933 void
1934 init_window(void)
1935 {
1936 #ifndef NO_X
1937     XGCValues gcv;
1938     int i;
1939
1940     {
1941         /*
1942          * Arg...  I can no longer change X's fd out from under it.
1943          * Open up all the available fd's, leave 3 behind for X
1944          * to play with, open X and then release all the other fds
1945          */
1946         int nfds = sysconf(_SC_OPEN_MAX);
1947         int *fds = malloc(sizeof(int) * nfds);
1948         i = 0;
1949         if (fds)
1950             for (i = 0; i < nfds && (i == 0 || fds[i-1] < 63); ++i)
1951                 if ((fds[i] = open(_PATH_DEVNULL, 0)) < 0)
1952                     break;
1953         /*
1954          * Leave 3 fds behind for X to play with
1955          */
1956         if (i > 0) close(fds[--i]);
1957         if (i > 0) close(fds[--i]);
1958         if (i > 0) close(fds[--i]);
1959                 
1960         dpy = XOpenDisplay(NULL);
1961                 
1962         while (i > 0)
1963             close(fds[--i]);
1964     }
1965     if (dpy == NULL)
1966         err(1, "Could not open display ``%s''\n", XDisplayName(NULL));
1967     xfd = ConnectionNumber(dpy);
1968
1969     _RegisterIO(xfd, video_async_event, 0, Failure);
1970     if (debug_flags & D_DEBUGIN)
1971         _RegisterIO(0, debug_event, 0, Failure);
1972
1973     /* Create window, but defer setting a size and GC. */
1974     win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
1975                               1, 1, 2, black, black);
1976
1977     gcv.foreground = white;
1978     gcv.background = black;
1979     gc = XCreateGC(dpy, win, GCForeground | GCBackground, &gcv);
1980
1981     gcv.foreground = 1;
1982     gcv.background = 0;
1983     gcv.function = GXxor;
1984     cgc = XCreateGC(dpy, win, GCForeground|GCBackground|GCFunction, &gcv);
1985
1986     if (raw_kbd) {
1987         XSelectInput(dpy, win, ExposureMask | ButtonPressMask
1988                      | ButtonReleaseMask | PointerMotionMask );
1989     } else {
1990         XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask |
1991                      ExposureMask | ButtonPressMask
1992                      | ButtonReleaseMask | PointerMotionMask );
1993     }
1994
1995     XStoreName(dpy, win, "DOS");
1996
1997     /* Get the default visual and depth for later use. */
1998     depth = DefaultDepth(dpy, DefaultScreen(dpy));
1999     visual = DefaultVisual(dpy, DefaultScreen(dpy));
2000
2001     prepare_lut();
2002
2003 #if 0
2004     /* While we are developing the graphics code ... */
2005     call_on_quit(write_vram, NULL);
2006 #endif
2007 #endif
2008 }
2009
2010 void
2011 load_font(void)
2012 {
2013 #ifndef NO_X
2014     XGCValues gcv;
2015     
2016     if (!xfont)
2017         xfont = FONTVGA;
2018
2019     font = XLoadQueryFont(dpy, xfont);
2020
2021     if (font == NULL)
2022         font = XLoadQueryFont(dpy, FONTVGA);
2023
2024     if (font == NULL)
2025         err(1, "Could not open font ``%s''\n", xfont);
2026
2027     gcv.font = font->fid;
2028     XChangeGC(dpy, gc, GCFont, &gcv);
2029     
2030     FW = font->max_bounds.width;
2031     FH = font->max_bounds.ascent + font->max_bounds.descent;
2032     FD = font->max_bounds.descent;
2033
2034     /* Put the pixel representation at c000:3000. */
2035     switch (CharHeight) {
2036     case 8:
2037         memcpy((void *)0xc3000, font8x8, sizeof(font8x8));
2038         break;
2039     case 14:
2040         memcpy((void *)0xc3000, font8x14, sizeof(font8x14));
2041         break;
2042     case 16:
2043         memcpy((void *)0xc3000, font8x16, sizeof(font8x16));
2044         break;
2045     default:
2046         err(1, "load_font: CharHeight = %d?", CharHeight);
2047     }
2048     
2049     return;
2050 #endif
2051 }
2052
2053 /* Get a new, or resize an old XImage as canvas for the graphics display. */
2054 void
2055 get_ximage(void)
2056 {
2057 #ifndef NO_X
2058     if (xi != NULL)
2059         XFree(xi);
2060     
2061     xi = XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL,
2062                       width, height, 32, 0);
2063     if (xi == NULL)
2064         err(1, "Could not get ximage");
2065
2066     xi->data = malloc(width * height * depth / 8);
2067     if (xi->data == NULL) {
2068         XDestroyImage(xi);
2069         err(1, "Could not get memory for ximage data");
2070     }
2071
2072     return;
2073 #endif
2074 }
2075
2076 /* Get memory for the text line buffer. */
2077 void
2078 get_lines(void)
2079 {
2080     int i;
2081     
2082     if (lines == NULL) {
2083         lines = (TextLine *)malloc(sizeof(TextLine) * height);
2084         if (lines == NULL)
2085             err(1, "Could not allocate data structure for text lines\n");
2086
2087         for (i = 0; i < height; ++i) {
2088             lines[i].max_length = width;
2089             lines[i].data = (u_short *)malloc(width * sizeof(u_short));
2090             if (lines[i].data == NULL)
2091                 err(1, "Could not allocate data structure for text lines\n");
2092             lines[i].changed = 1;
2093         }
2094     } else {
2095         lines = (TextLine *)realloc(lines, sizeof(TextLine) * height);
2096         if (lines == NULL)
2097             err(1, "Could not allocate data structure for text lines\n");
2098
2099         for (i = 0; i < height; ++i) {
2100             lines[i].max_length = width;
2101             lines[i].data = (u_short *)realloc(lines[i].data,
2102                                                width * sizeof(u_short));
2103             if (lines[i].data == NULL)
2104                 err(1, "Could not allocate data structure for text lines\n");
2105             lines[i].changed = 1;
2106         }
2107     }
2108 }
2109
2110 #ifndef NO_X
2111 /* Prepare the LUT for the VRAM -> XImage conversion. */
2112 static void
2113 prepare_lut(void)
2114 {
2115     int i, j, k;
2116
2117     for (i = 0; i < 4; i++) {
2118         for (j = 0; j < 256; j++) {
2119             for (k = 0; k < 8; k++) {
2120                 lut[i][j][7 - k] = ((j & (1 << k)) ? (1 << i) : 0);
2121             }
2122         }
2123     }
2124
2125     return;
2126 }
2127 #endif
2128
2129 /* Resize the window, using information from 'vga_status[]'. This function is
2130    called after a mode change. */
2131 void
2132 resize_window(void)
2133 {
2134 #ifndef NO_X
2135     XSizeHints *sh;
2136     vmode_t vmode;
2137     
2138     sh = XAllocSizeHints();
2139     if (sh == NULL)
2140         err(1, "Could not get XSizeHints structure");
2141 #endif
2142     
2143     width = DpyCols;
2144     height = DpyRows + 1;
2145
2146 #ifndef NO_X
2147     vmode = vmodelist[find_vmode(VideoMode)];
2148     if (vmode.type == TEXT) {
2149         sh->base_width = FW * width + 4;
2150         sh->base_height = FH * height + 4;
2151         sh->base_width += 4;
2152         sh->base_height += 4;
2153     } else {
2154         width *= 8;
2155         height *= CharHeight;
2156         sh->base_width = width;
2157         sh->base_height = height;
2158     }
2159     
2160     sh->min_width = sh->max_width = sh->base_width;
2161     sh->min_height = sh->max_height = sh->base_height;
2162     sh->flags = USSize | PMinSize | PMaxSize | PSize;
2163
2164     debug(D_VIDEO, "VGA: Set window size %dx%d\n",
2165           sh->base_width, sh->base_height);
2166     
2167     XSetWMNormalHints(dpy, win, sh);
2168     XResizeWindow(dpy, win, sh->base_width, sh->base_height);
2169     XMapWindow(dpy, win);
2170     XFlush(dpy);
2171     
2172     XFree(sh);
2173     
2174     return;
2175 #endif
2176 }
2177
2178 /* Calculate 'pixels[]' from the current DAC table and palette.
2179
2180    To do: do not use 'pixels[]', use an array of 'XColor's which we can
2181    allocate and free on demand. Install a private colormap if necessary. */
2182 void
2183 update_pixels(void)
2184 {
2185 #ifndef NO_X
2186     int i;
2187
2188     /* We support only 16 colors for now. */
2189     for (i = 0; i < 16; i++) {
2190         XColor color;
2191
2192         dac2rgb(&color, i);
2193         if (XAllocColor(dpy,
2194                         DefaultColormap(dpy, DefaultScreen(dpy)), &color)) {
2195             pixels[i] = color.pixel;
2196         } else if (i < 7)
2197             pixels[i] = BlackPixel(dpy, DefaultScreen(dpy));
2198         else
2199             pixels[i] = WhitePixel(dpy, DefaultScreen(dpy));
2200     }
2201 #endif
2202 }
2203
2204 void
2205 write_vram(void *arg __unused)
2206 {
2207     int fd;
2208
2209     if ((fd = open("vram", O_WRONLY | O_CREAT, 0644)) == -1)
2210         err(1, "Can't open vram file");
2211     (void)write(fd, (void *)vram, 256 * 1024);
2212
2213     return;
2214 }