src/keyboard.c

Sat, 17 Nov 2012 19:18:29 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sat, 17 Nov 2012 19:18:29 +0000
changeset 112
a392eb8f9806
parent 99
2d06b823a015
child 136
f7d78dfb45d0
permissions
-rw-r--r--

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 }