aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortmk <nobody@nowhere>2013-11-25 17:43:26 +0900
committertmk <nobody@nowhere>2013-11-25 17:43:26 +0900
commit9ae9742ac59b18cf989370f53d669daeb75bd7a3 (patch)
tree2a661eaef74bb7817ff5d03ff115ec00249e188a
parentd5ecbb83daa13b806ee4879692aaf807b6b1b69f (diff)
downloadqmk_firmware-9ae9742ac59b18cf989370f53d669daeb75bd7a3.tar.gz
qmk_firmware-9ae9742ac59b18cf989370f53d669daeb75bd7a3.zip
Add ps2_busywait.c and recfactor PS/2 protocol
-rw-r--r--converter/ps2_usb/matrix.c28
-rw-r--r--protocol.mk2
-rw-r--r--protocol/ps2.c59
-rw-r--r--protocol/ps2.h144
-rw-r--r--protocol/ps2_busywait.c179
5 files changed, 361 insertions, 51 deletions
diff --git a/converter/ps2_usb/matrix.c b/converter/ps2_usb/matrix.c
index 4187ea060..a4c27f5d5 100644
--- a/converter/ps2_usb/matrix.c
+++ b/converter/ps2_usb/matrix.c
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
19#include <stdbool.h> 19#include <stdbool.h>
20#include <avr/io.h> 20#include <avr/io.h>
21#include <util/delay.h> 21#include <util/delay.h>
22#include "action.h"
22#include "print.h" 23#include "print.h"
23#include "util.h" 24#include "util.h"
24#include "debug.h" 25#include "debug.h"
@@ -185,8 +186,8 @@ uint8_t matrix_scan(void)
185 matrix_break(PAUSE); 186 matrix_break(PAUSE);
186 } 187 }
187 188
188 uint8_t code; 189 uint8_t code = ps2_host_recv();
189 while ((code = ps2_host_recv())) { 190 if (!ps2_error) {
190 switch (state) { 191 switch (state) {
191 case INIT: 192 case INIT:
192 switch (code) { 193 switch (code) {
@@ -207,11 +208,17 @@ uint8_t matrix_scan(void)
207 matrix_make(PRINT_SCREEN); 208 matrix_make(PRINT_SCREEN);
208 state = INIT; 209 state = INIT;
209 break; 210 break;
211 case 0x00: // Overrun [3]p.25
212 print("Overrun\n");
213 clear_keyboard();
214 state = INIT;
215 break;
210 default: // normal key make 216 default: // normal key make
211 if (code < 0x80) { 217 if (code < 0x80) {
212 matrix_make(code); 218 matrix_make(code);
213 } else { 219 } else {
214 debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n"); 220 printf("unexpected scan code at INIT: %02X\n", code);
221 clear_keyboard();
215 } 222 }
216 state = INIT; 223 state = INIT;
217 } 224 }
@@ -232,7 +239,8 @@ uint8_t matrix_scan(void)
232 if (code < 0x80) { 239 if (code < 0x80) {
233 matrix_make(code|0x80); 240 matrix_make(code|0x80);
234 } else { 241 } else {
235 debug("unexpected scan code at E0: "); debug_hex(code); debug("\n"); 242 printf("unexpected scan code at E0: %02X\n", code);
243 clear_keyboard();
236 } 244 }
237 state = INIT; 245 state = INIT;
238 } 246 }
@@ -251,7 +259,8 @@ uint8_t matrix_scan(void)
251 if (code < 0x80) { 259 if (code < 0x80) {
252 matrix_break(code); 260 matrix_break(code);
253 } else { 261 } else {
254 debug("unexpected scan code at F0: "); debug_hex(code); debug("\n"); 262 printf("unexpected scan code at F0: %02X\n", code);
263 clear_keyboard();
255 } 264 }
256 state = INIT; 265 state = INIT;
257 } 266 }
@@ -266,7 +275,8 @@ uint8_t matrix_scan(void)
266 if (code < 0x80) { 275 if (code < 0x80) {
267 matrix_break(code|0x80); 276 matrix_break(code|0x80);
268 } else { 277 } else {
269 debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n"); 278 printf("unexpected scan code at E0_F0: %02X\n", code);
279 clear_keyboard();
270 } 280 }
271 state = INIT; 281 state = INIT;
272 } 282 }
@@ -357,7 +367,11 @@ uint8_t matrix_scan(void)
357 default: 367 default:
358 state = INIT; 368 state = INIT;
359 } 369 }
360 phex(code); 370 }
371
372 if (ps2_error > PS2_ERR_STARTBIT3) {
373 uint8_t ret = ps2_host_send(PS2_RESEND);
374 printf("Resend: %02X\n", ret);
361 } 375 }
362 return 1; 376 return 1;
363} 377}
diff --git a/protocol.mk b/protocol.mk
index 0d5f06c7e..e33200873 100644
--- a/protocol.mk
+++ b/protocol.mk
@@ -8,7 +8,7 @@ ifdef PS2_MOUSE_ENABLE
8endif 8endif
9 9
10ifdef PS2_USE_BUSYWAIT 10ifdef PS2_USE_BUSYWAIT
11 SRC += protocol/ps2.c 11 SRC += protocol/ps2_busywait.c
12 OPT_DEFS += -DPS2_USE_BUSYWAIT 12 OPT_DEFS += -DPS2_USE_BUSYWAIT
13endif 13endif
14 14
diff --git a/protocol/ps2.c b/protocol/ps2.c
index e5873a9bf..4886b16d0 100644
--- a/protocol/ps2.c
+++ b/protocol/ps2.c
@@ -91,6 +91,9 @@ uint8_t ps2_error = PS2_ERR_NONE;
91 91
92void ps2_host_init(void) 92void ps2_host_init(void)
93{ 93{
94 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
95 _delay_ms(2500);
96
94#ifdef PS2_USE_INT 97#ifdef PS2_USE_INT
95 PS2_INT_INIT(); 98 PS2_INT_INIT();
96 PS2_INT_ON(); 99 PS2_INT_ON();
@@ -163,32 +166,30 @@ ERROR:
163/* receive data when host want else inhibit communication */ 166/* receive data when host want else inhibit communication */
164uint8_t ps2_host_recv_response(void) 167uint8_t ps2_host_recv_response(void)
165{ 168{
169 // Command might take 20ms to response([3]p.21)
170 // TrackPoint might take 25ms ([5]2.7)
166 uint8_t data = 0; 171 uint8_t data = 0;
167 172 uint8_t try = 200;
168#ifdef PS2_USE_INT 173 while (try-- && (data = ps2_host_recv())) ;
169 PS2_INT_OFF(); 174 return data;
175}
170#endif 176#endif
171 /* terminate a transmission if we have */ 177
172 inhibit(); 178#ifndef PS2_USE_INT
173 _delay_us(100); 179uint8_t ps2_host_recv(void)
180{
181 uint8_t data = 0;
174 182
175 /* release lines(idle state) */ 183 /* release lines(idle state) */
176 idle(); 184 idle();
177 185
178 /* wait start bit */ 186 /* wait start bit */
179 wait_clock_lo(25000); // command response may take 20 ms at most 187 wait_clock_lo(100); // TODO: this is enough?
180 data = recv_data(); 188 data = recv_data();
181 189
182 inhibit(); 190 inhibit();
183 return data; 191 return data;
184} 192}
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#else
193/* ring buffer to store ps/2 key data */ 194/* ring buffer to store ps/2 key data */
194#define PBUF_SIZE 32 195#define PBUF_SIZE 32
@@ -241,13 +242,6 @@ static inline void pbuf_clear(void)
241/* get data received by interrupt */ 242/* get data received by interrupt */
242uint8_t ps2_host_recv(void) 243uint8_t ps2_host_recv(void)
243{ 244{
244 if (ps2_error) {
245 print("x");
246 phex(ps2_error);
247 ps2_host_send(0xFE); // request to resend
248 ps2_error = PS2_ERR_NONE;
249 }
250 idle();
251 return pbuf_dequeue(); 245 return pbuf_dequeue();
252} 246}
253 247
@@ -450,3 +444,26 @@ static inline void inhibit(void)
450 clock_lo(); 444 clock_lo();
451 data_hi(); 445 data_hi();
452} 446}
447
448
449/* PS/2 Resources
450 *
451 * [1] The PS/2 Mouse/Keyboard Protocol
452 * http://www.computer-engineering.org/ps2protocol/
453 * Concise and thorough primer of PS/2 protocol.
454 *
455 * [2] Keyboard and Auxiliary Device Controller
456 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
457 * Signal Timing and Format
458 *
459 * [3] Keyboards(101- and 102-key)
460 * http://www.mcamafia.de/pdf/ibm_hitrc11.pdf
461 * Keyboard Layout, Scan Code Set, POR, and Commands.
462 *
463 * [4] PS/2 Reference Manuals
464 * http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
465 * Collection of IBM Personal System/2 documents.
466 *
467 * [5] TrackPoint Engineering Specifications for version 3E
468 * https://web.archive.org/web/20100526161812/http://wwwcssrv.almaden.ibm.com/trackpoint/download.html
469 */
diff --git a/protocol/ps2.h b/protocol/ps2.h
index 834165356..b780d01a2 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,44 @@ 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#define PS2_ERR_NONE 0
65#define PS2_ERR_PARITY 0x10 74#define PS2_ERR_STARTBIT1 1
75#define PS2_ERR_STARTBIT2 2
76#define PS2_ERR_STARTBIT3 3
77#define PS2_ERR_PARITY 0x10
66 78
67#define PS2_LED_SCROLL_LOCK 0 79#define PS2_LED_SCROLL_LOCK 0
68#define PS2_LED_NUM_LOCK 1 80#define PS2_LED_NUM_LOCK 1
@@ -71,13 +83,101 @@ POSSIBILITY OF SUCH DAMAGE.
71 83
72extern uint8_t ps2_error; 84extern uint8_t ps2_error;
73 85
74/* host role */
75void ps2_host_init(void); 86void ps2_host_init(void);
76uint8_t ps2_host_send(uint8_t data); 87uint8_t ps2_host_send(uint8_t data);
77uint8_t ps2_host_recv_response(void); 88uint8_t ps2_host_recv_response(void);
78uint8_t ps2_host_recv(void); 89uint8_t ps2_host_recv(void);
79void ps2_host_set_led(uint8_t usb_led); 90void ps2_host_set_led(uint8_t usb_led);
80 91
81/* device role */ 92
93/* Check port settings for clock and data line */
94#if !(defined(PS2_CLOCK_PORT) && \
95 defined(PS2_CLOCK_PIN) && \
96 defined(PS2_CLOCK_DDR) && \
97 defined(PS2_CLOCK_BIT))
98# error "PS/2 clock port setting is required in config.h"
99#endif
100
101#if !(defined(PS2_DATA_PORT) && \
102 defined(PS2_DATA_PIN) && \
103 defined(PS2_DATA_DDR) && \
104 defined(PS2_DATA_BIT))
105# error "PS/2 data port setting is required in config.h"
106#endif
107
108/*--------------------------------------------------------------------
109 * static functions
110 *------------------------------------------------------------------*/
111static inline void clock_lo(void)
112{
113 PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
114 PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
115}
116static inline void clock_hi(void)
117{
118 /* input with pull up */
119 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
120 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
121}
122static inline bool clock_in(void)
123{
124 PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
125 PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
126 _delay_us(1);
127 return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
128}
129static inline void data_lo(void)
130{
131 PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
132 PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
133}
134static inline void data_hi(void)
135{
136 /* input with pull up */
137 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
138 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
139}
140static inline bool data_in(void)
141{
142 PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
143 PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
144 _delay_us(1);
145 return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
146}
147
148static inline uint16_t wait_clock_lo(uint16_t us)
149{
150 while (clock_in() && us) { asm(""); _delay_us(1); us--; }
151 return us;
152}
153static inline uint16_t wait_clock_hi(uint16_t us)
154{
155 while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
156 return us;
157}
158static inline uint16_t wait_data_lo(uint16_t us)
159{
160 while (data_in() && us) { asm(""); _delay_us(1); us--; }
161 return us;
162}
163static inline uint16_t wait_data_hi(uint16_t us)
164{
165 while (!data_in() && us) { asm(""); _delay_us(1); us--; }
166 return us;
167}
168
169/* idle state that device can send */
170static inline void idle(void)
171{
172 clock_hi();
173 data_hi();
174}
175
176/* inhibit device to send */
177static inline void inhibit(void)
178{
179 clock_lo();
180 data_hi();
181}
82 182
83#endif 183#endif
diff --git a/protocol/ps2_busywait.c b/protocol/ps2_busywait.c
new file mode 100644
index 000000000..1e2925889
--- /dev/null
+++ b/protocol/ps2_busywait.c
@@ -0,0 +1,179 @@
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#include <stdbool.h>
39#include <util/delay.h>
40#include "ps2.h"
41#include "debug.h"
42
43
44/*
45 * PS/2 protocol busywait version
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
55uint8_t ps2_error = PS2_ERR_NONE;
56
57
58void ps2_host_init(void)
59{
60 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
61 _delay_ms(2500);
62
63 inhibit();
64}
65
66uint8_t ps2_host_send(uint8_t data)
67{
68 uint8_t res = 0;
69 bool parity = true;
70 ps2_error = PS2_ERR_NONE;
71 /* terminate a transmission if we have */
72 inhibit();
73 _delay_us(200); // at least 100us
74
75 /* start bit [1] */
76 data_lo();
77 clock_hi();
78 WAIT(clock_lo, 20000, 10); // may take 15ms at most until device starts clocking
79 /* data [2-9] */
80 for (uint8_t i = 0; i < 8; i++) {
81 _delay_us(15);
82 if (data&(1<<i)) {
83 parity = !parity;
84 data_hi();
85 } else {
86 data_lo();
87 }
88 WAIT(clock_hi, 50, 2);
89 WAIT(clock_lo, 50, 3);
90 }
91 /* parity [10] */
92 _delay_us(15);
93 if (parity) { data_hi(); } else { data_lo(); }
94 WAIT(clock_hi, 50, 4);
95 WAIT(clock_lo, 50, 5);
96 /* stop bit [11] */
97 _delay_us(15);
98 data_hi();
99 /* ack [12] */
100 WAIT(data_lo, 50, 6);
101 WAIT(clock_lo, 50, 7);
102
103 /* wait for idle state */
104 WAIT(clock_hi, 50, 8);
105 WAIT(data_hi, 50, 9);
106
107 res = ps2_host_recv_response();
108ERROR:
109 inhibit();
110 return res;
111}
112
113/* receive data when host want else inhibit communication */
114uint8_t ps2_host_recv_response(void)
115{
116 // TODO:
117 // Command might take 20ms to response([3]p.21)
118 // TrackPoint might take 25ms ([5]2.7)
119 uint8_t data = 0;
120 uint8_t try = 200;
121 while (try-- && (data = ps2_host_recv())) ;
122 return data;
123}
124
125/* send LED state to keyboard */
126void ps2_host_set_led(uint8_t led)
127{
128 ps2_host_send(0xED);
129 ps2_host_send(led);
130}
131
132
133/* called after start bit comes */
134uint8_t ps2_host_recv(void)
135{
136 uint8_t data = 0;
137 bool parity = true;
138 ps2_error = PS2_ERR_NONE;
139
140 /* release lines(idle state) */
141 idle();
142
143 /* start bit [1] */
144 WAIT(clock_lo, 100, 1); // TODO: this is enough?
145 WAIT(data_lo, 1, 2);
146 WAIT(clock_hi, 50, 3);
147
148 /* data [2-9] */
149 for (uint8_t i = 0; i < 8; i++) {
150 WAIT(clock_lo, 50, 4);
151 if (data_in()) {
152 parity = !parity;
153 data |= (1<<i);
154 }
155 WAIT(clock_hi, 50, 5);
156 }
157
158 /* parity [10] */
159 WAIT(clock_lo, 50, 6);
160 if (data_in() != parity) {
161 ps2_error = PS2_ERR_PARITY;
162 goto ERROR;
163 }
164 WAIT(clock_hi, 50, 7);
165
166 /* stop bit [11] */
167 WAIT(clock_lo, 50, 8);
168 WAIT(data_hi, 1, 9);
169 WAIT(clock_hi, 50, 10);
170
171 inhibit();
172 return data;
173ERROR:
174 if (ps2_error > PS2_ERR_STARTBIT3) {
175 printf("x%02X\n", ps2_error);
176 }
177 inhibit();
178 return 0;
179}