Fix matrix_clear() for new matrix API
[tmk_keyboard.git] / converter / ps2_usb / matrix.c
1 /*
2 Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include "action.h"
21 #include "print.h"
22 #include "util.h"
23 #include "debug.h"
24 #include "ps2.h"
25 #include "host.h"
26 #include "led.h"
27 #include "matrix.h"
28
29
30 static void matrix_make(uint8_t code);
31 static void matrix_break(uint8_t code);
32
33
34 /*
35 * Matrix Array usage:
36 * 'Scan Code Set 2' is assigned into 256(32x8)cell matrix.
37 * Hmm, it is very sparse and not efficient :(
38 *
39 * Notes:
40 * Both 'Hanguel/English'(F1) and 'Hanja'(F2) collide with 'Delete'(E0 71) and 'Down'(E0 72).
41 * These two Korean keys need exceptional handling and are not supported for now. Sorry.
42 *
43 * 8bit wide
44 * +---------+
45 * 0| |
46 * :| XX | 00-7F for normal codes(without E0-prefix)
47 * f|_________|
48 * 10| |
49 * :| E0 YY | 80-FF for E0-prefixed codes
50 * 1f| | (<YY>|0x80) is used as matrix position.
51 * +---------+
52 *
53 * Exceptions:
54 * 0x83: F7(0x83) This is a normal code but beyond 0x7F.
55 * 0xFC: PrintScreen
56 * 0xFE: Pause
57 */
58 static uint8_t matrix[MATRIX_ROWS];
59 #define ROW(code) (code>>3)
60 #define COL(code) (code&0x07)
61
62 // matrix positions for exceptional keys
63 #define F7 (0x83)
64 #define PRINT_SCREEN (0xFC)
65 #define PAUSE (0xFE)
66
67 static bool is_modified = false;
68
69
70 void matrix_init(void)
71 {
72 debug_enable = true;
73 ps2_host_init();
74
75 // initialize matrix state: all keys off
76 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
77
78 return;
79 }
80
81 /*
82 * PS/2 Scan Code Set 2: Exceptional Handling
83 *
84 * There are several keys to be handled exceptionally.
85 * The scan code for these keys are varied or prefix/postfix'd
86 * depending on modifier key state.
87 *
88 * Keyboard Scan Code Specification:
89 * http://www.microsoft.com/whdc/archive/scancode.mspx
90 * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
91 *
92 *
93 * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
94 * a) when Num Lock is off
95 * modifiers | make | break
96 * ----------+---------------------------+----------------------
97 * Ohter | <make> | <break>
98 * LShift | E0 F0 12 <make> | <break> E0 12
99 * RShift | E0 F0 59 <make> | <break> E0 59
100 * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
101 *
102 * b) when Num Lock is on
103 * modifiers | make | break
104 * ----------+---------------------------+----------------------
105 * Other | E0 12 <make> | <break> E0 F0 12
106 * Shift'd | <make> | <break>
107 *
108 * Handling: These prefix/postfix codes are ignored.
109 *
110 *
111 * 2) Keypad /
112 * modifiers | make | break
113 * ----------+---------------------------+----------------------
114 * Ohter | <make> | <break>
115 * LShift | E0 F0 12 <make> | <break> E0 12
116 * RShift | E0 F0 59 <make> | <break> E0 59
117 * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
118 *
119 * Handling: These prefix/postfix codes are ignored.
120 *
121 *
122 * 3) PrintScreen
123 * modifiers | make | break
124 * ----------+--------------+-----------------------------------
125 * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
126 * Shift'd | E0 7C | E0 F0 7C
127 * Control'd | E0 7C | E0 F0 7C
128 * Alt'd | 84 | F0 84
129 *
130 * Handling: These prefix/postfix codes are ignored, and both scan codes
131 * 'E0 7C' and 84 are seen as PrintScreen.
132 *
133 * 4) Pause
134 * modifiers | make(no break code)
135 * ----------+--------------------------------------------------
136 * Other | E1 14 77 E1 F0 14 F0 77
137 * Control'd | E0 7E E0 F0 7E
138 *
139 * Handling: Both code sequences are treated as a whole.
140 * And we need a ad hoc 'pseudo break code' hack to get the key off
141 * because it has no break code.
142 *
143 */
144 uint8_t matrix_scan(void)
145 {
146
147 // scan code reading states
148 static enum {
149 INIT,
150 F0,
151 E0,
152 E0_F0,
153 // Pause
154 E1,
155 E1_14,
156 E1_14_77,
157 E1_14_77_E1,
158 E1_14_77_E1_F0,
159 E1_14_77_E1_F0_14,
160 E1_14_77_E1_F0_14_F0,
161 // Control'd Pause
162 E0_7E,
163 E0_7E_E0,
164 E0_7E_E0_F0,
165 } state = INIT;
166
167
168 is_modified = false;
169
170 // 'pseudo break code' hack
171 if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
172 matrix_break(PAUSE);
173 }
174
175 uint8_t code = ps2_host_recv();
176 if (code) xprintf("%i\r\n", code);
177 if (!ps2_error) {
178 switch (state) {
179 case INIT:
180 switch (code) {
181 case 0xE0:
182 state = E0;
183 break;
184 case 0xF0:
185 state = F0;
186 break;
187 case 0xE1:
188 state = E1;
189 break;
190 case 0x83: // F7
191 matrix_make(F7);
192 state = INIT;
193 break;
194 case 0x84: // Alt'd PrintScreen
195 matrix_make(PRINT_SCREEN);
196 state = INIT;
197 break;
198 case 0x00: // Overrun [3]p.25
199 matrix_clear();
200 clear_keyboard();
201 print("Overrun\n");
202 state = INIT;
203 break;
204 case 0xAA: // Self-test passed
205 case 0xFC: // Self-test failed
206 printf("BAT %s\n", (code == 0xAA) ? "OK" : "NG");
207 led_set(host_keyboard_leds());
208 state = INIT;
209 break;
210 default: // normal key make
211 if (code < 0x80) {
212 matrix_make(code);
213 } else {
214 matrix_clear();
215 clear_keyboard();
216 xprintf("unexpected scan code at INIT: %02X\n", code);
217 }
218 state = INIT;
219 }
220 break;
221 case E0: // E0-Prefixed
222 switch (code) {
223 case 0x12: // to be ignored
224 case 0x59: // to be ignored
225 state = INIT;
226 break;
227 case 0x7E: // Control'd Pause
228 state = E0_7E;
229 break;
230 case 0xF0:
231 state = E0_F0;
232 break;
233 default:
234 if (code < 0x80) {
235 matrix_make(code|0x80);
236 } else {
237 matrix_clear();
238 clear_keyboard();
239 xprintf("unexpected scan code at E0: %02X\n", code);
240 }
241 state = INIT;
242 }
243 break;
244 case F0: // Break code
245 switch (code) {
246 case 0x83: // F7
247 matrix_break(F7);
248 state = INIT;
249 break;
250 case 0x84: // Alt'd PrintScreen
251 matrix_break(PRINT_SCREEN);
252 state = INIT;
253 break;
254 case 0xF0:
255 matrix_clear();
256 clear_keyboard();
257 xprintf("unexpected scan code at F0: F0(clear and cont.)\n");
258 break;
259 default:
260 if (code < 0x80) {
261 matrix_break(code);
262 } else {
263 matrix_clear();
264 clear_keyboard();
265 xprintf("unexpected scan code at F0: %02X\n", code);
266 }
267 state = INIT;
268 }
269 break;
270 case E0_F0: // Break code of E0-prefixed
271 switch (code) {
272 case 0x12: // to be ignored
273 case 0x59: // to be ignored
274 state = INIT;
275 break;
276 default:
277 if (code < 0x80) {
278 matrix_break(code|0x80);
279 } else {
280 matrix_clear();
281 clear_keyboard();
282 xprintf("unexpected scan code at E0_F0: %02X\n", code);
283 }
284 state = INIT;
285 }
286 break;
287 // following are states of Pause
288 case E1:
289 switch (code) {
290 case 0x14:
291 state = E1_14;
292 break;
293 default:
294 state = INIT;
295 }
296 break;
297 case E1_14:
298 switch (code) {
299 case 0x77:
300 state = E1_14_77;
301 break;
302 default:
303 state = INIT;
304 }
305 break;
306 case E1_14_77:
307 switch (code) {
308 case 0xE1:
309 state = E1_14_77_E1;
310 break;
311 default:
312 state = INIT;
313 }
314 break;
315 case E1_14_77_E1:
316 switch (code) {
317 case 0xF0:
318 state = E1_14_77_E1_F0;
319 break;
320 default:
321 state = INIT;
322 }
323 break;
324 case E1_14_77_E1_F0:
325 switch (code) {
326 case 0x14:
327 state = E1_14_77_E1_F0_14;
328 break;
329 default:
330 state = INIT;
331 }
332 break;
333 case E1_14_77_E1_F0_14:
334 switch (code) {
335 case 0xF0:
336 state = E1_14_77_E1_F0_14_F0;
337 break;
338 default:
339 state = INIT;
340 }
341 break;
342 case E1_14_77_E1_F0_14_F0:
343 switch (code) {
344 case 0x77:
345 matrix_make(PAUSE);
346 state = INIT;
347 break;
348 default:
349 state = INIT;
350 }
351 break;
352 // Following are states of Control'd Pause
353 case E0_7E:
354 if (code == 0xE0)
355 state = E0_7E_E0;
356 else
357 state = INIT;
358 break;
359 case E0_7E_E0:
360 if (code == 0xF0)
361 state = E0_7E_E0_F0;
362 else
363 state = INIT;
364 break;
365 case E0_7E_E0_F0:
366 if (code == 0x7E)
367 matrix_make(PAUSE);
368 state = INIT;
369 break;
370 default:
371 state = INIT;
372 }
373 }
374
375 // TODO: request RESEND when error occurs?
376 /*
377 if (PS2_IS_FAILED(ps2_error)) {
378 uint8_t ret = ps2_host_send(PS2_RESEND);
379 xprintf("Resend: %02X\n", ret);
380 }
381 */
382 return 1;
383 }
384
385 inline
386 bool matrix_is_on(uint8_t row, uint8_t col)
387 {
388 return (matrix[row] & (1<<col));
389 }
390
391 inline
392 uint8_t matrix_get_row(uint8_t row)
393 {
394 return matrix[row];
395 }
396
397 uint8_t matrix_key_count(void)
398 {
399 uint8_t count = 0;
400 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
401 count += bitpop(matrix[i]);
402 }
403 return count;
404 }
405
406
407 inline
408 static void matrix_make(uint8_t code)
409 {
410 if (!matrix_is_on(ROW(code), COL(code))) {
411 matrix[ROW(code)] |= 1<<COL(code);
412 is_modified = true;
413 }
414 }
415
416 inline
417 static void matrix_break(uint8_t code)
418 {
419 if (matrix_is_on(ROW(code), COL(code))) {
420 matrix[ROW(code)] &= ~(1<<COL(code));
421 is_modified = true;
422 }
423 }
424
425 void matrix_clear(void)
426 {
427 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
428 }
Imprint / Impressum