]>
Commit | Line | Data |
---|---|---|
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 | } |