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 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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 "print.h"
  19. #include "util.h"
  20. #include "debug.h"
  21. #include "ps2.h"
  22. #include "matrix.h"
  23. static void matrix_make(uint8_t code);
  24. static void matrix_break(uint8_t code);
  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. ps2_host_init();
  73. // initialize matrix state: all keys off
  74. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  75. return;
  76. }
  77. /*
  78. * PS/2 Scan Code Set 2: Exceptional Handling
  79. *
  80. * There are several keys to be handled exceptionally.
  81. * The scan code for these keys are varied or prefix/postfix'd
  82. * depending on modifier key state.
  83. *
  84. * Keyboard Scan Code Specification:
  85. * http://www.microsoft.com/whdc/archive/scancode.mspx
  86. * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
  87. *
  88. *
  89. * 1) Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left
  90. * a) when Num Lock is off
  91. * modifiers | make | break
  92. * ----------+---------------------------+----------------------
  93. * Ohter | <make> | <break>
  94. * LShift | E0 F0 12 <make> | <break> E0 12
  95. * RShift | E0 F0 59 <make> | <break> E0 59
  96. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  97. *
  98. * b) when Num Lock is on
  99. * modifiers | make | break
  100. * ----------+---------------------------+----------------------
  101. * Other | E0 12 <make> | <break> E0 F0 12
  102. * Shift'd | <make> | <break>
  103. *
  104. * Handling: These prefix/postfix codes are ignored.
  105. *
  106. *
  107. * 2) Keypad /
  108. * modifiers | make | break
  109. * ----------+---------------------------+----------------------
  110. * Ohter | <make> | <break>
  111. * LShift | E0 F0 12 <make> | <break> E0 12
  112. * RShift | E0 F0 59 <make> | <break> E0 59
  113. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  114. *
  115. * Handling: These prefix/postfix codes are ignored.
  116. *
  117. *
  118. * 3) PrintScreen
  119. * modifiers | make | break
  120. * ----------+--------------+-----------------------------------
  121. * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
  122. * Shift'd | E0 7C | E0 F0 7C
  123. * Control'd | E0 7C | E0 F0 7C
  124. * Alt'd | 84 | F0 84
  125. *
  126. * Handling: These prefix/postfix codes are ignored, and both scan codes
  127. * 'E0 7C' and 84 are seen as PrintScreen.
  128. *
  129. * 4) Pause
  130. * modifiers | make(no break code)
  131. * ----------+--------------------------------------------------
  132. * Other | E1 14 77 E1 F0 14 F0 77
  133. * Control'd | E0 7E E0 F0 7E
  134. *
  135. * Handling: Both code sequences are treated as a whole.
  136. * And we need a ad hoc 'pseudo break code' hack to get the key off
  137. * because it has no break code.
  138. *
  139. */
  140. uint8_t matrix_scan(void)
  141. {
  142. // scan code reading states
  143. static enum {
  144. INIT,
  145. F0,
  146. E0,
  147. E0_F0,
  148. // Pause
  149. E1,
  150. E1_14,
  151. E1_14_77,
  152. E1_14_77_E1,
  153. E1_14_77_E1_F0,
  154. E1_14_77_E1_F0_14,
  155. E1_14_77_E1_F0_14_F0,
  156. // Control'd Pause
  157. E0_7E,
  158. E0_7E_E0,
  159. E0_7E_E0_F0,
  160. } state = INIT;
  161. is_modified = false;
  162. // 'pseudo break code' hack
  163. if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
  164. matrix_break(PAUSE);
  165. }
  166. uint8_t code;
  167. while ((code = ps2_host_recv())) {
  168. switch (state) {
  169. case INIT:
  170. switch (code) {
  171. case 0xE0:
  172. state = E0;
  173. break;
  174. case 0xF0:
  175. state = F0;
  176. break;
  177. case 0xE1:
  178. state = E1;
  179. break;
  180. case 0x83: // F7
  181. matrix_make(F7);
  182. state = INIT;
  183. break;
  184. case 0x84: // Alt'd PrintScreen
  185. matrix_make(PRINT_SCREEN);
  186. state = INIT;
  187. break;
  188. default: // normal key make
  189. if (code < 0x80) {
  190. matrix_make(code);
  191. } else {
  192. debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n");
  193. }
  194. state = INIT;
  195. }
  196. break;
  197. case E0: // E0-Prefixed
  198. switch (code) {
  199. case 0x12: // to be ignored
  200. case 0x59: // to be ignored
  201. state = INIT;
  202. break;
  203. case 0x7E: // Control'd Pause
  204. state = E0_7E;
  205. break;
  206. case 0xF0:
  207. state = E0_F0;
  208. break;
  209. default:
  210. if (code < 0x80) {
  211. matrix_make(code|0x80);
  212. } else {
  213. debug("unexpected scan code at E0: "); debug_hex(code); debug("\n");
  214. }
  215. state = INIT;
  216. }
  217. break;
  218. case F0: // Break code
  219. switch (code) {
  220. case 0x83: // F7
  221. matrix_break(F7);
  222. state = INIT;
  223. break;
  224. case 0x84: // Alt'd PrintScreen
  225. matrix_break(PRINT_SCREEN);
  226. state = INIT;
  227. break;
  228. default:
  229. if (code < 0x80) {
  230. matrix_break(code);
  231. } else {
  232. debug("unexpected scan code at F0: "); debug_hex(code); debug("\n");
  233. }
  234. state = INIT;
  235. }
  236. break;
  237. case E0_F0: // Break code of E0-prefixed
  238. switch (code) {
  239. case 0x12: // to be ignored
  240. case 0x59: // to be ignored
  241. state = INIT;
  242. break;
  243. default:
  244. if (code < 0x80) {
  245. matrix_break(code|0x80);
  246. } else {
  247. debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n");
  248. }
  249. state = INIT;
  250. }
  251. break;
  252. // following are states of Pause
  253. case E1:
  254. switch (code) {
  255. case 0x14:
  256. state = E1_14;
  257. break;
  258. default:
  259. state = INIT;
  260. }
  261. break;
  262. case E1_14:
  263. switch (code) {
  264. case 0x77:
  265. state = E1_14_77;
  266. break;
  267. default:
  268. state = INIT;
  269. }
  270. break;
  271. case E1_14_77:
  272. switch (code) {
  273. case 0xE1:
  274. state = E1_14_77_E1;
  275. break;
  276. default:
  277. state = INIT;
  278. }
  279. break;
  280. case E1_14_77_E1:
  281. switch (code) {
  282. case 0xF0:
  283. state = E1_14_77_E1_F0;
  284. break;
  285. default:
  286. state = INIT;
  287. }
  288. break;
  289. case E1_14_77_E1_F0:
  290. switch (code) {
  291. case 0x14:
  292. state = E1_14_77_E1_F0_14;
  293. break;
  294. default:
  295. state = INIT;
  296. }
  297. break;
  298. case E1_14_77_E1_F0_14:
  299. switch (code) {
  300. case 0xF0:
  301. state = E1_14_77_E1_F0_14_F0;
  302. break;
  303. default:
  304. state = INIT;
  305. }
  306. break;
  307. case E1_14_77_E1_F0_14_F0:
  308. switch (code) {
  309. case 0x77:
  310. matrix_make(PAUSE);
  311. state = INIT;
  312. break;
  313. default:
  314. state = INIT;
  315. }
  316. break;
  317. // Following are states of Control'd Pause
  318. case E0_7E:
  319. if (code == 0xE0)
  320. state = E0_7E_E0;
  321. else
  322. state = INIT;
  323. break;
  324. case E0_7E_E0:
  325. if (code == 0xF0)
  326. state = E0_7E_E0_F0;
  327. else
  328. state = INIT;
  329. break;
  330. case E0_7E_E0_F0:
  331. if (code == 0x7E)
  332. matrix_make(PAUSE);
  333. state = INIT;
  334. break;
  335. default:
  336. state = INIT;
  337. }
  338. phex(code);
  339. }
  340. return 1;
  341. }
  342. bool matrix_is_modified(void)
  343. {
  344. return is_modified;
  345. }
  346. inline
  347. bool matrix_has_ghost(void)
  348. {
  349. #ifdef MATRIX_HAS_GHOST
  350. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  351. if (matrix_has_ghost_in_row(i))
  352. return true;
  353. }
  354. #endif
  355. return false;
  356. }
  357. inline
  358. bool matrix_is_on(uint8_t row, uint8_t col)
  359. {
  360. return (matrix[row] & (1<<col));
  361. }
  362. inline
  363. uint8_t matrix_get_row(uint8_t row)
  364. {
  365. return matrix[row];
  366. }
  367. void matrix_print(void)
  368. {
  369. print("\nr/c 01234567\n");
  370. for (uint8_t row = 0; row < matrix_rows(); row++) {
  371. phex(row); print(": ");
  372. pbin_reverse(matrix_get_row(row));
  373. #ifdef MATRIX_HAS_GHOST
  374. if (matrix_has_ghost_in_row(row)) {
  375. print(" <ghost");
  376. }
  377. #endif
  378. print("\n");
  379. }
  380. }
  381. uint8_t matrix_key_count(void)
  382. {
  383. uint8_t count = 0;
  384. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  385. count += bitpop(matrix[i]);
  386. }
  387. return count;
  388. }
  389. #ifdef MATRIX_HAS_GHOST
  390. inline
  391. static bool matrix_has_ghost_in_row(uint8_t row)
  392. {
  393. // no ghost exists in case less than 2 keys on
  394. if (((matrix[row] - 1) & matrix[row]) == 0)
  395. return false;
  396. // ghost exists in case same state as other row
  397. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  398. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  399. return true;
  400. }
  401. return false;
  402. }
  403. #endif
  404. inline
  405. static void matrix_make(uint8_t code)
  406. {
  407. if (!matrix_is_on(ROW(code), COL(code))) {
  408. matrix[ROW(code)] |= 1<<COL(code);
  409. is_modified = true;
  410. }
  411. }
  412. inline
  413. static void matrix_break(uint8_t code)
  414. {
  415. if (matrix_is_on(ROW(code), COL(code))) {
  416. matrix[ROW(code)] &= ~(1<<COL(code));
  417. is_modified = true;
  418. }
  419. }