summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmir Hammad <amir.hammad@hotmail.com>2016-09-05 21:21:02 +0200
committerAmir Hammad <amir.hammad@hotmail.com>2016-09-11 13:31:47 +0200
commitc4e6f3b55b03b29b9f6ac269c4ce591944cb8cab (patch)
treef15590b8ec37a6246b7cc236e02546a0c5c11229
parent6d9ee8e9a63208e83adddfe1eeccf7461297dc1b (diff)
downloadsecure-hid-c4e6f3b55b03b29b9f6ac269c4ce591944cb8cab.tar.gz
secure-hid-c4e6f3b55b03b29b9f6ac269c4ce591944cb8cab.tar.bz2
secure-hid-c4e6f3b55b03b29b9f6ac269c4ce591944cb8cab.zip
core: add helper state machine for control read/write
Signed-off-by: Amir Hammad <amir.hammad@hotmail.com>
-rw-r--r--include/driver/usbh_device_driver.h51
-rw-r--r--src/usbh_core.c95
2 files changed, 122 insertions, 24 deletions
diff --git a/include/driver/usbh_device_driver.h b/include/driver/usbh_device_driver.h
index c70715b..f32457b 100644
--- a/include/driver/usbh_device_driver.h
+++ b/include/driver/usbh_device_driver.h
@@ -26,6 +26,7 @@
#include "usbh_config.h"
#include "usbh_core.h"
+#include <libopencm3/usb/usbstd.h>
#include <stdint.h>
BEGIN_DECLS
@@ -64,8 +65,6 @@ enum USBH_CONTROL_TYPE {
enum USBH_ENUM_STATE {
USBH_ENUM_STATE_SET_ADDRESS,
USBH_ENUM_STATE_FIRST = USBH_ENUM_STATE_SET_ADDRESS,
- USBH_ENUM_STATE_SET_ADDRESS_EMPTY_READ,
- USBH_ENUM_STATE_SET_ADDRESS_EMPTY_READ_COMPLETE,
USBH_ENUM_STATE_DEVICE_DT_READ_SETUP,
USBH_ENUM_STATE_DEVICE_DT_READ,
USBH_ENUM_STATE_DEVICE_DT_READ_COMPLETE,
@@ -81,6 +80,38 @@ enum USBH_ENUM_STATE {
USBH_ENUM_STATE_FIND_DRIVER,
};
+enum USBH_CONTROL_STATE {
+ USBH_CONTROL_STATE_NONE,
+ USBH_CONTROL_STATE_SETUP,
+ USBH_CONTROL_STATE_DATA,
+ USBH_CONTROL_STATE_STATUS,
+};
+
+typedef struct _usbh_device usbh_device_t;
+
+struct _usbh_packet_callback_data {
+ /// status - it is used for reporting of the errors
+ enum USBH_PACKET_CALLBACK_STATUS status;
+
+ /// count of bytes that has been actually transferred
+ uint32_t transferred_length;
+};
+typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
+
+typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
+
+struct _usbh_control {
+ enum USBH_CONTROL_STATE state;
+ usbh_packet_callback_t callback;
+ union {
+ const void *out;
+ void *in;
+ } data;
+ uint16_t data_length;
+ struct usb_setup_data setup_data;
+};
+typedef struct _usbh_control usbh_control_t;
+
/**
* @brief The _usbh_device struct
*
@@ -98,6 +129,7 @@ struct _usbh_device {
/// state used for enumeration purposes
enum USBH_ENUM_STATE state;
+ usbh_control_t control;
/// toggle bit
uint8_t toggle0;
@@ -119,17 +151,6 @@ struct _usbh_device {
};
typedef struct _usbh_device usbh_device_t;
-struct _usbh_packet_callback_data {
- /// status - it is used for reporting of the errors
- enum USBH_PACKET_CALLBACK_STATUS status;
-
- /// count of bytes that has been actually transferred
- uint32_t transferred_length;
-};
-typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
-
-typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
-
struct _usbh_packet {
/// pointer to data
union {
@@ -239,9 +260,7 @@ void usbh_read(usbh_device_t *dev, usbh_packet_t *packet);
void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet);
/* Helper functions used by device drivers */
-void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
-void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
-void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
+void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data);
END_DECLS
diff --git a/src/usbh_core.c b/src/usbh_core.c
index 7071281..4e0f112 100644
--- a/src/usbh_core.c
+++ b/src/usbh_core.c
@@ -28,6 +28,8 @@
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/usb/usbstd.h>
+#include <stddef.h>
+
static struct {
bool enumeration_run;
const usbh_low_level_driver_t * const *lld_drivers;
@@ -204,11 +206,7 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const
}
-/*
- * NEW ENUMERATE
- *
- */
-void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
+static void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
{
usbh_packet_t packet;
@@ -228,7 +226,7 @@ void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_pa
LOG_PRINTF("WR-setup@device...%d \n", dev->address);
}
-void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
+static void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
{
usbh_packet_t packet;
@@ -248,7 +246,7 @@ void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_pac
LOG_PRINTF("WR-data@device...%d \n", dev->address);
}
-void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
+static void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
{
usbh_packet_t packet;
@@ -268,6 +266,85 @@ void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback
}
+static void control_state_machine(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
+{
+ switch (dev->control.state) {
+ case USBH_CONTROL_STATE_SETUP:
+ if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
+ dev->control.state = USBH_CONTROL_STATE_NONE;
+ // Unable to deliver setup control packet - this is a fatal error
+ usbh_packet_callback_data_t ret_data;
+ ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ ret_data.transferred_length = 0;
+ dev->control.callback(dev, ret_data);
+ break;
+ }
+ if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
+ dev->control.state = USBH_CONTROL_STATE_DATA;
+ device_xfer_control_read(dev->control.data.in, dev->control.data_length, control_state_machine, dev);
+ } else {
+ if (dev->control.data_length == 0) {
+ dev->control.state = USBH_CONTROL_STATE_STATUS;
+ device_xfer_control_read(0, 0, control_state_machine, dev);
+ } else {
+ dev->control.state = USBH_CONTROL_STATE_DATA;
+ device_xfer_control_write_data(dev->control.data.out, dev->control.data_length, control_state_machine, dev);
+ }
+ }
+ break;
+
+ case USBH_CONTROL_STATE_DATA:
+ if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
+ dev->control.state = USBH_CONTROL_STATE_NONE;
+ dev->control.callback(dev, cb_data);
+ } else {
+ if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
+ dev->control.state = USBH_CONTROL_STATE_NONE;
+ // Unable to deliver data control packet - this is a fatal error
+ usbh_packet_callback_data_t ret_data;
+ ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ ret_data.transferred_length = 0;
+ dev->control.callback(dev, ret_data);
+ break;
+ }
+
+ if (dev->control.data_length == 0) {
+ // we should be in status state when the length of data is zero
+ LOG_PRINTF("Control logic error\n");
+ dev->control.state = USBH_CONTROL_STATE_NONE;
+ dev->control.callback(dev, cb_data);
+ } else {
+ dev->control.state = USBH_CONTROL_STATE_STATUS;
+ device_xfer_control_read(0, 0, control_state_machine, dev);
+ }
+ }
+ break;
+
+ case USBH_CONTROL_STATE_STATUS:
+ dev->control.state = USBH_CONTROL_STATE_NONE;
+ dev->control.callback(dev, cb_data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data)
+{
+ if (dev->control.state != USBH_CONTROL_STATE_NONE) {
+ LOG_PRINTF("ERROR: Use of control state machine while not idle\n");
+ return;
+ }
+
+ dev->control.state = USBH_CONTROL_STATE_SETUP;
+ dev->control.callback = callback;
+ dev->control.data.out = data;
+ dev->control.data_length = setup_data->wLength;
+ dev->control.setup_data = *setup_data;
+ device_xfer_control_write_setup(&dev->control.setup_data, sizeof(dev->control.setup_data), control_state_machine, dev);
+}
+
bool usbh_enum_available(void)
{
@@ -675,7 +752,7 @@ void usbh_poll(uint32_t time_curr_us)
{
uint32_t k = 0;
while (usbh_data.lld_drivers[k]) {
- usbh_device_t * usbh_device =
+ usbh_device_t *usbh_device =
((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device;
usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data;
@@ -689,12 +766,14 @@ void usbh_poll(uint32_t time_curr_us)
usbh_device[0].lld = usbh_data.lld_drivers[k];
usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data);
usbh_device[0].address = 1;
+ usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
device_enumeration_start(&usbh_device[0]);
break;
case USBH_POLL_STATUS_DEVICE_DISCONNECTED:
{
+ usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
uint32_t i;
for (i = 0; i < USBH_MAX_DEVICES; i++) {
device_remove(&usbh_device[i]);