Keyboard firmwares for Atmel AVR and Cortex-M
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

matrix.c 14KB

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