Răsfoiți Sursa

Update ADB impelemtation in TMK Core (#11168)

* Update ADB impelmentation in tmk_core to recent version.

Pcked from tmk_keyboard repository revision: 48d696443857512d45f9a7329e0dd0a76345860f

* Restore convenient ADB functions used in QMK port.

* Do cformat.
siggie0815 4 ani în urmă
părinte
comite
1b3504e329
2 a modificat fișierele cu 229 adăugiri și 85 ștergeri
  1. 176 80
      tmk_core/protocol/adb.c
  2. 53 5
      tmk_core/protocol/adb.h

+ 176 - 80
tmk_core/protocol/adb.c

@@ -1,5 +1,5 @@
 /*
-Copyright 2011 Jun WAKO <wakojun@gmail.com>
+Copyright 2011-19 Jun WAKO <wakojun@gmail.com>
 Copyright 2013 Shay Green <gblargg@gmail.com>
 
 This software is licensed with a Modified BSD License.
@@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include "adb.h"
+#include "print.h"
 
 // GCC doesn't inline functions normally
 #define data_lo() (ADB_DDR |= (1 << ADB_DATA_BIT))
@@ -59,7 +60,6 @@ static inline void     place_bit1(void);
 static inline void     send_byte(uint8_t data);
 static inline uint16_t wait_data_lo(uint16_t us);
 static inline uint16_t wait_data_hi(uint16_t us);
-static inline uint16_t adb_host_dev_recv(uint8_t device);
 
 void adb_host_init(void) {
     ADB_PORT &= ~(1 << ADB_DATA_BIT);
@@ -81,119 +81,164 @@ bool adb_host_psw(void) { return psw_in(); }
  * <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919>
  * <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139>
  */
-
-// ADB Bit Cells
-//
-// bit cell time: 70-130us
-// low part of bit0: 60-70% of bit cell
-// low part of bit1: 30-40% of bit cell
-//
-//    bit cell time         70us        130us
-//    --------------------------------------------
-//    low  part of bit0     42-49       78-91
-//    high part of bit0     21-28       39-52
-//    low  part of bit1     21-28       39-52
-//    high part of bit1     42-49       78-91
-//
-//
-// bit0:
-//    70us bit cell:
-//      ____________~~~~~~
-//      42-49        21-28
-//
-//    130us bit cell:
-//      ____________~~~~~~
-//      78-91        39-52
-//
-// bit1:
-//    70us bit cell:
-//      ______~~~~~~~~~~~~
-//      21-28        42-49
-//
-//    130us bit cell:
-//      ______~~~~~~~~~~~~
-//      39-52        78-91
-//
-// [from Apple IIgs Hardware Reference Second Edition]
-
-enum { ADDR_KEYB = 0x20, ADDR_MOUSE = 0x30 };
-
-uint16_t adb_host_kbd_recv(void) { return adb_host_dev_recv(ADDR_KEYB); }
+uint16_t adb_host_kbd_recv(void) { return adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_0); }
 
 #ifdef ADB_MOUSE_ENABLE
-void adb_mouse_init(void) { return; }
+__attribute__((weak)) void adb_mouse_init(void) { return; }
+
+__attribute__((weak)) void adb_mouse_task(void) { return; }
 
-uint16_t adb_host_mouse_recv(void) { return adb_host_dev_recv(ADDR_MOUSE); }
+uint16_t adb_host_mouse_recv(void) { return adb_host_talk(ADB_ADDR_MOUSE, ADB_REG_0); }
 #endif
 
