From 6051b84001bf571e5e76fd28df36bd87b86ec36a Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 26 Oct 2024 17:48:36 +0200 Subject: [PATCH] feat: implement most of enumeration --- include/usb.h | 78 +++++++--- include/usb_device.h | 10 +- src/usb.c | 29 ++-- src/usb_device.c | 349 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 418 insertions(+), 48 deletions(-) diff --git a/include/usb.h b/include/usb.h index 13c434e..4583fb5 100644 --- a/include/usb.h +++ b/include/usb.h @@ -3,6 +3,25 @@ #ifndef USB_H #define USB_H +#pragma GCC diagnostic error "-Wpadded" +typedef struct { + uint8_t self_powered : 1; + uint8_t remote_wakeup : 1; + uint16_t reserved_zeros : 14; +} usb_device_status_t; +_Static_assert(sizeof(usb_device_status_t) == 2, "Size check"); + +typedef struct { + uint8_t halt : 1; + uint16_t reserved_zeros : 15; +} usb_endpoint_status_t; +_Static_assert(sizeof(usb_endpoint_status_t) == 2, "Size check"); + +typedef struct { + uint16_t reserved; +} usb_interface_status_t; +_Static_assert(sizeof(usb_interface_status_t) == 2, "Size check"); + typedef enum { USB_SETUP_HOST_TO_DEVICE, USB_SETUP_DEVICE_TO_HOST, @@ -22,13 +41,13 @@ typedef enum { USB_SETUP_OTHER, } usb_setup_command_recipient_t; -typedef struct { +typedef struct __attribute__((packed)) { uint8_t recipient : 5; usb_setup_command_type_t type : 2; usb_setup_command_direction_t direction : 1; } usb_setup_command_request_type_t; -typedef enum { +typedef enum __attribute__((packed)) { USB_SETUP_GET_STATUS = 0, USB_SETUP_CLEAR_FEATURE = 1, RESERVED1 = 2, @@ -44,18 +63,23 @@ typedef enum { USB_SETUP_SYNCH_FRAME = 12, } usb_setup_request_t; +typedef enum { + USB_FEATURE_ENDPOINT_HALT = 0, + USB_FEATURE_DEVICE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +} usb_setup_feature_selector_t; + typedef enum { DESCRIPTOR_DEVICE = 1, - DESCRIPTOR_CONFIGURATION = 1, - DESCRIPTOR_STRING = 2, - DESCRIPTOR_INTERFACE = 3, - DESCRIPTOR_ENDPOINT = 4, - DESCRIPTOR_DEVICE_QUALIFIER = 5, - DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 6, - DESCRIPTOR_INTERFACE_POWER = 7, + DESCRIPTOR_CONFIGURATION = 2, + DESCRIPTOR_STRING = 3, + DESCRIPTOR_INTERFACE = 4, + DESCRIPTOR_ENDPOINT = 5, + DESCRIPTOR_DEVICE_QUALIFIER = 6, + DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + DESCRIPTOR_INTERFACE_POWER = 8, } usb_descriptor_type_t; -#pragma GCC diagnostic error "-Wpadded" typedef struct __attribute__((packed)) { usb_setup_command_request_type_t bmRequestType; usb_setup_request_t bRequest; @@ -191,17 +215,31 @@ typedef struct { uint8_t *bString; } usb_unicode_string_descriptor_t; - -void usb_generic_send(uint8_t* data, uint16_t size, uint32_t *fifo_tx_target); -void usb_generic_read(uint8_t *data, uint16_t size, uint32_t *fifo_rx_source); - -void usb_send_descriptor(usb_descriptor_t* descriptor, uint32_t *fifo_tx_target); +void usb_generic_send(uint8_t *data, uint16_t size, + volatile uint32_t *fifo_tx_target); +void usb_generic_read(uint8_t *data, uint16_t size, + volatile uint32_t *fifo_rx_source); +void usb_send_descriptor(usb_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_device_descriptor(usb_device_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_device_qualifier_descriptor(usb_device_qualifier_t *descriptor, + volatile uint32_t *fifo_tx_target); /* void usb_send_ack(uint32_t* fifo_tx_target); */ -void usb_send_configuration_descriptor(usb_configuration_descriptor_t* descriptor, uint32_t *fifo_tx_target); -void usb_send_interface_descriptor(usb_interface_descriptor_t* descriptor, uint32_t *fifo_tx_target); -void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t* descriptor, uint32_t *fifo_tx_target); -void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t* string_descriptor, uint32_t *fifo_tx_target); -void usb_send_unicode_string_descriptor(usb_unicode_string_descriptor_t* string_descriptor, uint32_t *fifo_tx_target); +void usb_send_configuration_descriptor( + usb_configuration_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_interface_descriptor(usb_interface_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_string_descriptor_zero( + usb_string_descriptor_zero_t *string_descriptor, + volatile uint32_t *fifo_tx_target); +void usb_send_unicode_string_descriptor( + usb_unicode_string_descriptor_t *string_descriptor, + volatile uint32_t *fifo_tx_target); + #endif // USB_H diff --git a/include/usb_device.h b/include/usb_device.h index 45b1f42..87cc9f5 100644 --- a/include/usb_device.h +++ b/include/usb_device.h @@ -16,8 +16,7 @@ typedef enum { RESET = 1, RESET_DONE = 2, SET_ADDRESS_RCVD = 3, - SET_CONFIG_RCVD = 4, - ENUMERATED = 5, + ENUMERATED = 4, } usb_device_state_t; typedef struct { @@ -28,6 +27,7 @@ typedef struct { usb_device_descriptor_t device_descriptor; usb_configuration_descriptor_t configuration_descriptor; usb_interface_descriptor_t interface_descriptor; + usb_device_qualifier_t device_qualifier; usb_endpoint_descriptor_t endpoint_descriptors[8]; } usb_class_t; @@ -45,7 +45,11 @@ typedef struct { usb_class_t class; usb_device_state_t state; - usb_setup_command_t received_setup_command; + + // TODO: is this count field required? + uint8_t received_setup_commands_count; + uint8_t received_setup_commands_index; + usb_setup_command_t received_setup_commands[3]; } usb_device_t; // has configuration etc diff --git a/src/usb.c b/src/usb.c index a4be090..1fd5afe 100644 --- a/src/usb.c +++ b/src/usb.c @@ -6,7 +6,7 @@ typedef union { uint8_t bytes[4]; } usb_data_t; -void usb_generic_send(uint8_t* data, uint16_t size, uint32_t *fifo_tx_target) { +void usb_generic_send(uint8_t* data, uint16_t size, volatile uint32_t *fifo_tx_target) { usb_data_t tx_data; uint8_t subWordBytes = size % 4; uint8_t wordCount = size / 4; @@ -27,7 +27,7 @@ void usb_generic_send(uint8_t* data, uint16_t size, uint32_t *fifo_tx_target) { } } -void usb_generic_read(uint8_t *data, uint16_t size, uint32_t *fifo_rx_source) { +void 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; @@ -48,31 +48,43 @@ void usb_generic_read(uint8_t *data, uint16_t size, uint32_t *fifo_rx_source) { } void usb_send_descriptor(usb_descriptor_t *descriptor, - uint32_t *fifo_tx_target) { + volatile uint32_t *fifo_tx_target) { usb_generic_send((uint8_t*)descriptor, descriptor->bLength, fifo_tx_target); } void usb_send_configuration_descriptor( - usb_configuration_descriptor_t *descriptor, uint32_t *fifo_tx_target) { + usb_configuration_descriptor_t *descriptor, volatile uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_CONFIGURATION; descriptor->header.bLength = sizeof(usb_configuration_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } +void usb_send_device_descriptor(usb_device_descriptor_t *descriptor, + volatile uint32_t *fifo_tx_target) { + descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE; + descriptor->header.bLength = sizeof(usb_device_descriptor_t); + usb_send_descriptor(&descriptor->header, fifo_tx_target); +} +void usb_send_device_qualifier_descriptor(usb_device_qualifier_t *descriptor, + volatile uint32_t *fifo_tx_target) { + descriptor->header.bDescriptorType = DESCRIPTOR_DEVICE_QUALIFIER; + descriptor->header.bLength = sizeof(usb_device_qualifier_t); + usb_send_descriptor(&descriptor->header, fifo_tx_target); +} void usb_send_interface_descriptor(usb_interface_descriptor_t *descriptor, - uint32_t *fifo_tx_target) { + volatile uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_INTERFACE; descriptor->header.bLength = sizeof(usb_interface_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } void usb_send_endpoint_descriptor(usb_endpoint_descriptor_t *descriptor, - uint32_t *fifo_tx_target) { + volatile uint32_t *fifo_tx_target) { descriptor->header.bDescriptorType = DESCRIPTOR_ENDPOINT; descriptor->header.bLength = sizeof(usb_endpoint_descriptor_t); usb_send_descriptor(&descriptor->header, fifo_tx_target); } void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t *string_descriptor, - uint32_t *fifo_tx_target) { + volatile uint32_t *fifo_tx_target) { usb_data_t data; data.word = 0; @@ -97,8 +109,7 @@ void usb_send_string_descriptor_zero(usb_string_descriptor_zero_t *string_descri } void usb_send_unicode_string_descriptor( usb_unicode_string_descriptor_t *string_descriptor, - uint32_t *fifo_tx_target) { - + volatile uint32_t *fifo_tx_target) { usb_data_t data = { .word = 0 }; data.halfwords[0] = *((uint16_t*)string_descriptor); if (string_descriptor->bString != 0 && string_descriptor->header.bLength > 2) { diff --git a/src/usb_device.c b/src/usb_device.c index ed76a0f..fe36d76 100644 --- a/src/usb_device.c +++ b/src/usb_device.c @@ -4,6 +4,7 @@ #include #include #include "registers.h" +#include "delay.h" /* USB_OTG_GlobalTypeDef */ @@ -23,6 +24,9 @@ void* usb_device_init(void* peripheral_address, usb_class_t* class, void* buffer device->in = peripheral_address + USB_OTG_IN_ENDPOINT_BASE; device->fifos = (usb_fifo_t*)(((uint8_t*)device->core) + USB_OTG_FIFO_BASE); device->endpoint_count = 8; + device->received_setup_commands_count = 0; + device->received_setup_commands_index = 0; + device->class = *class; // TODO: clarify how this should work... usb1_device = device; @@ -41,6 +45,7 @@ void usb_device_reset(void* device_ptr) { while (device->core->GRSTCTL & USB_OTG_GRSTCTL_CSRST); // Wait for idle while ((device->core->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0); + DELAY_US(3); } void usb_device_clear_interrupts(void* device_ptr) { @@ -78,6 +83,7 @@ void usb_device_setup(void* device_ptr) { device->core->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; + DELAY_US(3); usb_device_reset(device_ptr); // global interrupt mask @@ -114,11 +120,6 @@ void usb_device_setup(void* device_ptr) { /* while (((device->core->GINTSTS) & USB_OTG_GINTSTS_ENUMDNE) == 0) {} */ } -void usb_handle_endpoint_int(usb_device_t* device) { - device->core->GRXSTSP; - device->core->GRXFSIZ; -} - typedef enum { PACKET_GLOBAL_OUT_NAK = 1, PACKET_OUT_DATA_PACKET_RCVD = 2, @@ -141,6 +142,187 @@ typedef struct { uint8_t endpoint_num; } packet_info_t; +void usb_prepare_send_packet(USB_OTG_INEndpointTypeDef* in, uint8_t packet_count, uint8_t packet_size) { + if (ep enabled) { + // this is bad! Can't send the packet + } + + in->DIEPTSIZ = (packet_count << USB_OTG_DIEPTSIZ_PKTCNT_Pos) | (packet_size << USB_OTG_DIEPTSIZ_XFRSIZ_Pos); +} + +void usb_control_send(usb_device_t *device, uint8_t value) { + usb_prepare_send_packet(&device->in[0], + 1, sizeof(uint8_t)); + usb_generic_send(&value, + sizeof(uint8_t), &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; +} + +void usb_control_send_ack(usb_device_t* device) { + usb_prepare_send_packet(&device->in[0], + 1, sizeof(uint8_t)); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; +} + +void usb_handle_setup(usb_device_t *device, usb_setup_command_t* cmd) { + switch (cmd->bRequest) { + case USB_SETUP_GET_STATUS: { + uint8_t size; + uint8_t* packet; + usb_device_status_t device_status; + usb_interface_status_t interface_status; + usb_endpoint_status_t endpoint_status; + + switch (cmd->bmRequestType.recipient) { + case USB_SETUP_DEVICE: { + size = sizeof(usb_device_status_t); + device_status.self_powered = 0; + device_status.remote_wakeup = 0; + device_status.reserved_zeros = 0; + packet = (uint8_t*)&device_status; + } + break; + case USB_SETUP_INTERFACE: { + size = sizeof(usb_interface_status_t); + interface_status.reserved = 0; + packet = (uint8_t*)&interface_status; + } + break; + case USB_SETUP_ENDPOINT: { + size = sizeof(usb_endpoint_status_t); + endpoint_status.halt = 0; + endpoint_status.reserved_zeros = 0; + packet = (uint8_t*)&interface_status; + } + break; + } + + usb_prepare_send_packet(device, 1, size); + usb_generic_send(packet, size, + &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; + } + break; + case USB_SETUP_GET_DESCRIPTOR: { + usb_descriptor_type_t descriptor_type = (cmd->wValue >> 8) & 0xFF; + uint8_t descriptor_index = cmd->wValue & 0xFF; + + switch (descriptor_type) { + case DESCRIPTOR_DEVICE: + usb_prepare_send_packet(&device->in[0], + 1, sizeof(usb_device_descriptor_t)); + usb_send_device_descriptor(&device->class.device_descriptor, &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; + break; + case DESCRIPTOR_CONFIGURATION: + usb_prepare_send_packet(&device->in[0], + 1, sizeof(usb_configuration_descriptor_t)); + usb_send_configuration_descriptor(&device->class.configuration_descriptor, &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; + break; + case DESCRIPTOR_STRING: + break; + case DESCRIPTOR_ENDPOINT: + usb_prepare_send_packet(&device->in[0], + 1, sizeof(usb_endpoint_descriptor_t)); + usb_send_endpoint_descriptor(&device->class.endpoint_descriptors[descriptor_index], &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; + break; + case DESCRIPTOR_DEVICE_QUALIFIER: + usb_prepare_send_packet(&device->in[0], + 1, sizeof(usb_device_qualifier_t)); + usb_send_device_qualifier_descriptor(&device->class.device_qualifier, &device->fifos[0].data[0]); + device->in[0].DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA; + break; + case DESCRIPTOR_OTHER_SPEED_CONFIGURATION: + case DESCRIPTOR_INTERFACE_POWER: + reg_set_bits(&device->out[0].DOEPCTL, USB_OTG_DOEPCTL_STALL); + break; + } + // TODO + } + break; + case USB_SETUP_GET_CONFIGURATION: { + uint8_t value = device->class.configuration_descriptor.bConfigurationValue; + if (device->state != ENUMERATED) { + value = 0; + } + usb_control_send(device, value); + } + break; + case USB_SETUP_GET_INTERFACE: { + usb_control_send(device, device->class.interface_descriptor.bAlternateSetting); + } + break; + case USB_SETUP_SET_ADDRESS: + reg_write_bits_pos(&device->device->DCFG, + cmd->wValue, + USB_OTG_DCFG_DAD_Pos, + 0x7F); + usb_control_send_ack(device); + device->state = SET_ADDRESS_RCVD; + break; + case USB_SETUP_SET_CONFIGURATION: { + if (cmd->wValue == 0) { + device->state = SET_ADDRESS_RCVD; + usb_control_send_ack(device); + + // TODO disable endpoints + } else if (cmd->wValue == device->class.configuration_descriptor.bConfigurationValue) { + device->state = ENUMERATED; + usb_control_send_ack(device); + + // TODO setup endpoints + } else { + reg_set_bits(&device->in[0].DIEPCTL, USB_OTG_DIEPCTL_STALL); + } + } + break; + case USB_SETUP_CLEAR_FEATURE: + switch (cmd->wValue) { + case USB_FEATURE_ENDPOINT_HALT: { + uint8_t ep_id = cmd->wIndex; + reg_clear_bits(&device->in[ep_id].DIEPCTL, USB_OTG_DIEPCTL_STALL); + reg_clear_bits(&device->out[ep_id].DOEPCTL, USB_OTG_DOEPCTL_STALL); + } + break; + case USB_FEATURE_TEST_MODE: + case USB_FEATURE_DEVICE_REMOTE_WAKEUP: + // Do not do anything... + break; + } + + usb_control_send_ack(device); + break; + case USB_SETUP_SET_FEATURE: + switch (cmd->wValue) { + case USB_FEATURE_ENDPOINT_HALT: { + uint8_t ep_id = cmd->wIndex; + reg_set_bits(&device->in[ep_id].DIEPCTL, USB_OTG_DIEPCTL_STALL); + reg_set_bits(&device->out[ep_id].DOEPCTL, USB_OTG_DOEPCTL_STALL); + } + break; + case USB_FEATURE_TEST_MODE: + case USB_FEATURE_DEVICE_REMOTE_WAKEUP: + // Do not do anything... + break; + } + + usb_control_send_ack(device); + break; + case USB_SETUP_SET_DESCRIPTOR: + case USB_SETUP_SET_INTERFACE: + case USB_SETUP_SYNCH_FRAME: + device->in->DIEPCTL |= USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_STALL; + device->state = UNKNOWN_CONTROL_COMMAND; + break; + case RESERVED1: + case RESERVED2: + device->state = UNKNOWN_CONTROL_COMMAND; + break; + } +} + void usb_handle_rxflvl_control_int(usb_device_t *device, packet_info_t *packet_info) { uint32_t dummy; @@ -148,14 +330,20 @@ void usb_handle_rxflvl_control_int(usb_device_t *device, uint32_t *fifo = device->fifos[0].data; if (packet_info->packet_status == PACKET_SETUP_TRANSACTION_COMPLETED) { - + // Nothing do to. } else if (packet_info->packet_status == PACKET_SETUP_DATA_PACKET_RECEIVED) { - /* dummy = *fifo; // internal info */ // SAVE data - usb_generic_read((uint8_t*)&device->received_setup_command, 8, fifo); - - // 00000000010000000000000000000000 - // 00000000101010000000000000000000 + uint8_t setup_packets_count = 3 - reg_read_bits_pos(&device->out[0].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); + usb_generic_read( + (uint8_t *)&device + ->received_setup_commands[device->received_setup_commands_index++], + 8, + fifo); + device->received_setup_commands_index %= 3; + + if (setup_packets_count == 0) { + reg_write_bits_pos(&device->out[0].DOEPTSIZ, 3, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); + } dummy = *fifo; // the last that will trigger another interrupt } else if (packet_info->byte_count != 0) { @@ -187,12 +375,137 @@ void usb_handle_rxflvl_int(usb_device_t *device) { } } - // Read info about the endoint etc. + // Read info about the endpoint etc. // Re-enable the interrupt reg_set_bits(&device->core->GINTMSK, USB_OTG_GINTMSK_RXFLVLM); } +uint8_t usb_daint_get_endpoint_number(uint32_t endpoints) { + for (int i = 0; i < 15; i++) { + if (endpoints & (1 << i)) { + return i; + } + } + return 0xFF; +} + +void usb_handle_endpoint_in_int(usb_device_t* device) { + uint8_t ep_id = usb_daint_get_endpoint_number(reg_read_bits_pos(&device->device->DAINT, USB_OTG_DAINT_IEPINT_Pos, 0xFFFF)); + uint32_t interrupt_reg = device->in[ep_id].DIEPINT; + + if (interrupt_reg & USB_OTG_DIEPINT_PKTDRPSTS) { + // Not generated by interrupt! So if we get this one + // here, it's not from the interrupt. Just clear it, + // isochronous pipes can drop data from time to time + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_PKTDRPSTS); + } + + if (interrupt_reg & USB_OTG_DIEPINT_NAK) { + // NOTE no need to do much. Hardware will resend + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_NAK); + } else if (interrupt_reg & USB_OTG_DIEPINT_BNA) { + // NOTE this should not be reached as DMA is not used + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_BNA); + } else if (interrupt_reg & USB_OTG_DIEPINT_TXFIFOUDRN) { + // NOTE this should not be reached as thresholding is not used + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_TXFIFOUDRN); + } else if (interrupt_reg & USB_OTG_DIEPINT_TXFE) { + // Now we can send more data. TODO notify application about this + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_TXFE); + } else if (interrupt_reg & USB_OTG_DIEPINT_INEPNE) { + // NAK effective. Okay, ack, go on. + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_INEPNE); + } else if (interrupt_reg & USB_OTG_DIEPINT_INEPNM) { + device->state = ERROR; // data on top of TxFIFO belong to endpoint other + // than the one for which in token was received. + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_INEPNM); + } else if (interrupt_reg & USB_OTG_DIEPINT_ITTXFE) { + // In token when no data. How to proceed? TODO + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_ITTXFE); + } else if (interrupt_reg & USB_OTG_DIEPINT_TOC) { + // Timeout condition. Skip? TODO how to proceed? + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_TOC); + } else if (interrupt_reg & USB_OTG_DIEPINT_AHBERR) { + // NOTE this should not be reached as thresholding is not used + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_AHBERR); + } else if (interrupt_reg & USB_OTG_DIEPINT_EPDISD) { + // Endpoint is disabled, per application's request. Okay. + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_EPDISD); + } else if (interrupt_reg & USB_OTG_DIEPINT_XFRC) { + // Transfer is completed. TODO notify application? + reg_clear_bits(&device->in[ep_id].DIEPINT, USB_OTG_DIEPINT_XFRC); + } +} + +#define USB_OTG_DOEPINT_BNA_Pos (9U) +#define USB_OTG_DOEPINT_BNA_Msk (0x1UL << USB_OTG_DOEPINT_B2BSTUP_Pos) /*!< 0x00000040 */ +#define USB_OTG_DOEPINT_BNA USB_OTG_DOEPINT_B2BSTUP_Msk /*!< Back-to-back SETUP packets received */ + +void usb_handle_endpoint_out_int(usb_device_t* device) { + /* device->core->GRXSTSP; */ + /* device->core->GRXFSIZ; */ + + uint8_t ep_id = usb_daint_get_endpoint_number(reg_read_bits_pos(&device->device->DAINT, USB_OTG_DAINT_OEPINT_Pos, 0xFFFF)); + uint32_t interrupt_reg = device->out[ep_id].DOEPINT; + + if (interrupt_reg & USB_OTG_DOEPINT_STPKTRX) { + // NOTE This shouldn't be reached since DMA is not used + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_STPKTRX); + } else if (interrupt_reg & USB_OTG_DOEPINT_NYET) { + // We don't really care about this one for now + // TODO: for future - trigger a callback to application + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_NYET); + } else if (interrupt_reg & USB_OTG_DOEPINT_NAK) { + // We don't really care about this one for now + // TODO: for future - trigger a callback to application + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_NAK); + } else if (interrupt_reg & USB_OTG_DOEPINT_BERR) { + // Uh? Babble much? + device->state = CONTROL_ERROR; + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_BERR); + } else if (interrupt_reg & USB_OTG_DOEPINT_BNA) { + // NOTE This shoudln't be reached since DMA is not used + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_BNA); + } else if (interrupt_reg & USB_OTG_DOEPINT_OUTPKTERR) { + // NOTE thresholding not enabled, so this shouldn't be reached + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_OUTPKTERR); + } else if (interrupt_reg & USB_OTG_DOEPINT_B2BSTUP) { + // TODO: this is a problem! we couldn't capture all the packets! + device->state = CONTROL_ERROR; + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_B2BSTUP); + } else if (interrupt_reg & USB_OTG_DOEPINT_OTEPSPR) { + // TODO: ack or stall the status phase? How? + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_OTEPSPR); + } else if (interrupt_reg & USB_OTG_DOEPINT_OTEPDIS) { + // NOTE: Can we handle this? a callback to application? + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_OTEPDIS); + } else if (interrupt_reg & USB_OTG_DOEPINT_STUP) { + // handle all setup commands + uint8_t setup_packets_count = 3 - reg_read_bits_pos(&device->out[ep_id].DOEPTSIZ, USB_OTG_DOEPTSIZ_STUPCNT_Pos, 3); + usb_handle_setup(device, &device->received_setup_commands[0]); + for (int i = 0; i < device->received_setup_commands_count; i++) { + } + + device->received_setup_commands_count = 0; + // TODO: null the data? shouldn't be needed... + + // 3 packets to receive as setup + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_STUP); + } else if (interrupt_reg & USB_OTG_DOEPINT_AHBERR) { + // NOTE This shoudln't be reached since DMA is not used + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_AHBERR); + } else if (interrupt_reg & USB_OTG_DOEPINT_EPDISD) { + // NOTE endpoint has been disabled, as was instructed. So this shoudln't + // need handling? + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_EPDISD); + } else if (interrupt_reg & USB_OTG_DOEPINT_XFRC) { + // Transfer has been completed + // TODO: handle data? - callback to device data handle? + reg_clear_bits(&device->out[ep_id].DOEPINT, USB_OTG_DOEPINT_XFRC); + } +} + // NOTE: this is irq handler void otg_hs_handler(void) { @@ -215,7 +528,7 @@ void otg_hs_handler(void) { device->device->DIEPMSK |= USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_TOM; // 512 bytes - device->core->GRXFSIZ = 512 / 4; + device->core->GRXFSIZ = 256 / 4; // 64 bytes, beginning of ram device->core->DIEPTXF[0] = (0) << USB_OTG_DIEPTXF_INEPTXSA_Pos | (64 / 4) << USB_OTG_DIEPTXF_INEPTXFD_Pos; @@ -269,9 +582,13 @@ void otg_hs_handler(void) { } // Setup, data... - if (device->core->GINTSTS & (USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) { - // TODO - usb_handle_endpoint_int(device); + if (device->core->GINTSTS & USB_OTG_GINTSTS_OEPINT) { + usb_handle_endpoint_out_int(device); + return; + } + + if (device->core->GINTSTS & USB_OTG_GINTSTS_IEPINT) { + usb_handle_endpoint_in_int(device); return; } -- 2.48.1