diff options
| author | fredizzimo <fsundvik@gmail.com> | 2018-04-16 03:42:53 +0300 |
|---|---|---|
| committer | Jack Humbert <jack.humb@gmail.com> | 2018-04-15 20:42:53 -0400 |
| commit | e9d32b60b7f103cda42a19c5216e65b7b64ce9eb (patch) | |
| tree | a954db818d58a86ee5bb4189568de82a453b11e8 | |
| parent | e2fb3079c7168ba109dfeeec20931ad75870186a (diff) | |
| download | qmk_firmware-e9d32b60b7f103cda42a19c5216e65b7b64ce9eb.tar.gz qmk_firmware-e9d32b60b7f103cda42a19c5216e65b7b64ce9eb.zip | |
Add a custom USB driver for ARM (#2750)
* Copy Chibios serial_usb_driver into the chibios/protocol
It's renamed to usb_driver to avoid name conflicts
* Make the usb driver compile
* Disable ChibiOS serial usb driver for all keyboards
* Change usb_main to use QMKUSBDriver
* Initialize the usb driver buffers
* Add support for fixed size queues
* Fix USB driver initialization
* Don't transfer an empty packet for fixed size streams
| -rw-r--r-- | keyboards/chibios_test/stm32_f072_onekey/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/chibios_test/stm32_f103_onekey/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/chibios_test/teensy_lc_onekey/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/clueboard/60/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/ergodox_infinity/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/infinity60/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/jm60/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/k_type/halconf.h | 2 | ||||
| -rw-r--r-- | keyboards/whitefox/halconf.h | 2 | ||||
| -rw-r--r-- | tmk_core/protocol/chibios.mk | 1 | ||||
| -rw-r--r-- | tmk_core/protocol/chibios/usb_driver.c | 502 | ||||
| -rw-r--r-- | tmk_core/protocol/chibios/usb_driver.h | 184 | ||||
| -rw-r--r-- | tmk_core/protocol/chibios/usb_main.c | 84 |
13 files changed, 738 insertions, 51 deletions
diff --git a/keyboards/chibios_test/stm32_f072_onekey/halconf.h b/keyboards/chibios_test/stm32_f072_onekey/halconf.h index 762572558..8b9724b1a 100644 --- a/keyboards/chibios_test/stm32_f072_onekey/halconf.h +++ b/keyboards/chibios_test/stm32_f072_onekey/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/chibios_test/stm32_f103_onekey/halconf.h b/keyboards/chibios_test/stm32_f103_onekey/halconf.h index 762572558..8b9724b1a 100644 --- a/keyboards/chibios_test/stm32_f103_onekey/halconf.h +++ b/keyboards/chibios_test/stm32_f103_onekey/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/chibios_test/teensy_lc_onekey/halconf.h b/keyboards/chibios_test/teensy_lc_onekey/halconf.h index 5e1f6a8a1..1b6f2adc2 100644 --- a/keyboards/chibios_test/teensy_lc_onekey/halconf.h +++ b/keyboards/chibios_test/teensy_lc_onekey/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/clueboard/60/halconf.h b/keyboards/clueboard/60/halconf.h index 8fe8e0c6f..e617fdffc 100644 --- a/keyboards/clueboard/60/halconf.h +++ b/keyboards/clueboard/60/halconf.h | |||
| @@ -146,7 +146,7 @@ | |||
| 146 | * @brief Enables the SERIAL over USB subsystem. | 146 | * @brief Enables the SERIAL over USB subsystem. |
| 147 | */ | 147 | */ |
| 148 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 148 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 149 | #define HAL_USE_SERIAL_USB TRUE | 149 | #define HAL_USE_SERIAL_USB FALSE |
| 150 | #endif | 150 | #endif |
| 151 | 151 | ||
| 152 | /** | 152 | /** |
diff --git a/keyboards/ergodox_infinity/halconf.h b/keyboards/ergodox_infinity/halconf.h index 3f4ffb7be..ade55ae72 100644 --- a/keyboards/ergodox_infinity/halconf.h +++ b/keyboards/ergodox_infinity/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/infinity60/halconf.h b/keyboards/infinity60/halconf.h index f48413c6d..b87b0635c 100644 --- a/keyboards/infinity60/halconf.h +++ b/keyboards/infinity60/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/jm60/halconf.h b/keyboards/jm60/halconf.h index 762572558..8b9724b1a 100644 --- a/keyboards/jm60/halconf.h +++ b/keyboards/jm60/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/k_type/halconf.h b/keyboards/k_type/halconf.h index f48413c6d..b87b0635c 100644 --- a/keyboards/k_type/halconf.h +++ b/keyboards/k_type/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/whitefox/halconf.h b/keyboards/whitefox/halconf.h index f48413c6d..b87b0635c 100644 --- a/keyboards/whitefox/halconf.h +++ b/keyboards/whitefox/halconf.h | |||
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/tmk_core/protocol/chibios.mk b/tmk_core/protocol/chibios.mk index 6e7cfbd83..222fb4dad 100644 --- a/tmk_core/protocol/chibios.mk +++ b/tmk_core/protocol/chibios.mk | |||
| @@ -5,6 +5,7 @@ CHIBIOS_DIR = $(PROTOCOL_DIR)/chibios | |||
| 5 | SRC += $(CHIBIOS_DIR)/usb_main.c | 5 | SRC += $(CHIBIOS_DIR)/usb_main.c |
| 6 | SRC += $(CHIBIOS_DIR)/main.c | 6 | SRC += $(CHIBIOS_DIR)/main.c |
| 7 | SRC += usb_descriptor.c | 7 | SRC += usb_descriptor.c |
| 8 | SRC += $(CHIBIOS_DIR)/usb_driver.c | ||
| 8 | 9 | ||
| 9 | VPATH += $(TMK_PATH)/$(PROTOCOL_DIR) | 10 | VPATH += $(TMK_PATH)/$(PROTOCOL_DIR) |
| 10 | VPATH += $(TMK_PATH)/$(CHIBIOS_DIR) | 11 | VPATH += $(TMK_PATH)/$(CHIBIOS_DIR) |
diff --git a/tmk_core/protocol/chibios/usb_driver.c b/tmk_core/protocol/chibios/usb_driver.c new file mode 100644 index 000000000..fe535eeb3 --- /dev/null +++ b/tmk_core/protocol/chibios/usb_driver.c | |||
| @@ -0,0 +1,502 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** | ||
| 18 | * @file hal_serial_usb.c | ||
| 19 | * @brief Serial over USB Driver code. | ||
| 20 | * | ||
| 21 | * @addtogroup SERIAL_USB | ||
| 22 | * @{ | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "hal.h" | ||
| 26 | #include "usb_driver.h" | ||
| 27 | #include <string.h> | ||
| 28 | |||
| 29 | /*===========================================================================*/ | ||
| 30 | /* Driver local definitions. */ | ||
| 31 | /*===========================================================================*/ | ||
| 32 | |||
| 33 | /*===========================================================================*/ | ||
| 34 | /* Driver exported variables. */ | ||
| 35 | /*===========================================================================*/ | ||
| 36 | |||
| 37 | /*===========================================================================*/ | ||
| 38 | /* Driver local variables and types. */ | ||
| 39 | /*===========================================================================*/ | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Current Line Coding. | ||
| 43 | */ | ||
| 44 | static cdc_linecoding_t linecoding = { | ||
| 45 | {0x00, 0x96, 0x00, 0x00}, /* 38400. */ | ||
| 46 | LC_STOP_1, LC_PARITY_NONE, 8 | ||
| 47 | }; | ||
| 48 | |||
| 49 | /*===========================================================================*/ | ||
| 50 | /* Driver local functions. */ | ||
| 51 | /*===========================================================================*/ | ||
| 52 | |||
| 53 | static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) { | ||
| 54 | uint8_t *buf; | ||
| 55 | |||
| 56 | /* If the USB driver is not in the appropriate state then transactions | ||
| 57 | must not be started.*/ | ||
| 58 | if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || | ||
| 59 | (qmkusbp->state != QMKUSB_READY)) { | ||
| 60 | return true; | ||
| 61 | } | ||
| 62 | |||
| 63 | /* Checking if there is already a transaction ongoing on the endpoint.*/ | ||
| 64 | if (usbGetReceiveStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) { | ||
| 65 | return true; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* Checking if there is a buffer ready for incoming data.*/ | ||
| 69 | buf = ibqGetEmptyBufferI(&qmkusbp->ibqueue); | ||
| 70 | if (buf == NULL) { | ||
| 71 | return true; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* Buffer found, starting a new transaction.*/ | ||
| 75 | usbStartReceiveI(qmkusbp->config->usbp, qmkusbp->config->bulk_out, | ||
| 76 | buf, qmkusbp->ibqueue.bsize - sizeof(size_t)); | ||
| 77 | |||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Interface implementation. | ||
| 83 | */ | ||
| 84 | |||
| 85 | static size_t _write(void *ip, const uint8_t *bp, size_t n) { | ||
| 86 | |||
| 87 | return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, | ||
| 88 | n, TIME_INFINITE); | ||
| 89 | } | ||
| 90 | |||
| 91 | static size_t _read(void *ip, uint8_t *bp, size_t n) { | ||
| 92 | |||
| 93 | return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, | ||
| 94 | n, TIME_INFINITE); | ||
| 95 | } | ||
| 96 | |||
| 97 | static msg_t _put(void *ip, uint8_t b) { | ||
| 98 | |||
| 99 | return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, TIME_INFINITE); | ||
| 100 | } | ||
| 101 | |||
| 102 | static msg_t _get(void *ip) { | ||
| 103 | |||
| 104 | return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, TIME_INFINITE); | ||
| 105 | } | ||
| 106 | |||
| 107 | static msg_t _putt(void *ip, uint8_t b, systime_t timeout) { | ||
| 108 | |||
| 109 | return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, timeout); | ||
| 110 | } | ||
| 111 | |||
| 112 | static msg_t _gett(void *ip, systime_t timeout) { | ||
| 113 | |||
| 114 | return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, timeout); | ||
| 115 | } | ||
| 116 | |||
| 117 | static size_t _writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { | ||
| 118 | |||
| 119 | return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, timeout); | ||
| 120 | } | ||
| 121 | |||
| 122 | static size_t _readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { | ||
| 123 | |||
| 124 | return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, timeout); | ||
| 125 | } | ||
| 126 | |||
| 127 | static const struct QMKUSBDriverVMT vmt = { | ||
| 128 | _write, _read, _put, _get, | ||
| 129 | _putt, _gett, _writet, _readt | ||
| 130 | }; | ||
| 131 | |||
| 132 | /** | ||
| 133 | * @brief Notification of empty buffer released into the input buffers queue. | ||
| 134 | * | ||
| 135 | * @param[in] bqp the buffers queue pointer. | ||
| 136 | */ | ||
| 137 | static void ibnotify(io_buffers_queue_t *bqp) { | ||
| 138 | QMKUSBDriver *qmkusbp = bqGetLinkX(bqp); | ||
| 139 | (void) qmkusb_start_receive(qmkusbp); | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * @brief Notification of filled buffer inserted into the output buffers queue. | ||
| 144 | * | ||
| 145 | * @param[in] bqp the buffers queue pointer. | ||
| 146 | */ | ||
| 147 | static void obnotify(io_buffers_queue_t *bqp) { | ||
| 148 | size_t n; | ||
| 149 | QMKUSBDriver *qmkusbp = bqGetLinkX(bqp); | ||
| 150 | |||
| 151 | /* If the USB driver is not in the appropriate state then transactions | ||
| 152 | must not be started.*/ | ||
| 153 | if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || | ||
| 154 | (qmkusbp->state != QMKUSB_READY)) { | ||
| 155 | return; | ||
| 156 | } | ||
| 157 | |||
| 158 | /* Checking if there is already a transaction ongoing on the endpoint.*/ | ||
| 159 | if (!usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) { | ||
| 160 | /* Trying to get a full buffer.*/ | ||
| 161 | uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n); | ||
| 162 | if (buf != NULL) { | ||
| 163 | /* Buffer found, starting a new transaction.*/ | ||
| 164 | usbStartTransmitI(qmkusbp->config->usbp, qmkusbp->config->bulk_in, buf, n); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /*===========================================================================*/ | ||
| 170 | /* Driver exported functions. */ | ||
| 171 | /*===========================================================================*/ | ||
| 172 | |||
| 173 | /** | ||
| 174 | * @brief Serial Driver initialization. | ||
| 175 | * @note This function is implicitly invoked by @p halInit(), there is | ||
| 176 | * no need to explicitly initialize the driver. | ||
| 177 | * | ||
| 178 | * @init | ||
| 179 | */ | ||
| 180 | void qmkusbInit(void) { | ||
| 181 | } | ||
| 182 | |||
| 183 | /** | ||
| 184 | * @brief Initializes a generic full duplex driver object. | ||
| 185 | * @details The HW dependent part of the initialization has to be performed | ||
| 186 | * outside, usually in the hardware initialization code. | ||
| 187 | * | ||
| 188 | * @param[out] qmkusbp pointer to a @p QMKUSBDriver structure | ||
| 189 | * | ||
| 190 | * @init | ||
| 191 | */ | ||
| 192 | void qmkusbObjectInit(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config) { | ||
| 193 | |||
| 194 | qmkusbp->vmt = &vmt; | ||
| 195 | osalEventObjectInit(&qmkusbp->event); | ||
| 196 | qmkusbp->state = QMKUSB_STOP; | ||
| 197 | // Note that the config uses the USB direction naming | ||
| 198 | ibqObjectInit(&qmkusbp->ibqueue, true, config->ob, | ||
| 199 | config->out_size, config->out_buffers, | ||
| 200 | ibnotify, qmkusbp); | ||
| 201 | obqObjectInit(&qmkusbp->obqueue, true, config->ib, | ||
| 202 | config->in_size, config->in_buffers, | ||
| 203 | obnotify, qmkusbp); | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * @brief Configures and starts the driver. | ||
| 208 | * | ||
| 209 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 210 | * @param[in] config the serial over USB driver configuration | ||
| 211 | * | ||
| 212 | * @api | ||
| 213 | */ | ||
| 214 | void qmkusbStart(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config) { | ||
| 215 | USBDriver *usbp = config->usbp; | ||
| 216 | |||
| 217 | osalDbgCheck(qmkusbp != NULL); | ||
| 218 | |||
| 219 | osalSysLock(); | ||
| 220 | osalDbgAssert((qmkusbp->state == QMKUSB_STOP) || (qmkusbp->state == QMKUSB_READY), | ||
| 221 | "invalid state"); | ||
| 222 | usbp->in_params[config->bulk_in - 1U] = qmkusbp; | ||
| 223 | usbp->out_params[config->bulk_out - 1U] = qmkusbp; | ||
| 224 | if (config->int_in > 0U) { | ||
| 225 | usbp->in_params[config->int_in - 1U] = qmkusbp; | ||
| 226 | } | ||
| 227 | qmkusbp->config = config; | ||
| 228 | qmkusbp->state = QMKUSB_READY; | ||
| 229 | osalSysUnlock(); | ||
| 230 | } | ||
| 231 | |||
| 232 | /** | ||
| 233 | * @brief Stops the driver. | ||
| 234 | * @details Any thread waiting on the driver's queues will be awakened with | ||
| 235 | * the message @p MSG_RESET. | ||
| 236 | * | ||
| 237 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 238 | * | ||
| 239 | * @api | ||
| 240 | */ | ||
| 241 | void qmkusbStop(QMKUSBDriver *qmkusbp) { | ||
| 242 | USBDriver *usbp = qmkusbp->config->usbp; | ||
| 243 | |||
| 244 | osalDbgCheck(qmkusbp != NULL); | ||
| 245 | |||
| 246 | osalSysLock(); | ||
| 247 | |||
| 248 | osalDbgAssert((qmkusbp->state == QMKUSB_STOP) || (qmkusbp->state == QMKUSB_READY), | ||
| 249 | "invalid state"); | ||
| 250 | |||
| 251 | /* Driver in stopped state.*/ | ||
| 252 | usbp->in_params[qmkusbp->config->bulk_in - 1U] = NULL; | ||
| 253 | usbp->out_params[qmkusbp->config->bulk_out - 1U] = NULL; | ||
| 254 | if (qmkusbp->config->int_in > 0U) { | ||
| 255 | usbp->in_params[qmkusbp->config->int_in - 1U] = NULL; | ||
| 256 | } | ||
| 257 | qmkusbp->config = NULL; | ||
| 258 | qmkusbp->state = QMKUSB_STOP; | ||
| 259 | |||
| 260 | /* Enforces a disconnection.*/ | ||
| 261 | chnAddFlagsI(qmkusbp, CHN_DISCONNECTED); | ||
| 262 | ibqResetI(&qmkusbp->ibqueue); | ||
| 263 | obqResetI(&qmkusbp->obqueue); | ||
| 264 | osalOsRescheduleS(); | ||
| 265 | |||
| 266 | osalSysUnlock(); | ||
| 267 | } | ||
| 268 | |||
| 269 | /** | ||
| 270 | * @brief USB device suspend handler. | ||
| 271 | * @details Generates a @p CHN_DISCONNECT event and puts queues in | ||
| 272 | * non-blocking mode, this way the application cannot get stuck | ||
| 273 | * in the middle of an I/O operations. | ||
| 274 | * @note If this function is not called from an ISR then an explicit call | ||
| 275 | * to @p osalOsRescheduleS() in necessary afterward. | ||
| 276 | * | ||
| 277 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 278 | * | ||
| 279 | * @iclass | ||
| 280 | */ | ||
| 281 | void qmkusbSuspendHookI(QMKUSBDriver *qmkusbp) { | ||
| 282 | |||
| 283 | chnAddFlagsI(qmkusbp, CHN_DISCONNECTED); | ||
| 284 | bqSuspendI(&qmkusbp->ibqueue); | ||
| 285 | bqSuspendI(&qmkusbp->obqueue); | ||
| 286 | } | ||
| 287 | |||
| 288 | /** | ||
| 289 | * @brief USB device wakeup handler. | ||
| 290 | * @details Generates a @p CHN_CONNECT event and resumes normal queues | ||
| 291 | * operations. | ||
| 292 | * | ||
| 293 | * @note If this function is not called from an ISR then an explicit call | ||
| 294 | * to @p osalOsRescheduleS() in necessary afterward. | ||
| 295 | * | ||
| 296 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 297 | * | ||
| 298 | * @iclass | ||
| 299 | */ | ||
| 300 | void qmkusbWakeupHookI(QMKUSBDriver *qmkusbp) { | ||
| 301 | |||
| 302 | chnAddFlagsI(qmkusbp, CHN_CONNECTED); | ||
| 303 | bqResumeX(&qmkusbp->ibqueue); | ||
| 304 | bqResumeX(&qmkusbp->obqueue); | ||
| 305 | } | ||
| 306 | |||
| 307 | /** | ||
| 308 | * @brief USB device configured handler. | ||
| 309 | * | ||
| 310 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 311 | * | ||
| 312 | * @iclass | ||
| 313 | */ | ||
| 314 | void qmkusbConfigureHookI(QMKUSBDriver *qmkusbp) { | ||
| 315 | |||
| 316 | ibqResetI(&qmkusbp->ibqueue); | ||
| 317 | bqResumeX(&qmkusbp->ibqueue); | ||
| 318 | obqResetI(&qmkusbp->obqueue); | ||
| 319 | bqResumeX(&qmkusbp->obqueue); | ||
| 320 | chnAddFlagsI(qmkusbp, CHN_CONNECTED); | ||
| 321 | (void) qmkusb_start_receive(qmkusbp); | ||
| 322 | } | ||
| 323 | |||
| 324 | /** | ||
| 325 | * @brief Default requests hook. | ||
| 326 | * @details Applications wanting to use the Serial over USB driver can use | ||
| 327 | * this function as requests hook in the USB configuration. | ||
| 328 | * The following requests are emulated: | ||
| 329 | * - CDC_GET_LINE_CODING. | ||
| 330 | * - CDC_SET_LINE_CODING. | ||
| 331 | * - CDC_SET_CONTROL_LINE_STATE. | ||
| 332 | * . | ||
| 333 | * | ||
| 334 | * @param[in] usbp pointer to the @p USBDriver object | ||
| 335 | * @return The hook status. | ||
| 336 | * @retval true Message handled internally. | ||
| 337 | * @retval false Message not handled. | ||
| 338 | */ | ||
| 339 | bool qmkusbRequestsHook(USBDriver *usbp) { | ||
| 340 | |||
| 341 | if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { | ||
| 342 | switch (usbp->setup[1]) { | ||
| 343 | case CDC_GET_LINE_CODING: | ||
| 344 | usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); | ||
| 345 | return true; | ||
| 346 | case CDC_SET_LINE_CODING: | ||
| 347 | usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); | ||
| 348 | return true; | ||
| 349 | case CDC_SET_CONTROL_LINE_STATE: | ||
| 350 | /* Nothing to do, there are no control lines.*/ | ||
| 351 | usbSetupTransfer(usbp, NULL, 0, NULL); | ||
| 352 | return true; | ||
| 353 | default: | ||
| 354 | return false; | ||
| 355 | } | ||
| 356 | } | ||
| 357 | return false; | ||
| 358 | } | ||
| 359 | |||
| 360 | /** | ||
| 361 | * @brief SOF handler. | ||
| 362 | * @details The SOF interrupt is used for automatic flushing of incomplete | ||
| 363 | * buffers pending in the output queue. | ||
| 364 | * | ||
| 365 | * @param[in] qmkusbp pointer to a @p QMKUSBDriver object | ||
| 366 | * | ||
| 367 | * @iclass | ||
| 368 | */ | ||
| 369 | void qmkusbSOFHookI(QMKUSBDriver *qmkusbp) { | ||
| 370 | |||
| 371 | /* If the USB driver is not in the appropriate state then transactions | ||
| 372 | must not be started.*/ | ||
| 373 | if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || | ||
| 374 | (qmkusbp->state != QMKUSB_READY)) { | ||
| 375 | return; | ||
| 376 | } | ||
| 377 | |||
| 378 | /* If there is already a transaction ongoing then another one cannot be | ||
| 379 | started.*/ | ||
| 380 | if (usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) { | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* Checking if there only a buffer partially filled, if so then it is | ||
| 385 | enforced in the queue and transmitted.*/ | ||
| 386 | if (obqTryFlushI(&qmkusbp->obqueue)) { | ||
| 387 | size_t n; | ||
| 388 | uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n); | ||
| 389 | |||
| 390 | /* For fixed size drivers, fill the end with zeros */ | ||
| 391 | if (qmkusbp->config->fixed_size) { | ||
| 392 | memset(buf + n, 0, qmkusbp->config->in_size - n); | ||
| 393 | n = qmkusbp->config->in_size; | ||
| 394 | } | ||
| 395 | |||
| 396 | osalDbgAssert(buf != NULL, "queue is empty"); | ||
| 397 | |||
| 398 | usbStartTransmitI(qmkusbp->config->usbp, qmkusbp->config->bulk_in, buf, n); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | /** | ||
| 403 | * @brief Default data transmitted callback. | ||
| 404 | * @details The application must use this function as callback for the IN | ||
| 405 | * data endpoint. | ||
| 406 | * | ||
| 407 | * @param[in] usbp pointer to the @p USBDriver object | ||
| 408 | * @param[in] ep IN endpoint number | ||
| 409 | */ | ||
| 410 | void qmkusbDataTransmitted(USBDriver *usbp, usbep_t ep) { | ||
| 411 | uint8_t *buf; | ||
| 412 | size_t n; | ||
| 413 | QMKUSBDriver *qmkusbp = usbp->in_params[ep - 1U]; | ||
| 414 | |||
| 415 | if (qmkusbp == NULL) { | ||
| 416 | return; | ||
| 417 | } | ||
| 418 | |||
| 419 | osalSysLockFromISR(); | ||
| 420 | |||
| 421 | /* Signaling that space is available in the output queue.*/ | ||
| 422 | chnAddFlagsI(qmkusbp, CHN_OUTPUT_EMPTY); | ||
| 423 | |||
| 424 | /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ | ||
| 425 | if (usbp->epc[ep]->in_state->txsize > 0U) { | ||
| 426 | obqReleaseEmptyBufferI(&qmkusbp->obqueue); | ||
| 427 | } | ||
| 428 | |||
| 429 | /* Checking if there is a buffer ready for transmission.*/ | ||
| 430 | buf = obqGetFullBufferI(&qmkusbp->obqueue, &n); | ||
| 431 | |||
| 432 | if (buf != NULL) { | ||
| 433 | /* The endpoint cannot be busy, we are in the context of the callback, | ||
| 434 | so it is safe to transmit without a check.*/ | ||
| 435 | usbStartTransmitI(usbp, ep, buf, n); | ||
| 436 | } | ||
| 437 | else if ((usbp->epc[ep]->in_state->txsize > 0U) && | ||
| 438 | ((usbp->epc[ep]->in_state->txsize & | ||
| 439 | ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { | ||
| 440 | /* Transmit zero sized packet in case the last one has maximum allowed | ||
| 441 | size. Otherwise the recipient may expect more data coming soon and | ||
| 442 | not return buffered data to app. See section 5.8.3 Bulk Transfer | ||
| 443 | Packet Size Constraints of the USB Specification document.*/ | ||
| 444 | if (!qmkusbp->config->fixed_size) { | ||
| 445 | usbStartTransmitI(usbp, ep, usbp->setup, 0); | ||
| 446 | } | ||
| 447 | |||
| 448 | } | ||
| 449 | else { | ||
| 450 | /* Nothing to transmit.*/ | ||
| 451 | } | ||
| 452 | |||
| 453 | osalSysUnlockFromISR(); | ||
| 454 | } | ||
| 455 | |||
| 456 | /** | ||
| 457 | * @brief Default data received callback. | ||
| 458 | * @details The application must use this function as callback for the OUT | ||
| 459 | * data endpoint. | ||
| 460 | * | ||
| 461 | * @param[in] usbp pointer to the @p USBDriver object | ||
| 462 | * @param[in] ep OUT endpoint number | ||
| 463 | */ | ||
| 464 | void qmkusbDataReceived(USBDriver *usbp, usbep_t ep) { | ||
| 465 | QMKUSBDriver *qmkusbp = usbp->out_params[ep - 1U]; | ||
| 466 | if (qmkusbp == NULL) { | ||
| 467 | return; | ||
| 468 | } | ||
| 469 | |||
| 470 | osalSysLockFromISR(); | ||
| 471 | |||
| 472 | /* Signaling that data is available in the input queue.*/ | ||
| 473 | chnAddFlagsI(qmkusbp, CHN_INPUT_AVAILABLE); | ||
| 474 | |||
| 475 | /* Posting the filled buffer in the queue.*/ | ||
| 476 | ibqPostFullBufferI(&qmkusbp->ibqueue, | ||
| 477 | usbGetReceiveTransactionSizeX(qmkusbp->config->usbp, | ||
| 478 | qmkusbp->config->bulk_out)); | ||
| 479 | |||
| 480 | /* The endpoint cannot be busy, we are in the context of the callback, | ||
| 481 | so a packet is in the buffer for sure. Trying to get a free buffer | ||
| 482 | for the next transaction.*/ | ||
| 483 | (void) qmkusb_start_receive(qmkusbp); | ||
| 484 | |||
| 485 | osalSysUnlockFromISR(); | ||
| 486 | } | ||
| 487 | |||
| 488 | /** | ||
| 489 | * @brief Default data received callback. | ||
| 490 | * @details The application must use this function as callback for the IN | ||
| 491 | * interrupt endpoint. | ||
| 492 | * | ||
| 493 | * @param[in] usbp pointer to the @p USBDriver object | ||
| 494 | * @param[in] ep endpoint number | ||
| 495 | */ | ||
| 496 | void qmkusbInterruptTransmitted(USBDriver *usbp, usbep_t ep) { | ||
| 497 | |||
| 498 | (void)usbp; | ||
| 499 | (void)ep; | ||
| 500 | } | ||
| 501 | |||
| 502 | /** @} */ | ||
diff --git a/tmk_core/protocol/chibios/usb_driver.h b/tmk_core/protocol/chibios/usb_driver.h new file mode 100644 index 000000000..558479e19 --- /dev/null +++ b/tmk_core/protocol/chibios/usb_driver.h | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | /* | ||
| 2 | ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio | ||
| 3 | |||
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | you may not use this file except in compliance with the License. | ||
| 6 | You may obtain a copy of the License at | ||
| 7 | |||
| 8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | |||
| 10 | Unless required by applicable law or agreed to in writing, software | ||
| 11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | See the License for the specific language governing permissions and | ||
| 14 | limitations under the License. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /** | ||
| 18 | * @file usb_driver.h | ||
| 19 | * @brief Usb driver suitable for both packet and serial formats | ||
| 20 | * | ||
| 21 | * @addtogroup SERIAL_USB | ||
| 22 | * @{ | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef USB_DRIVER_H | ||
| 26 | #define USB_DRIVER_H | ||
| 27 | |||
| 28 | #include "hal_usb_cdc.h" | ||
| 29 | |||
| 30 | /*===========================================================================*/ | ||
| 31 | /* Driver constants. */ | ||
| 32 | /*===========================================================================*/ | ||
| 33 | |||
| 34 | /*===========================================================================*/ | ||
| 35 | /* Derived constants and error checks. */ | ||
| 36 | /*===========================================================================*/ | ||
| 37 | |||
| 38 | #if HAL_USE_USB == FALSE | ||
| 39 | #error "The USB Driver requires HAL_USE_USB" | ||
| 40 | #endif | ||
| 41 | |||
| 42 | /*===========================================================================*/ | ||
| 43 | /* Driver data structures and types. */ | ||
| 44 | /*===========================================================================*/ | ||
| 45 | |||
| 46 | /** | ||
| 47 | * @brief Driver state machine possible states. | ||
| 48 | */ | ||
| 49 | typedef enum { | ||
| 50 | QMKUSB_UNINIT = 0, /**< Not initialized. */ | ||
| 51 | QMKUSB_STOP = 1, /**< Stopped. */ | ||
| 52 | QMKUSB_READY = 2 /**< Ready. */ | ||
| 53 | } qmkusbstate_t; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * @brief Structure representing a serial over USB driver. | ||
| 57 | */ | ||
| 58 | typedef struct QMKUSBDriver QMKUSBDriver; | ||
| 59 | |||
| 60 | /** | ||
| 61 | * @brief Serial over USB Driver configuration structure. | ||
| 62 | * @details An instance of this structure must be passed to @p sduStart() | ||
| 63 | * in order to configure and start the driver operations. | ||
| 64 | */ | ||
| 65 | typedef struct { | ||
| 66 | /** | ||
| 67 | * @brief USB driver to use. | ||
| 68 | */ | ||
| 69 | USBDriver *usbp; | ||
| 70 | /** | ||
| 71 | * @brief Bulk IN endpoint used for outgoing data transfer. | ||
| 72 | */ | ||
| 73 | usbep_t bulk_in; | ||
| 74 | /** | ||
| 75 | * @brief Bulk OUT endpoint used for incoming data transfer. | ||
| 76 | */ | ||
| 77 | usbep_t bulk_out; | ||
| 78 | /** | ||
| 79 | * @brief Interrupt IN endpoint used for notifications. | ||
| 80 | * @note If set to zero then the INT endpoint is assumed to be not | ||
| 81 | * present, USB descriptors must be changed accordingly. | ||
| 82 | */ | ||
| 83 | usbep_t int_in; | ||
| 84 | |||
| 85 | /** | ||
| 86 | * @brief The number of buffers in the queues | ||
| 87 | */ | ||
| 88 | size_t in_buffers; | ||
| 89 | size_t out_buffers; | ||
| 90 | |||
| 91 | /** | ||
| 92 | * @brief The size of each buffer in the queue, typically the same as the endpoint size | ||
| 93 | */ | ||
| 94 | size_t in_size; | ||
| 95 | size_t out_size; | ||
| 96 | |||
| 97 | /** | ||
| 98 | * @brief Always send full buffers in_size (the rest is filled with zeroes) | ||
| 99 | */ | ||
| 100 | bool fixed_size; | ||
| 101 | |||
| 102 | /* Input buffer | ||
| 103 | * @note needs to be initialized with a memory buffer of the right size | ||
| 104 | */ | ||
| 105 | uint8_t* ib; | ||
| 106 | /* Output buffer | ||
| 107 | * @note needs to be initialized with a memory buffer of the right size | ||
| 108 | */ | ||
| 109 | uint8_t* ob; | ||
| 110 | } QMKUSBConfig; | ||
| 111 | |||
| 112 | /** | ||
| 113 | * @brief @p SerialDriver specific data. | ||
| 114 | */ | ||
| 115 | #define _qmk_usb_driver_data \ | ||
| 116 | _base_asynchronous_channel_data \ | ||
| 117 | /* Driver state.*/ \ | ||
| 118 | qmkusbstate_t state; \ | ||
| 119 | /* Input buffers queue.*/ \ | ||
| 120 | input_buffers_queue_t ibqueue; \ | ||
| 121 | /* Output queue.*/ \ | ||
| 122 | output_buffers_queue_t obqueue; \ | ||
| 123 | /* End of the mandatory fields.*/ \ | ||
| 124 | /* Current configuration data.*/ \ | ||
| 125 | const QMKUSBConfig *config; | ||
| 126 | |||
| 127 | /** | ||
| 128 | * @brief @p SerialUSBDriver specific methods. | ||
| 129 | */ | ||
| 130 | #define _qmk_usb_driver_methods \ | ||
| 131 | _base_asynchronous_channel_methods | ||
| 132 | |||
| 133 | /** | ||
| 134 | * @extends BaseAsynchronousChannelVMT | ||
| 135 | * | ||
| 136 | * @brief @p SerialDriver virtual methods table. | ||
| 137 | */ | ||
| 138 | struct QMKUSBDriverVMT { | ||
| 139 | _qmk_usb_driver_methods | ||
| 140 | }; | ||
| 141 | |||
| 142 | /** | ||
| 143 | * @extends BaseAsynchronousChannel | ||
| 144 | * | ||
| 145 | * @brief Full duplex serial driver class. | ||
| 146 | * @details This class extends @p BaseAsynchronousChannel by adding physical | ||
| 147 | * I/O queues. | ||
| 148 | */ | ||
| 149 | struct QMKUSBDriver { | ||
| 150 | /** @brief Virtual Methods Table.*/ | ||
| 151 | const struct QMKUSBDriverVMT *vmt; | ||
| 152 | _qmk_usb_driver_data | ||
| 153 | }; | ||
| 154 | |||
| 155 | /*===========================================================================*/ | ||
| 156 | /* Driver macros. */ | ||
| 157 | /*===========================================================================*/ | ||
| 158 | |||
| 159 | /*===========================================================================*/ | ||
| 160 | /* External declarations. */ | ||
| 161 | /*===========================================================================*/ | ||
| 162 | |||
| 163 | #ifdef __cplusplus | ||
| 164 | extern "C" { | ||
| 165 | #endif | ||
| 166 | void qmkusbInit(void); | ||
| 167 | void qmkusbObjectInit(QMKUSBDriver *qmkusbp, const QMKUSBConfig * config); | ||
| 168 | void qmkusbStart(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config); | ||
| 169 | void qmkusbStop(QMKUSBDriver *qmkusbp); | ||
| 170 | void qmkusbSuspendHookI(QMKUSBDriver *qmkusbp); | ||
| 171 | void qmkusbWakeupHookI(QMKUSBDriver *qmkusbp); | ||
| 172 | void qmkusbConfigureHookI(QMKUSBDriver *qmkusbp); | ||
| 173 | bool qmkusbRequestsHook(USBDriver *usbp); | ||
| 174 | void qmkusbSOFHookI(QMKUSBDriver *qmkusbp); | ||
| 175 | void qmkusbDataTransmitted(USBDriver *usbp, usbep_t ep); | ||
| 176 | void qmkusbDataReceived(USBDriver *usbp, usbep_t ep); | ||
| 177 | void qmkusbInterruptTransmitted(USBDriver *usbp, usbep_t ep); | ||
| 178 | #ifdef __cplusplus | ||
| 179 | } | ||
| 180 | #endif | ||
| 181 | |||
| 182 | #endif /* USB_DRIVER_H */ | ||
| 183 | |||
| 184 | /** @} */ | ||
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c index f980024ab..cbe257194 100644 --- a/tmk_core/protocol/chibios/usb_main.c +++ b/tmk_core/protocol/chibios/usb_main.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #endif | 29 | #endif |
| 30 | #include "wait.h" | 30 | #include "wait.h" |
| 31 | #include "usb_descriptor.h" | 31 | #include "usb_descriptor.h" |
| 32 | #include "usb_driver.h" | ||
| 32 | 33 | ||
| 33 | #ifdef NKRO_ENABLE | 34 | #ifdef NKRO_ENABLE |
| 34 | #include "keycode_config.h" | 35 | #include "keycode_config.h" |
| @@ -170,27 +171,23 @@ static const USBEndpointConfig nkro_ep_config = { | |||
| 170 | typedef struct { | 171 | typedef struct { |
| 171 | size_t queue_capacity_in; | 172 | size_t queue_capacity_in; |
| 172 | size_t queue_capacity_out; | 173 | size_t queue_capacity_out; |
| 173 | uint8_t* queue_buffer_in; | ||
| 174 | uint8_t* queue_buffer_out; | ||
| 175 | USBInEndpointState in_ep_state; | 174 | USBInEndpointState in_ep_state; |
| 176 | USBOutEndpointState out_ep_state; | 175 | USBOutEndpointState out_ep_state; |
| 177 | USBInEndpointState int_ep_state; | 176 | USBInEndpointState int_ep_state; |
| 178 | USBEndpointConfig in_ep_config; | 177 | USBEndpointConfig in_ep_config; |
| 179 | USBEndpointConfig out_ep_config; | 178 | USBEndpointConfig out_ep_config; |
| 180 | USBEndpointConfig int_ep_config; | 179 | USBEndpointConfig int_ep_config; |
| 181 | const SerialUSBConfig config; | 180 | const QMKUSBConfig config; |
| 182 | SerialUSBDriver driver; | 181 | QMKUSBDriver driver; |
| 183 | } stream_driver_t; | 182 | } usb_driver_config_t; |
| 184 | 183 | ||
| 185 | #define STREAM_DRIVER(stream, notification) { \ | 184 | #define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) { \ |
| 186 | .queue_capacity_in = stream##_IN_CAPACITY, \ | 185 | .queue_capacity_in = stream##_IN_CAPACITY, \ |
| 187 | .queue_capacity_out = stream##_OUT_CAPACITY, \ | 186 | .queue_capacity_out = stream##_OUT_CAPACITY, \ |
| 188 | .queue_buffer_in = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \ | ||
| 189 | .queue_buffer_out = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \ | ||
| 190 | .in_ep_config = { \ | 187 | .in_ep_config = { \ |
| 191 | .ep_mode = stream##_IN_MODE, \ | 188 | .ep_mode = stream##_IN_MODE, \ |
| 192 | .setup_cb = NULL, \ | 189 | .setup_cb = NULL, \ |
| 193 | .in_cb = sduDataTransmitted, \ | 190 | .in_cb = qmkusbDataTransmitted, \ |
| 194 | .out_cb = NULL, \ | 191 | .out_cb = NULL, \ |
| 195 | .in_maxsize = stream##_EPSIZE, \ | 192 | .in_maxsize = stream##_EPSIZE, \ |
| 196 | .out_maxsize = 0, \ | 193 | .out_maxsize = 0, \ |
| @@ -204,7 +201,7 @@ typedef struct { | |||
| 204 | .ep_mode = stream##_OUT_MODE, \ | 201 | .ep_mode = stream##_OUT_MODE, \ |
| 205 | .setup_cb = NULL, \ | 202 | .setup_cb = NULL, \ |
| 206 | .in_cb = NULL, \ | 203 | .in_cb = NULL, \ |
| 207 | .out_cb = sduDataReceived, \ | 204 | .out_cb = qmkusbDataReceived, \ |
| 208 | .in_maxsize = 0, \ | 205 | .in_maxsize = 0, \ |
| 209 | .out_maxsize = stream##_EPSIZE, \ | 206 | .out_maxsize = stream##_EPSIZE, \ |
| 210 | /* The pointer to the states will be filled during initialization */ \ | 207 | /* The pointer to the states will be filled during initialization */ \ |
| @@ -216,7 +213,7 @@ typedef struct { | |||
| 216 | .int_ep_config = { \ | 213 | .int_ep_config = { \ |
| 217 | .ep_mode = USB_EP_MODE_TYPE_INTR, \ | 214 | .ep_mode = USB_EP_MODE_TYPE_INTR, \ |
| 218 | .setup_cb = NULL, \ | 215 | .setup_cb = NULL, \ |
| 219 | .in_cb = sduInterruptTransmitted, \ | 216 | .in_cb = qmkusbInterruptTransmitted, \ |
| 220 | .out_cb = NULL, \ | 217 | .out_cb = NULL, \ |
| 221 | .in_maxsize = CDC_NOTIFICATION_EPSIZE, \ | 218 | .in_maxsize = CDC_NOTIFICATION_EPSIZE, \ |
| 222 | .out_maxsize = 0, \ | 219 | .out_maxsize = 0, \ |
| @@ -230,7 +227,14 @@ typedef struct { | |||
| 230 | .usbp = &USB_DRIVER, \ | 227 | .usbp = &USB_DRIVER, \ |
| 231 | .bulk_in = stream##_IN_EPNUM, \ | 228 | .bulk_in = stream##_IN_EPNUM, \ |
| 232 | .bulk_out = stream##_OUT_EPNUM, \ | 229 | .bulk_out = stream##_OUT_EPNUM, \ |
| 233 | .int_in = notification \ | 230 | .int_in = notification, \ |
| 231 | .in_buffers = stream##_IN_CAPACITY, \ | ||
| 232 | .out_buffers = stream##_OUT_CAPACITY, \ | ||
| 233 | .in_size = stream##_EPSIZE, \ | ||
| 234 | .out_size = stream##_EPSIZE, \ | ||
| 235 | .fixed_size = fixedsize, \ | ||
| 236 | .ib = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \ | ||
| 237 | .ob = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \ | ||
| 234 | } \ | 238 | } \ |
| 235 | } | 239 | } |
| 236 | 240 | ||
| @@ -238,36 +242,36 @@ typedef struct { | |||
| 238 | union { | 242 | union { |
| 239 | struct { | 243 | struct { |
| 240 | #ifdef CONSOLE_ENABLE | 244 | #ifdef CONSOLE_ENABLE |
| 241 | stream_driver_t console_driver; | 245 | usb_driver_config_t console_driver; |
| 242 | #endif | 246 | #endif |
| 243 | #ifdef RAW_ENABLE | 247 | #ifdef RAW_ENABLE |
| 244 | stream_driver_t raw_driver; | 248 | usb_driver_config_t raw_driver; |
| 245 | #endif | 249 | #endif |
| 246 | #ifdef MIDI_ENABLE | 250 | #ifdef MIDI_ENABLE |
| 247 | stream_driver_t midi_driver; | 251 | usb_driver_config_t midi_driver; |
| 248 | #endif | 252 | #endif |
| 249 | #ifdef VIRTSER_ENABLE | 253 | #ifdef VIRTSER_ENABLE |
| 250 | stream_driver_t serial_driver; | 254 | usb_driver_config_t serial_driver; |
| 251 | #endif | 255 | #endif |
| 252 | }; | 256 | }; |
| 253 | stream_driver_t array[0]; | 257 | usb_driver_config_t array[0]; |
| 254 | }; | 258 | }; |
| 255 | } stream_drivers_t; | 259 | } usb_driver_configs_t; |
| 256 | 260 | ||
| 257 | static stream_drivers_t drivers = { | 261 | static usb_driver_configs_t drivers = { |
| 258 | #ifdef CONSOLE_ENABLE | 262 | #ifdef CONSOLE_ENABLE |
| 259 | #define CONSOLE_IN_CAPACITY 4 | 263 | #define CONSOLE_IN_CAPACITY 4 |
| 260 | #define CONSOLE_OUT_CAPACITY 4 | 264 | #define CONSOLE_OUT_CAPACITY 4 |
| 261 | #define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR | 265 | #define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR |
| 262 | #define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR | 266 | #define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR |
| 263 | .console_driver = STREAM_DRIVER(CONSOLE, 0), | 267 | .console_driver = QMK_USB_DRIVER_CONFIG(CONSOLE, 0, true), |
| 264 | #endif | 268 | #endif |
| 265 | #ifdef RAW_ENABLE | 269 | #ifdef RAW_ENABLE |
| 266 | #define RAW_IN_CAPACITY 4 | 270 | #define RAW_IN_CAPACITY 4 |
| 267 | #define RAW_OUT_CAPACITY 4 | 271 | #define RAW_OUT_CAPACITY 4 |
| 268 | #define RAW_IN_MODE USB_EP_MODE_TYPE_INTR | 272 | #define RAW_IN_MODE USB_EP_MODE_TYPE_INTR |
| 269 | #define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR | 273 | #define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR |
| 270 | .raw_driver = STREAM_DRIVER(RAW, 0), | 274 | .raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false), |
| 271 | #endif | 275 | #endif |
| 272 | 276 | ||
| 273 | #ifdef MIDI_ENABLE | 277 | #ifdef MIDI_ENABLE |
| @@ -275,7 +279,7 @@ static stream_drivers_t drivers = { | |||
| 275 | #define MIDI_STREAM_OUT_CAPACITY 4 | 279 | #define MIDI_STREAM_OUT_CAPACITY 4 |
| 276 | #define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK | 280 | #define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK |
| 277 | #define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK | 281 | #define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK |
| 278 | .midi_driver = STREAM_DRIVER(MIDI_STREAM, 0), | 282 | .midi_driver = QMK_USB_DRIVER_CONFIG(MIDI_STREAM, 0, false), |
| 279 | #endif | 283 | #endif |
| 280 | 284 | ||
| 281 | #ifdef VIRTSER_ENABLE | 285 | #ifdef VIRTSER_ENABLE |
| @@ -283,11 +287,11 @@ static stream_drivers_t drivers = { | |||
| 283 | #define CDC_OUT_CAPACITY 4 | 287 | #define CDC_OUT_CAPACITY 4 |
| 284 | #define CDC_IN_MODE USB_EP_MODE_TYPE_BULK | 288 | #define CDC_IN_MODE USB_EP_MODE_TYPE_BULK |
| 285 | #define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK | 289 | #define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK |
| 286 | .serial_driver = STREAM_DRIVER(CDC, CDC_NOTIFICATION_EPNUM), | 290 | .serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false), |
| 287 | #endif | 291 | #endif |
| 288 | }; | 292 | }; |
| 289 | 293 | ||
| 290 | #define NUM_STREAM_DRIVERS (sizeof(drivers) / sizeof(stream_driver_t)) | 294 | #define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t)) |
| 291 | 295 | ||
| 292 | 296 | ||
| 293 | /* --------------------------------------------------------- | 297 | /* --------------------------------------------------------- |
| @@ -315,13 +319,13 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) { | |||
| 315 | #ifdef NKRO_ENABLE | 319 | #ifdef NKRO_ENABLE |
| 316 | usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config); | 320 | usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config); |
| 317 | #endif /* NKRO_ENABLE */ | 321 | #endif /* NKRO_ENABLE */ |
| 318 | for (int i=0;i<NUM_STREAM_DRIVERS;i++) { | 322 | for (int i=0;i<NUM_USB_DRIVERS;i++) { |
| 319 | usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config); | 323 | usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config); |
| 320 | usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config); | 324 | usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config); |
| 321 | if (drivers.array[i].config.int_in) { | 325 | if (drivers.array[i].config.int_in) { |
| 322 | usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config); | 326 | usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config); |
| 323 | } | 327 | } |
| 324 | sduConfigureHookI(&drivers.array[i].driver); | 328 | qmkusbConfigureHookI(&drivers.array[i].driver); |
| 325 | } | 329 | } |
| 326 | osalSysUnlockFromISR(); | 330 | osalSysUnlockFromISR(); |
| 327 | return; | 331 | return; |
| @@ -333,20 +337,20 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) { | |||
| 333 | case USB_EVENT_UNCONFIGURED: | 337 | case USB_EVENT_UNCONFIGURED: |
| 334 | /* Falls into.*/ | 338 | /* Falls into.*/ |
| 335 | case USB_EVENT_RESET: | 339 | case USB_EVENT_RESET: |
| 336 | for (int i=0;i<NUM_STREAM_DRIVERS;i++) { | 340 | for (int i=0;i<NUM_USB_DRIVERS;i++) { |
| 337 | chSysLockFromISR(); | 341 | chSysLockFromISR(); |
| 338 | /* Disconnection event on suspend.*/ | 342 | /* Disconnection event on suspend.*/ |
| 339 | sduSuspendHookI(&drivers.array[i].driver); | 343 | qmkusbSuspendHookI(&drivers.array[i].driver); |
| 340 | chSysUnlockFromISR(); | 344 | chSysUnlockFromISR(); |
| 341 | } | 345 | } |
| 342 | return; | 346 | return; |
| 343 | 347 | ||
| 344 | case USB_EVENT_WAKEUP: | 348 | case USB_EVENT_WAKEUP: |
| 345 | //TODO: from ISR! print("[W]"); | 349 | //TODO: from ISR! print("[W]"); |
| 346 | for (int i=0;i<NUM_STREAM_DRIVERS;i++) { | 350 | for (int i=0;i<NUM_USB_DRIVERS;i++) { |
| 347 | chSysLockFromISR(); | 351 | chSysLockFromISR(); |
| 348 | /* Disconnection event on suspend.*/ | 352 | /* Disconnection event on suspend.*/ |
| 349 | sduWakeupHookI(&drivers.array[i].driver); | 353 | qmkusbWakeupHookI(&drivers.array[i].driver); |
| 350 | chSysUnlockFromISR(); | 354 | chSysUnlockFromISR(); |
| 351 | } | 355 | } |
| 352 | suspend_wakeup_init(); | 356 | suspend_wakeup_init(); |
| @@ -527,10 +531,10 @@ static bool usb_request_hook_cb(USBDriver *usbp) { | |||
| 527 | return TRUE; | 531 | return TRUE; |
| 528 | } | 532 | } |
| 529 | 533 | ||
| 530 | for (int i=0;i<NUM_STREAM_DRIVERS;i++) { | 534 | for (int i=0;i<NUM_USB_DRIVERS;i++) { |
| 531 | if (drivers.array[i].config.int_in) { | 535 | if (drivers.array[i].config.int_in) { |
| 532 | // NOTE: Assumes that we only have one serial driver | 536 | // NOTE: Assumes that we only have one serial driver |
| 533 | return sduRequestsHook(usbp); | 537 | return qmkusbRequestsHook(usbp); |
| 534 | } | 538 | } |
| 535 | } | 539 | } |
| 536 | 540 | ||
| @@ -541,8 +545,8 @@ static bool usb_request_hook_cb(USBDriver *usbp) { | |||
| 541 | static void usb_sof_cb(USBDriver *usbp) { | 545 | static void usb_sof_cb(USBDriver *usbp) { |
| 542 | kbd_sof_cb(usbp); | 546 | kbd_sof_cb(usbp); |
| 543 | osalSysLockFromISR(); | 547 | osalSysLockFromISR(); |
| 544 | for (int i=0; i<NUM_STREAM_DRIVERS;i++) { | 548 | for (int i=0; i<NUM_USB_DRIVERS;i++) { |
| 545 | sduSOFHookI(&drivers.array[i].driver); | 549 | qmkusbSOFHookI(&drivers.array[i].driver); |
| 546 | } | 550 | } |
| 547 | osalSysUnlockFromISR(); | 551 | osalSysUnlockFromISR(); |
| 548 | } | 552 | } |
| @@ -560,17 +564,13 @@ static const USBConfig usbcfg = { | |||
| 560 | * Initialize the USB driver | 564 | * Initialize the USB driver |
| 561 | */ | 565 | */ |
| 562 | void init_usb_driver(USBDriver *usbp) { | 566 | void init_usb_driver(USBDriver *usbp) { |
| 563 | for (int i=0; i<NUM_STREAM_DRIVERS;i++) { | 567 | for (int i=0; i<NUM_USB_DRIVERS;i++) { |
| 564 | SerialUSBDriver* driver = &drivers.array[i].driver; | 568 | QMKUSBDriver* driver = &drivers.array[i].driver; |
| 565 | drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state; | 569 | drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state; |
| 566 | drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state; | 570 | drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state; |
| 567 | drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state; | 571 | drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state; |
| 568 | sduObjectInit(driver); | 572 | qmkusbObjectInit(driver, &drivers.array[i].config); |
| 569 | bqnotify_t notify = driver->ibqueue.notify; | 573 | qmkusbStart(driver, &drivers.array[i].config); |
| 570 | ibqObjectInit(&driver->ibqueue, false, drivers.array[i].queue_buffer_in, drivers.array[i].in_ep_config.in_maxsize, drivers.array[i].queue_capacity_in, notify, driver); | ||
| 571 | notify = driver->obqueue.notify; | ||
| 572 | ibqObjectInit(&driver->ibqueue, false, drivers.array[i].queue_buffer_out, drivers.array[i].out_ep_config.out_maxsize, drivers.array[i].queue_capacity_out, notify, driver); | ||
| 573 | sduStart(driver, &drivers.array[i].config); | ||
| 574 | } | 574 | } |
| 575 | 575 | ||
| 576 | /* | 576 | /* |
