summaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
Diffstat (limited to 'usb')
-rw-r--r--usb/endpt0.c82
-rw-r--r--usb/txhandler.c82
-rw-r--r--usb/txhandler.h38
3 files changed, 135 insertions, 67 deletions
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 <tk@the-tk.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include <reg/usbotg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#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 <tk@the-tk.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef FMK_USB_TXHANDLER_H
+#define FMK_USB_TXHANDLER_H
+
+#include <reg/usbotg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+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 */