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.

280 lines
7.8 KiB

Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
Use a single endpoint for HID reports (#3951) * Unify multiple HID interfaces into one This reduces the number of USB endpoints required, which frees them up for other things. NKRO and EXTRAKEY always use the shared endpoint. By default, MOUSEKEY also uses it. This means it won't work as a Boot Procotol mouse in some BIOSes, etc. If you really think your keyboard needs to work as a mouse in your BIOS, set MOUSE_SHARED_EP = no in your rules.mk. By default, the core keyboard does not use the shared endpoint, as not all BIOSes are standards compliant and that's one place you don't want to find out your keyboard doesn't work.. If you are really confident, you can set KEYBOARD_SHARED_EP = yes to use the shared endpoint here too. * unify endpoints: ChibiOS protocol implementation * fixup: missing #ifdef EXTRAKEY_ENABLEs broke build on AVR with EXTRAKEY disabled * endpoints: restore error when too many endpoints required * lufa: wait up to 10ms to send keyboard input This avoids packets being dropped when two reports are sent in quick succession (eg. releasing a dual role key). * endpoints: fix compile on ARM_ATSAM * endpoint: ARM_ATSAM fixes No longer use wrong or unexpected endpoint IDs * endpoints: accommodate VUSB protocol V-USB has its own, understandably simple ideas about the report formats. It already blasts the mouse and extrakeys through one endpoint with report IDs. We just stay out of its way. * endpoints: document new endpoint configuration options * endpoints: respect keyboard_report->mods in NKRO The caller(s) of host_keyboard_send expect to be able to just drop modifiers in the mods field and not worry about whether NKRO is in use. This is a good thing. So we just shift it over if needs be. * endpoints: report.c: update for new keyboard_report format
5 years ago
  1. /* Copyright 2017 Fred Sundvik
  2. *
  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. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "report.h"
  17. #include "host.h"
  18. #include "keycode_config.h"
  19. #include "debug.h"
  20. #include "util.h"
  21. #include <string.h>
  22. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  23. # define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
  24. # define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
  25. # define RO_INC(a) RO_ADD(a, 1)
  26. # define RO_DEC(a) RO_SUB(a, 1)
  27. static int8_t cb_head = 0;
  28. static int8_t cb_tail = 0;
  29. static int8_t cb_count = 0;
  30. #endif
  31. /** \brief has_anykey
  32. *
  33. * FIXME: Needs doc
  34. */
  35. uint8_t has_anykey(report_keyboard_t* keyboard_report) {
  36. uint8_t cnt = 0;
  37. uint8_t* p = keyboard_report->keys;
  38. uint8_t lp = sizeof(keyboard_report->keys);
  39. #ifdef NKRO_ENABLE
  40. if (keyboard_protocol && keymap_config.nkro) {
  41. p = keyboard_report->nkro.bits;
  42. lp = sizeof(keyboard_report->nkro.bits);
  43. }
  44. #endif
  45. while (lp--) {
  46. if (*p++) cnt++;
  47. }
  48. return cnt;
  49. }
  50. /** \brief get_first_key
  51. *
  52. * FIXME: Needs doc
  53. */
  54. uint8_t get_first_key(report_keyboard_t* keyboard_report) {
  55. #ifdef NKRO_ENABLE
  56. if (keyboard_protocol && keymap_config.nkro) {
  57. uint8_t i = 0;
  58. for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
  59. ;
  60. return i << 3 | biton(keyboard_report->nkro.bits[i]);
  61. }
  62. #endif
  63. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  64. uint8_t i = cb_head;
  65. do {
  66. if (keyboard_report->keys[i] != 0) {
  67. break;
  68. }
  69. i = RO_INC(i);
  70. } while (i != cb_tail);
  71. return keyboard_report->keys[i];
  72. #else
  73. return keyboard_report->keys[0];
  74. #endif
  75. }
  76. /** \brief Checks if a key is pressed in the report
  77. *
  78. * Returns true if the keyboard_report reports that the key is pressed, otherwise false
  79. * Note: The function doesn't support modifers currently, and it returns false for KC_NO
  80. */
  81. bool is_key_pressed(report_keyboard_t* keyboard_report, uint8_t key) {
  82. if (key == KC_NO) {
  83. return false;
  84. }
  85. #ifdef NKRO_ENABLE
  86. if (keyboard_protocol && keymap_config.nkro) {
  87. if ((key >> 3) < KEYBOARD_REPORT_BITS) {
  88. return keyboard_report->nkro.bits[key >> 3] & 1 << (key & 7);
  89. } else {
  90. return false;
  91. }
  92. }
  93. #endif
  94. for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
  95. if (keyboard_report->keys[i] == key) {
  96. return true;
  97. }
  98. }
  99. return false;
  100. }
  101. /** \brief add key byte
  102. *
  103. * FIXME: Needs doc
  104. */
  105. void add_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
  106. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  107. int8_t i = cb_head;
  108. int8_t empty = -1;
  109. if (cb_count) {
  110. do {
  111. if (keyboard_report->keys[i] == code) {
  112. return;
  113. }
  114. if (empty == -1 && keyboard_report->keys[i] == 0) {
  115. empty = i;
  116. }
  117. i = RO_INC(i);
  118. } while (i != cb_tail);
  119. if (i == cb_tail) {
  120. if (cb_tail == cb_head) {
  121. // buffer is full
  122. if (empty == -1) {
  123. // pop head when has no empty space
  124. cb_head = RO_INC(cb_head);
  125. cb_count--;
  126. } else {
  127. // left shift when has empty space
  128. uint8_t offset = 1;
  129. i = RO_INC(empty);
  130. do {
  131. if (keyboard_report->keys[i] != 0) {
  132. keyboard_report->keys[empty] = keyboard_report->keys[i];
  133. keyboard_report->keys[i] = 0;
  134. empty = RO_INC(empty);
  135. } else {
  136. offset++;
  137. }
  138. i = RO_INC(i);
  139. } while (i != cb_tail);
  140. cb_tail = RO_SUB(cb_tail, offset);
  141. }
  142. }
  143. }
  144. }
  145. // add to tail
  146. keyboard_report->keys[cb_tail] = code;
  147. cb_tail = RO_INC(cb_tail);
  148. cb_count++;
  149. #else
  150. int8_t i = 0;
  151. int8_t empty = -1;
  152. for (; i < KEYBOARD_REPORT_KEYS; i++) {
  153. if (keyboard_report->keys[i] == code) {
  154. break;
  155. }
  156. if (empty == -1 && keyboard_report->keys[i] == 0) {
  157. empty = i;
  158. }
  159. }
  160. if (i == KEYBOARD_REPORT_KEYS) {
  161. if (empty != -1) {
  162. keyboard_report->keys[empty] = code;
  163. }
  164. }
  165. #endif
  166. }
  167. /** \brief del key byte
  168. *
  169. * FIXME: Needs doc
  170. */
  171. void del_key_byte(report_keyboard_t* keyboard_report, uint8_t code) {
  172. #ifdef RING_BUFFERED_6KRO_REPORT_ENABLE
  173. uint8_t i = cb_head;
  174. if (cb_count) {
  175. do {
  176. if (keyboard_report->keys[i] == code) {
  177. keyboard_report->keys[i] = 0;
  178. cb_count--;
  179. if (cb_count == 0) {
  180. // reset head and tail
  181. cb_tail = cb_head = 0;
  182. }
  183. if (i == RO_DEC(cb_tail)) {
  184. // left shift when next to tail
  185. do {
  186. cb_tail = RO_DEC(cb_tail);
  187. if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
  188. break;
  189. }
  190. } while (cb_tail != cb_head);
  191. }
  192. break;
  193. }
  194. i = RO_INC(i);
  195. } while (i != cb_tail);
  196. }
  197. #else
  198. for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
  199. if (keyboard_report->keys[i] == code) {
  200. keyboard_report->keys[i] = 0;
  201. }
  202. }
  203. #endif
  204. }
  205. #ifdef NKRO_ENABLE
  206. /** \brief add key bit
  207. *
  208. * FIXME: Needs doc
  209. */
  210. void add_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
  211. if ((code >> 3) < KEYBOARD_REPORT_BITS) {
  212. keyboard_report->nkro.bits[code >> 3] |= 1 << (code & 7);
  213. } else {
  214. dprintf("add_key_bit: can't add: %02X\n", code);
  215. }
  216. }
  217. /** \brief del key bit
  218. *
  219. * FIXME: Needs doc
  220. */
  221. void del_key_bit(report_keyboard_t* keyboard_report, uint8_t code) {
  222. if ((code >> 3) < KEYBOARD_REPORT_BITS) {
  223. keyboard_report->nkro.bits[code >> 3] &= ~(1 << (code & 7));
  224. } else {
  225. dprintf("del_key_bit: can't del: %02X\n", code);
  226. }
  227. }
  228. #endif
  229. /** \brief add key to report
  230. *
  231. * FIXME: Needs doc
  232. */
  233. void add_key_to_report(report_keyboard_t* keyboard_report, uint8_t key) {
  234. #ifdef NKRO_ENABLE
  235. if (keyboard_protocol && keymap_config.nkro) {
  236. add_key_bit(keyboard_report, key);
  237. return;
  238. }
  239. #endif
  240. add_key_byte(keyboard_report, key);
  241. }
  242. /** \brief del key from report
  243. *
  244. * FIXME: Needs doc
  245. */
  246. void del_key_from_report(report_keyboard_t* keyboard_report, uint8_t key) {
  247. #ifdef NKRO_ENABLE
  248. if (keyboard_protocol && keymap_config.nkro) {
  249. del_key_bit(keyboard_report, key);
  250. return;
  251. }
  252. #endif
  253. del_key_byte(keyboard_report, key);
  254. }
  255. /** \brief clear key from report
  256. *
  257. * FIXME: Needs doc
  258. */
  259. void clear_keys_from_report(report_keyboard_t* keyboard_report) {
  260. // not clear mods
  261. #ifdef NKRO_ENABLE
  262. if (keyboard_protocol && keymap_config.nkro) {
  263. memset(keyboard_report->nkro.bits, 0, sizeof(keyboard_report->nkro.bits));
  264. return;
  265. }
  266. #endif
  267. memset(keyboard_report->keys, 0, sizeof(keyboard_report->keys));
  268. }