adb_usb: Initialize keyboard dynamically #671

Extended and ISO keyboard are properly setup even after hot-plug
This commit is contained in:
tmk 2021-11-16 13:26:00 +09:00
parent 0de65d999d
commit d0cddedcdc
3 changed files with 90 additions and 55 deletions

View file

@ -61,6 +61,64 @@ static void device_scan(void)
xprintf("\n"); xprintf("\n");
} }
static void keyboard_init(void)
{
uint16_t reg3;
uint8_t handler;
// Check if there is keyboard at default address
reg3 = adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_3);
if (!reg3) return;
if (reg3) {
xprintf("K:found: addr:" xstr(ADB_ADDR_KEYBOARD) " reg3:%04X\n", reg3);
adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_KBD_TMP, 0xFE);
}
// Check if there is device to setup at temporary address
reg3 = adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3);
if (!reg3) {
xprintf("K:fail: move\n");
return;
}
// Determine ISO keyboard by handler id
// http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L815
handler = reg3 & 0xFF;
switch (handler) {
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
is_iso_layout = true;
break;
default:
is_iso_layout = false;
break;
}
// Adjustable keyboard media keys: address=0x07 and handlerID=0x02
has_media_keys = (0x02 == (adb_host_talk(ADB_ADDR_APPLIANCE, ADB_REG_3) & 0xff));
if (has_media_keys) {
xprintf("K:Media keys\n");
}
// Enable keyboard left/right modifier distinction
// Listen Register3
// upper byte: reserved bits 0000, keyboard address 0010
// lower byte: device handler 00000011
adb_host_listen(ADB_ADDR_KBD_TMP, ADB_REG_3, ADB_ADDR_KBD_TMP, ADB_HANDLER_EXTENDED_KEYBOARD);
reg3 = adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3);
adb_host_kbd_led(ADB_ADDR_KBD_TMP, ~(host_keyboard_leds()));
// Move to keyboard polling address
adb_host_listen(ADB_ADDR_KBD_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_KBD_POLL, 0xFE);
if (adb_host_talk(ADB_ADDR_KBD_TMP, ADB_REG_3)) {
xprintf("K:fail: move\n");
}
xprintf("K:setup: addr:" xstr(ADB_ADDR_KBD_POLL) " reg3:%04X, ISO:%s\n",
reg3, (is_iso_layout ? "yes" : "no"));
}
void matrix_init(void) void matrix_init(void)
{ {
debug_enable = true; debug_enable = true;
@ -82,47 +140,13 @@ void matrix_init(void)
// M0115J(AEK), M3501(AEKII), M0116(Standard), M1242(Adjustable), // M0115J(AEK), M3501(AEKII), M0116(Standard), M1242(Adjustable),
// G5431(Mouse), 64210(Kensington Trubo Mouse 5) // G5431(Mouse), 64210(Kensington Trubo Mouse 5)
wait_ms(1000); wait_ms(1000);
device_scan(); device_scan();
//
// Keyboard
//
xprintf("\nKeyboard:\n");
// Determine ISO keyboard by handler id
// http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L815
uint8_t handler_id = (uint8_t) adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_3);
switch (handler_id) {
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
case 0xC4: case 0xC7:
is_iso_layout = true;
break;
default:
is_iso_layout = false;
break;
}
xprintf("handler: %02X, ISO: %s\n", handler_id, (is_iso_layout ? "yes" : "no"));
// Adjustable keyboard media keys: address=0x07 and handlerID=0x02
has_media_keys = (0x02 == (adb_host_talk(ADB_ADDR_APPLIANCE, ADB_REG_3) & 0xff));
if (has_media_keys) {
xprintf("Media keys\n");
}
// Enable keyboard left/right modifier distinction
// Listen Register3
// upper byte: reserved bits 0000, keyboard address 0010
// lower byte: device handler 00000011
adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_3, ADB_ADDR_KEYBOARD, ADB_HANDLER_EXTENDED_KEYBOARD);
// initialize matrix state: all keys off // initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
led_set(host_keyboard_leds()); led_set(host_keyboard_leds());
device_scan();
// LED off // LED off
DDRD |= (1<<6); PORTD &= ~(1<<6); DDRD |= (1<<6); PORTD &= ~(1<<6);
return; return;
@ -144,12 +168,12 @@ again:
// initialization of mouse can fail. To recover this you may have to replug mouse or converter. // initialization of mouse can fail. To recover this you may have to replug mouse or converter.
// It is safe to have just one mouse device, but more than one device can be handled somehow. // It is safe to have just one mouse device, but more than one device can be handled somehow.
adb_host_flush(ADB_ADDR_MOUSE); adb_host_flush(ADB_ADDR_MOUSE);
adb_host_listen(ADB_ADDR_MOUSE, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_TMP, 0xFE); adb_host_listen(ADB_ADDR_MOUSE, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_TMP, 0xFE);
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
} }
// Check if there is mouse device to setup at temporary address 15 // Check if there is mouse device to setup at temporary address 15
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3)) & 0xFF; mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
if (!reg3) { if (!reg3) {
return; return;
} }
@ -158,14 +182,14 @@ again:
// Try to escalate into extended/classic2 protocol // Try to escalate into extended/classic2 protocol
if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE || mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) { if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE || mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) {
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_EXTENDED_MOUSE); adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_EXTENDED_MOUSE);
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3)) & 0xFF; mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) { if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) {
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_CLASSIC2_MOUSE); adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_CLASSIC2_MOUSE);
mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3)) & 0xFF; mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3)) & 0xFF;
} }
dmprintf("EXT: reg3:%04X\n", reg3); dmprintf("EXT: reg3:%04X\n", reg3);
} }
@ -191,7 +215,7 @@ again:
// 7 : num of buttons // 7 : num of buttons
uint8_t len; uint8_t len;
uint8_t buf[8]; uint8_t buf[8];
len = adb_host_talk_buf(ADB_ADDR_TMP, ADB_REG_1, buf, sizeof(buf)); len = adb_host_talk_buf(ADB_ADDR_MOUSE_TMP, ADB_REG_1, buf, sizeof(buf));
if (len > 5) { if (len > 5) {
mouse_cpi = (buf[4]<<8) | buf[5]; mouse_cpi = (buf[4]<<8) | buf[5];
@ -215,8 +239,8 @@ again:
// The mouse has the two devices at same time transiently in the result. The default device is // The mouse has the two devices at same time transiently in the result. The default device is
// removed automatically after the another device receives command sequence. // removed automatically after the another device receives command sequence.
// NOTE: The mouse hangs if you try moving the two deivces to same address. // NOTE: The mouse hangs if you try moving the two deivces to same address.
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_0, 0xFE); adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_0, 0xFE);
goto again; goto again;
} else { } else {
dmprintf("Unknown\n"); dmprintf("Unknown\n");
@ -268,16 +292,16 @@ again:
*/ */
uint8_t cmd[] = { 0xB5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x37 }; uint8_t cmd[] = { 0xB5, 0x14, 0x00, 0x00, 0x69, 0xFF, 0xFF, 0x37 };
// cmd[7] = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ 0xFF; // cmd[7] = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ 0xFF;
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen_buf(ADB_ADDR_TMP, ADB_REG_2, cmd, sizeof(cmd)); adb_host_listen_buf(ADB_ADDR_MOUSE_TMP, ADB_REG_2, cmd, sizeof(cmd));
} }
// Move to address 10 for mouse polling // Move to address 10 for mouse polling
adb_host_flush(ADB_ADDR_TMP); adb_host_flush(ADB_ADDR_MOUSE_TMP);
adb_host_listen(ADB_ADDR_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_POLL, 0xFE); adb_host_listen(ADB_ADDR_MOUSE_TMP, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_POLL, 0xFE);
adb_host_flush(ADB_ADDR_MOUSE_POLL); adb_host_flush(ADB_ADDR_MOUSE_POLL);
reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3); reg3 = adb_host_talk(ADB_ADDR_MOUSE_TMP, ADB_REG_3);
if (reg3) { if (reg3) {
dmprintf("POL: fail reg3:%04X\n", reg3); dmprintf("POL: fail reg3:%04X\n", reg3);
} else { } else {
@ -441,7 +465,7 @@ uint8_t matrix_scan(void)
if (timer_elapsed(tick_ms) < 12) return 0; if (timer_elapsed(tick_ms) < 12) return 0;
tick_ms = timer_read(); tick_ms = timer_read();
codes = adb_host_kbd_recv(ADB_ADDR_KEYBOARD); codes = adb_host_kbd_recv(ADB_ADDR_KBD_POLL);
if (codes) xprintf("%04X ", codes); if (codes) xprintf("%04X ", codes);
// Adjustable keybaord media keys // Adjustable keybaord media keys
@ -491,7 +515,13 @@ uint8_t matrix_scan(void)
key0 = codes>>8; key0 = codes>>8;
key1 = codes&0xFF; key1 = codes&0xFF;
if (codes == 0) { // no keys if (codes == 0) { // no keys
static uint16_t detect_ms;
if (timer_elapsed(detect_ms) > 1000) {
detect_ms = timer_read();
// check new device on addr2
keyboard_init();
}
return 0; return 0;
} else if (codes == 0x7F7F) { // power key press } else if (codes == 0x7F7F) { // power key press
register_key(0x7F); register_key(0x7F);
@ -577,5 +607,5 @@ static void register_key(uint8_t key)
void led_set(uint8_t usb_led) void led_set(uint8_t usb_led)
{ {
adb_host_kbd_led(ADB_ADDR_KEYBOARD, ~usb_led); adb_host_kbd_led(ADB_ADDR_KBD_POLL, ~usb_led);
} }

View file

@ -30,6 +30,9 @@
#include "util.h" #include "util.h"
// https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define xstr(s) str(s)
#define str(s) #s
#ifndef NO_PRINT #ifndef NO_PRINT

View file

@ -69,8 +69,10 @@ POSSIBILITY OF SUCH DAMAGE.
#define ADB_ADDR_14 14 #define ADB_ADDR_14 14
#define ADB_ADDR_15 15 #define ADB_ADDR_15 15
// for temporary purpose, do not use for polling // for temporary purpose, do not use for polling
#define ADB_ADDR_TMP 15 #define ADB_ADDR_KBD_POLL 9
#define ADB_ADDR_MOUSE_POLL 10 #define ADB_ADDR_MOUSE_POLL 10
#define ADB_ADDR_KBD_TMP 14
#define ADB_ADDR_MOUSE_TMP 15
// Command Type // Command Type
#define ADB_CMD_RESET 0 #define ADB_CMD_RESET 0
#define ADB_CMD_FLUSH 1 #define ADB_CMD_FLUSH 1