Merge remote-tracking branch 'tmk/master'

This commit is contained in:
Mark Sikora 2021-08-05 10:54:33 -04:00
commit 9c3121e122
18 changed files with 5738 additions and 5126 deletions

View file

@ -82,10 +82,26 @@ KEYMAP_SECTION_ENABLE ?= yes # fixed address keymap for keymap editor
ADB_MOUSE_MAXACC ?= 8
OPT_DEFS += -DADB_MOUSE_MAXACC=$(ADB_MOUSE_MAXACC)
# Enable scroll wheel functionality using the y-axis of the mouse
# Hold the assigned button down to scroll using the mouse
#
# Example:
# Kensington Turbo Mouse 5
# ________
# middle click -> |3 __ 4| <- scroll toggle (browser back when disabled)
# | / \ |
# | \__/ |
# left click -> |1 2| <- right click
# |________|
#
ADB_MOUSE_SCROLL_BUTTON ?= 4 # Assign the button (1-8) (0 to disable)
ADB_MOUSE_SCROLL_SPEED ?= 10 # 1 (fastest) to 127 (slowest)
# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax
OPT_DEFS += -DADB_MOUSE_SCROLL_BUTTON=$(ADB_MOUSE_SCROLL_BUTTON)
OPT_DEFS += -DADB_MOUSE_SCROLL_SPEED=$(ADB_MOUSE_SCROLL_SPEED)
#
# Keymap file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -39,6 +39,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
// Mouse Extended Report
#define MOUSE_EXT_REPORT
/* ADB port setting */
#define ADB_PORT PORTD

View file

