~ruther/stm32h747i-disco-usb-image-viewer

6051b84001bf571e5e76fd28df36bd87b86ec36a — Rutherther 5 months ago e583c8b
feat: implement most of enumeration
4 files changed, 418 insertions(+), 48 deletions(-)

M include/usb.h
M include/usb_device.h
M src/usb.c
M src/usb_device.c
M include/usb.h => include/usb.h +58 -20
@@ 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,


@@ 45,17 64,22 @@ typedef enum {
} 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

M include/usb_device.h => include/usb_device.h +7 -3
@@ 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

M src/usb.c => src/usb.c +20 -9
@@ 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) {

M src/usb_device.c => src/usb_device.c +333 -16
@@ 4,6 4,7 @@
#include <stddef.h>
#include <stm32h747xx.h>
#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;
  }


Do not follow this link