initial commit master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 23 Dec 2022 21:36:15 +0000 (23:36 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 23 Dec 2022 21:36:15 +0000 (23:36 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
keyb.c [new file with mode: 0644]
keyb.h [new file with mode: 0644]
main.c [new file with mode: 0644]
midi.c [new file with mode: 0644]
midi.h [new file with mode: 0644]
scancode.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..aeaa582
--- /dev/null
@@ -0,0 +1,7 @@
+*.obj
+*.OBJ
+*.swp
+*.lnk
+*.LNK
+*.exe
+*.EXE
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..8c08adc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+obj = main.obj midi.obj keyb.obj
+bin = midikeys.exe
+
+CC = wcc
+LD = wlink
+CFLAGS = -d3 -s -zq -bt=dos
+
+$(bin): $(obj)
+       %write objects.lnk $(obj)
+       $(LD) debug all name $@ system dos file { @objects } $(LDFLAGS)
+
+.c.obj:
+       $(CC) -fo=$@ $(CFLAGS) $<
+
+.asm.obj:
+       nasm -f obj -o $@ $(ASFLAGS) $<
+
+clean: .symbolic
+       del *.obj
+       del $(bin)
diff --git a/keyb.c b/keyb.c
new file mode 100644 (file)
index 0000000..295b191
--- /dev/null
+++ b/keyb.c
@@ -0,0 +1,222 @@
+/*
+DOS interrupt-based keyboard driver.
+Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License  for more details.
+
+You should have received a copy of the GNU General Public License
+along with the program. If not, see <http://www.gnu.org/licenses/>
+*/
+#define KEYB_C_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <conio.h>
+#include <dos.h>
+
+#ifdef __WATCOMC__
+#include <i86.h>
+#endif
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <go32.h>
+#include <pc.h>
+#endif
+
+#include "keyb.h"
+#include "scancode.h"
+
+#define KB_INTR                0x9
+#define KB_PORT                0x60
+
+#define PIC1_CMD_PORT  0x20
+#define OCW2_EOI               (1 << 5)
+
+#ifdef __WATCOMC__
+#define INTERRUPT __interrupt __far
+
+#define DONE_INIT      (prev_handler)
+static void (INTERRUPT *prev_handler)();
+#endif
+
+#ifdef __DJGPP__
+#define INTERRUPT
+
+#define DONE_INIT prev_intr.pm_offset
+static _go32_dpmi_seginfo intr, prev_intr;
+#endif
+
+static void INTERRUPT kbintr();
+
+#define BUFSZ  32
+static struct kb_event evbuf[BUFSZ];
+static int buf_ridx, buf_widx;
+static int last_key;
+
+static unsigned int num_pressed;
+unsigned char keystate[256];
+
+#define ADVANCE(x)     ((x) = ((x) + 1) & (BUFSZ - 1))
+
+int kb_init(int bufsz)
+{
+       if(DONE_INIT) {
+               fprintf(stderr, "keyboard driver already initialized!\n");
+               return 0;
+       }
+
+       buf_ridx = buf_widx = 0;
+       last_key = -1;
+
+       memset(keystate, 0, sizeof keystate);
+       num_pressed = 0;
+
+       /* set our interrupt handler */
+       _disable();
+#ifdef __WATCOMC__
+       prev_handler = _dos_getvect(KB_INTR);
+       _dos_setvect(KB_INTR, kbintr);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_get_protected_mode_interrupt_vector(KB_INTR, &prev_intr);
+       intr.pm_offset = (intptr_t)kbintr;
+       intr.pm_selector = _go32_my_cs();
+       _go32_dpmi_allocate_iret_wrapper(&intr);
+       _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &intr);
+#endif
+       _enable();
+
+       return 0;
+}
+
+void kb_shutdown(void)
+{
+       if(!DONE_INIT) {
+               return;
+       }
+
+       /* restore the original interrupt handler */
+       _disable();
+#ifdef __WATCOMC__
+       _dos_setvect(KB_INTR, prev_handler);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &prev_intr);
+       _go32_dpmi_free_iret_wrapper(&intr);
+#endif
+       _enable();
+}
+
+int kb_isdown(int key)
+{
+       switch(key) {
+       case KB_ANY:
+               return num_pressed;
+
+       case KB_ALT:
+               return keystate[KB_LALT] + keystate[KB_RALT];
+
+       case KB_CTRL:
+               return keystate[KB_LCTRL] + keystate[KB_RCTRL];
+       }
+
+       if(isalpha(key)) {
+               key = tolower(key);
+       }
+       return keystate[key];
+}
+
+#ifdef __WATCOMC__
+void halt(void);
+#pragma aux halt = \
+       "sti" \
+       "hlt";
+#endif
+
+#ifdef __DJGPP__
+#define halt() asm volatile("sti\n\thlt\n\t")
+#endif
+
+
+int kb_event(struct kb_event *ev)
+{
+       struct kb_event tmp;
+
+       if(!ev) ev = &tmp;
+
+       _disable();
+       while(buf_ridx == buf_widx) {
+               _enable();
+               halt();
+               _disable();
+       }
+
+       *ev = evbuf[buf_ridx];
+       ADVANCE(buf_ridx);
+       _enable();
+
+       return ev->press ? ev->key : (ev->key | 0x100);
+}
+
+static void INTERRUPT kbintr()
+{
+       struct kb_event *ev;
+       unsigned char code;
+       int key, c, press;
+       static int ext;
+
+       code = inp(KB_PORT);
+
+       if(code == 0xe0) {
+               ext = 1;
+               goto eoi;
+       }
+
+       if(code & 0x80) {
+               press = 0;
+               code &= 0x7f;
+
+               if(num_pressed > 0) {
+                       num_pressed--;
+               }
+       } else {
+               press = 1;
+
+               num_pressed++;
+       }
+
+       if(ext) {
+               key = scantbl_ext[code];
+               c = key;
+               ext = 0;
+       } else {
+               key = scantbl[code];
+               c = (keystate[KB_LSHIFT] | keystate[KB_RSHIFT]) ? scantbl_shift[code] : key;
+       }
+
+       ev = evbuf + buf_widx;
+       ADVANCE(buf_widx);
+       if(buf_widx == buf_ridx) {
+               ADVANCE(buf_ridx);
+       }
+
+       ev->key = key;
+       ev->code = code;
+       ev->press = press;
+
+       /* and update keystate table */
+       keystate[key] = press;
+
+eoi:
+       outp(PIC1_CMD_PORT, OCW2_EOI);  /* send end-of-interrupt */
+}
diff --git a/keyb.h b/keyb.h
new file mode 100644 (file)
index 0000000..f70bfad
--- /dev/null
+++ b/keyb.h
@@ -0,0 +1,71 @@
+/*
+DOS interrupt-based keyboard driver.
+Copyright (C) 2013-2023  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License  for more details.
+
+You should have received a copy of the GNU General Public License
+along with the program. If not, see <http://www.gnu.org/licenses/>
+*/
+#ifndef KEYB_H_
+#define KEYB_H_
+
+/* special keys */
+enum {
+       KB_BACKSP = 8,
+       KB_ESC = 27,
+       KB_DEL = 127,
+
+       KB_NUM_0, KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_4,
+       KB_NUM_5, KB_NUM_6, KB_NUM_7, KB_NUM_8, KB_NUM_9,
+       KB_NUM_DOT, KB_NUM_DIV, KB_NUM_MUL, KB_NUM_MINUS, KB_NUM_PLUS, KB_NUM_ENTER, KB_NUM_EQUALS,
+       KB_UP, KB_DOWN, KB_RIGHT, KB_LEFT,
+       KB_INSERT, KB_HOME, KB_END, KB_PGUP, KB_PGDN,
+       KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6,
+       KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12,
+       KB_F13, KB_F14, KB_F15,
+       KB_NUMLK, KB_CAPSLK, KB_SCRLK,
+       KB_RSHIFT, KB_LSHIFT, KB_RCTRL, KB_LCTRL, KB_RALT, KB_LALT,
+       KB_RMETA, KB_LMETA, KB_LSUPER, KB_RSUPER, KB_MODE, KB_COMPOSE,
+       KB_HELP, KB_PRINT, KB_SYSRQ, KB_BREAK
+};
+
+#define KB_ANY         (-1)
+#define KB_ALT         (-2)
+#define KB_CTRL                (-3)
+#define KB_SHIFT       (-4)
+
+struct kb_event {
+       int key;
+       int code;
+       int press;
+};
+
+extern unsigned char keystate[256];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int kb_init(void);
+void kb_shutdown(void);
+
+/* Returns the ASCII key event with bit 8 set of release, clear for press
+ * kb_event filled if the pointer is non-null
+ */
+int kb_event(struct kb_event *ev);
+int kb_pending(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KEYB_H_ */
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..1d49603
--- /dev/null
+++ b/main.c
@@ -0,0 +1,201 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include "midi.h"
+#include "keyb.h"
+
+static int parse_args(int argc, char **argv);
+
+static int bottom[] = {
+       0, 2, 4, 5, 7, 9, 11,  12, 14, 16
+};
+static int top[] = {
+       -1, 1, 3, -1, 6, 8, 10, -1, 13, 15
+};
+
+static int port = 0x330;
+static int chan = 0;
+static int octave = 4;
+static int octave_offs = 60;
+static int prog = 0;
+static int vel = 127;
+
+static int note_state[128];
+
+static const char *helptext =
+       "Controls:\n"
+       " Play using the bottom two rows of the keyboard. Esc to exit.\n"
+       " change MIDI channel: 1-8    change instrument: (/)\n"
+       " shift octave: [/]           change velocity: +/-\n";
+
+
+int main(int argc, char **argv)
+{
+       int i, note, c;
+       char *env, *ptr, *endp;
+
+       if((env = getenv("BLASTER")) && ((ptr = strstr(env, "P:")) ||
+                               (ptr = strstr(env, "p:")))) {
+               port = strtol(ptr + 2, &endp, 16);
+               if(endp == ptr + 2) {
+                       fprintf(stderr, "invalid MPU port specified in BLASTER environment variable, ignoring\n");
+                       port = 0x330;
+               }
+       }
+
+       if(parse_args(argc, argv) == -1) {
+               return 1;
+       }
+
+       kb_init();
+
+       printf("Initializing MIDI interface at port %x\n", port);
+       if(midi_init(port) == -1) {
+               fprintf(stderr, "failed to initialize MPU port\n");
+               return 1;
+       }
+       midi_chprog(chan, prog);
+
+       fputs(helptext, stdout);
+
+       for(;;) {
+               struct kb_event ev;
+               c = kb_event(&ev);
+               if(c == 27) {
+                       break;
+               }
+
+               if(ev.code >= 44 && ev.code <= 53) {
+                       note = bottom[ev.code - 44] + octave_offs;
+                       if(note_state[note] != ev.press) {
+                               midi_note(chan, note, ev.press ? vel : 0);
+                       }
+                       note_state[note] = ev.press;
+
+               } else if(ev.code >= 30 && ev.code <= 40) {
+                       if((note = top[ev.code - 30]) != -1) {
+                               note += octave_offs;
+                               if(note_state[note] != ev.press) {
+                                       midi_note(chan, note, ev.press ? vel : 0);
+                               }
+                               note_state[note] = ev.press;
+                       }
+               } else if(c >= '1' && c <= '8') {
+                       chan = c - '1';
+               } else {
+                       switch(c) {
+                       case '[':
+                               if(octave > 1) {
+                                       octave_offs = --octave * 12 + 12;
+                                       printf("octave: %d (midi offset: %d)\n", octave, octave_offs);
+                               }
+                               break;
+
+                       case ']':
+                               if(octave < 7) {
+                                       octave_offs = ++octave * 12 + 12;
+                                       printf("octave: %d (midi offset: %d)\n", octave, octave_offs);
+                               }
+                               break;
+
+                       case '9':
+                               prog = (prog - 1) & 0x7f;
+                               printf("[%d] instrument: %d\n", chan, prog);
+                               midi_chprog(chan, prog);
+                               break;
+
+                       case '0':
+                               prog = (prog + 1) & 0x7f;
+                               printf("[%d] instrument: %d\n", chan, prog);
+                               midi_chprog(chan, prog);
+                               break;
+
+                       case '-':
+                               if(vel > 0) {
+                                       vel--;
+                                       printf("velocity: %d\n", vel);
+                               }
+                               break;
+
+                       case '=':
+                               if(vel < 127) {
+                                       vel++;
+                                       printf("velocity: %d\n", vel);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       midi_shutdown();
+
+       kb_shutdown();
+       return 0;
+}
+
+static const char *usage_fmt = "Usage: %s [options]\n"
+       "Options:\n"
+       "  -p <port>: set MIDI base I/O port\n"
+       "  -c <channel>: set MIDI channel\n"
+       "  -i <instrument>: MIDI instrument\n"
+       "  -o <octave>: select octave (1-7)\n"
+       "  -h: print usage information and exit\n"
+       "\n";
+
+static int parse_args(int argc, char **argv)
+{
+       int i;
+       char *endp;
+
+       for(i=1; i<argc; i++) {
+               if(argv[i][0] == '-') {
+                       if(argv[i][2]) {
+                               fprintf(stderr, "invalid option: %s\n", argv[i]);
+                               printf(usage_fmt, argv[0]);
+                               return -1;
+                       }
+                       switch(argv[i][1]) {
+                       case 'p':
+                               if(!argv[++i] || ((port = strtol(argv[i], &endp, 16)), endp == argv[i])) {
+                                       fprintf(stderr, "-p should be followed by the port number in hex\n");
+                                       return -1;
+                               }
+                               break;
+
+                       case 'c':
+                               if(!argv[++i] || !(chan = atoi(argv[i]))) {
+                                       fprintf(stderr, "-c should be followed by the channel number\n");
+                                       return -1;
+                               }
+                               break;
+
+                       case 'i':
+                               if(!argv[++i] || !(prog = atoi(argv[i]))) {
+                                       fprintf(stderr, "-i should be followed by a valid channel number\n");
+                                       return -1;
+                               }
+                               break;
+
+                       case 'o':
+                               if(!argv[++i] || !(octave = atoi(argv[i]))) {
+                                       fprintf(stderr, "-o should be followed by the octane number.\n");
+                                       return -1;
+                               }
+
+                       case 'h':
+                               printf(usage_fmt, argv[0]);
+                               exit(0);
+
+                       default:
+                               fprintf(stderr, "invalid option: %s\n", argv[i]);
+                               printf(usage_fmt, argv[0]);
+                               return -1;
+                       }
+               }
+               fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+               printf(usage_fmt, argv[0]);
+               return -1;
+       }
+       return 0;
+}
diff --git a/midi.c b/midi.c
new file mode 100644 (file)
index 0000000..a04c636
--- /dev/null
+++ b/midi.c
@@ -0,0 +1,94 @@
+#include <conio.h>
+#include "midi.h"
+
+static int iobase = 0x330;
+
+#define MPU_PORT_DATA  iobase
+#define MPU_PORT_STAT  (iobase | 1)
+#define MPU_PORT_CMD   (iobase | 1)
+
+#define MPU_STAT_ORDY  0x40
+#define MPU_STAT_IRDY  0x80
+
+#define MPU_ACK                                0xfe
+#define MPU_CMD_RESET          0xff
+#define MPU_CMD_UARTMODE       0x3f
+
+#define MIDI_CMD_NOTEON                0x90
+#define MIDI_CMD_NOTEOFF       0x80
+#define MIDI_CMD_CHANMSG       0xb0
+#define MIDI_CMD_CHPROG                0xc0
+
+#define MIDI_CHANMSG_NOTESOFF  0x7b
+
+int midi_init(int port)
+{
+       iobase = port;
+
+       if(midi_send_cmd(MPU_CMD_RESET) == -1) {
+               return -1;
+       }
+       if(midi_send_cmd(MPU_CMD_UARTMODE) == -1) {
+               return -1;
+       }
+       midi_alloff();
+       return 0;
+}
+
+void midi_shutdown(void)
+{
+       midi_alloff();
+       midi_send_cmd(MPU_CMD_RESET);
+}
+
+void midi_note(int chan, int note, int vel)
+{
+       if(vel > 0) {
+               midi_send_data(MIDI_CMD_NOTEON | chan);
+       } else {
+               midi_send_data(MIDI_CMD_NOTEOFF | chan);
+       }
+       midi_send_data(note);
+       midi_send_data(vel);
+}
+
+void midi_chprog(int chan, int prog)
+{
+       midi_send_data(MIDI_CMD_CHPROG | chan);
+       midi_send_data(prog);
+}
+
+void midi_alloff(void)
+{
+       midi_send_data(MIDI_CMD_CHANMSG);
+       midi_send_data(MIDI_CHANMSG_NOTESOFF);
+}
+
+static int wait_ordy(void)
+{
+       int i;
+       for(i=0; i<1024; i++) {
+               if((inp(MPU_PORT_STAT) & MPU_STAT_ORDY) == 0) {
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+int midi_send_cmd(int cmd)
+{
+       if(wait_ordy() == -1) {
+               return -1;
+       }
+       outp(MPU_PORT_CMD, cmd);
+       return 0;
+}
+
+int midi_send_data(int data)
+{
+       if(wait_ordy() == -1) {
+               return -1;
+       }
+       outp(MPU_PORT_DATA, data);
+       return 0;
+}
diff --git a/midi.h b/midi.h
new file mode 100644 (file)
index 0000000..7b74491
--- /dev/null
+++ b/midi.h
@@ -0,0 +1,14 @@
+#ifndef MIDI_H_
+#define MIDI_H_
+
+int midi_init(int port);
+void midi_shutdown(void);
+
+void midi_note(int chan, int note, int vel);
+void midi_chprog(int chan, int prog);
+void midi_alloff(void);
+
+int midi_send_cmd(int cmd);
+int midi_send_data(int data);
+
+#endif /* MIDI_H_ */
diff --git a/scancode.h b/scancode.h
new file mode 100644 (file)
index 0000000..b0e398c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+colcycle - color cycling image viewer
+Copyright (C) 2016  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef KEYB_C_
+#error "do not include scancode.h anywhere..."
+#endif
+
+/* table with rough translations from set 1 scancodes to ASCII-ish */
+static int scantbl[] = {
+       0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',            /* 0 - e */
+       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',                 /* f - 1c */
+       KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',                          /* 1d - 29 */
+       KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,                   /* 2a - 36 */
+       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
+       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
+       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
+       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
+};
+
+static int scantbl_shift[] = {
+       0, KB_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',            /* 0 - e */
+       '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',                 /* f - 1c */
+       KB_LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',                           /* 1d - 29 */
+       KB_LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', KB_RSHIFT,                    /* 2a - 36 */
+       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
+       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
+       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
+       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
+};
+
+
+/* extended scancodes, after the 0xe0 prefix */
+static int scantbl_ext[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 0 - f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r', KB_RCTRL, 0, 0,                       /* 10 - 1f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 20 - 2f */
+       0, 0, 0, 0, 0, KB_NUM_MINUS, 0, KB_SYSRQ, KB_RALT, 0, 0, 0, 0, 0, 0, 0,                 /* 30 - 3f */
+       0, 0, 0, 0, 0, 0, 0, KB_HOME, KB_UP, KB_PGUP, 0, KB_LEFT, 0, KB_RIGHT, 0, KB_END,       /* 40 - 4f */
+       KB_DOWN, KB_PGDN, KB_INSERT, KB_DEL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                        /* 50 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 70 - 7f */
+};
+