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