aboutsummaryrefslogtreecommitdiff
path: root/ps2_usb/matrix.c
diff options
context:
space:
mode:
authortmk <nobody@nowhere>2011-01-17 21:51:51 +0900
committertmk <nobody@nowhere>2011-01-23 04:10:35 +0900
commitbf1a37ba712b3c42861e7cfabb174724791b41b6 (patch)
treef6df1afe42e3421ae3646fb981727f2e5aa1c3e9 /ps2_usb/matrix.c
parent7ad93f7850cd3d20260628b10a8b123d97736e4e (diff)
downloadqmk_firmware-bf1a37ba712b3c42861e7cfabb174724791b41b6.tar.gz
qmk_firmware-bf1a37ba712b3c42861e7cfabb174724791b41b6.zip
PS/2 to USB keyboard converter
Diffstat (limited to 'ps2_usb/matrix.c')
-rw-r--r--ps2_usb/matrix.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/ps2_usb/matrix.c b/ps2_usb/matrix.c
new file mode 100644
index 000000000..366568d68
--- /dev/null
+++ b/ps2_usb/matrix.c
@@ -0,0 +1,456 @@
1/*
2 * scan matrix
3 */
4#include <stdint.h>
5#include <stdbool.h>
6#include <avr/io.h>
7#include <util/delay.h>
8#include "print.h"
9#include "util.h"
10#include "debug.h"
11#include "ps2.h"
12#include "usb_keyboard.h"
13#include "matrix_skel.h"
14
15
16#if (MATRIX_COLS > 16)
17# error "MATRIX_COLS must not exceed 16"
18#endif
19#if (MATRIX_ROWS > 255)
20# error "MATRIX_ROWS must not exceed 255"
21#endif
22
23
24/*
25 * Matrix usage:
26 * "PS/2 Scan Codes Set 2" is assigned to 256(32x8)cells matrix.
27 * Hmm, It is very sparse and not efficient :(
28 *
29 * 8bit
30 * ---------
31 * 0| |
32 * :| XX | 00-7F for normal codes
33 * f|_________|
34 * 10| |
35 * :| E0 XX | 80-FF for E0-prefix codes(use (XX|0x80) as code)
36 * 1f| |
37 * ---------
38 * exceptions:
39 * 0x83: F8(normal code placed beyond 0x7F)
40 * 0xFE: PrintScreen
41 * 0xFF: Puause/Break
42 */
43#define _PRINT_SCREEN (0xFE)
44#define _PAUSE_BREAK (0xFF)
45#define _ROW(code) (code>>3)
46#define _COL(code) (code&0x07)
47
48static bool _matrix_is_modified = false;
49
50// matrix state buffer(1:on, 0:off)
51#if (MATRIX_COLS <= 8)
52static uint8_t *matrix;
53static uint8_t _matrix0[MATRIX_ROWS];
54#else
55static uint16_t *matrix;
56static uint16_t _matrix0[MATRIX_ROWS];
57#endif
58
59#ifdef MATRIX_HAS_GHOST
60static bool matrix_has_ghost_in_row(uint8_t row);
61#endif
62static void _matrix_make(uint8_t code);
63static void _matrix_break(uint8_t code);
64static void _ps2_reset(void);
65static void _ps2_set_leds(uint8_t leds);
66
67
68inline
69uint8_t matrix_rows(void)
70{
71 return MATRIX_ROWS;
72}
73
74inline
75uint8_t matrix_cols(void)
76{
77 return MATRIX_COLS;
78}
79
80void matrix_init(void)
81{
82 print_enable = true;
83 ps2_host_init();
84
85 _ps2_reset();
86
87 // flush LEDs
88 _ps2_set_leds(1<<PS2_LED_NUM_LOCK);
89 _delay_ms(100);
90 _ps2_set_leds(1<<PS2_LED_NUM_LOCK|1<<PS2_LED_CAPS_LOCK);
91 _delay_ms(100);
92 _ps2_set_leds(1<<PS2_LED_NUM_LOCK|1<<PS2_LED_CAPS_LOCK|1<<PS2_LED_SCROLL_LOCK);
93 _delay_ms(300);
94 _ps2_set_leds(0x00);
95
96 // initialize matrix state: all keys off
97 for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
98 matrix = _matrix0;
99
100 return;
101}
102
103uint8_t matrix_scan(void)
104{
105
106 static enum {
107 INIT,
108 BREAK,
109 E0,
110 E0_F0,
111 // states for PrintScreen
112 E0_12,
113 E0_12_E0,
114 E0_F0_7C,
115 E0_F0_7C_E0,
116 E0_F0_7C_E0_F0,
117 // states for Pause/Break
118 E1,
119 E1_14,
120 E1_14_77,
121 E1_14_77_E1,
122 E1_14_77_E1_F0,
123 E1_14_77_E1_F0_14,
124 E1_14_77_E1_F0_14_F0,
125 } state = INIT;
126
127
128 _matrix_is_modified = false;
129
130 // Pause/Break off(PS/2 has no break for this key)
131 if (matrix_is_on(_ROW(_PAUSE_BREAK), _COL(_PAUSE_BREAK))) {
132 _matrix_break(_PAUSE_BREAK);
133 }
134
135 uint8_t code;
136 while ((code = ps2_host_recv())) {
137 switch (state) {
138 case INIT:
139 switch (code) {
140 case 0xE0: // 2byte make
141 state = E0;
142 break;
143 case 0xF0: // break code
144 state = BREAK;
145 break;
146 case 0xE1: // Pause/Break
147 state = E1;
148 break;
149 default: // normal key make
150 if (code < 0x80) {
151 _matrix_make(code);
152 } else {
153 debug("ps/2 unknow code: "); debug_hex(code); debug("\n");
154 }
155 state = INIT;
156 }
157 break;
158 case E0:
159 switch (code) {
160 case 0x12: // PrintScreen(make)
161 state = E0_12;
162 break;
163 case 0x7C: // PrintScreen(typematic)
164 // ignore
165 state = INIT;
166 break;
167 case 0xF0: // E0 break
168 state = E0_F0;
169 break;
170 default: // E0 make
171 if (code < 0x80) {
172 _matrix_make(code|0x80);
173 } else {
174 debug("ps/2 unknow code: "); debug_hex(code); debug("\n");
175 }
176 state = INIT;
177 }
178 break;
179 case BREAK:
180 if (code < 0x80) {
181 _matrix_break(code);
182 } else {
183 debug("ps/2 unknow code: "); debug_hex(code); debug("\n");
184 }
185 state = INIT;
186 break;
187 case E0_F0: // E0 break
188 switch (code) {
189 case 0x7C:
190 state = E0_F0_7C;
191 break;
192 default:
193 if (code < 0x80) {
194 _matrix_break(code|0x80);
195 } else {
196 debug("ps/2 unknow code: "); debug_hex(code); debug("\n");
197 }
198 state = INIT;
199 }
200 break;
201 /* PrintScreen(make) */
202 case E0_12:
203 switch (code) {
204 case 0xE0:
205 state = E0_12_E0;
206 break;
207 default:
208 state = INIT;
209 }
210 break;
211 case E0_12_E0:
212 switch (code) {
213 case 0x7C:
214 _matrix_make(_PRINT_SCREEN);
215 state = INIT;
216 break;
217 default:
218 state = INIT;
219 }
220 break;
221 /* PrintScreen(break) */
222 case E0_F0_7C:
223 switch (code) {
224 case 0xE0:
225 state = E0_F0_7C_E0;
226 break;
227 default:
228 state = INIT;
229 }
230 break;
231 case E0_F0_7C_E0:
232 switch (code) {
233 case 0xF0:
234 state = E0_F0_7C_E0_F0;
235 break;
236 default:
237 state = INIT;
238 }
239 break;
240 case E0_F0_7C_E0_F0:
241 switch (code) {
242 case 0x12:
243 _matrix_break(_PRINT_SCREEN);
244 state = INIT;
245 break;
246 default:
247 state = INIT;
248 }
249 break;
250 /* Pause/Break */
251 case E1:
252 switch (code) {
253 case 0x14:
254 state = E1_14;
255 break;
256 default:
257 state = INIT;
258 }
259 break;
260 case E1_14:
261 switch (code) {
262 case 0x77:
263 state = E1_14_77;
264 break;
265 default:
266 state = INIT;
267 }
268 break;
269 case E1_14_77:
270 switch (code) {
271 case 0xE1:
272 state = E1_14_77_E1;
273 break;
274 default:
275 state = INIT;
276 }
277 break;
278 case E1_14_77_E1:
279 switch (code) {
280 case 0xF0:
281 state = E1_14_77_E1_F0;
282 break;
283 default:
284 state = INIT;
285 }
286 break;
287 case E1_14_77_E1_F0:
288 switch (code) {
289 case 0x14:
290 state = E1_14_77_E1_F0_14;
291 break;
292 default:
293 state = INIT;
294 }
295 break;
296 case E1_14_77_E1_F0_14:
297 switch (code) {
298 case 0xF0:
299 state = E1_14_77_E1_F0_14_F0;
300 break;
301 default:
302 state = INIT;
303 }
304 break;
305 case E1_14_77_E1_F0_14_F0:
306 switch (code) {
307 case 0x77:
308 _matrix_make(_PAUSE_BREAK);
309 state = INIT;
310 break;
311 default:
312 state = INIT;
313 }
314 break;
315 default:
316 state = INIT;
317 }
318 }
319
320 static uint8_t prev_leds = 0;
321 if (prev_leds != usb_keyboard_leds) {
322 uint8_t leds = 0;
323 if (usb_keyboard_leds&(1<<USB_LED_SCROLL_LOCK))
324 leds |= (1<<PS2_LED_SCROLL_LOCK);
325 if (usb_keyboard_leds&(1<<USB_LED_NUM_LOCK))
326 leds |= (1<<PS2_LED_NUM_LOCK);
327 if (usb_keyboard_leds&(1<<USB_LED_CAPS_LOCK))
328 leds |= (1<<PS2_LED_CAPS_LOCK);
329
330 _ps2_set_leds(leds);
331 prev_leds = usb_keyboard_leds;
332 }
333
334 return 1;
335}
336
337bool matrix_is_modified(void)
338{
339 return _matrix_is_modified;
340}
341
342inline
343bool matrix_has_ghost(void)
344{
345#ifdef MATRIX_HAS_GHOST
346 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
347 if (matrix_has_ghost_in_row(i))
348 return true;
349 }
350#endif
351 return false;
352}
353
354inline
355bool matrix_is_on(uint8_t row, uint8_t col)
356{
357 return (matrix[row] & (1<<col));
358}
359
360inline
361#if (MATRIX_COLS <= 8)
362uint8_t matrix_get_row(uint8_t row)
363#else
364uint16_t matrix_get_row(uint8_t row)
365#endif
366{
367 return matrix[row];
368}
369
370void matrix_print(void)
371{
372#if (MATRIX_COLS <= 8)
373 print("\nr/c 01234567\n");
374#else
375 print("\nr/c 0123456789ABCDEF\n");
376#endif
377 for (uint8_t row = 0; row < matrix_rows(); row++) {
378 phex(row); print(": ");
379#if (MATRIX_COLS <= 8)
380 pbin_reverse(matrix_get_row(row));
381#else
382 pbin_reverse16(matrix_get_row(row));
383#endif
384#ifdef MATRIX_HAS_GHOST
385 if (matrix_has_ghost_in_row(row)) {
386 print(" <ghost");
387 }
388#endif
389 print("\n");
390 }
391}
392
393uint8_t matrix_key_count(void)
394{
395 uint8_t count = 0;
396 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
397#if (MATRIX_COLS <= 8)
398 count += bitpop(matrix[i]);
399#else
400 count += bitpop16(matrix[i]);
401#endif
402 }
403 return count;
404}
405
406#ifdef MATRIX_HAS_GHOST
407inline
408static bool matrix_has_ghost_in_row(uint8_t row)
409{
410 // no ghost exists in case less than 2 keys on
411 if (((matrix[row] - 1) & matrix[row]) == 0)
412 return false;
413
414 // ghost exists in case same state as other row
415 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
416 if (i != row && (matrix[i] & matrix[row]) == matrix[row])
417 return true;
418 }
419 return false;
420}
421#endif
422
423
424inline
425static void _matrix_make(uint8_t code)
426{
427 if (!matrix_is_on(_ROW(code), _COL(code))) {
428 matrix[_ROW(code)] |= 1<<_COL(code);
429 _matrix_is_modified = true;
430 }
431}
432
433inline
434static void _matrix_break(uint8_t code)
435{
436 if (matrix_is_on(_ROW(code), _COL(code))) {
437 matrix[_ROW(code)] &= ~(1<<_COL(code));
438 _matrix_is_modified = true;
439 }
440}
441
442static void _ps2_reset(void)
443{
444 ps2_host_send(0xFF);
445 ps2_host_recv(); // 0xFA
446 ps2_host_recv(); // 0xAA
447 _delay_ms(1000);
448}
449
450static void _ps2_set_leds(uint8_t leds)
451{
452 ps2_host_send(0xED);
453 ps2_host_recv(); // 0xFA
454 ps2_host_send(leds);
455 ps2_host_recv(); // 0xFA
456}