~ruther/qmk_firmware

1b3504e3292db2074b83944c32b67a7c88bb4f51 — siggie0815 4 years ago 9410b15
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.
2 files changed, 229 insertions(+), 85 deletions(-)

M tmk_core/protocol/adb.c
M tmk_core/protocol/adb.h
M tmk_core/protocol/adb.c => tmk_core/protocol/adb.c +176 -80
@@ 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
*/

M tmk_core/protocol/adb.h => tmk_core/protocol/adb.h +53 -5
@@ 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);