/* * scan matrix */ #include #include #include #include #include "print.h" #include "util.h" #include "debug.h" #include "ps2.h" #include "matrix_skel.h" #if (MATRIX_COLS > 16) # error "MATRIX_COLS must not exceed 16" #endif #if (MATRIX_ROWS > 255) # error "MATRIX_ROWS must not exceed 255" #endif /* * Matrix usage: * "PS/2 Scan Codes Set 2" is assigned to 256(32x8)cells matrix. * Hmm, It is very sparse and not efficient :( * * 8bit * --------- * 0| | * :| XX | 00-7F for normal codes(without E0-prefix) * f|_________| * 10| | * :| E0 XX | 80-FF for E0-prefix codes(use (XX|0x80) as code) * 1f| | * --------- * exceptions: * 83: F8[0x83](normal codes but > 0x7F) * FC: PrintScreen[E0 7C or 84] * FE: Puause */ #define F8 (0x83) #define PRINT_SCREEN (0xFC) #define PAUSE (0xFE) #define ROW(code) (code>>3) #define COL(code) (code&0x07) static bool is_modified = false; // matrix state buffer(1:on, 0:off) #if (MATRIX_COLS <= 8) static uint8_t matrix[MATRIX_ROWS]; #else static uint16_t matrix[MATRIX_ROWS]; #endif #ifdef MATRIX_HAS_GHOST static bool matrix_has_ghost_in_row(uint8_t row); #endif static void matrix_make(uint8_t code); static void matrix_break(uint8_t code); inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } inline uint8_t matrix_cols(void) { return MATRIX_COLS; } void matrix_init(void) { ps2_host_init(); // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00; return; } /* * PS/2 Scan Code Set 2: Exceptional Handling * * There are several keys to be handled exceptionally. * The scan code for these keys are varied or prefix/postfix'd * depending on modifier key state. * * References: * http://www.microsoft.com/whdc/archive/scancode.mspx * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc * * * Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left: * Num Lock: off * modifiers | make | break * ----------+---------------------------+---------------------- * Ohter | | * LShift | E0 F0 12 | E0 12 * RShift | E0 F0 59 | E0 59 * L+RShift | E0 F0 12 E0 F0 59 | E0 59 E0 12 * * Num Lock: on * modifiers | make | break * ----------+---------------------------+---------------------- * Other | E0 12 | E0 F0 12 * Shift'd | | * * Handling: ignore these prefix/postfix codes * * * Keypad-/: * modifiers | make | break * ----------+---------------------------+---------------------- * Ohter | | * LShift | E0 F0 12 | E0 12 * RShift | E0 F0 59 | E0 59 * L+RShift | E0 F0 12 E0 F0 59 | E0 59 E0 12 * * Handling: ignore these prefix/postfix codes * * * PrintScreen: * With hoding down modifiers, the scan code is sent as following: * * modifiers | make | break * ----------+--------------+----------------------------------- * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12 * Shift'd | E0 7C | E0 F0 7C * Control'd | E0 7C | E0 F0 7C * Alt'd | 84 | F0 84 * * Handling: ignore prefix/postfix codes and treat both scan code * E0 7C and 84 as PrintScreen. * * Pause: * With hoding down modifiers, the scan code is sent as following: * * modifiers | make(no break code) * ----------+-------------------------------------------------- * no mods | E1 14 77 E1 F0 14 F0 77 * Control'd | E0 7E E0 F0 7E * * Handling: treat these two code sequence as Pause * */ uint8_t matrix_scan(void) { static enum { INIT, F0, E0, E0_F0, // states for Pause/Break E1, E1_14, E1_14_77, E1_14_77_E1, E1_14_77_E1_F0, E1_14_77_E1_F0_14, E1_14_77_E1_F0_14_F0, } state = INIT; is_modified = false; // Pause/Break off(PS/2 has no break for this key) if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) { matrix_break(PAUSE); } uint8_t code; while ((code = ps2_host_recv())) { switch (state) { case INIT: switch (code) { case 0xE0: // 2byte make state = E0; break; case 0xF0: // break code state = F0; break; case 0xE1: // Pause/Break state = E1; break; case 0x83: // F8 matrix_make(F8); state = INIT; break; case 0x84: // PrintScreen matrix_make(PRINT_SCREEN); state = INIT; break; default: // normal key make if (code < 0x80) { matrix_make(code); } else { debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n"); } state = INIT; } break; case E0: switch (code) { case 0x12: // postfix/postfix code for exceptional keys case 0x59: // postfix/postfix code for exceptional keys // ignore state = INIT; break; case 0x7E: // former part of Control-Pause[E0 7E E0 F0 7E] matrix_make(PAUSE); state = INIT; break; case 0xF0: // E0 break state = E0_F0; break; default: // E0 make if (code < 0x80) { matrix_make(code|0x80); } else { debug("unexpected scan code at E0: "); debug_hex(code); debug("\n"); } state = INIT; } break; case F0: switch (code) { case 0x83: matrix_break(F8); state = INIT; break; case 0x84: matrix_break(PRINT_SCREEN); state = INIT; break; default: if (code < 0x80) { matrix_break(code); } else { debug("unexpected scan code at F0: "); debug_hex(code); debug("\n"); } state = INIT; } break; case E0_F0: // E0 break switch (code) { case 0x12: // postfix/postfix code for exceptional keys case 0x59: // postfix/postfix code for exceptional keys case 0x7E: // latter part of Control-Pause[E0 7E E0 F0 7E] // ignore state = INIT; break; default: if (code < 0x80) { matrix_break(code|0x80); } else { debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n"); } state = INIT; } break; /* Pause */ case E1: switch (code) { case 0x14: state = E1_14; break; default: state = INIT; } break; case E1_14: switch (code) { case 0x77: state = E1_14_77; break; default: state = INIT; } break; case E1_14_77: switch (code) { case 0xE1: state = E1_14_77_E1; break; default: state = INIT; } break; case E1_14_77_E1: switch (code) { case 0xF0: state = E1_14_77_E1_F0; break; default: state = INIT; } break; case E1_14_77_E1_F0: switch (code) { case 0x14: state = E1_14_77_E1_F0_14; break; default: state = INIT; } break; case E1_14_77_E1_F0_14: switch (code) { case 0xF0: state = E1_14_77_E1_F0_14_F0; break; default: state = INIT; } break; case E1_14_77_E1_F0_14_F0: switch (code) { case 0x77: matrix_make(PAUSE); state = INIT; break; default: state = INIT; } break; default: state = INIT; } } return 1; } bool matrix_is_modified(void) { return is_modified; } inline bool matrix_has_ghost(void) { #ifdef MATRIX_HAS_GHOST for (uint8_t i = 0; i < MATRIX_ROWS; i++) { if (matrix_has_ghost_in_row(i)) return true; } #endif return false; } inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & (1<