@ -71,6 +71,8 @@ void matrix_init(void)
DDRD |= (1<<6); PORTD |= (1<<6);
adb_host_init();
adb_host_reset_hard();
//adb_host_reset(); // some of devices done't recognize
// AEK/AEKII(ANSI/ISO) startup is slower. Without proper delay
// it would fail to recognize layout and enable Extended protocol.
@ -228,16 +230,51 @@ detect_again:
if (mouse_handler == ADB_HANDLER_TURBO_MOUSE) {
xprintf("TM5: ext\n");
// Kensington Turbo Mouse 5 command sequence to enable four buttons
// https://elixir.bootlin.com/linux/v4.4/source/drivers/macintosh/adbhid.c#L1176
// https://github.com/NetBSD/src/blob/64b8a48e1288eb3902ed73113d157af50b2ec596/sys/arch/macppc/dev/ams.c#L261
static uint8_t cmd1[] = { 0xE7, 0x8C, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x94 };
static uint8_t cmd2[] = { 0xA5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x27 };
/* byte0: speed
* 0xa0, 0xa5, 0xb0 and 0xb5 seem to work
* uppper nibble:
* 0x00-70, 0xc0-f0 no movement and button event
* 0x80 enables mouse output speed slow
* 0x90 enables mouse output
* 0xa0 enables mouse output
* 0xb0 enables mouse output speed fast -126 to 126
* lower nibble:
* 0x08 makes cursor not smooth, bit4 should be 0
* 0x02 disables button4, bit1 should be 0
* how other bits work is not clear.
* byte1: button mapping - upper nibble for button1 and lower for button2
* 0x14 button1 and button2 mapped as themselves
* 0x0 disabled
* 0x1 button1
* 0x2 button1 toggle
* 0x3 no effect key event FFFF
* 0x4 button2
* 0x5 button2 toggle
* 0x6 button3
* 0x7 button3 toggle
* 0x8 ?toggle weirdly?
* 0x9 button4
* 0xa button4 toggle
* 0xb ?disabled?
* 0xc Left
* 0xd Right
* 0xe Alt+Left
* 0xf Alt+Right
* byte2: 0x00 - 0x40 on powerup, seems to do nothing
* byte3: 0x00 - 0x01 on powerup, seems to do nothing
* byte4: button mapping - upper nibble for button3 and lower for button4
* 0x69 button3 and button4 mapped as themselves(see byte1)
* byte5: 0xff unknown
* byte6: 0xff unknown
* byte7: 0xff checksum - must be 0xff before calculating
* https://github.com/NetBSD/src/blob/8966d5b1cf335756dd9bba3331e84c659bf917e1/sys/dev/adb/adb_ktm.c#L181
*/
//static uint8_t cmd[] = { 0xA5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0xFF };
static uint8_t cmd[] = { 0xB5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0xFF };
cmd[7] = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
adb_host_flush(addr);
adb_host_listen_buf(addr, ADB_REG_2, cmd1, sizeof(cmd1));
adb_host_flush(addr);
adb_host_listen_buf(addr, ADB_REG_2, cmd2, sizeof(cmd2));
adb_host_listen_buf(addr, ADB_REG_2, cmd, sizeof(cmd));
}
@ -255,12 +292,10 @@ detect_again:
goto again;
}
#ifdef MAX
#undef MAX
#endif
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
static report_mouse_t mouse_report = {};
static int32_t scroll_state = 0;
static uint8_t scroll_speed = ADB_MOUSE_SCROLL_SPEED;
static uint8_t scroll_button_mask = (1 << ADB_MOUSE_SCROLL_BUTTON) >> 1;
void adb_mouse_task(void)
{
@ -332,6 +367,12 @@ void adb_mouse_task(void)
if (!(buf[2] & 0x80)) buttons |= MOUSE_BTN3;
if (!(buf[1] & 0x80)) buttons |= MOUSE_BTN2;
if (!(buf[0] & 0x80)) buttons |= MOUSE_BTN1;
// check if the scroll enable button is pressed
bool scroll_enable = (bool)(buttons & scroll_button_mask);
// mask out the scroll button so it isn't reported
buttons &= ~scroll_button_mask;
mouse_report.buttons = buttons;
int16_t xx, yy;
@ -342,14 +383,27 @@ void adb_mouse_task(void)
x = xx * mouseacc;
y = yy * mouseacc;
// TODO: Fix HID report descriptor for mouse to support finer resolution
// Cap our two bytes per axis to one byte.
// Easier with a MIN-function, but since -MAX(-a,-b) = MIN(a,b)...
// I.E. MIN(MAX(x,-127),127) = -MAX(-MAX(x, -127), -127) = MIN(-MIN(-x,127),127)
mouse_report.x = -MAX(-MAX(x, -127), -127);
mouse_report.y = -MAX(-MAX(y, -127), -127);
#ifndef MOUSE_EXT_REPORT
x = (x > 127) ? 127 : ((x < -127) ? -127 : x);
y = (y > 127) ? 127 : ((y < -127) ? -127 : y);
#endif
dmprintf("[B:%02X X:%d(%d) Y:%d(%d) A:%d]\n", mouse_report.buttons, mouse_report.x, xx, mouse_report.y, yy, mouseacc);
if (scroll_enable) {
scroll_state -= y;
mouse_report.v = scroll_state / scroll_speed;
scroll_state %= scroll_speed;
mouse_report.x = 0;
mouse_report.y = 0;
} else {
scroll_state = 0;
mouse_report.v = 0;
mouse_report.x = x;
mouse_report.y = y;
}
dmprintf("[B:%02X X:%d(%d) Y:%d(%d) V:%d A:%d]\n", mouse_report.buttons, mouse_report.x, xx, mouse_report.y, yy, mouse_report.v, mouseacc);
// Send result by usb.
host_mouse_send(&mouse_report);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// G80-2551 terminal keyboard support
#define G80_2551_SUPPORT
// PS/2 Mouse support
//#define IBMPC_MOUSE_ENABLE
// Mouse Extended Report
//#define MOUSE_EXT_REPORT
/*
* Pin and interrupt configuration

View file

@ -50,6 +50,11 @@ static int16_t read_wait(uint16_t wait_ms)
return code;
}
#define ID_STR(id) (id == 0xFFFE ? "_????" : \
(id == 0xFFFD ? "_Z150" : \
(id == 0x0000 ? "_AT84" : \
"")))
static uint16_t read_keyboard_id(void)
{
uint16_t id = 0;
@ -85,7 +90,6 @@ DONE:
void hook_early_init(void)
{
ibmpc_host_init();
ibmpc_host_enable();
}
void matrix_init(void)
@ -130,9 +134,18 @@ uint8_t matrix_scan(void)
} state = INIT;
static uint16_t init_time;
#ifdef IBMPC_MOUSE_ENABLE
static enum {
MOUSE_DEFAULT = 0, // Default three-button
MOUSE_INTELLI = 3, // Intellimouse Explorer 3-button & wheel
MOUSE_EXPLORER = 4, // Intellimouse Explorer 5-button & wheel
MOUSE_LOGITECH = 9 // Logitech PS/2++
} mouse_id = MOUSE_DEFAULT;
static uint8_t mouse_btn = 0;
#endif
if (ibmpc_error) {
xprintf("\nERR:%02X ISR:%04X ", ibmpc_error, ibmpc_isr_debug);
xprintf("\n%u ERR:%02X ISR:%04X ", timer_read(), ibmpc_error, ibmpc_isr_debug);
// when recv error, neither send error nor buffer full
if (!(ibmpc_error & (IBMPC_ERR_SEND | IBMPC_ERR_FULL))) {
@ -150,7 +163,7 @@ uint8_t matrix_scan(void)
// check protocol change AT/XT
if (ibmpc_protocol && ibmpc_protocol != current_protocol) {
xprintf("\nPRT:%02X ISR:%04X ", ibmpc_protocol, ibmpc_isr_debug);
xprintf("\n%u PRT:%02X ISR:%04X ", timer_read(), ibmpc_protocol, ibmpc_isr_debug);
// protocol change between AT and XT indicates that
// keyboard is hotswapped or something goes wrong.
@ -169,8 +182,6 @@ uint8_t matrix_scan(void)
switch (state) {
case INIT:
ibmpc_host_disable();
xprintf("I%u ", timer_read());
keyboard_kind = NONE;
keyboard_id = 0x0000;
@ -181,19 +192,20 @@ uint8_t matrix_scan(void)
init_time = timer_read();
state = WAIT_SETTLE;
ibmpc_host_enable();
break;
case WAIT_SETTLE:
while (ibmpc_host_recv() != -1) ; // read data
// wait for keyboard to settle after plugin
if (timer_elapsed(init_time) > 1000) {
if (timer_elapsed(init_time) > 3000) {
state = AT_RESET;
}
break;
case AT_RESET:
ibmpc_host_isr_clear();
ibmpc_host_enable();
wait_ms(1); // keyboard can't respond to command without this
xprintf("A%u ", timer_read());
// SKIDATA-2-DE(and some other keyboards?) stores 'Code Set' setting in nonvlatile memory
// SKIDATA-2-DE(and some other keyboards?) stores 'Code Set' setting in nonvolatile memory
// and keeps it until receiving reset. Sending reset here may be useful to clear it, perhaps.
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#select-alternate-scan-codesf0
@ -203,7 +215,6 @@ uint8_t matrix_scan(void)
} else {
state = XT_RESET;
}
xprintf("A%u ", timer_read());
break;
case XT_RESET:
// Reset XT-initialize keyboard
@ -281,15 +292,15 @@ uint8_t matrix_scan(void)
} else if (0xFFFE == keyboard_id) { // CodeSet2 PS/2 fails to response?
keyboard_kind = PC_AT;
} else if (0xFFFD == keyboard_id) { // Zenith Z-150 AT
keyboard_kind = PC_AT_Z150;
keyboard_kind = PC_AT;
} else if (0x00FF == keyboard_id) { // Mouse is not supported
xprintf("Mouse: not supported\n");
keyboard_kind = NONE;
#ifdef G80_2551_SUPPORT
} else if (0xAB86 == keyboard_id ||
0xAB85 == keyboard_id) { // For G80-2551 and other 122-key terminal
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab86
keyboard_kind = PC_MOUSE;
} else if (0xAB85 == keyboard_id || // IBM 122-key Model M, NCD N-97
0xAB86 == keyboard_id || // Cherry G80-2551, IBM 1397000
0xAB92 == keyboard_id) { // IBM 5576-001
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab85
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab86
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab92
if ((0xFA == ibmpc_host_send(0xF0)) &&
(0xFA == ibmpc_host_send(0x03))) {
@ -298,7 +309,21 @@ uint8_t matrix_scan(void)
} else {
keyboard_kind = PC_AT;
}
#endif
} else if (0xAB90 == keyboard_id || // IBM 5576-002
0xAB91 == keyboard_id) { // IBM 5576-003
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab90
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ab91
xprintf("\n5576_CS82h:");
if ((0xFA == ibmpc_host_send(0xF0)) &&
(0xFA == ibmpc_host_send(0x82))) {
// switch to code set 82h
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ibm-5576-scan-codes-set
xprintf("OK ");
} else {
xprintf("NG ");
}
keyboard_kind = PC_AT;
} else if (0xBFB0 == keyboard_id) { // IBM RT Keyboard
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#bfb0
// TODO: LED indicator fix
@ -308,11 +333,24 @@ uint8_t matrix_scan(void)
keyboard_kind = PC_AT;
} else if (0xBF00 == (keyboard_id & 0xFF00)) { // CodeSet3 Terminal
keyboard_kind = PC_TERMINAL;
} else if (0x7F00 == (keyboard_id & 0xFF00)) { // CodeSet3 Terminal 1394204
keyboard_kind = PC_TERMINAL;
} else {
keyboard_kind = PC_AT;
xprintf("\nUnknown ID: Report to TMK ");
if ((0xFA == ibmpc_host_send(0xF0)) &&
(0xFA == ibmpc_host_send(0x02))) {
// switch to code set 2
keyboard_kind = PC_AT;
} else if ((0xFA == ibmpc_host_send(0xF0)) &&
(0xFA == ibmpc_host_send(0x03))) {
// switch to code set 3
keyboard_kind = PC_TERMINAL;
} else {
keyboard_kind = PC_AT;
}
}
xprintf("\nID:%04X(%s) ", keyboard_id, KEYBOARD_KIND_STR(keyboard_kind));
xprintf("\nID:%04X(%s%s) ", keyboard_id, KEYBOARD_KIND_STR(keyboard_kind), ID_STR(keyboard_id));
state = SETUP;
break;
@ -324,15 +362,89 @@ uint8_t matrix_scan(void)
case PC_AT:
led_set(host_keyboard_leds());
break;
case PC_AT_Z150:
// TODO: do not set indicators temporarily for debug
break;
case PC_TERMINAL:
// Set all keys to make/break type
ibmpc_host_send(0xF8);
// This should not be harmful
led_set(host_keyboard_leds());
break;
#ifdef IBMPC_MOUSE_ENABLE
case PC_MOUSE: {
uint8_t s[3];
void read_status(void) {
ibmpc_host_send(0xE9);
s[0] = ibmpc_host_recv_response();
s[1] = ibmpc_host_recv_response();
s[2] = ibmpc_host_recv_response();
xprintf("S[%02X %02X %02X] ", s[0], s[1], s[2]);
}
ibmpc_host_send(0xF5); // Disable
ibmpc_host_send(0xEA); // Set Stream Mode
read_status();
// Logitech Magic Status
// https://github.com/torvalds/linux/blob/master/drivers/input/mouse/logips2pp.c#L352
xprintf("\nLMS: ");
ibmpc_host_send(0xE8); ibmpc_host_send(0x00);
ibmpc_host_send(0xE6); ibmpc_host_send(0xE6); ibmpc_host_send(0xE6);
read_status();
if (s[0] == 0 || s[1] == 0) {
// Not Logitech
goto MOUSE_INTELLI;
}
// Logitech Magic Knock
// https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
// https://web.archive.org/web/20030714000535/www.dqcs.com/logitech/ps2ppspec.htm
// https://github.com/torvalds/linux/blob/5bfc75d92efd494db37f5c4c173d3639d4772966/drivers/input/serio/libps2.c#L347
xprintf("\nLOG: ");
// sliced magic byte: 0x39
ibmpc_host_send(0xE6);
ibmpc_host_send(0xE8); ibmpc_host_send(0x00);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
ibmpc_host_send(0xE8); ibmpc_host_send(0x02);
ibmpc_host_send(0xE8); ibmpc_host_send(0x01);
// sliced magic byte: 0xDB
ibmpc_host_send(0xE6);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
ibmpc_host_send(0xE8); ibmpc_host_send(0x01);
ibmpc_host_send(0xE8); ibmpc_host_send(0x02);
ibmpc_host_send(0xE8); ibmpc_host_send(0x03);
mouse_id = MOUSE_LOGITECH; // 9
goto MOUSE_DONE;
MOUSE_INTELLI:
// Intellimouse protocol: 3
xprintf("\nINT: ");
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0x64);
ibmpc_host_send(0xF3); ibmpc_host_send(0x50);
mouse_id = read_keyboard_id() >> 8;
// Intellimouse Explorer protocol: 4
xprintf("\nEXP: ");
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0xC8);
ibmpc_host_send(0xF3); ibmpc_host_send(0x50);
mouse_id = read_keyboard_id() >> 8;
// Not Intellimouse
if (mouse_id == 0) {
xprintf("\nDEF: ");
ibmpc_host_send(0xF6); // Set Default
}
MOUSE_DONE:
//ibmpc_host_send(0xEA); // Set Stream Mode
ibmpc_host_send(0xF4); // Enable
read_status();
xprintf("\nMouse: %s\n", ((mouse_id == MOUSE_LOGITECH) ? "LOGITECH" :
((mouse_id == MOUSE_INTELLI) ? "INTELLI" :
((mouse_id == MOUSE_EXPLORER) ? "EXPLORER" :
((mouse_id == MOUSE_DEFAULT) ? "DEFAULT" : "???")))));
break; }
#endif
default:
break;
}
@ -350,12 +462,12 @@ uint8_t matrix_scan(void)
// Scan Code Set 1: 0xFF
// Scan Code Set 2 and 3: 0x00
// Buffer full(IBMPC_ERR_FULL): 0xFF
if (code == 0x00 || code == 0xFF) {
if (keyboard_kind != PC_MOUSE && (code == 0x00 || code == 0xFF)) {
// clear stuck keys
matrix_clear();
clear_keyboard();
xprintf("\n[OVR] ");
xprintf("\n[CLR] ");
break;
}
@ -364,12 +476,118 @@ uint8_t matrix_scan(void)
if (process_cs1(code) == -1) state = INIT;
break;
case PC_AT:
case PC_AT_Z150:
if (process_cs2(code) == -1) state = INIT;
break;
case PC_TERMINAL:
if (process_cs3(code) == -1) state = INIT;
break;
#ifdef IBMPC_MOUSE_ENABLE
case PC_MOUSE: {
// Logitec Mouse Data:
// https://github.com/torvalds/linux/blob/d2912cb15bdda8ba4a5dd73396ad62641af2f520/drivers/input/mouse/logips2pp.c#L41
// Intellimouse Data:
// https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
int16_t b0, b1, b2, b3;
int16_t x = 0, y = 0;
int8_t v = 0, h = 0;
b0 = code;
b1 = ibmpc_host_recv_response();
if (b1 == -1) break;
b2 = ibmpc_host_recv_response();
if (b2 == -1) break;
switch (mouse_id) {
case MOUSE_DEFAULT:
case MOUSE_INTELLI:
case MOUSE_EXPLORER:
mouse_btn = (mouse_btn & 0xF8) | (b0 & 0x07);
x = (b0 & 0x10) ? (b1 | 0xFF00) : b1;
y = (b0 & 0x20) ? (b2 | 0xFF00) : b2;
break;
case MOUSE_LOGITECH:
if ((b0 & 0x48) == 0x48 && (b1 & 0x02) == 0x02) {
switch (((b0 & 0x30) >> 2) | ((b1 & 0x30) >> 4)) {
case 1: // C8 Dx xx
// Ignored while Scroll-Up/Down is pressed
if (!(b2 & 0x40)) {
if (b2 & 0x80)
h = ((b2 & 0x08) ? 0xF0 : 0x00) | (b2 & 0x0F);
else
v = ((b2 & 0x08) ? 0xF0 : 0x00) | (b2 & 0x0F);
}
// Back
if (b2 & 0x10) mouse_btn |= (1 << 3); else mouse_btn &= ~(1 << 3);
// Forward
if (b2 & 0x20) mouse_btn |= (1 << 4); else mouse_btn &= ~(1 << 4);
break;
case 2: // C8 Ex xx
if (b2 & 0x01) mouse_btn |= (1 << 6); else mouse_btn &= ~(1 << 6);
if (b2 & 0x02) mouse_btn |= (1 << 7); else mouse_btn &= ~(1 << 7);
// Task
if (b2 & 0x04) mouse_btn |= (1 << 5); else mouse_btn &= ~(1 << 5);
// Scroll-Up
if (b2 & 0x08) mouse_btn |= (1 << 6); else mouse_btn &= ~(1 << 6);
// Scroll-Down
if (b2 & 0x10) mouse_btn |= (1 << 7); else mouse_btn &= ~(1 << 7);
break;
case 3: // TouchPad?
if (b2 & 0x80)
h = ((b2 & 0x80) ? 0xF0 : 0x00) | ((b2 >> 4) & 0x0F);
else
v = ((b2 & 0x80) ? 0xF0 : 0x00) | ((b2 >> 4) & 0x0F);
mouse_btn = (mouse_btn & 0xF8) | (b2 & 0x07);
break;
}
} else {
mouse_btn = (mouse_btn & 0xF8) | (b0 & 0x07);
x = (b0 & 0x10) ? (b1 | 0xFF00) : b1;
y = (b0 & 0x20) ? (b2 | 0xFF00) : b2;
}
break;
}
// Extra byte
switch (mouse_id) {
case MOUSE_INTELLI:
b3 = ibmpc_host_recv_response();
if (b3 == -1) break;
v = b3 & 0xFF;
break;
case MOUSE_EXPLORER:
b3 = ibmpc_host_recv_response();
if (b3 == -1) break;
// sign extension
v = ((b3 & 0x08) ? 0xF0 : 0x00) | (b3 & 0x0F);
// Back/Forward
if (b3 & 0x10) mouse_btn |= (1 << 3); else mouse_btn &= ~(1 << 3);
if (b3 & 0x20) mouse_btn |= (1 << 4); else mouse_btn &= ~(1 << 4);
break;
default:
break;
}
// chop to 8-bit
#define CHOP8(a) (((a) > 127) ? 127 : (((a) < -127) ? -127 : (a)))
report_mouse_t mouse_report = {};
mouse_report.buttons = mouse_btn;
#ifdef MOUSE_EXT_REPORT
mouse_report.x = x;
mouse_report.y = -y;
#else
mouse_report.x = CHOP8(x);
mouse_report.y = -CHOP8(y);
#endif
mouse_report.v = -CHOP8(v);
mouse_report.h = CHOP8(h);
host_mouse_send(&mouse_report);
xprintf("M[x:%d y:%d v:%d h:%d b:%02X]\n", mouse_report.x, mouse_report.y,
mouse_report.v, mouse_report.h, mouse_report.buttons);
break; }
#endif
default:
break;
}
@ -432,6 +650,7 @@ void led_set(uint8_t usb_led)
// XT keyobard doesn't support any command and it is harmful perhaps
// https://github.com/tmk/tmk_keyboard/issues/635#issuecomment-626993437
if (keyboard_kind == PC_XT) return;
if (keyboard_kind == PC_MOUSE) return;
// It should be safe to send the command to keyboards with AT protocol
// - IBM Terminal doesn't support the command and response with 0xFE but it is not harmful.
@ -736,6 +955,30 @@ static uint8_t cs2_e0code(uint8_t code) {
}
}
// IBM 5576-002/003 Scan code translation
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ibm-5576-code-set-82h
static uint8_t translate_5576_cs2(uint8_t code) {
switch (code) {
case 0x11: return 0x0F; // Zenmen -> RALT
case 0x13: return 0x11; // Kanji -> LALT
case 0x0E: return 0x54; // @
case 0x54: return 0x5B; // [
case 0x5B: return 0x5D; // ]
case 0x5C: return 0x6A; // JYEN
case 0x5D: return 0x6A; // JYEN
case 0x62: return 0x0E; // Han/Zen -> `~
case 0x7C: return 0x77; // Keypad *
}
return code;
}
static uint8_t translate_5576_cs2_e0(uint8_t code) {
switch (code) {
case 0x11: return 0x13; // Hiragana -> KANA
case 0x41: return 0x7C; // Keypad '
}
return code;
}
static int8_t process_cs2(uint8_t code)
{
// scan code reading states
@ -754,6 +997,9 @@ static int8_t process_cs2(uint8_t code)
switch (state) {
case INIT:
if (0xAB90 == keyboard_id || 0xAB91 == keyboard_id) {
code = translate_5576_cs2(code);
}
switch (code) {
case 0xE0:
state = E0;
@ -787,6 +1033,9 @@ static int8_t process_cs2(uint8_t code)
}
break;
case E0: // E0-Prefixed
if (0xAB90 == keyboard_id || 0xAB91 == keyboard_id) {
code = translate_5576_cs2_e0(code);
}
switch (code) {
case 0x12: // to be ignored
case 0x59: // to be ignored
@ -807,6 +1056,9 @@ static int8_t process_cs2(uint8_t code)
}
break;
case F0: // Break code
if (0xAB90 == keyboard_id || 0xAB91 == keyboard_id) {
code = translate_5576_cs2(code);
}
switch (code) {
case 0x83: // F7
matrix_break(0x02);
@ -828,6 +1080,9 @@ static int8_t process_cs2(uint8_t code)
}
break;
case E0_F0: // Break code of E0-prefixed
if (0xAB90 == keyboard_id || 0xAB91 == keyboard_id) {
code = translate_5576_cs2_e0(code);
}
switch (code) {
case 0x12: // to be ignored
case 0x59: // to be ignored
@ -902,12 +1157,26 @@ static int8_t process_cs2(uint8_t code)
return 0;
}
/*
* Terminal: Scan Code Set 3
*
* See [3], [7] and
* https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#scan-code-set-3
*/
// IBM 5576-001 Scan code translation
// https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#ibm-5576-code-set-3
static uint8_t translate_5576_cs3(uint8_t code) {
switch (code) {
// Fix positon of keys to fit 122-key layout
case 0x13: return 0x5D; // JYEN
case 0x5C: return 0x51; // RO
case 0x76: return 0x7E; // Keypad '
case 0x7E: return 0x76; // Keypad Dup
}
return code;
}
static int8_t process_cs3(uint8_t code)
{
static enum {
@ -920,8 +1189,21 @@ static int8_t process_cs3(uint8_t code)
#endif
} state = READY;
switch (code) {
case 0xAA: // BAT code
case 0xFC: // BAT code
case 0xBF: // Part of keyboard ID
case 0xAB: // Part keyboard ID
state = READY;
xprintf("!CS3_RESET!\n");
return -1;
}
switch (state) {
case READY:
if (0xAB92 == keyboard_id) {
code = translate_5576_cs3(code);
}
switch (code) {
case 0xF0:
state = F0;
@ -933,10 +1215,10 @@ static int8_t process_cs3(uint8_t code)
matrix_make(0x7F);
break;
case 0x85: // Muhenkan
matrix_make(0x0B);
matrix_make(0x68);
break;
case 0x86: // Henkan
matrix_make(0x06);
matrix_make(0x78);
break;
case 0x87: // Hiragana
matrix_make(0x00);
@ -960,51 +1242,44 @@ static int8_t process_cs3(uint8_t code)
matrix_make(code);
} else {
xprintf("!CS3_READY!\n");
return -1;
}
}
break;
case F0: // Break code
state = READY;
if (0xAB92 == keyboard_id) {
code = translate_5576_cs3(code);
}
switch (code) {
case 0x83: // PrintScreen
matrix_break(0x02);
state = READY;
break;
case 0x84: // Keypad *
matrix_break(0x7F);
state = READY;
break;
case 0x85: // Muhenkan
matrix_break(0x0B);
state = READY;
matrix_break(0x68);
break;
case 0x86: // Henkan
matrix_break(0x06);
state = READY;
matrix_break(0x78);
break;
case 0x87: // Hiragana
matrix_break(0x00);
state = READY;
break;
case 0x8B: // Left GUI
matrix_break(0x01);
state = READY;
break;
case 0x8C: // Right GUI
matrix_break(0x09);
state = READY;
break;
case 0x8D: // Application
matrix_break(0x0A);
state = READY;
break;
default:
state = READY;
if (code < 0x80) {
matrix_break(code);
} else {
xprintf("!CS3_F0!\n");
return -1;
}
}
break;

View file

@ -1,12 +1,12 @@
#ifndef IBMPC_USB_H
#define IBMPC_USB_H
typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_AT_Z150 } keyboard_kind_t;
typedef enum { NONE, PC_XT, PC_AT, PC_TERMINAL, PC_MOUSE } keyboard_kind_t;
#define KEYBOARD_KIND_STR(kind) \
(kind == PC_XT ? "XT" : \
kind == PC_AT ? "AT" : \
kind == PC_TERMINAL ? "TERMINAL" : \
kind == PC_AT_Z150 ? "AT_Z150" : \
kind == PC_MOUSE ? "MOUSE" : \
"NONE")

View file

@ -269,7 +269,7 @@ enum layer_pram_tap_op {
#define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF)
#define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON)
#define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR)
#define ACTION_LAYER_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xc0 | ((mods>>8)&0x1f))
#define ACTION_LAYER_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xc0 | (((mods)>>8)&0x1f))
/* With Tapping */
#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
#define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE)

View file

@ -65,6 +65,11 @@ void host_keyboard_send(report_keyboard_t *report)
void host_mouse_send(report_mouse_t *report)
{
if (!driver) return;
#ifdef MOUSE_EXT_REPORT
// clip and copy to Boot protocol XY
report->boot_x = (report->x > 127) ? 127 : ((report->x < -127) ? -127 : report->x);
report->boot_y = (report->y > 127) ? 127 : ((report->y < -127) ? -127 : report->y);
#endif
(*driver->send_mouse)(report);
}

View file

@ -159,8 +159,15 @@ typedef struct {
typedef struct {
uint8_t buttons;
#ifndef MOUSE_EXT_REPORT
int8_t x;
int8_t y;
#else
int8_t boot_x;
int8_t boot_y;
int16_t x;
int16_t y;
#endif
int8_t v;
int8_t h;
} __attribute__ ((packed)) report_mouse_t;

View file

@ -254,6 +254,23 @@ void adb_host_flush(uint8_t addr)
sei();
}
void adb_host_reset(void)
{
cli();
attention();
send_byte(ADB_CMD_RESET);
place_bit0(); // Stopbit(0)
_delay_us(200); // Tlt/Stop to Start
sei();
}
void adb_host_reset_hard(void)
{
data_lo();
_delay_us(3000);
data_hi();
}
// send state of LEDs
void adb_host_kbd_led(uint8_t addr, uint8_t led)
{

View file

@ -104,6 +104,8 @@ uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len)
void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l);
void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len);
void adb_host_flush(uint8_t addr);
void adb_host_reset(void);
void adb_host_reset_hard(void);
void adb_host_kbd_led(uint8_t addr, uint8_t led);
void adb_mouse_task(void);
void adb_mouse_init(void);

