X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=converter%2Fadb_usb%2Fmatrix.c;h=c3b3ab8bb627e628133d726ee0788db9f216e4ef;hb=7544754df42ebc01d9c86f40571d282a9b5878f4;hp=6190c71a06c8d33bb1f4425628837284e4bb7ab7;hpb=ad1c5594928ce952f5205b0f9aaf3e8c04771336;p=max%2Ftmk_keyboard.git diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 6190c71a..c3b3ab8b 100644 --- a/converter/adb_usb/matrix.c +++ b/converter/adb_usb/matrix.c @@ -21,7 +21,6 @@ along with this program. If not, see . #include #include #include -#include #include "print.h" #include "util.h" #include "debug.h" @@ -29,68 +28,67 @@ along with this program. If not, see . #include "matrix.h" #include "report.h" #include "host.h" +#include "led.h" +#include "timer.h" +#include "wait.h" -#if (MATRIX_COLS > 16) -# error "MATRIX_COLS must not exceed 16" -#endif -#if (MATRIX_ROWS > 255) -# error "MATRIX_ROWS must not exceed 255" -#endif static bool has_media_keys = false; static bool is_iso_layout = false; -static bool is_modified = false; -static report_mouse_t mouse_report = {}; -// matrix state buffer(1:on, 0:off) -#if (MATRIX_COLS <= 8) -static uint8_t matrix[MATRIX_ROWS]; -#else -static uint16_t matrix[MATRIX_ROWS]; +#if ADB_MOUSE_ENABLE +#define dmprintf(fmt, ...) do { /* if (debug_mouse) */ xprintf("M:" fmt, ##__VA_ARGS__); } while (0) +static uint16_t mouse_cpi = 100; +static void mouse_init(uint8_t addr); #endif -#ifdef MATRIX_HAS_GHOST -static bool matrix_has_ghost_in_row(uint8_t row); -#endif -static void register_key(uint8_t key); - +// matrix state buffer(1:on, 0:off) +static matrix_row_t matrix[MATRIX_ROWS]; -inline -uint8_t matrix_rows(void) -{ - return MATRIX_ROWS; -} +static void register_key(uint8_t key); -inline -uint8_t matrix_cols(void) +static void device_scan(void) { - return MATRIX_COLS; + xprintf("\nScan:\n"); + for (uint8_t addr = 0; addr < 16; addr++) { + uint16_t reg3 = adb_host_talk(addr, ADB_REG_3); + if (reg3) { + xprintf(" addr:%d, reg3:%04X\n", addr, reg3); + } + } } void matrix_init(void) { + debug_enable = true; + //debug_matrix = true; + //debug_keyboard = true; + //debug_mouse = true; + // LED on DDRD |= (1<<6); PORTD |= (1<<6); adb_host_init(); - // wait for keyboard to boot up and receive command - _delay_ms(2000); - // device scan - xprintf("Before init:\n"); - for (uint8_t addr = 1; addr < 16; addr++) { - uint16_t reg3 = adb_host_talk(addr, ADB_REG_3); - if (reg3) { - xprintf("Scan: addr:%d, reg3:%04X\n", addr, reg3); - } - _delay_ms(20); - } + // AEK/AEKII(ANSI/ISO) startup is slower. Without proper delay + // it would fail to recognize layout and enable Extended protocol. + // 200ms seems to be enough for AEKs. 1000ms is used for safety. + // Tested with devices: + // M0115J(AEK), M3501(AEKII), M0116(Standard), M1242(Adjustable), + // G5431(Mouse), 64210(Kensington Trubo Mouse 5) + wait_ms(1000); + 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 - uint16_t handler_id = adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_3); + 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: @@ -101,37 +99,26 @@ void matrix_init(void) 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("Found: media keys\n"); + 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_PROTOCOL); - - // device scan - xprintf("After init:\n"); - for (uint8_t addr = 1; addr < 16; addr++) { - uint16_t reg3 = adb_host_talk(addr, ADB_REG_3); - if (reg3) { - xprintf("Scan: addr:%d, reg3:%04X\n", addr, reg3); - } - _delay_ms(20); - } + adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_3, ADB_ADDR_KEYBOARD, ADB_HANDLER_EXTENDED_KEYBOARD); // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; - debug_enable = true; - //debug_matrix = true; - //debug_keyboard = true; - //debug_mouse = true; - print("debug enabled.\n"); + led_set(host_keyboard_leds()); + + device_scan(); // LED off DDRD |= (1<<6); PORTD &= ~(1<<6); @@ -139,59 +126,238 @@ void matrix_init(void) } #ifdef ADB_MOUSE_ENABLE +static void mouse_init(uint8_t orig_addr) +{ + uint16_t reg3; + uint8_t mouse_handler; + uint8_t addr; + +again: + // Move to tmp address 15 to setup mouse function + mouse_handler = (reg3 = adb_host_talk(orig_addr, ADB_REG_3)) & 0xFF; + if (!reg3) return; + dmprintf("addr%d reg3: %04X\n", orig_addr, reg3); + + // Move device to tmp address + adb_host_flush(orig_addr); + adb_host_listen(orig_addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_TMP, 0xFE); + adb_host_flush(ADB_ADDR_TMP); + + mouse_handler = (reg3 = adb_host_talk(ADB_ADDR_TMP, ADB_REG_3)) & 0xFF; + if (!reg3) { + dmprintf("move fail\n"); + goto again; + } + addr = ADB_ADDR_TMP; + + +detect_again: + // Try to escalate into extended/classic2 protocol + if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE || mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) { + adb_host_flush(addr); + adb_host_listen(addr, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_EXTENDED_MOUSE); + + mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF; + + + if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) { + adb_host_flush(addr); + adb_host_listen(addr, ADB_REG_3, (reg3 >> 8), ADB_HANDLER_CLASSIC2_MOUSE); + + mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF; + } + dmprintf("addr%d reg3: %04X\n", addr, reg3); + + } + + // Classic Protocol 100cpi + if (mouse_handler == ADB_HANDLER_CLASSIC1_MOUSE) { + xprintf("Classic 100cpi\n"); + mouse_cpi = 100; + } + + // Classic Protocol 200cpi + if (mouse_handler == ADB_HANDLER_CLASSIC2_MOUSE) { + xprintf("Classic 200cpi\n"); + mouse_cpi = 200; + } + + // Extended Mouse Protocol + if (mouse_handler == ADB_HANDLER_EXTENDED_MOUSE) { + // Device info format(reg1 8-byte data) + // 0-3: device id + // 4-5: resolution in units/inch (0xC8=200upi) + // 6 : device class (0: Tablet, 1: Mouse, 2: Trackball) + // 7 : num of buttons + uint8_t len; + uint8_t buf[8]; + len = adb_host_talk_buf(addr, ADB_REG_1, buf, sizeof(buf)); + + if (len > 5) { + mouse_cpi = (buf[4]<<8) | buf[5]; + } else { + mouse_cpi = 100; + } + + if (len) { + xprintf("Ext: [", len); + for (int8_t i = 0; i < len; i++) xprintf("%02X ", buf[i]); + xprintf("] cpi=%d\n", mouse_cpi); + } + + + // Kensington Turbo Mouse 5: default device + if (buf[0] == 0x4B && buf[1] == 0x4D && buf[2] == 0x4C && buf[3] == 0x31) { + xprintf("TM5: default\n"); + // Move it to addr0 to remove this device and get new device with handle id 50 on addr 3 + // and the new device on address 3 should be handled with command sequence later. + // + // Turbo Mouse 5 has one default device on addr3 as normal mouse at first, and another device + // with hander id 50 appears after the default device is moved from addr3. + // 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. + // NOTE: The mouse hangs if you try moving the two deivces to same address. + adb_host_flush(addr); + adb_host_listen(addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_0, 0xFE); + } else { + xprintf("Unknown\n"); + } + } + + // Kensington Turbo Mouse 5: setup + 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 }; + + 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)); + } + + + // Move to address 10 for mouse polling + adb_host_flush(addr); + adb_host_listen(addr, ADB_REG_3, ((reg3 >> 8) & 0xF0) | ADB_ADDR_MOUSE_POLL, 0xFE); + adb_host_flush(ADB_ADDR_MOUSE_POLL); + + mouse_handler = (reg3 = adb_host_talk(addr, ADB_REG_3)) & 0xFF; + if (reg3) { + dmprintf("detect again\n"); + goto detect_again; + } + + goto again; +} #ifdef MAX #undef MAX #endif #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +static report_mouse_t mouse_report = {}; + void adb_mouse_task(void) { - uint16_t codes; + uint8_t len; + uint8_t buf[5]; int16_t x, y; static int8_t mouseacc; - _delay_ms(12); // delay for preventing overload of poor ADB keyboard controller - codes = adb_host_mouse_recv(); + + /* tick of last polling */ + static uint16_t tick_ms; + + // polling with 12ms interval + if (timer_elapsed(tick_ms) < 12) return; + tick_ms = timer_read(); + + static uint16_t detect_ms; + if (timer_elapsed(detect_ms) > 1000) { + detect_ms = timer_read(); + // check new device on addr3 + mouse_init(ADB_ADDR_MOUSE); + } + + // Extended Mouse Protocol data can be 2-5 bytes + // https://developer.apple.com/library/archive/technotes/hw/hw_01.html#Extended + // + // Byte 0: b00 y06 y05 y04 y03 y02 y01 y00 + // Byte 1: b01 x06 x05 x04 x03 x02 x01 x00 + // Byte 2: b02 y09 y08 y07 b03 x09 x08 x07 + // Byte 3: b04 y12 y11 y10 b05 x12 x11 x10 + // Byte 4: b06 y15 y14 y13 b07 x15 x14 x13 + // + // b--: Button state.(0: on, 1: off) + // x--: X axis movement. + // y--: Y axis movement. + len = adb_host_talk_buf(ADB_ADDR_MOUSE_POLL, ADB_REG_0, buf, sizeof(buf)); + // If nothing received reset mouse acceleration, and quit. - if (!codes) { + if (len < 2) { mouseacc = 1; return; }; - // Bit sixteen is button. - if (~codes & (1 << 15)) - mouse_report.buttons |= MOUSE_BTN1; - if (codes & (1 << 15)) - mouse_report.buttons &= ~MOUSE_BTN1; - // lower seven bits are movement, as signed int_7. - // low byte is X-axis, high byte is Y. - y = (codes>>8 & 0x3F); - x = (codes>>0 & 0x3F); - // bit seven and fifteen is negative - // usb does not use int_8, but int_7 (measuring distance) with sign-bit. - if (codes & (1 << 6)) - x = (x-0x40); - if (codes & (1 << 14)) - y = (y-0x40); + dmprintf("[%02X %02X %02X %02X %02X]\n", buf[0], buf[1], buf[2], buf[3], buf[4]); + + // Store off-buttons and 0-movements in unused bytes + bool xneg = false; + bool yneg = false; + if (len == 2) { + if (buf[0] & 0x40) yneg = true; + if (buf[1] & 0x40) xneg = true; + } else { + if (buf[len - 1] & 0x40) yneg = true; + if (buf[len - 1] & 0x04) xneg = true; + } + + for (int8_t i = len; i < sizeof(buf); i++) { + buf[i] = 0x88; + if (yneg) buf[i] |= 0x70; + if (xneg) buf[i] |= 0x07; + } + + // 8 buttons at max + // TODO: Fix HID report descriptor for mouse to support button6-8 + uint8_t buttons = 0; + if (!(buf[4] & 0x08)) buttons |= MOUSE_BTN8; + if (!(buf[4] & 0x80)) buttons |= MOUSE_BTN7; + if (!(buf[3] & 0x08)) buttons |= MOUSE_BTN6; + if (!(buf[3] & 0x80)) buttons |= MOUSE_BTN5; + if (!(buf[2] & 0x08)) buttons |= MOUSE_BTN4; + if (!(buf[2] & 0x80)) buttons |= MOUSE_BTN3; + if (!(buf[1] & 0x80)) buttons |= MOUSE_BTN2; + if (!(buf[0] & 0x80)) buttons |= MOUSE_BTN1; + mouse_report.buttons = buttons; + + int16_t xx, yy; + yy = (buf[0] & 0x7F) | (buf[2] & 0x70) << 3 | (buf[3] & 0x70) << 6 | (buf[4] & 0x70) << 9; + xx = (buf[1] & 0x7F) | (buf[2] & 0x07) << 7 | (buf[3] & 0x07) << 10 | (buf[4] & 0x07) << 13; + // Accelerate mouse. (They weren't meant to be used on screens larger than 320x200). - x *= mouseacc; - y *= mouseacc; + 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) + // 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); - if (debug_mouse) { - print("adb_host_mouse_recv: "); print_bin16(codes); print("\n"); - print("adb_mouse raw: ["); - phex(mouseacc); print(" "); - phex(mouse_report.buttons); print("|"); - print_decs(mouse_report.x); print(" "); - print_decs(mouse_report.y); print("]\n"); - } + + dmprintf("[B:%02X X:%d(%d) Y:%d(%d) A:%d]\n", mouse_report.buttons, mouse_report.x, xx, mouse_report.y, yy, mouseacc); + // Send result by usb. host_mouse_send(&mouse_report); + + // TODO: acceleration curve is needed for precise operation? // increase acceleration of mouse - mouseacc += ( mouseacc < ADB_MOUSE_MAXACC ? 1 : 0 ); + mouseacc += ( mouseacc < (mouse_cpi < 200 ? ADB_MOUSE_MAXACC : ADB_MOUSE_MAXACC/2) ? 1 : 0 ); + return; } #endif @@ -208,19 +374,25 @@ uint8_t matrix_scan(void) uint16_t codes; uint8_t key0, key1; - is_modified = false; + /* tick of last polling */ + static uint16_t tick_ms; codes = extra_key; extra_key = 0xFFFF; if ( codes == 0xFFFF ) { - _delay_ms(12); // delay for preventing overload of poor ADB keyboard controller + // polling with 12ms interval + if (timer_elapsed(tick_ms) < 12) return 0; + tick_ms = timer_read(); + codes = adb_host_kbd_recv(ADB_ADDR_KEYBOARD); + if (codes) xprintf("%04X ", codes); // Adjustable keybaord media keys if (codes == 0 && has_media_keys && (codes = adb_host_kbd_recv(ADB_ADDR_APPLIANCE))) { + xprintf("m:%04X ", codes); // key1 switch (codes & 0x7f ) { case 0x00: // Mic @@ -264,22 +436,20 @@ uint8_t matrix_scan(void) key0 = codes>>8; key1 = codes&0xFF; - if (debug_matrix && codes) { - print("adb_host_kbd_recv: "); phex16(codes); print("\n"); - } - if (codes == 0) { // no keys return 0; } else if (codes == 0x7F7F) { // power key press register_key(0x7F); } else if (codes == 0xFFFF) { // power key release register_key(0xFF); - } else if (key0 == 0xFF) { // error - xprintf("adb_host_kbd_recv: ERROR(%d)\n", codes); - // something wrong or plug-in - matrix_init(); - return key1; } else { + // Macally keyboard sends keys inversely against ADB protocol + // https://deskthority.net/workshop-f7/macally-mk96-t20116.html + if (key0 == 0xFF) { + key0 = key1; + key1 = 0xFF; + } + /* Swap codes for ISO keyboard * https://github.com/tmk/tmk_keyboard/issues/35 * @@ -309,9 +479,9 @@ uint8_t matrix_scan(void) * ------------- --------- * Key ANSI ISO ANSI ISO * --------------------------------------------- - * *a 0x32 0x0A 0x35 0x35 - * *b ---- 0x32 ---- 0x64 - * *c 0x2A 0x2A 0x31 0x31(or 0x32) + * *a 0x32 0x0A GRAVE GRAVE + * *b ---- 0x32 ---- NUBS + * *c 0x2A 0x70 BSLASH NUHS */ if (is_iso_layout) { if ((key0 & 0x7F) == 0x32) { @@ -319,6 +489,9 @@ uint8_t matrix_scan(void) } else if ((key0 & 0x7F) == 0x0A) { key0 = (key0 & 0x80) | 0x32; } + if ((key0 & 0x7F) == 0x2A) { + key0 = (key0 & 0x80) | 0x70; + } } register_key(key0); if (key1 != 0xFF) // key1 is 0xFF when no second key. @@ -328,93 +501,12 @@ uint8_t matrix_scan(void) return 1; } -bool matrix_is_modified(void) -{ - return is_modified; -} - inline -bool matrix_has_ghost(void) -{ -#ifdef MATRIX_HAS_GHOST - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - if (matrix_has_ghost_in_row(i)) - return true; - } -#endif - return false; -} - -inline -bool matrix_is_on(uint8_t row, uint8_t col) -{ - return (matrix[row] & (1<