From 0f3ba45c0b1eb233a66ebd4191ecd39c0c62adad Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Thu, 25 May 2017 21:29:03 +0100 Subject: usb/txhandler: generate transmission handling --- Makefile | 2 +- usb/endpt0.c | 82 +++++++++++---------------------------------------------- usb/txhandler.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ usb/txhandler.h | 38 ++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 68 deletions(-) create mode 100644 usb/txhandler.c create mode 100644 usb/txhandler.h diff --git a/Makefile b/Makefile index fc7c13c..c9f111c 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ LDFLAGS = -T layout.ld -O2 -flto -ffreestanding -nostdlib ASFLAGS = $(TARGET_ARCH) OBJ := crt0.o vectors.o flashconf.o setup.o fmk.o lib/le.o usb/usb.o \ - usb/endpt0.o usb/endpt1.o uart.o + usb/endpt0.o usb/endpt1.o usb/txhandler.o uart.o include $(MK20DX256)/mk20dx256.mk CPPFLAGS += $(mk20dx256_CPPFLAGS) diff --git a/usb/endpt0.c b/usb/endpt0.c index 57c994e..b3e195b 100644 --- a/usb/endpt0.c +++ b/usb/endpt0.c @@ -28,18 +28,16 @@ #include "bdt.h" #include "endpt0.h" #include "endpt1.h" +#include "txhandler.h" #include "descriptors.h" #define MAX_PACKET 64 static unsigned char buf[2][MAX_PACKET]; -static bool tx_odd; -static bool tx_data01; static volatile unsigned int nextaddr; -static void *tx_data; -static size_t tx_size; +static struct tx_ctx tx; struct tok_setup { uint8_t reqtyp; @@ -61,56 +59,6 @@ static void read_setup(struct tok_setup *setup, const void *_data) setup->length = le16toh(&data[6]); } -/* TODO: Make this a shared thing across all USB endpoints */ - -/* puttx: place data in the current buffer descriptor */ -static bool puttx(void *data, size_t size) -{ - if (GET_BIT(usb_bdt[0][BDT_TX][tx_odd].desc, BD_OWN)) - return false; - - /* TODO: Just stop bothering with const */ - usb_bdt[0][BDT_TX][tx_odd].addr = data; - usb_bdt[0][BDT_TX][tx_odd].desc = USB0_BD_INIT(size, tx_data01); - tx_odd = !tx_odd; - tx_data01 = !tx_data01; - - return true; -} - -/* pushtx: attempt to push rest of the current transmission into a BD */ -static bool pushtx(void) -{ - size_t size = tx_size; - - if (tx_data == NULL) - return false; - - if (size > MAX_PACKET) - size = MAX_PACKET; - - if (!puttx(tx_data, size)) - return false; - - tx_data = (char *)tx_data + size; - tx_size -= size; - - if (tx_size == 0 && size < MAX_PACKET) - tx_data = NULL; - - return true; -} - -/* quetx: enqueue a transmission */ -static void quetx(void *data, size_t size) -{ - tx_data = data; - tx_size = size; - - while (pushtx()) - ; -} - /* usb_endpt0_disable: Disable endpoint 0 (not valid) */ void usb_endpt0_disable(void) { @@ -133,9 +81,7 @@ void usb_endpt0_enable(void) USB0_ENDPT(0) = BV(ENDPT_EPRXEN) | BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK); nextaddr = 0; - tx_data = NULL; - tx_odd = 0; - tx_data01 = 0; + tx = TX_CTX(usb_bdt[0][BDT_TX], MAX_PACKET); } /* trunc: truncate size_t to a limit TODO: MOVE THIS */ @@ -152,32 +98,32 @@ static void tok_setup(struct tok_setup *setup) switch (setup->reqtyp << 8 | setup->req) { case 0x0005: /* SET ADDRESS */ nextaddr = setup->value; - puttx(NULL, 0); + tx_que(&tx, NULL, 0); break; case 0x0009: /* SET CONFIGURATION */ usb_endpt1_enable(); - puttx(NULL, 0); + tx_que(&tx, NULL, 0); break; case 0x210a: /* SET IDLE */ - puttx(NULL, 0); + tx_que(&tx, NULL, 0); break; case 0x8106: /* GET INTERFACE */ case 0x8006: /* GET DESCRIPTOR */ switch (setup->value) { case 0x0100: /* DEVICE */ - quetx(ds_dev, trunc(ARRLEN(ds_dev), setup->length)); + tx_que(&tx, ds_dev, trunc(ARRLEN(ds_dev), setup->length)); return; case 0x0200: /* CONFIGURATION */ - quetx(ds_conf, trunc(ARRLEN(ds_conf), setup->length)); + tx_que(&tx, ds_conf, trunc(ARRLEN(ds_conf), setup->length)); return; case 0x0300: /* STRING 0 */ - quetx(ds_lang, trunc(ARRLEN(ds_lang), setup->length)); + tx_que(&tx, ds_lang, trunc(ARRLEN(ds_lang), setup->length)); return; case 0x0301: /* STRING 1 */ - quetx(ds_str1, trunc(ARRLEN(ds_str1), setup->length)); + tx_que(&tx, ds_str1, trunc(ARRLEN(ds_str1), setup->length)); return; case 0x2200: - quetx(ds_hidrep, trunc(ARRLEN(ds_hidrep), setup->length)); + tx_que(&tx, ds_hidrep, trunc(ARRLEN(ds_hidrep), setup->length)); return; } /* fall through */ @@ -200,6 +146,7 @@ void usb_endpt0_token(uint8_t state) bd->desc = USB0_BD_INIT(sizeof buf[0], 1); break; case BD_TOK_PID_IN: + tx_push(&tx); if (nextaddr) { USB0_ADDR = nextaddr; nextaddr = 0; @@ -209,11 +156,12 @@ void usb_endpt0_token(uint8_t state) read_setup(&setup, bd->addr); bd->desc = USB0_BD_INIT(sizeof buf[0], 1); + /* This is a bit of a dodgy thing to do */ usb_bdt[0][BDT_TX][BDT_EVEN].desc = 0; usb_bdt[0][BDT_TX][BDT_ODD].desc = 0; - tx_data = NULL; + tx.data = NULL; - tx_data01 = 1; + tx.data01 = 1; tok_setup(&setup); diff --git a/usb/txhandler.c b/usb/txhandler.c new file mode 100644 index 0000000..89cd0cf --- /dev/null +++ b/usb/txhandler.c @@ -0,0 +1,82 @@ +/* + * usb/txhandler.c -- USB Transmission Handling + * + * Copyright (C) 2017 Tomasz Kramkowski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include + +#include "bdt.h" +#include "txhandler.h" + +/* puttx: place data in the current buffer descriptor */ +static bool puttx(struct tx_ctx *tx, void *data, size_t size) +{ + if (GET_BIT(tx->bdt[tx->odd].desc, BD_OWN)) + return false; + + tx->bdt[tx->odd].addr = data; + tx->bdt[tx->odd].desc = USB0_BD_INIT(size, tx->data01); + tx->odd = !tx->odd; + tx->data01 = !tx->data01; + + return true; +} + +/* tx_push: attempt to push rest of the current transmission into a BD */ +bool tx_push(struct tx_ctx *tx) +{ + size_t size = tx->size; + + if (tx->data == NULL) + return false; + + if (size > tx->max) + size = tx->max; + + if (!puttx(tx, tx->data, size)) + return false; + + tx->data = (char *)tx->data + size; + tx->size -= size; + + if (tx->size == 0 && size < tx->max) + tx->data = NULL; + + return true; +} + +/* tx_que: enqueue a transmission */ +void tx_que(struct tx_ctx *tx, void *data, size_t size) +{ + if (data == NULL || size == 0) { + puttx(tx, NULL, 0); + return; + } + + tx->data = data; + tx->size = size; + + while (tx_push(tx)) + ; +} + +/* tx_isempty: check if there's nothing left to transmit */ +bool tx_isempty(struct tx_ctx *tx) +{ + return tx->data == NULL; +} diff --git a/usb/txhandler.h b/usb/txhandler.h new file mode 100644 index 0000000..3e6bc4c --- /dev/null +++ b/usb/txhandler.h @@ -0,0 +1,38 @@ +/* + * usb/txhandler.h -- USB Transmission Handling + * + * Copyright (C) 2017 Tomasz Kramkowski + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef FMK_USB_TXHANDLER_H +#define FMK_USB_TXHANDLER_H + +#include +#include +#include + +struct tx_ctx { + volatile struct usb0_bd *bdt; + bool odd, data01; + void *data; + size_t size, max; +}; +#define TX_CTX(b, m) ((struct tx_ctx){ .bdt = (b), .max = (m) }) + +void tx_que(struct tx_ctx *tx, void *data, size_t size); +bool tx_push(struct tx_ctx *tx); +bool tx_isempty(struct tx_ctx *tx); + +#endif /* FMK_USB_TXHANDLER_H */ -- cgit v1.2.3-54-g00ecf