View file

@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "debug.h"
#include "timer.h"
#include "wait.h"
#include "ringbuf.h"
#define WAIT(stat, us, err) do { \
@ -60,15 +61,11 @@ volatile uint16_t ibmpc_isr_debug = 0;
volatile uint8_t ibmpc_protocol = IBMPC_PROTOCOL_NO;
volatile uint8_t ibmpc_error = IBMPC_ERR_NONE;
/* 2-byte buffer for data received from keyboard
* buffer states:
* FFFF: empty
* FFss: one data
* sstt: two data
* eeFF: error
* where ss, tt and ee are 0x00-0xFE. 0xFF means empty or no data in buffer.
*/
static volatile uint16_t recv_data = 0xFFFF;
/* buffer for data received from device */
#define RINGBUF_SIZE 16
static uint8_t rbuf[RINGBUF_SIZE];
static ringbuf_t rb = {};
/* internal state of receiving data */
static volatile uint16_t isr_state = 0x8000;
static uint8_t timer_start = 0;
@ -80,6 +77,7 @@ void ibmpc_host_init(void)
inhibit();
IBMPC_INT_INIT();
IBMPC_INT_OFF();
ringbuf_init(&rb, rbuf, RINGBUF_SIZE);
}
void ibmpc_host_enable(void)
@ -98,18 +96,30 @@ int16_t ibmpc_host_send(uint8_t data)
{
bool parity = true;
ibmpc_error = IBMPC_ERR_NONE;
uint8_t retry = 0;
dprintf("w%02X ", data);
// Not receiving data
if (isr_state != 0x8000) dprintf("isr:%04X ", isr_state);
while (isr_state != 0x8000) ;
// Not clock Lo
if (!clock_in()) dprintf("c:%u ", wait_clock_hi(1000));
// Not data Lo
if (!data_in()) dprintf("d:%u ", wait_data_hi(1000));
IBMPC_INT_OFF();
RETRY:
/* terminate a transmission if we have */
inhibit();
wait_us(100); // [5]p.54
wait_us(200); // [5]p.54
/* 'Request to Send' and Start bit */
data_lo();
wait_us(100);
wait_us(200);
clock_hi(); // [5]p.54 [clock low]>100us [5]p.50
WAIT(clock_lo, 10000, 1); // [5]p.53, -10ms [5]p.50
@ -135,27 +145,29 @@ int16_t ibmpc_host_send(uint8_t data)
/* Stop bit */
wait_us(15);
data_hi();
WAIT(clock_hi, 50, 6);
if (ibmpc_protocol == IBMPC_PROTOCOL_AT_Z150) { goto RECV; }
WAIT(clock_lo, 50, 7);
/* Ack */
WAIT(data_lo, 50, 8);
WAIT(data_lo, 300, 6);
WAIT(data_hi, 300, 7);
WAIT(clock_hi, 300, 8);
/* wait for idle state */
WAIT(clock_hi, 50, 9);
WAIT(data_hi, 50, 10);
RECV:
// clear buffer to get response correctly
recv_data = 0xFFFF;
ibmpc_host_isr_clear();
idle();
IBMPC_INT_ON();
return ibmpc_host_recv_response();
ERROR:
// Retry for Z-150 AT start bit error
if (ibmpc_error == 1 && retry++ < 10) {
ibmpc_error = IBMPC_ERR_NONE;
dprintf("R ");
goto RETRY;
}
ibmpc_error |= IBMPC_ERR_SEND;
inhibit();
wait_ms(2);
idle();
IBMPC_INT_ON();
return -1;
@ -166,54 +178,19 @@ ERROR:
*/
int16_t ibmpc_host_recv(void)
{
uint16_t data = 0;
uint8_t ret = 0xFF;
int16_t ret = -1;
// Enable ISR if buffer was full
if (ringbuf_is_full(&rb)) {
ibmpc_host_isr_clear();
IBMPC_INT_ON();
idle();
}
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
data = recv_data;
// remove data from buffer:
// FFFF(empty) -> FFFF
// FFss(one data) -> FFFF
// sstt(two data) -> FFtt
// eeFF(errror) -> FFFF
recv_data = data | (((data&0xFF00) == 0xFF00) ? 0x00FF : 0xFF00);
ret = ringbuf_get(&rb);
}
if ((data&0x00FF) == 0x00FF) {
// error: eeFF
switch (data>>8) {
case IBMPC_ERR_FF:
// 0xFF(Overrun/Error) from keyboard
dprintf("!FF! ");
ret = 0xFF;
break;
case IBMPC_ERR_FULL:
// buffer full
dprintf("!FULL! ");
ret = 0xFF;
break;
case 0xFF:
// empty: FFFF
return -1;
default:
// other errors
dprintf("e%02X ", data>>8);
return -1;
}
} else {
if ((data | 0x00FF) != 0xFFFF) {
// two data: sstt
dprintf("b:%04X ", data);
ret = (data>>8);
} else {
// one data: FFss
ret = (data&0x00FF);
}
}
//dprintf("i%04X ", ibmpc_isr_debug); ibmpc_isr_debug = 0;
dprintf("r%02X ", ret);
if (ret != -1) dprintf("r%02X ", ret&0xFF);
return ret;
}
@ -234,7 +211,7 @@ void ibmpc_host_isr_clear(void)
ibmpc_protocol = 0;
ibmpc_error = 0;
isr_state = 0x8000;
recv_data = 0xFFFF;
ringbuf_reset(&rb);
}
#define LO8(w) (*((uint8_t *)&(w)))
@ -387,25 +364,19 @@ ISR(IBMPC_INT_VECT)
break;
}
ERROR:
// error: eeFF
recv_data = (ibmpc_error<<8) | 0x00FF;
goto CLEAR;
DONE:
if ((isr_state & 0x00FF) == 0x00FF) {
// receive error code 0xFF
ibmpc_error = IBMPC_ERR_FF;
goto ERROR;
}
if (HI8(recv_data) != 0xFF && LO8(recv_data) != 0xFF) {
// buffer full
ibmpc_error = IBMPC_ERR_FULL;
goto ERROR;
}
// store data
recv_data = recv_data<<8;
recv_data |= isr_state & 0xFF;
CLEAR:
if (!ringbuf_put(&rb, isr_state & 0xFF)) {
// buffer overflow
ibmpc_error = IBMPC_ERR_FULL;
// Disable ISR if buffer is full
IBMPC_INT_OFF();
// inhibit: clock_lo
IBMPC_CLOCK_PORT &= ~(1<<IBMPC_CLOCK_BIT);
IBMPC_CLOCK_DDR |= (1<<IBMPC_CLOCK_BIT);
}
ERROR:
// clear for next data
isr_state = 0x8000;
NEXT:

