changeset 1232:c0120977eeea

Initial implementation of the XBAND "Eric Smith" keyboard
author Michael Pavone <pavone@retrodev.com>
date Sat, 25 Feb 2017 02:31:07 -0800
parents d9d775d61fcf
children 2e58b3da1ec1
files io.c io.h
diffstat 2 files changed, 156 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/io.c	Sat Feb 25 02:30:55 2017 -0800
+++ b/io.c	Sat Feb 25 02:31:07 2017 -0800
@@ -30,6 +30,7 @@
 	"6-button gamepad",
 	"Mega Mouse",
 	"Saturn Keyboard",
+	"XBAND Keyboard",
 	"Menacer",
 	"Justifier",
 	"Sega multi-tap",
@@ -488,7 +489,7 @@
 	int idx = keycode & 0x7FFF;
 	keybinding * binding = bindings[bucket] + idx;
 	handle_binding_up(binding);
-	store_key_event(0x100 | scancode);
+	store_key_event(0xF000 | scancode);
 }
 
 void handle_joyup(int joystick, int button)
@@ -787,6 +788,10 @@
 		port->device_type = IO_SATURN_KEYBOARD;
 		port->device.keyboard.read_pos = 0xFF;
 		port->device.keyboard.write_pos = 0;
+	} else if(!strcmp(device_type, "xband keyboard")) {
+		port->device_type = IO_XBAND_KEYBOARD;
+		port->device.keyboard.read_pos = 0xFF;
+		port->device.keyboard.write_pos = 0;
 	} else if(!strcmp(device_type, "sega_parallel")) {
 		port->device_type = IO_SEGA_PARALLEL;
 		port->device.stream.data_fd = -1;
@@ -1381,7 +1386,7 @@
 	keyboard_port = NULL;
 	for (int i = 0; i < 3; i++)
 	{
-		if (ports[i].device_type == IO_SATURN_KEYBOARD) {
+		if (ports[i].device_type == IO_SATURN_KEYBOARD || ports[i].device_type == IO_XBAND_KEYBOARD) {
 			keyboard_port = ports + i;
 			break;
 		}
@@ -1552,6 +1557,12 @@
 
 const int mouse_delays[] = {112*7, 120*7, 96*7, 132*7, 104*7, 96*7, 112*7, 96*7};
 
+enum {
+	KB_SETUP,
+	KB_READ,
+	KB_WRITE
+};
+
 void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle)
 {
 	uint8_t old_output = (port->control & port->output) | (~port->control & 0xFF);
@@ -1606,6 +1617,68 @@
 			}
 		}
 		break;
+	case IO_XBAND_KEYBOARD:
+		if (output & TH) {
+			//request is over
+			if (
+				port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 7
+				&& (port->device.keyboard.tr_counter & 1)
+			) {
+				if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
+					port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
+				} else {
+					port->device.keyboard.read_pos++;
+					port->device.keyboard.read_pos &= 7;
+					if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
+						port->device.keyboard.read_pos = 0xFF;
+					}
+				}
+			}
+			port->device.keyboard.tr_counter = 0;
+			port->device.keyboard.mode = KB_SETUP;
+		} else {
+			if ((output & TR) != (old_output & TR)) {
+				port->device.keyboard.tr_counter++;
+				if (port->device.keyboard.tr_counter == 2) {
+					port->device.keyboard.mode = (output & 0xF) ? KB_READ : KB_WRITE;
+				} else if (port->device.keyboard.mode == KB_WRITE) {
+					switch (port->device.keyboard.tr_counter)
+					{
+					case 3:
+						//host writes 0b0001
+						break;
+					case 4:
+						//host writes 0b0000
+						break;
+					case 5:
+						//host writes 0b0000
+						break;
+					case 6:
+						port->device.keyboard.cmd = output << 4;
+						break;
+					case 7:
+						port->device.keyboard.cmd |= output & 0xF;
+						//TODO: actually do something with the command
+						break;
+					}
+				} else if (
+					port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 7
+					&& !(port->device.keyboard.tr_counter & 1)
+				) {
+					
+					if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
+						port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
+					} else {
+						port->device.keyboard.read_pos++;
+						port->device.keyboard.read_pos &= 7;
+						if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
+							port->device.keyboard.read_pos = 0xFF;
+						}
+					}
+				}
+			}
+		}
+		break;
 #ifndef _WIN32
 	case IO_GENERIC:
 		wait_for_connection(port);
