aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/protocol/ps2_interrupt.c
diff options
context:
space:
mode:
authorJoel Challis <git@zvecr.com>2021-10-20 21:18:49 +0100
committerGitHub <noreply@github.com>2021-10-20 21:18:49 +0100
commitd4be4b67a251ecc046d857c5cd00cfb37c394ab7 (patch)
tree15f6dd05ec293081782a9b42a30e1a81b33b6aa0 /tmk_core/protocol/ps2_interrupt.c
parent5500c428dd41348243e8a1695986b0da070e2ffa (diff)
downloadqmk_firmware-d4be4b67a251ecc046d857c5cd00cfb37c394ab7.tar.gz
qmk_firmware-d4be4b67a251ecc046d857c5cd00cfb37c394ab7.zip
Relocate PS2 code (#14895)
* Relocate ps2 protocol code * clang * Move makefile logic
Diffstat (limited to 'tmk_core/protocol/ps2_interrupt.c')
-rw-r--r--tmk_core/protocol/ps2_interrupt.c340
1 files changed, 0 insertions, 340 deletions
diff --git a/tmk_core/protocol/ps2_interrupt.c b/tmk_core/protocol/ps2_interrupt.c
deleted file mode 100644
index 70debd02f..000000000
--- a/tmk_core/protocol/ps2_interrupt.c
+++ /dev/null
@@ -1,340 +0,0 @@
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 Pin interrupt version
40 */
41
42#include <stdbool.h>
43
44#if defined(__AVR__)
45# include <avr/interrupt.h>
46#elif defined(PROTOCOL_CHIBIOS) // TODO: or STM32 ?
47// chibiOS headers
48# include "ch.h"
49# include "hal.h"
50#endif
51
52#include "ps2.h"
53#include "ps2_io.h"
54#include "print.h"
55#include "wait.h"
56
57#define WAIT(stat, us, err) \
58 do { \
59 if (!wait_##stat(us)) { \
60 ps2_error = err; \
61 goto ERROR; \
62 } \
63 } while (0)
64
65uint8_t ps2_error = PS2_ERR_NONE;
66
67static inline uint8_t pbuf_dequeue(void);
68static inline void pbuf_enqueue(uint8_t data);
69static inline bool pbuf_has_data(void);
70static inline void pbuf_clear(void);
71
72#if defined(PROTOCOL_CHIBIOS)
73void ps2_interrupt_service_routine(void);
74void palCallback(void *arg) { ps2_interrupt_service_routine(); }
75
76# define PS2_INT_INIT() \
77 { palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT); } \
78 while (0)
79# define PS2_INT_ON() \
80 { \
81 palEnableLineEvent(PS2_CLOCK_PIN, PAL_EVENT_MODE_FALLING_EDGE); \
82 palSetLineCallback(PS2_CLOCK_PIN, palCallback, NULL); \
83 } \
84 while (0)
85# define PS2_INT_OFF() \
86 { palDisableLineEvent(PS2_CLOCK_PIN); } \
87 while (0)
88#endif // PROTOCOL_CHIBIOS
89
90void ps2_host_init(void) {
91 idle();
92 PS2_INT_INIT();
93 PS2_INT_ON();
94 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
95 // wait_ms(2500);
96}
97
98uint8_t ps2_host_send(uint8_t data) {
99 bool parity = true;
100 ps2_error = PS2_ERR_NONE;
101
102 PS2_INT_OFF();
103
104 /* terminate a transmission if we have */
105 inhibit();
106 wait_us(100); // 100us [4]p.13, [5]p.50
107
108 /* 'Request to Send' and Start bit */
109 data_lo();
110 clock_hi();
111 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
112
113 /* Data bit[2-9] */
114 for (uint8_t i = 0; i < 8; i++) {
115 if (data & (1 << i)) {
116 parity = !parity;
117 data_hi();
118 } else {
119 data_lo();
120 }
121 WAIT(clock_hi, 50, 2);
122 WAIT(clock_lo, 50, 3);
123 }
124
125 /* Parity bit */
126 wait_us(15);
127 if (parity) {
128 data_hi();
129 } else {
130 data_lo();
131 }
132 WAIT(clock_hi, 50, 4);
133 WAIT(clock_lo, 50, 5);
134
135 /* Stop bit */
136 wait_us(15);
137 data_hi();
138
139 /* Ack */
140 WAIT(data_lo, 50, 6);
141 WAIT(clock_lo, 50, 7);
142
143 /* wait for idle state */
144 WAIT(clock_hi, 50, 8);
145 WAIT(data_hi, 50, 9);
146
147 idle();
148 PS2_INT_ON();
149 return ps2_host_recv_response();
150ERROR:
151 idle();
152 PS2_INT_ON();
153 return 0;
154}
155
156uint8_t ps2_host_recv_response(void) {
157 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
158 uint8_t retry = 25;
159 while (retry-- && !pbuf_has_data()) {
160 wait_ms(1);
161 }
162 return pbuf_dequeue();
163}
164
165/* get data received by interrupt */
166uint8_t ps2_host_recv(void) {
167 if (pbuf_has_data()) {
168 ps2_error = PS2_ERR_NONE;
169 return pbuf_dequeue();
170 } else {
171 ps2_error = PS2_ERR_NODATA;
172 return 0;
173 }
174}
175
176void ps2_interrupt_service_routine(void) {
177 static enum {
178 INIT,
179 START,
180 BIT0,
181 BIT1,
182 BIT2,
183 BIT3,
184 BIT4,
185 BIT5,
186 BIT6,
187 BIT7,
188 PARITY,
189 STOP,
190 } state = INIT;
191 static uint8_t data = 0;
192 static uint8_t parity = 1;
193
194 // TODO: abort if elapse 100us from previous interrupt
195
196 // return unless falling edge
197 if (clock_in()) {
198 goto RETURN;
199 }
200
201 state++;
202 switch (state) {
203 case START:
204 if (data_in()) goto ERROR;
205 break;
206 case BIT0:
207 case BIT1:
208 case BIT2:
209 case BIT3:
210 case BIT4:
211 case BIT5:
212 case BIT6:
213 case BIT7:
214 data >>= 1;
215 if (data_in()) {
216 data |= 0x80;
217 parity++;
218 }
219 break;
220 case PARITY:
221 if (data_in()) {
222 if (!(parity & 0x01)) goto ERROR;
223 } else {
224 if (parity & 0x01) goto ERROR;
225 }
226 break;
227 case STOP:
228 if (!data_in()) goto ERROR;
229 pbuf_enqueue(data);
230 goto DONE;
231 break;
232 default:
233 goto ERROR;
234 }
235 goto RETURN;
236ERROR:
237 ps2_error = state;
238DONE:
239 state = INIT;
240 data = 0;
241 parity = 1;
242RETURN:
243 return;
244}
245
246#if defined(__AVR__)
247ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); }
248#endif
249
250/* send LED state to keyboard */
251void ps2_host_set_led(uint8_t led) {
252 ps2_host_send(0xED);
253 ps2_host_send(led);
254}
255
256/*--------------------------------------------------------------------
257 * Ring buffer to store scan codes from keyboard
258 *------------------------------------------------------------------*/
259#define PBUF_SIZE 32
260static uint8_t pbuf[PBUF_SIZE];
261static uint8_t pbuf_head = 0;
262static uint8_t pbuf_tail = 0;
263static inline void pbuf_enqueue(uint8_t data) {
264#if defined(__AVR__)
265 uint8_t sreg = SREG;
266 cli();
267#elif defined(PROTOCOL_CHIBIOS)
268 chSysLockFromISR();
269#endif
270
271 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
272 if (next != pbuf_tail) {
273 pbuf[pbuf_head] = data;
274 pbuf_head = next;
275 } else {
276 print("pbuf: full\n");
277 }
278
279#if defined(__AVR__)
280 SREG = sreg;
281#elif defined(PROTOCOL_CHIBIOS)
282 chSysUnlockFromISR();
283#endif
284}
285static inline uint8_t pbuf_dequeue(void) {
286 uint8_t val = 0;
287
288#if defined(__AVR__)
289 uint8_t sreg = SREG;
290 cli();
291#elif defined(PROTOCOL_CHIBIOS)
292 chSysLock();
293#endif
294
295 if (pbuf_head != pbuf_tail) {
296 val = pbuf[pbuf_tail];
297 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
298 }
299
300#if defined(__AVR__)
301 SREG = sreg;
302#elif defined(PROTOCOL_CHIBIOS)
303 chSysUnlock();
304#endif
305
306 return val;
307}
308static inline bool pbuf_has_data(void) {
309#if defined(__AVR__)
310 uint8_t sreg = SREG;
311 cli();
312#elif defined(PROTOCOL_CHIBIOS)
313 chSysLock();
314#endif
315
316 bool has_data = (pbuf_head != pbuf_tail);
317
318#if defined(__AVR__)
319 SREG = sreg;
320#elif defined(PROTOCOL_CHIBIOS)
321 chSysUnlock();
322#endif
323 return has_data;
324}
325static inline void pbuf_clear(void) {
326#if defined(__AVR__)
327 uint8_t sreg = SREG;
328 cli();
329#elif defined(PROTOCOL_CHIBIOS)
330 chSysLock();
331#endif
332
333 pbuf_head = pbuf_tail = 0;
334
335#if defined(__AVR__)
336 SREG = sreg;
337#elif defined(PROTOCOL_CHIBIOS)
338 chSysUnlock();
339#endif
340}