]> git.gir.st - tmk_keyboard.git/blob - ps2_usb/matrix.c
PS/2 to USB keyboard converter
[tmk_keyboard.git] / ps2_usb / matrix.c
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
48 static bool _matrix_is_modified = false;
49
50 // matrix state buffer(1:on, 0:off)
51 #if (MATRIX_COLS <= 8)
52 static uint8_t *matrix;
53 static uint8_t _matrix0[MATRIX_ROWS];
54 #else
55 static uint16_t *matrix;
56 static uint16_t _matrix0[MATRIX_ROWS];
57 #endif
58
59 #ifdef MATRIX_HAS_GHOST
60 static bool matrix_has_ghost_in_row(uint8_t row);
61 #endif
62 static void _matrix_make(uint8_t code);
63 static void _matrix_break(uint8_t code);
64 static void _ps2_reset(void);
65 static void _ps2_set_leds(uint8_t leds);
66
67
68 inline
69 uint8_t matrix_rows(void)
70 {
71 return MATRIX_ROWS;
72 }
73
74 inline
75 uint8_t matrix_cols(void)
76 {
77 return MATRIX_COLS;
78 }
79
80 void 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
103 uint8_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
337 bool matrix_is_modified(void)
338 {
339 return _matrix_is_modified;
340 }
341
342 inline
343 bool 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
354 inline
355 bool matrix_is_on(uint8_t row, uint8_t col)
356 {
357 return (matrix[row] & (1<<col));
358 }
359
360 inline
361 #if (MATRIX_COLS <= 8)
362 uint8_t matrix_get_row(uint8_t row)
363 #else
364 uint16_t matrix_get_row(uint8_t row)
365 #endif
366 {
367 return matrix[row];
368 }
369
370 void 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
393 uint8_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
407 inline
408 static 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
424 inline
425 static 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
433 inline
434 static 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
442 static 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
450 static 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 }
Imprint / Impressum