mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-11-04 07:12:33 +01:00 
			
		
		
		
	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
					
				@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -146,7 +146,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -139,7 +139,7 @@
 | 
			
		||||
 * @brief   Enables the SERIAL over USB subsystem.
 | 
			
		||||
 */
 | 
			
		||||
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
 | 
			
		||||
#define HAL_USE_SERIAL_USB          TRUE
 | 
			
		||||
#define HAL_USE_SERIAL_USB          FALSE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ CHIBIOS_DIR = $(PROTOCOL_DIR)/chibios
 | 
			
		||||
SRC += $(CHIBIOS_DIR)/usb_main.c
 | 
			
		||||
SRC += $(CHIBIOS_DIR)/main.c
 | 
			
		||||
SRC += usb_descriptor.c
 | 
			
		||||
SRC += $(CHIBIOS_DIR)/usb_driver.c
 | 
			
		||||
 | 
			
		||||
VPATH += $(TMK_PATH)/$(PROTOCOL_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
 | 
			
		||||
#include "wait.h"
 | 
			
		||||
#include "usb_descriptor.h"
 | 
			
		||||
#include "usb_driver.h"
 | 
			
		||||
 | 
			
		||||
#ifdef NKRO_ENABLE
 | 
			
		||||
  #include "keycode_config.h"
 | 
			
		||||
@ -170,27 +171,23 @@ static const USBEndpointConfig nkro_ep_config = {
 | 
			
		||||
typedef struct {
 | 
			
		||||
  size_t queue_capacity_in;
 | 
			
		||||
  size_t queue_capacity_out;
 | 
			
		||||
  uint8_t* queue_buffer_in;
 | 
			
		||||
  uint8_t* queue_buffer_out;
 | 
			
		||||
  USBInEndpointState in_ep_state;
 | 
			
		||||
  USBOutEndpointState out_ep_state;
 | 
			
		||||
  USBInEndpointState int_ep_state;
 | 
			
		||||
  USBEndpointConfig in_ep_config;
 | 
			
		||||
  USBEndpointConfig out_ep_config;
 | 
			
		||||
  USBEndpointConfig int_ep_config;
 | 
			
		||||
  const SerialUSBConfig config;
 | 
			
		||||
  SerialUSBDriver driver;
 | 
			
		||||
} stream_driver_t;
 | 
			
		||||
  const QMKUSBConfig config;
 | 
			
		||||
  QMKUSBDriver driver;
 | 
			
		||||
} 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_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 = { \
 | 
			
		||||
    .ep_mode = stream##_IN_MODE, \
 | 
			
		||||
    .setup_cb = NULL, \
 | 
			
		||||
    .in_cb = sduDataTransmitted, \
 | 
			
		||||
    .in_cb = qmkusbDataTransmitted, \
 | 
			
		||||
    .out_cb = NULL, \
 | 
			
		||||
    .in_maxsize = stream##_EPSIZE, \
 | 
			
		||||
    .out_maxsize = 0, \
 | 
			
		||||
@ -204,7 +201,7 @@ typedef struct {
 | 
			
		||||
    .ep_mode = stream##_OUT_MODE, \
 | 
			
		||||
    .setup_cb = NULL, \
 | 
			
		||||
    .in_cb = NULL, \
 | 
			
		||||
    .out_cb = sduDataReceived, \
 | 
			
		||||
    .out_cb = qmkusbDataReceived, \
 | 
			
		||||
    .in_maxsize = 0, \
 | 
			
		||||
    .out_maxsize = stream##_EPSIZE, \
 | 
			
		||||
    /* The pointer to the states will be filled during initialization */ \
 | 
			
		||||
@ -216,7 +213,7 @@ typedef struct {
 | 
			
		||||
  .int_ep_config = { \
 | 
			
		||||
    .ep_mode = USB_EP_MODE_TYPE_INTR, \
 | 
			
		||||
    .setup_cb = NULL, \
 | 
			
		||||
    .in_cb = sduInterruptTransmitted, \
 | 
			
		||||
    .in_cb = qmkusbInterruptTransmitted, \
 | 
			
		||||
    .out_cb = NULL, \
 | 
			
		||||
    .in_maxsize = CDC_NOTIFICATION_EPSIZE, \
 | 
			
		||||
    .out_maxsize = 0, \
 | 
			
		||||
@ -230,7 +227,14 @@ typedef struct {
 | 
			
		||||
    .usbp = &USB_DRIVER, \
 | 
			
		||||
    .bulk_in = stream##_IN_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 {
 | 
			
		||||
    struct {
 | 
			
		||||
#ifdef CONSOLE_ENABLE
 | 
			
		||||
      stream_driver_t console_driver;
 | 
			
		||||
      usb_driver_config_t console_driver;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef RAW_ENABLE
 | 
			
		||||
      stream_driver_t raw_driver;
 | 
			
		||||
      usb_driver_config_t raw_driver;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MIDI_ENABLE
 | 
			
		||||
      stream_driver_t midi_driver;
 | 
			
		||||
      usb_driver_config_t midi_driver;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef VIRTSER_ENABLE
 | 
			
		||||
      stream_driver_t serial_driver;
 | 
			
		||||
      usb_driver_config_t serial_driver;
 | 
			
		||||
#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
 | 
			
		||||
  #define CONSOLE_IN_CAPACITY 4
 | 
			
		||||
  #define CONSOLE_OUT_CAPACITY 4
 | 
			
		||||
  #define CONSOLE_IN_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
 | 
			
		||||
#ifdef RAW_ENABLE
 | 
			
		||||
  #define RAW_IN_CAPACITY 4
 | 
			
		||||
  #define RAW_OUT_CAPACITY 4
 | 
			
		||||
  #define RAW_IN_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
 | 
			
		||||
 | 
			
		||||
#ifdef MIDI_ENABLE
 | 
			
		||||
@ -275,7 +279,7 @@ static stream_drivers_t drivers = {
 | 
			
		||||
  #define MIDI_STREAM_OUT_CAPACITY 4
 | 
			
		||||
  #define MIDI_STREAM_IN_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
 | 
			
		||||
 | 
			
		||||
#ifdef VIRTSER_ENABLE
 | 
			
		||||
@ -283,11 +287,11 @@ static stream_drivers_t drivers = {
 | 
			
		||||
  #define CDC_OUT_CAPACITY 4
 | 
			
		||||
  #define CDC_IN_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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#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
 | 
			
		||||
    usbInitEndpointI(usbp, NKRO_IN_EPNUM, &nkro_ep_config);
 | 
			
		||||
#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_out, &drivers.array[i].out_ep_config);
 | 
			
		||||
      if (drivers.array[i].config.int_in) {
 | 
			
		||||
        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();
 | 
			
		||||
    return;
 | 
			
		||||
@ -333,20 +337,20 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
 | 
			
		||||
  case USB_EVENT_UNCONFIGURED:
 | 
			
		||||
    /* Falls into.*/
 | 
			
		||||
  case USB_EVENT_RESET:
 | 
			
		||||
      for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
 | 
			
		||||
      for (int i=0;i<NUM_USB_DRIVERS;i++) {
 | 
			
		||||
        chSysLockFromISR();
 | 
			
		||||
        /* Disconnection event on suspend.*/
 | 
			
		||||
        sduSuspendHookI(&drivers.array[i].driver);
 | 
			
		||||
        qmkusbSuspendHookI(&drivers.array[i].driver);
 | 
			
		||||
        chSysUnlockFromISR();
 | 
			
		||||
      }
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  case USB_EVENT_WAKEUP:
 | 
			
		||||
    //TODO: from ISR! print("[W]");
 | 
			
		||||
      for (int i=0;i<NUM_STREAM_DRIVERS;i++) {
 | 
			
		||||
      for (int i=0;i<NUM_USB_DRIVERS;i++) {
 | 
			
		||||
        chSysLockFromISR();
 | 
			
		||||
        /* Disconnection event on suspend.*/
 | 
			
		||||
        sduWakeupHookI(&drivers.array[i].driver);
 | 
			
		||||
        qmkusbWakeupHookI(&drivers.array[i].driver);
 | 
			
		||||
        chSysUnlockFromISR();
 | 
			
		||||
      }
 | 
			
		||||
    suspend_wakeup_init();
 | 
			
		||||
@ -527,10 +531,10 @@ static bool usb_request_hook_cb(USBDriver *usbp) {
 | 
			
		||||
    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) {
 | 
			
		||||
      // 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) {
 | 
			
		||||
  kbd_sof_cb(usbp);
 | 
			
		||||
  osalSysLockFromISR();
 | 
			
		||||
  for (int i=0; i<NUM_STREAM_DRIVERS;i++) {
 | 
			
		||||
    sduSOFHookI(&drivers.array[i].driver);
 | 
			
		||||
  for (int i=0; i<NUM_USB_DRIVERS;i++) {
 | 
			
		||||
    qmkusbSOFHookI(&drivers.array[i].driver);
 | 
			
		||||
  }
 | 
			
		||||
  osalSysUnlockFromISR();
 | 
			
		||||
}
 | 
			
		||||
@ -560,17 +564,13 @@ static const USBConfig usbcfg = {
 | 
			
		||||
 * Initialize the USB driver
 | 
			
		||||
 */
 | 
			
		||||
void init_usb_driver(USBDriver *usbp) {
 | 
			
		||||
  for (int i=0; i<NUM_STREAM_DRIVERS;i++) {
 | 
			
		||||
    SerialUSBDriver* driver = &drivers.array[i].driver;
 | 
			
		||||
  for (int i=0; i<NUM_USB_DRIVERS;i++) {
 | 
			
		||||
    QMKUSBDriver* driver = &drivers.array[i].driver;
 | 
			
		||||
    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].int_ep_config.in_state = &drivers.array[i].int_ep_state;
 | 
			
		||||
    sduObjectInit(driver);
 | 
			
		||||
    bqnotify_t notify = driver->ibqueue.notify;
 | 
			
		||||
    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);
 | 
			
		||||
    qmkusbObjectInit(driver, &drivers.array[i].config);
 | 
			
		||||
    qmkusbStart(driver, &drivers.array[i].config);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user