View file

@ -94,16 +94,14 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
HID_RI_USAGE_PAGE(8, 0x09), /* Button */
HID_RI_USAGE_MINIMUM(8, 0x01), /* Button 1 */
HID_RI_USAGE_MAXIMUM(8, 0x05), /* Button 5 */
HID_RI_USAGE_MAXIMUM(8, 0x08), /* Button 8 */
HID_RI_LOGICAL_MINIMUM(8, 0x00),
HID_RI_LOGICAL_MAXIMUM(8, 0x01),
HID_RI_REPORT_COUNT(8, 0x05),
HID_RI_REPORT_COUNT(8, 0x08),
HID_RI_REPORT_SIZE(8, 0x01),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_REPORT_COUNT(8, 0x01),
HID_RI_REPORT_SIZE(8, 0x03),
HID_RI_INPUT(8, HID_IOF_CONSTANT),
#ifndef MOUSE_EXT_REPORT
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x30), /* Usage X */
HID_RI_USAGE(8, 0x31), /* Usage Y */
@ -112,6 +110,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM MouseReport[] =
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
#else
/* Boot protocol XY ignored in Report protocol */
HID_RI_USAGE_PAGE(8, 0xff), /* Vendor */
HID_RI_USAGE(8, 0xff), /* Vendor */
HID_RI_LOGICAL_MINIMUM(8, -127),
HID_RI_LOGICAL_MAXIMUM(8, 127),
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 0x08),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
HID_RI_USAGE_PAGE(8, 0x01), /* Generic Desktop */
HID_RI_USAGE(8, 0x30), /* Usage X */
HID_RI_USAGE(8, 0x31), /* Usage Y */
HID_RI_LOGICAL_MINIMUM(16, -32767),
HID_RI_LOGICAL_MAXIMUM(16, 32767),
HID_RI_REPORT_COUNT(8, 0x02),
HID_RI_REPORT_SIZE(8, 16),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_RELATIVE),
#endif
HID_RI_USAGE(8, 0x38), /* Wheel */
HID_RI_LOGICAL_MINIMUM(8, -127),