#include <hal.h>
#include "usb_driver.h"
#include <string.h>
static cdc_linecoding_t linecoding = {{0x00, 0x96, 0x00, 0x00},
LC_STOP_1,
LC_PARITY_NONE,
8};
static bool qmkusb_start_receive(QMKUSBDriver *qmkusbp) {
uint8_t *buf;
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || (qmkusbp->state != QMKUSB_READY)) {
return true;
}
if (usbGetReceiveStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
return true;
}
buf = ibqGetEmptyBufferI(&qmkusbp->ibqueue);
if (buf == NULL) {
return true;
}
usbStartReceiveI(qmkusbp->config->usbp, qmkusbp->config->bulk_out, buf, qmkusbp->ibqueue.bsize - sizeof(size_t));
return false;
}
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, sysinterval_t timeout) { return obqPutTimeout(&((QMKUSBDriver *)ip)->obqueue, b, timeout); }
static msg_t _gett(void *ip, sysinterval_t timeout) { return ibqGetTimeout(&((QMKUSBDriver *)ip)->ibqueue, timeout); }
static size_t _writet(void *ip, const uint8_t *bp, size_t n, sysinterval_t timeout) { return obqWriteTimeout(&((QMKUSBDriver *)ip)->obqueue, bp, n, timeout); }
static size_t _readt(void *ip, uint8_t *bp, size_t n, sysinterval_t timeout) { return ibqReadTimeout(&((QMKUSBDriver *)ip)->ibqueue, bp, n, timeout); }
static const struct QMKUSBDriverVMT vmt = {0, _write, _read, _put, _get, _putt, _gett, _writet, _readt};
static void ibnotify(io_buffers_queue_t *bqp) {
QMKUSBDriver *qmkusbp = bqGetLinkX(bqp);
(void)qmkusb_start_receive(qmkusbp);
}
static void obnotify(io_buffers_queue_t *bqp) {
size_t n;
QMKUSBDriver *qmkusbp = bqGetLinkX(bqp);
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || (qmkusbp->state != QMKUSB_READY)) {
return;
}
if (!usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
if (buf != NULL) {
usbStartTransmitI(qmkusbp->config->usbp, qmkusbp->config->bulk_in, buf, n);
}
}
}
void qmkusbInit(void) {}
void qmkusbObjectInit(QMKUSBDriver *qmkusbp, const QMKUSBConfig *config) {
qmkusbp->vmt = &vmt;
osalEventObjectInit(&qmkusbp->event);
qmkusbp->state = QMKUSB_STOP;
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);
}
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();
}
void qmkusbStop(QMKUSBDriver *qmkusbp) {
USBDriver *usbp = qmkusbp->config->usbp;
osalDbgCheck(qmkusbp != NULL);
osalSysLock();
osalDbgAssert((qmkusbp->state == QMKUSB_STOP) || (qmkusbp->state == QMKUSB_READY), "invalid 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;
chnAddFlagsI(qmkusbp, CHN_DISCONNECTED);
ibqResetI(&qmkusbp->ibqueue);
obqResetI(&qmkusbp->obqueue);
osalOsRescheduleS();
osalSysUnlock();
}
void qmkusbSuspendHookI(QMKUSBDriver *qmkusbp) {
chnAddFlagsI(qmkusbp, CHN_DISCONNECTED);
bqSuspendI(&qmkusbp->ibqueue);
bqSuspendI(&qmkusbp->obqueue);
}
void qmkusbWakeupHookI(QMKUSBDriver *qmkusbp) {
chnAddFlagsI(qmkusbp, CHN_CONNECTED);
bqResumeX(&qmkusbp->ibqueue);
bqResumeX(&qmkusbp->obqueue);
}
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);
}
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:
usbSetupTransfer(usbp, NULL, 0, NULL);
return true;
default:
return false;
}
}
return false;
}
void qmkusbSOFHookI(QMKUSBDriver *qmkusbp) {
if ((usbGetDriverStateI(qmkusbp->config->usbp) != USB_ACTIVE) || (qmkusbp->state != QMKUSB_READY)) {
return;
}
if (usbGetTransmitStatusI(qmkusbp->config->usbp, qmkusbp->config->bulk_in)) {
return;
}
if (obqTryFlushI(&qmkusbp->obqueue)) {
size_t n;
uint8_t *buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
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);
}
}
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();
chnAddFlagsI(qmkusbp, CHN_OUTPUT_EMPTY);
if (usbp->epc[ep]->in_state->txsize > 0U) {
obqReleaseEmptyBufferI(&qmkusbp->obqueue);
}
buf = obqGetFullBufferI(&qmkusbp->obqueue, &n);
if (buf != NULL) {
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)) {
if (!qmkusbp->config->fixed_size) {
usbStartTransmitI(usbp, ep, usbp->setup, 0);
}
} else {
}
osalSysUnlockFromISR();
}
void qmkusbDataReceived(USBDriver *usbp, usbep_t ep) {
QMKUSBDriver *qmkusbp = usbp->out_params[ep - 1U];
if (qmkusbp == NULL) {
return;
}
osalSysLockFromISR();
chnAddFlagsI(qmkusbp, CHN_INPUT_AVAILABLE);
ibqPostFullBufferI(&qmkusbp->ibqueue, usbGetReceiveTransactionSizeX(qmkusbp->config->usbp, qmkusbp->config->bulk_out));
(void)qmkusb_start_receive(qmkusbp);
osalSysUnlockFromISR();
}
void qmkusbInterruptTransmitted(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
}