]>
Commit | Line | Data |
---|---|---|
0dde25e8 | 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 | ||
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 | 30 | static void matrix_make(uint8_t code); |
31 | static 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 | 58 | static 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 | 67 | static bool is_modified = false; |
bf1a37ba | 68 | |
69 | ||
bf1a37ba | 70 | void 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 | 144 | uint8_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 | 385 | inline |
386 | bool matrix_is_on(uint8_t row, uint8_t col) | |
387 | { | |
388 | return (matrix[row] & (1<<col)); | |
389 | } | |
390 | ||
391 | inline | |
bf1a37ba | 392 | uint8_t matrix_get_row(uint8_t row) |
bf1a37ba | 393 | { |
394 | return matrix[row]; | |
395 | } | |
396 | ||
bf1a37ba | 397 | uint8_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 | |
407 | inline | |
23c686ad | 408 | static 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 | ||
416 | inline | |
23c686ad | 417 | static 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 | 425 | void matrix_clear(void) |
10b2b1ae | 426 | { |
427 | for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; | |
428 | } |