-static inline uint16_t adb_host_dev_recv(uint8_t device) {
-    uint16_t data = 0;
+// This sends Talk command to read data from register and returns length of the data.
+uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) {
+    for (int8_t i = 0; i < len; i++) buf[i] = 0;
+
     cli();
     attention();
-    send_byte(device | 0x0C);  // Addr:Keyboard(0010)/Mouse(0011), Cmd:Talk(11), Register0(00)
-    place_bit0();              // Stopbit(0)
+    send_byte((addr << 4) | ADB_CMD_TALK | reg);
+    place_bit0();  // Stopbit(0)
+    // TODO: Service Request(Srq):
+    // Device holds low part of comannd stopbit for 140-260us
+    //
+    // Command:
+    // ......._     ______________________    ___ ............_     -------
+    //         |   |                      |  |   |             |   |
+    // Command |   |                      |  |   | Data bytes  |   |
+    // ........|___|  |     140-260       |__|   |_............|___|
+    //         |stop0 | Tlt Stop-to-Start |start1|             |stop0 |
+    //
+    // Command without data:
+    // ......._     __________________________
+    //         |   |
+    // Command |   |
+    // ........|___|  |     140-260       |
+    //         |stop0 | Tlt Stop-to-Start |
+    //
+    // Service Request:
+    // ......._                     ______    ___ ............_     -------
+    //         |     140-260       |      |  |   |             |   |
+    // Command |  Service Request  |      |  |   | Data bytes  |   |
+    // ........|___________________|      |__|   |_............|___|
+    //         |stop0 |                   |start1|             |stop0 |
+    // ......._                     __________
+    //         |     140-260       |
+    // Command |  Service Request  |
+    // ........|___________________|
+    //         |stop0 |
+    // This can be happened?
+    // ......._     ______________________    ___ ............_                   -----
+    //         |   |                      |  |   |             |    140-260      |
+    // Command |   |                      |  |   | Data bytes  | Service Request |
+    // ........|___|  |     140-260       |__|   |_............|_________________|
+    //         |stop0 | Tlt Stop-to-Start |start1|             |stop0 |
+    //
+    // "Service requests are issued by the devices during a very specific time at the
+    // end of the reception of the command packet.
+    // If a device in need of service issues a service request, it must do so within
+    // the 65 µs of the Stop Bit’s low time and maintain the line low for a total of 300 µs."
+    //
+    // "A device sends a Service Request signal by holding the bus low during the low
+    // portion of the stop bit of any command or data transaction. The device must lengthen
+    // the stop by a minimum of 140 J.lS beyond its normal duration, as shown in Figure 8-15."
+    // http://ww1.microchip.com/downloads/en/AppNotes/00591b.pdf
     if (!wait_data_hi(500)) {  // Service Request(310us Adjustable Keyboard): just ignored
+        xprintf("R");
         sei();
-        return -30;  // something wrong
+        return 0;
     }
     if (!wait_data_lo(500)) {  // Tlt/Stop to Start(140-260us)
         sei();
-        return 0;  // No data to send
+        return 0;  // No data from device(not error);
+    }
+
+    // start bit(1)
+    if (!wait_data_hi(40)) {
+        xprintf("S");
+        sei();
+        return 0;
+    }
+    if (!wait_data_lo(100)) {
+        xprintf("s");
+        sei();
+        return 0;
     }
 
-    uint8_t n = 17;  // start bit + 16 data bits
+    uint8_t n = 0;  // bit count
     do {
+        //
+        // |<- bit_cell_max(130) ->|
+        // |        |<-   lo     ->|
+        // |        |       |<-hi->|
+        //           _______
+        // |        |       |
+        // | 130-lo | lo-hi |
+        // |________|       |
+        //
         uint8_t lo = (uint8_t)wait_data_hi(130);
-        if (!lo) goto error;
+        if (!lo) goto error;  // no more bit or after stop bit
 
         uint8_t hi = (uint8_t)wait_data_lo(lo);
-        if (!hi) goto error;
+        if (!hi) goto error;  // stop bit extedned by Srq?
 
-        hi = lo - hi;
-        lo = 130 - lo;
+        if (n / 8 >= len) continue;  // can't store in buf
 
-        data <<= 1;
-        if (lo < hi) {
-            data |= 1;
-        } else if (n == 17) {
-            sei();
-            return -20;
+        buf[n / 8] <<= 1;
+        if ((130 - lo) < (lo - hi)) {
+            buf[n / 8] |= 1;
         }
-    } while (--n);
-
-    // Stop bit can't be checked normally since it could have service request lenghtening
-    // and its high state never goes low.
-    if (!wait_data_hi(351) || wait_data_lo(91)) {
-        sei();
-        return -21;
-    }
-    sei();
-    return data;
+    } while (++n);
 
 error:
     sei();
-    return -n;
+    return n / 8;
 }
 
