aboutsummaryrefslogtreecommitdiffstats
path: root/libmaple/usb/stm32f1
diff options
context:
space:
mode:
Diffstat (limited to 'libmaple/usb/stm32f1')
-rw-r--r--libmaple/usb/stm32f1/usb.c381
-rw-r--r--libmaple/usb/stm32f1/usb_cdcacm.c762
-rw-r--r--libmaple/usb/stm32f1/usb_descriptors.h148
-rw-r--r--libmaple/usb/stm32f1/usb_lib_globals.h55
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.c79
-rw-r--r--libmaple/usb/stm32f1/usb_reg_map.h433
6 files changed, 1858 insertions, 0 deletions
diff --git a/libmaple/usb/stm32f1/usb.c b/libmaple/usb/stm32f1/usb.c
new file mode 100644
index 0000000..0130bab
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb.c
@@ -0,0 +1,381 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usb/usb.c
+ * @brief USB support.
+ *
+ * This is a mess. What we need almost amounts to a ground-up rewrite.
+ */
+
+#include <libmaple/usb.h>
+
+#include <libmaple/libmaple.h>
+#include <libmaple/rcc.h>
+
+/* Private headers */
+#include "usb_reg_map.h"
+#include "usb_lib_globals.h"
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+
+static void dispatch_ctr_lp(void);
+
+/*
+ * usb_lib/ globals
+ */
+
+uint16 SaveTState; /* caches TX status for later use */
+uint16 SaveRState; /* caches RX status for later use */
+
+/*
+ * Other state
+ */
+
+typedef enum {
+ RESUME_EXTERNAL,
+ RESUME_INTERNAL,
+ RESUME_LATER,
+ RESUME_WAIT,
+ RESUME_START,
+ RESUME_ON,
+ RESUME_OFF,
+ RESUME_ESOF
+} RESUME_STATE;
+
+struct {
+ volatile RESUME_STATE eState;
+ volatile uint8 bESOFcnt;
+} ResumeS;
+
+static usblib_dev usblib = {
+ .irq_mask = USB_ISR_MSK,
+ .state = USB_UNCONNECTED,
+ .clk_id = RCC_USB,
+};
+usblib_dev *USBLIB = &usblib;
+
+/*
+ * Routines
+ */
+
+void usb_init_usblib(usblib_dev *dev,
+ void (**ep_int_in)(void),
+ void (**ep_int_out)(void)) {
+ rcc_clk_enable(dev->clk_id);
+
+ dev->ep_int_in = ep_int_in;
+ dev->ep_int_out = ep_int_out;
+
+ /* usb_lib/ declares both and then assumes that pFoo points to Foo
+ * (even though the names don't always match), which is stupid for
+ * all of the obvious reasons, but whatever. Here we are. */
+ pInformation = &Device_Info;
+ pProperty = &Device_Property;
+ pUser_Standard_Requests = &User_Standard_Requests;
+
+ pInformation->ControlState = 2; /* FIXME [0.0.12] use
+ CONTROL_STATE enumerator */
+ pProperty->Init();
+}
+
+static void usb_suspend(void) {
+ uint16 cntr;
+
+ /* TODO decide if read/modify/write is really what we want
+ * (e.g. usb_resume_init() reconfigures CNTR). */
+ cntr = USB_BASE->CNTR;
+ cntr |= USB_CNTR_FSUSP;
+ USB_BASE->CNTR = cntr;
+ cntr |= USB_CNTR_LP_MODE;
+ USB_BASE->CNTR = cntr;
+
+ USBLIB->state = USB_SUSPENDED;
+}
+
+static void usb_resume_init(void) {
+ uint16 cntr;
+
+ cntr = USB_BASE->CNTR;
+ cntr &= ~USB_CNTR_LP_MODE;
+ USB_BASE->CNTR = cntr;
+
+ /* Enable interrupt lines */
+ USB_BASE->CNTR = USB_ISR_MSK;
+}
+
+static void usb_resume(RESUME_STATE eResumeSetVal) {
+ uint16 cntr;
+
+ if (eResumeSetVal != RESUME_ESOF)
+ ResumeS.eState = eResumeSetVal;
+
+ switch (ResumeS.eState)
+ {
+ case RESUME_EXTERNAL:
+ usb_resume_init();
+ ResumeS.eState = RESUME_OFF;
+ break;
+ case RESUME_INTERNAL:
+ usb_resume_init();
+ ResumeS.eState = RESUME_START;
+ break;
+ case RESUME_LATER:
+ ResumeS.bESOFcnt = 2;
+ ResumeS.eState = RESUME_WAIT;
+ break;
+ case RESUME_WAIT:
+ ResumeS.bESOFcnt--;
+ if (ResumeS.bESOFcnt == 0)
+ ResumeS.eState = RESUME_START;
+ break;
+ case RESUME_START:
+ cntr = USB_BASE->CNTR;
+ cntr |= USB_CNTR_RESUME;
+ USB_BASE->CNTR = cntr;
+ ResumeS.eState = RESUME_ON;
+ ResumeS.bESOFcnt = 10;
+ break;
+ case RESUME_ON:
+ ResumeS.bESOFcnt--;
+ if (ResumeS.bESOFcnt == 0) {
+ cntr = USB_BASE->CNTR;
+ cntr &= ~USB_CNTR_RESUME;
+ USB_BASE->CNTR = cntr;
+ ResumeS.eState = RESUME_OFF;
+ }
+ break;
+ case RESUME_OFF:
+ case RESUME_ESOF:
+ default:
+ ResumeS.eState = RESUME_OFF;
+ break;
+ }
+}
+
+#define SUSPEND_ENABLED 1
+void __irq_usb_lp_can_rx0(void) {
+ uint16 istr = USB_BASE->ISTR;
+
+ /* Use USB_ISR_MSK to only include code for bits we care about. */
+
+#if (USB_ISR_MSK & USB_ISTR_RESET)
+ if (istr & USB_ISTR_RESET & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_RESET;
+ pProperty->Reset();
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_PMAOVR)
+ if (istr & ISTR_PMAOVR & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_PMAOVR;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_ERR)
+ if (istr & USB_ISTR_ERR & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_ERR;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_WKUP)
+ if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_WKUP;
+ usb_resume(RESUME_EXTERNAL);
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_SUSP)
+ if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) {
+ /* check if SUSPEND is possible */
+ if (SUSPEND_ENABLED) {
+ usb_suspend();
+ } else {
+ /* if not possible then resume after xx ms */
+ usb_resume(RESUME_LATER);
+ }
+ /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
+ USB_BASE->ISTR = ~USB_ISTR_SUSP;
+}
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_SOF)
+ if (istr & USB_ISTR_SOF & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_SOF;
+ }
+#endif
+
+#if (USB_ISR_MSK & USB_ISTR_ESOF)
+ if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) {
+ USB_BASE->ISTR = ~USB_ISTR_ESOF;
+ /* resume handling timing is made with ESOFs */
+ usb_resume(RESUME_ESOF); /* request without change of the machine state */
+ }
+#endif
+
+ /*
+ * Service the correct transfer interrupt.
+ */
+
+#if (USB_ISR_MSK & USB_ISTR_CTR)
+ if (istr & USB_ISTR_CTR & USBLIB->irq_mask) {
+ dispatch_ctr_lp();
+ }
+#endif
+}
+
+/*
+ * Auxiliary routines
+ */
+
+static inline uint8 dispatch_endpt_zero(uint16 istr_dir);
+static inline void dispatch_endpt(uint8 ep);
+static inline void set_rx_tx_status0(uint16 rx, uint16 tx);
+
+static void handle_setup0(void);
+static void handle_in0(void);
+static void handle_out0(void);
+
+static void dispatch_ctr_lp() {
+ uint16 istr;
+ while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) {
+ /* TODO WTF, figure this out: RM0008 says CTR is read-only,
+ * but ST's firmware claims it's clear-only, and emphasizes
+ * the importance of clearing it in more than one place. */
+ USB_BASE->ISTR = ~USB_ISTR_CTR;
+ uint8 ep_id = istr & USB_ISTR_EP_ID;
+ if (ep_id == 0) {
+ /* TODO figure out why it's OK to break out of the loop
+ * once we're done serving endpoint zero, but not okay if
+ * there are multiple nonzero endpoint transfers to
+ * handle. */
+ if (dispatch_endpt_zero(istr & USB_ISTR_DIR))
+ return;
+ } else {
+ dispatch_endpt(ep_id);
+ }
+ }
+}
+
+/* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's
+ * code, and is ugly/confusing in its use of SaveRState/SaveTState.
+ * Fixing this requires filling in handle_in0(), handle_setup0(),
+ * handle_out0(). */
+static inline uint8 dispatch_endpt_zero(uint16 istr_dir) {
+ uint32 epr = (uint16)USB_BASE->EP[0];
+
+ if (!(epr & (USB_EP_CTR_TX | USB_EP_SETUP | USB_EP_CTR_RX))) {
+ return 0;
+ }
+
+ /* Cache RX/TX statuses in SaveRState/SaveTState, respectively.
+ * The various handle_foo0() may clobber these values
+ * before we reset them at the end of this routine. */
+ SaveRState = epr & USB_EP_STAT_RX;
+ SaveTState = epr & USB_EP_STAT_TX;
+
+ /* Set actual RX/TX statuses to NAK while we're thinking */
+ set_rx_tx_status0(USB_EP_STAT_RX_NAK, USB_EP_STAT_TX_NAK);
+
+ if (istr_dir == 0) {
+ /* ST RM0008: "If DIR bit=0, CTR_TX bit is set in the USB_EPnR
+ * register related to the interrupting endpoint. The
+ * interrupting transaction is of IN type (data transmitted by
+ * the USB peripheral to the host PC)." */
+ ASSERT_FAULT(epr & USB_EP_CTR_TX);
+ usb_clear_ctr_tx(USB_EP0);
+ handle_in0();
+ } else {
+ /* RM0008: "If DIR bit=1, CTR_RX bit or both CTR_TX/CTR_RX
+ * are set in the USB_EPnR register related to the
+ * interrupting endpoint. The interrupting transaction is of
+ * OUT type (data received by the USB peripheral from the host
+ * PC) or two pending transactions are waiting to be
+ * processed."
+ *
+ * [mbolivar] Note how the following control flow (which
+ * replicates ST's) doesn't seem to actually handle both
+ * interrupts that are ostensibly pending when both CTR_RX and
+ * CTR_TX are set.
+ *
+ * TODO sort this mess out.
+ */
+ if (epr & USB_EP_CTR_TX) {
+ usb_clear_ctr_tx(USB_EP0);
+ handle_in0();
+ } else { /* SETUP or CTR_RX */
+ /* SETUP is held constant while CTR_RX is set, so clear it
+ * either way */
+ usb_clear_ctr_rx(USB_EP0);
+ if (epr & USB_EP_SETUP) {
+ handle_setup0();
+ } else { /* CTR_RX */
+ handle_out0();
+ }
+ }
+ }
+
+ set_rx_tx_status0(SaveRState, SaveTState);
+ return 1;
+}
+
+static inline void dispatch_endpt(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ /* If ISTR_CTR is set and the ISTR gave us this EP_ID to handle,
+ * then presumably at least one of CTR_RX and CTR_TX is set, but
+ * again, ST's control flow allows for the possibility of neither.
+ *
+ * TODO try to find out if neither being set is possible. */
+ if (epr & USB_EP_CTR_RX) {
+ usb_clear_ctr_rx(ep);
+ (USBLIB->ep_int_out[ep - 1])();
+ }
+ if (epr & USB_EP_CTR_TX) {
+ usb_clear_ctr_tx(ep);
+ (USBLIB->ep_int_in[ep - 1])();
+ }
+}
+
+static inline void set_rx_tx_status0(uint16 rx, uint16 tx) {
+ usb_set_ep_rx_stat(USB_EP0, rx);
+ usb_set_ep_tx_stat(USB_EP0, tx);
+}
+
+/* TODO Rip out usb_lib/ dependency from the following functions: */
+
+static void handle_setup0(void) {
+ Setup0_Process();
+}
+
+static void handle_in0(void) {
+ In0_Process();
+}
+
+static void handle_out0(void) {
+ Out0_Process();
+}
diff --git a/libmaple/usb/stm32f1/usb_cdcacm.c b/libmaple/usb/stm32f1/usb_cdcacm.c
new file mode 100644
index 0000000..6ef4806
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_cdcacm.c
@@ -0,0 +1,762 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+/**
+ * @file libmaple/usb/usb_cdcacm.c
+ * @brief USB CDC ACM (a.k.a. virtual serial terminal, VCOM).
+ *
+ * FIXME: this works on the STM32F1 USB peripherals, and probably no
+ * place else. Nonportable bits really need to be factored out, and
+ * the result made cleaner.
+ */
+
+#include <libmaple/usb_cdcacm.h>
+
+#include <libmaple/usb.h>
+#include <libmaple/nvic.h>
+#include <libmaple/delay.h>
+
+/* Private headers */
+#include "usb_descriptors.h"
+#include "usb_lib_globals.h"
+#include "usb_reg_map.h"
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+#include "usb_def.h"
+
+/******************************************************************************
+ ******************************************************************************
+ ***
+ *** HACK ALERT! FIXME FIXME FIXME FIXME!
+ ***
+ *** A bunch of LeafLabs-specific configuration lives in here for
+ *** now. This mess REALLY needs to get teased apart, with
+ *** appropriate pieces moved into Wirish.
+ ***
+ ******************************************************************************
+ *****************************************************************************/
+
+#if !(defined(BOARD_maple) || defined(BOARD_maple_RET6) || \
+ defined(BOARD_maple_mini) || defined(BOARD_maple_native))
+#warning USB CDC ACM relies on LeafLabs board-specific configuration.\
+ You may have problems on non-LeafLabs boards.
+#endif
+
+static void vcomDataTxCb(void);
+static void vcomDataRxCb(void);
+static uint8* vcomGetSetLineCoding(uint16);
+
+static void usbInit(void);
+static void usbReset(void);
+static RESULT usbDataSetup(uint8 request);
+static RESULT usbNoDataSetup(uint8 request);
+static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting);
+static uint8* usbGetDeviceDescriptor(uint16 length);
+static uint8* usbGetConfigDescriptor(uint16 length);
+static uint8* usbGetStringDescriptor(uint16 length);
+static void usbSetConfiguration(void);
+static void usbSetDeviceAddress(void);
+
+static void wait_reset(void);
+
+/*
+ * VCOM config
+ */
+
+#define VCOM_CTRL_EPNUM 0x00
+#define VCOM_CTRL_RX_ADDR 0x40
+#define VCOM_CTRL_TX_ADDR 0x80
+#define VCOM_CTRL_EPSIZE 0x40
+
+#define VCOM_TX_ENDP 1
+#define VCOM_TX_EPNUM 0x01
+#define VCOM_TX_ADDR 0xC0
+#define VCOM_TX_EPSIZE 0x40
+
+#define VCOM_NOTIFICATION_ENDP 2
+#define VCOM_NOTIFICATION_EPNUM 0x02
+#define VCOM_NOTIFICATION_ADDR 0x100
+#define VCOM_NOTIFICATION_EPSIZE 0x40
+
+#define VCOM_RX_ENDP 3
+#define VCOM_RX_EPNUM 0x03
+#define VCOM_RX_ADDR 0x110
+#define VCOM_RX_EPSIZE 0x40
+#define VCOM_RX_BUFLEN (VCOM_RX_EPSIZE*3)
+
+/*
+ * CDC ACM Requests
+ */
+
+#define SET_LINE_CODING 0x20
+#define GET_LINE_CODING 0x21
+#define SET_COMM_FEATURE 0x02
+#define SET_CONTROL_LINE_STATE 0x22
+#define CONTROL_LINE_DTR (0x01)
+#define CONTROL_LINE_RTS (0x02)
+
+/*
+ * Descriptors
+ */
+
+#define USB_DEVICE_CLASS_CDC 0x02
+#define USB_DEVICE_SUBCLASS_CDC 0x00
+#define LEAFLABS_ID_VENDOR 0x1EAF
+#define MAPLE_ID_PRODUCT 0x0004
+const USB_Descriptor_Device usbVcomDescriptor_Device = {
+ .bLength = sizeof(USB_Descriptor_Device),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = USB_DEVICE_CLASS_CDC,
+ .bDeviceSubClass = USB_DEVICE_SUBCLASS_CDC,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = 0x40,
+ .idVendor = LEAFLABS_ID_VENDOR,
+ .idProduct = MAPLE_ID_PRODUCT,
+ .bcdDevice = 0x0200,
+ .iManufacturer = 0x01,
+ .iProduct = 0x02,
+ .iSerialNumber = 0x00,
+ .bNumConfigurations = 0x01,
+};
+
+#define MAX_POWER (100 >> 1)
+const USB_Descriptor_Config usbVcomDescriptor_Config = {
+ .Config_Header = {
+ .bLength = sizeof(USB_Descriptor_Config_Header),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIGURATION,
+ .wTotalLength = sizeof(USB_Descriptor_Config),
+ .bNumInterfaces = 0x02,
+ .bConfigurationValue = 0x01,
+ .iConfiguration = 0x00,
+ .bmAttributes = (USB_CONFIG_ATTR_BUSPOWERED |
+ USB_CONFIG_ATTR_SELF_POWERED),
+ .bMaxPower = MAX_POWER,
+ },
+
+ .CCI_Interface = {
+ .bLength = sizeof(USB_Descriptor_Interface),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x01,
+ .bInterfaceClass = USB_INTERFACE_CLASS_CDC,
+ .bInterfaceSubClass = USB_INTERFACE_SUBCLASS_CDC_ACM,
+ .bInterfaceProtocol = 0x01, /* Common AT Commands */
+ .iInterface = 0x00,
+ },
+
+ .CDC_Functional_IntHeader = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x00,
+ .Data = {0x01, 0x10},
+ },
+
+ .CDC_Functional_CallManagement = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x01,
+ .Data = {0x03, 0x01},
+ },
+
+ .CDC_Functional_ACM = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(1),
+ .bDescriptorType = 0x24,
+ .SubType = 0x02,
+ .Data = {0x06},
+ },
+
+ .CDC_Functional_Union = {
+ .bLength = CDC_FUNCTIONAL_DESCRIPTOR_SIZE(2),
+ .bDescriptorType = 0x24,
+ .SubType = 0x06,
+ .Data = {0x00, 0x01},
+ },
+
+ .ManagementEndpoint = {
+ .bLength = sizeof(USB_Descriptor_Endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN |
+ VCOM_NOTIFICATION_EPNUM),
+ .bmAttributes = EP_TYPE_INTERRUPT,
+ .wMaxPacketSize = VCOM_NOTIFICATION_EPSIZE,
+ .bInterval = 0xFF,
+ },
+
+ .DCI_Interface = {
+ .bLength = sizeof(USB_Descriptor_Interface),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE,
+ .bInterfaceNumber = 0x01,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x02,
+ .bInterfaceClass = USB_INTERFACE_CLASS_DIC,
+ .bInterfaceSubClass = 0x00, /* None */
+ .bInterfaceProtocol = 0x00, /* None */
+ .iInterface = 0x00,
+ },
+
+ .DataOutEndpoint = {
+ .bLength = sizeof(USB_Descriptor_Endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_OUT | VCOM_RX_EPNUM),
+ .bmAttributes = EP_TYPE_BULK,
+ .wMaxPacketSize = VCOM_RX_EPSIZE,
+ .bInterval = 0x00,
+ },
+
+ .DataInEndpoint = {
+ .bLength = sizeof(USB_Descriptor_Endpoint),
+ .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT,
+ .bEndpointAddress = (USB_DESCRIPTOR_ENDPOINT_IN | VCOM_TX_EPNUM),
+ .bmAttributes = EP_TYPE_BULK,
+ .wMaxPacketSize = VCOM_TX_EPSIZE,
+ .bInterval = 0x00,
+ },
+};
+
+/*
+ String Identifiers:
+
+ we may choose to specify any or none of the following string
+ identifiers:
+
+ iManufacturer: LeafLabs
+ iProduct: Maple
+ iSerialNumber: NONE
+ iConfiguration: NONE
+ iInterface(CCI): NONE
+ iInterface(DCI): NONE
+
+ additionally we must provide the unicode language identifier,
+ which is 0x0409 for US English
+*/
+
+const uint8 usbVcomDescriptor_LangID[USB_DESCRIPTOR_STRING_LEN(1)] = {
+ USB_DESCRIPTOR_STRING_LEN(1),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 0x09,
+ 0x04,
+};
+
+const uint8 usbVcomDescriptor_iManufacturer[USB_DESCRIPTOR_STRING_LEN(8)] = {
+ USB_DESCRIPTOR_STRING_LEN(8),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 'L', 0, 'e', 0, 'a', 0, 'f', 0,
+ 'L', 0, 'a', 0, 'b', 0, 's', 0,
+};
+
+const uint8 usbVcomDescriptor_iProduct[USB_DESCRIPTOR_STRING_LEN(8)] = {
+ USB_DESCRIPTOR_STRING_LEN(8),
+ USB_DESCRIPTOR_TYPE_STRING,
+ 'M', 0, 'a', 0, 'p', 0, 'l', 0,
+ 'e', 0, ' ', 0, ' ', 0, ' ', 0
+};
+
+ONE_DESCRIPTOR Device_Descriptor = {
+ (uint8*)&usbVcomDescriptor_Device,
+ sizeof(USB_Descriptor_Device)
+};
+
+ONE_DESCRIPTOR Config_Descriptor = {
+ (uint8*)&usbVcomDescriptor_Config,
+ sizeof(USB_Descriptor_Config)
+};
+
+ONE_DESCRIPTOR String_Descriptor[3] = {
+ {(uint8*)&usbVcomDescriptor_LangID, USB_DESCRIPTOR_STRING_LEN(1)},
+ {(uint8*)&usbVcomDescriptor_iManufacturer,USB_DESCRIPTOR_STRING_LEN(8)},
+ {(uint8*)&usbVcomDescriptor_iProduct, USB_DESCRIPTOR_STRING_LEN(8)}
+};
+
+/*
+ * Etc.
+ */
+
+typedef enum {
+ DTR_UNSET,
+ DTR_HIGH,
+ DTR_NEGEDGE,
+ DTR_LOW
+} RESET_STATE;
+
+typedef struct {
+ uint32 bitrate;
+ uint8 format;
+ uint8 paritytype;
+ uint8 datatype;
+} USB_Line_Coding;
+
+uint8 last_request = 0;
+USB_Line_Coding line_coding = {
+ .bitrate = 115200,
+ .format = 0x00, /* stop bits-1 */
+ .paritytype = 0x00,
+ .datatype = 0x08
+};
+uint8 vcomBufferRx[VCOM_RX_BUFLEN];
+volatile uint32 countTx = 0;
+volatile uint32 recvBufIn = 0;
+volatile uint32 recvBufOut = 0;
+volatile uint32 maxNewBytes = VCOM_RX_BUFLEN;
+volatile uint32 newBytes = 0;
+RESET_STATE reset_state = DTR_UNSET;
+uint8 line_dtr_rts = 0;
+
+/*
+ * Endpoint callbacks
+ */
+
+static void (*ep_int_in[7])(void) =
+ {vcomDataTxCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
+
+static void (*ep_int_out[7])(void) =
+ {NOP_Process,
+ NOP_Process,
+ vcomDataRxCb,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process,
+ NOP_Process};
+
+/*
+ * Globals required by usb_lib/
+ */
+
+#define NUM_ENDPTS 0x04
+DEVICE Device_Table = {
+ .Total_Endpoint = NUM_ENDPTS,
+ .Total_Configuration = 1
+};
+
+#define MAX_PACKET_SIZE 0x40 /* 64B, maximum for USB FS Devices */
+DEVICE_PROP Device_Property = {
+ .Init = usbInit,
+ .Reset = usbReset,
+ .Process_Status_IN = NOP_Process,
+ .Process_Status_OUT = NOP_Process,
+ .Class_Data_Setup = usbDataSetup,
+ .Class_NoData_Setup = usbNoDataSetup,
+ .Class_Get_Interface_Setting = usbGetInterfaceSetting,
+ .GetDeviceDescriptor = usbGetDeviceDescriptor,
+ .GetConfigDescriptor = usbGetConfigDescriptor,
+ .GetStringDescriptor = usbGetStringDescriptor,
+ .RxEP_buffer = NULL,
+ .MaxPacketSize = MAX_PACKET_SIZE
+};
+
+USER_STANDARD_REQUESTS User_Standard_Requests = {
+ .User_GetConfiguration = NOP_Process,
+ .User_SetConfiguration = usbSetConfiguration,
+ .User_GetInterface = NOP_Process,
+ .User_SetInterface = NOP_Process,
+ .User_GetStatus = NOP_Process,
+ .User_ClearFeature = NOP_Process,
+ .User_SetEndPointFeature = NOP_Process,
+ .User_SetDeviceFeature = NOP_Process,
+ .User_SetDeviceAddress = usbSetDeviceAddress
+};
+
+/*
+ * CDC ACM interface
+ */
+
+void usb_cdcacm_enable(gpio_dev *disc_dev, uint8 disc_bit) {
+ /* Present ourselves to the host */
+ gpio_set_mode(disc_dev, disc_bit, GPIO_OUTPUT_PP);
+ gpio_write_bit(disc_dev, disc_bit, 0); // presents us to the host
+
+ /* initialize USB peripheral */
+ usb_init_usblib(USBLIB, ep_int_in, ep_int_out);
+}
+
+void usb_cdcacm_disable(gpio_dev *disc_dev, uint8 disc_bit) {
+ // These are just guesses about how to do this, but it seems to work.
+ // TODO: verify this with USB spec
+ nvic_irq_disable(NVIC_USB_LP_CAN_RX0);
+ gpio_write_bit(disc_dev, disc_bit, 1);
+}
+
+void usb_cdcacm_putc(char ch) {
+ while (!usb_cdcacm_tx((uint8*)&ch, 1))
+ ;
+}
+
+/* This function is non-blocking.
+ *
+ * It copies data from a usercode buffer into the USB peripheral TX
+ * buffer and return the number placed in that buffer.
+ */
+uint32 usb_cdcacm_tx(const uint8* buf, uint32 len) {
+ /* Last transmission hasn't finished, abort */
+ if (countTx) {
+ return 0;
+ }
+
+ // We can only put VCOM_TX_EPSIZE bytes in the buffer
+ /* FIXME then why are we only copying half as many? */
+ if (len > VCOM_TX_EPSIZE / 2) {
+ len = VCOM_TX_EPSIZE / 2;
+ }
+
+ // Try to load some bytes if we can
+ if (len) {
+ usb_copy_to_pma(buf, len, VCOM_TX_ADDR);
+ usb_set_ep_tx_count(VCOM_TX_ENDP, len);
+ countTx += len;
+ usb_set_ep_tx_stat(VCOM_TX_ENDP, USB_EP_STAT_TX_VALID);
+ }
+
+ return len;
+}
+
+/* returns the number of available bytes are in the recv FIFO */
+uint32 usb_cdcacm_data_available(void) {
+ return newBytes;
+}
+
+uint16 usb_cdcacm_get_pending() {
+ return countTx;
+}
+
+/* Nonblocking byte receive.
+ *
+ * Copies up to len bytes from our private data buffer (*NOT* the PMA)
+ * into buf and deq's the FIFO. */
+uint32 usb_cdcacm_rx(uint8* buf, uint32 len) {
+ static int offset = 0;
+ int i;
+
+ if (len > newBytes) {
+ len = newBytes;
+ }
+
+ for (i = 0; i < len; i++) {
+ buf[i] = vcomBufferRx[i + offset];
+ }
+
+ newBytes -= len;
+ offset += len;
+
+ /* Re-enable the RX endpoint, which we had set to receive 0 bytes */
+ if (newBytes == 0) {
+ usb_set_ep_rx_count(VCOM_RX_ENDP, VCOM_RX_EPSIZE);
+ usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_VALID);
+ offset = 0;
+ }
+
+ return len;
+}
+
+uint8 usb_cdcacm_get_dtr() {
+ return ((line_dtr_rts & CONTROL_LINE_DTR) != 0);
+}
+
+uint8 usb_cdcacm_get_rts() {
+ return ((line_dtr_rts & CONTROL_LINE_RTS) != 0);
+}
+
+/*
+ * Callbacks
+ */
+
+static void vcomDataTxCb(void) {
+ /* assumes tx transactions are atomic 64 bytes (nearly certain they are) */
+ countTx = 0;
+}
+
+#define EXC_RETURN 0xFFFFFFF9
+#define DEFAULT_CPSR 0x61000000
+static void vcomDataRxCb(void) {
+ /* FIXME this is mad buggy */
+
+ /* setEPRxCount on the previous cycle should garuntee
+ we havnt received more bytes than we can fit */
+ newBytes = usb_get_ep_rx_count(VCOM_RX_ENDP);
+ usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_NAK);
+
+ /* magic number, {0x31, 0x45, 0x41, 0x46} is "1EAF" */
+ uint8 chkBuf[4];
+ uint8 cmpBuf[4] = {0x31, 0x45, 0x41, 0x46};
+ if (reset_state == DTR_NEGEDGE) {
+ reset_state = DTR_LOW;
+
+ if (newBytes >= 4) {
+ unsigned int target = (unsigned int)wait_reset | 0x1;
+
+ usb_copy_from_pma(chkBuf, 4, VCOM_RX_ADDR);
+
+ int i;
+ USB_Bool cmpMatch = TRUE;
+ for (i = 0; i < 4; i++) {
+ if (chkBuf[i] != cmpBuf[i]) {
+ cmpMatch = FALSE;
+ }
+ }
+
+ if (cmpMatch) {
+ asm volatile("mov r0, %[stack_top] \n\t" // Reset stack
+ "mov sp, r0 \n\t"
+ "mov r0, #1 \n\t"
+ "mov r1, %[target_addr] \n\t"
+ "mov r2, %[cpsr] \n\t"
+ "push {r2} \n\t" // Fake xPSR
+ "push {r1} \n\t" // PC target addr
+ "push {r0} \n\t" // Fake LR
+ "push {r0} \n\t" // Fake R12
+ "push {r0} \n\t" // Fake R3
+ "push {r0} \n\t" // Fake R2
+ "push {r0} \n\t" // Fake R1
+ "push {r0} \n\t" // Fake R0
+ "mov lr, %[exc_return] \n\t"
+ "bx lr"
+ :
+ : [stack_top] "r" (STACK_TOP),
+ [target_addr] "r" (target),
+ [exc_return] "r" (EXC_RETURN),
+ [cpsr] "r" (DEFAULT_CPSR)
+ : "r0", "r1", "r2");
+ /* should never get here */
+ }
+ }
+ }
+
+ usb_copy_from_pma(vcomBufferRx, newBytes, VCOM_RX_ADDR);
+}
+
+static uint8* vcomGetSetLineCoding(uint16 length) {
+ if (length == 0) {
+ pInformation->Ctrl_Info.Usb_wLength = sizeof(USB_Line_Coding);
+ }
+ return (uint8*)&line_coding;
+}
+
+static void usbInit(void) {
+ pInformation->Current_Configuration = 0;
+
+ USB_BASE->CNTR = USB_CNTR_FRES;
+
+ USBLIB->irq_mask = 0;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+ USB_BASE->ISTR = 0;
+ USBLIB->irq_mask = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+
+ USB_BASE->ISTR = 0;
+ USBLIB->irq_mask = USB_ISR_MSK;
+ USB_BASE->CNTR = USBLIB->irq_mask;
+
+ nvic_irq_enable(NVIC_USB_LP_CAN_RX0);
+ USBLIB->state = USB_UNCONNECTED;
+}
+
+/* choose addresses to give endpoints the max 64 byte buffers */
+#define BTABLE_ADDRESS 0x00
+static void usbReset(void) {
+ pInformation->Current_Configuration = 0;
+
+ /* current feature is current bmAttributes */
+ pInformation->Current_Feature = (USB_CONFIG_ATTR_BUSPOWERED |
+ USB_CONFIG_ATTR_SELF_POWERED);
+
+ USB_BASE->BTABLE = BTABLE_ADDRESS;
+
+ /* setup control endpoint 0 */
+ usb_set_ep_type(USB_EP0, USB_EP_EP_TYPE_CONTROL);
+ usb_set_ep_tx_stat(USB_EP0, USB_EP_STAT_TX_STALL);
+ usb_set_ep_rx_addr(USB_EP0, VCOM_CTRL_RX_ADDR);
+ usb_set_ep_tx_addr(USB_EP0, VCOM_CTRL_TX_ADDR);
+ usb_clear_status_out(USB_EP0);
+
+ usb_set_ep_rx_count(USB_EP0, pProperty->MaxPacketSize);
+ usb_set_ep_rx_stat(USB_EP0, USB_EP_STAT_RX_VALID);
+
+ /* setup management endpoint 1 */
+ usb_set_ep_type(VCOM_NOTIFICATION_ENDP, USB_EP_EP_TYPE_INTERRUPT);
+ usb_set_ep_tx_addr(VCOM_NOTIFICATION_ENDP, VCOM_NOTIFICATION_ADDR);
+ usb_set_ep_tx_stat(VCOM_NOTIFICATION_ENDP, USB_EP_STAT_TX_NAK);
+ usb_set_ep_rx_stat(VCOM_NOTIFICATION_ENDP, USB_EP_STAT_RX_DISABLED);
+
+ /* TODO figure out differences in style between RX/TX EP setup */
+
+ /* set up data endpoint OUT (RX) */
+ usb_set_ep_type(VCOM_RX_ENDP, USB_EP_EP_TYPE_BULK);
+ usb_set_ep_rx_addr(VCOM_RX_ENDP, 0x110);
+ usb_set_ep_rx_count(VCOM_RX_ENDP, 64);
+ usb_set_ep_rx_stat(VCOM_RX_ENDP, USB_EP_STAT_RX_VALID);
+
+ /* set up data endpoint IN (TX) */
+ usb_set_ep_type(VCOM_TX_ENDP, USB_EP_EP_TYPE_BULK);
+ usb_set_ep_tx_addr(VCOM_TX_ENDP, VCOM_TX_ADDR);
+ usb_set_ep_tx_stat(VCOM_TX_ENDP, USB_EP_STAT_TX_NAK);
+ usb_set_ep_rx_stat(VCOM_TX_ENDP, USB_EP_STAT_RX_DISABLED);
+
+ USBLIB->state = USB_ATTACHED;
+ SetDeviceAddress(0);
+
+ /* reset the rx fifo */
+ recvBufIn = 0;
+ recvBufOut = 0;
+ maxNewBytes = VCOM_RX_EPSIZE;
+ countTx = 0;
+}
+
+static RESULT usbDataSetup(uint8 request) {
+ uint8 *(*CopyRoutine)(uint16);
+ CopyRoutine = NULL;
+
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+ switch (request) {
+ case (GET_LINE_CODING):
+ CopyRoutine = vcomGetSetLineCoding;
+ last_request = GET_LINE_CODING;
+ break;
+ case (SET_LINE_CODING):
+ CopyRoutine = vcomGetSetLineCoding;
+ last_request = SET_LINE_CODING;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (CopyRoutine == NULL) {
+ return USB_UNSUPPORT;
+ }
+
+ pInformation->Ctrl_Info.CopyData = CopyRoutine;
+ pInformation->Ctrl_Info.Usb_wOffset = 0;
+ (*CopyRoutine)(0);
+ return USB_SUCCESS;
+}
+
+static RESULT usbNoDataSetup(uint8 request) {
+ uint8 new_signal;
+
+ /* we support set com feature but dont handle it */
+ if (Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
+
+ switch (request) {
+ case (SET_COMM_FEATURE):
+ return USB_SUCCESS;
+ case (SET_CONTROL_LINE_STATE):
+ /* to reset the board, pull both dtr and rts low
+ then pulse dtr by itself */
+ new_signal = (pInformation->USBwValues.bw.bb0 &
+ (CONTROL_LINE_DTR | CONTROL_LINE_RTS));
+ line_dtr_rts = new_signal & 0x03;
+
+ switch (reset_state) {
+ /* no default, covered enum */
+ case DTR_UNSET:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_HIGH:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_NEGEDGE;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_NEGEDGE:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+
+ case DTR_LOW:
+ if ((new_signal & CONTROL_LINE_DTR) == 0 ) {
+ reset_state = DTR_LOW;
+ } else {
+ reset_state = DTR_HIGH;
+ }
+ break;
+ }
+
+ return USB_SUCCESS;
+ }
+ }
+ return USB_UNSUPPORT;
+}
+
+static RESULT usbGetInterfaceSetting(uint8 interface, uint8 alt_setting) {
+ if (alt_setting > 0) {
+ return USB_UNSUPPORT;
+ } else if (interface > 1) {
+ return USB_UNSUPPORT;
+ }
+
+ return USB_SUCCESS;
+}
+
+static uint8* usbGetDeviceDescriptor(uint16 length) {
+ return Standard_GetDescriptorData(length, &Device_Descriptor);
+}
+
+static uint8* usbGetConfigDescriptor(uint16 length) {
+ return Standard_GetDescriptorData(length, &Config_Descriptor);
+}
+
+static uint8* usbGetStringDescriptor(uint16 length) {
+ uint8 wValue0 = pInformation->USBwValue0;
+
+ if (wValue0 > 2) {
+ return NULL;
+ }
+ return Standard_GetDescriptorData(length, &String_Descriptor[wValue0]);
+}
+
+static void usbSetConfiguration(void) {
+ if (pInformation->Current_Configuration != 0) {
+ USBLIB->state = USB_CONFIGURED;
+ }
+}
+
+static void usbSetDeviceAddress(void) {
+ USBLIB->state = USB_ADDRESSED;
+}
+
+#define RESET_DELAY 100000
+static void wait_reset(void) {
+ delay_us(RESET_DELAY);
+ nvic_sys_reset();
+}
diff --git a/libmaple/usb/stm32f1/usb_descriptors.h b/libmaple/usb/stm32f1/usb_descriptors.h
new file mode 100644
index 0000000..9bcb2b6
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_descriptors.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2010 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#ifndef _USB_DESCRIPTORS_H_
+#define _USB_DESCRIPTORS_H_
+
+#include <libmaple/libmaple.h>
+
+#define USB_DESCRIPTOR_TYPE_DEVICE 0x01
+#define USB_DESCRIPTOR_TYPE_CONFIGURATION 0x02
+#define USB_DESCRIPTOR_TYPE_STRING 0x03
+#define USB_DESCRIPTOR_TYPE_INTERFACE 0x04
+#define USB_DESCRIPTOR_TYPE_ENDPOINT 0x05
+
+#define USB_DEVICE_CLASS_CDC 0x02
+#define USB_DEVICE_SUBCLASS_CDC 0x00
+#define USB_INTERFACE_CLASS_CDC 0x02
+/* CDC Abstract Control Model */
+#define USB_INTERFACE_SUBCLASS_CDC_ACM 0x02
+#define USB_INTERFACE_CLASS_DIC 0x0A
+
+#define USB_CONFIG_ATTR_BUSPOWERED 0b10000000
+#define USB_CONFIG_ATTR_SELF_POWERED 0b11000000
+
+#define EP_TYPE_INTERRUPT 0x03
+#define EP_TYPE_BULK 0x02
+
+#define USB_DESCRIPTOR_ENDPOINT_IN 0x80
+#define USB_DESCRIPTOR_ENDPOINT_OUT 0x00
+
+#define USB_DESCRIPTOR_STRING_LEN(x) (2 + (x << 1))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define USB_DESCRIPTOR_STRING(len) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint16 bString[len]; \
+ } __packed
+
+#define CDC_FUNCTIONAL_DESCRIPTOR_SIZE(DataSize) (3 + DataSize)
+#define CDC_FUNCTIONAL_DESCRIPTOR(DataSize) \
+ struct { \
+ uint8 bLength; \
+ uint8 bDescriptorType; \
+ uint8 SubType; \
+ uint8 Data[DataSize]; \
+ } __packed
+
+typedef struct {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 bcdUSB;
+ uint8 bDeviceClass;
+ uint8 bDeviceSubClass;
+ uint8 bDeviceProtocol;
+ uint8 bMaxPacketSize0;
+ uint16 idVendor;
+ uint16 idProduct;
+ uint16 bcdDevice;
+ uint8 iManufacturer;
+ uint8 iProduct;
+ uint8 iSerialNumber;
+ uint8 bNumConfigurations;
+} __packed USB_Descriptor_Device;
+
+typedef struct {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 wTotalLength;
+ uint8 bNumInterfaces;
+ uint8 bConfigurationValue;
+ uint8 iConfiguration;
+ uint8 bmAttributes;
+ uint8 bMaxPower;
+} __packed USB_Descriptor_Config_Header;
+
+typedef struct {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bInterfaceNumber;
+ uint8 bAlternateSetting;
+ uint8 bNumEndpoints;
+ uint8 bInterfaceClass;
+ uint8 bInterfaceSubClass;
+ uint8 bInterfaceProtocol;
+ uint8 iInterface;
+} __packed USB_Descriptor_Interface;
+
+typedef struct {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint8 bEndpointAddress;
+ uint8 bmAttributes;
+ uint16 wMaxPacketSize;
+ uint8 bInterval;
+} __packed USB_Descriptor_Endpoint;
+
+typedef struct {
+ USB_Descriptor_Config_Header Config_Header;
+ USB_Descriptor_Interface CCI_Interface;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_IntHeader;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_CallManagement;
+ CDC_FUNCTIONAL_DESCRIPTOR(1) CDC_Functional_ACM;
+ CDC_FUNCTIONAL_DESCRIPTOR(2) CDC_Functional_Union;
+ USB_Descriptor_Endpoint ManagementEndpoint;
+ USB_Descriptor_Interface DCI_Interface;
+ USB_Descriptor_Endpoint DataOutEndpoint;
+ USB_Descriptor_Endpoint DataInEndpoint;
+} __packed USB_Descriptor_Config;
+
+typedef struct {
+ uint8 bLength;
+ uint8 bDescriptorType;
+ uint16 bString[];
+} USB_Descriptor_String;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/libmaple/usb/stm32f1/usb_lib_globals.h b/libmaple/usb/stm32f1/usb_lib_globals.h
new file mode 100644
index 0000000..1cd2754
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_lib_globals.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#ifndef _USB_LIB_GLOBALS_H_
+#define _USB_LIB_GLOBALS_H_
+
+/* usb_lib headers */
+#include "usb_type.h"
+#include "usb_core.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern USER_STANDARD_REQUESTS User_Standard_Requests;
+extern USER_STANDARD_REQUESTS *pUser_Standard_Requests;
+
+extern DEVICE_PROP Device_Property;
+extern DEVICE_PROP *pProperty;
+
+extern DEVICE_INFO Device_Info;
+extern DEVICE_INFO *pInformation;
+
+extern DEVICE Device_Table;
+extern u16 SaveRState;
+extern u16 SaveTState;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libmaple/usb/stm32f1/usb_reg_map.c b/libmaple/usb/stm32f1/usb_reg_map.c
new file mode 100644
index 0000000..75562e1
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_reg_map.c
@@ -0,0 +1,79 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#include "usb_reg_map.h"
+
+/* TODO these could use some improvement; they're fairly
+ * straightforward ports of the analogous ST code. The PMA blit
+ * routines in particular are obvious targets for performance
+ * measurement and tuning. */
+
+void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset) {
+ uint16 *dst = (uint16*)usb_pma_ptr(pma_offset);
+ uint16 n = len >> 1;
+ uint16 i;
+ for (i = 0; i < n; i++) {
+ *dst = (uint16)(*buf) | *(buf + 1) << 8;
+ buf += 2;
+ dst += 2;
+ }
+ if (len & 1) {
+ *dst = *buf;
+ }
+}
+
+void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset) {
+ uint32 *src = (uint32*)usb_pma_ptr(pma_offset);
+ uint16 *dst = (uint16*)buf;
+ uint16 n = len >> 1;
+ uint16 i;
+ for (i = 0; i < n; i++) {
+ *dst++ = *src++;
+ }
+ if (len & 1) {
+ *dst = *src & 0xFF;
+ }
+}
+
+void usb_set_ep_rx_count(uint8 ep, uint16 count) {
+ uint32 *rxc = usb_ep_rx_count_ptr(ep);
+ uint16 nblocks;
+ if (count > 62) {
+ /* use 32-byte memory block size */
+ nblocks = count >> 5;
+ if ((count & 0x1F) == 0) {
+ nblocks--;
+ }
+ *rxc = (nblocks << 10) | 0x8000;
+ } else {
+ /* use 2-byte memory block size */
+ nblocks = count >> 1;
+ if ((count & 0x1) != 0) {
+ nblocks++;
+ }
+ *rxc = nblocks << 10;
+ }
+}
diff --git a/libmaple/usb/stm32f1/usb_reg_map.h b/libmaple/usb/stm32f1/usb_reg_map.h
new file mode 100644
index 0000000..ce80842
--- /dev/null
+++ b/libmaple/usb/stm32f1/usb_reg_map.h
@@ -0,0 +1,433 @@
+/******************************************************************************
+ * The MIT License
+ *
+ * Copyright (c) 2011 LeafLabs, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *****************************************************************************/
+
+#include <libmaple/libmaple_types.h>
+#include <libmaple/util.h>
+
+#ifndef _USB_REG_MAP_H_
+#define _USB_REG_MAP_H_
+
+/* TODO:
+ * - Pick one of "endp", "ep" "endpt"
+ */
+
+/*
+ * Register map and base pointer
+ */
+
+#define USB_NR_EP_REGS 8
+
+/** USB register map type */
+typedef struct usb_reg_map {
+ __io uint32 EP[USB_NR_EP_REGS]; /**< Endpoint registers */
+ const uint32 RESERVED[8]; /**< Reserved */
+ __io uint32 CNTR; /**< Control register */
+ __io uint32 ISTR; /**< Interrupt status register */
+ __io uint32 FNR; /**< Frame number register */
+ __io uint32 DADDR; /**< Device address */
+ __io uint32 BTABLE; /**< @brief Buffer table address
+ *
+ * Address offset within the USB
+ * packet memory area which points
+ * to the base of the buffer
+ * descriptor table. Must be
+ * aligned to an 8 byte boundary.
+ */
+} usb_reg_map;
+
+/** USB register map base pointer */
+#define USB_BASE ((struct usb_reg_map*)0x40005C00)
+
+/*
+ * Register bit definitions
+ */
+
+/* Endpoint registers (USB_EPnR) */
+
+#define USB_EP_CTR_RX_BIT 15
+#define USB_EP_DTOG_RX_BIT 14
+#define USB_EP_SETUP_BIT 11
+#define USB_EP_EP_KIND_BIT 8
+#define USB_EP_CTR_TX_BIT 7
+#define USB_EP_DTOG_TX_BIT 6
+
+#define USB_EP_CTR_RX BIT(USB_EP_CTR_RX_BIT)
+#define USB_EP_DTOG_RX BIT(USB_EP_DTOG_RX_BIT)
+#define USB_EP_STAT_RX (0x3 << 12)
+#define USB_EP_STAT_RX_DISABLED (0x0 << 12)
+#define USB_EP_STAT_RX_STALL (0x1 << 12)
+#define USB_EP_STAT_RX_NAK (0x2 << 12)
+#define USB_EP_STAT_RX_VALID (0x3 << 12)
+#define USB_EP_SETUP BIT(USB_EP_SETUP_BIT)
+#define USB_EP_EP_TYPE (0x3 << 9)
+#define USB_EP_EP_TYPE_BULK (0x0 << 9)
+#define USB_EP_EP_TYPE_CONTROL (0x1 << 9)
+#define USB_EP_EP_TYPE_ISO (0x2 << 9)
+#define USB_EP_EP_TYPE_INTERRUPT (0x3 << 9)
+#define USB_EP_EP_KIND BIT(USB_EP_EP_KIND_BIT)
+#define USB_EP_CTR_TX BIT(USB_EP_CTR_TX_BIT)
+#define USB_EP_DTOG_TX BIT(USB_EP_DTOG_TX_BIT)
+#define USB_EP_STAT_TX (0x3 << 4)
+#define USB_EP_STAT_TX_DISABLED (0x0 << 4)
+#define USB_EP_STAT_TX_STALL (0x1 << 4)
+#define USB_EP_STAT_TX_NAK (0x2 << 4)
+#define USB_EP_STAT_TX_VALID (0x3 << 4)
+#define USB_EP_EA 0xF
+
+/* Control register (USB_CNTR) */
+
+#define USB_CNTR_CTRM_BIT 15
+#define USB_CNTR_PMAOVERM_BIT 14
+#define USB_CNTR_ERRM_BIT 13
+#define USB_CNTR_WKUPM_BIT 12
+#define USB_CNTR_SUSPM_BIT 11
+#define USB_CNTR_RESETM_BIT 10
+#define USB_CNTR_SOFM_BIT 9
+#define USB_CNTR_ESOFM_BIT 8
+#define USB_CNTR_RESUME_BIT 4
+#define USB_CNTR_FSUSP_BIT 3
+#define USB_CNTR_LP_MODE_BIT 2
+#define USB_CNTR_PDWN_BIT 1
+#define USB_CNTR_FRES_BIT 0
+
+#define USB_CNTR_CTRM BIT(USB_CNTR_CTRM_BIT)
+#define USB_CNTR_PMAOVERM BIT(USB_CNTR_PMAOVERM_BIT)
+#define USB_CNTR_ERRM BIT(USB_CNTR_ERRM_BIT)
+#define USB_CNTR_WKUPM BIT(USB_CNTR_WKUPM_BIT)
+#define USB_CNTR_SUSPM BIT(USB_CNTR_SUSPM_BIT)
+#define USB_CNTR_RESETM BIT(USB_CNTR_RESETM_BIT)
+#define USB_CNTR_SOFM BIT(USB_CNTR_SOFM_BIT)
+#define USB_CNTR_ESOFM BIT(USB_CNTR_ESOFM_BIT)
+#define USB_CNTR_RESUME BIT(USB_CNTR_RESUME_BIT)
+#define USB_CNTR_FSUSP BIT(USB_CNTR_FSUSP_BIT)
+#define USB_CNTR_LP_MODE BIT(USB_CNTR_LP_MODE_BIT)
+#define USB_CNTR_PDWN BIT(USB_CNTR_PDWN_BIT)
+#define USB_CNTR_FRES BIT(USB_CNTR_FRES_BIT)
+
+/* Interrupt status register (USB_ISTR) */
+
+#define USB_ISTR_CTR_BIT 15
+#define USB_ISTR_PMAOVR_BIT 14
+#define USB_ISTR_ERR_BIT 13
+#define USB_ISTR_WKUP_BIT 12
+#define USB_ISTR_SUSP_BIT 11
+#define USB_ISTR_RESET_BIT 10
+#define USB_ISTR_SOF_BIT 9
+#define USB_ISTR_ESOF_BIT 8
+#define USB_ISTR_DIR_BIT 4
+
+#define USB_ISTR_CTR BIT(USB_ISTR_CTR_BIT)
+#define USB_ISTR_PMAOVR BIT(USB_ISTR_PMAOVR_BIT)
+#define USB_ISTR_ERR BIT(USB_ISTR_ERR_BIT)
+#define USB_ISTR_WKUP BIT(USB_ISTR_WKUP_BIT)
+#define USB_ISTR_SUSP BIT(USB_ISTR_SUSP_BIT)
+#define USB_ISTR_RESET BIT(USB_ISTR_RESET_BIT)
+#define USB_ISTR_SOF BIT(USB_ISTR_SOF_BIT)
+#define USB_ISTR_ESOF BIT(USB_ISTR_ESOF_BIT)
+#define USB_ISTR_DIR BIT(USB_ISTR_DIR_BIT)
+#define USB_ISTR_EP_ID 0xF
+
+/* Frame number register (USB_FNR) */
+
+#define USB_FNR_RXDP_BIT 15
+#define USB_FNR_RXDM_BIT 14
+#define USB_FNR_LCK_BIT 13
+
+#define USB_FNR_RXDP BIT(USB_FNR_RXDP_BIT)
+#define USB_FNR_RXDM BIT(USB_FNR_RXDM_BIT)
+#define USB_FNR_LCK BIT(USB_FNR_LCK_BIT)
+#define USB_FNR_LSOF (0x3 << 11)
+#define USB_FNR_FN 0x7FF
+
+/* Device address (USB_DADDR) */
+
+#define USB_DADDR_EF_BIT 7
+#define USB_DADDR_ADD6_BIT 6
+#define USB_DADDR_ADD5_BIT 5
+#define USB_DADDR_ADD4_BIT 4
+#define USB_DADDR_ADD3_BIT 3
+#define USB_DADDR_ADD2_BIT 2
+#define USB_DADDR_ADD1_BIT 1
+#define USB_DADDR_ADD0_BIT 0
+
+#define USB_DADDR_EF BIT(USB_DADDR_EF_BIT)
+#define USB_DADDR_ADD6 BIT(USB_DADDR_ADD6_BIT)
+#define USB_DADDR_ADD5 BIT(USB_DADDR_ADD5_BIT)
+#define USB_DADDR_ADD4 BIT(USB_DADDR_ADD4_BIT)
+#define USB_DADDR_ADD3 BIT(USB_DADDR_ADD3_BIT)
+#define USB_DADDR_ADD2 BIT(USB_DADDR_ADD2_BIT)
+#define USB_DADDR_ADD1 BIT(USB_DADDR_ADD1_BIT)
+#define USB_DADDR_ADD0 BIT(USB_DADDR_ADD0_BIT)
+
+/* Buffer table address (USB_BTABLE) */
+
+#define USB_BTABLE_BTABLE (0x1FFF << 3)
+
+/*
+ * Register convenience routines
+ */
+
+#define __EP_CTR_NOP (USB_EP_CTR_RX | USB_EP_CTR_TX)
+#define __EP_NONTOGGLE (USB_EP_CTR_RX | USB_EP_SETUP | \
+ USB_EP_EP_TYPE | USB_EP_EP_KIND | \
+ USB_EP_CTR_TX | USB_EP_EA)
+
+static inline void usb_clear_ctr_rx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ USB_BASE->EP[ep] = epr & ~USB_EP_CTR_RX & __EP_NONTOGGLE;
+}
+
+static inline void usb_clear_ctr_tx(uint8 ep) {
+ uint32 epr = USB_BASE->EP[ep];
+ USB_BASE->EP[ep] = epr & ~USB_EP_CTR_TX & __EP_NONTOGGLE;
+}
+
+static inline void usb_set_ep_rx_stat(uint8 ep, uint32 status) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~(USB_EP_STAT_TX | USB_EP_DTOG_RX | USB_EP_DTOG_TX);
+ epr |= __EP_CTR_NOP;
+ epr ^= status;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_tx_stat(uint8 ep, uint32 status) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~(USB_EP_STAT_RX | USB_EP_DTOG_RX | USB_EP_DTOG_TX);
+ epr |= __EP_CTR_NOP;
+ epr ^= status;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_type(uint8 ep, uint32 type) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~USB_EP_EP_TYPE & __EP_NONTOGGLE;
+ epr |= type;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_set_ep_kind(uint8 ep, uint32 kind) {
+ uint32 epr = USB_BASE->EP[ep];
+ epr &= ~USB_EP_EP_KIND & __EP_NONTOGGLE;
+ epr |= kind;
+ USB_BASE->EP[ep] = epr;
+}
+
+static inline void usb_clear_status_out(uint8 ep) {
+ usb_set_ep_kind(ep, 0);
+}
+
+/*
+ * Packet memory area (PMA) base pointer
+ */
+
+/**
+ * @brief USB packet memory area (PMA) base pointer.
+ *
+ * The USB PMA is SRAM shared between USB and CAN. The USB peripheral
+ * accesses this memory directly via the packet buffer interface. */
+#define USB_PMA_BASE ((__io void*)0x40006000)
+
+/*
+ * PMA conveniences
+ */
+
+void usb_copy_to_pma(const uint8 *buf, uint16 len, uint16 pma_offset);
+void usb_copy_from_pma(uint8 *buf, uint16 len, uint16 pma_offset);
+
+static inline void* usb_pma_ptr(uint32 offset) {
+ return (void*)(USB_PMA_BASE + 2 * offset);
+}
+
+/*
+ * BTABLE
+ */
+
+/* (Forward-declared) BTABLE entry.
+ *
+ * The BTABLE can be viewed as an array of usb_btable_ent values;
+ * these vary in structure according to the configuration of the
+ * endpoint.
+ */
+union usb_btable_ent;
+
+/* Bidirectional endpoint BTABLE entry */
+typedef struct usb_btable_bidi {
+ __io uint16 addr_tx; const uint16 PAD1;
+ __io uint16 count_tx; const uint16 PAD2;
+ __io uint16 addr_rx; const uint16 PAD3;
+ __io uint16 count_rx; const uint16 PAD4;
+} usb_btable_bidi;
+
+/* Unidirectional receive-only endpoint BTABLE entry */
+typedef struct usb_btable_uni_rx {
+ __io uint16 empty1; const uint16 PAD1;
+ __io uint16 empty2; const uint16 PAD2;
+ __io uint16 addr_rx; const uint16 PAD3;
+ __io uint16 count_rx; const uint16 PAD4;
+} usb_btable_uni_rx;
+
+/* Unidirectional transmit-only endpoint BTABLE entry */
+typedef struct usb_btable_uni_tx {
+ __io uint16 addr_tx; const uint16 PAD1;
+ __io uint16 count_tx; const uint16 PAD2;
+ __io uint16 empty1; const uint16 PAD3;
+ __io uint16 empty2; const uint16 PAD4;
+} usb_btable_uni_tx;
+
+/* Double-buffered transmission endpoint BTABLE entry */
+typedef struct usb_btable_dbl_tx {
+ __io uint16 addr_tx0; const uint16 PAD1;
+ __io uint16 count_tx0; const uint16 PAD2;
+ __io uint16 addr_tx1; const uint16 PAD3;
+ __io uint16 count_tx1; const uint16 PAD4;
+} usb_btable_dbl_tx;
+
+/* Double-buffered reception endpoint BTABLE entry */
+typedef struct usb_btable_dbl_rx {
+ __io uint16 addr_rx0; const uint16 PAD1;
+ __io uint16 count_rx0; const uint16 PAD2;
+ __io uint16 addr_rx1; const uint16 PAD3;
+ __io uint16 count_rx1; const uint16 PAD4;
+} usb_btable_dbl_rx;
+
+/* TODO isochronous endpoint entries */
+
+/* Definition for above forward-declared BTABLE entry. */
+typedef union usb_btable_ent {
+ usb_btable_bidi bidi;
+ usb_btable_uni_rx u_rx;
+ usb_btable_uni_tx u_tx;
+ usb_btable_dbl_tx d_tx;
+ usb_btable_dbl_rx d_rx;
+} usb_btable_ent;
+
+/*
+ * BTABLE conveniences
+ */
+
+/* TODO (?) Convert usages of the many (and lengthily-named)
+ * accessors/mutators below to just manipulating usb_btable_entry
+ * values. */
+
+static inline uint32* usb_btable_ptr(uint32 offset) {
+ return (uint32*)usb_pma_ptr(USB_BASE->BTABLE + offset);
+}
+
+static inline usb_btable_ent *usb_btable(void) {
+ return (usb_btable_ent*)usb_btable_ptr(0);
+}
+
+/* TX address */
+
+static inline uint32* usb_ep_tx_addr_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8);
+}
+
+static inline uint16 usb_get_ep_tx_addr(uint8 ep) {
+ return (uint16)*usb_ep_tx_addr_ptr(ep);
+}
+
+static inline void usb_set_ep_tx_addr(uint8 ep, uint16 addr) {
+ uint32 *tx_addr = usb_ep_tx_addr_ptr(ep);
+ *tx_addr = addr & ~0x1;
+}
+
+/* RX address */
+
+static inline uint32* usb_ep_rx_addr_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 4);
+}
+
+static inline uint16 usb_get_ep_rx_addr(uint8 ep) {
+ return (uint16)*usb_ep_rx_addr_ptr(ep);
+}
+
+static inline void usb_set_ep_rx_addr(uint8 ep, uint16 addr) {
+ uint32 *rx_addr = usb_ep_rx_addr_ptr(ep);
+ *rx_addr = addr & ~0x1;
+}
+
+/* TX count (doesn't cover double-buffered and isochronous in) */
+
+static inline uint32* usb_ep_tx_count_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 2);
+}
+
+static inline uint16 usb_get_ep_tx_count(uint8 ep) {
+ return (uint16)*usb_ep_tx_count_ptr(ep);
+}
+
+static inline void usb_set_ep_tx_count(uint8 ep, uint16 count) {
+ uint32 *txc = usb_ep_tx_count_ptr(ep);
+ *txc = count;
+}
+
+/* RX count */
+
+static inline uint32* usb_ep_rx_count_ptr(uint8 ep) {
+ return usb_btable_ptr(ep * 8 + 6);
+}
+
+static inline uint16 usb_get_ep_rx_count(uint8 ep) {
+ return (uint16)*usb_ep_rx_count_ptr(ep) & 0x3FF;
+}
+
+void usb_set_ep_rx_count(uint8 ep, uint16 count);
+
+/*
+ * Misc. types
+ */
+
+typedef enum usb_ep {
+ USB_EP0,
+ USB_EP1,
+ USB_EP2,
+ USB_EP3,
+ USB_EP4,
+ USB_EP5,
+ USB_EP6,
+ USB_EP7,
+} usb_ep;
+
+typedef enum usb_ep_type {
+ USB_EP_T_CTL = USB_EP_EP_TYPE_CONTROL,
+ USB_EP_T_BULK = USB_EP_EP_TYPE_BULK,
+ USB_EP_T_INT = USB_EP_EP_TYPE_INTERRUPT,
+ USB_EP_T_ISO = USB_EP_EP_TYPE_ISO
+} usb_ep_type;
+
+typedef enum usb_ep_stat {
+ USB_EP_ST_RX_DIS = USB_EP_STAT_RX_DISABLED,
+ USB_EP_ST_RX_STL = USB_EP_STAT_RX_STALL,
+ USB_EP_ST_RX_NAK = USB_EP_STAT_RX_NAK,
+ USB_EP_ST_RX_VAL = USB_EP_STAT_RX_VALID,
+ USB_EP_ST_TX_DIS = USB_EP_STAT_TX_DISABLED,
+ USB_EP_ST_TX_STL = USB_EP_STAT_TX_STALL,
+ USB_EP_ST_TX_NAK = USB_EP_STAT_TX_NAK,
+ USB_EP_ST_TX_VAL = USB_EP_STAT_TX_VALID
+} usb_ep_stat;
+
+#endif