1
0
tmk_keyboard/protocol/ps2_interrupt.c
tmk 22b6e15a17 Squashed 'tmk_core/' changes from 8da1898..e5f9940
e5f9940 Merge commit '1bc3dd200b023cecf063a0cb3ba347f77f6d759d' into core_update
da03c50 Add note for L/R side bit being ignored
e80f3c1 Add in basic documentation for Macro system
35e8a76 core: Swap position of PEQL and PENT in unimap
00751f1 Merge pull request #406 from 39aldo39/patch-1
e50d7de V-USB remote wakeup
4340997 core: Fix typo in definition AC_g
958144d core: Debug print for system and consumer keys
e7e1030 core: Fix sleep_led
0866323 core: Change matrix_init and matrix_print
0dbf73d core: Add matrix_clear() and default impl.
3202ca3 core: Add suspend mode options
4cda3aa core: Fix suspend/wake for converters #386
4e15247 core: LUFA_DEBUG_SUART for serial debug
b9cf8e7 core: Fix mechanical locking supoort #390
12aa0fd Merge branch 'nemith-master'
fccb3fa core: Fix OPT_DEFS for mbed build
2e2d2c8 Merge branch 'master' of github.com:leizzer/tmk_keyboard
f1d3634 Change .gitignore for ChibiOS
3aab802 core: Fix build config in protocol.mk
5e43da0 core: Add short names in unimap
7a56998 core: Fix dfu wait in rules.mk
6d9c500 Merge branch 'mediakey-fix'
08382ac core: Fix 'make dfu' message
78cb04e Fix OS X Recognizing keyboard as Mouse/Tablet
a114714 core: 'make dfu' waits for bootloader to start
d0a8f13 core: Fix unimap UNIMAP_NO case
e17abef core: Change lufa NKRO report size 16 to 32 bytes
375b20f core: Fix common.mk for build options
394fdff core: Fix unimap layout comment
912326c core: Add unimap support
00f4011 core: Fix doc/keymap.md for new keymap framework
ddbd7b4 core: Add default implemenation of keymap read
671cacc core: action codes are action_t struct now
b4fdb27 core: Change chibios repo directory names
7daed10 core: Fix keycode.txt
90399d7 core: Fix USB remote wakeup on ATmega32U2 #361
3677e84 usb_usb: Add multiple keyboard support
54d5b26 core: Fix Logical Maximum in report descriptor
bd0d372 core: Fix LUFA report descriptor
95327b5 Merge pull request #355 from papodaca/XT
62bf548 core: change API of adb.c to accept device address
3097c9e Fix function name in host.h
836e209 Merge branch 'core_split_160522'
3918ea2 Merge commit '20b787fc1284176834cbe7ca2134e4b36bec5828'
7f87b11 core: Add comment of register 3 of ADB
ef6478a core: Add adb_host_talk()
5c665b4 update macro names in bluefruit
4f2c5bf Merge commit '71381457fa1311dfa0b58ba882a96db740640871'
53a9c08 Merge pull request #321 from njbair/master
f08a656 core: Fix media/consumer keys
d526de8 Clean up wording in keymap example
0bb3dbb Clarify layer precedence
d915c75 clarify layer documentation
72070d4 ps2_usb: Fix for VUSB configuration
170e2dc Mostly working. Is unstable, will emit bad codes after a while.
c8e45b5 core: Actionmap support
aabaa24 Codes appear to be detected correctly, the break codes are broken.

git-subtree-dir: tmk_core
git-subtree-split: e5f994033cbc8700745ac0c6d12772820492eed0
2016-12-10 10:29:51 +09:00

222 lines
5.2 KiB
C

/*
Copyright 2010,2011,2012,2013 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,
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 <stdbool.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "pbuff.h"
#include "ps2.h"
#include "ps2_io.h"
#include "print.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;
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<<i)) {
parity = !parity;
data_hi();
} else {
data_lo();
}
WAIT(clock_hi, 50, 2);
WAIT(clock_lo, 50, 3);
}
/* Parity bit */
_delay_us(15);
if (parity) { data_hi(); } else { data_lo(); }
WAIT(clock_hi, 50, 4);
WAIT(clock_lo, 50, 5);
/* Stop bit */
_delay_us(15);
data_hi();
/* Ack */
WAIT(data_lo, 50, 6);
WAIT(clock_lo, 50, 7);
/* wait for idle state */
WAIT(clock_hi, 50, 8);
WAIT(data_hi, 50, 9);
idle();
PS2_INT_ON();
return ps2_host_recv_response();
ERROR:
idle();
PS2_INT_ON();
return 0;
}
uint8_t ps2_host_recv_response(void)
{
// Command may take 25ms/20ms at most([5]p.46, [3]p.21)
uint8_t retry = 25;
while (retry-- && !pbuf_has_data()) {
_delay_ms(1);
}
return pbuf_dequeue();
}
/* get data received by interrupt */
uint8_t ps2_host_recv(void)
{
if (pbuf_has_data()) {
ps2_error = PS2_ERR_NONE;
return pbuf_dequeue();
} else {
ps2_error = PS2_ERR_NODATA;
return 0;
}
}
ISR(PS2_INT_VECT)
{
static enum {
INIT,
START,
BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7,
PARITY,
STOP,
} state = INIT;
static uint8_t data = 0;
static uint8_t parity = 1;
// TODO: abort if elapse 100us from previous interrupt
// return unless falling edge
if (clock_in()) {
goto RETURN;
}
state++;
switch (state) {
case START:
if (data_in())
goto ERROR;
break;
case BIT0:
case BIT1:
case BIT2:
case BIT3:
case BIT4:
case BIT5:
case BIT6:
case BIT7:
data >>= 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);
}