aboutsummaryrefslogtreecommitdiff
path: root/lib/usb
diff options
context:
space:
mode:
authorJeff Ciesielski2012-11-13 11:06:21 -0800
committerJeff Ciesielski2012-11-13 13:13:40 -0800
commitdb35fbb7ba97a8a6d7481edf07cb82cae06aa834 (patch)
treec213211778736d5ce2f06b4cf186a6900f522b20 /lib/usb
parent1768df7edae1cd430183c03f3d0ad7f7b4d13c90 (diff)
parent4691568ca476177dc338e8c62872ceca6b4b4999 (diff)
Merge branch 'master' of git://github.com/libopencm3/libopencm3 into upstream-merge
Diffstat (limited to 'lib/usb')
-rw-r--r--lib/usb/usb.c108
-rw-r--r--lib/usb/usb_control.c196
-rw-r--r--lib/usb/usb_f103.c99
-rw-r--r--lib/usb/usb_f107.c338
-rw-r--r--lib/usb/usb_f207.c91
-rw-r--r--lib/usb/usb_fx07_common.c318
-rw-r--r--lib/usb/usb_fx07_common.h38
-rw-r--r--lib/usb/usb_private.h81
-rw-r--r--lib/usb/usb_standard.c128
9 files changed, 813 insertions, 584 deletions
diff --git a/lib/usb/usb.c b/lib/usb/usb.c
index d5ec980..0799202 100644
--- a/lib/usb/usb.c
+++ b/lib/usb/usb.c
@@ -21,8 +21,6 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
-struct _usbd_device _usbd_device;
-
u8 usbd_control_buffer[128] __attribute__((weak));
/**
@@ -43,106 +41,112 @@ u8 usbd_control_buffer[128] __attribute__((weak));
* @param strings TODO
* @return Zero on success (currently cannot fail).
*/
-int usbd_init(const usbd_driver *driver,
- const struct usb_device_descriptor *dev,
- const struct usb_config_descriptor *conf,
- const char **strings, int num_strings)
+usbd_device *usbd_init(const usbd_driver *driver,
+ const struct usb_device_descriptor *dev,
+ const struct usb_config_descriptor *conf,
+ const char **strings, int num_strings)
{
- _usbd_device.driver = driver;
- _usbd_device.desc = dev;
- _usbd_device.config = conf;
- _usbd_device.strings = strings;
- _usbd_device.num_strings = num_strings;
- _usbd_device.ctrl_buf = usbd_control_buffer;
- _usbd_device.ctrl_buf_len = sizeof(usbd_control_buffer);
+ usbd_device *usbd_dev;
+
+ usbd_dev = driver->init();
- _usbd_hw_init();
+ usbd_dev->driver = driver;
+ usbd_dev->desc = dev;
+ usbd_dev->config = conf;
+ usbd_dev->strings = strings;
+ usbd_dev->num_strings = num_strings;
+ usbd_dev->ctrl_buf = usbd_control_buffer;
+ usbd_dev->ctrl_buf_len = sizeof(usbd_control_buffer);
- _usbd_device.user_callback_ctr[0][USB_TRANSACTION_SETUP] =
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_SETUP] =
_usbd_control_setup;
- _usbd_device.user_callback_ctr[0][USB_TRANSACTION_OUT] =
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_OUT] =
_usbd_control_out;
- _usbd_device.user_callback_ctr[0][USB_TRANSACTION_IN] =
+ usbd_dev->user_callback_ctr[0][USB_TRANSACTION_IN] =
_usbd_control_in;
- return 0;
+ return usbd_dev;
}
-void usbd_register_reset_callback(void (*callback)(void))
+void usbd_register_reset_callback(usbd_device *usbd_dev, void (*callback)(void))
{
- _usbd_device.user_callback_reset = callback;
+ usbd_dev->user_callback_reset = callback;
}
-void usbd_register_suspend_callback(void (*callback)(void))
+void usbd_register_suspend_callback(usbd_device *usbd_dev,
+ void (*callback)(void))
{
- _usbd_device.user_callback_suspend = callback;
+ usbd_dev->user_callback_suspend = callback;
}
-void usbd_register_resume_callback(void (*callback)(void))
+void usbd_register_resume_callback(usbd_device *usbd_dev,
+ void (*callback)(void))
{
- _usbd_device.user_callback_resume = callback;
+ usbd_dev->user_callback_resume = callback;
}
-void usbd_register_sof_callback(void (*callback)(void))
+void usbd_register_sof_callback(usbd_device *usbd_dev, void (*callback)(void))
{
- _usbd_device.user_callback_sof = callback;
+ usbd_dev->user_callback_sof = callback;
}
-void usbd_set_control_buffer_size(u16 size)
+void usbd_set_control_buffer_size(usbd_device *usbd_dev, u16 size)
{
- _usbd_device.ctrl_buf_len = size;
+ usbd_dev->ctrl_buf_len = size;
}
-void _usbd_reset(void)
+void _usbd_reset(usbd_device *usbd_dev)
{
- _usbd_device.current_address = 0;
- _usbd_device.current_config = 0;
- usbd_ep_setup(0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL);
- _usbd_hw_set_address(0);
+ usbd_dev->current_address = 0;
+ usbd_dev->current_config = 0;
+ usbd_ep_setup(usbd_dev, 0, USB_ENDPOINT_ATTR_CONTROL, 64, NULL);
+ usbd_dev->driver->set_address(usbd_dev, 0);
- if (_usbd_device.user_callback_reset)
- _usbd_device.user_callback_reset();
+ if (usbd_dev->user_callback_reset)
+ usbd_dev->user_callback_reset();
}
/* Functions to wrap the low-level driver */
-void usbd_poll(void)
+void usbd_poll(usbd_device *usbd_dev)
{
- _usbd_device.driver->poll();
+ usbd_dev->driver->poll(usbd_dev);
}
-void usbd_disconnect(bool disconnected)
+void usbd_disconnect(usbd_device *usbd_dev, bool disconnected)
{
/* not all drivers support disconnection */
- if (_usbd_device.driver->disconnect)
- _usbd_device.driver->disconnect(disconnected);
+ if (usbd_dev->driver->disconnect)
+ usbd_dev->driver->disconnect(usbd_dev, disconnected);
}
-void usbd_ep_setup(u8 addr, u8 type, u16 max_size, void (*callback)(u8 ep))
+void usbd_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
+ void (*callback)(usbd_device *usbd_dev, u8 ep))
{
- _usbd_device.driver->ep_setup(addr, type, max_size, callback);
+ usbd_dev->driver->ep_setup(usbd_dev, addr, type, max_size, callback);
}
-u16 usbd_ep_write_packet(u8 addr, const void *buf, u16 len)
+u16 usbd_ep_write_packet(usbd_device *usbd_dev, u8 addr,
+ const void *buf, u16 len)
{
- return _usbd_device.driver->ep_write_packet(addr, buf, len);
+ return usbd_dev->driver->ep_write_packet(usbd_dev, addr, buf, len);
}
-u16 usbd_ep_read_packet(u8 addr, void *buf, u16 len)
+u16 usbd_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf, u16 len)
{
- return _usbd_device.driver->ep_read_packet(addr, buf, len);
+ return usbd_dev->driver->ep_read_packet(usbd_dev, addr, buf, len);
}
-void usbd_ep_stall_set(u8 addr, u8 stall)
+void usbd_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
{
- _usbd_device.driver->ep_stall_set(addr, stall);
+ usbd_dev->driver->ep_stall_set(usbd_dev, addr, stall);
}
-u8 usbd_ep_stall_get(u8 addr)
+u8 usbd_ep_stall_get(usbd_device *usbd_dev, u8 addr)
{
- return _usbd_device.driver->ep_stall_get(addr);
+ return usbd_dev->driver->ep_stall_get(usbd_dev, addr);
}
-void usbd_ep_nak_set(u8 addr, u8 nak)
+void usbd_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
{
- _usbd_device.driver->ep_nak_set(addr, nak);
+ usbd_dev->driver->ep_nak_set(usbd_dev, addr, nak);
}
diff --git a/lib/usb/usb_control.c b/lib/usb/usb_control.c
index b4ac57e..82843df 100644
--- a/lib/usb/usb_control.c
+++ b/lib/usb/usb_control.c
@@ -21,77 +21,73 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
-static struct usb_control_state {
- enum {
- IDLE, STALLED,
- DATA_IN, LAST_DATA_IN, STATUS_IN,
- DATA_OUT, LAST_DATA_OUT, STATUS_OUT,
- } state;
- struct usb_setup_data req;
- u8 *ctrl_buf;
- u16 ctrl_len;
- void (*complete)(struct usb_setup_data *req);
-} control_state;
-
/* Register application callback function for handling USB control requests. */
-int usbd_register_control_callback(u8 type, u8 type_mask,
+int usbd_register_control_callback(usbd_device *usbd_dev, u8 type, u8 type_mask,
usbd_control_callback callback)
{
int i;
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
- if (_usbd_device.user_control_callback[i].cb)
+ if (usbd_dev->user_control_callback[i].cb)
continue;
- _usbd_device.user_control_callback[i].type = type;
- _usbd_device.user_control_callback[i].type_mask = type_mask;
- _usbd_device.user_control_callback[i].cb = callback;
+ usbd_dev->user_control_callback[i].type = type;
+ usbd_dev->user_control_callback[i].type_mask = type_mask;
+ usbd_dev->user_control_callback[i].cb = callback;
return 0;
}
return -1;
}
-static void usb_control_send_chunk(void)
+static void usb_control_send_chunk(usbd_device *usbd_dev)
{
- if (_usbd_device.desc->bMaxPacketSize0 < control_state.ctrl_len) {
+ if (usbd_dev->desc->bMaxPacketSize0 < usbd_dev->control_state.ctrl_len) {
/* Data stage, normal transmission */
- usbd_ep_write_packet(0, control_state.ctrl_buf,
- _usbd_device.desc->bMaxPacketSize0);
- control_state.state = DATA_IN;
- control_state.ctrl_buf += _usbd_device.desc->bMaxPacketSize0;
- control_state.ctrl_len -= _usbd_device.desc->bMaxPacketSize0;
+ usbd_ep_write_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf,
+ usbd_dev->desc->bMaxPacketSize0);
+ usbd_dev->control_state.state = DATA_IN;
+ usbd_dev->control_state.ctrl_buf +=
+ usbd_dev->desc->bMaxPacketSize0;
+ usbd_dev->control_state.ctrl_len -=
+ usbd_dev->desc->bMaxPacketSize0;
} else {
/* Data stage, end of transmission */
- usbd_ep_write_packet(0, control_state.ctrl_buf,
- control_state.ctrl_len);
- control_state.state = LAST_DATA_IN;
- control_state.ctrl_len = 0;
- control_state.ctrl_buf = NULL;
+ usbd_ep_write_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf,
+ usbd_dev->control_state.ctrl_len);
+ usbd_dev->control_state.state = LAST_DATA_IN;
+ usbd_dev->control_state.ctrl_len = 0;
+ usbd_dev->control_state.ctrl_buf = NULL;
}
}
-static int usb_control_recv_chunk(void)
+static int usb_control_recv_chunk(usbd_device *usbd_dev)
{
- u16 packetsize = MIN(_usbd_device.desc->bMaxPacketSize0,
- control_state.req.wLength - control_state.ctrl_len);
- u16 size = usbd_ep_read_packet(0, control_state.ctrl_buf +
- control_state.ctrl_len, packetsize);
+ u16 packetsize = MIN(usbd_dev->desc->bMaxPacketSize0,
+ usbd_dev->control_state.req.wLength -
+ usbd_dev->control_state.ctrl_len);
+ u16 size = usbd_ep_read_packet(usbd_dev, 0,
+ usbd_dev->control_state.ctrl_buf +
+ usbd_dev->control_state.ctrl_len,
+ packetsize);
if (size != packetsize) {
- usbd_ep_stall_set(0, 1);
+ usbd_ep_stall_set(usbd_dev, 0, 1);
return -1;
}
- control_state.ctrl_len += size;
+ usbd_dev->control_state.ctrl_len += size;
return packetsize;
}
-static int usb_control_request_dispatch(struct usb_setup_data *req)
+static int usb_control_request_dispatch(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
{
int i, result = 0;
- struct user_control_callback *cb = _usbd_device.user_control_callback;
+ struct user_control_callback *cb = usbd_dev->user_control_callback;
/* Call user command hook function. */
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++) {
@@ -99,141 +95,149 @@ static int usb_control_request_dispatch(struct usb_setup_data *req)
break;
if ((req->bmRequestType & cb[i].type_mask) == cb[i].type) {
- result = cb[i].cb(req, &control_state.ctrl_buf,
- &control_state.ctrl_len,
- &control_state.complete);
+ result = cb[i].cb(usbd_dev, req,
+ &(usbd_dev->control_state.ctrl_buf),
+ &(usbd_dev->control_state.ctrl_len),
+ &(usbd_dev->control_state.complete));
if (result == USBD_REQ_HANDLED ||
result == USBD_REQ_NOTSUPP)
return result;
}
}
-
+
/* Try standard request if not already handled. */
- return _usbd_standard_request(req, &control_state.ctrl_buf,
- &control_state.ctrl_len);
+ return _usbd_standard_request(usbd_dev, req,
+ &(usbd_dev->control_state.ctrl_buf),
+ &(usbd_dev->control_state.ctrl_len));
}
/* Handle commands and read requests. */
-static void usb_control_setup_read(struct usb_setup_data *req)
+static void usb_control_setup_read(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
{
- control_state.ctrl_buf = _usbd_device.ctrl_buf;
- control_state.ctrl_len = req->wLength;
+ usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
+ usbd_dev->control_state.ctrl_len = req->wLength;
- if (usb_control_request_dispatch(req)) {
- if (control_state.ctrl_len) {
+ if (usb_control_request_dispatch(usbd_dev, req)) {
+ if (usbd_dev->control_state.ctrl_len) {
/* Go to data out stage if handled. */
- usb_control_send_chunk();
+ usb_control_send_chunk(usbd_dev);
} else {
/* Go to status stage if handled. */
- usbd_ep_write_packet(0, NULL, 0);
- control_state.state = STATUS_IN;
+ usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = STATUS_IN;
}
} else {
/* Stall endpoint on failure. */
- usbd_ep_stall_set(0, 1);
+ usbd_ep_stall_set(usbd_dev, 0, 1);
}
}
-static void usb_control_setup_write(struct usb_setup_data *req)
+static void usb_control_setup_write(usbd_device *usbd_dev,
+ struct usb_setup_data *req)
{
- if (req->wLength > _usbd_device.ctrl_buf_len) {
- usbd_ep_stall_set(0, 1);
+ if (req->wLength > usbd_dev->ctrl_buf_len) {
+ usbd_ep_stall_set(usbd_dev, 0, 1);
return;
}
/* Buffer into which to write received data. */
- control_state.ctrl_buf = _usbd_device.ctrl_buf;
- control_state.ctrl_len = 0;
+ usbd_dev->control_state.ctrl_buf = usbd_dev->ctrl_buf;
+ usbd_dev->control_state.ctrl_len = 0;
/* Wait for DATA OUT stage. */
- if (req->wLength > _usbd_device.desc->bMaxPacketSize0)
- control_state.state = DATA_OUT;
+ if (req->wLength > usbd_dev->desc->bMaxPacketSize0)
+ usbd_dev->control_state.state = DATA_OUT;
else
- control_state.state = LAST_DATA_OUT;
+ usbd_dev->control_state.state = LAST_DATA_OUT;
}
-void _usbd_control_setup(u8 ea)
+void _usbd_control_setup(usbd_device *usbd_dev, u8 ea)
{
- struct usb_setup_data *req = &control_state.req;
+ struct usb_setup_data *req = &usbd_dev->control_state.req;
(void)ea;
- control_state.complete = NULL;
+ usbd_dev->control_state.complete = NULL;
- if (usbd_ep_read_packet(0, req, 8) != 8) {
- usbd_ep_stall_set(0, 1);
+ if (usbd_ep_read_packet(usbd_dev, 0, req, 8) != 8) {
+ usbd_ep_stall_set(usbd_dev, 0, 1);
return;
}
if (req->wLength == 0) {
- usb_control_setup_read(req);
+ usb_control_setup_read(usbd_dev, req);
} else if (req->bmRequestType & 0x80) {
- usb_control_setup_read(req);
+ usb_control_setup_read(usbd_dev, req);
} else {
- usb_control_setup_write(req);
+ usb_control_setup_write(usbd_dev, req);
}
}
-void _usbd_control_out(u8 ea)
+void _usbd_control_out(usbd_device *usbd_dev, u8 ea)
{
(void)ea;
- switch (control_state.state) {
+ switch (usbd_dev->control_state.state) {
case DATA_OUT:
- if (usb_control_recv_chunk() < 0)
+ if (usb_control_recv_chunk(usbd_dev) < 0)
break;
- if ((control_state.req.wLength - control_state.ctrl_len) <=
- _usbd_device.desc->bMaxPacketSize0)
- control_state.state = LAST_DATA_OUT;
+ if ((usbd_dev->control_state.req.wLength -
+ usbd_dev->control_state.ctrl_len) <=
+ usbd_dev->desc->bMaxPacketSize0)
+ usbd_dev->control_state.state = LAST_DATA_OUT;
break;
case LAST_DATA_OUT:
- if (usb_control_recv_chunk() < 0)
+ if (usb_control_recv_chunk(usbd_dev) < 0)
break;
/*
* We have now received the full data payload.
* Invoke callback to process.
*/
- if (usb_control_request_dispatch(&control_state.req)) {
+ if (usb_control_request_dispatch(usbd_dev,
+ &(usbd_dev->control_state.req))) {
/* Got to status stage on success. */
- usbd_ep_write_packet(0, NULL, 0);
- control_state.state = STATUS_IN;
+ usbd_ep_write_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = STATUS_IN;
} else {
- usbd_ep_stall_set(0, 1);
+ usbd_ep_stall_set(usbd_dev, 0, 1);
}
break;
case STATUS_OUT:
- usbd_ep_read_packet(0, NULL, 0);
- control_state.state = IDLE;
- if (control_state.complete)
- control_state.complete(&control_state.req);
- control_state.complete = NULL;
+ usbd_ep_read_packet(usbd_dev, 0, NULL, 0);
+ usbd_dev->control_state.state = IDLE;
+ if (usbd_dev->control_state.complete)
+ usbd_dev->control_state.complete(usbd_dev,
+ &(usbd_dev->control_state.req));
+ usbd_dev->control_state.complete = NULL;
break;
default:
- usbd_ep_stall_set(0, 1);
+ usbd_ep_stall_set(usbd_dev, 0, 1);
}
}
-void _usbd_control_in(u8 ea)
+void _usbd_control_in(usbd_device *usbd_dev, u8 ea)
{
(void)ea;
- struct usb_setup_data *req = &control_state.req;
+ struct usb_setup_data *req = &(usbd_dev->control_state.req);
- switch (control_state.state) {
+ switch (usbd_dev->control_state.state) {
case DATA_IN:
- usb_control_send_chunk();
+ usb_control_send_chunk(usbd_dev);
break;
case LAST_DATA_IN:
- control_state.state = STATUS_OUT;
+ usbd_dev->control_state.state = STATUS_OUT;
break;
case STATUS_IN:
- if (control_state.complete)
- control_state.complete(&control_state.req);
+ if (usbd_dev->control_state.complete)
+ usbd_dev->control_state.complete(usbd_dev,
+ &(usbd_dev->control_state.req));
/* Exception: Handle SET ADDRESS function here... */
if ((req->bmRequestType == 0) &&
(req->bRequest == USB_REQ_SET_ADDRESS))
- _usbd_hw_set_address(req->wValue);
- control_state.state = IDLE;
+ usbd_dev->driver->set_address(usbd_dev, req->wValue);
+ usbd_dev->control_state.state = IDLE;
break;
default:
- usbd_ep_stall_set(0, 1);
+ usbd_ep_stall_set(usbd_dev, 0, 1);
}
}
diff --git a/lib/usb/usb_f103.c b/lib/usb/usb_f103.c
index 22db8cc..aa323d9 100644
--- a/lib/usb/usb_f103.c
+++ b/lib/usb/usb_f103.c
@@ -24,19 +24,23 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
-static void stm32f103_usbd_init(void);
-static void stm32f103_set_address(u8 addr);
-static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
- void (*callback) (u8 ep));
-static void stm32f103_endpoints_reset(void);
-static void stm32f103_ep_stall_set(u8 addr, u8 stall);
-static u8 stm32f103_ep_stall_get(u8 addr);
-static void stm32f103_ep_nak_set(u8 addr, u8 nak);
-static u16 stm32f103_ep_write_packet(u8 addr, const void *buf, u16 len);
-static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len);
-static void stm32f103_poll(void);
+static usbd_device *stm32f103_usbd_init(void);
+static void stm32f103_set_address(usbd_device *usbd_dev, u8 addr);
+static void stm32f103_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type,
+ u16 max_size,
+ void (*callback) (usbd_device *usbd_dev, u8 ep));
+static void stm32f103_endpoints_reset(usbd_device *usbd_dev);
+static void stm32f103_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall);
+static u8 stm32f103_ep_stall_get(usbd_device *usbd_dev, u8 addr);
+static void stm32f103_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak);
+static u16 stm32f103_ep_write_packet(usbd_device *usbd_dev, u8 addr,
+ const void *buf, u16 len);
+static u16 stm32f103_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
+ u16 len);
+static void stm32f103_poll(usbd_device *usbd_dev);
static u8 force_nak[8];
+static struct _usbd_device usbd_dev;
const struct _usbd_driver stm32f103_usb_driver = {
.init = stm32f103_usbd_init,
@@ -52,7 +56,7 @@ const struct _usbd_driver stm32f103_usb_driver = {
};
/** Initialize the USB device controller hardware of the STM32. */
-static void stm32f103_usbd_init(void)
+static usbd_device *stm32f103_usbd_init(void)
{
rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USBEN);
SET_REG(USB_CNTR_REG, 0);
@@ -62,10 +66,12 @@ static void stm32f103_usbd_init(void)
/* Enable RESET, SUSPEND, RESUME and CTR interrupts. */
SET_REG(USB_CNTR_REG, USB_CNTR_RESETM | USB_CNTR_CTRM |
USB_CNTR_SUSPM | USB_CNTR_WKUPM);
+ return &usbd_dev;
}
-static void stm32f103_set_address(u8 addr)
+static void stm32f103_set_address(usbd_device *usbd_dev, u8 addr)
{
+ (void)usbd_dev;
/* Set device address and enable. */
SET_REG(USB_DADDR_REG, (addr & USB_DADDR_ADDR) | USB_DADDR_ENABLE);
}
@@ -76,8 +82,9 @@ static void stm32f103_set_address(u8 addr)
* @param ep Index of endpoint to configure.
* @param size Size in bytes of the RX buffer.
*/
-static void usb_set_ep_rx_bufsize(u8 ep, u32 size)
+static void usb_set_ep_rx_bufsize(usbd_device *usbd_dev, u8 ep, u32 size)
{
+ (void)usbd_dev;
if (size > 62) {
if (size & 0x1f)
size -= 32;
@@ -89,8 +96,9 @@ static void usb_set_ep_rx_bufsize(u8 ep, u32 size)
}
}
-static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
- void (*callback) (u8 ep))
+static void stm32f103_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type,
+ u16 max_size,
+ void (*callback) (usbd_device *usbd_dev, u8 ep))
{
/* Translate USB standard type codes to STM32. */
const u16 typelookup[] = {
@@ -107,32 +115,30 @@ static void stm32f103_ep_setup(u8 addr, u8 type, u16 max_size,
USB_SET_EP_TYPE(addr, typelookup[type]);
if (dir || (addr == 0)) {
- USB_SET_EP_TX_ADDR(addr, _usbd_device.pm_top);
+ USB_SET_EP_TX_ADDR(addr, usbd_dev->pm_top);
if (callback) {
- _usbd_device.
- user_callback_ctr[addr][USB_TRANSACTION_IN] =
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
(void *)callback;
}
USB_CLR_EP_TX_DTOG(addr);
USB_SET_EP_TX_STAT(addr, USB_EP_TX_STAT_NAK);
- _usbd_device.pm_top += max_size;
+ usbd_dev->pm_top += max_size;
}
if (!dir) {
- USB_SET_EP_RX_ADDR(addr, _usbd_device.pm_top);
- usb_set_ep_rx_bufsize(addr, max_size);
+ USB_SET_EP_RX_ADDR(addr, usbd_dev->pm_top);
+ usb_set_ep_rx_bufsize(usbd_dev, addr, max_size);
if (callback) {
- _usbd_device.
- user_callback_ctr[addr][USB_TRANSACTION_OUT] =
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
(void *)callback;
}
USB_CLR_EP_RX_DTOG(addr);
USB_SET_EP_RX_STAT(addr, USB_EP_RX_STAT_VALID);
- _usbd_device.pm_top += max_size;
+ usbd_dev->pm_top += max_size;
}
}
-static void stm32f103_endpoints_reset(void)
+static void stm32f103_endpoints_reset(usbd_device *usbd_dev)
{
int i;
@@ -141,11 +147,12 @@ static void stm32f103_endpoints_reset(void)
USB_SET_EP_TX_STAT(i, USB_EP_TX_STAT_DISABLED);
USB_SET_EP_RX_STAT(i, USB_EP_RX_STAT_DISABLED);
}
- _usbd_device.pm_top = 0x40 + (2 * _usbd_device.desc->bMaxPacketSize0);
+ usbd_dev->pm_top = 0x40 + (2 * usbd_dev->desc->bMaxPacketSize0);
}
-static void stm32f103_ep_stall_set(u8 addr, u8 stall)
+static void stm32f103_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
{
+ (void)usbd_dev;
if (addr == 0)
USB_SET_EP_TX_STAT(addr, stall ? USB_EP_TX_STAT_STALL :
USB_EP_TX_STAT_NAK);
@@ -169,8 +176,9 @@ static void stm32f103_ep_stall_set(u8 addr, u8 stall)
}
}
-static u8 stm32f103_ep_stall_get(u8 addr)
+static u8 stm32f103_ep_stall_get(usbd_device *usbd_dev, u8 addr)
{
+ (void)usbd_dev;
if (addr & 0x80) {
if ((*USB_EP_REG(addr & 0x7F) & USB_EP_TX_STAT) ==
USB_EP_TX_STAT_STALL)
@@ -183,8 +191,9 @@ static u8 stm32f103_ep_stall_get(u8 addr)
return 0;
}
-static void stm32f103_ep_nak_set(u8 addr, u8 nak)
+static void stm32f103_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
{
+ (void)usbd_dev;
/* It does not make sence to force NAK on IN endpoints. */
if (addr & 0x80)
return;
@@ -213,8 +222,10 @@ static void usb_copy_to_pm(volatile void *vPM, const void *buf, u16 len)
*PM = *lbuf;
}
-static u16 stm32f103_ep_write_packet(u8 addr, const void *buf, u16 len)
+static u16 stm32f103_ep_write_packet(usbd_device *usbd_dev, u8 addr,
+ const void *buf, u16 len)
{
+ (void)usbd_dev;
addr &= 0x7F;
if ((*USB_EP_REG(addr) & USB_EP_TX_STAT) == USB_EP_TX_STAT_VALID)
@@ -247,8 +258,10 @@ static void usb_copy_from_pm(void *buf, const volatile void *vPM, u16 len)
*(u8 *) lbuf = *(u8 *) PM;
}
-static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len)
+static u16 stm32f103_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
+ u16 len)
{
+ (void)usbd_dev;
if ((*USB_EP_REG(addr) & USB_EP_RX_STAT) == USB_EP_RX_STAT_VALID)
return 0;
@@ -262,13 +275,13 @@ static u16 stm32f103_ep_read_packet(u8 addr, void *buf, u16 len)
return len;
}
-static void stm32f103_poll(void)
+static void stm32f103_poll(usbd_device *usbd_dev)
{
u16 istr = *USB_ISTR_REG;
if (istr & USB_ISTR_RESET) {
- _usbd_device.pm_top = 0x40;
- _usbd_reset();
+ usbd_dev->pm_top = 0x40;
+ _usbd_reset(usbd_dev);
USB_CLR_ISTR_RESET();
return;
}
@@ -282,27 +295,27 @@ static void stm32f103_poll(void)
else /* IN transaction */
USB_CLR_EP_TX_CTR(ep);
- if (_usbd_device.user_callback_ctr[ep][type])
- _usbd_device.user_callback_ctr[ep][type] (ep);
+ if (usbd_dev->user_callback_ctr[ep][type])
+ usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
else
USB_CLR_EP_RX_CTR(ep);
}
if (istr & USB_ISTR_SUSP) {
USB_CLR_ISTR_SUSP();
- if (_usbd_device.user_callback_suspend)
- _usbd_device.user_callback_suspend();
+ if (usbd_dev->user_callback_suspend)
+ usbd_dev->user_callback_suspend();
}
if (istr & USB_ISTR_WKUP) {
USB_CLR_ISTR_WKUP();
- if (_usbd_device.user_callback_resume)
- _usbd_device.user_callback_resume();
+ if (usbd_dev->user_callback_resume)
+ usbd_dev->user_callback_resume();
}
if (istr & USB_ISTR_SOF) {
- if (_usbd_device.user_callback_sof)
- _usbd_device.user_callback_sof();
+ if (usbd_dev->user_callback_sof)
+ usbd_dev->user_callback_sof();
USB_CLR_ISTR_SOF();
}
}
diff --git a/lib/usb/usb_f107.c b/lib/usb/usb_f107.c
index a5a4a6c..009979d 100644
--- a/lib/usb/usb_f107.c
+++ b/lib/usb/usb_f107.c
@@ -23,49 +23,34 @@
#include <libopencm3/stm32/otg_fs.h>
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
+#include "usb_fx07_common.h"
/* Receive FIFO size in 32-bit words. */
#define RX_FIFO_SIZE 128
-static uint16_t fifo_mem_top;
-static uint16_t fifo_mem_top_ep0;
-static u8 force_nak[4];
+static usbd_device *stm32f107_usbd_init(void);
-static void stm32f107_usbd_init(void);
-static void stm32f107_set_address(u8 addr);
-static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size,
- void (*callback)(u8 ep));
-static void stm32f107_endpoints_reset(void);
-static void stm32f107_ep_stall_set(u8 addr, u8 stall);
-static u8 stm32f107_ep_stall_get(u8 addr);
-static void stm32f107_ep_nak_set(u8 addr, u8 nak);
-static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len);
-static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len);
-static void stm32f107_poll(void);
-static void stm32f107_disconnect(bool disconnected);
-
-/*
- * We keep a backup copy of the out endpoint size registers to restore them
- * after a transaction.
- */
-static u32 doeptsiz[4];
+static struct _usbd_device usbd_dev;
const struct _usbd_driver stm32f107_usb_driver = {
.init = stm32f107_usbd_init,
- .set_address = stm32f107_set_address,
- .ep_setup = stm32f107_ep_setup,
- .ep_reset = stm32f107_endpoints_reset,
- .ep_stall_set = stm32f107_ep_stall_set,
- .ep_stall_get = stm32f107_ep_stall_get,
- .ep_nak_set = stm32f107_ep_nak_set,
- .ep_write_packet = stm32f107_ep_write_packet,
- .ep_read_packet = stm32f107_ep_read_packet,
- .poll = stm32f107_poll,
- .disconnect = stm32f107_disconnect,
+ .set_address = stm32fx07_set_address,
+ .ep_setup = stm32fx07_ep_setup,
+ .ep_reset = stm32fx07_endpoints_reset,
+ .ep_stall_set = stm32fx07_ep_stall_set,
+ .ep_stall_get = stm32fx07_ep_stall_get,
+ .ep_nak_set = stm32fx07_ep_nak_set,
+ .ep_write_packet = stm32fx07_ep_write_packet,
+ .ep_read_packet = stm32fx07_ep_read_packet,
+ .poll = stm32fx07_poll,
+ .disconnect = stm32fx07_disconnect,
+ .base_address = USB_OTG_FS_BASE,
+ .set_address_before_status = 1,
+ .rx_fifo_size = RX_FIFO_SIZE,
};
/** Initialize the USB device controller hardware of the STM32. */
-static void stm32f107_usbd_init(void)
+static usbd_device *stm32f107_usbd_init(void)
{
OTG_FS_GINTSTS = OTG_FS_GINTSTS_MMIS;
@@ -88,8 +73,8 @@ static void stm32f107_usbd_init(void)
/* Restart the PHY clock. */
OTG_FS_PCGCCTL = 0;
- OTG_FS_GRXFSIZ = RX_FIFO_SIZE;
- fifo_mem_top = RX_FIFO_SIZE;
+ OTG_FS_GRXFSIZ = stm32f107_usb_driver.rx_fifo_size;
+ usbd_dev.fifo_mem_top = stm32f107_usb_driver.rx_fifo_size;
/* Unmask interrupts for TX and RX. */
OTG_FS_GAHBCFG |= OTG_FS_GAHBCFG_GINT;
@@ -101,289 +86,6 @@ static void stm32f107_usbd_init(void)
OTG_FS_GINTMSK_SOFM;
OTG_FS_DAINTMSK = 0xF;
OTG_FS_DIEPMSK = OTG_FS_DIEPMSK_XFRCM;
-}
-
-static void stm32f107_set_address(u8 addr)
-{
- OTG_FS_DCFG = (OTG_FS_DCFG & ~OTG_FS_DCFG_DAD) | (addr << 4);
-}
-
-static void stm32f107_ep_setup(u8 addr, u8 type, u16 max_size,
- void (*callback) (u8 ep))
-{
- /*
- * Configure endpoint address and type. Allocate FIFO memory for
- * endpoint. Install callback funciton.
- */
- u8 dir = addr & 0x80;
- addr &= 0x7f;
-
- if (addr == 0) { /* For the default control endpoint */
- /* Configure IN part. */
- if (max_size >= 64) {
- OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_64;
- } else if (max_size >= 32) {
- OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_32;
- } else if (max_size >= 16) {
- OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_16;
- } else {
- OTG_FS_DIEPCTL0 = OTG_FS_DIEPCTL0_MPSIZ_8;
- }
- OTG_FS_DIEPTSIZ0 = (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
- OTG_FS_DIEPCTL0 |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
-
- /* Configure OUT part. */
- doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 | (1 << 19) |
- (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
- OTG_FS_DOEPTSIZ(0) = doeptsiz[0];
- OTG_FS_DOEPCTL(0) |=
- OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
-
- OTG_FS_GNPTXFSIZ = ((max_size / 4) << 16) | RX_FIFO_SIZE;
- fifo_mem_top += max_size / 4;
- fifo_mem_top_ep0 = fifo_mem_top;
-
- return;
- }
-
- if (dir) {
- OTG_FS_DIEPTXF(addr) = ((max_size / 4) << 16) | fifo_mem_top;
- fifo_mem_top += max_size / 4;
-
- OTG_FS_DIEPTSIZ(addr) =
- (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
- OTG_FS_DIEPCTL(addr) |=
- OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18)
- | OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID
- | (addr << 22) | max_size;
-
- if (callback) {
- _usbd_device.
- user_callback_ctr[addr][USB_TRANSACTION_IN] =
- (void *)callback;
- }
- }
-
- if (!dir) {
- doeptsiz[addr] = (1 << 19) |
- (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
- OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr];
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA |
- OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK |
- OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size;
-
- if (callback) {
- _usbd_device.
- user_callback_ctr[addr][USB_TRANSACTION_OUT] =
- (void *)callback;
- }
- }
-}
-
-static void stm32f107_endpoints_reset(void)
-{
- /* The core resets the endpoints automatically on reset. */
- fifo_mem_top = fifo_mem_top_ep0;
-}
-
-static void stm32f107_ep_stall_set(u8 addr, u8 stall)
-{
- if (addr == 0) {
- if (stall)
- OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_STALL;
- else
- OTG_FS_DIEPCTL(addr) &= ~OTG_FS_DIEPCTL0_STALL;
- }
-
- if (addr & 0x80) {
- addr &= 0x7F;
-
- if (stall) {
- OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_STALL;
- } else {
- OTG_FS_DIEPCTL(addr) &= ~OTG_FS_DIEPCTL0_STALL;
- OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTLX_SD0PID;
- }
- } else {
- if (stall) {
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_STALL;
- } else {
- OTG_FS_DOEPCTL(addr) &= ~OTG_FS_DOEPCTL0_STALL;
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTLX_SD0PID;
- }
- }
-}
-
-static u8 stm32f107_ep_stall_get(u8 addr)
-{
- /* Return non-zero if STALL set. */
- if (addr & 0x80)
- return
- (OTG_FS_DIEPCTL(addr & 0x7f) & OTG_FS_DIEPCTL0_STALL) ? 1 : 0;
- else
- return (OTG_FS_DOEPCTL(addr) & OTG_FS_DOEPCTL0_STALL) ? 1 : 0;
-}
-
-static void stm32f107_ep_nak_set(u8 addr, u8 nak)
-{
- /* It does not make sence to force NAK on IN endpoints. */
- if (addr & 0x80)
- return;
-
- force_nak[addr] = nak;
-
- if (nak)
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_SNAK;
- else
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_CNAK;
-}
-static u16 stm32f107_ep_write_packet(u8 addr, const void *buf, u16 len)
-{
- const u32 *buf32 = buf;
- int i;
-
- addr &= 0x7F;
-
- /* Return if endpoint is already enabled. */
- if (OTG_FS_DIEPTSIZ(addr) & OTG_FS_DIEPSIZ0_PKTCNT)
- return 0;
-
- /* Enable endpoint for transmission. */
- OTG_FS_DIEPTSIZ(addr) = (1 << 19) | len;
- OTG_FS_DIEPCTL(addr) |= OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_CNAK;
-
- /* Copy buffer to endpoint FIFO. */
- volatile u32 *fifo = OTG_FS_FIFO(addr);
- for (i = len; i > 0; i -= 4)
- *fifo++ = *buf32++;
-
- return len;
-}
-
-/*
- * Received packet size for each endpoint. This is assigned in
- * stm32f107_poll() which reads the packet status push register GRXSTSP
- * for use in stm32f107_ep_read_packet().
- */
-static uint16_t rxbcnt;
-
-static u16 stm32f107_ep_read_packet(u8 addr, void *buf, u16 len)
-{
- int i;
- u32 *buf32 = buf;
- u32 extra;
-
- len = MIN(len, rxbcnt);
- rxbcnt -= len;
-
- volatile u32 *fifo = OTG_FS_FIFO(addr);
- for (i = len; i >= 4; i -= 4)
- *buf32++ = *fifo++;
-
- if (i) {
- extra = *fifo++;
- memcpy(buf32, &extra, i);
- }
-
- OTG_FS_DOEPTSIZ(addr) = doeptsiz[addr];
- OTG_FS_DOEPCTL(addr) |= OTG_FS_DOEPCTL0_EPENA |
- (force_nak[addr] ? OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK);
-
- return len;
-}
-
-static void stm32f107_poll(void)
-{
- /* Read interrupt status register. */
- u32 intsts = OTG_FS_GINTSTS;
- int i;
-
- if (intsts & OTG_FS_GINTSTS_ENUMDNE) {
- /* Handle USB RESET condition. */
- OTG_FS_GINTSTS = OTG_FS_GINTSTS_ENUMDNE;
- fifo_mem_top = RX_FIFO_SIZE;
- _usbd_reset();
- return;
- }
-
- /* Note: RX and TX handled differently in this device. */
- if (intsts & OTG_FS_GINTSTS_RXFLVL) {
- /* Receive FIFO non-empty. */
- u32 rxstsp = OTG_FS_GRXSTSP;
- u32 pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK;
- if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) &&
- (pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP))
- return;
-
- u8 ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK;
- u8 type;
- if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP)
- type = USB_TRANSACTION_SETUP;
- else
- type = USB_TRANSACTION_OUT;
-
- /* Save packet size for stm32f107_ep_read_packet(). */
- rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4;
-
- /*
- * FIXME: Why is a delay needed here?
- * This appears to fix a problem where the first 4 bytes
- * of the DATA OUT stage of a control transaction are lost.
- */
- for (i = 0; i < 1000; i++)
- __asm__("nop");
-
- if (_usbd_device.user_callback_ctr[ep][type])
- _usbd_device.user_callback_ctr[ep][type] (ep);
-
- /* Discard unread packet data. */
- for (i = 0; i < rxbcnt; i += 4)
- (void)*OTG_FS_FIFO(ep);
-
- rxbcnt = 0;
- }
-
- /*
- * There is no global interrupt flag for transmit complete.
- * The XFRC bit must be checked in each OTG_FS_DIEPINT(x).
- */
- for (i = 0; i < 4; i++) { /* Iterate over endpoints. */
- if (OTG_FS_DIEPINT(i) & OTG_FS_DIEPINTX_XFRC) {
- /* Transfer complete. */
- if (_usbd_device.
- user_callback_ctr[i][USB_TRANSACTION_IN]) {
- _usbd_device.
- user_callback_ctr[i][USB_TRANSACTION_IN](i);
- }
- OTG_FS_DIEPINT(i) = OTG_FS_DIEPINTX_XFRC;
- }
- }
-
- if (intsts & OTG_FS_GINTSTS_USBSUSP) {
- if (_usbd_device.user_callback_suspend)
- _usbd_device.user_callback_suspend();
- OTG_FS_GINTSTS = OTG_FS_GINTSTS_USBSUSP;
- }
-
- if (intsts & OTG_FS_GINTSTS_WKUPINT) {
- if (_usbd_device.user_callback_resume)
- _usbd_device.user_callback_resume();
- OTG_FS_GINTSTS = OTG_FS_GINTSTS_WKUPINT;
- }
-
- if (intsts & OTG_FS_GINTSTS_SOF) {
- if (_usbd_device.user_callback_sof)
- _usbd_device.user_callback_sof();
- OTG_FS_GINTSTS = OTG_FS_GINTSTS_SOF;
- }
-}
-
-static void stm32f107_disconnect(bool disconnected)
-{
- if (disconnected) {
- OTG_FS_DCTL |= OTG_FS_DCTL_SDIS;
- } else {
- OTG_FS_DCTL &= ~OTG_FS_DCTL_SDIS;
- }
+ return &usbd_dev;
}
diff --git a/lib/usb/usb_f207.c b/lib/usb/usb_f207.c
new file mode 100644
index 0000000..b2509e5
--- /dev/null
+++ b/lib/usb/usb_f207.c
@@ -0,0 +1,91 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/otg_hs.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+#include "usb_fx07_common.h"
+
+/* Receive FIFO size in 32-bit words. */
+#define RX_FIFO_SIZE 512
+
+static usbd_device *stm32f207_usbd_init(void);
+
+static struct _usbd_device usbd_dev;
+
+const struct _usbd_driver stm32f207_usb_driver = {
+ .init = stm32f207_usbd_init,
+ .set_address = stm32fx07_set_address,
+ .ep_setup = stm32fx07_ep_setup,
+ .ep_reset = stm32fx07_endpoints_reset,
+ .ep_stall_set = stm32fx07_ep_stall_set,
+ .ep_stall_get = stm32fx07_ep_stall_get,
+ .ep_nak_set = stm32fx07_ep_nak_set,
+ .ep_write_packet = stm32fx07_ep_write_packet,
+ .ep_read_packet = stm32fx07_ep_read_packet,
+ .poll = stm32fx07_poll,
+ .disconnect = stm32fx07_disconnect,
+ .base_address = USB_OTG_HS_BASE,
+ .set_address_before_status = 1,
+ .rx_fifo_size = RX_FIFO_SIZE,
+};
+
+/** Initialize the USB device controller hardware of the STM32. */
+static usbd_device *stm32f207_usbd_init(void)
+{
+ OTG_HS_GINTSTS = OTG_HS_GINTSTS_MMIS;
+
+ OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_PHYSEL;
+ /* Enable VBUS sensing in device mode and power down the PHY. */
+ OTG_HS_GCCFG |= OTG_HS_GCCFG_VBUSBSEN | OTG_HS_GCCFG_PWRDWN;
+
+ /* Wait for AHB idle. */
+ while (!(OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_AHBIDL)) ;
+ /* Do core soft reset. */
+ OTG_HS_GRSTCTL |= OTG_HS_GRSTCTL_CSRST;
+ while (OTG_HS_GRSTCTL & OTG_HS_GRSTCTL_CSRST) ;
+
+ /* Force peripheral only mode. */
+ OTG_HS_GUSBCFG |= OTG_HS_GUSBCFG_FDMOD | OTG_HS_GUSBCFG_TRDT_MASK;
+
+ /* Full speed device. */
+ OTG_HS_DCFG |= OTG_HS_DCFG_DSPD;
+
+ /* Restart the PHY clock. */
+ OTG_HS_PCGCCTL = 0;
+
+ OTG_HS_GRXFSIZ = stm32f207_usb_driver.rx_fifo_size;
+ usbd_dev.fifo_mem_top = stm32f207_usb_driver.rx_fifo_size;
+
+ /* Unmask interrupts for TX and RX. */
+ OTG_HS_GAHBCFG |= OTG_HS_GAHBCFG_GINT;
+ OTG_HS_GINTMSK = OTG_HS_GINTMSK_ENUMDNEM |
+ OTG_HS_GINTMSK_RXFLVLM |
+ OTG_HS_GINTMSK_IEPINT |
+ OTG_HS_GINTMSK_USBSUSPM |
+ OTG_HS_GINTMSK_WUIM |
+ OTG_HS_GINTMSK_SOFM;
+ OTG_HS_DAINTMSK = 0xF;
+ OTG_HS_DIEPMSK = OTG_HS_DIEPMSK_XFRCM;
+
+ return &usbd_dev;
+}
diff --git a/lib/usb/usb_fx07_common.c b/lib/usb/usb_fx07_common.c
new file mode 100644
index 0000000..9178092
--- /dev/null
+++ b/lib/usb/usb_fx07_common.c
@@ -0,0 +1,318 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/tools.h>
+#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/stm32/otg_hs.h>
+#include <libopencm3/usb/usbd.h>
+#include "usb_private.h"
+#include "usb_fx07_common.h"
+
+/* The FS core and the HS core have the same register layout.
+ * As the code can be used on both cores, the registers offset is modified
+ * according to the selected cores base address. */
+#define dev_base_address (usbd_dev->driver->base_address)
+#define REBASE(x) MMIO32((x)+(dev_base_address))
+#define REBASE_FIFO(x) ((volatile u32*)((dev_base_address) + (OTG_FIFO(x))))
+
+void stm32fx07_set_address(usbd_device *usbd_dev, u8 addr)
+{
+ REBASE(OTG_DCFG) = (REBASE(OTG_DCFG) & ~OTG_FS_DCFG_DAD) | (addr << 4);
+}
+
+void stm32fx07_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
+ void (*callback) (usbd_device *usbd_dev, u8 ep))
+{
+ /*
+ * Configure endpoint address and type. Allocate FIFO memory for
+ * endpoint. Install callback funciton.
+ */
+ u8 dir = addr & 0x80;
+ addr &= 0x7f;
+
+ if (addr == 0) { /* For the default control endpoint */
+ /* Configure IN part. */
+ if (max_size >= 64) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_64;
+ } else if (max_size >= 32) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_32;
+ } else if (max_size >= 16) {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_16;
+ } else {
+ REBASE(OTG_DIEPCTL0) = OTG_FS_DIEPCTL0_MPSIZ_8;
+ }
+ REBASE(OTG_DIEPTSIZ0) =
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DIEPCTL0) |=
+ OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
+
+ /* Configure OUT part. */
+ usbd_dev->doeptsiz[0] = OTG_FS_DIEPSIZ0_STUPCNT_1 |
+ OTG_FS_DIEPSIZ0_PKTCNT |
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DOEPTSIZ(0)) = usbd_dev->doeptsiz[0];
+ REBASE(OTG_DOEPCTL(0)) |=
+ OTG_FS_DOEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK;
+
+ REBASE(OTG_GNPTXFSIZ) = ((max_size / 4) << 16) |
+ usbd_dev->driver->rx_fifo_size;
+ usbd_dev->fifo_mem_top += max_size / 4;
+ usbd_dev->fifo_mem_top_ep0 = usbd_dev->fifo_mem_top;
+
+ return;
+ }
+
+ if (dir) {
+ REBASE(OTG_DIEPTXF(addr)) = ((max_size / 4) << 16) |
+ usbd_dev->fifo_mem_top;
+ usbd_dev->fifo_mem_top += max_size / 4;
+
+ REBASE(OTG_DIEPTSIZ(addr)) =
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DIEPCTL(addr)) |=
+ OTG_FS_DIEPCTL0_EPENA | OTG_FS_DIEPCTL0_SNAK | (type << 18)
+ | OTG_FS_DIEPCTL0_USBAEP | OTG_FS_DIEPCTLX_SD0PID
+ | (addr << 22) | max_size;
+
+ if (callback) {
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_IN] =
+ (void *)callback;
+ }
+ }
+
+ if (!dir) {
+ usbd_dev->doeptsiz[addr] = OTG_FS_DIEPSIZ0_PKTCNT |
+ (max_size & OTG_FS_DIEPSIZ0_XFRSIZ_MASK);
+ REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
+ OTG_FS_DOEPCTL0_USBAEP | OTG_FS_DIEPCTL0_CNAK |
+ OTG_FS_DOEPCTLX_SD0PID | (type << 18) | max_size;
+
+ if (callback) {
+ usbd_dev->user_callback_ctr[addr][USB_TRANSACTION_OUT] =
+ (void *)callback;
+ }
+ }
+}
+
+void stm32fx07_endpoints_reset(usbd_device *usbd_dev)
+{
+ /* The core resets the endpoints automatically on reset. */
+ usbd_dev->fifo_mem_top = usbd_dev->fifo_mem_top_ep0;
+}
+
+void stm32fx07_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall)
+{
+ if (addr == 0) {
+ if (stall)
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
+ else
+ REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
+ }
+
+ if (addr & 0x80) {
+ addr &= 0x7F;
+
+ if (stall) {
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_STALL;
+ } else {
+ REBASE(OTG_DIEPCTL(addr)) &= ~OTG_FS_DIEPCTL0_STALL;
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTLX_SD0PID;
+ }
+ } else {
+ if (stall) {
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_STALL;
+ } else {
+ REBASE(OTG_DOEPCTL(addr)) &= ~OTG_FS_DOEPCTL0_STALL;
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTLX_SD0PID;
+ }
+ }
+}
+
+u8 stm32fx07_ep_stall_get(usbd_device *usbd_dev, u8 addr)
+{
+ /* Return non-zero if STALL set. */
+ if (addr & 0x80)
+ return (REBASE(OTG_DIEPCTL(addr & 0x7f)) &
+ OTG_FS_DIEPCTL0_STALL) ? 1 : 0;
+ else
+ return (REBASE(OTG_DOEPCTL(addr)) &
+ OTG_FS_DOEPCTL0_STALL) ? 1 : 0;
+}
+
+void stm32fx07_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak)
+{
+ /* It does not make sence to force NAK on IN endpoints. */
+ if (addr & 0x80)
+ return;
+
+ usbd_dev->force_nak[addr] = nak;
+
+ if (nak)
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_SNAK;
+ else
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_CNAK;
+}
+
+u16 stm32fx07_ep_write_packet(usbd_device *usbd_dev, u8 addr,
+ const void *buf, u16 len)
+{
+ const u32 *buf32 = buf;
+ int i;
+
+ addr &= 0x7F;
+
+ /* Return if endpoint is already enabled. */
+ if (REBASE(OTG_DIEPTSIZ(addr)) & OTG_FS_DIEPSIZ0_PKTCNT)
+ return 0;
+
+ /* Enable endpoint for transmission. */
+ REBASE(OTG_DIEPTSIZ(addr)) = OTG_FS_DIEPSIZ0_PKTCNT | len;
+ REBASE(OTG_DIEPCTL(addr)) |= OTG_FS_DIEPCTL0_EPENA |
+ OTG_FS_DIEPCTL0_CNAK;
+ volatile u32 *fifo = REBASE_FIFO(addr);
+
+ /* Copy buffer to endpoint FIFO, note - memcpy does not work */
+ for (i = len; i > 0; i -= 4)
+ *fifo++ = *buf32++;
+
+ return len;
+}
+
+u16 stm32fx07_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf, u16 len)
+{
+ int i;
+ u32 *buf32 = buf;
+ u32 extra;
+
+ len = MIN(len, usbd_dev->rxbcnt);
+ usbd_dev->rxbcnt -= len;
+
+ volatile u32 *fifo = REBASE_FIFO(addr);
+ for (i = len; i >= 4; i -= 4)
+ *buf32++ = *fifo++;
+
+ if (i) {
+ extra = *fifo++;
+ memcpy(buf32, &extra, i);
+ }
+
+ REBASE(OTG_DOEPTSIZ(addr)) = usbd_dev->doeptsiz[addr];
+ REBASE(OTG_DOEPCTL(addr)) |= OTG_FS_DOEPCTL0_EPENA |
+ (usbd_dev->force_nak[addr] ?
+ OTG_FS_DOEPCTL0_SNAK : OTG_FS_DOEPCTL0_CNAK);
+
+ return len;
+}
+
+void stm32fx07_poll(usbd_device *usbd_dev)
+{
+ /* Read interrupt status register. */
+ u32 intsts = REBASE(OTG_GINTSTS);
+ int i;
+
+ if (intsts & OTG_FS_GINTSTS_ENUMDNE) {
+ /* Handle USB RESET condition. */
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_ENUMDNE;
+ usbd_dev->fifo_mem_top = usbd_dev->driver->rx_fifo_size;
+ _usbd_reset(usbd_dev);
+ return;
+ }
+
+ /* Note: RX and TX handled differently in this device. */
+ if (intsts & OTG_FS_GINTSTS_RXFLVL) {
+ /* Receive FIFO non-empty. */
+ u32 rxstsp = REBASE(OTG_GRXSTSP);
+ u32 pktsts = rxstsp & OTG_FS_GRXSTSP_PKTSTS_MASK;
+ if ((pktsts != OTG_FS_GRXSTSP_PKTSTS_OUT) &&
+ (pktsts != OTG_FS_GRXSTSP_PKTSTS_SETUP))
+ return;
+
+ u8 ep = rxstsp & OTG_FS_GRXSTSP_EPNUM_MASK;
+ u8 type;
+ if (pktsts == OTG_FS_GRXSTSP_PKTSTS_SETUP)
+ type = USB_TRANSACTION_SETUP;
+ else
+ type = USB_TRANSACTION_OUT;
+
+ /* Save packet size for stm32f107_ep_read_packet(). */
+ usbd_dev->rxbcnt = (rxstsp & OTG_FS_GRXSTSP_BCNT_MASK) >> 4;
+
+ /*
+ * FIXME: Why is a delay needed here?
+ * This appears to fix a problem where the first 4 bytes
+ * of the DATA OUT stage of a control transaction are lost.
+ */
+ for (i = 0; i < 1000; i++)
+ __asm__("nop");
+
+ if (usbd_dev->user_callback_ctr[ep][type])
+ usbd_dev->user_callback_ctr[ep][type] (usbd_dev, ep);
+
+ /* Discard unread packet data. */
+ for (i = 0; i < usbd_dev->rxbcnt; i += 4)
+ (void)*REBASE_FIFO(ep);
+
+ usbd_dev->rxbcnt = 0;
+ }
+
+ /*
+ * There is no global interrupt flag for transmit complete.
+ * The XFRC bit must be checked in each OTG_FS_DIEPINT(x).
+ */
+ for (i = 0; i < 4; i++) { /* Iterate over endpoints. */
+ if (REBASE(OTG_DIEPINT(i)) & OTG_FS_DIEPINTX_XFRC) {
+ /* Transfer complete. */
+ if (usbd_dev->user_callback_ctr[i][USB_TRANSACTION_IN])
+ usbd_dev->user_callback_ctr[i]
+ [USB_TRANSACTION_IN](usbd_dev, i);
+
+ REBASE(OTG_DIEPINT(i)) = OTG_FS_DIEPINTX_XFRC;
+ }
+ }
+
+ if (intsts & OTG_FS_GINTSTS_USBSUSP) {
+ if (usbd_dev->user_callback_suspend)
+ usbd_dev->user_callback_suspend();
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_USBSUSP;
+ }
+
+ if (intsts & OTG_FS_GINTSTS_WKUPINT) {
+ if (usbd_dev->user_callback_resume)
+ usbd_dev->user_callback_resume();
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_WKUPINT;
+ }
+
+ if (intsts & OTG_FS_GINTSTS_SOF) {
+ if (usbd_dev->user_callback_sof)
+ usbd_dev->user_callback_sof();
+ REBASE(OTG_GINTSTS) = OTG_FS_GINTSTS_SOF;
+ }
+}
+
+void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected)
+{
+ if (disconnected) {
+ REBASE(OTG_DCTL) |= OTG_FS_DCTL_SDIS;
+ } else {
+ REBASE(OTG_DCTL) &= ~OTG_FS_DCTL_SDIS;
+ }
+}
diff --git a/lib/usb/usb_fx07_common.h b/lib/usb/usb_fx07_common.h
new file mode 100644
index 0000000..4d8d38e
--- /dev/null
+++ b/lib/usb/usb_fx07_common.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __USB_FX07_COMMON_H_
+#define __USB_FX07_COMMON_H_
+
+void stm32fx07_set_address(usbd_device *usbd_dev, u8 addr);
+void stm32fx07_ep_setup(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
+ void (*callback)(usbd_device *usbd_dev, u8 ep));
+void stm32fx07_endpoints_reset(usbd_device *usbd_dev);
+void stm32fx07_ep_stall_set(usbd_device *usbd_dev, u8 addr, u8 stall);
+u8 stm32fx07_ep_stall_get(usbd_device *usbd_dev, u8 addr);
+void stm32fx07_ep_nak_set(usbd_device *usbd_dev, u8 addr, u8 nak);
+u16 stm32fx07_ep_write_packet(usbd_device *usbd_dev, u8 addr, const void *buf,
+ u16 len);
+u16 stm32fx07_ep_read_packet(usbd_device *usbd_dev, u8 addr, void *buf,
+ u16 len);
+void stm32fx07_poll(usbd_device *usbd_dev);
+void stm32fx07_disconnect(usbd_device *usbd_dev, bool disconnected);
+
+
+#endif /* __USB_FX07_COMMON_H_ */
diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h
index 238f14f..454e8c6 100644
--- a/lib/usb/usb_private.h
+++ b/lib/usb/usb_private.h
@@ -25,7 +25,7 @@
#define MIN(a, b) ((a)<(b) ? (a) : (b))
/** Internal collection of device information. */
-extern struct _usbd_device {
+struct _usbd_device {
const struct usb_device_descriptor *desc;
const struct usb_config_descriptor *config;
const char **strings;
@@ -45,19 +45,49 @@ extern struct _usbd_device {
void (*user_callback_resume)(void);
void (*user_callback_sof)(void);
+ struct usb_control_state {
+ enum {
+ IDLE, STALLED,
+ DATA_IN, LAST_DATA_IN, STATUS_IN,
+ DATA_OUT, LAST_DATA_OUT, STATUS_OUT,
+ } state;
+ struct usb_setup_data req __attribute__((aligned(4)));
+ u8 *ctrl_buf;
+ u16 ctrl_len;
+ void (*complete)(usbd_device *usbd_dev,
+ struct usb_setup_data *req);
+ } control_state;
+
struct user_control_callback {
usbd_control_callback cb;
u8 type;
u8 type_mask;
} user_control_callback[MAX_USER_CONTROL_CALLBACK];
- void (*user_callback_ctr[8][3])(u8 ea);
+ void (*user_callback_ctr[8][3])(usbd_device *usbd_dev, u8 ea);
/* User callback function for some standard USB function hooks */
- void (*user_callback_set_config)(u16 wValue);
+ void (*user_callback_set_config)(usbd_device *usbd_dev, u16 wValue);
const struct _usbd_driver *driver;
-} _usbd_device;
+
+ /* private driver data */
+
+ uint16_t fifo_mem_top;
+ uint16_t fifo_mem_top_ep0;
+ u8 force_nak[4];
+ /*
+ * We keep a backup copy of the out endpoint size registers to restore them
+ * after a transaction.
+ */
+ u32 doeptsiz[4];
+ /*
+ * Received packet size for each endpoint. This is assigned in
+ * stm32f107_poll() which reads the packet status push register GRXSTSP
+ * for use in stm32f107_ep_read_packet().
+ */
+ uint16_t rxbcnt;
+};
enum _usbd_transaction {
USB_TRANSACTION_IN,
@@ -65,31 +95,34 @@ enum _usbd_transaction {
USB_TRANSACTION_SETUP,
};
-void _usbd_control_in(u8 ea);
-void _usbd_control_out(u8 ea);
-void _usbd_control_setup(u8 ea);
+void _usbd_control_in(usbd_device *usbd_dev, u8 ea);
+void _usbd_control_out(usbd_device *usbd_dev, u8 ea);
+void _usbd_control_setup(usbd_device *usbd_dev, u8 ea);
-int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len);
+int _usbd_standard_request(usbd_device *usbd_dev, struct usb_setup_data *req,
+ u8 **buf, u16 *len);
-void _usbd_reset(void);
+void _usbd_reset(usbd_device *usbd_dev);
/* Functions provided by the hardware abstraction. */
struct _usbd_driver {
- void (*init)(void);
- void (*set_address)(u8 addr);
- void (*ep_setup)(u8 addr, u8 type, u16 max_size, void (*cb)(u8 ep));
- void (*ep_reset)(void);
- void (*ep_stall_set)(u8 addr, u8 stall);
- void (*ep_nak_set)(u8 addr, u8 nak);
- u8 (*ep_stall_get)(u8 addr);
- u16 (*ep_write_packet)(u8 addr, const void *buf, u16 len);
- u16 (*ep_read_packet)(u8 addr, void *buf, u16 len);
- void (*poll)(void);
- void (*disconnect)(bool disconnected);
+ usbd_device *(*init)(void);
+ void (*set_address)(usbd_device *usbd_dev, u8 addr);
+ void (*ep_setup)(usbd_device *usbd_dev, u8 addr, u8 type, u16 max_size,
+ void (*cb)(usbd_device *usbd_dev, u8 ep));
+ void (*ep_reset)(usbd_device *usbd_dev);
+ void (*ep_stall_set)(usbd_device *usbd_dev, u8 addr, u8 stall);
+ void (*ep_nak_set)(usbd_device *usbd_dev, u8 addr, u8 nak);
+ u8 (*ep_stall_get)(usbd_device *usbd_dev, u8 addr);
+ u16 (*ep_write_packet)(usbd_device *usbd_dev, u8 addr, const void *buf,
+ u16 len);
+ u16 (*ep_read_packet)(usbd_device *usbd_dev, u8 addr, void *buf,
+ u16 len);
+ void (*poll)(usbd_device *usbd_dev);
+ void (*disconnect)(usbd_device *usbd_dev, bool disconnected);
+ u32 base_address;
+ bool set_address_before_status;
+ u16 rx_fifo_size;
};
-#define _usbd_hw_init() _usbd_device.driver->init()
-#define _usbd_hw_set_address(addr) _usbd_device.driver->set_address(addr)
-#define _usbd_hw_endpoints_reset() _usbd_device.driver->ep_reset()
-
#endif
diff --git a/lib/usb/usb_standard.c b/lib/usb/usb_standard.c
index 08923d8..e14fee3 100644
--- a/lib/usb/usb_standard.c
+++ b/lib/usb/usb_standard.c
@@ -21,15 +21,18 @@
#include <libopencm3/usb/usbd.h>
#include "usb_private.h"
-void usbd_register_set_config_callback(void (*callback)(u16 wValue))
+void usbd_register_set_config_callback(usbd_device *usbd_dev,
+ void (*callback)(usbd_device *usbd_dev,
+ u16 wValue))
{
- _usbd_device.user_callback_set_config = callback;
+ usbd_dev->user_callback_set_config = callback;
}
-static u16 build_config_descriptor(u8 index, u8 *buf, u16 len)
+static u16 build_config_descriptor(usbd_device *usbd_dev,
+ u8 index, u8 *buf, u16 len)
{
u8 *tmpbuf = buf;
- const struct usb_config_descriptor *cfg = &_usbd_device.config[index];
+ const struct usb_config_descriptor *cfg = &usbd_dev->config[index];
u16 count, total = 0, totallen = 0;
u16 i, j, k;
@@ -43,7 +46,7 @@ static u16 build_config_descriptor(u8 index, u8 *buf, u16 len)
for (i = 0; i < cfg->bNumInterfaces; i++) {
/* Interface Association Descriptor, if any */
if (cfg->interface[i].iface_assoc) {
- const struct usb_iface_assoc_descriptor *assoc =
+ const struct usb_iface_assoc_descriptor *assoc =
cfg->interface[i].iface_assoc;
memcpy(buf, assoc, count = MIN(len, assoc->bLength));
buf += count;
@@ -97,7 +100,8 @@ static int usb_descriptor_index(u16 wValue)
return wValue & 0xFF;
}
-static int usb_standard_get_descriptor(struct usb_setup_data *req,
+static int usb_standard_get_descriptor(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
int i, array_idx, descr_idx;
@@ -107,15 +111,15 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
switch (usb_descriptor_type(req->wValue)) {
case USB_DT_DEVICE:
- *buf = (u8 *) _usbd_device.desc;
- *len = MIN(*len, _usbd_device.desc->bLength);
+ *buf = (u8 *) usbd_dev->desc;
+ *len = MIN(*len, usbd_dev->desc->bLength);
return USBD_REQ_HANDLED;
case USB_DT_CONFIGURATION:
- *buf = _usbd_device.ctrl_buf;
- *len = build_config_descriptor(descr_idx, *buf, *len);
+ *buf = usbd_dev->ctrl_buf;
+ *len = build_config_descriptor(usbd_dev, descr_idx, *buf, *len);
return USBD_REQ_HANDLED;
case USB_DT_STRING:
- sd = (struct usb_string_descriptor *)_usbd_device.ctrl_buf;
+ sd = (struct usb_string_descriptor *)usbd_dev->ctrl_buf;
if (descr_idx == 0) {
/* Send sane Language ID descriptor... */
@@ -127,10 +131,10 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
} else {
array_idx = descr_idx - 1;
- if (!_usbd_device.strings)
+ if (!usbd_dev->strings)
return USBD_REQ_NOTSUPP; /* Device doesn't support strings. */
/* Check that string index is in range. */
- if (array_idx >= _usbd_device.num_strings)
+ if (array_idx >= usbd_dev->num_strings)
return USBD_REQ_NOTSUPP;
/* Strings with Language ID differnet from
@@ -139,14 +143,14 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
return USBD_REQ_NOTSUPP;
/* Ths string is returned as UTF16, hence the multiplication */
- sd->bLength = strlen(_usbd_device.strings[array_idx]) * 2 +
+ sd->bLength = strlen(usbd_dev->strings[array_idx]) * 2 +
sizeof(sd->bLength) + sizeof(sd->bDescriptorType);
*len = MIN(*len, sd->bLength);
for (i = 0; i < (*len / 2) - 1; i++)
sd->wData[i] =
- _usbd_device.strings[array_idx][i];
+ usbd_dev->strings[array_idx][i];
}
sd->bDescriptorType = USB_DT_STRING;
@@ -157,7 +161,8 @@ static int usb_standard_get_descriptor(struct usb_setup_data *req,
return USBD_REQ_NOTSUPP;
}
-static int usb_standard_set_address(struct usb_setup_data *req, u8 **buf,
+static int usb_standard_set_address(usbd_device *usbd_dev,
+ struct usb_setup_data *req, u8 **buf,
u16 *len)
{
(void)req;
@@ -168,19 +173,20 @@ static int usb_standard_set_address(struct usb_setup_data *req, u8 **buf,
if ((req->bmRequestType != 0) || (req->wValue >= 128))
return 0;
- _usbd_device.current_address = req->wValue;
+ usbd_dev->current_address = req->wValue;
/*
* Special workaround for STM32F10[57] that require the address
* to be set here. This is undocumented!
*/
- if (_usbd_device.driver == &stm32f107_usb_driver)
- _usbd_device.driver->set_address(req->wValue);
+ if ( usbd_dev->driver->set_address_before_status)
+ usbd_dev->driver->set_address(usbd_dev, req->wValue);
return 1;
}
-static int usb_standard_set_configuration(struct usb_setup_data *req,
+static int usb_standard_set_configuration(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
int i;
@@ -190,43 +196,46 @@ static int usb_standard_set_configuration(struct usb_setup_data *req,
(void)len;
/* Is this correct, or should we reset alternate settings. */
- if (req->wValue == _usbd_device.current_config)
+ if (req->wValue == usbd_dev->current_config)
return 1;
- _usbd_device.current_config = req->wValue;
+ usbd_dev->current_config = req->wValue;
/* Reset all endpoints. */
- _usbd_hw_endpoints_reset();
+ usbd_dev->driver->ep_reset(usbd_dev);
- if (_usbd_device.user_callback_set_config) {
+ if (usbd_dev->user_callback_set_config) {
/*
* Flush control callbacks. These will be reregistered
* by the user handler.
*/
for (i = 0; i < MAX_USER_CONTROL_CALLBACK; i++)
- _usbd_device.user_control_callback[i].cb = NULL;
+ usbd_dev->user_control_callback[i].cb = NULL;
- _usbd_device.user_callback_set_config(req->wValue);
+ usbd_dev->user_callback_set_config(usbd_dev, req->wValue);
}
return 1;
}
-static int usb_standard_get_configuration(struct usb_setup_data *req,
+static int usb_standard_get_configuration(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)req;
if (*len > 1)
*len = 1;
- (*buf)[0] = _usbd_device.current_config;
+ (*buf)[0] = usbd_dev->current_config;
return 1;
}
-static int usb_standard_set_interface(struct usb_setup_data *req,
+static int usb_standard_set_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
+ (void)usbd_dev;
(void)req;
(void)buf;
@@ -238,9 +247,11 @@ static int usb_standard_set_interface(struct usb_setup_data *req,
return 1;
}
-static int usb_standard_get_interface(struct usb_setup_data *req,
+static int usb_standard_get_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
+ (void)usbd_dev;
(void)req;
(void)buf;
@@ -251,9 +262,11 @@ static int usb_standard_get_interface(struct usb_setup_data *req,
return 1;
}
-static int usb_standard_device_get_status(struct usb_setup_data *req,
+static int usb_standard_device_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
+ (void)usbd_dev;
(void)req;
/* bit 0: self powered */
@@ -266,9 +279,11 @@ static int usb_standard_device_get_status(struct usb_setup_data *req,
return 1;
}
-static int usb_standard_interface_get_status(struct usb_setup_data *req,
+static int usb_standard_interface_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
+ (void)usbd_dev;
(void)req;
/* not defined */
@@ -280,45 +295,50 @@ static int usb_standard_interface_get_status(struct usb_setup_data *req,
return 1;
}
-static int usb_standard_endpoint_get_status(struct usb_setup_data *req,
+static int usb_standard_endpoint_get_status(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)req;
if (*len > 2)
*len = 2;
- (*buf)[0] = usbd_ep_stall_get(req->wIndex) ? 1 : 0;
+ (*buf)[0] = usbd_ep_stall_get(usbd_dev, req->wIndex) ? 1 : 0;
(*buf)[1] = 0;
return 1;
}
-static int usb_standard_endpoint_stall(struct usb_setup_data *req,
+static int usb_standard_endpoint_stall(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)buf;
(void)len;
- usbd_ep_stall_set(req->wIndex, 1);
+ usbd_ep_stall_set(usbd_dev, req->wIndex, 1);
return 1;
}
-static int usb_standard_endpoint_unstall(struct usb_setup_data *req,
+static int usb_standard_endpoint_unstall(usbd_device *usbd_dev,
+ struct usb_setup_data *req,
u8 **buf, u16 *len)
{
(void)buf;
(void)len;
- usbd_ep_stall_set(req->wIndex, 0);
+ usbd_ep_stall_set(usbd_dev, req->wIndex, 0);
return 1;
}
-int _usbd_standard_request_device(struct usb_setup_data *req, u8 **buf,
+int _usbd_standard_request_device(usbd_device *usbd_dev,
+ struct usb_setup_data *req, u8 **buf,
u16 *len)
{
- int (*command)(struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
+ int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req, u8
+ **buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -361,13 +381,15 @@ int _usbd_standard_request_device(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
- return command(req, buf, len);
+ return command(usbd_dev, req, buf, len);
}
-int _usbd_standard_request_interface(struct usb_setup_data *req, u8 **buf,
+int _usbd_standard_request_interface(usbd_device *usbd_dev,
+ struct usb_setup_data *req, u8 **buf,
u16 *len)
{
- int (*command)(struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
+ int (*command)(usbd_device *usbd_dev, struct usb_setup_data *req,
+ u8 **buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -388,13 +410,15 @@ int _usbd_standard_request_interface(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
- return command(req, buf, len);
+ return command(usbd_dev, req, buf, len);
}
-int _usbd_standard_request_endpoint(struct usb_setup_data *req, u8 **buf,
+int _usbd_standard_request_endpoint(usbd_device *usbd_dev,
+ struct usb_setup_data *req, u8 **buf,
u16 *len)
{
- int (*command) (struct usb_setup_data *req, u8 **buf, u16 *len) = NULL;
+ int (*command) (usbd_device *usbd_dev, struct usb_setup_data *req,
+ u8 **buf, u16 *len) = NULL;
switch (req->bRequest) {
case USB_REQ_CLEAR_FEATURE:
@@ -420,10 +444,11 @@ int _usbd_standard_request_endpoint(struct usb_setup_data *req, u8 **buf,
if (!command)
return 0;
- return command(req, buf, len);
+ return command(usbd_dev, req, buf, len);
}
-int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len)
+int _usbd_standard_request(usbd_device *usbd_dev,
+ struct usb_setup_data *req, u8 **buf, u16 *len)
{
/* FIXME: Have class/vendor requests as well. */
if ((req->bmRequestType & USB_REQ_TYPE_TYPE) != USB_REQ_TYPE_STANDARD)
@@ -431,11 +456,12 @@ int _usbd_standard_request(struct usb_setup_data *req, u8 **buf, u16 *len)
switch (req->bmRequestType & USB_REQ_TYPE_RECIPIENT) {
case USB_REQ_TYPE_DEVICE:
- return _usbd_standard_request_device(req, buf, len);
+ return _usbd_standard_request_device(usbd_dev, req, buf, len);
case USB_REQ_TYPE_INTERFACE:
- return _usbd_standard_request_interface(req, buf, len);
+ return _usbd_standard_request_interface(usbd_dev, req,
+ buf, len);
case USB_REQ_TYPE_ENDPOINT:
- return _usbd_standard_request_endpoint(req, buf, len);
+ return _usbd_standard_request_endpoint(usbd_dev, req, buf, len);
default:
return 0;
}