-void adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l) {
+uint16_t adb_host_talk(uint8_t addr, uint8_t reg) {
+    uint8_t len;
+    uint8_t buf[8];
+    len = adb_host_talk_buf(addr, reg, buf, 8);
+    if (len != 2) return 0;
+    return (buf[0] << 8 | buf[1]);
+}
+
+void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) {
     cli();
     attention();
-    send_byte(cmd);
-    place_bit0();    // Stopbit(0)
+    send_byte((addr << 4) | ADB_CMD_LISTEN | reg);
+    place_bit0();  // Stopbit(0)
+    // TODO: Service Request
     _delay_us(200);  // Tlt/Stop to Start
     place_bit1();    // Startbit(1)
-    send_byte(data_h);
-    send_byte(data_l);
+    for (int8_t i = 0; i < len; i++) {
+        send_byte(buf[i]);
+        // xprintf("%02X ", buf[i]);
+    }
     place_bit0();  // Stopbit(0);
     sei();
 }
 
+void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l) {
+    uint8_t buf[2] = {data_h, data_l};
+    adb_host_listen_buf(addr, reg, buf, 2);
+}
+
+void adb_host_flush(uint8_t addr) {
+    cli();
+    attention();
+    send_byte((addr << 4) | ADB_CMD_FLUSH);
+    place_bit0();    // Stopbit(0)
+    _delay_us(200);  // Tlt/Stop to Start
+    sei();
+}
+
 // send state of LEDs
 void adb_host_kbd_led(uint8_t led) {
-    // Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
-    // send upper byte (not used)
-    // send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0:
-    adb_host_listen(0x2A, 0, led & 0x07);
+    // Listen Register2
+    //  upper byte: not used
+    //  lower byte: bit2=ScrollLock, bit1=CapsLock, bit0=NumLock
+    adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_2, 0, led & 0x07);
 }
 
 #ifdef ADB_PSW_BIT
@@ -327,7 +372,7 @@ Commands
 
     bits                commands
     ------------------------------------------------------
-    - - - - 0 0 0 0     Send Request(reset all devices)
+    - - - - 0 0 0 0     Send Reset(reset all devices)
     A A A A 0 0 0 1     Flush(reset a device)
     - - - - 0 0 1 0     Reserved
     - - - - 0 0 1 1     Reserved
@@ -435,5 +480,56 @@ Keyboard LEDs & state of keys(Register2)
      | +-----------------------------   Delete
      +-------------------------------   Reserved
 
+Address, Handler ID and bits(Register3)
+    1514131211 . . 8 7 . . . . . . 0
+     | | | | | | | | | | | | | | | |
+     | | | | | | | | +-+-+-+-+-+-+-+-   Handler ID
+     | | | | +-+-+-+-----------------   Address
+     | | | +-------------------------   0
+     | | +---------------------------   Service request enable(1 = enabled)
+     | +-----------------------------   Exceptional event(alwyas 1 if not used)
+     +-------------------------------   0
+
+ADB Bit Cells
+    bit cell time: 70-130us
+    low part of bit0: 60-70% of bit cell
+    low part of bit1: 30-40% of bit cell
+
+       bit cell time         70us        130us
+       --------------------------------------------
+       low  part of bit0     42-49       78-91
+       high part of bit0     21-28       39-52
+       low  part of bit1     21-28       39-52
+       high part of bit1     42-49       78-91
+
+
+    bit0:
+       70us bit cell:
+         ____________~~~~~~
+         42-49        21-28
+
+       130us bit cell:
+         ____________~~~~~~
+         78-91        39-52
+
+    bit1:
+       70us bit cell:
+         ______~~~~~~~~~~~~
+         21-28        42-49
+
+       130us bit cell:
+         ______~~~~~~~~~~~~
+         39-52        78-91
+
+    [from Apple IIgs Hardware Reference Second Edition]
+
+Keyboard Handle ID
+    Apple Standard Keyboard M0116:      0x01
+    Apple Extended Keyboard M0115:      0x02
+    Apple Extended Keyboard II M3501:   0x02
+    Apple Adjustable Keybaord:          0x10
+
+    http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L802
+
 END_OF_ADB
 */

