A include/generic.h => include/generic.h +10 -0
@@ 0,0 1,10 @@
+#ifndef GENERIC_H
+#define GENERIC_H
+
+typedef enum {
+ RES_OK,
+ RES_ERROR,
+ RES_WOULD_BLOCK
+} task_result_t;
+
+#endif // GENERIC_H
A include/queue.h => include/queue.h +25 -0
@@ 0,0 1,25 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef struct {
+ uint16_t curr_read_ptr;
+ uint16_t curr_write_ptr;
+
+ uint16_t element_size;
+
+ uint16_t length;
+ uint16_t space;
+
+ uint8_t elements[0];
+} queue_t;
+
+queue_t* queue_malloc(uint16_t element_size, uint16_t length);
+void queue_init(queue_t* queue, uint16_t element_size, uint16_t length);
+bool queue_enqueue(queue_t* queue, void* element);
+void* queue_dequeue(queue_t* queue);
+void* queue_peek(queue_t* queue);
+
+#endif // QUEUE_H
M include/usb.h => include/usb.h +28 -14
@@ 1,5 1,7 @@
#include <stdint.h>
#include <stm32h747xx.h>
+#include "generic.h"
+#include <stdbool.h>
#ifndef USB_H
#define USB_H
@@ 297,6 299,15 @@ void usb_generic_fill_fifo_words(USB_OTG_INEndpointTypeDef *endpoint,
uint32_t *sub_word_data,
uint8_t *sub_word_bytes);
+void usb_generic_fill_fifo(USB_OTG_INEndpointTypeDef *endpoint,
+ uint8_t *data,
+ uint16_t size,
+ volatile uint32_t *fifo_tx_target);
+
+task_result_t usb_generic_setup_in_endpoint(USB_OTG_INEndpointTypeDef *endpoint,
+ uint16_t size,
+ uint16_t max_packet_size);
+
/**
* @brief Send data through usb
* @details Configures the endpoint with given data count, fills fifos with those, and enabled the endpoint.
@@ 305,11 316,14 @@ void usb_generic_fill_fifo_words(USB_OTG_INEndpointTypeDef *endpoint,
* @param[in] size Number of bytes to send.
* @param[out] fifo_tx_target Address of the fifo. All data is written to this exact address, no offsets are made.
*/
-void usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
uint8_t *data,
uint16_t size,
volatile uint32_t *fifo_tx_target);
+bool usb_is_inendpoint_ready(USB_OTG_INEndpointTypeDef *endpoint);
+bool usb_check_fifo_space(USB_OTG_INEndpointTypeDef *endpoint, uint16_t size);
+
/**
* @brief Read data from the usb fifo.
* @details The data are read from the fifo pointer, without any offsets, and put into data array
@@ 317,9 331,9 @@ void usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
* @param[in] size Number of bytes to store in the array.
* @param[out] fifo_rx_source Address of the fifo. All data are read from this exact address, no offsets are made.
*/
-void usb_generic_read(uint8_t *data,
- uint16_t size,
- volatile uint32_t *fifo_rx_source);
+task_result_t usb_generic_read(uint8_t *data,
+ uint16_t size,
+ volatile uint32_t *fifo_rx_source);
/**
* @brief Sends descriptor
@@ 328,7 342,7 @@ void usb_generic_read(uint8_t *data,
* @param[out] descriptor The descriptor to send. The wlength has to be set.
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target);
@@ 340,7 354,7 @@ void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
* @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_device_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target);
@@ 352,7 366,7 @@ void usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
* @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef* endpoint,usb_device_qualifier_t *descriptor,
+task_result_t usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef* endpoint,usb_device_qualifier_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target);
@@ 363,7 377,7 @@ void usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef* endpoint,us
* @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_interface_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target);
@@ 375,10 389,10 @@ void usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
* @param[out] descriptor The descriptor to send. The wLength in header can be wrong, it will get replaced.
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
- usb_endpoint_descriptor_t *descriptor,
- uint16_t max_size,
- volatile uint32_t *fifo_tx_target);
+task_result_t usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+ usb_endpoint_descriptor_t *descriptor,
+ uint16_t max_size,
+ volatile uint32_t *fifo_tx_target);
/**
* @brief Sends string descriptor zero.
@@ 387,7 401,7 @@ void usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
* @param[out] string_descriptor The descriptor to send. The wLength NEEDS to be correct!
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_string_descriptor_zero(
+task_result_t usb_send_string_descriptor_zero(
USB_OTG_INEndpointTypeDef *endpoint,
usb_string_descriptor_zero_t *string_descriptor,
uint16_t max_size,
@@ 400,7 414,7 @@ void usb_send_string_descriptor_zero(
* @param[out] string_descriptor The descriptor to send. The wLength NEEDS to be correct!
* @param[out] fifo_tx_target Address of the fifo. All data are written to this exact address, no offsets are made.
*/
-void usb_send_unicode_string_descriptor(
+task_result_t usb_send_unicode_string_descriptor(
USB_OTG_INEndpointTypeDef *endpoint,
usb_unicode_string_descriptor_t *string_descriptor,
uint16_t max_size,
M include/usb_device.h => include/usb_device.h +15 -9
@@ 1,5 1,7 @@
#include <stm32h747xx.h>
#include "usb.h"
+#include "generic.h"
+#include "queue.h"
#ifndef USB_DEVICE_H
#define USB_DEVICE_H
@@ 70,7 72,7 @@ typedef struct {
* @param[in,out] device The usb device.
* @param[out] cmd The command that has been received, GET_DESCRIPTOR of type CONFIGURATION
*/
- void (*send_configuration)(usb_device_t* device, usb_setup_command_t* cmd);
+ task_result_t (*send_configuration)(usb_device_t* device, usb_setup_command_t* cmd);
/**
* @brief Set all endpoints except for endpoint 0 based on the configuration.
@@ 98,9 100,9 @@ typedef struct {
* @details Got a setup packet that cannot be handled by the device handler. That likely means a class specific setup command.
* @param[in,out] device The usb device.
* @param[out] cmd The command that was received.
- * @return Zero if packet was handled, other if there is an issue.
+ * @return A result of the callback, successfull or error.
*/
- uint8_t (*setup_packet_callback)(usb_device_t* device, usb_setup_command_t* cmd);
+ task_result_t (*setup_packet_callback)(usb_device_t* device, usb_setup_command_t* cmd);
/**
* @brief Received SET_CONFIGURATION, Endpoints set up.
@@ 186,6 188,15 @@ typedef enum {
SETUP_STAGE_AWAITING_ACK, /**< Handled a setup packet, sent data, waiting for acknowledge */
} usb_setup_command_stage_t;
+#define MAX_SETUP_PACKETS 3
+typedef struct {
+ queue_t* received_setup_commands;
+
+ usb_setup_command_stage_t stage; /**< Current stage status. */
+
+ uint8_t detected_setup_errors; /**< Number of errors when handling setup commands. This should be zero. */
+} usb_device_setup_t;
+
/**
* @struct usb_device_t
* Struct representing usb device.
@@ 204,12 215,7 @@ struct usb_device_t {
usb_device_state_t state; /**< The current status of the device. */
- // TODO: is this count field required? /**< Description */
- uint8_t received_setup_commands_count; /**< Number of setup commands received, max 3, wrapped. */
- uint8_t received_setup_commands_index; /**< Currently handled setup command index. */
- usb_setup_command_stage_t setup_stage; /**< Current stage status. */
- uint8_t detected_setup_errors; /**< Number of errors when handling setup commands. This should be zero. */
- usb_setup_command_t received_setup_commands[3]; /**< The setup commands reseived so far. */
+ usb_device_setup_t setup;
};
// has configuration etc
M include/usb_device_cdc.h => include/usb_device_cdc.h +2 -2
@@ 106,9 106,9 @@ usb_class_header_t* usb_device_cdc_init(usb_device_t *device,
char *vendor_name, char *product_name,
uint16_t serial_number, char* serial_name);
-void usb_device_cdc_send_configuration(usb_device_t* device, usb_setup_command_t* cmd);
+task_result_t usb_device_cdc_send_configuration(usb_device_t* device, usb_setup_command_t* cmd);
-uint8_t usb_device_cdc_setup_packet_callback(usb_device_t* device, usb_setup_command_t* cmd);
+task_result_t usb_device_cdc_setup_packet_callback(usb_device_t* device, usb_setup_command_t* cmd);
void usb_device_cdc_enumeration_done_callback(usb_device_t* device);
void usb_device_cdc_txfifo_empty_callback(usb_device_t* device, uint8_t endpoint);
void usb_device_cdc_rxfifo_empty_callback(usb_device_t* device, uint8_t endpoint);
A src/queue.c => src/queue.c +49 -0
@@ 0,0 1,49 @@
+#include <stdlib.h>
+#include "queue.h"
+
+queue_t *queue_malloc(uint16_t element_size, uint16_t length) {
+ return (queue_t*)malloc(sizeof(queue_t) + element_size * length);
+}
+
+void queue_init(queue_t* queue, uint16_t element_size, uint16_t length) {
+ queue->curr_write_ptr = 0;
+ queue->curr_read_ptr = 0;
+ queue->element_size = element_size;
+ queue->length = length;
+ queue->space = length;
+}
+
+bool queue_enqueue(queue_t *queue, void *element) {
+ if (queue->space == 0) {
+ return false;
+ }
+
+ for (uint16_t i = 0; i < queue->element_size; i++) {
+ queue->elements[queue->curr_write_ptr + i] = *(uint8_t*)(element + i);
+ }
+
+ queue->space--;
+ queue->curr_write_ptr += queue->element_size;
+ queue->curr_write_ptr %= queue->length * queue->element_size;
+ return true;
+}
+
+void *queue_dequeue(queue_t *queue) {
+ void* element = queue_peek(queue);
+
+ if (element != NULL) {
+ queue->curr_read_ptr += queue->element_size;
+ queue->curr_read_ptr %= queue->length * queue->element_size;
+ queue->space++;
+ }
+
+ return element;
+}
+
+void *queue_peek(queue_t *queue) {
+ if (queue->space == queue->length) {
+ return NULL;
+ }
+
+ return &queue->elements[queue->curr_read_ptr];
+}
M src/usb.c => src/usb.c +64 -80
@@ 77,21 77,32 @@ void usb_generic_fill_fifo(USB_OTG_INEndpointTypeDef *endpoint,
uint8_t *data,
uint16_t size,
volatile uint32_t *fifo_tx_target) {
- size = ((size + 3) / 4) * 4;
+ usb_data_t txData;
+ uint8_t subWordBytes = size % 4;
+ uint8_t wordCount = size / 4;
+
+ for (uint8_t i = 0; i < wordCount; i++) {
+ txData.word = *((uint32_t*)data);
+ *fifo_tx_target = txData.word;
+ data += 4;
+ }
- uint32_t subWordData;
- uint8_t subWordCount;
+ if (subWordBytes > 0) {
+ txData.word = 0;
+ for (int i = 0; i < subWordBytes; i++) {
+ txData.bytes[i] = *(data++);
+ size--;
+ }
- usb_generic_fill_fifo_words(endpoint, data, size, fifo_tx_target, &subWordData, &subWordCount);
+ *fifo_tx_target = txData.word;
+ }
}
-void usb_generic_setup_in_endpoint(USB_OTG_INEndpointTypeDef *endpoint, uint16_t size, uint16_t max_packet_size) {
+task_result_t usb_generic_setup_in_endpoint(USB_OTG_INEndpointTypeDef *endpoint, uint16_t size, uint16_t max_packet_size) {
uint16_t packet_count = (size + max_packet_size - 1) / max_packet_size;
- if (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
- // this is bad! Can't send the packet, this shouldn't get here, ever.
- while (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA);
- /* __nop(); */
+ if (usb_is_inendpoint_ready(endpoint)) {
+ return RES_WOULD_BLOCK;
}
if (size > 0) {
@@ 100,50 111,27 @@ void usb_generic_setup_in_endpoint(USB_OTG_INEndpointTypeDef *endpoint, uint16_t
endpoint->DIEPTSIZ = (1 << USB_OTG_DIEPTSIZ_PKTCNT_Pos);
}
endpoint->DIEPCTL = USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
+
+ return RES_OK;
}
-void usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_generic_send(USB_OTG_INEndpointTypeDef *endpoint,
uint8_t *data,
uint16_t size,
volatile uint32_t *fifo_tx_target) {
- if (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
- // this is bad! Can't send the packet, this shouldn't get here, ever.
- while (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA);
- /* __nop(); */
- }
-
- uint32_t fifo_size;
- while ((fifo_size = endpoint->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) < (size + 3) / 4) {
- /* __nop(); */
+ task_result_t result = usb_generic_setup_in_endpoint(endpoint, size, 64);
+ if (result != RES_OK) {
+ return result;
}
- // TODO: generic max packet size
- usb_generic_setup_in_endpoint(endpoint, size, 64);
-
- usb_data_t tx_data;
- uint8_t subWordBytes = size % 4;
- uint8_t wordCount = size / 4;
-
- for (uint8_t i = 0; i < wordCount; i++) {
- tx_data.word = *((uint32_t*)data);
- *fifo_tx_target = tx_data.word;
- data += 4;
- }
-
- // TODO: check where to put it... beginning, end...
- if (subWordBytes != 0) {
- tx_data.word = 0;
- for (uint8_t i = 0; i < subWordBytes; i++) {
- tx_data.bytes[i] = *(data + i);
- }
- *fifo_tx_target = tx_data.word;
- }
+ usb_generic_fill_fifo(endpoint, data, size, fifo_tx_target);
// After the fifo is filled...
endpoint->DIEPCTL = USB_OTG_DIEPCTL_CNAK;
+ return RES_OK;
}
-void usb_generic_read(uint8_t *data, uint16_t size, volatile uint32_t *fifo_rx_source) {
+task_result_t usb_generic_read(uint8_t *data, uint16_t size, volatile uint32_t *fifo_rx_source) {
usb_data_t rx_data;
uint8_t subWordBytes = size % 4;
uint8_t wordCount = size / 4;
@@ 161,9 149,11 @@ void usb_generic_read(uint8_t *data, uint16_t size, volatile uint32_t *fifo_rx_s
*(data + i) = rx_data.bytes[i];
}
}
+
+ return RES_OK;
}
-void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
@@ 172,81 162,60 @@ void usb_send_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
size = max_size;
}
- usb_generic_send(endpoint, (uint8_t*)descriptor, size, fifo_tx_target);
+ return usb_generic_send(endpoint, (uint8_t*)descriptor, size, fifo_tx_target);
}
-/* void usb_send_configuration_descriptor(USB_OTG_INEndpointTypeDef* endpoint, */
-/* usb_class_t *class, */
-/* volatile uint32_t *fifo_tx_target) { */
-/* class->configuration_descriptor.header.bDescriptorType = DESCRIPTOR_CONFIGURATION; */
-/* class->configuration_descriptor.header.bLength = sizeof(usb_configuration_descriptor_t); */
-/* class->interface_descriptor.header.bDescriptorType = DESCRIPTOR_INTERFACE; */
-/* class->interface_descriptor.header.bLength = sizeof(usb_interface_descriptor_t); */
-/* uint16_t total_length = */
-/* sizeof(usb_configuration_descriptor_t) + */
-/* sizeof(usb_interface_descriptor_t) + */
-/* class->interface_descriptor.bNumEndpoints * sizeof(usb_endpoint_descriptor_t); */
-
-/* for (int i = 0; i < class->interface_descriptor.bNumEndpoints; i++) { */
-/* class->endpoint_descriptors[i].header.bDescriptorType = DESCRIPTOR_ENDPOINT; */
-/* class->endpoint_descriptors[i].header.bLength = sizeof(usb_endpoint_descriptor_t); */
-/* } */
-
-/* // NOTE: since the memory layout is: configuration, interface, endpoints, */
-/* // we can send directly like this. */
-/* usb_generic_send(endpoint, */
-/* (uint8_t*)&class->configuration_descriptor, */
-/* total_length, fifo_tx_target); */
-/* } */
-
-void usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_device_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_device_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE;
descriptor->header.bLength = sizeof(usb_device_descriptor_t);
- usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
+ return usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
}
-void usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_device_qualifier_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_device_qualifier_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE_QUALIFIER;
descriptor->header.bLength = sizeof(usb_device_qualifier_t);
- usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
+ return usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
}
-void usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_interface_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_interface_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
descriptor->header.bDescriptorType = DESCRIPTOR_INTERFACE;
descriptor->header.bLength = sizeof(usb_interface_descriptor_t);
- usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
+ return usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
}
-void usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_endpoint_descriptor(USB_OTG_INEndpointTypeDef *endpoint,
usb_endpoint_descriptor_t *descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
descriptor->header.bDescriptorType = DESCRIPTOR_ENDPOINT;
descriptor->header.bLength = sizeof(usb_endpoint_descriptor_t);
- usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
+ return usb_send_descriptor(endpoint, &descriptor->header, max_size, fifo_tx_target);
}
-void usb_send_string_descriptor_zero(USB_OTG_INEndpointTypeDef *endpoint,
+task_result_t usb_send_string_descriptor_zero(USB_OTG_INEndpointTypeDef *endpoint,
usb_string_descriptor_zero_t *string_descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
usb_data_t data;
data.word = 0;
- usb_generic_setup_in_endpoint(endpoint, string_descriptor->header.bLength, 64);
+ task_result_t result = usb_generic_setup_in_endpoint(endpoint, string_descriptor->header.bLength, 64);
+ if (result != RES_OK) {
+ return result;
+ }
data.bytes[0] = string_descriptor->header.bLength;
data.bytes[1] = string_descriptor->header.bDescriptorType;
if (string_descriptor->header.bLength == 2) {
usb_generic_fill_fifo(endpoint, &data.bytes[0], 2, fifo_tx_target);
- return;
+ return RES_OK;
}
data.halfwords[1] = string_descriptor->wLANGID[0];
@@ 258,14 227,20 @@ void usb_send_string_descriptor_zero(USB_OTG_INEndpointTypeDef *endpoint,
}
endpoint->DIEPCTL = USB_OTG_DIEPCTL_CNAK;
+
+ return RES_OK;
}
-void usb_send_unicode_string_descriptor(
+
+task_result_t usb_send_unicode_string_descriptor(
USB_OTG_INEndpointTypeDef *endpoint,
usb_unicode_string_descriptor_t *string_descriptor,
uint16_t max_size,
volatile uint32_t *fifo_tx_target) {
- usb_generic_setup_in_endpoint(endpoint, string_descriptor->header.bLength, 64);
+ task_result_t result = usb_generic_setup_in_endpoint(endpoint, string_descriptor->header.bLength, 64);
+ if (result != RES_OK) {
+ return result;
+ }
usb_data_t data = { .word = 0 };
@@ 285,4 260,13 @@ void usb_send_unicode_string_descriptor(
}
endpoint->DIEPCTL = USB_OTG_DIEPCTL_CNAK;
+ return RES_OK;
+}
+
+bool usb_is_inendpoint_ready(USB_OTG_INEndpointTypeDef *endpoint) {
+ return (endpoint->DIEPCTL & USB_OTG_DIEPCTL_EPENA) != 0;
+}
+
+bool usb_check_fifo_space(USB_OTG_INEndpointTypeDef *endpoint, uint16_t size) {
+ return ((endpoint->DTXFSTS & (USB_OTG_DTXFSTS_INEPTFSAV_Msk)) >> USB_OTG_DTXFSTS_INEPTFSAV_Pos) >= (size + 3) / 4;
}
M src/usb_device.c => src/usb_device.c +134 -94
@@ 20,14 20,15 @@ void* usb_device_init(usb_device_slot_t slot, usb_class_vtable_t *class,
void* peripheral_address = usb_periph_addresses[slot];
device->state = INIT;
- device->detected_setup_errors = 0;
+ device->setup.detected_setup_errors = 0;
device->core = peripheral_address + USB_OTG_GLOBAL_BASE;
device->device = peripheral_address + USB_OTG_DEVICE_BASE;
device->out = peripheral_address + USB_OTG_OUT_ENDPOINT_BASE;
device->in = peripheral_address + USB_OTG_IN_ENDPOINT_BASE;
device->fifos = (usb_fifo_t*)(((uint8_t*)device->core) + USB_OTG_FIFO_BASE);
- device->received_setup_commands_count = 0;
- device->received_setup_commands_index = 0;
+
+ device->setup.received_setup_commands = queue_malloc(sizeof(usb_setup_command_t), MAX_SETUP_PACKETS);
+ queue_init(device->setup.received_setup_commands, sizeof(usb_setup_command_t), MAX_SETUP_PACKETS);
device->vt = *class;
device->class = device->
@@ 152,10 153,8 @@ typedef struct {
uint8_t status_phase_start;
} packet_info_t;
-void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
- if (device->setup_stage != SETUP_STAGE_RCVD_SETUP_PACKET) {
- device->detected_setup_errors++;
- }
+task_result_t usb_handle_setup_command(usb_device_t *device, usb_setup_command_t* cmd) {
+ task_result_t result = RES_ERROR;
switch (cmd->bRequest) {
case USB_SETUP_GET_STATUS: {
@@ 189,9 188,11 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
break;
}
- usb_generic_send(device->in, packet, size,
- &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_generic_send(device->in, packet, size,
+ &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_RESPONSE;
+ }
}
break;
case USB_SETUP_GET_DESCRIPTOR: {
@@ 200,44 201,40 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
switch (descriptor_type) {
case DESCRIPTOR_DEVICE:
- usb_send_device_descriptor(device->in, &device->class->device_descriptor, cmd->wLength, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_send_device_descriptor(device->in, &device->class->device_descriptor, cmd->wLength, &device->fifos[0].data[0]);
break;
case DESCRIPTOR_CONFIGURATION:
- device->vt.send_configuration(device, cmd);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = device->vt.send_configuration(device, cmd);
break;
case DESCRIPTOR_STRING: {
if (descriptor_index == 0) {
- usb_send_string_descriptor_zero(device->in, &device->class->string_descriptor_zero, cmd->wLength, &device->fifos[0].data[0]);
+ result = usb_send_string_descriptor_zero(device->in, &device->class->string_descriptor_zero, cmd->wLength, &device->fifos[0].data[0]);
} else {
uint8_t index = descriptor_index - 1;
// NOTE: the user could potentially read different memory part!!
// This has to be fixed, the length has to be stored somewhere.
- usb_send_unicode_string_descriptor(device->in, &device->class->string_descriptors[index], cmd->wLength, &device->fifos[0].data[0]);
+ result = usb_send_unicode_string_descriptor(device->in, &device->class->string_descriptors[index], cmd->wLength, &device->fifos[0].data[0]);
}
}
break;
case DESCRIPTOR_INTERFACE:
- usb_send_interface_descriptor(device->in, &device->class->interfaces[descriptor_index].interface_descriptor, cmd->wLength, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_send_interface_descriptor(device->in, &device->class->interfaces[descriptor_index].interface_descriptor, cmd->wLength, &device->fifos[0].data[0]);
break;
case DESCRIPTOR_ENDPOINT:
// TODO: how to match the interface to the descriptor index?
- usb_send_endpoint_descriptor(device->in, &device->class->interfaces[0].endpoint_descriptors[descriptor_index], cmd->wLength, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_send_endpoint_descriptor(device->in, &device->class->interfaces[0].endpoint_descriptors[descriptor_index], cmd->wLength, &device->fifos[0].data[0]);
break;
case DESCRIPTOR_DEVICE_QUALIFIER:
- usb_send_device_qualifier_descriptor(device->in, &device->class->device_qualifier, cmd->wLength, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_send_device_qualifier_descriptor(device->in, &device->class->device_qualifier, cmd->wLength, &device->fifos[0].data[0]);
break;
case DESCRIPTOR_OTHER_SPEED_CONFIGURATION:
case DESCRIPTOR_INTERFACE_POWER:
reg_set_bits(&device->out[0].DOEPCTL, USB_OTG_DOEPCTL_STALL);
- device->setup_stage = SETUP_STAGE_NONE;
break;
}
- // TODO
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_RESPONSE;
+ }
}
break;
case USB_SETUP_GET_CONFIGURATION: {
@@ 245,16 242,20 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
if (device->state != ENUMERATED) {
value = 0;
}
- usb_generic_send(device->in, &value, sizeof(value), &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_generic_send(device->in, &value, sizeof(value), &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_RESPONSE;
+ }
}
break;
case USB_SETUP_GET_INTERFACE: {
- usb_generic_send(device->in,
- &device->class->interfaces[cmd->wIndex].interface_descriptor.bAlternateSetting,
- sizeof(uint8_t),
- &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_RESPONSE;
+ result = usb_generic_send(device->in,
+ &device->class->interfaces[cmd->wIndex].interface_descriptor.bAlternateSetting,
+ sizeof(uint8_t),
+ &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_RESPONSE;
+ }
}
break;
case USB_SETUP_SET_ADDRESS:
@@ 262,9 263,11 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
cmd->wValue,
USB_OTG_DCFG_DAD_Pos,
0x7F);
- usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_ACK;
- device->state = SET_ADDRESS_RCVD;
+ result = usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_ACK;
+ device->state = SET_ADDRESS_RCVD;
+ }
break;
case USB_SETUP_SET_CONFIGURATION: {
if (cmd->wValue == 0) {
@@ 275,7 278,7 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
} else if (cmd->wValue == device->class->configuration_descriptor.bConfigurationValue) {
device->state = ENUMERATED;
usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_ACK;
+ device->setup.stage = SETUP_STAGE_SENDING_ACK;
// TODO setup endpoints
} else {
@@ 297,8 300,10 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
break;
}
- usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_ACK;
+ result = usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_ACK;
+ }
break;
case USB_SETUP_SET_FEATURE:
switch (cmd->wValue) {
@@ 314,8 319,10 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
break;
}
- usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
- device->setup_stage = SETUP_STAGE_SENDING_ACK;
+ result = usb_generic_send(device->in, NULL, 0, &device->fifos[0].data[0]);
+ if (result == RES_OK) {
+ device->setup.stage = SETUP_STAGE_SENDING_ACK;
+ }
break;
case USB_SETUP_SET_DESCRIPTOR:
case USB_SETUP_SET_INTERFACE:
@@ 326,13 333,77 @@ void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) {
case RESERVED1:
case RESERVED2:
default:
- device->vt.setup_packet_callback(device, cmd);
+ return device->vt.setup_packet_callback(device, cmd);
break;
}
- device->out[0].DOEPCTL = USB_OTG_DOEPCTL_CNAK;
+ return result;
}
+typedef enum {
+ USB_UNKNOWN,
+ USB_GOT_SETUP,
+ USB_PROCESS_SETUP,
+ USB_GOT_ACK,
+ USB_GOT_RESPONSE,
+ USB_SENT_RESPONSE,
+} usb_event_t;
+
+task_result_t usb_handle_setup(usb_device_t *device, usb_event_t event) {
+ switch (device->setup.stage) {
+ case SETUP_STAGE_RCVD_SETUP_PACKET: {
+ if (event == USB_GOT_SETUP) {
+ return RES_OK;
+ }
+
+ usb_setup_command_t* command = queue_peek(device->setup.received_setup_commands);
+ task_result_t result = usb_handle_setup_command(device, command);
+ if (result == RES_OK) {
+ queue_dequeue(device->setup.received_setup_commands);
+ uint8_t setup_packets_count = reg_read_bits_pos(&device->out[0].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3);
+ if (setup_packets_count == 0) {
+ reg_write_bits_pos(&device->out[0].DOEPTSIZ, 3, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3);
+ }
+ }
+ return result;
+ }
+ break;
+ case SETUP_STAGE_NONE:
+ if (queue_peek(device->setup.received_setup_commands) != NULL) {
+ device->setup.stage = SETUP_STAGE_RCVD_SETUP_PACKET;
+
+ if (event == USB_PROCESS_SETUP) {
+ usb_handle_setup(device, event);
+ }
+ }
+ break;
+ case SETUP_STAGE_AWAITING_RESPONSE:
+ // NOTE: Currently not really supported.
+ return RES_ERROR;
+ break;
+ case SETUP_STAGE_SENDING_RESPONSE:
+ if (event == USB_SENT_RESPONSE) {
+ device->setup.stage = SETUP_STAGE_AWAITING_ACK;
+ }
+ break;
+ case SETUP_STAGE_SENDING_ACK:
+ if (event == USB_SENT_RESPONSE) {
+ device->setup.stage = SETUP_STAGE_NONE;
+ return usb_handle_setup(device, event);
+ }
+ break;
+ case SETUP_STAGE_AWAITING_ACK:
+ if (event == USB_GOT_ACK) {
+ device->setup.stage = SETUP_STAGE_NONE;
+ return usb_handle_setup(device, event);
+ }
+ break;
+ }
+
+ return RES_OK;
+}
+
+
void usb_handle_rxflvl_control_int(usb_device_t *device,
packet_info_t *packet_info) {
uint32_t dummy;
@@ 342,44 413,27 @@ void usb_handle_rxflvl_control_int(usb_device_t *device,
if (packet_info->packet_status == PACKET_SETUP_TRANSACTION_COMPLETED) {
// Nothing do to.
dummy = *fifo;
-
- if (device->setup_stage != SETUP_STAGE_RCVD_SETUP_PACKET) {
- // something went wrong. Let's continue, but this isn't looking good.
- device->detected_setup_errors++;
- }
-
- device->received_setup_commands_index %= 3;
- uint8_t setup_packets_count = reg_read_bits_pos(&device->out[0].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3);
- usb_setup_command_t* command = &device->received_setup_commands[device->received_setup_commands_index++];
- usb_handle_setup(device, command);
-
- if (setup_packets_count == 0) {
- reg_write_bits_pos(&device->out[0].DOEPTSIZ, 3, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3);
- }
+ usb_handle_setup(device, USB_PROCESS_SETUP);
} else if (packet_info->packet_status == PACKET_SETUP_DATA_PACKET_RECEIVED) {
// SAVE data
- uint8_t setup_packets_count = reg_read_bits_pos(&device->out[0].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3);
- usb_setup_command_t* command = &device
- ->received_setup_commands[device->received_setup_commands_count++];
- device->received_setup_commands_count %= 3;
-
- usb_generic_read(command, 8, fifo);
+ usb_setup_command_t command;
+ usb_generic_read((uint8_t*)&command, 8, fifo);
+ usb_handle_setup(device, USB_GOT_SETUP);
- device->setup_stage = SETUP_STAGE_RCVD_SETUP_PACKET;
-
- /* if (setup_packets_count == 0) { */
- /* reg_write_bits_pos(&device->out[0].DOEPTSIZ, 3, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); */
- /* } */
+ if (!queue_enqueue(device->setup.received_setup_commands, &command)) {
+ // Got a problem, setup command lost!
+ device->setup.detected_setup_errors++;
+ }
dummy = *fifo; // the last that will trigger another interrupt
} else if (packet_info->byte_count != 0) {
usb_generic_read(data, packet_info->byte_count, fifo);
- if (device->setup_stage == SETUP_STAGE_AWAITING_ACK) {
+ if (device->setup.stage == SETUP_STAGE_AWAITING_ACK) {
// This is an error, since there is data in status phase...
// TODO: How to handle?
- device->detected_setup_errors++;
- device->setup_stage = SETUP_STAGE_NONE;
+ device->setup.detected_setup_errors++;
+ usb_handle_setup(device, USB_GOT_RESPONSE);
}
}
}
@@ 494,11 548,8 @@ void usb_handle_endpoint_in_int(usb_device_t* device) {
}
if (ep_id == 0) {
- if (device->setup_stage == SETUP_STAGE_SENDING_RESPONSE) {
- device->setup_stage = SETUP_STAGE_AWAITING_ACK;
- } else if (device->setup_stage == SETUP_STAGE_SENDING_ACK) {
- device->setup_stage = SETUP_STAGE_NONE;
- }
+ usb_handle_setup(device, USB_GOT_RESPONSE);
+ usb_handle_setup(device, USB_PROCESS_SETUP);
}
reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_XFRC);
}
@@ 566,20 617,8 @@ void usb_handle_endpoint_out_int(usb_device_t* device) {
reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_OTEPDIS);
}
if (interrupt_reg & USB_OTG_DOEPINT_STUP) {
+ usb_handle_setup(device, USB_PROCESS_SETUP);
reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_STUP);
- /* if (device->setup_stage != SETUP_STAGE_RCVD_SETUP_PACKET) { */
- /* // something went wrong. Let's continue, but this isn't looking good. */
- /* device->detected_setup_errors++; */
- /* } */
-
- /* device->received_setup_commands_index %= 3; */
- /* uint8_t setup_packets_count = reg_read_bits_pos(&device->out[ep_id].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); */
- /* usb_setup_command_t* command = &device->received_setup_commands[device->received_setup_commands_index++]; */
- /* usb_handle_setup(device, command); */
-
- /* if (setup_packets_count == 0) { */
- /* reg_write_bits_pos(&device->out[0].DOEPTSIZ, 3, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); */
- /* } */
}
if (interrupt_reg & USB_OTG_DOEPINT_AHBERR) {
// NOTE This shoudln't be reached since DMA is not used
@@ 591,15 630,15 @@ void usb_handle_endpoint_out_int(usb_device_t* device) {
reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_EPDISD);
}
if (interrupt_reg & USB_OTG_DOEPINT_XFRC) {
- // TODO: handle data? - callback to device data handle?
+ device->out[0].DOEPCTL = USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA;
reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_XFRC);
- if (ep_id == 0 && device->setup_stage == SETUP_STAGE_AWAITING_ACK) {
- device->setup_stage = SETUP_STAGE_NONE;
- }
+ // TODO: handle data? - callback to device data handle?
- device->out[0].DOEPCTL = USB_OTG_DOEPCTL_CNAK | USB_OTG_DOEPCTL_EPENA;
- // Transfer has been completed
+ if (ep_id == 0) {
+ usb_handle_setup(device, USB_GOT_ACK);
+ usb_handle_setup(device, USB_PROCESS_SETUP);
+ }
}
}
@@ 696,9 735,10 @@ void otg_hs_handler(void) {
// Start of frame
if (device->core->GINTSTS & USB_OTG_GINTSTS_SOF) {
- // Nothing to do?
device->core->GINTSTS = USB_OTG_GINTSTS_SOF;
handled = 1;
+
+ usb_handle_setup(device, USB_PROCESS_SETUP);
return;
}
M src/usb_device_cdc.c => src/usb_device_cdc.c +11 -15
@@ 248,19 248,14 @@ uint16_t get_size(uint16_t size_to_send, uint16_t* remaining_size) {
return size;
}
-void usb_device_cdc_send_configuration(usb_device_t *device,
- usb_setup_command_t *cmd) {
+task_result_t usb_device_cdc_send_configuration(usb_device_t *device,
+ usb_setup_command_t *cmd) {
usb_device_cdc_t* dev = (usb_device_cdc_t*)device->class;
USB_OTG_INEndpointTypeDef* enp0 = &device->in[0];
volatile uint32_t* enp0fifo = &device->fifos[0].data[0];
uint32_t sub_word_data;
uint8_t sub_word_count = 0;
- if (enp0->DIEPCTL & USB_OTG_DIEPCTL_EPENA) {
- // this is bad! Can't send the packet, this shouldn't get here, ever.
- while (enp0->DIEPCTL & USB_OTG_DIEPCTL_EPENA);
- }
-
// first configure the size
uint16_t size =
sizeof(usb_configuration_descriptor_t) +
@@ 285,11 280,11 @@ void usb_device_cdc_send_configuration(usb_device_t *device,
// TODO: what if there is not enough space for this?
// I mean there should be... but that case should probably be handled to,
// it depends a lot on how many functions and interfaces we do have...
- uint16_t packet_count = (size + 63) / 64;
- // configure size
- enp0->DIEPTSIZ = (1 << USB_OTG_DIEPTSIZ_MULCNT_Pos) | (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | (size << USB_OTG_DIEPTSIZ_XFRSIZ_Pos);
- // enable endpoint
- enp0->DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA;
+ task_result_t result = usb_generic_setup_in_endpoint(enp0, size, 64);
+
+ if (result != RES_OK) {
+ return result;
+ }
// fill fifo with all configuration
usb_generic_fill_fifo_words(enp0,
@@ 334,12 329,13 @@ void usb_device_cdc_send_configuration(usb_device_t *device,
// After the fifo is filled...
enp0->DIEPCTL = USB_OTG_DIEPCTL_CNAK;
+ return result;
}
-uint8_t usb_device_cdc_setup_packet_callback(usb_device_t *device,
- usb_setup_command_t *cmd) {
+task_result_t usb_device_cdc_setup_packet_callback(usb_device_t *device,
+ usb_setup_command_t *cmd) {
// TODO - is there something to do? maybe just the multiplexed commands?
- return 1;
+ return RES_OK;
}
void usb_device_cdc_enumeration_done_callback(usb_device_t *device) {
// TODO start the application somehow