aboutsummaryrefslogtreecommitdiff
path: root/protocol
diff options
context:
space:
mode:
Diffstat (limited to 'protocol')
-rw-r--r--protocol/lufa/lufa.c4
-rw-r--r--protocol/pjrc/usb.c3
-rw-r--r--protocol/ps2.h146
-rw-r--r--protocol/ps2_busywait.c185
-rw-r--r--protocol/ps2_interrupt.c (renamed from protocol/ps2.c)334
-rw-r--r--protocol/ps2_usart.c174
6 files changed, 431 insertions, 415 deletions
diff --git a/protocol/lufa/lufa.c b/protocol/lufa/lufa.c
index 04e8e78f3..eca51c878 100644
--- a/protocol/lufa/lufa.c
+++ b/protocol/lufa/lufa.c
@@ -148,7 +148,6 @@ static void Console_Task(void)
148*/ 148*/
149void EVENT_USB_Device_Connect(void) 149void EVENT_USB_Device_Connect(void)
150{ 150{
151 led_set(0x1f); // all on
152} 151}
153 152
154void EVENT_USB_Device_Disconnect(void) 153void EVENT_USB_Device_Disconnect(void)
@@ -172,8 +171,9 @@ void EVENT_USB_Device_WakeUp()
172 171
173#ifdef SLEEP_LED_ENABLE 172#ifdef SLEEP_LED_ENABLE
174 sleep_led_disable(); 173 sleep_led_disable();
175#endif 174 // NOTE: converters may not accept this
176 led_set(host_keyboard_leds()); 175 led_set(host_keyboard_leds());
176#endif
177} 177}
178 178
179void EVENT_USB_Device_StartOfFrame(void) 179void EVENT_USB_Device_StartOfFrame(void)
diff --git a/protocol/pjrc/usb.c b/protocol/pjrc/usb.c
index 84c99972f..393b36f78 100644
--- a/protocol/pjrc/usb.c
+++ b/protocol/pjrc/usb.c
@@ -662,8 +662,9 @@ ISR(USB_GEN_vect)
662 suspend_wakeup_init(); 662 suspend_wakeup_init();
663#ifdef SLEEP_LED_ENABLE 663#ifdef SLEEP_LED_ENABLE
664 sleep_led_disable(); 664 sleep_led_disable();
665#endif 665 // NOTE: converters may not accept this
666 led_set(host_keyboard_leds()); 666 led_set(host_keyboard_leds());
667#endif
667 668
668 UDIEN |= (1<<SUSPE); 669 UDIEN |= (1<<SUSPE);
669 UDIEN &= ~(1<<WAKEUPE); 670 UDIEN &= ~(1<<WAKEUPE);
diff --git a/protocol/ps2.h b/protocol/ps2.h
index 834165356..483eea720 100644
--- a/protocol/ps2.h
+++ b/protocol/ps2.h
@@ -1,5 +1,5 @@
1/* 1/*
2Copyright 2010,2011 Jun WAKO <wakojun@gmail.com> 2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3 3
4This software is licensed with a Modified BSD License. 4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free, 5All of this is supposed to be Free Software, Open Source, DFSG-free,
@@ -37,32 +37,46 @@ POSSIBILITY OF SUCH DAMAGE.
37 37
38#ifndef PS2_H 38#ifndef PS2_H
39#define PS2_H 39#define PS2_H
40
41#include <stdbool.h>
42#include <util/delay.h>
43#include <avr/io.h>
44
40/* 45/*
41 * Primitive PS/2 Library for AVR 46 * Primitive PS/2 Library for AVR
47 *
48 * PS/2 Resources
49 * --------------
50 * [1] The PS/2 Mouse/Keyboard Protocol
51 * http://www.computer-engineering.org/ps2protocol/
52 * Concise and thorough primer of PS/2 protocol.
53 *
54 * [2] Keyboard and Auxiliary Device Controller
55 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
56 * Signal Timing and Format
57 *
58 * [3] Keyboards(101- and 102-key)
59 * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
60 * Keyboard Layout, Scan Code Set, POR, and Commands.
61 *
62 * [4] PS/2 Reference Manuals
63 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
64 * Collection of IBM Personal System/2 documents.
65 *
66 * [5] TrackPoint Engineering Specifications for version 3E
67 * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
42 */ 68 */
43
44
45/* port settings for clock and data line */
46#if !(defined(PS2_CLOCK_PORT) && \
47 defined(PS2_CLOCK_PIN) && \
48 defined(PS2_CLOCK_DDR) && \
49 defined(PS2_CLOCK_BIT))
50# error "PS/2 clock port setting is required in config.h"
51#endif
52
53#if !(defined(PS2_DATA_PORT) && \
54 defined(PS2_DATA_PIN) && \
55 defined(PS2_DATA_DDR) && \
56 defined(PS2_DATA_BIT))
57# error "PS/2 data port setting is required in config.h"
58#endif
59
60#define PS2_ACK 0xFA 69#define PS2_ACK 0xFA
61#define PS2_RESEND 0xFE 70#define PS2_RESEND 0xFE
62#define PS2_SET_LED 0xED 71#define PS2_SET_LED 0xED
63 72
64#define PS2_ERR_NONE 0 73// TODO: error numbers
65#define PS2_ERR_PARITY 0x10 74#define PS2_ERR_NONE 0
75#define PS2_ERR_STARTBIT1 1
76#define PS2_ERR_STARTBIT2 2
77#define PS2_ERR_STARTBIT3 3
78#define PS2_ERR_PARITY 0x10
79#define PS2_ERR_NODATA 0x20
66 80
67#define PS2_LED_SCROLL_LOCK 0 81#define PS2_LED_SCROLL_LOCK 0
68#define PS2_LED_NUM_LOCK 1 82#define PS2_LED_NUM_LOCK 1
@@ -71,13 +85,101 @@ POSSIBILITY OF SUCH DAMAGE.
71 85
72extern uint8_t ps2_error; 86extern uint8_t ps2_error;
73 87
74/* host role */
75void ps2_host_init(void); 88void ps2_host_init(void);
76uint8_t ps2_host_send(uint8_t data); 89uint8_t ps2_host_send(uint8_t data);
77uint8_t ps2_host_recv_response(void); 90uint8_t ps2_host_recv_response(void);
78uint8_t ps2_host_recv(void); 91uint8_t ps2_host_recv(void);
79void ps2_host_set_led(uint8_t usb_led); 92void ps2_host_set_led(uint8_t usb_led);
80 93
81/* device role */ 94
95/* Check port settings for clock and data line */
96#if !(defined(PS2_CLOCK_PORT) && \
97 defined(PS2_CLOCK_PIN) && \
98 defined(PS2_CLOCK_DDR) && \
99 defined(PS2_CLOCK_BIT))
100# error "PS/2 clock port setting is required in config.h"
101#endif
102
103#if !(defined(PS2_DATA_PORT) && \
104 defined(PS2_DATA_PIN) && \
105 defined(PS2_DATA_DDR) && \
106 defined(PS2_DATA_BIT))
107# error "PS/2 data port setting is required in config.h"
108#endif
109
110/*--------------------------------------------------------------------
111 * static functions
112 *------------------------------------------------------------------*/
113static inline void clock_lo(void)
114{
115 PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
116 PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
117}
118static inline void clock_hi(void)
119{
120 /* input with pull up */
121 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
122 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
123}
124static inline bool clock_in(void)
125{
126 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
127 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
128 _delay_us(1);
129 return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
130}
131static inline void data_lo(void)
132{
133 PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
134 PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
135}
136static inline void data_hi(void)
137{
138 /* input with pull up */
139 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
140 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
141}
142static inline bool data_in(void)
143{
144 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
145 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
146 _delay_us(1);
147 return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
148}
149
150static inline uint16_t wait_clock_lo(uint16_t us)
151{
152 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
153 return us;
154}
155static inline uint16_t wait_clock_hi(uint16_t us)
156{
157 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
158 return us;
159}
160static inline uint16_t wait_data_lo(uint16_t us)
161{
162 while (data_in() && us) { asm(""); _delay_us(1); us--; }
163 return us;
164}
165static inline uint16_t wait_data_hi(uint16_t us)
166{
167 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
168 return us;
169}
170
171/* idle state that device can send */
172static inline void idle(void)
173{
174 clock_hi();
175 data_hi();
176}
177
178/* inhibit device to send */
179static inline void inhibit(void)
180{
181 clock_lo();
182 data_hi();
183}
82 184
83#endif 185#endif
diff --git a/protocol/ps2_busywait.c b/protocol/ps2_busywait.c
new file mode 100644
index 000000000..05dd7b27e
--- /dev/null
+++ b/protocol/ps2_busywait.c
@@ -0,0 +1,185 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38/*
39 * PS/2 protocol busywait version
40 */
41
42#include <stdbool.h>
43#include <util/delay.h>
44#include "ps2.h"
45#include "debug.h"
46
47
48#define WAIT(stat, us, err) do { \
49 if (!wait_##stat(us)) { \
50 ps2_error = err; \
51 goto ERROR; \
52 } \
53} while (0)
54
55
56uint8_t ps2_error = PS2_ERR_NONE;
57
58
59void ps2_host_init(void)
60{
61 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
62 _delay_ms(2500);
63
64 inhibit();
65}
66
67uint8_t ps2_host_send(uint8_t data)
68{
69 bool parity = true;
70 ps2_error = PS2_ERR_NONE;
71
72 /* terminate a transmission if we have */
73 inhibit();
74 _delay_us(100); // 100us [4]p.13, [5]p.50
75
76 /* 'Request to Send' and Start bit */
77 data_lo();
78 clock_hi();
79 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
80
81 /* Data bit */
82 for (uint8_t i = 0; i < 8; i++) {
83 _delay_us(15);
84 if (data&(1<<i)) {
85 parity = !parity;
86 data_hi();
87 } else {
88 data_lo();
89 }
90 WAIT(clock_hi, 50, 2);
91 WAIT(clock_lo, 50, 3);
92 }
93
94 /* Parity bit */
95 _delay_us(15);
96 if (parity) { data_hi(); } else { data_lo(); }
97 WAIT(clock_hi, 50, 4);
98 WAIT(clock_lo, 50, 5);
99
100 /* Stop bit */
101 _delay_us(15);
102 data_hi();
103
104 /* Ack */
105 WAIT(data_lo, 50, 6);
106 WAIT(clock_lo, 50, 7);
107
108 /* wait for idle state */
109 WAIT(clock_hi, 50, 8);
110 WAIT(data_hi, 50, 9);
111
112 inhibit();
113 return ps2_host_recv_response();
114ERROR:
115 inhibit();
116 return 0;
117}
118
119/* receive data when host want else inhibit communication */
120uint8_t ps2_host_recv_response(void)
121{
122 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
123 // 250 * 100us(wait for start bit in ps2_host_recv)
124 uint8_t data = 0;
125 uint8_t try = 250;
126 do {
127 data = ps2_host_recv();
128 } while (try-- && ps2_error);
129 return data;
130}
131
132/* called after start bit comes */
133uint8_t ps2_host_recv(void)
134{
135 uint8_t data = 0;
136 bool parity = true;
137 ps2_error = PS2_ERR_NONE;
138
139 /* release lines(idle state) */
140 idle();
141
142 /* start bit [1] */
143 WAIT(clock_lo, 100, 1); // TODO: this is enough?
144 WAIT(data_lo, 1, 2);
145 WAIT(clock_hi, 50, 3);
146
147 /* data [2-9] */
148 for (uint8_t i = 0; i < 8; i++) {
149 WAIT(clock_lo, 50, 4);
150 if (data_in()) {
151 parity = !parity;
152 data |= (1<<i);
153 }
154 WAIT(clock_hi, 50, 5);
155 }
156
157 /* parity [10] */
158 WAIT(clock_lo, 50, 6);
159 if (data_in() != parity) {
160 ps2_error = PS2_ERR_PARITY;
161 goto ERROR;
162 }
163 WAIT(clock_hi, 50, 7);
164
165 /* stop bit [11] */
166 WAIT(clock_lo, 50, 8);
167 WAIT(data_hi, 1, 9);
168 WAIT(clock_hi, 50, 10);
169
170 inhibit();
171 return data;
172ERROR:
173 if (ps2_error > PS2_ERR_STARTBIT3) {
174 xprintf("x%02X\n", ps2_error);
175 }
176 inhibit();
177 return 0;
178}
179
180/* send LED state to keyboard */
181void ps2_host_set_led(uint8_t led)
182{
183 ps2_host_send(0xED);
184 ps2_host_send(led);
185}
diff --git a/protocol/ps2.c b/protocol/ps2_interrupt.c
index e5873a9bf..259d25400 100644
--- a/protocol/ps2.c
+++ b/protocol/ps2_interrupt.c
@@ -35,47 +35,15 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE. 35POSSIBILITY OF SUCH DAMAGE.
36*/ 36*/
37 37
38/*
39 * PS/2 protocol Pin interrupt version
40 */
41
38#include <stdbool.h> 42#include <stdbool.h>
39#include <avr/io.h>
40#include <avr/interrupt.h> 43#include <avr/interrupt.h>
41#include <util/delay.h> 44#include <util/delay.h>
42#include "ps2.h" 45#include "ps2.h"
43#include "debug.h" 46#include "print.h"
44
45
46#ifndef PS2_USE_INT
47static uint8_t recv_data(void);
48#endif
49static inline void clock_lo(void);
50static inline void clock_hi(void);
51static inline bool clock_in(void);
52static inline void data_lo(void);
53static inline void data_hi(void);
54static inline bool data_in(void);
55static inline uint16_t wait_clock_lo(uint16_t us);
56static inline uint16_t wait_clock_hi(uint16_t us);
57static inline uint16_t wait_data_lo(uint16_t us);
58static inline uint16_t wait_data_hi(uint16_t us);
59static inline void idle(void);
60static inline void inhibit(void);
61
62
63/*
64Primitive PS/2 Library for AVR
65==============================
66Host side is only supported now.
67
68
69I/O control
70-----------
71High state is asserted by input with pull up.
72
73
74PS/2 References
75---------------
76http://www.computer-engineering.org/ps2protocol/
77http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
78*/
79 47
80 48
81#define WAIT(stat, us, err) do { \ 49#define WAIT(stat, us, err) do { \
@@ -89,35 +57,38 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
89uint8_t ps2_error = PS2_ERR_NONE; 57uint8_t ps2_error = PS2_ERR_NONE;
90 58
91 59
60static inline uint8_t pbuf_dequeue(void);
61static inline void pbuf_enqueue(uint8_t data);
62static inline bool pbuf_has_data(void);
63static inline void pbuf_clear(void);
64
65
92void ps2_host_init(void) 66void ps2_host_init(void)
93{ 67{
94#ifdef PS2_USE_INT 68 idle();
95 PS2_INT_INIT(); 69 PS2_INT_INIT();
96 PS2_INT_ON(); 70 PS2_INT_ON();
97 idle(); 71 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
98#else 72 //_delay_ms(2500);
99 inhibit();
100#endif
101} 73}
102 74
103// TODO: send using interrupt if available
104uint8_t ps2_host_send(uint8_t data) 75uint8_t ps2_host_send(uint8_t data)
105{ 76{
106 uint8_t res = 0;
107 bool parity = true; 77 bool parity = true;
108 ps2_error = PS2_ERR_NONE; 78 ps2_error = PS2_ERR_NONE;
109#ifdef PS2_USE_INT 79
110 PS2_INT_OFF(); 80 PS2_INT_OFF();
111#endif 81
112 /* terminate a transmission if we have */ 82 /* terminate a transmission if we have */
113 inhibit(); 83 inhibit();
114 _delay_us(200); // at least 100us 84 _delay_us(100); // 100us [4]p.13, [5]p.50
115 85
116 /* start bit [1] */ 86 /* 'Request to Send' and Start bit */
117 data_lo(); 87 data_lo();
118 clock_hi(); 88 clock_hi();
119 WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking 89 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
120 /* data [2-9] */ 90
91 /* Data bit[2-9] */
121 for (uint8_t i = 0; i < 8; i++) { 92 for (uint8_t i = 0; i < 8; i++) {
122 _delay_us(15); 93 _delay_us(15);
123 if (data&(1<<i)) { 94 if (data&(1<<i)) {
@@ -129,15 +100,18 @@ uint8_t ps2_host_send(uint8_t data)
129 WAIT(clock_hi, 50, 2); 100 WAIT(clock_hi, 50, 2);
130 WAIT(clock_lo, 50, 3); 101 WAIT(clock_lo, 50, 3);
131 } 102 }
132 /* parity [10] */ 103
104 /* Parity bit */
133 _delay_us(15); 105 _delay_us(15);
134 if (parity) { data_hi(); } else { data_lo(); } 106 if (parity) { data_hi(); } else { data_lo(); }
135 WAIT(clock_hi, 50, 4); 107 WAIT(clock_hi, 50, 4);
136 WAIT(clock_lo, 50, 5); 108 WAIT(clock_lo, 50, 5);
137 /* stop bit [11] */ 109
110 /* Stop bit */
138 _delay_us(15); 111 _delay_us(15);
139 data_hi(); 112 data_hi();
140 /* ack [12] */ 113
114 /* Ack */
141 WAIT(data_lo, 50, 6); 115 WAIT(data_lo, 50, 6);
142 WAIT(clock_lo, 50, 7); 116 WAIT(clock_lo, 50, 7);
143 117
@@ -145,116 +119,35 @@ uint8_t ps2_host_send(uint8_t data)
145 WAIT(clock_hi, 50, 8); 119 WAIT(clock_hi, 50, 8);
146 WAIT(data_hi, 50, 9); 120 WAIT(data_hi, 50, 9);
147 121
148#ifdef PS2_USE_INT 122 idle();
149 PS2_INT_ON(); 123 PS2_INT_ON();
150#endif 124 return ps2_host_recv_response();
151 res = ps2_host_recv_response();
152ERROR: 125ERROR:
153#ifdef PS2_USE_INT
154 PS2_INT_ON();
155 idle(); 126 idle();
156#else 127 PS2_INT_ON();
157 inhibit(); 128 return 0;
158#endif
159 return res;
160} 129}
161 130
162#ifndef PS2_USE_INT
163/* receive data when host want else inhibit communication */
164uint8_t ps2_host_recv_response(void) 131uint8_t ps2_host_recv_response(void)
165{ 132{
166 uint8_t data = 0; 133 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
167 134 uint8_t retry = 25;
168#ifdef PS2_USE_INT 135 while (retry-- && !pbuf_has_data()) {
169 PS2_INT_OFF(); 136 _delay_ms(1);
170#endif
171 /* terminate a transmission if we have */
172 inhibit();
173 _delay_us(100);
174
175 /* release lines(idle state) */
176 idle();
177
178 /* wait start bit */
179 wait_clock_lo(25000); // command response may take 20 ms at most
180 data = recv_data();
181
182 inhibit();
183 return data;
184}
185#endif
186
187#ifndef PS2_USE_INT
188uint8_t ps2_host_recv(void)
189{
190 return ps2_host_recv_response();
191}
192#else
193/* ring buffer to store ps/2 key data */
194#define PBUF_SIZE 32
195static uint8_t pbuf[PBUF_SIZE];
196static uint8_t pbuf_head = 0;
197static uint8_t pbuf_tail = 0;
198static inline void pbuf_enqueue(uint8_t data)
199{
200 uint8_t sreg = SREG;
201 cli();
202 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
203 if (next != pbuf_tail) {
204 pbuf[pbuf_head] = data;
205 pbuf_head = next;
206 } else {
207 debug("pbuf: full\n");
208 }
209 SREG = sreg;
210}
211static inline uint8_t pbuf_dequeue(void)
212{
213 uint8_t val = 0;
214
215 uint8_t sreg = SREG;
216 cli();
217 if (pbuf_head != pbuf_tail) {
218 val = pbuf[pbuf_tail];
219 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
220 } 137 }
221 SREG = sreg; 138 return pbuf_dequeue();
222
223 return val;
224}
225static inline bool pbuf_has_data(void)
226{
227 uint8_t sreg = SREG;
228 cli();
229 bool has_data = (pbuf_head != pbuf_tail);
230 SREG = sreg;
231 return has_data;
232}
233static inline void pbuf_clear(void)
234{
235 uint8_t sreg = SREG;
236 cli();
237 pbuf_head = pbuf_tail = 0;
238 SREG = sreg;
239} 139}
240 140
241/* get data received by interrupt */ 141/* get data received by interrupt */
242uint8_t ps2_host_recv(void) 142uint8_t ps2_host_recv(void)
243{ 143{
244 if (ps2_error) { 144 if (pbuf_has_data()) {
245 print("x");
246 phex(ps2_error);
247 ps2_host_send(0xFE); // request to resend
248 ps2_error = PS2_ERR_NONE; 145 ps2_error = PS2_ERR_NONE;
146 return pbuf_dequeue();
147 } else {
148 ps2_error = PS2_ERR_NODATA;
149 return 0;
249 } 150 }
250 idle();
251 return pbuf_dequeue();
252}
253
254uint8_t ps2_host_recv_response(void)
255{
256 while (!pbuf_has_data()) ;
257 return pbuf_dequeue();
258} 151}
259 152
260ISR(PS2_INT_VECT) 153ISR(PS2_INT_VECT)
@@ -309,7 +202,6 @@ ISR(PS2_INT_VECT)
309 if (!data_in()) 202 if (!data_in())
310 goto ERROR; 203 goto ERROR;
311 pbuf_enqueue(data); 204 pbuf_enqueue(data);
312//phex(data);
313 goto DONE; 205 goto DONE;
314 break; 206 break;
315 default: 207 default:
@@ -317,7 +209,6 @@ ISR(PS2_INT_VECT)
317 } 209 }
318 goto RETURN; 210 goto RETURN;
319ERROR: 211ERROR:
320 inhibit();
321 ps2_error = state; 212 ps2_error = state;
322DONE: 213DONE:
323 state = INIT; 214 state = INIT;
@@ -326,8 +217,6 @@ DONE:
326RETURN: 217RETURN:
327 return; 218 return;
328} 219}
329#endif
330
331 220
332/* send LED state to keyboard */ 221/* send LED state to keyboard */
333void ps2_host_set_led(uint8_t led) 222void ps2_host_set_led(uint8_t led)
@@ -337,116 +226,53 @@ void ps2_host_set_led(uint8_t led)
337} 226}
338 227
339 228
340#ifndef PS2_USE_INT 229/*--------------------------------------------------------------------
341/* called after start bit comes */ 230 * Ring buffer to store scan codes from keyboard
342static uint8_t recv_data(void) 231 *------------------------------------------------------------------*/
232#define PBUF_SIZE 32
233static uint8_t pbuf[PBUF_SIZE];
234static uint8_t pbuf_head = 0;
235static uint8_t pbuf_tail = 0;
236static inline void pbuf_enqueue(uint8_t data)
343{ 237{
344 uint8_t data = 0; 238 uint8_t sreg = SREG;
345 bool parity = true; 239 cli();
346 ps2_error = PS2_ERR_NONE; 240 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
347 241 if (next != pbuf_tail) {
348 /* start bit [1] */ 242 pbuf[pbuf_head] = data;
349 WAIT(clock_lo, 1, 1); 243 pbuf_head = next;
350 WAIT(data_lo, 1, 2); 244 } else {
351 WAIT(clock_hi, 50, 3); 245 print("pbuf: full\n");
352
353 /* data [2-9] */
354 for (uint8_t i = 0; i < 8; i++) {
355 WAIT(clock_lo, 50, 4);
356 if (data_in()) {
357 parity = !parity;
358 data |= (1<<i);
359 }
360 WAIT(clock_hi, 50, 5);
361 }
362
363 /* parity [10] */
364 WAIT(clock_lo, 50, 6);
365 if (data_in() != parity) {
366 ps2_error = PS2_ERR_PARITY;
367 goto ERROR;
368 } 246 }
369 WAIT(clock_hi, 50, 7); 247 SREG = sreg;
370
371 /* stop bit [11] */
372 WAIT(clock_lo, 50, 8);
373 WAIT(data_hi, 1, 9);
374 WAIT(clock_hi, 50, 10);
375
376 return data;
377ERROR:
378 return 0;
379}
380#endif
381
382static inline void clock_lo()
383{
384 PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
385 PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
386}
387static inline void clock_hi()
388{
389 /* input with pull up */
390 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
391 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
392}
393static inline bool clock_in()
394{
395 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
396 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
397 _delay_us(1);
398 return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
399}
400static inline void data_lo()
401{
402 PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
403 PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
404}
405static inline void data_hi()
406{
407 /* input with pull up */
408 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
409 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
410} 248}
411static inline bool data_in() 249static inline uint8_t pbuf_dequeue(void)
412{ 250{
413 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT); 251 uint8_t val = 0;
414 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
415 _delay_us(1);
416 return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
417}
418 252
419static inline uint16_t wait_clock_lo(uint16_t us) 253 uint8_t sreg = SREG;
420{ 254 cli();
421 while (clock_in() && us) { asm(""); _delay_us(1); us--; } 255 if (pbuf_head != pbuf_tail) {
422 return us; 256 val = pbuf[pbuf_tail];
423} 257 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
424static inline uint16_t wait_clock_hi(uint16_t us) 258 }
425{ 259 SREG = sreg;
426 while (!clock_in() && us) { asm(""); _delay_us(1); us--; } 260
427 return us; 261 return val;
428}
429static inline uint16_t wait_data_lo(uint16_t us)
430{
431 while (data_in() && us) { asm(""); _delay_us(1); us--; }
432 return us;
433} 262}
434static inline uint16_t wait_data_hi(uint16_t us) 263static inline bool pbuf_has_data(void)
435{ 264{
436 while (!data_in() && us) { asm(""); _delay_us(1); us--; } 265 uint8_t sreg = SREG;
437 return us; 266 cli();
267 bool has_data = (pbuf_head != pbuf_tail);
268 SREG = sreg;
269 return has_data;
438} 270}
439 271static inline void pbuf_clear(void)
440/* idle state that device can send */
441static inline void idle(void)
442{ 272{
443 clock_hi(); 273 uint8_t sreg = SREG;
444 data_hi(); 274 cli();
275 pbuf_head = pbuf_tail = 0;
276 SREG = sreg;
445} 277}
446 278
447/* inhibit device to send */
448static inline void inhibit(void)
449{
450 clock_lo();
451 data_hi();
452}
diff --git a/protocol/ps2_usart.c b/protocol/ps2_usart.c
index 40c46c497..c2d9d0a20 100644
--- a/protocol/ps2_usart.c
+++ b/protocol/ps2_usart.c
@@ -36,32 +36,14 @@ POSSIBILITY OF SUCH DAMAGE.
36*/ 36*/
37 37
38/* 38/*
39Primitive PS/2 Library for AVR 39 * PS/2 protocol USART version
40============================== 40 */
41Host side is only supported now.
42Synchronous USART is used to receive data by hardware process
43rather than interrupt. During V-USB interrupt runs, CLOCK interrupt
44cannot interpose. In the result it is prone to lost CLOCK edge.
45 41
46
47I/O control
48-----------
49High state is asserted by internal pull-up.
50If you have a signaling problem, you may need to have
51external pull-up resisters on CLOCK and DATA line.
52
53
54PS/2 References
55---------------
56http://www.computer-engineering.org/ps2protocol/
57http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
58*/
59#include <stdbool.h> 42#include <stdbool.h>
60#include <avr/io.h>
61#include <avr/interrupt.h> 43#include <avr/interrupt.h>
62#include <util/delay.h> 44#include <util/delay.h>
63#include "ps2.h" 45#include "ps2.h"
64#include "debug.h" 46#include "print.h"
65 47
66 48
67#define WAIT(stat, us, err) do { \ 49#define WAIT(stat, us, err) do { \
@@ -75,18 +57,6 @@ http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
75uint8_t ps2_error = PS2_ERR_NONE; 57uint8_t ps2_error = PS2_ERR_NONE;
76 58
77 59
78static inline void clock_lo(void);
79static inline void clock_hi(void);
80static inline bool clock_in(void);
81static inline void data_lo(void);
82static inline void data_hi(void);
83static inline bool data_in(void);
84static inline uint16_t wait_clock_lo(uint16_t us);
85static inline uint16_t wait_clock_hi(uint16_t us);
86static inline uint16_t wait_data_lo(uint16_t us);
87static inline uint16_t wait_data_hi(uint16_t us);
88static inline void idle(void);
89static inline void inhibit(void);
90static inline uint8_t pbuf_dequeue(void); 60static inline uint8_t pbuf_dequeue(void);
91static inline void pbuf_enqueue(uint8_t data); 61static inline void pbuf_enqueue(uint8_t data);
92static inline bool pbuf_has_data(void); 62static inline bool pbuf_has_data(void);
@@ -95,14 +65,15 @@ static inline void pbuf_clear(void);
95 65
96void ps2_host_init(void) 66void ps2_host_init(void)
97{ 67{
98 idle(); 68 idle(); // without this many USART errors occur when cable is disconnected
99 PS2_USART_INIT(); 69 PS2_USART_INIT();
100 PS2_USART_RX_INT_ON(); 70 PS2_USART_RX_INT_ON();
71 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
72 //_delay_ms(2500);
101} 73}
102 74
103uint8_t ps2_host_send(uint8_t data) 75uint8_t ps2_host_send(uint8_t data)
104{ 76{
105 uint8_t res = 0;
106 bool parity = true; 77 bool parity = true;
107 ps2_error = PS2_ERR_NONE; 78 ps2_error = PS2_ERR_NONE;
108 79
@@ -110,13 +81,14 @@ uint8_t ps2_host_send(uint8_t data)
110 81
111 /* terminate a transmission if we have */ 82 /* terminate a transmission if we have */
112 inhibit(); 83 inhibit();
113 _delay_us(100); 84 _delay_us(100); // [4]p.13
114 85
115 /* start bit [1] */ 86 /* 'Request to Send' and Start bit */
116 data_lo(); 87 data_lo();
117 clock_hi(); 88 clock_hi();
118 WAIT(clock_lo, 15000, 1); 89 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
119 /* data [2-9] */ 90
91 /* Data bit[2-9] */
120 for (uint8_t i = 0; i < 8; i++) { 92 for (uint8_t i = 0; i < 8; i++) {
121 _delay_us(15); 93 _delay_us(15);
122 if (data&(1<<i)) { 94 if (data&(1<<i)) {
@@ -128,15 +100,18 @@ uint8_t ps2_host_send(uint8_t data)
128 WAIT(clock_hi, 50, 2); 100 WAIT(clock_hi, 50, 2);
129 WAIT(clock_lo, 50, 3); 101 WAIT(clock_lo, 50, 3);
130 } 102 }
131 /* parity [10] */ 103
104 /* Parity bit */
132 _delay_us(15); 105 _delay_us(15);
133 if (parity) { data_hi(); } else { data_lo(); } 106 if (parity) { data_hi(); } else { data_lo(); }
134 WAIT(clock_hi, 50, 4); 107 WAIT(clock_hi, 50, 4);
135 WAIT(clock_lo, 50, 5); 108 WAIT(clock_lo, 50, 5);
136 /* stop bit [11] */ 109
110 /* Stop bit */
137 _delay_us(15); 111 _delay_us(15);
138 data_hi(); 112 data_hi();
139 /* ack [12] */ 113
114 /* Ack */
140 WAIT(data_lo, 50, 6); 115 WAIT(data_lo, 50, 6);
141 WAIT(clock_lo, 50, 7); 116 WAIT(clock_lo, 50, 7);
142 117
@@ -144,127 +119,55 @@ uint8_t ps2_host_send(uint8_t data)
144 WAIT(clock_hi, 50, 8); 119 WAIT(clock_hi, 50, 8);
145 WAIT(data_hi, 50, 9); 120 WAIT(data_hi, 50, 9);
146 121
122 idle();
147 PS2_USART_INIT(); 123 PS2_USART_INIT();
148 PS2_USART_RX_INT_ON(); 124 PS2_USART_RX_INT_ON();
149 res = ps2_host_recv_response(); 125 return ps2_host_recv_response();
150ERROR: 126ERROR:
151 idle(); 127 idle();
152 PS2_USART_INIT(); 128 PS2_USART_INIT();
153 PS2_USART_RX_INT_ON(); 129 PS2_USART_RX_INT_ON();
154 return res; 130 return 0;
155} 131}
156 132
157// Do polling data from keyboard to get response to last command.
158uint8_t ps2_host_recv_response(void) 133uint8_t ps2_host_recv_response(void)
159{ 134{
160 while (!pbuf_has_data()) { 135 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
161 _delay_ms(1); // without this delay it seems to fall into deadlock 136 uint8_t retry = 25;
137 while (retry-- && !pbuf_has_data()) {
138 _delay_ms(1);
162 } 139 }
163 return pbuf_dequeue(); 140 return pbuf_dequeue();
164} 141}
165 142
166uint8_t ps2_host_recv(void) 143uint8_t ps2_host_recv(void)
167{ 144{
168 return pbuf_dequeue(); 145 if (pbuf_has_data()) {
146 ps2_error = PS2_ERR_NONE;
147 return pbuf_dequeue();
148 } else {
149 ps2_error = PS2_ERR_NODATA;
150 return 0;
151 }
169} 152}
170 153
171ISR(PS2_USART_RX_VECT) 154ISR(PS2_USART_RX_VECT)
172{ 155{
173 uint8_t error = PS2_USART_ERROR; 156 // TODO: request RESEND when error occurs?
157 uint8_t error = PS2_USART_ERROR; // USART error should be read before data
174 uint8_t data = PS2_USART_RX_DATA; 158 uint8_t data = PS2_USART_RX_DATA;
175 if (!error) { 159 if (!error) {
176 pbuf_enqueue(data); 160 pbuf_enqueue(data);
161 } else {
162 xprintf("PS2 USART error: %02X data: %02X\n", error, data);
177 } 163 }
178} 164}
179 165
180/* send LED state to keyboard */ 166/* send LED state to keyboard */
181void ps2_host_set_led(uint8_t led) 167void ps2_host_set_led(uint8_t led)
182{ 168{
183 // send 0xED then keyboard keeps waiting for next LED data 169 ps2_host_send(0xED);
184 // and keyboard does not send any scan codes during waiting. 170 ps2_host_send(led);
185 // If fail to send LED data keyboard looks like being freezed.
186 uint8_t retry = 3;
187 while (retry-- && ps2_host_send(PS2_SET_LED) != PS2_ACK)
188 ;
189 retry = 3;
190 while (retry-- && ps2_host_send(led) != PS2_ACK)
191 ;
192}
193
194
195/*--------------------------------------------------------------------
196 * static functions
197 *------------------------------------------------------------------*/
198static inline void clock_lo()
199{
200 PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
201 PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
202}
203static inline void clock_hi()
204{
205 /* input with pull up */
206 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
207 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
208}
209static inline bool clock_in()
210{
211 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
212 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
213 _delay_us(1);
214 return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
215}
216static inline void data_lo()
217{
218 PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
219 PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
220}
221static inline void data_hi()
222{
223 /* input with pull up */
224 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
225 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
226}
227static inline bool data_in()
228{
229 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
230 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
231 _delay_us(1);
232 return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
233}
234
235static inline uint16_t wait_clock_lo(uint16_t us)
236{
237 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
238 return us;
239}
240static inline uint16_t wait_clock_hi(uint16_t us)
241{
242 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
243 return us;
244}
245static inline uint16_t wait_data_lo(uint16_t us)
246{
247 while (data_in() && us) { asm(""); _delay_us(1); us--; }
248 return us;
249}
250static inline uint16_t wait_data_hi(uint16_t us)
251{
252 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
253 return us;
254}
255
256/* idle state that device can send */
257static inline void idle(void)
258{
259 clock_hi();
260 data_hi();
261}
262
263/* inhibit device to send */
264static inline void inhibit(void)
265{
266 clock_lo();
267 data_hi();
268} 171}
269 172
270 173
@@ -284,11 +187,10 @@ static inline void pbuf_enqueue(uint8_t data)
284 pbuf[pbuf_head] = data; 187 pbuf[pbuf_head] = data;
285 pbuf_head = next; 188 pbuf_head = next;
286 } else { 189 } else {
287 debug("pbuf: full\n"); 190 print("pbuf: full\n");
288 } 191 }
289 SREG = sreg; 192 SREG = sreg;
290} 193}
291
292static inline uint8_t pbuf_dequeue(void) 194static inline uint8_t pbuf_dequeue(void)
293{ 195{
294 uint8_t val = 0; 196 uint8_t val = 0;