X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=converter%2Fadb_usb%2Fmatrix.c;h=f4bf50c1f5af375f2da651f0af85e127e821616f;hb=83ebf5212de1dc5d8fa60e86b2f43cc717c2904c;hp=8f6a0dc9a81382af76d437aa47fc78069b243d28;hpb=f699291e2adf0eb8fb4e7dd64e6b0157b0378f04;p=max%2Ftmk_keyboard.git diff --git a/converter/adb_usb/matrix.c b/converter/adb_usb/matrix.c index 8f6a0dc9..f4bf50c1 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,42 +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" static bool has_media_keys = false; static bool is_iso_layout = false; -static report_mouse_t mouse_report = {}; + +#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 // matrix state buffer(1:on, 0:off) static matrix_row_t matrix[MATRIX_ROWS]; static void register_key(uint8_t key); +static void device_scan(void) +{ + 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: @@ -75,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); @@ -113,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 @@ -182,12 +374,18 @@ uint8_t matrix_scan(void) uint16_t codes; uint8_t key0, key1; + /* 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); // Adjustable keybaord media keys @@ -246,12 +444,14 @@ uint8_t matrix_scan(void) 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 * @@ -318,3 +518,8 @@ static void register_key(uint8_t key) matrix[row] |= (1<