qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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 /** @} */