]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - ps2_usb/matrix.c
PS/2 to USB keyboard converter
[max/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 }