src/keyboard.c

Thu, 11 Apr 2013 09:37:11 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Thu, 11 Apr 2013 09:37:11 +0100
changeset 138
d744db15cdf7
parent 136
f7d78dfb45d0
child 146
fb6a37a266da
permissions
-rw-r--r--

Check return value of fread()

     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 		// Keyboard Data Begins Here (BEGKBD)
   222 		//ks->buffer[ks->writep] = KEY_BEGIN_KEYBOARD;
   223 		//ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
   224 		//if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
   226 		for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
   227 			if (ks->keystate[i]) {
   228 				LOG_IF(kbc_debug, "KBC KEY DOWN: %d\n", i);
   229 				ks->buffer[ks->writep] = i;
   230 				ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
   231 				if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
   232 				nkeys++;
   233 			}
   234 		}
   235 		if (nkeys) {
   236 			ks->buffer[ks->writep - 1] |= 0x80;
   237 		}else{
   238 			// If no keys down, then send All Keys Up byte
   239 			LOG_IFS(kbc_debug, "KBC ALL KEYS UP\n");
   240 			ks->buffer[ks->writep] = KEY_ALL_UP;
   241 			ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
   242 			if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
   243 		}
   245 		// TODO: inject "mouse data follows" chunk header and mouse movement info
   247 	}
   249 	// Clear the update flag
   250 	ks->update_flag = false;
   251 }
   253 bool keyboard_get_irq(KEYBOARD_STATE *ks)
   254 {
   255 	bool irq_status = false;
   257 	// Conditions which may cause an IRQ :-
   258 	//   Read Data Reg has data and RxIRQ enabled
   259 	if (ks->rxie)
   260 		if (ks->buflen > 0) irq_status = true;
   262 	//   Transmit Data Reg empty and TxIRQ enabled
   263 //	if (ks->txie)
   265 	//   DCD set and RxIRQ enabled
   266 //
   268 	// returns interrupt status -- i.e. is there data in the buffer?
   269 	return irq_status;
   270 }
   272 uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr)
   273 {
   274 	if ((addr & 1) == 0) {
   275 		// Status register -- RS=0, read
   276 		uint8_t sr = 0;
   277 		if (ks->buflen > 0) sr |= 1;			// SR0: a new character has been received
   278 		sr |= 2;								// SR1: Transmitter Data Register Empty
   279 //			0 +								// SR2: Data Carrier Detect
   280 //			0 +								// SR3: Clear To Send
   281 //			0 +								// SR4: Framing Error
   282 //			0 +								// SR5: Receiver Overrun
   283 //			0 +								// SR6: Parity Error
   284 		if (keyboard_get_irq(ks)) sr |= 0x80;	// SR7: IRQ status
   285 		//LOG_IF(kbc_debug, "KBC DBG: sr=%02X\n", sr);
   286 		return sr;
   287 	} else {
   288 		// return data, pop off the fifo
   289 		uint8_t x = ks->buffer[ks->readp];
   290 		ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE;
   291 		if (ks->buflen > 0) ks->buflen--;
   292 		//LOG_IF(kbc_debug, "\tKBC DBG: rxd=%02X\n", x);
   293 		return x;
   294 	}
   295 }
   297 void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val)
   298 {
   299 	if ((addr & 1) == 0) {
   300 		// write to control register
   301 		// transmit intr enabled when CR6,5 = 01
   302 		// receive intr enabled when CR7 = 1
   304 		// CR0,1 = divider registers. When =11, do a software reset
   305 		if ((val & 3) == 3) {
   306 			ks->readp = ks->writep = ks->buflen = 0;
   307 		}
   309 		// Ignore CR2,3,4 (word length)...
   311 		// CR5,6 = Transmit Mode
   312 		ks->txie = (val & 0x60)==0x20;
   314 		// CR7 = Receive Interrupt Enable
   315 		ks->rxie = (val & 0x80)==0x80;
   316 	} else {
   317 		// Write command to KBC -- TODO!
   318 		if (val == KEY_CMD_RESET) {
   319 			LOG_IFS(kbc_debug, "KBC: KEYBOARD RESET!\n");
   320 			ks->readp = ks->writep = ks->buflen = 0;
   321 		} else {
   322 			LOG("KBC TODO: write keyboard data 0x%02X\n", val);
   323 		}
   324 	}
   325 }