@@ -1618,6 +1691,21 @@
 
 }
 
+uint8_t get_scancode_bytes(io_port *port)
+{
+	if (port->device.keyboard.read_pos == 0xFF) {
+		return 0;
+	}
+	uint8_t bytes = 0, read_pos = port->device.keyboard.read_pos;
+	do {
+		bytes += port->device.keyboard.events[read_pos] & 0xFF00 ? 2 : 1;
+		read_pos++;
+		read_pos &= 7;
+	} while (read_pos != port->device.keyboard.write_pos);
+	
+	return bytes;
+}
+
 uint8_t io_data_read(io_port * port, uint32_t current_cycle)
 {
 	uint8_t control = port->control | 0x80;
@@ -1777,7 +1865,7 @@
 				break;
 			case 8:
 				input = 6;
-				if (code & 0x100) {
+				if (code & 0xFF00) {
 					//break
 					input |= 1;
 				} else if (code) {
@@ -1801,6 +1889,68 @@
 		}
 		break;
 	}
+	case IO_XBAND_KEYBOARD:
+	{
+		if (th) {
+			input = 0x1C;
+		} else {
+			uint8_t size;
+			if (port->device.keyboard.mode == KB_SETUP || port->device.keyboard.mode == KB_READ) {
+				switch (port->device.keyboard.tr_counter)
+				{
+				case 0:
+					input = 0x3;
+					break;
+				case 1:
+					input = 0x6;
+					break;
+				case 2:
+					//This is where thoe host indicates a read or write
+					//presumably, the keyboard only outputs this if the host
+					//is not already driving the data bus low
+					input = 0x9;
+					break;
+				case 3:
+					size = get_scancode_bytes(port);
+					if (size) {
+						++size;
+					}
+					if (size > 15) {
+						size = 15;
+					}
+					input = size;
+					break;
+				case 4:
+				case 5:
+					//always send packet type 0 for now
+					input = 0;
+					break;
+				default:
+					if (port->device.keyboard.read_pos == 0xFF) {
+						//we've run out of bytes
+						input = 0;
+					} else if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
+						if (port->device.keyboard.tr_counter & 1) {
+							input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 8 & 0xF;
+						} else {
+							input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 12;
+						}
+					} else {
+						if (port->device.keyboard.tr_counter & 1) {
+							input = port->device.keyboard.events[port->device.keyboard.read_pos] & 0xF;
+						} else {
+							input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 4;
+						}
+					}
+					break;
+				}
+			} else {
+				input = 0xF;
+			}
+			input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
+		}
+		break;
+	}
 #ifndef _WIN32
 	case IO_SEGA_PARALLEL:
 		if (!th)
--- a/io.h	Sat Feb 25 02:30:55 2017 -0800
+++ b/io.h	Sat Feb 25 02:31:07 2017 -0800
@@ -15,6 +15,7 @@
 	IO_GAMEPAD6,
 	IO_MOUSE,
 	IO_SATURN_KEYBOARD,
+	IO_XBAND_KEYBOARD,
 	IO_MENACER,
 	IO_JUSTIFIER,
 	IO_SEGA_MULTI,
@@ -52,6 +53,8 @@
 			uint8_t  read_pos;
 			uint8_t  write_pos;
 			uint8_t  tr_counter;
+			uint8_t  mode;
+			uint8_t  cmd;
 		} keyboard;
 	} device;
 	uint8_t  output;