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