+ 53 - 5
tmk_core/protocol/adb.h

@@ -1,5 +1,5 @@
 /*
-Copyright 2011 Jun WAKO <wakojun@gmail.com>
+Copyright 2011-19 Jun WAKO <wakojun@gmail.com>
 
 This software is licensed with a Modified BSD License.
 All of this is supposed to be Free Software, Open Source, DFSG-free,
@@ -47,12 +47,60 @@ POSSIBILITY OF SUCH DAMAGE.
 #define ADB_POWER 0x7F
 #define ADB_CAPS 0x39
 
+/* ADB commands */
+// Default Address
+#define ADB_ADDR_0 0
+#define ADB_ADDR_DONGLE 1
+#define ADB_ADDR_KEYBOARD 2
+#define ADB_ADDR_MOUSE 3
+#define ADB_ADDR_TABLET 4
+#define ADB_ADDR_APPLIANCE 7
+#define ADB_ADDR_8 8
+#define ADB_ADDR_9 9
+#define ADB_ADDR_10 10
+#define ADB_ADDR_11 11
+#define ADB_ADDR_12 12
+#define ADB_ADDR_13 13
+#define ADB_ADDR_14 14
+#define ADB_ADDR_15 15
+// for temporary purpose, do not use for polling
+#define ADB_ADDR_TMP 15
+#define ADB_ADDR_MOUSE_POLL 10
+// Command Type
+#define ADB_CMD_RESET 0
+#define ADB_CMD_FLUSH 1
+#define ADB_CMD_LISTEN 8
+#define ADB_CMD_TALK 12
+// Register
+#define ADB_REG_0 0
+#define ADB_REG_1 1
+#define ADB_REG_2 2
+#define ADB_REG_3 3
+
+/* ADB keyboard handler id */
+#define ADB_HANDLER_STD 0x01        /* IIGS, M0116 */
+#define ADB_HANDLER_AEK 0x02        /* M0115, M3501 */
+#define ADB_HANDLER_AEK_RMOD 0x03   /* M0115, M3501, alternate mode enableing right modifiers */
+#define ADB_HANDLER_STD_ISO 0x04    /* M0118, ISO swapping keys */
+#define ADB_HANDLER_AEK_ISO 0x05    /* M0115, M3501, ISO swapping keys */
+#define ADB_HANDLER_M1242_ANSI 0x10 /* Adjustable keyboard */
+#define ADB_HANDLER_CLASSIC1_MOUSE 0x01
+#define ADB_HANDLER_CLASSIC2_MOUSE 0x02
+#define ADB_HANDLER_EXTENDED_MOUSE 0x04
+#define ADB_HANDLER_TURBO_MOUSE 0x32
+
 // ADB host
 void     adb_host_init(void);
 bool     adb_host_psw(void);
+uint16_t adb_host_talk(uint8_t addr, uint8_t reg);
+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_kbd_led(uint8_t led);
 uint16_t adb_host_kbd_recv(void);
 uint16_t adb_host_mouse_recv(void);
-void     adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l);
-void     adb_host_kbd_led(uint8_t led);
-void     adb_mouse_task(void);
-void     adb_mouse_init(void);
+
+// ADB Mouse
+void adb_mouse_task(void);
+void adb_mouse_init(void);