usb_hid.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. #include "include.h"
  2. #include "usb_com.h"
  3. #include "usb_hid.h"
  4. #include "usb_hid_desc.h"
  5. #if USB_HID_EN
  6. #define TRACE_RATE_EN 0
  7. #define TRACE_RATE_PERIOD 1000 // Unit: sof
  8. #define HID_RECV_PKS_NUM 5
  9. #define HID_RESUME_PREVENT_TIME 1000 // Unit: ms
  10. udh_t udh_0 AT(.usb_buf.usb);
  11. epcb_t ep_hid_tx AT(.usb_buf.usb);
  12. epcb_t ep_hid_rx AT(.usb_buf.usb);
  13. u8 ep_hid_buf_out[HID_EP_OUT_MAX_SIZE + 4] AT(.usb_buf.hid); // CRC
  14. u8 ep_hid_buf_in[HID_EP_IN_MAX_SIZE] AT(.usb_buf.hid);
  15. u32 tick_resume_prevent AT(.bss.usb_buf.hid);
  16. #if TRACE_RATE_EN
  17. static u32 statistic_sof_count;
  18. static u32 statistic_tx_done_count;
  19. #endif
  20. static struct {
  21. uint8_t ridx;
  22. uint8_t widx;
  23. uint16_t cnt;
  24. uint8_t data[HID_EP_IN_MAX_SIZE * HID_RECV_PKS_NUM];
  25. } hid_recv_cb AT(.usb_buf.hid);
  26. #define usb_hid_is_valid() (udh_0.valid == true)
  27. #define usb_hid_resume_prevent_en() {tick_resume_prevent = tick_get();}
  28. #define usb_hid_resume_prevent_dis() {tick_resume_prevent = 0;}
  29. #define usb_hid_resume_prevent_chk() (!tick_resume_prevent || !tick_check_expire(tick_resume_prevent, HID_RESUME_PREVENT_TIME))
  30. AT(.com_text.hid.mouse)
  31. static bool hid_recv_queue_push(uint8_t *data)
  32. {
  33. GLOBAL_INT_DISABLE();
  34. bool status = false;
  35. uint8_t *wptr = &hid_recv_cb.data[hid_recv_cb.widx * HID_EP_IN_MAX_SIZE];
  36. if (hid_recv_cb.cnt < HID_RECV_PKS_NUM) {
  37. memcpy(wptr, data, HID_EP_IN_MAX_SIZE);
  38. hid_recv_cb.widx = (hid_recv_cb.widx + 1) % HID_RECV_PKS_NUM;
  39. hid_recv_cb.cnt++;
  40. status = true;
  41. }
  42. GLOBAL_INT_RESTORE();
  43. return (status);
  44. }
  45. AT(.com_text.hid.mouse)
  46. static bool hid_recv_queue_pop(uint8_t *data)
  47. {
  48. GLOBAL_INT_DISABLE();
  49. bool status = false;
  50. uint8_t *rptr = &hid_recv_cb.data[hid_recv_cb.ridx * HID_EP_IN_MAX_SIZE];
  51. if (hid_recv_cb.cnt) {
  52. memcpy(data, rptr, HID_EP_IN_MAX_SIZE);
  53. hid_recv_cb.ridx = (hid_recv_cb.ridx + 1) % HID_RECV_PKS_NUM;
  54. hid_recv_cb.cnt--;
  55. status = true;
  56. }
  57. GLOBAL_INT_RESTORE();
  58. return (status);
  59. }
  60. AT(.com_text.hid.mouse)
  61. static void hid_recv_queue_clear(void)
  62. {
  63. GLOBAL_INT_DISABLE();
  64. hid_recv_cb.ridx = 0;
  65. hid_recv_cb.widx = 0;
  66. hid_recv_cb.cnt = 0;
  67. GLOBAL_INT_RESTORE();
  68. }
  69. void ude_hid_setvalid(bool valid)
  70. {
  71. udh_t *udh = &udh_0;
  72. udh->valid = valid;
  73. }
  74. AT(.usbdev.com)
  75. void ude_hid_rx_process(void)
  76. {
  77. u16 size;
  78. udh_t *udh = &udh_0;
  79. if (udh->valid) {
  80. size = usb_ep_get_rx_len(udh->int_out);
  81. usb_hid_receive_callback(udh->int_out->buf, size);
  82. usb_ep_clear_rx_fifo(udh->int_out);
  83. }
  84. }
  85. AT(.usbdev.com)
  86. void ude_hid_tx_process(void)
  87. {
  88. usb_hid_send_kick();
  89. #if TRACE_RATE_EN
  90. if (statistic_sof_count < (TRACE_RATE_PERIOD + 1)) {
  91. statistic_tx_done_count++;
  92. }
  93. #endif
  94. }
  95. AT(.com_text.isr.suspend)
  96. void usb_hid_suspend_callback(bool suspend)
  97. {
  98. if (suspend) {
  99. hid_recv_queue_clear();
  100. usb_hid_resume_prevent_en();
  101. } else {
  102. usb_hid_resume_prevent_dis();
  103. }
  104. }
  105. AT(.com_text.isr.sof)
  106. void usb_sof_hid_isr(void)
  107. {
  108. #if TRACE_RATE_EN
  109. if (statistic_sof_count < (TRACE_RATE_PERIOD + 1)) {
  110. statistic_sof_count++;
  111. }
  112. #endif
  113. }
  114. ///USB hid endpoint reset
  115. void usb_int_ep_reset(void)
  116. {
  117. udh_t *udh = &udh_0;
  118. /* Any usb class can't always use ep0, so it't un-init when index is zere */
  119. if (udh->int_in->index) {
  120. usb_ep_reset(udh->int_in);
  121. }
  122. if (udh->int_out->index) {
  123. usb_ep_reset(udh->int_out);
  124. }
  125. }
  126. ///USB HID 初始化
  127. void udh_init(void)
  128. {
  129. epcb_t *epcb;
  130. udh_t *udh = &udh_0;
  131. memset(&udh_0, 0, sizeof(udh_0));
  132. udh_0.int_in = &ep_hid_tx;
  133. udh_0.int_out = &ep_hid_rx;
  134. memset(udh->int_in, 0x00, sizeof(epcb_t));
  135. memset(udh->int_out, 0x00, sizeof(epcb_t));
  136. usb_ep_callback_register(ude_hid_tx_process, USB_HID_EP_IN_INDEX, EP_DIR_IN);
  137. usb_ep_callback_register(ude_hid_rx_process, USB_HID_EP_OUT_INDEX, EP_DIR_OUT);
  138. memset(ep_hid_buf_in, 0, sizeof(ep_hid_buf_in));
  139. epcb = udh->int_in;
  140. epcb->dir = EP_DIR_IN;
  141. epcb->index = USB_HID_EP_IN_INDEX;
  142. epcb->type = EP_TYPE_INTR;
  143. epcb->epsize = HID_EP_IN_MAX_SIZE;
  144. epcb->buf = ep_hid_buf_in;
  145. usb_ep_init(epcb);
  146. memset(ep_hid_buf_out, 0, sizeof(ep_hid_buf_out));
  147. epcb = udh->int_out;
  148. epcb->dir = EP_DIR_OUT;
  149. epcb->index = USB_HID_EP_OUT_INDEX;
  150. epcb->type = EP_TYPE_INTR;
  151. epcb->epsize = HID_EP_OUT_MAX_SIZE;
  152. epcb->buf = ep_hid_buf_out;
  153. usb_ep_init(epcb);
  154. ude_hid_setvalid(false);
  155. }
  156. /* START: API for upper layer */
  157. WEAK void usb_hid_receive_callback(uint8_t *buf, uint32_t size)
  158. {
  159. hid_rep_info_t *hid_rep_info = (hid_rep_info_t *)buf;
  160. printf("hid data out[%d]:\n", size);
  161. print_r(buf, size);
  162. if (hid_rep_info->report_id == HID_REP_ID_LED) {
  163. u8 caps_lock[1] = {(hid_rep_info->pdu.led.caps_lock)? 1: 0};
  164. wireless_send_ctrl_cmd(WIRELESS_CTRL_CMD_CODE_CAPS_LOCK_CHANGE, 1, caps_lock);
  165. }
  166. }
  167. AT(.com_text.usb.kick)
  168. void usb_hid_send_kick(void)
  169. {
  170. udh_t *udh = &udh_0;
  171. u32 size = 0;
  172. if (!udh->valid) {
  173. return;
  174. }
  175. if (usb_device_is_suspend()) {
  176. if (false == usb_hid_resume_prevent_chk()) {
  177. usb_hid_resume_prevent_dis();
  178. usb_device_resume();
  179. }
  180. return;
  181. }
  182. if (usb_ep_transfer(udh->int_in)) {
  183. usb_hid_send_prepare(udh->int_in->buf, &size);
  184. if (size) {
  185. usb_ep_start_transfer(udh->int_in, size);
  186. }
  187. }
  188. }
  189. AT(.com_text.usb.hid)
  190. bool usb_hid_buffer_push(uint8_t *buf, uint32_t size)
  191. {
  192. if (!usb_hid_is_valid() || usb_device_is_suspend()) {
  193. return false;
  194. }
  195. if ((size % HID_EP_IN_MAX_SIZE) != 0) {
  196. return false;
  197. }
  198. while (size && hid_recv_queue_push(buf)) {
  199. size -= HID_EP_IN_MAX_SIZE;
  200. buf += HID_EP_IN_MAX_SIZE;
  201. }
  202. // ASSERT: all data can push in queue
  203. if (size) {
  204. }
  205. return true;
  206. }
  207. AT(.com_text.usb.hid)
  208. bool usb_hid_buffer_push_check(void)
  209. {
  210. return (hid_recv_cb.cnt < HID_RECV_PKS_NUM);
  211. }
  212. AT(.com_text.usb.hid)
  213. void usb_hid_send_prepare(uint8_t *buf, uint32_t *size)
  214. {
  215. if (sys_cb.usb_is_active && hid_recv_queue_pop(buf)) {
  216. *size = HID_EP_IN_MAX_SIZE;
  217. } else {
  218. *size = 0;
  219. }
  220. }
  221. void usb_hid_init(void)
  222. {
  223. memset(&hid_recv_cb, 0x00, sizeof(hid_recv_cb));
  224. }
  225. void usb_hid_deinit(void)
  226. {
  227. ude_hid_setvalid(false);
  228. }
  229. #if TRACE_RATE_EN
  230. AT(.com_text.test)
  231. void usb_hid_statistic_flush(void)
  232. {
  233. GLOBAL_INT_DISABLE();
  234. statistic_sof_count = 0;
  235. statistic_tx_done_count = 0;
  236. GLOBAL_INT_RESTORE();
  237. }
  238. #endif
  239. void usb_hid_process(void)
  240. {
  241. #if TRACE_RATE_EN
  242. if (statistic_sof_count > TRACE_RATE_PERIOD)
  243. {
  244. printf("[USB]: %din/%dsof\n", statistic_tx_done_count, TRACE_RATE_PERIOD);
  245. usb_hid_statistic_flush();
  246. }
  247. #endif
  248. }
  249. #endif // USB_HID_EN