Tue, 01 Mar 2011 21:33:32 +0000
Add keyboard patch from Andrew Warkentin <andreww591 gmail com>
I fixed the keyboard in FreeBee. I looked at the keyboard driver source available on a few sites, and it appears that BEGKBD/KEY_BEGIN_KEYBOARD is only supposed to be sent after the end of mouse data, and that KLAST/KEY_LIST_END is not a separate code, but a flag that is set on the last non-KALLUP/KEY_ALL_UP code in a list. I have attached a patch that implements these changes. I have also attached a patch that adds the 60Hz timer interrupt (I'm not sure if it's totally correct, though, since the cursor blinks rather slowly).
Received-From: Andrew Warkentin <andreww591 gmail com>
Signed-Off-By: Philip Pemberton <philpem@philpem.me.uk>
1 #include <stdbool.h>
2 #include "SDL.h"
3 #include "keyboard.h"
5 /**
6 * Key map -- a mapping from SDLK_xxx constants to scancodes and vice versa.
7 */
8 struct {
9 SDLKey key; ///< SDLK_xxx key code constant
10 int extended; ///< 1 if this is an extended keycode
11 unsigned char scancode; ///< Keyboard scan code
12 } keymap[] = {
13 { SDLK_UP, 0, 0x01 }, // ROLL/Up [UpArrow]
14 { SDLK_KP2, 0, 0x01 }, // ROLL/Up [Keypad 2]
15 // { SDLK_, 1, 0x02 }, // Clear Line
16 // { SDLK_, 1, 0x03 }, // Rstrt / Ref
17 // { SDLK_, 1, 0x04 }, // Exit
18 { SDLK_KP1, 0, 0x05 }, // PREV [Keypad 1]
19 // { SDLK_, 1, 0x06 }, // Msg
20 // { SDLK_, 1, 0x07 }, // Cancl
21 { SDLK_BACKSPACE, 0, 0x08 }, // Backspace
22 { SDLK_TAB, 0, 0x09 }, // Tab
23 // { SDLK_RETURN, 1, 0x0a }, // ENTER
24 { SDLK_DOWN, 0, 0x0b }, // ROLL/Down [DownArrow]
25 { SDLK_KP0, 0, 0x0b }, // ROLL/Down [Keypad 0]
26 { SDLK_KP3, 0, 0x0c }, // NEXT [Keypad 3]
27 { SDLK_RETURN, 0, 0x0d }, // RETURN [Return]
28 { SDLK_LEFT, 0, 0x0e }, // <-- [LeftArrow]
29 { SDLK_KP_MINUS, 0, 0x0e }, // <-- [Keypad -]
30 { SDLK_RIGHT, 0, 0x0f }, // --> [RightArrow]
31 { SDLK_KP_PERIOD, 0, 0x0f }, // --> [Keypad .]
32 // { SDLK_, 1, 0x10 }, // Creat
33 // { SDLK_, 1, 0x11 }, // Save
34 // { SDLK_, 1, 0x12 }, // Move
35 // { SDLK_, 1, 0x13 }, // Ops
36 // { SDLK_, 1, 0x14 }, // Copy
37 { SDLK_F1, 0, 0x15 }, // F1
38 { SDLK_F2, 0, 0x16 }, // F2
39 { SDLK_F3, 0, 0x17 }, // F3
40 { SDLK_F4, 0, 0x18 }, // F4
41 { SDLK_F5, 0, 0x19 }, // F5
42 { SDLK_F6, 0, 0x1a }, // F6
43 { SDLK_ESCAPE, 0, 0x1b }, // ESC/DEL [Escape]
44 { SDLK_F7, 0, 0x1c }, // F7
45 { SDLK_F8, 0, 0x1d }, // F8
46 // { SDLK_, 1, 0x1e }, // Suspd
47 // { SDLK_, 1, 0x1f }, // Rsume
48 { SDLK_SPACE, 0, 0x20 }, // SPACE [Spacebar]
49 // { SDLK_, 1, 0x21 }, // Undo
50 // { SDLK_, 1, 0x22 }, // Redo
51 // { SDLK_, 1, 0x23 }, // FIND
52 // { SDLK_, 1, 0x24 }, // RPLAC
53 { SDLK_BREAK, 0, 0x25 }, // RESET/BREAK [Pause/Break]
54 // { SDLK_, 1, 0x26 }, // DleteChar
55 { SDLK_QUOTE, 0, 0x27 }, // ' (single-quote)
56 // { SDLK_, 1, 0x28 }, // SLCT/MARK
57 // { SDLK_, 1, 0x29 }, // INPUT/MODE
58 // { SDLK_, 1, 0x2a }, // HELP
59 // Keycode 2B not used
60 { SDLK_COMMA, 0, 0x2c }, // , [Comma]
61 { SDLK_MINUS, 0, 0x2d }, // - [Dash]
62 { SDLK_PERIOD, 0, 0x2e }, // . [Period]
63 { SDLK_SLASH, 0, 0x2f }, // / [Forward-slash]
64 { SDLK_0, 0, 0x30 }, // 0
65 { SDLK_1, 0, 0x31 }, // 1
66 { SDLK_2, 0, 0x32 }, // 2
67 { SDLK_3, 0, 0x33 }, // 3
68 { SDLK_4, 0, 0x34 }, // 4
69 { SDLK_5, 0, 0x35 }, // 5
70 { SDLK_6, 0, 0x36 }, // 6
71 { SDLK_7, 0, 0x37 }, // 7
72 { SDLK_8, 0, 0x38 }, // 8
73 { SDLK_9, 0, 0x39 }, // 9
74 // Keycode 3A not used
75 { SDLK_SEMICOLON, 0, 0x3b }, // ; [Semicolon]
76 // Keycode 3C not used
77 { SDLK_EQUALS, 0, 0x3d }, // = [Equals]
78 // Keycodes 3E, 3F, 40 not used
79 // { SDLK_, 1, 0x41 }, // CMD
80 // { SDLK_, 1, 0x42 }, // CLOSE/OPEN
81 { SDLK_KP7, 0, 0x43 }, // PRINT
82 { SDLK_KP8, 0, 0x44 }, // CLEAR/RFRSH
83 { SDLK_CAPSLOCK, 0, 0x45 }, // Caps Lock
84 { SDLK_KP9, 0, 0x46 }, // PAGE
85 { SDLK_KP4, 0, 0x47 }, // BEG
86 { SDLK_LSHIFT, 0, 0x48 }, // Left Shift
87 { SDLK_RSHIFT, 0, 0x49 }, // Right Shift
88 { SDLK_HOME, 0, 0x4a }, // Home
89 { SDLK_KP5, 0, 0x4a }, // Home [Keypad 5]
90 { SDLK_END, 0, 0x4b }, // End
91 { SDLK_KP6, 0, 0x4b }, // End [Keypad 6]
92 { SDLK_LCTRL, 0, 0x4c }, // Left Ctrl? \___ not sure which is left and which is right...
93 { SDLK_RCTRL, 0, 0x4d }, // Right Ctrl? /
94 // Keycodes 4E thru 5A not used
95 { SDLK_LEFTBRACKET, 0, 0x5b }, // [
96 { SDLK_BACKSLASH, 0, 0x5c }, // \ (backslash)
97 { SDLK_RIGHTBRACKET, 0, 0x5d }, // ]
98 // Keycodes 5E, 5F not used
99 { SDLK_BACKQUOTE, 0, 0x60 }, // `
100 { SDLK_a, 0, 0x61 }, // A
101 { SDLK_b, 0, 0x62 }, // B
102 { SDLK_c, 0, 0x63 }, // C
103 { SDLK_d, 0, 0x64 }, // D
104 { SDLK_e, 0, 0x65 }, // E
105 { SDLK_f, 0, 0x66 }, // F
106 { SDLK_g, 0, 0x67 }, // G
107 { SDLK_h, 0, 0x68 }, // H
108 { SDLK_i, 0, 0x69 }, // I
109 { SDLK_j, 0, 0x6a }, // J
110 { SDLK_k, 0, 0x6b }, // K
111 { SDLK_l, 0, 0x6c }, // L
112 { SDLK_m, 0, 0x6d }, // M
113 { SDLK_n, 0, 0x6e }, // N
114 { SDLK_o, 0, 0x6f }, // O
115 { SDLK_p, 0, 0x70 }, // P
116 { SDLK_q, 0, 0x71 }, // Q
117 { SDLK_r, 0, 0x72 }, // R
118 { SDLK_s, 0, 0x73 }, // S
119 { SDLK_t, 0, 0x74 }, // T
120 { SDLK_u, 0, 0x75 }, // U
121 { SDLK_v, 0, 0x76 }, // V
122 { SDLK_w, 0, 0x77 }, // W
123 { SDLK_x, 0, 0x78 }, // X
124 { SDLK_y, 0, 0x79 }, // Y
125 { SDLK_z, 0, 0x7a }, // Z
126 // Keycodes 7B, 7C, 7D not used
127 { SDLK_NUMLOCK, 0, 0x7e }, // Numlock
128 { SDLK_DELETE, 0, 0x7f } // Dlete
129 };
131 /**
132 * List of special key codes
133 */
134 enum {
135 KEY_ALL_UP = 0x40, ///< All keys up
136 KEY_LIST_END = 0x80, ///< End of key code list
137 KEY_BEGIN_MOUSE = 0xCF, ///< Mouse data follows
138 KEY_BEGIN_KEYBOARD = 0xDF, ///< Keyboard data follows
139 };
141 /**
142 * List of keyboard commands
143 */
144 enum {
145 KEY_CMD_RESET = 0x92, ///< Reset keyboard
146 KEY_CMD_CAPSLED_OFF = 0xB1, ///< Caps Lock LED off--CHECK!
147 KEY_CMD_CAPSLED_ON = 0xB0, ///< Caps Lock LED on --CHECK!
148 KEY_CMD_NUMLED_OFF = 0xA1, ///< Num Lock LED off --CHECK!
149 KEY_CMD_NUMLED_ON = 0xA0, ///< Num Lock LED on --CHECK!
150 KEY_CMD_MOUSE_ENABLE = 0xD0, ///< Enable mouse
151 KEY_CMD_MOUSE_DISABLE = 0xD1 ///< Disable mouse
152 };
154 void keyboard_init(KEYBOARD_STATE *ks)
155 {
156 // Set all key states to "not pressed"
157 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
158 ks->keystate[i] = 0;
159 }
161 // Reset the R/W pointers and length
162 ks->readp = ks->writep = ks->buflen = 0;
164 // Clear the update flag
165 ks->update_flag = false;
166 }
168 void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev)
169 {
170 int v = 0;
171 switch (ev->type) {
172 case SDL_KEYDOWN:
173 // Key down (pressed)
174 v = 1;
175 break;
176 case SDL_KEYUP:
177 // Key up (released)
178 v = 0;
179 break;
180 default:
181 // Not a keyboard event
182 return;
183 }
185 // scan the keymap
186 for (int i=0; i < sizeof(keymap)/sizeof(keymap[0]); i++) {
187 if (keymap[i].key == ev->key.keysym.sym) {
188 // Keycode match. Is this an Extended Map key?
189 if (keymap[i].extended) {
190 // Yes -- need ALT set when pressing the key for this to be a match
191 if (ev->key.keysym.mod & KMOD_ALT) {
192 ks->keystate[keymap[i].scancode] = v;
193 ks->update_flag = true;
194 break;
195 }
196 } else {
197 // Standard Map key. ALT must NOT be pressed for this to be a match
198 if (!(ev->key.keysym.mod & KMOD_ALT)) {
199 ks->keystate[keymap[i].scancode] = v;
200 ks->update_flag = true;
201 break;
202 }
203 }
204 }
205 }
206 }
207 void keyboard_scan(KEYBOARD_STATE *ks)
208 {
209 int nkeys = 0;
211 // Skip doing the scan if the keyboard hasn't changed state
212 if (!ks->update_flag) return;
215 // if buffer empty, do a keyboard scan
216 if (ks->buflen == 0) {
217 size_t last_writep;
218 // Keyboard Data Begins Here (BEGKBD)
219 //ks->buffer[ks->writep] = KEY_BEGIN_KEYBOARD;
220 //ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
221 //if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
223 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
224 if (ks->keystate[i]) {
225 printf("\tKBC KEY DOWN: %d\n", i);
226 ks->buffer[ks->writep] = i;
227 last_writep = ks->writep;
228 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
229 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
230 nkeys++;
231 }
232 }
233 if (nkeys) {
234 ks->buffer[ks->writep - 1] |= 0x80;
235 }else{
236 // If no keys down, then send All Keys Up byte
237 printf("\tKBC ALL KEYS UP\n");
238 ks->buffer[ks->writep] = KEY_ALL_UP;
239 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
240 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
241 }
243 // TODO: inject "mouse data follows" chunk header and mouse movement info
245 }
247 // Clear the update flag
248 ks->update_flag = false;
249 }
251 bool keyboard_get_irq(KEYBOARD_STATE *ks)
252 {
253 bool irq_status = false;
255 // Conditions which may cause an IRQ :-
256 // Read Data Reg has data and RxIRQ enabled
257 if (ks->rxie)
258 if (ks->buflen > 0) irq_status = true;
260 // Transmit Data Reg empty and TxIRQ enabled
261 // if (ks->txie)
263 // DCD set and RxIRQ enabled
264 //
266 // returns interrupt status -- i.e. is there data in the buffer?
267 return irq_status;
268 }
270 uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr)
271 {
272 if ((addr & 1) == 0) {
273 // Status register -- RS=0, read
274 uint8_t sr = 0;
275 if (ks->buflen > 0) sr |= 1; // SR0: a new character has been received
276 sr |= 2; // SR1: Transmitter Data Register Empty
277 // 0 + // SR2: Data Carrier Detect
278 // 0 + // SR3: Clear To Send
279 // 0 + // SR4: Framing Error
280 // 0 + // SR5: Receiver Overrun
281 // 0 + // SR6: Parity Error
282 if (keyboard_get_irq(ks)) sr |= 0x80; // SR7: IRQ status
283 printf("\tKBC DBG: sr=%02X\n", sr);
284 return sr;
285 } else {
286 // return data, pop off the fifo
287 uint8_t x = ks->buffer[ks->readp];
288 ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE;
289 if (ks->buflen > 0) ks->buflen--;
290 //printf("\tKBC DBG: rxd=%02X\n", x);
291 return x;
292 }
293 }
295 void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val)
296 {
297 if ((addr & 1) == 0) {
298 // write to control register
299 // transmit intr enabled when CR6,5 = 01
300 // receive intr enabled when CR7 = 1
302 // CR0,1 = divider registers. When =11, do a software reset
303 if ((val & 3) == 3) {
304 ks->readp = ks->writep = ks->buflen = 0;
305 }
307 // Ignore CR2,3,4 (word length)...
309 // CR5,6 = Transmit Mode
310 ks->txie = (val & 0x60)==0x20;
312 // CR7 = Receive Interrupt Enable
313 ks->rxie = (val & 0x80)==0x80;
314 } else {
315 // Write command to KBC -- TODO!
316 printf("KBC TODO: write keyboard data 0x%02X\n", val);
317 if (val == KEY_CMD_RESET) {
318 printf("\tKBC: KEYBOARD RESET!\n");
319 ks->readp = ks->writep = ks->buflen = 0;
320 }
321 }
322 }