Implement preliminary SAM Coupé emulation
[qemu/z80.git] / hw / sam_keyboard.c
blob74bcc676efc45f6834125d438ed8c782f04f03c4
1 /*
2 * SAM Coupé Keyboard Emulation
4 * Copyright (c) 2007-2009 Stuart Brady <stuart.brady@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "hw.h"
25 #include "qemu-timer.h"
26 #include "console.h"
27 #include "isa.h"
28 #include "sysemu.h"
29 #include "sam_keyboard.h"
30 #include "boards.h"
32 //#define DEBUG_SAM_KEYBOARD
34 #ifdef DEBUG_SAM_KEYBOARD
35 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
36 #else
37 #define DPRINTF(fmt, ...)
38 #endif
40 static int keystate[9];
42 uint32_t sam_keyboard_read(void *opaque, uint32_t addr)
44 int r = 0;
45 uint8_t colbits = 0xff;
46 uint32_t rowbits = ((addr >> 8) & 0xff);
48 if (rowbits == 0xff) {
49 colbits &= keystate[8];
50 } else {
51 for (r = 0; r < 8; r++) {
52 if (!(rowbits & (1 << r))) {
53 colbits &= keystate[r];
57 return colbits;
60 typedef struct {
61 int row;
62 int column;
63 } SAMKeypos;
65 #define DEF_SAM_KEY(name, row, column) SAM_KEY_ ## name,
66 enum sam_keys {
67 #include "sam_key_template.h"
68 SAM_MAX_KEYS
71 #define DEF_SAM_KEY(name, row, column) [SAM_KEY_ ## name] = {row, column},
72 static const SAMKeypos keypos[SAM_MAX_KEYS] = {
73 #include "sam_key_template.h"
76 static int sam_keypressed[SAM_MAX_KEYS];
77 static int qemu_keypressed[0x100];
79 static const int map[0x100][2] = {
80 [0 ... 0xff] = {-1, -1}, /* Unmapped by default */
82 [0x01] = {SAM_KEY_ESCAPE, -1},
84 [0x02] = {SAM_KEY_1, -1},
85 [0x03] = {SAM_KEY_2, -1},
86 [0x04] = {SAM_KEY_3, -1},
87 [0x05] = {SAM_KEY_4, -1},
88 [0x06] = {SAM_KEY_5, -1},
89 [0x07] = {SAM_KEY_6, -1},
90 [0x08] = {SAM_KEY_7, -1},
91 [0x09] = {SAM_KEY_8, -1},
92 [0x0a] = {SAM_KEY_9, -1},
93 [0x0b] = {SAM_KEY_0, -1},
95 [0x0c] = {SAM_KEY_MINUS, -1},
97 [0x0e] = {SAM_KEY_DELETE, -1}, /* Backspace */
99 [0x10] = {SAM_KEY_Q, -1},
100 [0x11] = {SAM_KEY_W, -1},
101 [0x12] = {SAM_KEY_E, -1},
102 [0x13] = {SAM_KEY_R, -1},
103 [0x14] = {SAM_KEY_T, -1},
104 [0x15] = {SAM_KEY_Y, -1},
105 [0x16] = {SAM_KEY_U, -1},
106 [0x17] = {SAM_KEY_I, -1},
107 [0x18] = {SAM_KEY_O, -1},
108 [0x19] = {SAM_KEY_P, -1},
110 [0x0d] = {SAM_KEY_PLUS, -1},
111 [0x0f] = {SAM_KEY_TAB, -1},
113 [0x1a] = {SAM_KEY_EQUALS, -1},
114 [0x1b] = {SAM_KEY_DQUOTE, -1},
116 [0x1c] = {SAM_KEY_ENTER, -1},
118 [0x1d] = {SAM_KEY_CONTROL, -1}, /* Left Control */
120 [0x1e] = {SAM_KEY_A, -1},
121 [0x1f] = {SAM_KEY_S, -1},
122 [0x20] = {SAM_KEY_D, -1},
123 [0x21] = {SAM_KEY_F, -1},
124 [0x22] = {SAM_KEY_G, -1},
125 [0x23] = {SAM_KEY_H, -1},
126 [0x24] = {SAM_KEY_J, -1},
127 [0x25] = {SAM_KEY_K, -1},
128 [0x26] = {SAM_KEY_L, -1},
130 [0x27] = {SAM_KEY_SEMICOLON, -1}, /* Semicolon */
131 [0x28] = {SAM_KEY_SYMBSHIFT, SAM_KEY_7}, /* Apostrophe */
133 [0x2a] = {SAM_KEY_CAPSSHIFT, -1}, /* Left Shift */
135 [0x2b] = {SAM_KEY_SYMBSHIFT, SAM_KEY_3}, /* Hash */
137 [0x2c] = {SAM_KEY_Z, -1},
138 [0x2d] = {SAM_KEY_X, -1},
139 [0x2e] = {SAM_KEY_C, -1},
140 [0x2f] = {SAM_KEY_V, -1},
141 [0x30] = {SAM_KEY_B, -1},
142 [0x31] = {SAM_KEY_N, -1},
143 [0x32] = {SAM_KEY_M, -1},
145 [0x33] = {SAM_KEY_COMMA, -1},
146 [0x34] = {SAM_KEY_PERIOD, -1},
147 [0x35] = {SAM_KEY_SYMBSHIFT, -1}, /* Slash */
149 [0x36] = {SAM_KEY_CAPSSHIFT, -1}, /* Right Shift */
150 [0x37] = {SAM_KEY_SYMBSHIFT, SAM_KEY_B}, /* * (Numpad) */
151 [0x38] = {SAM_KEY_SYMBSHIFT, -1}, /* Left Alt */
152 [0x39] = {SAM_KEY_SPACE, -1}, /* Space Bar */
154 [0x47] = {SAM_KEY_F7, -1}, /* 7 (Numpad) */
155 [0x48] = {SAM_KEY_F8, -1}, /* 8 (Numpad) */
156 [0x49] = {SAM_KEY_F9, -1}, /* 9 (Numpad) */
157 [0x4a] = {SAM_KEY_MINUS, -1}, /* Minus (Numpad) */
158 [0x4b] = {SAM_KEY_F4, -1}, /* 4 (Numpad) */
159 [0x4c] = {SAM_KEY_F5, -1}, /* 5 (Numpad) */
160 [0x4d] = {SAM_KEY_F6, -1}, /* 6 (Numpad) */
161 [0x4e] = {SAM_KEY_PLUS, -1}, /* Plus (Numpad) */
162 [0x4f] = {SAM_KEY_F1, -1}, /* 1 (Numpad) */
163 [0x50] = {SAM_KEY_F2, -1}, /* 2 (Numpad) */
164 [0x51] = {SAM_KEY_F3, -1}, /* 3 (Numpad) */
165 [0x52] = {SAM_KEY_F0, -1}, /* 0 (Numpad) */
166 [0x53] = {SAM_KEY_PERIOD, -1}, /* Period (Numpad) */
168 [0x9c] = {SAM_KEY_ENTER, -1}, /* Enter (Numpad) */
169 [0x9d] = {SAM_KEY_CONTROL, -1}, /* Right Control */
170 [0xb5] = {SAM_KEY_SYMBSHIFT, SAM_KEY_V}, /* Slash (Numpad) */
171 [0xb8] = {SAM_KEY_EDIT, -1}, /* Right Alt */
173 [0xc8] = {SAM_KEY_UP, SAM_KEY_7}, /* Up Arrow */
174 [0xcb] = {SAM_KEY_LEFT, SAM_KEY_5}, /* Left Arrow */
175 [0xcd] = {SAM_KEY_RIGHT, SAM_KEY_8}, /* Right Arrow */
176 [0xd0] = {SAM_KEY_DOWN, SAM_KEY_6}, /* Down Arrow */
178 [0xdb] = {SAM_KEY_CONTROL, SAM_KEY_SYMBSHIFT}, /* Left Meta */
179 [0xdc] = {SAM_KEY_EDIT, SAM_KEY_SYMBSHIFT}, /* Menu */
180 [0xdd] = {SAM_KEY_CONTROL, SAM_KEY_SYMBSHIFT}, /* Right Meta */
183 /* FIXME:
184 * Need to mappings from stepping on each other...
185 * or at least make them step on one another in a consistent manner?
186 * Could use separate state arrays for surpressing/adding keys
187 * and allow only one change to the modifier keys at a time...
189 * Also need to implement shifted mappings.
192 static void sam_put_keycode(void *opaque, int keycode)
194 int release = keycode & 0x80;
195 int key, row, col;
196 static int ext_keycode = 0;
197 int i;
198 int valid;
200 if (keycode == 0xe0) {
201 ext_keycode = 1;
202 } else {
203 if (ext_keycode) {
204 keycode |= 0x80;
205 } else {
206 keycode &= 0x7f;
208 ext_keycode = 0;
210 DPRINTF("Keycode 0x%02x (%s)\n", keycode,
211 release ? "release" : "press");
213 if (release && qemu_keypressed[keycode]) {
214 valid = 1;
215 qemu_keypressed[keycode] = 0;
216 } else if (!release && !qemu_keypressed[keycode]) {
217 valid = 1;
218 qemu_keypressed[keycode] = 1;
219 } else {
220 valid = 0;
223 if (valid) {
224 for (i = 0; i < 2; i++) {
225 key = map[keycode][i];
226 if (key != -1) {
227 row = keypos[key].row;
228 col = keypos[key].column;
229 if (release) {
230 if (--sam_keypressed[key] <= 0) {
231 DPRINTF("Releasing 0x%02x\n", key);
232 sam_keypressed[key] = 0;
233 keystate[row] |= 1 << col;
235 } else {
236 DPRINTF("Pressing 0x%02x\n", key);
237 sam_keypressed[key]++;
238 keystate[row] &= ~(1 << col);
246 void sam_keyboard_init(void)
248 int i;
249 for (i=0; i<9; i++) {
250 keystate[i] = 0xff;
252 memset(sam_keypressed, 0, sizeof(sam_keypressed));
253 memset(qemu_keypressed, 0, sizeof(qemu_keypressed));
254 qemu_add_kbd_event_handler(sam_put_keycode, NULL);