Wed, 09 Feb 2011 17:11:48 +0000
more keyboard fixes... interrupt logic needs fixing... grrrrr...
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 void keyboard_init(KEYBOARD_STATE *ks)
132 {
133 // Set all key states to "not pressed"
134 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
135 ks->keystate[i] = 0;
136 }
138 // Reset the R/W pointers and length
139 ks->readp = ks->writep = ks->buflen = 0;
140 }
142 void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev)
143 {
144 // Ignore non-keyboard events
145 if ((ev->type != SDL_KEYDOWN) && (ev->type != SDL_KEYUP)) return;
147 // scan the keymap
148 int keyidx = 0;
149 bool found = false;
150 for (keyidx=0; keyidx < sizeof(keymap)/sizeof(keymap[0]); keyidx++) {
151 if (keymap[keyidx].key == ev->key.keysym.sym) {
152 found = true;
153 break;
154 }
155 }
157 switch (ev->type) {
158 // key pressed
159 case SDL_KEYDOWN:
160 ks->keystate[keymap[keyidx].scancode] = 1;
161 break;
162 // key released
163 case SDL_KEYUP:
164 ks->keystate[keymap[keyidx].scancode] = 0;
165 break;
166 }
167 }
169 void keyboard_scan(KEYBOARD_STATE *ks)
170 {
171 int nkeys = 0;
173 // if buffer empty, do a keyboard scan
174 if (ks->buflen == 0) {
175 // Keyboard Data Begins Here (BEGKBD)
176 ks->buffer[ks->writep] = 0xDF;
177 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
178 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
180 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
181 if (ks->keystate[i]) {
182 printf("\tKBC KEY DOWN: %d\n", i);
183 ks->buffer[ks->writep] = i;
184 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
185 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
186 nkeys++;
187 }
188 }
190 // If no keys down, then send All Keys Up byte
191 if (nkeys == 0) {
192 ks->buffer[ks->writep] = 0x40;
193 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
194 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
195 }
197 // TODO: inject "mouse data follows" chunk header and mouse movement info
199 // Last Entry In List
200 ks->buffer[ks->writep] = 0x80;
201 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
202 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
203 }
204 }
206 bool keyboard_get_irq(KEYBOARD_STATE *ks)
207 {
208 bool irq_status = false;
210 // Conditions which may cause an IRQ :-
211 // Read Data Reg has data and RxIRQ enabled
212 if (ks->rxie)
213 if (ks->buflen > 0) irq_status = true;
215 // Transmit Data Reg empty and TxIRQ enabled
216 // if (ks->txie)
218 // DCD set and RxIRQ enabled
219 //
221 // returns interrupt status -- i.e. is there data in the buffer?
222 return irq_status;
223 }
225 uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr)
226 {
227 if ((addr & 1) == 0) {
228 // Status register -- RS=0, read
229 uint8_t sr = 0;
230 if (ks->buflen > 0) sr |= 1; // SR0: a new character has been received
231 sr |= 2; // SR1: Transmitter Data Register Empty
232 // 0 + // SR2: Data Carrier Detect
233 // 0 + // SR3: Clear To Send
234 // 0 + // SR4: Framing Error
235 // 0 + // SR5: Receiver Overrun
236 // 0 + // SR6: Parity Error
237 if (keyboard_get_irq(ks)) sr |= 0x80; // SR7: IRQ status
238 printf("\tKBC DBG: sr=%02X\n", sr);
239 return sr;
240 } else {
241 // return data, pop off the fifo
242 uint8_t x = ks->buffer[ks->readp];
243 ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE;
244 if (ks->buflen > 0) ks->buflen--;
245 return x;
246 }
247 }
249 void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val)
250 {
251 if ((addr & 1) == 0) {
252 // write to control register
253 // transmit intr enabled when CR6,5 = 01
254 // receive intr enabled when CR7 = 1
256 // CR0,1 = divider registers. When =11, do a software reset
257 if ((val & 3) == 3) {
258 ks->readp = ks->writep = ks->buflen = 0;
259 }
261 // Ignore CR2,3,4 (word length)...
263 // CR5,6 = Transmit Mode
264 ks->txie = (val & 0x60)==0x20;
266 // CR7 = Receive Interrupt Enable
267 ks->rxie = (val & 0x80)==0x80;
268 } else {
269 // Write command to KBC -- TODO!
270 printf("KBC TODO: write keyboard data 0x%02X\n", val);
271 }
272 }