Fix matrix_clear() for new matrix API
[tmk_keyboard.git] / converter / ps2_usb / matrix.c
CommitLineData
0dde25e8 1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
bf1a37ba 18#include <stdint.h>
19#include <stdbool.h>
9ae9742a 20#include "action.h"
bf1a37ba 21#include "print.h"
22#include "util.h"
23#include "debug.h"
24#include "ps2.h"
435a1d33 25#include "host.h"
26#include "led.h"
fb8d23c6 27#include "matrix.h"
bf1a37ba 28
29
3f9de373 30static void matrix_make(uint8_t code);
31static void matrix_break(uint8_t code);
bf1a37ba 32
33
34/*
3f9de373 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.
bf1a37ba 42 *
3f9de373 43 * 8bit wide
44 * +---------+
bf1a37ba 45 * 0| |
23c686ad 46 * :| XX | 00-7F for normal codes(without E0-prefix)
bf1a37ba 47 * f|_________|
48 * 10| |
3f9de373 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
bf1a37ba 57 */
3f9de373 58static uint8_t matrix[MATRIX_ROWS];
23c686ad 59#define ROW(code) (code>>3)
60#define COL(code) (code&0x07)
bf1a37ba 61
3f9de373 62// matrix positions for exceptional keys
63#define F7 (0x83)
64#define PRINT_SCREEN (0xFC)
65#define PAUSE (0xFE)
bf1a37ba 66
3f9de373 67static bool is_modified = false;
bf1a37ba 68
69
bf1a37ba 70void matrix_init(void)
71{
10b2b1ae 72 debug_enable = true;
bf1a37ba 73 ps2_host_init();
74
bf1a37ba 75 // initialize matrix state: all keys off
23c686ad 76 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
bf1a37ba 77
78 return;
79}
80
23c686ad 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 *
3f9de373 88 * Keyboard Scan Code Specification:
23c686ad 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 *
3f9de373 93 * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
94 * a) when Num Lock is off
23c686ad 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 *
3f9de373 102 * b) when Num Lock is on
23c686ad 103 * modifiers | make | break
104 * ----------+---------------------------+----------------------
105 * Other | E0 12 <make> | <break> E0 F0 12
106 * Shift'd | <make> | <break>
107 *
3f9de373 108 * Handling: These prefix/postfix codes are ignored.
23c686ad 109 *
110 *
3f9de373 111 * 2) Keypad /
23c686ad 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 *
3f9de373 119 * Handling: These prefix/postfix codes are ignored.
23c686ad 120 *
121 *
3f9de373 122 * 3) PrintScreen
23c686ad 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 *
3f9de373 130 * Handling: These prefix/postfix codes are ignored, and both scan codes
131 * 'E0 7C' and 84 are seen as PrintScreen.
23c686ad 132 *
3f9de373 133 * 4) Pause
23c686ad 134 * modifiers | make(no break code)
135 * ----------+--------------------------------------------------
3f9de373 136 * Other | E1 14 77 E1 F0 14 F0 77
23c686ad 137 * Control'd | E0 7E E0 F0 7E
138 *
3f9de373 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.
23c686ad 142 *
143 */
bf1a37ba 144uint8_t matrix_scan(void)
145{
146
3f9de373 147 // scan code reading states
bf1a37ba 148 static enum {
149 INIT,
23c686ad 150 F0,
bf1a37ba 151 E0,
152 E0_F0,
3f9de373 153 // Pause
bf1a37ba 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,
3f9de373 161 // Control'd Pause
162 E0_7E,
163 E0_7E_E0,
164 E0_7E_E0_F0,
bf1a37ba 165 } state = INIT;
166
167
23c686ad 168 is_modified = false;
bf1a37ba 169
3f9de373 170 // 'pseudo break code' hack
23c686ad 171 if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
172 matrix_break(PAUSE);
bf1a37ba 173 }
174
9ae9742a 175 uint8_t code = ps2_host_recv();
4c8e0fd0 176 if (code) xprintf("%i\r\n", code);
9ae9742a 177 if (!ps2_error) {
bf1a37ba 178 switch (state) {
179 case INIT:
180 switch (code) {
3f9de373 181 case 0xE0:
bf1a37ba 182 state = E0;
183 break;
3f9de373 184 case 0xF0:
23c686ad 185 state = F0;
bf1a37ba 186 break;
3f9de373 187 case 0xE1:
bf1a37ba 188 state = E1;
189 break;
3f9de373 190 case 0x83: // F7
191 matrix_make(F7);
23c686ad 192 state = INIT;
193 break;
3f9de373 194 case 0x84: // Alt'd PrintScreen
23c686ad 195 matrix_make(PRINT_SCREEN);
196 state = INIT;
197 break;
9ae9742a 198 case 0x00: // Overrun [3]p.25
10b2b1ae 199 matrix_clear();
9ae9742a 200 clear_keyboard();
10b2b1ae 201 print("Overrun\n");
9ae9742a 202 state = INIT;
203 break;
435a1d33 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;
bf1a37ba 210 default: // normal key make
211 if (code < 0x80) {
23c686ad 212 matrix_make(code);
bf1a37ba 213 } else {
10b2b1ae 214 matrix_clear();
9ae9742a 215 clear_keyboard();
10b2b1ae 216 xprintf("unexpected scan code at INIT: %02X\n", code);
bf1a37ba 217 }
218 state = INIT;
219 }
220 break;
3f9de373 221 case E0: // E0-Prefixed
bf1a37ba 222 switch (code) {
3f9de373 223 case 0x12: // to be ignored
224 case 0x59: // to be ignored
bf1a37ba 225 state = INIT;
226 break;
3f9de373 227 case 0x7E: // Control'd Pause
228 state = E0_7E;
23c686ad 229 break;
3f9de373 230 case 0xF0:
bf1a37ba 231 state = E0_F0;
232 break;
3f9de373 233 default:
bf1a37ba 234 if (code < 0x80) {
23c686ad 235 matrix_make(code|0x80);
bf1a37ba 236 } else {
10b2b1ae 237 matrix_clear();
9ae9742a 238 clear_keyboard();
10b2b1ae 239 xprintf("unexpected scan code at E0: %02X\n", code);
bf1a37ba 240 }
241 state = INIT;
242 }
243 break;
3f9de373 244 case F0: // Break code
bf1a37ba 245 switch (code) {
3f9de373 246 case 0x83: // F7
247 matrix_break(F7);
bf1a37ba 248 state = INIT;
249 break;
3f9de373 250 case 0x84: // Alt'd PrintScreen
23c686ad 251 matrix_break(PRINT_SCREEN);
bf1a37ba 252 state = INIT;
bf1a37ba 253 break;
10b2b1ae 254 case 0xF0:
255 matrix_clear();
256 clear_keyboard();
257 xprintf("unexpected scan code at F0: F0(clear and cont.)\n");
258 break;
bf1a37ba 259 default:
23c686ad 260 if (code < 0x80) {
261 matrix_break(code);
262 } else {
10b2b1ae 263 matrix_clear();
9ae9742a 264 clear_keyboard();
10b2b1ae 265 xprintf("unexpected scan code at F0: %02X\n", code);
23c686ad 266 }
267 state = INIT;
bf1a37ba 268 }
269 break;
3f9de373 270 case E0_F0: // Break code of E0-prefixed
bf1a37ba 271 switch (code) {
3f9de373 272 case 0x12: // to be ignored
273 case 0x59: // to be ignored
bf1a37ba 274 state = INIT;
275 break;
276 default:
23c686ad 277 if (code < 0x80) {
278 matrix_break(code|0x80);
279 } else {
10b2b1ae 280 matrix_clear();
9ae9742a 281 clear_keyboard();
10b2b1ae 282 xprintf("unexpected scan code at E0_F0: %02X\n", code);
23c686ad 283 }
bf1a37ba 284 state = INIT;
285 }
286 break;
3f9de373 287 // following are states of Pause
bf1a37ba 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:
23c686ad 345 matrix_make(PAUSE);
bf1a37ba 346 state = INIT;
347 break;
348 default:
349 state = INIT;
350 }
351 break;
3f9de373 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;
bf1a37ba 370 default:
371 state = INIT;
372 }
9ae9742a 373 }
374
10b2b1ae 375 // TODO: request RESEND when error occurs?
376/*
377 if (PS2_IS_FAILED(ps2_error)) {
9ae9742a 378 uint8_t ret = ps2_host_send(PS2_RESEND);
9d26053f 379 xprintf("Resend: %02X\n", ret);
bf1a37ba 380 }
10b2b1ae 381*/
bf1a37ba 382 return 1;
383}
384
bf1a37ba 385inline
386bool matrix_is_on(uint8_t row, uint8_t col)
387{
388 return (matrix[row] & (1<<col));
389}
390
391inline
bf1a37ba 392uint8_t matrix_get_row(uint8_t row)
bf1a37ba 393{
394 return matrix[row];
395}
396
bf1a37ba 397uint8_t matrix_key_count(void)
398{
399 uint8_t count = 0;
400 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
bf1a37ba 401 count += bitpop(matrix[i]);
bf1a37ba 402 }
403 return count;
404}
405
bf1a37ba 406
407inline
23c686ad 408static void matrix_make(uint8_t code)
bf1a37ba 409{
23c686ad 410 if (!matrix_is_on(ROW(code), COL(code))) {
411 matrix[ROW(code)] |= 1<<COL(code);
412 is_modified = true;
bf1a37ba 413 }
414}
415
416inline
23c686ad 417static void matrix_break(uint8_t code)
bf1a37ba 418{
23c686ad 419 if (matrix_is_on(ROW(code), COL(code))) {
420 matrix[ROW(code)] &= ~(1<<COL(code));
421 is_modified = true;
bf1a37ba 422 }
423}
10b2b1ae 424
124bafe9 425void matrix_clear(void)
10b2b1ae 426{
427 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
428}
Imprint / Impressum