logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

usb_driver.h (12315B)


  1. // Copyright 2023 Stefan Kerkmann (@KarlK90)
  2. // Copyright 2020 Ryan (@fauxpark)
  3. // Copyright 2016 Fredizzimo
  4. // Copyright 2016 Giovanni Di Sirio
  5. // SPDX-License-Identifier: GPL-3.0-or-later OR Apache-2.0
  6. #pragma once
  7. #include <hal_buffers.h>
  8. #include "usb_descriptor.h"
  9. #include "chibios_config.h"
  10. #include "usb_report_handling.h"
  11. #include "string.h"
  12. #include "timer.h"
  13. #if HAL_USE_USB == FALSE
  14. # error "The USB Driver requires HAL_USE_USB"
  15. #endif
  16. /* USB Low Level driver specific endpoint fields */
  17. #if !defined(usb_lld_endpoint_fields)
  18. # define usb_lld_endpoint_fields \
  19. 2, /* IN multiplier */ \
  20. NULL, /* SETUP buffer (not a SETUP endpoint) */
  21. #endif
  22. /*
  23. * Implementation notes:
  24. *
  25. * USBEndpointConfig - Configured using explicit order instead of struct member name.
  26. * This is due to ChibiOS hal LLD differences, which is dependent on hardware,
  27. * "USBv1" devices have `ep_buffers` and "OTGv1" have `in_multiplier`.
  28. * Given `USBv1/hal_usb_lld.h` marks the field as "not currently used" this code file
  29. * makes the assumption this is safe to avoid littering with preprocessor directives.
  30. */
  31. #define QMK_USB_ENDPOINT_IN(mode, ep_size, ep_num, _buffer_capacity, _usb_requests_cb, _report_storage) \
  32. { \
  33. .usb_requests_cb = _usb_requests_cb, .report_storage = _report_storage, \
  34. .ep_config = \
  35. { \
  36. mode, /* EP Mode */ \
  37. NULL, /* SETUP packet notification callback */ \
  38. usb_endpoint_in_tx_complete_cb, /* IN notification callback */ \
  39. NULL, /* OUT notification callback */ \
  40. ep_size, /* IN maximum packet size */ \
  41. 0, /* OUT maximum packet size */ \
  42. NULL, /* IN Endpoint state */ \
  43. NULL, /* OUT endpoint state */ \
  44. usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \
  45. }, \
  46. .config = { \
  47. .usbp = &USB_DRIVER, \
  48. .ep = ep_num, \
  49. .buffer_capacity = _buffer_capacity, \
  50. .buffer_size = ep_size, \
  51. .buffer = (_Alignas(4) uint8_t[BQ_BUFFER_SIZE(_buffer_capacity, ep_size)]){0}, \
  52. } \
  53. }
  54. #if !defined(USB_ENDPOINTS_ARE_REORDERABLE)
  55. # define QMK_USB_ENDPOINT_OUT(mode, ep_size, ep_num, _buffer_capacity) \
  56. { \
  57. .ep_config = \
  58. { \
  59. mode, /* EP Mode */ \
  60. NULL, /* SETUP packet notification callback */ \
  61. NULL, /* IN notification callback */ \
  62. usb_endpoint_out_rx_complete_cb, /* OUT notification callback */ \
  63. 0, /* IN maximum packet size */ \
  64. ep_size, /* OUT maximum packet size */ \
  65. NULL, /* IN Endpoint state */ \
  66. NULL, /* OUT endpoint state */ \
  67. usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \
  68. }, \
  69. .config = { \
  70. .usbp = &USB_DRIVER, \
  71. .ep = ep_num, \
  72. .buffer_capacity = _buffer_capacity, \
  73. .buffer_size = ep_size, \
  74. .buffer = (_Alignas(4) uint8_t[BQ_BUFFER_SIZE(_buffer_capacity, ep_size)]){0} \
  75. } \
  76. }
  77. #else
  78. # define QMK_USB_ENDPOINT_IN_SHARED(mode, ep_size, ep_num, _buffer_capacity, _usb_requests_cb, _report_storage) \
  79. { \
  80. .usb_requests_cb = _usb_requests_cb, .is_shared = true, .report_storage = _report_storage, \
  81. .ep_config = \
  82. { \
  83. mode, /* EP Mode */ \
  84. NULL, /* SETUP packet notification callback */ \
  85. usb_endpoint_in_tx_complete_cb, /* IN notification callback */ \
  86. usb_endpoint_out_rx_complete_cb, /* OUT notification callback */ \
  87. ep_size, /* IN maximum packet size */ \
  88. ep_size, /* OUT maximum packet size */ \
  89. NULL, /* IN Endpoint state */ \
  90. NULL, /* OUT endpoint state */ \
  91. usb_lld_endpoint_fields /* USB driver specific endpoint fields */ \
  92. }, \
  93. .config = { \
  94. .usbp = &USB_DRIVER, \
  95. .ep = ep_num, \
  96. .buffer_capacity = _buffer_capacity, \
  97. .buffer_size = ep_size, \
  98. .buffer = (_Alignas(4) uint8_t[BQ_BUFFER_SIZE(_buffer_capacity, ep_size)]){0}, \
  99. } \
  100. }
  101. /* The current assumption is that there are no standalone OUT endpoints, so the
  102. * OUT endpoint is always initialized by the IN endpoint. */
  103. # define QMK_USB_ENDPOINT_OUT(mode, ep_size, ep_num, _buffer_capacity) \
  104. { \
  105. .ep_config = \
  106. { \
  107. 0 /* Already defined in the IN endpoint */ \
  108. }, \
  109. .config = { \
  110. .usbp = &USB_DRIVER, \
  111. .ep = ep_num, \
  112. .buffer_capacity = _buffer_capacity, \
  113. .buffer_size = ep_size, \
  114. .buffer = (_Alignas(4) uint8_t[BQ_BUFFER_SIZE(_buffer_capacity, ep_size)]){0} \
  115. } \
  116. }
  117. #endif
  118. typedef struct {
  119. /**
  120. * @brief USB driver to use.
  121. */
  122. USBDriver *usbp;
  123. /**
  124. * @brief Endpoint used for data transfer
  125. */
  126. usbep_t ep;
  127. /**
  128. * @brief The number of buffers in the queue
  129. */
  130. size_t buffer_capacity;
  131. /**
  132. * @brief The size of each buffer in the queue, same as the endpoint size
  133. */
  134. size_t buffer_size;
  135. /**
  136. * @brief Buffer backing storage
  137. */
  138. uint8_t *buffer;
  139. } usb_endpoint_config_t;
  140. typedef struct {
  141. output_buffers_queue_t obqueue;
  142. USBEndpointConfig ep_config;
  143. USBInEndpointState ep_in_state;
  144. #if defined(USB_ENDPOINTS_ARE_REORDERABLE)
  145. USBOutEndpointState ep_out_state;
  146. bool is_shared;
  147. #endif
  148. usb_endpoint_config_t config;
  149. usbreqhandler_t usb_requests_cb;
  150. bool timed_out;
  151. usb_report_storage_t *report_storage;
  152. } usb_endpoint_in_t;
  153. typedef struct {
  154. input_buffers_queue_t ibqueue;
  155. USBEndpointConfig ep_config;
  156. USBOutEndpointState ep_out_state;
  157. usb_endpoint_config_t config;
  158. bool timed_out;
  159. } usb_endpoint_out_t;
  160. #ifdef __cplusplus
  161. extern "C" {
  162. #endif
  163. void usb_endpoint_in_init(usb_endpoint_in_t *endpoint);
  164. void usb_endpoint_in_start(usb_endpoint_in_t *endpoint);
  165. void usb_endpoint_in_stop(usb_endpoint_in_t *endpoint);
  166. bool usb_endpoint_in_send(usb_endpoint_in_t *endpoint, const uint8_t *data, size_t size, sysinterval_t timeout, bool buffered);
  167. void usb_endpoint_in_flush(usb_endpoint_in_t *endpoint, bool padded);
  168. bool usb_endpoint_in_is_inactive(usb_endpoint_in_t *endpoint);
  169. void usb_endpoint_in_suspend_cb(usb_endpoint_in_t *endpoint);
  170. void usb_endpoint_in_wakeup_cb(usb_endpoint_in_t *endpoint);
  171. void usb_endpoint_in_configure_cb(usb_endpoint_in_t *endpoint);
  172. void usb_endpoint_in_tx_complete_cb(USBDriver *usbp, usbep_t ep);
  173. void usb_endpoint_out_init(usb_endpoint_out_t *endpoint);
  174. void usb_endpoint_out_start(usb_endpoint_out_t *endpoint);
  175. void usb_endpoint_out_stop(usb_endpoint_out_t *endpoint);
  176. bool usb_endpoint_out_receive(usb_endpoint_out_t *endpoint, uint8_t *data, size_t size, sysinterval_t timeout);
  177. void usb_endpoint_out_suspend_cb(usb_endpoint_out_t *endpoint);
  178. void usb_endpoint_out_wakeup_cb(usb_endpoint_out_t *endpoint);
  179. void usb_endpoint_out_configure_cb(usb_endpoint_out_t *endpoint);
  180. void usb_endpoint_out_rx_complete_cb(USBDriver *usbp, usbep_t ep);
  181. #ifdef __cplusplus
  182. }
  183. #endif
  184. /** @} */