diff options
-rw-r--r-- | docs/feature_ps2_mouse.md | 28 | ||||
-rw-r--r-- | tmk_core/protocol.mk | 4 | ||||
-rw-r--r-- | tmk_core/protocol/ps2_interrupt.c | 91 | ||||
-rw-r--r-- | tmk_core/protocol/ps2_io_chibios.c | 55 | ||||
-rw-r--r-- | tmk_core/protocol/ps2_mouse.c | 14 |
5 files changed, 172 insertions, 20 deletions
diff --git a/docs/feature_ps2_mouse.md b/docs/feature_ps2_mouse.md index 8e84e22d8..00c7ee72e 100644 --- a/docs/feature_ps2_mouse.md +++ b/docs/feature_ps2_mouse.md | |||
@@ -50,7 +50,7 @@ In your keyboard config.h: | |||
50 | #endif | 50 | #endif |
51 | ``` | 51 | ``` |
52 | 52 | ||
53 | ## Interrupt Version :id=interrupt-version | 53 | ### Interrupt Version (AVR/ATMega32u4) :id=interrupt-version-avr |
54 | 54 | ||
55 | The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data. | 55 | The following example uses D2 for clock and D5 for data. You can use any INT or PCINT pin for clock, and any pin for data. |
56 | 56 | ||
@@ -88,7 +88,31 @@ In your keyboard config.h: | |||
88 | #endif | 88 | #endif |
89 | ``` | 89 | ``` |
90 | 90 | ||
91 | ## USART Version :id=usart-version | 91 | ### Interrupt Version (ARM chibios) :id=interrupt-version-chibios |
92 | |||
93 | Pretty much any two pins can be used for the (software) interrupt variant on ARM cores. The example below uses A8 for clock, and A9 for data. | ||
94 | |||
95 | In rules.mk: | ||
96 | |||
97 | ``` | ||
98 | PS2_MOUSE_ENABLE = yes | ||
99 | PS2_USE_INT = yes | ||
100 | ``` | ||
101 | |||
102 | In your keyboard config.h: | ||
103 | |||
104 | ```c | ||
105 | #define PS2_CLOCK A8 | ||
106 | #define PS2_DATA A9 | ||
107 | ``` | ||
108 | |||
109 | And in the chibios specifig halconf.h: | ||
110 | ```c | ||
111 | #define PAL_USE_CALLBACKS TRUE | ||
112 | ``` | ||
113 | |||
114 | |||
115 | ### USART Version :id=usart-version | ||
92 | 116 | ||
93 | To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version. | 117 | To use USART on the ATMega32u4, you have to use PD5 for clock and PD2 for data. If one of those are unavailable, you need to use interrupt version. |
94 | 118 | ||
diff --git a/tmk_core/protocol.mk b/tmk_core/protocol.mk index cc87e8347..b61f2f546 100644 --- a/tmk_core/protocol.mk +++ b/tmk_core/protocol.mk | |||
@@ -14,13 +14,13 @@ endif | |||
14 | 14 | ||
15 | ifeq ($(strip $(PS2_USE_INT)), yes) | 15 | ifeq ($(strip $(PS2_USE_INT)), yes) |
16 | SRC += protocol/ps2_interrupt.c | 16 | SRC += protocol/ps2_interrupt.c |
17 | SRC += protocol/ps2_io_avr.c | 17 | SRC += protocol/ps2_io_$(PLATFORM_KEY).c |
18 | OPT_DEFS += -DPS2_USE_INT | 18 | OPT_DEFS += -DPS2_USE_INT |
19 | endif | 19 | endif |
20 | 20 | ||
21 | ifeq ($(strip $(PS2_USE_USART)), yes) | 21 | ifeq ($(strip $(PS2_USE_USART)), yes) |
22 | SRC += protocol/ps2_usart.c | 22 | SRC += protocol/ps2_usart.c |
23 | SRC += protocol/ps2_io_avr.c | 23 | SRC += protocol/ps2_io_$(PLATFORM_KEY).c |
24 | OPT_DEFS += -DPS2_USE_USART | 24 | OPT_DEFS += -DPS2_USE_USART |
25 | endif | 25 | endif |
26 | 26 | ||
diff --git a/tmk_core/protocol/ps2_interrupt.c b/tmk_core/protocol/ps2_interrupt.c index 5afc8a82e..780040d15 100644 --- a/tmk_core/protocol/ps2_interrupt.c +++ b/tmk_core/protocol/ps2_interrupt.c | |||
@@ -40,11 +40,19 @@ POSSIBILITY OF SUCH DAMAGE. | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include <stdbool.h> | 42 | #include <stdbool.h> |
43 | #include <avr/interrupt.h> | 43 | |
44 | #include <util/delay.h> | 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 | |||
45 | #include "ps2.h" | 52 | #include "ps2.h" |
46 | #include "ps2_io.h" | 53 | #include "ps2_io.h" |
47 | #include "print.h" | 54 | #include "print.h" |
55 | #include "wait.h" | ||
48 | 56 | ||
49 | #define WAIT(stat, us, err) \ | 57 | #define WAIT(stat, us, err) \ |
50 | do { \ | 58 | do { \ |
@@ -61,12 +69,30 @@ static inline void pbuf_enqueue(uint8_t data); | |||
61 | static inline bool pbuf_has_data(void); | 69 | static inline bool pbuf_has_data(void); |
62 | static inline void pbuf_clear(void); | 70 | static inline void pbuf_clear(void); |
63 | 71 | ||
72 | #if defined(PROTOCOL_CHIBIOS) | ||
73 | void ps2_interrupt_service_routine(void); | ||
74 | void palCallback(void *arg) { ps2_interrupt_service_routine(); } | ||
75 | |||
76 | # define PS2_INT_INIT() \ | ||
77 | { palSetLineMode(PS2_CLOCK, PAL_MODE_INPUT); } \ | ||
78 | while (0) | ||
79 | # define PS2_INT_ON() \ | ||
80 | { \ | ||
81 | palEnableLineEvent(PS2_CLOCK, PAL_EVENT_MODE_FALLING_EDGE); \ | ||
82 | palSetLineCallback(PS2_CLOCK, palCallback, NULL); \ | ||
83 | } \ | ||
84 | while (0) | ||
85 | # define PS2_INT_OFF() \ | ||
86 | { palDisableLineEvent(PS2_CLOCK); } \ | ||
87 | while (0) | ||
88 | #endif // PROTOCOL_CHIBIOS | ||
89 | |||
64 | void ps2_host_init(void) { | 90 | void ps2_host_init(void) { |
65 | idle(); | 91 | idle(); |
66 | PS2_INT_INIT(); | 92 | PS2_INT_INIT(); |
67 | PS2_INT_ON(); | 93 | PS2_INT_ON(); |
68 | // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) | 94 | // POR(150-2000ms) plus BAT(300-500ms) may take 2.5sec([3]p.20) |
69 | //_delay_ms(2500); | 95 | // wait_ms(2500); |
70 | } | 96 | } |
71 | 97 | ||
72 | uint8_t ps2_host_send(uint8_t data) { | 98 | uint8_t ps2_host_send(uint8_t data) { |
@@ -77,7 +103,7 @@ uint8_t ps2_host_send(uint8_t data) { | |||
77 | 103 | ||
78 | /* terminate a transmission if we have */ | 104 | /* terminate a transmission if we have */ |
79 | inhibit(); | 105 | inhibit(); |
80 | _delay_us(100); // 100us [4]p.13, [5]p.50 | 106 | wait_us(100); // 100us [4]p.13, [5]p.50 |
81 | 107 | ||
82 | /* 'Request to Send' and Start bit */ | 108 | /* 'Request to Send' and Start bit */ |
83 | data_lo(); | 109 | data_lo(); |
@@ -86,7 +112,6 @@ uint8_t ps2_host_send(uint8_t data) { | |||
86 | 112 | ||
87 | /* Data bit[2-9] */ | 113 | /* Data bit[2-9] */ |
88 | for (uint8_t i = 0; i < 8; i++) { | 114 | for (uint8_t i = 0; i < 8; i++) { |
89 | _delay_us(15); | ||
90 | if (data & (1 << i)) { | 115 | if (data & (1 << i)) { |
91 | parity = !parity; | 116 | parity = !parity; |
92 | data_hi(); | 117 | data_hi(); |
@@ -98,7 +123,7 @@ uint8_t ps2_host_send(uint8_t data) { | |||
98 | } | 123 | } |
99 | 124 | ||
100 | /* Parity bit */ | 125 | /* Parity bit */ |
101 | _delay_us(15); | 126 | wait_us(15); |
102 | if (parity) { | 127 | if (parity) { |
103 | data_hi(); | 128 | data_hi(); |
104 | } else { | 129 | } else { |
@@ -108,7 +133,7 @@ uint8_t ps2_host_send(uint8_t data) { | |||
108 | WAIT(clock_lo, 50, 5); | 133 | WAIT(clock_lo, 50, 5); |
109 | 134 | ||
110 | /* Stop bit */ | 135 | /* Stop bit */ |
111 | _delay_us(15); | 136 | wait_us(15); |
112 | data_hi(); | 137 | data_hi(); |
113 | 138 | ||
114 | /* Ack */ | 139 | /* Ack */ |
@@ -132,7 +157,7 @@ uint8_t ps2_host_recv_response(void) { | |||
132 | // Command may take 25ms/20ms at most([5]p.46, [3]p.21) | 157 | // Command may take 25ms/20ms at most([5]p.46, [3]p.21) |
133 | uint8_t retry = 25; | 158 | uint8_t retry = 25; |
134 | while (retry-- && !pbuf_has_data()) { | 159 | while (retry-- && !pbuf_has_data()) { |
135 | _delay_ms(1); | 160 | wait_ms(1); |
136 | } | 161 | } |
137 | return pbuf_dequeue(); | 162 | return pbuf_dequeue(); |
138 | } | 163 | } |
@@ -148,7 +173,7 @@ uint8_t ps2_host_recv(void) { | |||
148 | } | 173 | } |
149 | } | 174 | } |
150 | 175 | ||
151 | ISR(PS2_INT_VECT) { | 176 | void ps2_interrupt_service_routine(void) { |
152 | static enum { | 177 | static enum { |
153 | INIT, | 178 | INIT, |
154 | START, | 179 | START, |
@@ -218,6 +243,10 @@ RETURN: | |||
218 | return; | 243 | return; |
219 | } | 244 | } |
220 | 245 | ||
246 | #if defined(__AVR__) | ||
247 | ISR(PS2_INT_VECT) { ps2_interrupt_service_routine(); } | ||
248 | #endif | ||
249 | |||
221 | /* send LED state to keyboard */ | 250 | /* send LED state to keyboard */ |
222 | void ps2_host_set_led(uint8_t led) { | 251 | void ps2_host_set_led(uint8_t led) { |
223 | ps2_host_send(0xED); | 252 | ps2_host_send(0xED); |
@@ -232,8 +261,13 @@ static uint8_t pbuf[PBUF_SIZE]; | |||
232 | static uint8_t pbuf_head = 0; | 261 | static uint8_t pbuf_head = 0; |
233 | static uint8_t pbuf_tail = 0; | 262 | static uint8_t pbuf_tail = 0; |
234 | static inline void pbuf_enqueue(uint8_t data) { | 263 | static inline void pbuf_enqueue(uint8_t data) { |
264 | #if defined(__AVR__) | ||
235 | uint8_t sreg = SREG; | 265 | uint8_t sreg = SREG; |
236 | cli(); | 266 | cli(); |
267 | #elif defined(PROTOCOL_CHIBIOS) | ||
268 | chSysLockFromISR(); | ||
269 | #endif | ||
270 | |||
237 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; | 271 | uint8_t next = (pbuf_head + 1) % PBUF_SIZE; |
238 | if (next != pbuf_tail) { | 272 | if (next != pbuf_tail) { |
239 | pbuf[pbuf_head] = data; | 273 | pbuf[pbuf_head] = data; |
@@ -241,31 +275,66 @@ static inline void pbuf_enqueue(uint8_t data) { | |||
241 | } else { | 275 | } else { |
242 | print("pbuf: full\n"); | 276 | print("pbuf: full\n"); |
243 | } | 277 | } |
278 | |||
279 | #if defined(__AVR__) | ||
244 | SREG = sreg; | 280 | SREG = sreg; |
281 | #elif defined(PROTOCOL_CHIBIOS) | ||
282 | chSysUnlockFromISR(); | ||
283 | #endif | ||
245 | } | 284 | } |
246 | static inline uint8_t pbuf_dequeue(void) { | 285 | static inline uint8_t pbuf_dequeue(void) { |
247 | uint8_t val = 0; | 286 | uint8_t val = 0; |
248 | 287 | ||
288 | #if defined(__AVR__) | ||
249 | uint8_t sreg = SREG; | 289 | uint8_t sreg = SREG; |
250 | cli(); | 290 | cli(); |
291 | #elif defined(PROTOCOL_CHIBIOS) | ||
292 | chSysLock(); | ||
293 | #endif | ||
294 | |||
251 | if (pbuf_head != pbuf_tail) { | 295 | if (pbuf_head != pbuf_tail) { |
252 | val = pbuf[pbuf_tail]; | 296 | val = pbuf[pbuf_tail]; |
253 | pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; | 297 | pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE; |
254 | } | 298 | } |
299 | |||
300 | #if defined(__AVR__) | ||
255 | SREG = sreg; | 301 | SREG = sreg; |
302 | #elif defined(PROTOCOL_CHIBIOS) | ||
303 | chSysUnlock(); | ||
304 | #endif | ||
256 | 305 | ||
257 | return val; | 306 | return val; |
258 | } | 307 | } |
259 | static inline bool pbuf_has_data(void) { | 308 | static inline bool pbuf_has_data(void) { |
309 | #if defined(__AVR__) | ||
260 | uint8_t sreg = SREG; | 310 | uint8_t sreg = SREG; |
261 | cli(); | 311 | cli(); |
312 | #elif defined(PROTOCOL_CHIBIOS) | ||
313 | chSysLock(); | ||
314 | #endif | ||
315 | |||
262 | bool has_data = (pbuf_head != pbuf_tail); | 316 | bool has_data = (pbuf_head != pbuf_tail); |
263 | SREG = sreg; | 317 | |
318 | #if defined(__AVR__) | ||
319 | SREG = sreg; | ||
320 | #elif defined(PROTOCOL_CHIBIOS) | ||
321 | chSysUnlock(); | ||
322 | #endif | ||
264 | return has_data; | 323 | return has_data; |
265 | } | 324 | } |
266 | static inline void pbuf_clear(void) { | 325 | static inline void pbuf_clear(void) { |
326 | #if defined(__AVR__) | ||
267 | uint8_t sreg = SREG; | 327 | uint8_t sreg = SREG; |
268 | cli(); | 328 | cli(); |
329 | #elif defined(PROTOCOL_CHIBIOS) | ||
330 | chSysLock(); | ||
331 | #endif | ||
332 | |||
269 | pbuf_head = pbuf_tail = 0; | 333 | pbuf_head = pbuf_tail = 0; |
270 | SREG = sreg; | 334 | |
335 | #if defined(__AVR__) | ||
336 | SREG = sreg; | ||
337 | #elif defined(PROTOCOL_CHIBIOS) | ||
338 | chSysUnlock(); | ||
339 | #endif | ||
271 | } | 340 | } |
diff --git a/tmk_core/protocol/ps2_io_chibios.c b/tmk_core/protocol/ps2_io_chibios.c new file mode 100644 index 000000000..b672bd1f4 --- /dev/null +++ b/tmk_core/protocol/ps2_io_chibios.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)) | ||
10 | # error "PS/2 clock setting is required in config.h" | ||
11 | #endif | ||
12 | |||
13 | #if !(defined(PS2_DATA)) | ||
14 | # error "PS/2 data setting is required in config.h" | ||
15 | #endif | ||
16 | |||
17 | /* | ||
18 | * Clock | ||
19 | */ | ||
20 | void clock_init(void) {} | ||
21 | |||
22 | void clock_lo(void) { | ||
23 | palSetLineMode(PS2_CLOCK, PAL_MODE_OUTPUT_OPENDRAIN); | ||
24 | palWriteLine(PS2_CLOCK, PAL_LOW); | ||
25 | } | ||
26 | |||
27 | void clock_hi(void) { | ||
28 | palSetLineMode(PS2_CLOCK, PAL_MODE_OUTPUT_OPENDRAIN); | ||
29 | palWriteLine(PS2_CLOCK, PAL_HIGH); | ||
30 | } | ||
31 | |||
32 | bool clock_in(void) { | ||
33 | palSetLineMode(PS2_CLOCK, PAL_MODE_INPUT); | ||
34 | return palReadLine(PS2_CLOCK); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Data | ||
39 | */ | ||
40 | void data_init(void) {} | ||
41 | |||
42 | void data_lo(void) { | ||
43 | palSetLineMode(PS2_DATA, PAL_MODE_OUTPUT_OPENDRAIN); | ||
44 | palWriteLine(PS2_DATA, PAL_LOW); | ||
45 | } | ||
46 | |||
47 | void data_hi(void) { | ||
48 | palSetLineMode(PS2_DATA, PAL_MODE_OUTPUT_OPENDRAIN); | ||
49 | palWriteLine(PS2_DATA, PAL_HIGH); | ||
50 | } | ||
51 | |||
52 | bool data_in(void) { | ||
53 | palSetLineMode(PS2_DATA, PAL_MODE_INPUT); | ||
54 | return palReadLine(PS2_DATA); | ||
55 | } | ||
diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index 5415453a0..525aeb45a 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c | |||
@@ -16,9 +16,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <stdbool.h> | 18 | #include <stdbool.h> |
19 | #include <avr/io.h> | 19 | |
20 | #include <util/delay.h> | 20 | #if defined(__AVR__) |
21 | # include <avr/io.h> | ||
22 | #endif | ||
23 | |||
21 | #include "ps2_mouse.h" | 24 | #include "ps2_mouse.h" |
25 | #include "wait.h" | ||
22 | #include "host.h" | 26 | #include "host.h" |
23 | #include "timer.h" | 27 | #include "timer.h" |
24 | #include "print.h" | 28 | #include "print.h" |
@@ -42,7 +46,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report); | |||
42 | void ps2_mouse_init(void) { | 46 | void ps2_mouse_init(void) { |
43 | ps2_host_init(); | 47 | ps2_host_init(); |
44 | 48 | ||
45 | _delay_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up | 49 | wait_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up |
46 | 50 | ||
47 | PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); | 51 | PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); |
48 | 52 | ||
@@ -210,7 +214,7 @@ static inline void ps2_mouse_enable_scrolling(void) { | |||
210 | PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate"); | 214 | PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate"); |
211 | PS2_MOUSE_SEND(80, "80"); | 215 | PS2_MOUSE_SEND(80, "80"); |
212 | PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel"); | 216 | PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel"); |
213 | _delay_ms(20); | 217 | wait_ms(20); |
214 | } | 218 | } |
215 | 219 | ||
216 | #define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK) | 220 | #define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK) |
@@ -252,7 +256,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) { | |||
252 | if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { | 256 | if (scroll_state == SCROLL_BTN && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { |
253 | PRESS_SCROLL_BUTTONS; | 257 | PRESS_SCROLL_BUTTONS; |
254 | host_mouse_send(mouse_report); | 258 | host_mouse_send(mouse_report); |
255 | _delay_ms(100); | 259 | wait_ms(100); |
256 | RELEASE_SCROLL_BUTTONS; | 260 | RELEASE_SCROLL_BUTTONS; |
257 | } | 261 | } |
258 | #endif | 262 | #endif |