]> git.gir.st - tmk_keyboard.git/blob - ps2_vusb/matrix.c
added protocol stack: pjrc, vusb
[tmk_keyboard.git] / ps2_vusb / 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 "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(without E0-prefix)
33 * f|_________|
34 * 10| |
35 * :| E0 XX | 80-FF for E0-prefix codes(use (XX|0x80) as code)
36 * 1f| |
37 * ---------
38 * exceptions:
39 * 83: F8[0x83](normal codes but > 0x7F)
40 * FC: PrintScreen[E0 7C or 84]
41 * FE: Puause
42 */
43 #define F8 (0x83)
44 #define PRINT_SCREEN (0xFC)
45 #define PAUSE (0xFE)
46 #define ROW(code) (code>>3)
47 #define COL(code) (code&0x07)
48
49 static bool is_modified = false;
50
51 // matrix state buffer(1:on, 0:off)
52 #if (MATRIX_COLS <= 8)
53 static uint8_t matrix[MATRIX_ROWS];
54 #else
55 static uint16_t matrix[MATRIX_ROWS];
56 #endif
57
58 #ifdef MATRIX_HAS_GHOST
59 static bool matrix_has_ghost_in_row(uint8_t row);
60 #endif
61 static void matrix_make(uint8_t code);
62 static void matrix_break(uint8_t code);
63
64
65 inline
66 uint8_t matrix_rows(void)
67 {
68 return MATRIX_ROWS;
69 }
70
71 inline
72 uint8_t matrix_cols(void)
73 {
74 return MATRIX_COLS;
75 }
76
77 void matrix_init(void)
78 {
79 ps2_host_init();
80
81 // initialize matrix state: all keys off
82 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
83
84 return;
85 }
86
87 /*
88 * PS/2 Scan Code Set 2: Exceptional Handling
89 *
90 * There are several keys to be handled exceptionally.
91 * The scan code for these keys are varied or prefix/postfix'd
92 * depending on modifier key state.
93 *
94 * References:
95 * http://www.microsoft.com/whdc/archive/scancode.mspx
96 * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
97 *
98 *
99 * Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left:
100 * Num Lock: off
101 * modifiers | make | break
102 * ----------+---------------------------+----------------------
103 * Ohter | <make> | <break>
104 * LShift | E0 F0 12 <make> | <break> E0 12
105 * RShift | E0 F0 59 <make> | <break> E0 59
106 * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
107 *
108 * Num Lock: on
109 * modifiers | make | break
110 * ----------+---------------------------+----------------------
111 * Other | E0 12 <make> | <break> E0 F0 12
112 * Shift'd | <make> | <break>
113 *
114 * Handling: ignore these prefix/postfix codes
115 *
116 *
117 * Keypad-/:
118 * modifiers | make | break
119 * ----------+---------------------------+----------------------
120 * Ohter | <make> | <break>
121 * LShift | E0 F0 12 <make> | <break> E0 12
122 * RShift | E0 F0 59 <make> | <break> E0 59
123 * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
124 *
125 * Handling: ignore these prefix/postfix codes
126 *
127 *
128 * PrintScreen:
129 * With hoding down modifiers, the scan code is sent as following:
130 *
131 * modifiers | make | break
132 * ----------+--------------+-----------------------------------
133 * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
134 * Shift'd | E0 7C | E0 F0 7C
135 * Control'd | E0 7C | E0 F0 7C
136 * Alt'd | 84 | F0 84
137 *
138 * Handling: ignore prefix/postfix codes and treat both scan code
139 * E0 7C and 84 as PrintScreen.
140 *
141 * Pause:
142 * With hoding down modifiers, the scan code is sent as following:
143 *
144 * modifiers | make(no break code)
145 * ----------+--------------------------------------------------
146 * no mods | E1 14 77 E1 F0 14 F0 77
147 * Control'd | E0 7E E0 F0 7E
148 *
149 * Handling: treat these two code sequence as Pause
150 *
151 */
152 uint8_t matrix_scan(void)
153 {
154
155 static enum {
156 INIT,
157 F0,
158 E0,
159 E0_F0,
160 // states for Pause/Break
161 E1,
162 E1_14,
163 E1_14_77,
164 E1_14_77_E1,
165 E1_14_77_E1_F0,
166 E1_14_77_E1_F0_14,
167 E1_14_77_E1_F0_14_F0,
168 } state = INIT;
169
170
171 is_modified = false;
172
173 // Pause/Break off(PS/2 has no break for this key)
174 if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
175 matrix_break(PAUSE);
176 }
177
178 uint8_t code;
179 while ((code = ps2_host_recv())) {
180 switch (state) {
181 case INIT:
182 switch (code) {
183 case 0xE0: // 2byte make
184 state = E0;
185 break;
186 case 0xF0: // break code
187 state = F0;
188 break;
189 case 0xE1: // Pause/Break
190 state = E1;
191 break;
192 case 0x83: // F8
193 matrix_make(F8);
194 state = INIT;
195 break;
196 case 0x84: // PrintScreen
197 matrix_make(PRINT_SCREEN);
198 state = INIT;
199 break;
200 default: // normal key make
201 if (code < 0x80) {
202 matrix_make(code);
203 } else {
204 debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n");
205 }
206 state = INIT;
207 }
208 break;
209 case E0:
210 switch (code) {
211 case 0x12: // postfix/postfix code for exceptional keys
212 case 0x59: // postfix/postfix code for exceptional keys
213 // ignore
214 state = INIT;
215 break;
216 case 0x7E: // former part of Control-Pause[E0 7E E0 F0 7E]
217 matrix_make(PAUSE);
218 state = INIT;
219 break;
220 case 0xF0: // E0 break
221 state = E0_F0;
222 break;
223 default: // E0 make
224 if (code < 0x80) {
225 matrix_make(code|0x80);
226 } else {
227 debug("unexpected scan code at E0: "); debug_hex(code); debug("\n");
228 }
229 state = INIT;
230 }
231 break;
232 case F0:
233 switch (code) {
234 case 0x83:
235 matrix_break(F8);
236 state = INIT;
237 break;
238 case 0x84:
239 matrix_break(PRINT_SCREEN);
240 state = INIT;
241 break;
242 default:
243 if (code < 0x80) {
244 matrix_break(code);
245 } else {
246 debug("unexpected scan code at F0: "); debug_hex(code); debug("\n");
247 }
248 state = INIT;
249 }
250 break;
251 case E0_F0: // E0 break
252 switch (code) {
253 case 0x12: // postfix/postfix code for exceptional keys
254 case 0x59: // postfix/postfix code for exceptional keys
255 case 0x7E: // latter part of Control-Pause[E0 7E E0 F0 7E]
256 // ignore
257 state = INIT;
258 break;
259 default:
260 if (code < 0x80) {
261 matrix_break(code|0x80);
262 } else {
263 debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n");
264 }
265 state = INIT;
266 }
267 break;
268 /* Pause */
269 case E1:
270 switch (code) {
271 case 0x14:
272 state = E1_14;
273 break;
274 default:
275 state = INIT;
276 }
277 break;
278 case E1_14:
279 switch (code) {
280 case 0x77:
281 state = E1_14_77;
282 break;
283 default:
284 state = INIT;
285 }
286 break;
287 case E1_14_77:
288 switch (code) {
289 case 0xE1:
290 state = E1_14_77_E1;
291 break;
292 default:
293 state = INIT;
294 }
295 break;
296 case E1_14_77_E1:
297 switch (code) {
298 case 0xF0:
299 state = E1_14_77_E1_F0;
300 break;
301 default:
302 state = INIT;
303 }
304 break;
305 case E1_14_77_E1_F0:
306 switch (code) {
307 case 0x14:
308 state = E1_14_77_E1_F0_14;
309 break;
310 default:
311 state = INIT;
312 }
313 break;
314 case E1_14_77_E1_F0_14:
315 switch (code) {
316 case 0xF0:
317 state = E1_14_77_E1_F0_14_F0;
318 break;
319 default:
320 state = INIT;
321 }
322 break;
323 case E1_14_77_E1_F0_14_F0:
324 switch (code) {
325 case 0x77:
326 matrix_make(PAUSE);
327 state = INIT;
328 break;
329 default:
330 state = INIT;
331 }
332 break;
333 default:
334 state = INIT;
335 }
336 }
337 return 1;
338 }
339
340 bool matrix_is_modified(void)
341 {
342 return is_modified;
343 }
344
345 inline
346 bool matrix_has_ghost(void)
347 {
348 #ifdef MATRIX_HAS_GHOST
349 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
350 if (matrix_has_ghost_in_row(i))
351 return true;
352 }
353 #endif
354 return false;
355 }
356
357 inline
358 bool matrix_is_on(uint8_t row, uint8_t col)
359 {
360 return (matrix[row] & (1<<col));
361 }
362
363 inline
364 #if (MATRIX_COLS <= 8)
365 uint8_t matrix_get_row(uint8_t row)
366 #else
367 uint16_t matrix_get_row(uint8_t row)
368 #endif
369 {
370 return matrix[row];
371 }
372
373 void matrix_print(void)
374 {
375 #if (MATRIX_COLS <= 8)
376 print("\nr/c 01234567\n");
377 #else
378 print("\nr/c 0123456789ABCDEF\n");
379 #endif
380 for (uint8_t row = 0; row < matrix_rows(); row++) {
381 phex(row); print(": ");
382 #if (MATRIX_COLS <= 8)
383 pbin_reverse(matrix_get_row(row));
384 #else
385 pbin_reverse16(matrix_get_row(row));
386 #endif
387 #ifdef MATRIX_HAS_GHOST
388 if (matrix_has_ghost_in_row(row)) {
389 print(" <ghost");
390 }
391 #endif
392 print("\n");
393 }
394 }
395
396 uint8_t matrix_key_count(void)
397 {
398 uint8_t count = 0;
399 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
400 #if (MATRIX_COLS <= 8)
401 count += bitpop(matrix[i]);
402 #else
403 count += bitpop16(matrix[i]);
404 #endif
405 }
406 return count;
407 }
408
409 #ifdef MATRIX_HAS_GHOST
410 inline
411 static bool matrix_has_ghost_in_row(uint8_t row)
412 {
413 // no ghost exists in case less than 2 keys on
414 if (((matrix[row] - 1) & matrix[row]) == 0)
415 return false;
416
417 // ghost exists in case same state as other row
418 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
419 if (i != row && (matrix[i] & matrix[row]) == matrix[row])
420 return true;
421 }
422 return false;
423 }
424 #endif
425
426
427 inline
428 static void matrix_make(uint8_t code)
429 {
430 if (!matrix_is_on(ROW(code), COL(code))) {
431 matrix[ROW(code)] |= 1<<COL(code);
432 is_modified = true;
433 //print("matrix_make: "); phex(code); print("\n");
434 }
435 }
436
437 inline
438 static void matrix_break(uint8_t code)
439 {
440 if (matrix_is_on(ROW(code), COL(code))) {
441 matrix[ROW(code)] &= ~(1<<COL(code));
442 is_modified = true;
443 //print("matrix_break: "); phex(code); print("\n");
444 }
445 }
Imprint / Impressum