From 4eb27ee89038e934dcb498df7508199efd9c93f1 Mon Sep 17 00:00:00 2001 From: tmk Date: Thu, 28 Nov 2013 14:20:00 +0900 Subject: Add ps2_interrupt.c --- protocol.mk | 2 +- protocol/ps2.c | 469 ----------------------------------------------- protocol/ps2_busywait.c | 51 +++--- protocol/ps2_interrupt.c | 277 ++++++++++++++++++++++++++++ protocol/ps2_usart.c | 23 ++- 5 files changed, 318 insertions(+), 504 deletions(-) delete mode 100644 protocol/ps2.c create mode 100644 protocol/ps2_interrupt.c diff --git a/protocol.mk b/protocol.mk index e332008731..7f561e62d6 100644 --- a/protocol.mk +++ b/protocol.mk @@ -13,7 +13,7 @@ ifdef PS2_USE_BUSYWAIT endif ifdef PS2_USE_INT - SRC += protocol/ps2.c + SRC += protocol/ps2_interrupt.c OPT_DEFS += -DPS2_USE_INT endif diff --git a/protocol/ps2.c b/protocol/ps2.c deleted file mode 100644 index 4886b16d03..0000000000 --- a/protocol/ps2.c +++ /dev/null @@ -1,469 +0,0 @@ -/* -Copyright 2010,2011,2012,2013 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. -*/ - -#include -#include -#include -#include -#include "ps2.h" -#include "debug.h" - - -#ifndef PS2_USE_INT -static uint8_t recv_data(void); -#endif -static inline void clock_lo(void); -static inline void clock_hi(void); -static inline bool clock_in(void); -static inline void data_lo(void); -static inline void data_hi(void); -static inline bool data_in(void); -static inline uint16_t wait_clock_lo(uint16_t us); -static inline uint16_t wait_clock_hi(uint16_t us); -static inline uint16_t wait_data_lo(uint16_t us); -static inline uint16_t wait_data_hi(uint16_t us); -static inline void idle(void); -static inline void inhibit(void); - - -/* -Primitive PS/2 Library for AVR -============================== -Host side is only supported now. - - -I/O control ------------ -High state is asserted by input with pull up. - - -PS/2 References ---------------- -http://www.computer-engineering.org/ps2protocol/ -http://www.mcamafia.de/pdf/ibm_hitrc07.pdf -*/ - - -#define WAIT(stat, us, err) do { \ - if (!wait_##stat(us)) { \ - ps2_error = err; \ - goto ERROR; \ - } \ -} while (0) - - -uint8_t ps2_error = PS2_ERR_NONE; - - -void ps2_host_init(void) -{ - // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) - _delay_ms(2500); - -#ifdef PS2_USE_INT - PS2_INT_INIT(); - PS2_INT_ON(); - idle(); -#else - inhibit(); -#endif -} - -// TODO: send using interrupt if available -uint8_t ps2_host_send(uint8_t data) -{ - uint8_t res = 0; - bool parity = true; - ps2_error = PS2_ERR_NONE; -#ifdef PS2_USE_INT - PS2_INT_OFF(); -#endif - /* terminate a transmission if we have */ - inhibit(); - _delay_us(200); // at least 100us - - /* start bit [1] */ - data_lo(); - clock_hi(); - WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking - /* data [2-9] */ - for (uint8_t i = 0; i < 8; i++) { - _delay_us(15); - if (data&(1<>= 1; - if (data_in()) { - data |= 0x80; - parity++; - } - break; - case PARITY: - if (data_in()) { - if (!(parity & 0x01)) - goto ERROR; - } else { - if (parity & 0x01) - goto ERROR; - } - break; - case STOP: - if (!data_in()) - goto ERROR; - pbuf_enqueue(data); -//phex(data); - goto DONE; - break; - default: - goto ERROR; - } - goto RETURN; -ERROR: - inhibit(); - ps2_error = state; -DONE: - state = INIT; - data = 0; - parity = 1; -RETURN: - return; -} -#endif - - -/* send LED state to keyboard */ -void ps2_host_set_led(uint8_t led) -{ - ps2_host_send(0xED); - ps2_host_send(led); -} - - -#ifndef PS2_USE_INT -/* called after start bit comes */ -static uint8_t recv_data(void) -{ - uint8_t data = 0; - bool parity = true; - ps2_error = PS2_ERR_NONE; - - /* start bit [1] */ - WAIT(clock_lo, 1, 1); - WAIT(data_lo, 1, 2); - WAIT(clock_hi, 50, 3); - - /* data [2-9] */ - for (uint8_t i = 0; i < 8; i++) { - WAIT(clock_lo, 50, 4); - if (data_in()) { - parity = !parity; - data |= (1< #include #include "ps2.h" #include "debug.h" -/* - * PS/2 protocol busywait version - */ - #define WAIT(stat, us, err) do { \ if (!wait_##stat(us)) { \ ps2_error = err; \ @@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE. } \ } while (0) + uint8_t ps2_error = PS2_ERR_NONE; @@ -65,18 +66,19 @@ void ps2_host_init(void) uint8_t ps2_host_send(uint8_t data) { - uint8_t res = 0; bool parity = true; ps2_error = PS2_ERR_NONE; + /* terminate a transmission if we have */ inhibit(); - _delay_us(200); // at least 100us + _delay_us(100); // 100us [4]p.13, [5]p.50 - /* start bit [1] */ + /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); - WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking - /* data [2-9] */ + WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 + + /* Data bit */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(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. +*/ + +/* + * PS/2 protocol Pin interrupt version + */ + +#include +#include +#include "ps2.h" +#include "debug.h" + + +#define WAIT(stat, us, err) do { \ + if (!wait_##stat(us)) { \ + ps2_error = err; \ + goto ERROR; \ + } \ +} while (0) + + +uint8_t ps2_error = PS2_ERR_NONE; + + +static inline uint8_t pbuf_dequeue(void); +static inline void pbuf_enqueue(uint8_t data); +static inline bool pbuf_has_data(void); +static inline void pbuf_clear(void); + + +void ps2_host_init(void) +{ + idle(); + PS2_INT_INIT(); + PS2_INT_ON(); + // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) + //_delay_ms(2500); +} + +uint8_t ps2_host_send(uint8_t data) +{ + bool parity = true; + ps2_error = PS2_ERR_NONE; + + PS2_INT_OFF(); + + /* terminate a transmission if we have */ + inhibit(); + _delay_us(100); // 100us [4]p.13, [5]p.50 + + /* 'Request to Send' and Start bit */ + data_lo(); + clock_hi(); + WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 + + /* Data bit[2-9] */ + for (uint8_t i = 0; i < 8; i++) { + _delay_us(15); + if (data&(1<>= 1; + if (data_in()) { + data |= 0x80; + parity++; + } + break; + case PARITY: + if (data_in()) { + if (!(parity & 0x01)) + goto ERROR; + } else { + if (parity & 0x01) + goto ERROR; + } + break; + case STOP: + if (!data_in()) + goto ERROR; + pbuf_enqueue(data); + goto DONE; + break; + default: + goto ERROR; + } + goto RETURN; +ERROR: + ps2_error = state; +DONE: + state = INIT; + data = 0; + parity = 1; +RETURN: + return; +} + +/* send LED state to keyboard */ +void ps2_host_set_led(uint8_t led) +{ + ps2_host_send(0xED); + ps2_host_send(led); +} + + +/*-------------------------------------------------------------------- + * Ring buffer to store scan codes from keyboard + *------------------------------------------------------------------*/ +#define PBUF_SIZE 32 +static uint8_t pbuf[PBUF_SIZE]; +static uint8_t pbuf_head = 0; +static uint8_t pbuf_tail = 0; +static inline void pbuf_enqueue(uint8_t data) +{ + uint8_t sreg = SREG; + cli(); + uint8_t next = (pbuf_head + 1) % PBUF_SIZE; + if (next != pbuf_tail) { + pbuf[pbuf_head] = data; + pbuf_head = next; + } else { + debug("pbuf: full\n"); + } + SREG = sreg; +} +static inline uint8_t pbuf_dequeue(void) +{ + uint8_t val = 0; + + uint8_t sreg = SREG; + cli(); + if (pbuf_head != pbuf_tail) { + val = pbuf[pbuf_tail]; + pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; + } + SREG = sreg; + + return val; +} +static inline bool pbuf_has_data(void) +{ + uint8_t sreg = SREG; + cli(); + bool has_data = (pbuf_head != pbuf_tail); + SREG = sreg; + return has_data; +} +static inline void pbuf_clear(void) +{ + uint8_t sreg = SREG; + cli(); + pbuf_head = pbuf_tail = 0; + SREG = sreg; +} + diff --git a/protocol/ps2_usart.c b/protocol/ps2_usart.c index d491142868..27947143ee 100644 --- a/protocol/ps2_usart.c +++ b/protocol/ps2_usart.c @@ -82,13 +82,14 @@ uint8_t ps2_host_send(uint8_t data) /* terminate a transmission if we have */ inhibit(); - _delay_us(100); + _delay_us(100); // [4]p.13 - /* start bit [1] */ + /* 'Request to Send' and Start bit */ data_lo(); clock_hi(); - WAIT(clock_lo, 15000, 1); - /* data [2-9] */ + WAIT(clock_lo, 10000, 10); // 10ms [5]p.50 + + /* Data bit[2-9] */ for (uint8_t i = 0; i < 8; i++) { _delay_us(15); if (data&(1<