aboutsummaryrefslogtreecommitdiff
path: root/platforms
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 /platforms
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 'platforms')
-rw-r--r--platforms/avr/drivers/ps2/ps2_io.c51
-rw-r--r--platforms/avr/drivers/ps2/ps2_usart.c227
-rw-r--r--platforms/chibios/drivers/ps2/ps2_io.c55
3 files changed, 333 insertions, 0 deletions
diff --git a/platforms/avr/drivers/ps2/ps2_io.c b/platforms/avr/drivers/ps2/ps2_io.c
new file mode 100644
index 000000000..7c826fbf1
--- /dev/null
+++ b/platforms/avr/drivers/ps2/ps2_io.c
@@ -0,0 +1,51 @@
1#include <stdbool.h>
2#include "ps2_io.h"
3#include "gpio.h"
4#include "wait.h"
5
6/* Check port settings for clock and data line */
7#if !(defined(PS2_CLOCK_PIN))
8# error "PS/2 clock setting is required in config.h"
9#endif
10
11#if !(defined(PS2_DATA_PIN))
12# error "PS/2 data setting is required in config.h"
13#endif
14
15/*
16 * Clock
17 */
18void clock_init(void) {}
19
20void clock_lo(void) {
21 // Transition from input with pull-up to output low via Hi-Z instead of output high
22 writePinLow(PS2_CLOCK_PIN);
23 setPinOutput(PS2_CLOCK_PIN);
24}
25
26void clock_hi(void) { setPinInputHigh(PS2_CLOCK_PIN); }
27
28bool clock_in(void) {
29 setPinInputHigh(PS2_CLOCK_PIN);
30 wait_us(1);
31 return readPin(PS2_CLOCK_PIN);
32}
33
34/*
35 * Data
36 */
37void data_init(void) {}
38
39void data_lo(void) {
40 // Transition from input with pull-up to output low via Hi-Z instead of output high
41 writePinLow(PS2_DATA_PIN);
42 setPinOutput(PS2_DATA_PIN);
43}
44
45void data_hi(void) { setPinInputHigh(PS2_DATA_PIN); }
46
47bool data_in(void) {
48 setPinInputHigh(PS2_DATA_PIN);
49 wait_us(1);
50 return readPin(PS2_DATA_PIN);
51}
diff --git a/platforms/avr/drivers/ps2/ps2_usart.c b/platforms/avr/drivers/ps2/ps2_usart.c
new file mode 100644
index 000000000..151cfcd68
--- /dev/null
+++ b/platforms/avr/drivers/ps2/ps2_usart.c
@@ -0,0 +1,227 @@
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 USART version
40 */
41
42#include <stdbool.h>
43#include <avr/interrupt.h>
44#include <util/delay.h>
45#include "gpio.h"
46#include "ps2.h"
47#include "ps2_io.h"
48#include "print.h"
49
50#ifndef PS2_CLOCK_DDR
51# define PS2_CLOCK_DDR PORTx_ADDRESS(PS2_CLOCK_PIN)
52#endif
53#ifndef PS2_CLOCK_BIT
54# define PS2_CLOCK_BIT (PS2_CLOCK_PIN & 0xF)
55#endif
56#ifndef PS2_DATA_DDR
57# define PS2_DATA_DDR PORTx_ADDRESS(PS2_DATA_PIN)
58#endif
59#ifndef PS2_DATA_BIT
60# define PS2_DATA_BIT (PS2_DATA_PIN & 0xF)
61#endif
62
63#define WAIT(stat, us, err) \
64 do { \
65 if (!wait_##stat(us)) { \
66 ps2_error = err; \
67 goto ERROR; \
68 } \
69 } while (0)
70
71uint8_t ps2_error = PS2_ERR_NONE;
72
73static inline uint8_t pbuf_dequeue(void);
74static inline void pbuf_enqueue(uint8_t data);
75static inline bool pbuf_has_data(void);
76static inline void pbuf_clear(void);
77
78void ps2_host_init(void) {
79 idle(); // without this many USART errors occur when cable is disconnected
80 PS2_USART_INIT();
81 PS2_USART_RX_INT_ON();
82 // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20)
83 //_delay_ms(2500);
84}
85
86uint8_t ps2_host_send(uint8_t data) {
87 bool parity = true;
88 ps2_error = PS2_ERR_NONE;
89
90 PS2_USART_OFF();
91
92 /* terminate a transmission if we have */
93 inhibit();
94 _delay_us(100); // [4]p.13
95
96 /* 'Request to Send' and Start bit */
97 data_lo();
98 clock_hi();
99 WAIT(clock_lo, 10000, 10); // 10ms [5]p.50
100
101 /* Data bit[2-9] */
102 for (uint8_t i = 0; i < 8; i++) {
103 _delay_us(15);
104 if (data & (1 << i)) {
105 parity = !parity;
106 data_hi();
107 } else {
108 data_lo();
109 }
110 WAIT(clock_hi, 50, 2);
111 WAIT(clock_lo, 50, 3);
112 }
113
114 /* Parity bit */
115 _delay_us(15);
116 if (parity) {
117 data_hi();
118 } else {
119 data_lo();
120 }
121 WAIT(clock_hi, 50, 4);
122 WAIT(clock_lo, 50, 5);
123
124 /* Stop bit */
125 _delay_us(15);
126 data_hi();
127
128 /* Ack */
129 WAIT(data_lo, 50, 6);
130 WAIT(clock_lo, 50, 7);
131
132 /* wait for idle state */
133 WAIT(clock_hi, 50, 8);
134 WAIT(data_hi, 50, 9);
135
136 idle();
137 PS2_USART_INIT();
138 PS2_USART_RX_INT_ON();
139 return ps2_host_recv_response();
140ERROR:
141 idle();
142 PS2_USART_INIT();
143 PS2_USART_RX_INT_ON();
144 return 0;
145}
146
147uint8_t ps2_host_recv_response(void) {
148 // Command may take 25ms/20ms at most([5]p.46, [3]p.21)
149 uint8_t retry = 25;
150 while (retry-- && !pbuf_has_data()) {
151 _delay_ms(1);
152 }
153 return pbuf_dequeue();
154}
155
156uint8_t ps2_host_recv(void) {
157 if (pbuf_has_data()) {
158 ps2_error = PS2_ERR_NONE;
159 return pbuf_dequeue();
160 } else {
161 ps2_error = PS2_ERR_NODATA;
162 return 0;
163 }
164}
165
166ISR(PS2_USART_RX_VECT) {
167 // TODO: request RESEND when error occurs?
168 uint8_t error = PS2_USART_ERROR; // USART error should be read before data
169 uint8_t data = PS2_USART_RX_DATA;
170 if (!error) {
171 pbuf_enqueue(data);
172 } else {
173 xprintf("PS2 USART error: %02X data: %02X\n", error, data);
174 }
175}
176
177/* send LED state to keyboard */
178void ps2_host_set_led(uint8_t led) {
179 ps2_host_send(0xED);
180 ps2_host_send(led);
181}
182
183/*--------------------------------------------------------------------
184 * Ring buffer to store scan codes from keyboard
185 *------------------------------------------------------------------*/
186#define PBUF_SIZE 32
187static uint8_t pbuf[PBUF_SIZE];
188static uint8_t pbuf_head = 0;
189static uint8_t pbuf_tail = 0;
190static inline void pbuf_enqueue(uint8_t data) {
191 uint8_t sreg = SREG;
192 cli();
193 uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
194 if (next != pbuf_tail) {
195 pbuf[pbuf_head] = data;
196 pbuf_head = next;
197 } else {
198 print("pbuf: full\n");
199 }
200 SREG = sreg;
201}
202static inline uint8_t pbuf_dequeue(void) {
203 uint8_t val = 0;
204
205 uint8_t sreg = SREG;
206 cli();
207 if (pbuf_head != pbuf_tail) {
208 val = pbuf[pbuf_tail];
209 pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
210 }
211 SREG = sreg;
212
213 return val;
214}
215static inline bool pbuf_has_data(void) {
216 uint8_t sreg = SREG;
217 cli();
218 bool has_data = (pbuf_head != pbuf_tail);
219 SREG = sreg;
220 return has_data;
221}
222static inline void pbuf_clear(void) {
223 uint8_t sreg = SREG;
224 cli();
225 pbuf_head = pbuf_tail = 0;
226 SREG = sreg;
227}
diff --git a/platforms/chibios/drivers/ps2/ps2_io.c b/platforms/chibios/drivers/ps2/ps2_io.c
new file mode 100644
index 000000000..906d85d84
--- /dev/null
+++ b/platforms/chibios/drivers/ps2/ps2_io.c
@@ -0,0 +1,55 @@
1#include <stdbool.h>
2#include "ps2_io.h"
3
4// chibiOS headers
5#include "ch.h"
6#include "hal.h"
7
8/* Check port settings for clock and data line */
9#if !(defined(PS2_CLOCK_PIN))
10# error "PS/2 clock setting is required in config.h"
11#endif
12
13#if !(defined(PS2_DATA_PIN))
14# error "PS/2 data setting is required in config.h"
15#endif
16
17/*
18 * Clock
19 */
20void clock_init(void) {}
21
22void clock_lo(void) {
23 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
24 palWriteLine(PS2_CLOCK_PIN, PAL_LOW);
25}
26
27void clock_hi(void) {
28 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
29 palWriteLine(PS2_CLOCK_PIN, PAL_HIGH);
30}
31
32bool clock_in(void) {
33 palSetLineMode(PS2_CLOCK_PIN, PAL_MODE_INPUT);
34 return palReadLine(PS2_CLOCK_PIN);
35}
36
37/*
38 * Data
39 */
40void data_init(void) {}
41
42void data_lo(void) {
43 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
44 palWriteLine(PS2_DATA_PIN, PAL_LOW);
45}
46
47void data_hi(void) {
48 palSetLineMode(PS2_DATA_PIN, PAL_MODE_OUTPUT_OPENDRAIN);
49 palWriteLine(PS2_DATA_PIN, PAL_HIGH);
50}
51
52bool data_in(void) {
53 palSetLineMode(PS2_DATA_PIN, PAL_MODE_INPUT);
54 return palReadLine(PS2_DATA_PIN);
55}