You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

matrix.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. Copyright 2011 Jun Wako <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdint.h>
  15. #include <stdbool.h>
  16. #include <avr/io.h>
  17. #include <util/delay.h>
  18. #include "action.h"
  19. #include "print.h"
  20. #include "util.h"
  21. #include "debug.h"
  22. #include "ps2.h"
  23. #include "matrix.h"
  24. static void matrix_make(uint8_t code);
  25. static void matrix_break(uint8_t code);
  26. #ifdef MATRIX_HAS_GHOST
  27. static bool matrix_has_ghost_in_row(uint8_t row);
  28. #endif
  29. /*
  30. * Matrix Array usage:
  31. * 'Scan Code Set 2' is assigned into 256(32x8)cell matrix.
  32. * Hmm, it is very sparse and not efficient :(
  33. *
  34. * Notes:
  35. * Both 'Hanguel/English'(F1) and 'Hanja'(F2) collide with 'Delete'(E0 71) and 'Down'(E0 72).
  36. * These two Korean keys need exceptional handling and are not supported for now. Sorry.
  37. *
  38. * 8bit wide
  39. * +---------+
  40. * 0| |
  41. * :| XX | 00-7F for normal codes(without E0-prefix)
  42. * f|_________|
  43. * 10| |
  44. * :| E0 YY | 80-FF for E0-prefixed codes
  45. * 1f| | (<YY>|0x80) is used as matrix position.
  46. * +---------+
  47. *
  48. * Exceptions:
  49. * 0x83: F7(0x83) This is a normal code but beyond 0x7F.
  50. * 0xFC: PrintScreen
  51. * 0xFE: Pause
  52. */
  53. static uint8_t matrix[MATRIX_ROWS];
  54. #define ROW(code) (code>>3)
  55. #define COL(code) (code&0x07)
  56. // matrix positions for exceptional keys
  57. #define F7 (0x83)
  58. #define PRINT_SCREEN (0xFC)
  59. #define PAUSE (0xFE)
  60. static bool is_modified = false;
  61. inline
  62. uint8_t matrix_rows(void)
  63. {
  64. return MATRIX_ROWS;
  65. }
  66. inline
  67. uint8_t matrix_cols(void)
  68. {
  69. return MATRIX_COLS;
  70. }
  71. void matrix_init(void)
  72. {
  73. ps2_host_init();
  74. // initialize matrix state: all keys off
  75. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  76. return;
  77. }
  78. /*
  79. * PS/2 Scan Code Set 2: Exceptional Handling
  80. *
  81. * There are several keys to be handled exceptionally.
  82. * The scan code for these keys are varied or prefix/postfix'd
  83. * depending on modifier key state.
  84. *
  85. * Keyboard Scan Code Specification:
  86. * http://www.microsoft.com/whdc/archive/scancode.mspx
  87. * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
  88. *
  89. *
  90. * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
  91. * a) when Num Lock is off
  92. * modifiers | make | break
  93. * ----------+---------------------------+----------------------
  94. * Ohter | <make> | <break>
  95. * LShift | E0 F0 12 <make> | <break> E0 12
  96. * RShift | E0 F0 59 <make> | <break> E0 59
  97. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  98. *
  99. * b) when Num Lock is on
  100. * modifiers | make | break
  101. * ----------+---------------------------+----------------------
  102. * Other | E0 12 <make> | <break> E0 F0 12
  103. * Shift'd | <make> | <break>
  104. *
  105. * Handling: These prefix/postfix codes are ignored.
  106. *
  107. *
  108. * 2) Keypad /
  109. * modifiers | make | break
  110. * ----------+---------------------------+----------------------
  111. * Ohter | <make> | <break>
  112. * LShift | E0 F0 12 <make> | <break> E0 12
  113. * RShift | E0 F0 59 <make> | <break> E0 59
  114. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  115. *
  116. * Handling: These prefix/postfix codes are ignored.
  117. *
  118. *
  119. * 3) PrintScreen
  120. * modifiers | make | break
  121. * ----------+--------------+-----------------------------------
  122. * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
  123. * Shift'd | E0 7C | E0 F0 7C
  124. * Control'd | E0 7C | E0 F0 7C
  125. * Alt'd | 84 | F0 84
  126. *
  127. * Handling: These prefix/postfix codes are ignored, and both scan codes
  128. * 'E0 7C' and 84 are seen as PrintScreen.
  129. *
  130. * 4) Pause
  131. * modifiers | make(no break code)
  132. * ----------+--------------------------------------------------
  133. * Other | E1 14 77 E1 F0 14 F0 77
  134. * Control'd | E0 7E E0 F0 7E
  135. *
  136. * Handling: Both code sequences are treated as a whole.
  137. * And we need a ad hoc 'pseudo break code' hack to get the key off
  138. * because it has no break code.
  139. *
  140. */
  141. uint8_t matrix_scan(void)
  142. {
  143. // scan code reading states
  144. static enum {
  145. INIT,
  146. F0,
  147. E0,
  148. E0_F0,
  149. // Pause
  150. E1,
  151. E1_14,
  152. E1_14_77,
  153. E1_14_77_E1,
  154. E1_14_77_E1_F0,
  155. E1_14_77_E1_F0_14,
  156. E1_14_77_E1_F0_14_F0,
  157. // Control'd Pause
  158. E0_7E,
  159. E0_7E_E0,
  160. E0_7E_E0_F0,
  161. } state = INIT;
  162. is_modified = false;
  163. // 'pseudo break code' hack
  164. if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
  165. matrix_break(PAUSE);
  166. }
  167. uint8_t code = ps2_host_recv();
  168. if (!ps2_error) {
  169. switch (state) {
  170. case INIT:
  171. switch (code) {
  172. case 0xE0:
  173. state = E0;
  174. break;
  175. case 0xF0:
  176. state = F0;
  177. break;
  178. case 0xE1:
  179. state = E1;
  180. break;
  181. case 0x83: // F7
  182. matrix_make(F7);
  183. state = INIT;
  184. break;
  185. case 0x84: // Alt'd PrintScreen
  186. matrix_make(PRINT_SCREEN);
  187. state = INIT;
  188. break;
  189. case 0x00: // Overrun [3]p.25
  190. print("Overrun\n");
  191. clear_keyboard();
  192. state = INIT;
  193. break;
  194. default: // normal key make
  195. if (code < 0x80) {
  196. matrix_make(code);
  197. } else {
  198. xprintf("unexpected scan code at INIT: %02X\n", code);
  199. clear_keyboard();
  200. }
  201. state = INIT;
  202. }
  203. break;
  204. case E0: // E0-Prefixed
  205. switch (code) {
  206. case 0x12: // to be ignored
  207. case 0x59: // to be ignored
  208. state = INIT;
  209. break;
  210. case 0x7E: // Control'd Pause
  211. state = E0_7E;
  212. break;
  213. case 0xF0:
  214. state = E0_F0;
  215. break;
  216. default:
  217. if (code < 0x80) {
  218. matrix_make(code|0x80);
  219. } else {
  220. xprintf("unexpected scan code at E0: %02X\n", code);
  221. clear_keyboard();
  222. }
  223. state = INIT;
  224. }
  225. break;
  226. case F0: // Break code
  227. switch (code) {
  228. case 0x83: // F7
  229. matrix_break(F7);
  230. state = INIT;
  231. break;
  232. case 0x84: // Alt'd PrintScreen
  233. matrix_break(PRINT_SCREEN);
  234. state = INIT;
  235. break;
  236. default:
  237. if (code < 0x80) {
  238. matrix_break(code);
  239. } else {
  240. xprintf("unexpected scan code at F0: %02X\n", code);
  241. clear_keyboard();
  242. }
  243. state = INIT;
  244. }
  245. break;
  246. case E0_F0: // Break code of E0-prefixed
  247. switch (code) {
  248. case 0x12: // to be ignored
  249. case 0x59: // to be ignored
  250. state = INIT;
  251. break;
  252. default:
  253. if (code < 0x80) {
  254. matrix_break(code|0x80);
  255. } else {
  256. xprintf("unexpected scan code at E0_F0: %02X\n", code);
  257. clear_keyboard();
  258. }
  259. state = INIT;
  260. }
  261. break;
  262. // following are states of Pause
  263. case E1:
  264. switch (code) {
  265. case 0x14:
  266. state = E1_14;
  267. break;
  268. default:
  269. state = INIT;
  270. }
  271. break;
  272. case E1_14:
  273. switch (code) {
  274. case 0x77:
  275. state = E1_14_77;
  276. break;
  277. default:
  278. state = INIT;
  279. }
  280. break;
  281. case E1_14_77:
  282. switch (code) {
  283. case 0xE1:
  284. state = E1_14_77_E1;
  285. break;
  286. default:
  287. state = INIT;
  288. }
  289. break;
  290. case E1_14_77_E1:
  291. switch (code) {
  292. case 0xF0:
  293. state = E1_14_77_E1_F0;
  294. break;
  295. default:
  296. state = INIT;
  297. }
  298. break;
  299. case E1_14_77_E1_F0:
  300. switch (code) {
  301. case 0x14:
  302. state = E1_14_77_E1_F0_14;
  303. break;
  304. default:
  305. state = INIT;
  306. }
  307. break;
  308. case E1_14_77_E1_F0_14:
  309. switch (code) {
  310. case 0xF0:
  311. state = E1_14_77_E1_F0_14_F0;
  312. break;
  313. default:
  314. state = INIT;
  315. }
  316. break;
  317. case E1_14_77_E1_F0_14_F0:
  318. switch (code) {
  319. case 0x77:
  320. matrix_make(PAUSE);
  321. state = INIT;
  322. break;
  323. default:
  324. state = INIT;
  325. }
  326. break;
  327. // Following are states of Control'd Pause
  328. case E0_7E:
  329. if (code == 0xE0)
  330. state = E0_7E_E0;
  331. else
  332. state = INIT;
  333. break;
  334. case E0_7E_E0:
  335. if (code == 0xF0)
  336. state = E0_7E_E0_F0;
  337. else
  338. state = INIT;
  339. break;
  340. case E0_7E_E0_F0:
  341. if (code == 0x7E)
  342. matrix_make(PAUSE);
  343. state = INIT;
  344. break;
  345. default:
  346. state = INIT;
  347. }
  348. }
  349. if (ps2_error > PS2_ERR_STARTBIT3) {
  350. uint8_t ret = ps2_host_send(PS2_RESEND);
  351. xprintf("Resend: %02X\n", ret);
  352. }
  353. return 1;
  354. }
  355. bool matrix_is_modified(void)
  356. {
  357. return is_modified;
  358. }
  359. inline
  360. bool matrix_has_ghost(void)
  361. {
  362. #ifdef MATRIX_HAS_GHOST
  363. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  364. if (matrix_has_ghost_in_row(i))
  365. return true;
  366. }
  367. #endif
  368. return false;
  369. }
  370. inline
  371. bool matrix_is_on(uint8_t row, uint8_t col)
  372. {
  373. return (matrix[row] & (1<<col));
  374. }
  375. inline
  376. uint8_t matrix_get_row(uint8_t row)
  377. {
  378. return matrix[row];
  379. }
  380. void matrix_print(void)
  381. {
  382. print("\nr/c 01234567\n");
  383. for (uint8_t row = 0; row < matrix_rows(); row++) {
  384. phex(row); print(": ");
  385. pbin_reverse(matrix_get_row(row));
  386. #ifdef MATRIX_HAS_GHOST
  387. if (matrix_has_ghost_in_row(row)) {
  388. print(" <ghost");
  389. }
  390. #endif
  391. print("\n");
  392. }
  393. }
  394. uint8_t matrix_key_count(void)
  395. {
  396. uint8_t count = 0;
  397. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  398. count += bitpop(matrix[i]);
  399. }
  400. return count;
  401. }
  402. #ifdef MATRIX_HAS_GHOST
  403. inline
  404. static bool matrix_has_ghost_in_row(uint8_t row)
  405. {
  406. // no ghost exists in case less than 2 keys on
  407. if (((matrix[row] - 1) & matrix[row]) == 0)
  408. return false;
  409. // ghost exists in case same state as other row
  410. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  411. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  412. return true;
  413. }
  414. return false;
  415. }
  416. #endif
  417. inline
  418. static void matrix_make(uint8_t code)
  419. {
  420. if (!matrix_is_on(ROW(code), COL(code))) {
  421. matrix[ROW(code)] |= 1<<COL(code);
  422. is_modified = true;
  423. }
  424. }
  425. inline
  426. static void matrix_break(uint8_t code)
  427. {
  428. if (matrix_is_on(ROW(code), COL(code))) {
  429. matrix[ROW(code)] &= ~(1<<COL(code));
  430. is_modified = true;
  431. }
  432. }