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.

преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 12 години
преди 10 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 10 години
преди 13 години
преди 13 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 10 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 12 години
преди 10 години
преди 10 години
преди 13 години
преди 13 години
преди 10 години
преди 10 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 10 години
преди 10 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 10 години
преди 13 години
преди 10 години
преди 10 години
преди 13 години
преди 12 години
преди 13 години
преди 12 години
преди 13 години
преди 10 години
преди 10 години
преди 13 години
преди 12 години
преди 13 години
преди 13 години
преди 12 години
преди 13 години
преди 10 години
преди 10 години
преди 13 години
преди 10 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 10 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  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 "action.h"
  17. #include "print.h"
  18. #include "util.h"
  19. #include "debug.h"
  20. #include "ps2.h"
  21. #include "matrix.h"
  22. static void matrix_make(uint8_t code);
  23. static void matrix_break(uint8_t code);
  24. static void matrix_clear(void);
  25. #ifdef MATRIX_HAS_GHOST
  26. static bool matrix_has_ghost_in_row(uint8_t row);
  27. #endif
  28. /*
  29. * Matrix Array usage:
  30. * 'Scan Code Set 2' is assigned into 256(32x8)cell matrix.
  31. * Hmm, it is very sparse and not efficient :(
  32. *
  33. * Notes:
  34. * Both 'Hanguel/English'(F1) and 'Hanja'(F2) collide with 'Delete'(E0 71) and 'Down'(E0 72).
  35. * These two Korean keys need exceptional handling and are not supported for now. Sorry.
  36. *
  37. * 8bit wide
  38. * +---------+
  39. * 0| |
  40. * :| XX | 00-7F for normal codes(without E0-prefix)
  41. * f|_________|
  42. * 10| |
  43. * :| E0 YY | 80-FF for E0-prefixed codes
  44. * 1f| | (<YY>|0x80) is used as matrix position.
  45. * +---------+
  46. *
  47. * Exceptions:
  48. * 0x83: F7(0x83) This is a normal code but beyond 0x7F.
  49. * 0xFC: PrintScreen
  50. * 0xFE: Pause
  51. */
  52. static uint8_t matrix[MATRIX_ROWS];
  53. #define ROW(code) (code>>3)
  54. #define COL(code) (code&0x07)
  55. // matrix positions for exceptional keys
  56. #define F7 (0x83)
  57. #define PRINT_SCREEN (0xFC)
  58. #define PAUSE (0xFE)
  59. static bool is_modified = false;
  60. inline
  61. uint8_t matrix_rows(void)
  62. {
  63. return MATRIX_ROWS;
  64. }
  65. inline
  66. uint8_t matrix_cols(void)
  67. {
  68. return MATRIX_COLS;
  69. }
  70. void matrix_init(void)
  71. {
  72. debug_enable = true;
  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 (code) xprintf("%i\r\n", code);
  169. if (!ps2_error) {
  170. switch (state) {
  171. case INIT:
  172. switch (code) {
  173. case 0xE0:
  174. state = E0;
  175. break;
  176. case 0xF0:
  177. state = F0;
  178. break;
  179. case 0xE1:
  180. state = E1;
  181. break;
  182. case 0x83: // F7
  183. matrix_make(F7);
  184. state = INIT;
  185. break;
  186. case 0x84: // Alt'd PrintScreen
  187. matrix_make(PRINT_SCREEN);
  188. state = INIT;
  189. break;
  190. case 0x00: // Overrun [3]p.25
  191. matrix_clear();
  192. clear_keyboard();
  193. print("Overrun\n");
  194. state = INIT;
  195. break;
  196. default: // normal key make
  197. if (code < 0x80) {
  198. matrix_make(code);
  199. } else {
  200. matrix_clear();
  201. clear_keyboard();
  202. xprintf("unexpected scan code at INIT: %02X\n", code);
  203. }
  204. state = INIT;
  205. }
  206. break;
  207. case E0: // E0-Prefixed
  208. switch (code) {
  209. case 0x12: // to be ignored
  210. case 0x59: // to be ignored
  211. state = INIT;
  212. break;
  213. case 0x7E: // Control'd Pause
  214. state = E0_7E;
  215. break;
  216. case 0xF0:
  217. state = E0_F0;
  218. break;
  219. default:
  220. if (code < 0x80) {
  221. matrix_make(code|0x80);
  222. } else {
  223. matrix_clear();
  224. clear_keyboard();
  225. xprintf("unexpected scan code at E0: %02X\n", code);
  226. }
  227. state = INIT;
  228. }
  229. break;
  230. case F0: // Break code
  231. switch (code) {
  232. case 0x83: // F7
  233. matrix_break(F7);
  234. state = INIT;
  235. break;
  236. case 0x84: // Alt'd PrintScreen
  237. matrix_break(PRINT_SCREEN);
  238. state = INIT;
  239. break;
  240. case 0xF0:
  241. matrix_clear();
  242. clear_keyboard();
  243. xprintf("unexpected scan code at F0: F0(clear and cont.)\n");
  244. break;
  245. default:
  246. if (code < 0x80) {
  247. matrix_break(code);
  248. } else {
  249. matrix_clear();
  250. clear_keyboard();
  251. xprintf("unexpected scan code at F0: %02X\n", code);
  252. }
  253. state = INIT;
  254. }
  255. break;
  256. case E0_F0: // Break code of E0-prefixed
  257. switch (code) {
  258. case 0x12: // to be ignored
  259. case 0x59: // to be ignored
  260. state = INIT;
  261. break;
  262. default:
  263. if (code < 0x80) {
  264. matrix_break(code|0x80);
  265. } else {
  266. matrix_clear();
  267. clear_keyboard();
  268. xprintf("unexpected scan code at E0_F0: %02X\n", code);
  269. }
  270. state = INIT;
  271. }
  272. break;
  273. // following are states of Pause
  274. case E1:
  275. switch (code) {
  276. case 0x14:
  277. state = E1_14;
  278. break;
  279. default:
  280. state = INIT;
  281. }
  282. break;
  283. case E1_14:
  284. switch (code) {
  285. case 0x77:
  286. state = E1_14_77;
  287. break;
  288. default:
  289. state = INIT;
  290. }
  291. break;
  292. case E1_14_77:
  293. switch (code) {
  294. case 0xE1:
  295. state = E1_14_77_E1;
  296. break;
  297. default:
  298. state = INIT;
  299. }
  300. break;
  301. case E1_14_77_E1:
  302. switch (code) {
  303. case 0xF0:
  304. state = E1_14_77_E1_F0;
  305. break;
  306. default:
  307. state = INIT;
  308. }
  309. break;
  310. case E1_14_77_E1_F0:
  311. switch (code) {
  312. case 0x14:
  313. state = E1_14_77_E1_F0_14;
  314. break;
  315. default:
  316. state = INIT;
  317. }
  318. break;
  319. case E1_14_77_E1_F0_14:
  320. switch (code) {
  321. case 0xF0:
  322. state = E1_14_77_E1_F0_14_F0;
  323. break;
  324. default:
  325. state = INIT;
  326. }
  327. break;
  328. case E1_14_77_E1_F0_14_F0:
  329. switch (code) {
  330. case 0x77:
  331. matrix_make(PAUSE);
  332. state = INIT;
  333. break;
  334. default:
  335. state = INIT;
  336. }
  337. break;
  338. // Following are states of Control'd Pause
  339. case E0_7E:
  340. if (code == 0xE0)
  341. state = E0_7E_E0;
  342. else
  343. state = INIT;
  344. break;
  345. case E0_7E_E0:
  346. if (code == 0xF0)
  347. state = E0_7E_E0_F0;
  348. else
  349. state = INIT;
  350. break;
  351. case E0_7E_E0_F0:
  352. if (code == 0x7E)
  353. matrix_make(PAUSE);
  354. state = INIT;
  355. break;
  356. default:
  357. state = INIT;
  358. }
  359. }
  360. // TODO: request RESEND when error occurs?
  361. /*
  362. if (PS2_IS_FAILED(ps2_error)) {
  363. uint8_t ret = ps2_host_send(PS2_RESEND);
  364. xprintf("Resend: %02X\n", ret);
  365. }
  366. */
  367. return 1;
  368. }
  369. bool matrix_is_modified(void)
  370. {
  371. return is_modified;
  372. }
  373. inline
  374. bool matrix_has_ghost(void)
  375. {
  376. #ifdef MATRIX_HAS_GHOST
  377. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  378. if (matrix_has_ghost_in_row(i))
  379. return true;
  380. }
  381. #endif
  382. return false;
  383. }
  384. inline
  385. bool matrix_is_on(uint8_t row, uint8_t col)
  386. {
  387. return (matrix[row] & (1<<col));
  388. }
  389. inline
  390. uint8_t matrix_get_row(uint8_t row)
  391. {
  392. return matrix[row];
  393. }
  394. void matrix_print(void)
  395. {
  396. print("\nr/c 01234567\n");
  397. for (uint8_t row = 0; row < matrix_rows(); row++) {
  398. phex(row); print(": ");
  399. pbin_reverse(matrix_get_row(row));
  400. #ifdef MATRIX_HAS_GHOST
  401. if (matrix_has_ghost_in_row(row)) {
  402. print(" <ghost");
  403. }
  404. #endif
  405. print("\n");
  406. }
  407. }
  408. uint8_t matrix_key_count(void)
  409. {
  410. uint8_t count = 0;
  411. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  412. count += bitpop(matrix[i]);
  413. }
  414. return count;
  415. }
  416. #ifdef MATRIX_HAS_GHOST
  417. inline
  418. static bool matrix_has_ghost_in_row(uint8_t row)
  419. {
  420. // no ghost exists in case less than 2 keys on
  421. if (((matrix[row] - 1) & matrix[row]) == 0)
  422. return false;
  423. // ghost exists in case same state as other row
  424. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  425. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  426. return true;
  427. }
  428. return false;
  429. }
  430. #endif
  431. inline
  432. static void matrix_make(uint8_t code)
  433. {
  434. if (!matrix_is_on(ROW(code), COL(code))) {
  435. matrix[ROW(code)] |= 1<<COL(code);
  436. is_modified = true;
  437. }
  438. }
  439. inline
  440. static void matrix_break(uint8_t code)
  441. {
  442. if (matrix_is_on(ROW(code), COL(code))) {
  443. matrix[ROW(code)] &= ~(1<<COL(code));
  444. is_modified = true;
  445. }
  446. }
  447. inline
  448. static void matrix_clear(void)
  449. {
  450. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  451. }