From f4f47aaee7a224db4543b301b529ae571a530ba6 Mon Sep 17 00:00:00 2001 From: tmk Date: Sun, 4 Jul 2021 22:02:08 +0900 Subject: [PATCH] ibmpc: C++ class for two-interface support --- tmk_core/protocol/ibmpc.cpp | 396 ++++++++++++++++++++++++++++++++++++ tmk_core/protocol/ibmpc.hpp | 245 ++++++++++++++++++++++ 2 files changed, 641 insertions(+) create mode 100644 tmk_core/protocol/ibmpc.cpp create mode 100644 tmk_core/protocol/ibmpc.hpp diff --git a/tmk_core/protocol/ibmpc.cpp b/tmk_core/protocol/ibmpc.cpp new file mode 100644 index 00000000..caa78e42 --- /dev/null +++ b/tmk_core/protocol/ibmpc.cpp @@ -0,0 +1,396 @@ +/* +Copyright 2010,2011,2012,2013,2019 Jun WAKO + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * IBM PC keyboard protocol + */ + +#include +#include +#include +#include "debug.h" +#include "timer.h" +#include "wait.h" +#include "ibmpc.hpp" + + +#define WAIT(stat, us, err) do { \ + if (!wait_##stat(us)) { \ + error = err; \ + goto ERROR; \ + } \ +} while (0) + + +IBMPC IBMPC::interface0 = IBMPC(IBMPC_CLOCK_BIT, IBMPC_DATA_BIT); +#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1) +IBMPC IBMPC::interface1 = IBMPC(IBMPC_CLOCK_BIT1, IBMPC_DATA_BIT1); +#endif + + +void IBMPC::host_init(void) +{ + // initialize reset pin to HiZ + IBMPC_RST_HIZ(); + inhibit(); + int_init(); + int_off(); + ringbuf_init(&rb, rbuf, RINGBUF_SIZE); + host_isr_clear(); +} + +void IBMPC::host_enable(void) +{ + int_on(); + idle(); +} + +void IBMPC::host_disable(void) +{ + int_off(); + inhibit(); +} + +int16_t IBMPC::host_send(uint8_t data) +{ + bool parity = true; + error = IBMPC_ERR_NONE; + uint8_t retry = 0; + + dprintf("w%02X ", data); + + // Not receiving data + if (isr_state != 0x8000) dprintf("isr:%04X ", isr_state); + while (isr_state != 0x8000) ; + + // Not clock Lo + if (!clock_in()) dprintf("c:%u ", wait_clock_hi(1000)); + + // Not data Lo + if (!data_in()) dprintf("d:%u ", wait_data_hi(1000)); + + int_off(); + +RETRY: + /* terminate a transmission if we have */ + inhibit(); + wait_us(200); // [5]p.54 + + /* 'Request to Send' and Start bit */ + data_lo(); + wait_us(200); + clock_hi(); // [5]p.54 [clock low]>100us [5]p.50 + WAIT(clock_lo, 10000, 1); // [5]p.53, -10ms [5]p.50 + + /* Data bit[2-9] */ + for (uint8_t i = 0; i < 8; i++) { + wait_us(15); + if (data&(1<= 3) { + isr_debug = isr_state; + error = IBMPC_ERR_TIMEOUT; + goto ERROR; + + // timeout error recovery - start receiving new data + // it seems to work somehow but may not under unstable situation + //timer_start = t; + //isr_state = 0x8000; + } + } + + isr_state = isr_state>>1; + if (dbit) isr_state |= 0x8000; + + // isr_state: state of receiving data from keyboard + // + // This should be initialized with 0x8000 before receiving data and + // the MSB '*1' works as marker to discrimitate between protocols. + // It stores sampled bit at MSB after right shift on each clock falling edge. + // + // XT protocol has two variants of signaling; XT_IBM and XT_Clone. + // XT_IBM uses two start bits 0 and 1 while XT_Clone uses just start bit 1. + // https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol + // + // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + // ----------------------------------------------------- + // *1 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 Initial state(0x8000) + // + // x x x x x x x x | 0 0 0 0 0 0 0 0 midway(0-7 bits received) + // x x x x x x x x | *1 0 0 0 0 0 0 0 midway(8 bits received) + // b6 b5 b4 b3 b2 b1 b0 1 | 0 *1 0 0 0 0 0 0 XT_IBM-midway ^1 + // b7 b6 b5 b4 b3 b2 b1 b0 | 0 *1 0 0 0 0 0 0 AT-midway ^1 + // b7 b6 b5 b4 b3 b2 b1 b0 | 1 *1 0 0 0 0 0 0 XT_Clone-done ^3 + // b6 b5 b4 b3 b2 b1 b0 1 | 1 *1 0 0 0 0 0 0 XT_IBM-error ^3 + // pr b7 b6 b5 b4 b3 b2 b1 | 0 0 *1 0 0 0 0 0 AT-midway[b0=0] + // b7 b6 b5 b4 b3 b2 b1 b0 | 1 0 *1 0 0 0 0 0 XT_IBM-done ^2 + // pr b7 b6 b5 b4 b3 b2 b1 | 1 0 *1 0 0 0 0 0 AT-midway[b0=1] ^2 + // b7 b6 b5 b4 b3 b2 b1 b0 | 1 1 *1 0 0 0 0 0 XT_IBM-error-done + // x x x x x x x x | x 1 1 0 0 0 0 0 illegal + // st pr b7 b6 b5 b4 b3 b2 | b1 b0 0 *1 0 0 0 0 AT-done + // x x x x x x x x | x x 1 *1 0 0 0 0 illegal + // all other states than above illegal + // + // ^1: AT and XT_IBM takes same state. + // ^2: AT and XT_IBM takes same state in case that AT b0 is 1, + // we have to check AT stop bit to discriminate between the two protocol. + switch (isr_state & 0xFF) { + case 0b00000000: + case 0b10000000: + case 0b01000000: // ^1 + case 0b00100000: + // midway + goto NEXT; + break; + case 0b11000000: // ^3 + { + uint8_t us = 100; + // wait for rising and falling edge of b7 of XT_IBM + while (!(IBMPC_CLOCK_PIN&(1<>8; + protocol = IBMPC_PROTOCOL_XT_CLONE; + goto DONE; + } + } + break; + case 0b11100000: + // XT_IBM-error-done + isr_debug = isr_state; + isr_state = isr_state>>8; + protocol = IBMPC_PROTOCOL_XT_ERROR; + goto DONE; + break; + case 0b10100000: // ^2 + { + uint8_t us = 100; + // wait for rising and falling edge of AT stop bit to discriminate between XT and AT + while (!(IBMPC_CLOCK_PIN&(1<>8; + protocol = IBMPC_PROTOCOL_XT_IBM; + goto DONE; + } + } + break; + case 0b00010000: + case 0b10010000: + case 0b01010000: + case 0b11010000: + // AT-done + // TODO: parity check? + isr_debug = isr_state; + // stop bit check + if (isr_state & 0x8000) { + protocol = IBMPC_PROTOCOL_AT; + } else { + // Zenith Z-150 AT(beige/white lable) asserts stop bit as low + // https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol#zenith-z-150-beige + protocol = IBMPC_PROTOCOL_AT_Z150; + } + isr_state = isr_state>>6; + goto DONE; + break; + case 0b01100000: + case 0b00110000: + case 0b10110000: + case 0b01110000: + case 0b11110000: + default: // xxxx_oooo(any 1 in low nibble) + // Illegal + isr_debug = isr_state; + error = IBMPC_ERR_ILLEGAL; + goto ERROR; + break; + } + +DONE: + // store data + if (!ringbuf_put(&rb, isr_state & 0xFF)) { + // buffer overflow + error = IBMPC_ERR_FULL; + + // Disable ISR if buffer is full + int_off(); + // inhibit: clock_lo + IBMPC_CLOCK_PORT &= ~(1< + +This software is licensed with a Modified BSD License. +All of this is supposed to be Free Software, Open Source, DFSG-free, +GPL-compatible, and OK to use in both free and proprietary applications. +Additions and corrections to this file are welcome. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +* Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef IBMPC_HPP +#define IBMPC_HPP + +#include +#include "wait.h" +#include "ringbuf.h" + +/* + * IBM PC keyboard protocol + * + * PS/2 Resources + * -------------- + * [1] The PS/2 Mouse/Keyboard Protocol + * http://www.computer-engineering.org/ps2protocol/ + * Concise and thorough primer of PS/2 protocol. + * + * [2] Keyboard and Auxiliary Device Controller + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Signal Timing and Format + * + * [3] Keyboards(101- and 102-key) + * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf + * Keyboard Layout, Scan Code Set, POR, and Commands. + * + * [4] PS/2 Reference Manuals + * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf + * Collection of IBM Personal System/2 documents. + * + * [5] TrackPoint Engineering Specifications for version 3E + * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html + */ +#define IBMPC_ACK 0xFA +#define IBMPC_RESEND 0xFE +#define IBMPC_SET_LED 0xED + +#define IBMPC_PROTOCOL_NO 0 +#define IBMPC_PROTOCOL_AT 0x10 +#define IBMPC_PROTOCOL_AT_Z150 0x11 +#define IBMPC_PROTOCOL_XT 0x20 +#define IBMPC_PROTOCOL_XT_IBM 0x21 +#define IBMPC_PROTOCOL_XT_CLONE 0x22 +#define IBMPC_PROTOCOL_XT_ERROR 0x23 + +// Error numbers +#define IBMPC_ERR_NONE 0 +#define IBMPC_ERR_RECV 0x00 +#define IBMPC_ERR_SEND 0x10 +#define IBMPC_ERR_TIMEOUT 0x20 +#define IBMPC_ERR_FULL 0x40 +#define IBMPC_ERR_ILLEGAL 0x80 +#define IBMPC_ERR_FF 0xF0 + +#define IBMPC_LED_SCROLL_LOCK 0 +#define IBMPC_LED_NUM_LOCK 1 +#define IBMPC_LED_CAPS_LOCK 2 + +#define RINGBUF_SIZE 16 + + +class IBMPC +{ + public: + static IBMPC interface0; +#if defined(IBMPC_CLOCK_BIT1) && defined(IBMPC_DATA_BIT1) + static IBMPC interface1; +#endif + + volatile uint16_t isr_debug; + volatile uint8_t protocol; + volatile uint8_t error; + + void host_init(void); + void host_enable(void); + void host_disable(void); + int16_t host_send(uint8_t data); + int16_t host_recv_response(void); + int16_t host_recv(void); + void host_isr_clear(void); + void host_set_led(uint8_t led); + + IBMPC() : isr_debug(IBMPC_ERR_NONE), protocol(IBMPC_PROTOCOL_NO), error(IBMPC_ERR_NONE), + isr_state(0x8000), timer_start(0), + clock_bit(IBMPC_CLOCK_BIT), data_bit(IBMPC_DATA_BIT) { + }; + IBMPC(uint8_t clock, uint8_t data) : IBMPC() { + clock_bit = clock; + data_bit = data; + } + + inline void isr(void) __attribute__((__always_inline__)); + + + private: + volatile uint16_t isr_state; + uint8_t timer_start; + ringbuf_t rb; + uint8_t rbuf[RINGBUF_SIZE]; + + uint8_t clock_bit, data_bit; + + + inline void clock_lo(void) + { + IBMPC_CLOCK_PORT &= ~(1<