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
This commit is contained in:
parent
e2fb3079c7
commit
e9d32b60b7
13 changed files with 738 additions and 51 deletions
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -146,7 +146,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
* @brief Enables the SERIAL over USB subsystem.
|
* @brief Enables the SERIAL over USB subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_SERIAL_USB TRUE
|
#define HAL_USE_SERIAL_USB FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@ CHIBIOS_DIR = $(PROTOCOL_DIR)/chibios
|
||||||
SRC += $(CHIBIOS_DIR)/usb_main.c
|
SRC += $(CHIBIOS_DIR)/usb_main.c
|
||||||
SRC += $(CHIBIOS_DIR)/main.c
|
SRC += $(CHIBIOS_DIR)/main.c
|
||||||
SRC += usb_descriptor.c
|
SRC += usb_descriptor.c
|
||||||
|
SRC += $(CHIBIOS_DIR)/usb_driver.c
|
||||||
|
|
||||||
VPATH += $(TMK_PATH)/$(PROTOCOL_DIR)
|
VPATH += $(TMK_PATH)/$(PROTOCOL_DIR)
|
||||||
VPATH += $(TMK_PATH)/$(CHIBIOS_DIR)
|
VPATH += $(TMK_PATH)/$(CHIBIOS_DIR)
|
||||||
|
|
502
tmk_core/protocol/chibios/usb_driver.c
Normal file
502
tmk_core/protocol/chibios/usb_driver.c
Normal file
|
@ -0,0 +1,502 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file hal_serial_usb.c
|
||||||
|
* @brief Serial over USB Driver code.
|
||||||
|
*
|
||||||
|
* @addtogroup SERIAL_USB
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
#include "usb_driver.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Current Line Coding.
|
||||||
|
*/
|
||||||
|
static cdc_linecoding_t linecoding = {
|
||||||
|
{0x00, 0x96, 0x00, 0x00}, /* 38400. */
|
||||||
|
LC_STOP_1, LC_PARITY_NONE, 8
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) {
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
/* If the USB driver is not in the appropriate state then transactions
|
||||||
|
must not be started.*/
|
||||||
|
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) ||
|
||||||
|
(qmkusbp->state != QMKUSB_READY)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking if there is already a transaction ongoing on the endpoint.*/
|
||||||
|
if (usbGetReceiveStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking if there is a buffer ready for incoming data.*/
|
||||||
|
buf = ibqGetEmptyBufferI(&qmkusbp->ibqueue);
|
||||||
|
if (buf == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer found, starting a new transaction.*/
|
||||||
|
usbStartReceiveI(qmkusbp->config->usbp, qmkusbp->config->bulk_out,
|
||||||
|
buf, qmkusbp->ibqueue.bsize - sizeof(size_t));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static size_t _write(void *ip, const uint8_t *bp, size_t n) {
|
||||||
|
|
||||||
|
return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp,
|
||||||
|
n, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _read(void *ip, uint8_t *bp, size_t n) {
|
||||||
|
|
||||||
|
return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp,
|
||||||
|
n, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _put(void *ip, uint8_t b) {
|
||||||
|
|
||||||
|
return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _get(void *ip) {
|
||||||
|
|
||||||
|
return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, TIME_INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _putt(void *ip, uint8_t b, systime_t timeout) {
|
||||||
|
|
||||||
|
return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static msg_t _gett(void *ip, systime_t timeout) {
|
||||||
|
|
||||||
|
return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) {
|
||||||
|
|
||||||
|
return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t _readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) {
|
||||||
|
|
||||||
|
return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct QMKUSBDriverVMT vmt = {
|
||||||
|
_write, _read, _put, _get,
|
||||||
|
_putt, _gett, _writet, _readt
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notification of empty buffer released into the input buffers queue.
|
||||||
|
*
|
||||||
|
* @param[in] bqp the buffers queue pointer.
|
||||||
|
*/
|
||||||
|
static void ibnotify(io_buffers_queue_t *bqp) {
|
||||||
|
QMKUSBDriver *qmkusbp = bqGetLinkX(bqp);
|
||||||
|
(void) qmkusb_start_receive(qmkusbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notification of filled buffer inserted into the output buffers queue.
|
||||||
|
*
|
||||||
|
* @param[in] bqp the buffers queue pointer.
|
||||||
|
*/
|
||||||
|
static void obnotify(io_buffers_queue_t *bqp) {
|
||||||
|
size_t n;
|
||||||
|
QMKUSBDriver *qmkusbp = bqGetLinkX(bqp);
|
||||||
|
|
||||||
|
/* If the USB driver is not in the appropriate state then transactions
|
||||||
|
must not be started.*/
|
||||||
|
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) ||
|
||||||
|
(qmkusbp->state != QMKUSB_READY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking if there is already a transaction ongoing on the endpoint.*/
|
||||||
|
if (!usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
|
||||||
|
/* Trying to get a full buffer.*/
|
||||||
|
uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
|
||||||
|
if (buf != NULL) {
|
||||||
|
/* Buffer found, starting a new transaction.*/
|
||||||
|
usbStartTransmitI(qmkusbp->config->usbp, qmkusbp->config->bulk_in, buf, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial Driver initialization.
|
||||||
|
* @note This function is implicitly invoked by @p halInit(), there is
|
||||||
|
* no need to explicitly initialize the driver.
|
||||||
|
*
|
||||||
|
* @init
|
||||||
|
*/
|
||||||
|
void qmkusbInit(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes a generic full duplex driver object.
|
||||||
|
* @details The HW dependent part of the initialization has to be performed
|
||||||
|
* outside, usually in the hardware initialization code.
|
||||||
|
*
|
||||||
|
* @param[out] qmkusbp pointer to a @p QMKUSBDriver structure
|
||||||
|
*
|
||||||
|
* @init
|
||||||
|
*/
|
||||||
|
void qmkusbObjectInit(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config) {
|
||||||
|
|
||||||
|
qmkusbp->vmt = &vmt;
|
||||||
|
osalEventObjectInit(&qmkusbp->event);
|
||||||
|
qmkusbp->state = QMKUSB_STOP;
|
||||||
|
// Note that the config uses the USB direction naming
|
||||||
|
ibqObjectInit(&qmkusbp->ibqueue, true, config->ob,
|
||||||
|
config->out_size, config->out_buffers,
|
||||||
|
ibnotify, qmkusbp);
|
||||||
|
obqObjectInit(&qmkusbp->obqueue, true, config->ib,
|
||||||
|
config->in_size, config->in_buffers,
|
||||||
|
obnotify, qmkusbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures and starts the driver.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
* @param[in] config the serial over USB driver configuration
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void qmkusbStart(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config) {
|
||||||
|
USBDriver *usbp = config->usbp;
|
||||||
|
|
||||||
|
osalDbgCheck(qmkusbp != NULL);
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
osalDbgAssert((qmkusbp->state == QMKUSB_STOP) || (qmkusbp->state == QMKUSB_READY),
|
||||||
|
"invalid state");
|
||||||
|
usbp->in_params[config->bulk_in - 1U] = qmkusbp;
|
||||||
|
usbp->out_params[config->bulk_out - 1U] = qmkusbp;
|
||||||
|
if (config->int_in > 0U) {
|
||||||
|
usbp->in_params[config->int_in - 1U] = qmkusbp;
|
||||||
|
}
|
||||||
|
qmkusbp->config = config;
|
||||||
|
qmkusbp->state = QMKUSB_READY;
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops the driver.
|
||||||
|
* @details Any thread waiting on the driver's queues will be awakened with
|
||||||
|
* the message @p MSG_RESET.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
*
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
void qmkusbStop(QMKUSBDriver *qmkusbp) {
|
||||||
|
USBDriver *usbp = qmkusbp->config->usbp;
|
||||||
|
|
||||||
|
osalDbgCheck(qmkusbp != NULL);
|
||||||
|
|
||||||
|
osalSysLock();
|
||||||
|
|
||||||
|
osalDbgAssert((qmkusbp->state == QMKUSB_STOP) || (qmkusbp->state == QMKUSB_READY),
|
||||||
|
"invalid state");
|
||||||
|
|
||||||
|
/* Driver in stopped state.*/
|
||||||
|
usbp->in_params[qmkusbp->config->bulk_in - 1U] = NULL;
|
||||||
|
usbp->out_params[qmkusbp->config->bulk_out - 1U] = NULL;
|
||||||
|
if (qmkusbp->config->int_in > 0U) {
|
||||||
|
usbp->in_params[qmkusbp->config->int_in - 1U] = NULL;
|
||||||
|
}
|
||||||
|
qmkusbp->config = NULL;
|
||||||
|
qmkusbp->state = QMKUSB_STOP;
|
||||||
|
|
||||||
|
/* Enforces a disconnection.*/
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_DISCONNECTED);
|
||||||
|
ibqResetI(&qmkusbp->ibqueue);
|
||||||
|
obqResetI(&qmkusbp->obqueue);
|
||||||
|
osalOsRescheduleS();
|
||||||
|
|
||||||
|
osalSysUnlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB device suspend handler.
|
||||||
|
* @details Generates a @p CHN_DISCONNECT event and puts queues in
|
||||||
|
* non-blocking mode, this way the application cannot get stuck
|
||||||
|
* in the middle of an I/O operations.
|
||||||
|
* @note If this function is not called from an ISR then an explicit call
|
||||||
|
* to @p osalOsRescheduleS() in necessary afterward.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
*
|
||||||
|
* @iclass
|
||||||
|
*/
|
||||||
|
void qmkusbSuspendHookI(QMKUSBDriver *qmkusbp) {
|
||||||
|
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_DISCONNECTED);
|
||||||
|
bqSuspendI(&qmkusbp->ibqueue);
|
||||||
|
bqSuspendI(&qmkusbp->obqueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB device wakeup handler.
|
||||||
|
* @details Generates a @p CHN_CONNECT event and resumes normal queues
|
||||||
|
* operations.
|
||||||
|
*
|
||||||
|
* @note If this function is not called from an ISR then an explicit call
|
||||||
|
* to @p osalOsRescheduleS() in necessary afterward.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
*
|
||||||
|
* @iclass
|
||||||
|
*/
|
||||||
|
void qmkusbWakeupHookI(QMKUSBDriver *qmkusbp) {
|
||||||
|
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_CONNECTED);
|
||||||
|
bqResumeX(&qmkusbp->ibqueue);
|
||||||
|
bqResumeX(&qmkusbp->obqueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief USB device configured handler.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
*
|
||||||
|
* @iclass
|
||||||
|
*/
|
||||||
|
void qmkusbConfigureHookI(QMKUSBDriver *qmkusbp) {
|
||||||
|
|
||||||
|
ibqResetI(&qmkusbp->ibqueue);
|
||||||
|
bqResumeX(&qmkusbp->ibqueue);
|
||||||
|
obqResetI(&qmkusbp->obqueue);
|
||||||
|
bqResumeX(&qmkusbp->obqueue);
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_CONNECTED);
|
||||||
|
(void) qmkusb_start_receive(qmkusbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default requests hook.
|
||||||
|
* @details Applications wanting to use the Serial over USB driver can use
|
||||||
|
* this function as requests hook in the USB configuration.
|
||||||
|
* The following requests are emulated:
|
||||||
|
* - CDC_GET_LINE_CODING.
|
||||||
|
* - CDC_SET_LINE_CODING.
|
||||||
|
* - CDC_SET_CONTROL_LINE_STATE.
|
||||||
|
* .
|
||||||
|
*
|
||||||
|
* @param[in] usbp pointer to the @p USBDriver object
|
||||||
|
* @return The hook status.
|
||||||
|
* @retval true Message handled internally.
|
||||||
|
* @retval false Message not handled.
|
||||||
|
*/
|
||||||
|
bool qmkusbRequestsHook(USBDriver *usbp) {
|
||||||
|
|
||||||
|
if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) {
|
||||||
|
switch (usbp->setup[1]) {
|
||||||
|
case CDC_GET_LINE_CODING:
|
||||||
|
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
|
||||||
|
return true;
|
||||||
|
case CDC_SET_LINE_CODING:
|
||||||
|
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
|
||||||
|
return true;
|
||||||
|
case CDC_SET_CONTROL_LINE_STATE:
|
||||||
|
/* Nothing to do, there are no control lines.*/
|
||||||
|
usbSetupTransfer(usbp, NULL, 0, NULL);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SOF handler.
|
||||||
|
* @details The SOF interrupt is used for automatic flushing of incomplete
|
||||||
|
* buffers pending in the output queue.
|
||||||
|
*
|
||||||
|
* @param[in] qmkusbp pointer to a @p QMKUSBDriver object
|
||||||
|
*
|
||||||
|
* @iclass
|
||||||
|
*/
|
||||||
|
void qmkusbSOFHookI(QMKUSBDriver *qmkusbp) {
|
||||||
|
|
||||||
|
/* If the USB driver is not in the appropriate state then transactions
|
||||||
|
must not be started.*/
|
||||||
|
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) ||
|
||||||
|
(qmkusbp->state != QMKUSB_READY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there is already a transaction ongoing then another one cannot be
|
||||||
|
started.*/
|
||||||
|
if (usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking if there only a buffer partially filled, if so then it is
|
||||||
|
enforced in the queue and transmitted.*/
|
||||||
|
if (obqTryFlushI(&qmkusbp->obqueue)) {
|
||||||
|
size_t n;
|
||||||
|
uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
|
||||||
|
|
||||||
|
/* For fixed size drivers, fill the end with zeros */
|
||||||
|
if (qmkusbp->config->fixed_size) {
|
||||||
|
memset(buf + n, 0, qmkusbp->config->in_size - n);
|
||||||
|
n = qmkusbp->config->in_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalDbgAssert(buf != NULL, "queue is empty");
|
||||||
|
|
||||||
|
usbStartTransmitI(qmkusbp->config->usbp, qmkusbp->config->bulk_in, buf, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default data transmitted callback.
|
||||||
|
* @details The application must use this function as callback for the IN
|
||||||
|
* data endpoint.
|
||||||
|
*
|
||||||
|
* @param[in] usbp pointer to the @p USBDriver object
|
||||||
|
* @param[in] ep IN endpoint number
|
||||||
|
*/
|
||||||
|
void qmkusbDataTransmitted(USBDriver *usbp, usbep_t ep) {
|
||||||
|
uint8_t *buf;
|
||||||
|
size_t n;
|
||||||
|
QMKUSBDriver *qmkusbp = usbp->in_params[ep - 1U];
|
||||||
|
|
||||||
|
if (qmkusbp == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysLockFromISR();
|
||||||
|
|
||||||
|
/* Signaling that space is available in the output queue.*/
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_OUTPUT_EMPTY);
|
||||||
|
|
||||||
|
/* Freeing the buffer just transmitted, if it was not a zero size packet.*/
|
||||||
|
if (usbp->epc[ep]->in_state->txsize > 0U) {
|
||||||
|
obqReleaseEmptyBufferI(&qmkusbp->obqueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking if there is a buffer ready for transmission.*/
|
||||||
|
buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
|
||||||
|
|
||||||
|
if (buf != NULL) {
|
||||||
|
/* The endpoint cannot be busy, we are in the context of the callback,
|
||||||
|
so it is safe to transmit without a check.*/
|
||||||
|
usbStartTransmitI(usbp, ep, buf, n);
|
||||||
|
}
|
||||||
|
else if ((usbp->epc[ep]->in_state->txsize > 0U) &&
|
||||||
|
((usbp->epc[ep]->in_state->txsize &
|
||||||
|
((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) {
|
||||||
|
/* Transmit zero sized packet in case the last one has maximum allowed
|
||||||
|
size. Otherwise the recipient may expect more data coming soon and
|
||||||
|
not return buffered data to app. See section 5.8.3 Bulk Transfer
|
||||||
|
Packet Size Constraints of the USB Specification document.*/
|
||||||
|
if (!qmkusbp->config->fixed_size) {
|
||||||
|
usbStartTransmitI(usbp, ep, usbp->setup, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Nothing to transmit.*/
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default data received callback.
|
||||||
|
* @details The application must use this function as callback for the OUT
|
||||||
|
* data endpoint.
|
||||||
|
*
|
||||||
|
* @param[in] usbp pointer to the @p USBDriver object
|
||||||
|
* @param[in] ep OUT endpoint number
|
||||||
|
*/
|
||||||
|
void qmkusbDataReceived(USBDriver *usbp, usbep_t ep) {
|
||||||
|
QMKUSBDriver *qmkusbp = usbp->out_params[ep - 1U];
|
||||||
|
if (qmkusbp == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysLockFromISR();
|
||||||
|
|
||||||
|
/* Signaling that data is available in the input queue.*/
|
||||||
|
chnAddFlagsI(qmkusbp, CHN_INPUT_AVAILABLE);
|
||||||
|
|
||||||
|
/* Posting the filled buffer in the queue.*/
|
||||||
|
ibqPostFullBufferI(&qmkusbp->ibqueue,
|
||||||
|
usbGetReceiveTransactionSizeX(qmkusbp->config->usbp,
|
||||||
|
qmkusbp->config->bulk_out));
|
||||||
|
|
||||||
|
/* The endpoint cannot be busy, we are in the context of the callback,
|
||||||
|
so a packet is in the buffer for sure. Trying to get a free buffer
|
||||||
|
for the next transaction.*/
|
||||||
|
(void) qmkusb_start_receive(qmkusbp);
|
||||||
|
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default data received callback.
|
||||||
|
* @details The application must use this function as callback for the IN
|
||||||
|
* interrupt endpoint.
|
||||||
|
*
|
||||||
|
* @param[in] usbp pointer to the @p USBDriver object
|
||||||
|
* @param[in] ep endpoint number
|
||||||
|
*/
|
||||||
|
void qmkusbInterruptTransmitted(USBDriver *usbp, usbep_t ep) {
|
||||||
|
|
||||||
|
(void)usbp;
|
||||||
|
(void)ep;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
184
tmk_core/protocol/chibios/usb_driver.h
Normal file
184
tmk_core/protocol/chibios/usb_driver.h
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file usb_driver.h
|
||||||
|
* @brief Usb driver suitable for both packet and serial formats
|
||||||
|
*
|
||||||
|
* @addtogroup SERIAL_USB
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USB_DRIVER_H
|
||||||
|
#define USB_DRIVER_H
|
||||||
|
|
||||||
|
#include "hal_usb_cdc.h"
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if HAL_USE_USB == FALSE
|
||||||
|
#error "The USB Driver requires HAL_USE_USB"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Driver state machine possible states.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
QMKUSB_UNINIT = 0, /**< Not initialized. */
|
||||||
|
QMKUSB_STOP = 1, /**< Stopped. */
|
||||||
|
QMKUSB_READY = 2 /**< Ready. */
|
||||||
|
} qmkusbstate_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure representing a serial over USB driver.
|
||||||
|
*/
|
||||||
|
typedef struct QMKUSBDriver QMKUSBDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serial over USB Driver configuration structure.
|
||||||
|
* @details An instance of this structure must be passed to @p sduStart()
|
||||||
|
* in order to configure and start the driver operations.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief USB driver to use.
|
||||||
|
*/
|
||||||
|
USBDriver *usbp;
|
||||||
|
/**
|
||||||
|
* @brief Bulk IN endpoint used for outgoing data transfer.
|
||||||
|
*/
|
||||||
|
usbep_t bulk_in;
|
||||||
|
/**
|
||||||
|
* @brief Bulk OUT endpoint used for incoming data transfer.
|
||||||
|
*/
|
||||||
|
usbep_t bulk_out;
|
||||||
|
/**
|
||||||
|
* @brief Interrupt IN endpoint used for notifications.
|
||||||
|
* @note If set to zero then the INT endpoint is assumed to be not
|
||||||
|
* present, USB descriptors must be changed accordingly.
|
||||||
|
*/
|
||||||
|
usbep_t int_in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The number of buffers in the queues
|
||||||
|
*/
|
||||||
|
size_t in_buffers;
|
||||||
|
size_t out_buffers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The size of each buffer in the queue, typically the same as the endpoint size
|
||||||
|
*/
|
||||||
|
size_t in_size;
|
||||||
|
size_t out_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Always send full buffers in_size (the rest is filled with zeroes)
|
||||||
|
*/
|
||||||
|
bool fixed_size;
|
||||||
|
|
||||||
|
/* Input buffer
|
||||||
|
* @note needs to be initialized with a memory buffer of the right size
|
||||||
|
*/
|
||||||
|
uint8_t* ib;
|
||||||
|
/* Output buffer
|
||||||
|
* @note needs to be initialized with a memory buffer of the right size
|
||||||
|
*/
|
||||||
|
uint8_t* ob;
|
||||||
|
} QMKUSBConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p SerialDriver specific data.
|
||||||
|
*/
|
||||||
|
#define _qmk_usb_driver_data \
|
||||||
|
_base_asynchronous_channel_data \
|
||||||
|
/* Driver state.*/ \
|
||||||
|
qmkusbstate_t state; \
|
||||||
|
/* Input buffers queue.*/ \
|
||||||
|
input_buffers_queue_t ibqueue; \
|
||||||
|
/* Output queue.*/ \
|
||||||
|
output_buffers_queue_t obqueue; \
|
||||||
|
/* End of the mandatory fields.*/ \
|
||||||
|
/* Current configuration data.*/ \
|
||||||
|
const QMKUSBConfig *config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @p SerialUSBDriver specific methods.
|
||||||
|
*/
|
||||||
|
#define _qmk_usb_driver_methods \
|
||||||
|
_base_asynchronous_channel_methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends BaseAsynchronousChannelVMT
|
||||||
|
*
|
||||||
|
* @brief @p SerialDriver virtual methods table.
|
||||||
|
*/
|
||||||
|
struct QMKUSBDriverVMT {
|
||||||
|
_qmk_usb_driver_methods
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends BaseAsynchronousChannel
|
||||||
|
*
|
||||||
|
* @brief Full duplex serial driver class.
|
||||||
|
* @details This class extends @p BaseAsynchronousChannel by adding physical
|
||||||
|
* I/O queues.
|
||||||
|
*/
|
||||||
|
struct QMKUSBDriver {
|
||||||
|
/** @brief Virtual Methods Table.*/
|
||||||
|
const struct QMKUSBDriverVMT *vmt;
|
||||||
|
_qmk_usb_driver_data
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void qmkusbInit(void);
|
||||||
|
void qmkusbObjectInit(QMKUSBDriver *qmkusbp, const QMKUSBConfig * config);
|
||||||
|
void qmkusbStart(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config);
|
||||||
|
void qmkusbStop(QMKUSBDriver *qmkusbp);
|
||||||
|
void qmkusbSuspendHookI(QMKUSBDriver *qmkusbp);
|
||||||
|
void qmkusbWakeupHookI(QMKUSBDriver *qmkusbp);
|
||||||
|
void qmkusbConfigureHookI(QMKUSBDriver *qmkusbp);
|
||||||
|
bool qmkusbRequestsHook(USBDriver *usbp);
|
||||||
|
void qmkusbSOFHookI(QMKUSBDriver *qmkusbp);
|
||||||
|
void qmkusbDataTransmitted(USBDriver *usbp, usbep_t ep);
|
||||||
|
void qmkusbDataReceived(USBDriver *usbp, usbep_t ep);
|
||||||
|
void qmkusbInterruptTransmitted(USBDriver *usbp, usbep_t ep);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* USB_DRIVER_H */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -29,6 +29,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
#include "usb_descriptor.h"
|
#include "usb_descriptor.h"
|
||||||
|
#include "usb_driver.h"
|
||||||
|
|
||||||
#ifdef NKRO_ENABLE
|
#ifdef NKRO_ENABLE
|
||||||
#include "keycode_config.h"
|
#include "keycode_config.h"
|
||||||
|
@ -170,27 +171,23 @@ static const USBEndpointConfig nkro_ep_config = {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t queue_capacity_in;
|
size_t queue_capacity_in;
|
||||||
size_t queue_capacity_out;
|
size_t queue_capacity_out;
|
||||||
uint8_t* queue_buffer_in;
|
|
||||||
uint8_t* queue_buffer_out;
|
|
||||||
USBInEndpointState in_ep_state;
|
USBInEndpointState in_ep_state;
|
||||||
USBOutEndpointState out_ep_state;
|
USBOutEndpointState out_ep_state;
|
||||||
USBInEndpointState int_ep_state;
|
USBInEndpointState int_ep_state;
|
||||||
USBEndpointConfig in_ep_config;
|
USBEndpointConfig in_ep_config;
|
||||||
USBEndpointConfig out_ep_config;
|
USBEndpointConfig out_ep_config;
|
||||||
USBEndpointConfig int_ep_config;
|
USBEndpointConfig int_ep_config;
|
||||||
const SerialUSBConfig config;
|
const QMKUSBConfig config;
|
||||||
SerialUSBDriver driver;
|
QMKUSBDriver driver;
|
||||||
} stream_driver_t;
|
} usb_driver_config_t;
|
||||||
|
|
||||||
#define STREAM_DRIVER(stream, notification) { \
|
#define QMK_USB_DRIVER_CONFIG(stream, notification, fixedsize) { \
|
||||||
.queue_capacity_in = stream##_IN_CAPACITY, \
|
.queue_capacity_in = stream##_IN_CAPACITY, \
|
||||||
.queue_capacity_out = stream##_OUT_CAPACITY, \
|
.queue_capacity_out = stream##_OUT_CAPACITY, \
|
||||||
.queue_buffer_in = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \
|
|
||||||
.queue_buffer_out = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \
|
|
||||||
.in_ep_config = { \
|
.in_ep_config = { \
|
||||||
.ep_mode = stream##_IN_MODE, \
|
.ep_mode = stream##_IN_MODE, \
|
||||||
.setup_cb = NULL, \
|
.setup_cb = NULL, \
|
||||||
.in_cb = sduDataTransmitted, \
|
.in_cb = qmkusbDataTransmitted, \
|
||||||
.out_cb = NULL, \
|
.out_cb = NULL, \
|
||||||
.in_maxsize = stream##_EPSIZE, \
|
.in_maxsize = stream##_EPSIZE, \
|
||||||
.out_maxsize = 0, \
|
.out_maxsize = 0, \
|
||||||
|
@ -204,7 +201,7 @@ typedef struct {
|
||||||
.ep_mode = stream##_OUT_MODE, \
|
.ep_mode = stream##_OUT_MODE, \
|
||||||
.setup_cb = NULL, \
|
.setup_cb = NULL, \
|
||||||
.in_cb = NULL, \
|
.in_cb = NULL, \
|
||||||
.out_cb = sduDataReceived, \
|
.out_cb = qmkusbDataReceived, \
|
||||||
.in_maxsize = 0, \
|
.in_maxsize = 0, \
|
||||||
.out_maxsize = stream##_EPSIZE, \
|
.out_maxsize = stream##_EPSIZE, \
|
||||||
/* The pointer to the states will be filled during initialization */ \
|
/* The pointer to the states will be filled during initialization */ \
|
||||||
|
@ -216,7 +213,7 @@ typedef struct {
|
||||||
.int_ep_config = { \
|
.int_ep_config = { \
|
||||||
.ep_mode = USB_EP_MODE_TYPE_INTR, \
|
.ep_mode = USB_EP_MODE_TYPE_INTR, \
|
||||||
.setup_cb = NULL, \
|
.setup_cb = NULL, \
|
||||||
.in_cb = sduInterruptTransmitted, \
|
.in_cb = qmkusbInterruptTransmitted, \
|
||||||
.out_cb = NULL, \
|
.out_cb = NULL, \
|
||||||
.in_maxsize = CDC_NOTIFICATION_EPSIZE, \
|
.in_maxsize = CDC_NOTIFICATION_EPSIZE, \
|
||||||
.out_maxsize = 0, \
|
.out_maxsize = 0, \
|
||||||
|
@ -230,7 +227,14 @@ typedef struct {
|
||||||
.usbp = &USB_DRIVER, \
|
.usbp = &USB_DRIVER, \
|
||||||
.bulk_in = stream##_IN_EPNUM, \
|
.bulk_in = stream##_IN_EPNUM, \
|
||||||
.bulk_out = stream##_OUT_EPNUM, \
|
.bulk_out = stream##_OUT_EPNUM, \
|
||||||
.int_in = notification \
|
.int_in = notification, \
|
||||||
|
.in_buffers = stream##_IN_CAPACITY, \
|
||||||
|
.out_buffers = stream##_OUT_CAPACITY, \
|
||||||
|
.in_size = stream##_EPSIZE, \
|
||||||
|
.out_size = stream##_EPSIZE, \
|
||||||
|
.fixed_size = fixedsize, \
|
||||||
|
.ib = (uint8_t[BQ_BUFFER_SIZE(stream##_IN_CAPACITY, stream##_EPSIZE)]) {}, \
|
||||||
|
.ob = (uint8_t[BQ_BUFFER_SIZE(stream##_OUT_CAPACITY,stream##_EPSIZE)]) {}, \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,36 +242,36 @@ typedef struct {
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
#ifdef CONSOLE_ENABLE
|
#ifdef CONSOLE_ENABLE
|
||||||
stream_driver_t console_driver;
|
usb_driver_config_t console_driver;
|
||||||
#endif
|
#endif
|
||||||
#ifdef RAW_ENABLE
|
#ifdef RAW_ENABLE
|
||||||
stream_driver_t raw_driver;
|
usb_driver_config_t raw_driver;
|
||||||
#endif
|
#endif
|
||||||
#ifdef MIDI_ENABLE
|
#ifdef MIDI_ENABLE
|
||||||
stream_driver_t midi_driver;
|
usb_driver_config_t midi_driver;
|
||||||
#endif
|
#endif
|
||||||
#ifdef VIRTSER_ENABLE
|
#ifdef VIRTSER_ENABLE
|
||||||
stream_driver_t serial_driver;
|
usb_driver_config_t serial_driver;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
stream_driver_t array[0];
|
usb_driver_config_t array[0];
|
||||||
};
|
};
|
||||||
} stream_drivers_t;
|
} usb_driver_configs_t;
|
||||||
|
|
||||||
static stream_drivers_t drivers = {
|
static usb_driver_configs_t drivers = {
|
||||||
#ifdef CONSOLE_ENABLE
|
#ifdef CONSOLE_ENABLE
|
||||||
#define CONSOLE_IN_CAPACITY 4
|
#define CONSOLE_IN_CAPACITY 4
|
||||||
#define CONSOLE_OUT_CAPACITY 4
|
#define CONSOLE_OUT_CAPACITY 4
|
||||||
#define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
|
#define CONSOLE_IN_MODE USB_EP_MODE_TYPE_INTR
|
||||||
#define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
|
#define CONSOLE_OUT_MODE USB_EP_MODE_TYPE_INTR
|
||||||
.console_driver = STREAM_DRIVER(CONSOLE, 0),
|
.console_driver = QMK_USB_DRIVER_CONFIG(CONSOLE, 0, true),
|
||||||
#endif
|
#endif
|
||||||
#ifdef RAW_ENABLE
|
#ifdef RAW_ENABLE
|
||||||
#define RAW_IN_CAPACITY 4
|
#define RAW_IN_CAPACITY 4
|
||||||
#define RAW_OUT_CAPACITY 4
|
#define RAW_OUT_CAPACITY 4
|
||||||
#define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
|
#define RAW_IN_MODE USB_EP_MODE_TYPE_INTR
|
||||||
#define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
|
#define RAW_OUT_MODE USB_EP_MODE_TYPE_INTR
|
||||||
.raw_driver = STREAM_DRIVER(RAW, 0),
|
.raw_driver = QMK_USB_DRIVER_CONFIG(RAW, 0, false),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MIDI_ENABLE
|
#ifdef MIDI_ENABLE
|
||||||
|
@ -275,7 +279,7 @@ static stream_drivers_t drivers = {
|
||||||
#define MIDI_STREAM_OUT_CAPACITY 4
|
#define MIDI_STREAM_OUT_CAPACITY 4
|
||||||
#define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
|
#define MIDI_STREAM_IN_MODE USB_EP_MODE_TYPE_BULK
|
||||||
#define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
|
#define MIDI_STREAM_OUT_MODE USB_EP_MODE_TYPE_BULK
|
||||||
.midi_driver = STREAM_DRIVER(MIDI_STREAM, 0),
|
.midi_driver = QMK_USB_DRIVER_CONFIG(MIDI_STREAM, 0, false),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VIRTSER_ENABLE
|
#ifdef VIRTSER_ENABLE
|
||||||
|
@ -283,11 +287,11 @@ static stream_drivers_t drivers = {
|
||||||
#define CDC_OUT_CAPACITY 4
|
#define CDC_OUT_CAPACITY 4
|
||||||
#define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
|
#define CDC_IN_MODE USB_EP_MODE_TYPE_BULK
|
||||||
#define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
|
#define CDC_OUT_MODE USB_EP_MODE_TYPE_BULK
|
||||||
.serial_driver = STREAM_DRIVER(CDC, CDC_NOTIFICATION_EPNUM),
|
.serial_driver = QMK_USB_DRIVER_CONFIG(CDC, CDC_NOTIFICATION_EPNUM, false),
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_STREAM_DRIVERS (sizeof(drivers) / sizeof(stream_driver_t))
|
#define NUM_USB_DRIVERS (sizeof(drivers) / sizeof(usb_driver_config_t))
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------
|
/* ---------------------------------------------------------
|
||||||
|
@ -315,13 +319,13 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
|
||||||
#ifdef NKRO_ENABLE
|
#ifdef NKRO_ENABLE
|
||||||
usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
|
usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
|
||||||
#endif /* NKRO_ENABLE */
|
#endif /* NKRO_ENABLE */
|
||||||
for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0;i<NUM_USB_DRIVERS;i++) {
|
||||||
usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
|
usbInitEndpointI(usbp, drivers.array[i].config.bulk_in, &drivers.array[i].in_ep_config);
|
||||||
usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
|
usbInitEndpointI(usbp, drivers.array[i].config.bulk_out, &drivers.array[i].out_ep_config);
|
||||||
if (drivers.array[i].config.int_in) {
|
if (drivers.array[i].config.int_in) {
|
||||||
usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
|
usbInitEndpointI(usbp, drivers.array[i].config.int_in, &drivers.array[i].int_ep_config);
|
||||||
}
|
}
|
||||||
sduConfigureHookI(&drivers.array[i].driver);
|
qmkusbConfigureHookI(&drivers.array[i].driver);
|
||||||
}
|
}
|
||||||
osalSysUnlockFromISR();
|
osalSysUnlockFromISR();
|
||||||
return;
|
return;
|
||||||
|
@ -333,20 +337,20 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
|
||||||
case USB_EVENT_UNCONFIGURED:
|
case USB_EVENT_UNCONFIGURED:
|
||||||
/* Falls into.*/
|
/* Falls into.*/
|
||||||
case USB_EVENT_RESET:
|
case USB_EVENT_RESET:
|
||||||
for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0;i<NUM_USB_DRIVERS;i++) {
|
||||||
chSysLockFromISR();
|
chSysLockFromISR();
|
||||||
/* Disconnection event on suspend.*/
|
/* Disconnection event on suspend.*/
|
||||||
sduSuspendHookI(&drivers.array[i].driver);
|
qmkusbSuspendHookI(&drivers.array[i].driver);
|
||||||
chSysUnlockFromISR();
|
chSysUnlockFromISR();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case USB_EVENT_WAKEUP:
|
case USB_EVENT_WAKEUP:
|
||||||
//TODO: from ISR! print("[W]");
|
//TODO: from ISR! print("[W]");
|
||||||
for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0;i<NUM_USB_DRIVERS;i++) {
|
||||||
chSysLockFromISR();
|
chSysLockFromISR();
|
||||||
/* Disconnection event on suspend.*/
|
/* Disconnection event on suspend.*/
|
||||||
sduWakeupHookI(&drivers.array[i].driver);
|
qmkusbWakeupHookI(&drivers.array[i].driver);
|
||||||
chSysUnlockFromISR();
|
chSysUnlockFromISR();
|
||||||
}
|
}
|
||||||
suspend_wakeup_init();
|
suspend_wakeup_init();
|
||||||
|
@ -527,10 +531,10 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0;i<NUM_USB_DRIVERS;i++) {
|
||||||
if (drivers.array[i].config.int_in) {
|
if (drivers.array[i].config.int_in) {
|
||||||
// NOTE: Assumes that we only have one serial driver
|
// NOTE: Assumes that we only have one serial driver
|
||||||
return sduRequestsHook(usbp);
|
return qmkusbRequestsHook(usbp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,8 +545,8 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
|
||||||
static void usb_sof_cb(USBDriver *usbp) {
|
static void usb_sof_cb(USBDriver *usbp) {
|
||||||
kbd_sof_cb(usbp);
|
kbd_sof_cb(usbp);
|
||||||
osalSysLockFromISR();
|
osalSysLockFromISR();
|
||||||
for (int i=0; i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0; i<NUM_USB_DRIVERS;i++) {
|
||||||
sduSOFHookI(&drivers.array[i].driver);
|
qmkusbSOFHookI(&drivers.array[i].driver);
|
||||||
}
|
}
|
||||||
osalSysUnlockFromISR();
|
osalSysUnlockFromISR();
|
||||||
}
|
}
|
||||||
|
@ -560,17 +564,13 @@ static const USBConfig usbcfg = {
|
||||||
* Initialize the USB driver
|
* Initialize the USB driver
|
||||||
*/
|
*/
|
||||||
void init_usb_driver(USBDriver *usbp) {
|
void init_usb_driver(USBDriver *usbp) {
|
||||||
for (int i=0; i<NUM_STREAM_DRIVERS;i++) {
|
for (int i=0; i<NUM_USB_DRIVERS;i++) {
|
||||||
SerialUSBDriver* driver = &drivers.array[i].driver;
|
QMKUSBDriver* driver = &drivers.array[i].driver;
|
||||||
drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
|
drivers.array[i].in_ep_config.in_state = &drivers.array[i].in_ep_state;
|
||||||
drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
|
drivers.array[i].out_ep_config.out_state = &drivers.array[i].out_ep_state;
|
||||||
drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
|
drivers.array[i].int_ep_config.in_state = &drivers.array[i].int_ep_state;
|
||||||
sduObjectInit(driver);
|
qmkusbObjectInit(driver, &drivers.array[i].config);
|
||||||
bqnotify_t notify = driver->ibqueue.notify;
|
qmkusbStart(driver, &drivers.array[i].config);
|
||||||
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);
|
|
||||||
notify = driver->obqueue.notify;
|
|
||||||
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);
|
|
||||||
sduStart(driver, &drivers.array[i].config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue