From: Martin Mares Date: Sat, 23 Jun 2018 22:41:19 +0000 (+0200) Subject: First bits of my own high-level USB stack X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=f0a255055982a16d6d0a3f58ef959a2389edbbd7;p=home-hw.git First bits of my own high-level USB stack --- diff --git a/Inc/usb.h b/Inc/usb.h new file mode 100644 index 0000000..ec7cc23 --- /dev/null +++ b/Inc/usb.h @@ -0,0 +1,167 @@ +#define USB_SELF_POWERED + +typedef unsigned int uint; +typedef uint8_t byte; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; + +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +/*** USB state structure ***/ + +struct usb_endpoint { + u32 max_packet_size; + u32 total_length; + u32 remaining_length; +}; + +struct usb { + PCD_HandleTypeDef *hpcd; + byte state; // USB_STATE_xxx + byte pre_suspend_state; + byte address; + byte speed; // PCD_SPEED_xxx + byte config; + byte remote_wakeup; + byte ep0_state; // USB_EP0_xxx + byte ep0_data_len; + struct usb_endpoint ep_in[15]; + struct usb_endpoint ep_out[15]; + byte status_buf[2]; +}; + +void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd); + +enum usb_device_state { + USB_STATE_DEFAULT, + USB_STATE_ADDRESSED, + USB_STATE_CONFIGURED, + USB_STATE_SUSPENDED, +}; + +enum usb_ep0_state { + USB_EP0_IDLE, + USB_EP0_SETUP, + USB_EP0_DATA_IN, + USB_EP0_DATA_OUT, + USB_EP0_STATUS_IN, + USB_EP0_STATUS_OUT, + USB_EP0_STALL, +}; + +/*** Constants from USB specs ***/ + +#define USB_REQ_DIRECTION 0x80 + +enum usb_req_type { + USB_REQ_TYPE_STANDARD = 0x00, + USB_REQ_TYPE_CLASS = 0x20, + USB_REQ_TYPE_VENDOR = 0x40, + USB_REQ_TYPE_MASK = 0x60, +}; + +enum usb_req_recipient { + USB_REQ_RECIPIENT_DEVICE = 0x00, + USB_REQ_RECIPIENT_INTERFACE = 0x01, + USB_REQ_RECIPIENT_ENDPOINT = 0x02, + USB_REQ_RECIPIENT_MASK = 0x1f, +}; + +enum usb_req_standard { + USB_REQ_GET_STATUS = 0x00, + USB_REQ_CLEAR_FEATURE = 0x01, + USB_REQ_SET_FEATURE = 0x03, + USB_REQ_SET_ADDRESS = 0x05, + USB_REQ_GET_DESCRIPTOR = 0x06, + USB_REQ_SET_DESCRIPTOR = 0x07, + USB_REQ_GET_CONFIGURATION = 0x08, + USB_REQ_SET_CONFIGURATION = 0x09, + USB_REQ_GET_INTERFACE = 0x0A, + USB_REQ_SET_INTERFACE = 0x0B, + USB_REQ_SYNCH_FRAME = 0x0C, +}; + +enum usb_desc_type { + USB_DESC_TYPE_DEVICE = 1, + USB_DESC_TYPE_CONFIGURATION = 2, + USB_DESC_TYPE_STRING = 3, + USB_DESC_TYPE_INTERFACE = 4, + USB_DESC_TYPE_ENDPOINT = 5, + USB_DESC_TYPE_DEVICE_QUALIFIER = 6, + USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION = 7, + USB_DESC_TYPE_BOS = 0x0F, +}; + +enum usb_dev_status { + USB_DEV_STATUS_REMOTE_WAKEUP = 2, + USB_DEV_STATUS_SELF_POWERED = 1, +}; + +enum usb_feature { + USB_FEATURE_EP_HALT = 0, + USB_FEATURE_REMOTE_WAKEUP = 1, + USB_FEATURE_TEST_MODE = 2, +}; + +#define USB_HS_MAX_PACKET_SIZE 512 +#define USB_FS_MAX_PACKET_SIZE 64 +#define USB_MAX_EP0_SIZE 64 + +enum usb_ep_type { + USB_EP_TYPE_CTRL = 0, + USB_EP_TYPE_ISOC = 1, + USB_EP_TYPE_BULK = 2, + USB_EP_TYPE_INTR = 3, +}; + +/*** Wrappers around HAL routines ***/ + +// Wrappers return HAL_OK / HAL_ERROR / HAL_BUSY / HAL_TIMEOUT + +static inline HAL_StatusTypeDef usb_ep_open(struct usb *usb, byte ep_addr, byte ep_type, byte ep_max_size) +{ + return HAL_PCD_EP_Open(usb->hpcd, ep_addr, ep_max_size, ep_type); +} + +static inline HAL_StatusTypeDef usb_ep_close(struct usb *usb, byte ep_addr) +{ + return HAL_PCD_EP_Close(usb->hpcd, ep_addr); +} + +static inline HAL_StatusTypeDef usb_ep_flush(struct usb *usb, byte ep_addr) +{ + return HAL_PCD_EP_Flush(usb->hpcd, ep_addr); +} + +static inline HAL_StatusTypeDef usb_ep_stall(struct usb *usb, byte ep_addr) +{ + return HAL_PCD_EP_SetStall(usb->hpcd, ep_addr); +} + +static inline HAL_StatusTypeDef usb_ep_unstall(struct usb *usb, byte ep_addr) +{ + return HAL_PCD_EP_ClrStall(usb->hpcd, ep_addr); +} + +static inline int usb_ep_is_stalled(struct usb *usb, byte ep_addr) +{ + return ((ep_addr & 0x80) ? usb->hpcd->IN_ep : usb->hpcd->OUT_ep) [ep_addr & 0x7f].is_stall; +} + +static inline HAL_StatusTypeDef usb_ep_transmit(struct usb *usb, byte ep_addr, byte *buf, u32 size) +{ + return HAL_PCD_EP_Transmit(usb->hpcd, ep_addr, buf, size); +} + +static inline HAL_StatusTypeDef usb_ep_receive(struct usb *usb, byte ep_addr, byte *buf, u32 size) +{ + return HAL_PCD_EP_Receive(usb->hpcd, ep_addr, buf, size); +} + +static inline u32 usb_ep_received_size(struct usb *usb, byte ep_addr) +{ + return HAL_PCD_EP_GetRxCount(usb->hpcd, ep_addr); +} diff --git a/Makefile b/Makefile index 5696535..7033be3 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,7 @@ BUILD_DIR = build C_SOURCES = \ /aux/misc/stm/F1-package/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_exti.c \ Src/main.c \ +Src/usb.c \ /aux/misc/stm/F1-package/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_ll_rcc.c \ /Src/system_stm32f1xx.c \ Src/stm32f1xx_it.c \ diff --git a/Src/main.c b/Src/main.c index 22395ad..9d3dbb8 100644 --- a/Src/main.c +++ b/Src/main.c @@ -39,6 +39,7 @@ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" +#include "usb.h" /* USER CODE BEGIN Includes */ @@ -50,7 +51,7 @@ PCD_HandleTypeDef hpcd_USB_FS; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ -USBD_HandleTypeDef USBD_Device; +struct usb usb; /* USER CODE END PV */ @@ -68,6 +69,168 @@ static void MX_USB_PCD_Init(void); /* USER CODE BEGIN 0 */ +#include +#include +#include + +void semi_put_char(char c) +{ + // This is tricky, we need to work around GCC bugs + volatile char cc = c; + asm volatile ( + "mov r0, #0x03\n" /* SYS_WRITEC */ + "mov r1, %[msg]\n" + "bkpt #0xAB\n" + : + : [msg] "r" (&cc) + : "r0", "r1" + ); +} + +void semi_write_string(char *c) +{ + asm volatile ( + "mov r0, #0x04\n" /* SYS_WRITE0 */ + "mov r1, %[msg]\n" + "bkpt #0xAB\n" + : + : [msg] "r" (c) + : "r0", "r1" + ); +} + +void debug_putc(int c) +{ + static char debug_buf[16]; + static int debug_i; + debug_buf[debug_i++] = c; + if (c == '\n' || debug_i >= sizeof(debug_buf) - 1) + { + debug_buf[debug_i] = 0; + semi_write_string(debug_buf); + debug_i = 0; + } +} + +void debug_puts(const char *s) +{ + while (*s) + debug_putc(*s++); +} + +enum printf_flags { + PF_ZERO_PAD = 1, + PF_SIGNED = 2, + PF_NEGATIVE = 4, + PF_UPPERCASE = 8, + PF_LEFT = 16, +}; + +static void printf_string(const char *s, uint width, uint flags) +{ + uint len = strlen(s); + uint pad = (len < width) ? width - len : 0; + char pad_char = (flags & PF_ZERO_PAD) ? '0' : ' '; + + if (flags & PF_LEFT) + debug_puts(s); + while (pad--) + debug_putc(pad_char); + if (!(flags & PF_LEFT)) + debug_puts(s); +} + +static void printf_number(uint i, uint width, uint flags, uint base) +{ + char buf[16]; + char *w = buf + sizeof(buf); + + if (flags & PF_SIGNED) + { + if ((int) i < 0) + { + i = - (int) i; + flags |= PF_NEGATIVE; + } + } + + *--w = 0; + do + { + uint digit = i % base; + if (digit < 10) + *--w = '0' + digit; + else + *--w = ((flags & PF_UPPERCASE) ? 'A' : 'a') + digit - 10; + i /= base; + } + while (i); + + if (flags & PF_NEGATIVE) + *--w = '-'; + + printf_string(w, width, flags); +} + +void debug_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + while (*fmt) + { + int c = *fmt++; + if (c != '%') + { + debug_putc(c); + continue; + } + + uint width = 0; + uint flags = 0; + + if (*fmt == '-') + { + fmt++; + flags |= PF_LEFT; + } + + if (*fmt == '0') + { + fmt++; + flags |= PF_ZERO_PAD; + } + + while (*fmt >= '0' && *fmt <= '9') + width = 10*width + *fmt++ - '0'; + + c = *fmt++; + switch (c) + { + case 'd': + printf_number(va_arg(args, int), width, flags | PF_SIGNED, 10); + break; + case 'u': + printf_number(va_arg(args, int), width, flags, 10); + break; + case 'X': + flags |= PF_UPPERCASE; + // fall-thru + case 'x': + printf_number(va_arg(args, int), width, flags, 16); + break; + case 's': + printf_string(va_arg(args, char *), width, flags); + break; + default: + debug_putc(c); + continue; + } + } + + va_end(args); +} + /* USER CODE END 0 */ /** @@ -103,17 +266,20 @@ int main(void) MX_I2C2_Init(); MX_USB_PCD_Init(); /* USER CODE BEGIN 2 */ + usb_init(&usb, &hpcd_USB_FS); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ + int cnt = 0; while (1) { LL_GPIO_SetOutputPin(LED_GPIO_Port, LED_Pin); - LL_mDelay(1000); + LL_mDelay(500); LL_GPIO_ResetOutputPin(LED_GPIO_Port, LED_Pin); - LL_mDelay(1000); + LL_mDelay(500); + debug_printf("Counter = %d\n", cnt++); /* USER CODE END WHILE */ @@ -263,7 +429,6 @@ static void MX_I2C2_Init(void) /* USB init function */ static void MX_USB_PCD_Init(void) { - hpcd_USB_FS.Instance = USB; hpcd_USB_FS.Init.dev_endpoints = 8; hpcd_USB_FS.Init.speed = PCD_SPEED_FULL; @@ -275,7 +440,6 @@ static void MX_USB_PCD_Init(void) { _Error_Handler(__FILE__, __LINE__); } - } /** Configure pins as diff --git a/Src/usb.c b/Src/usb.c new file mode 100644 index 0000000..434408d --- /dev/null +++ b/Src/usb.c @@ -0,0 +1,507 @@ +#include "stm32f1xx.h" +#include "stm32f1xx_hal.h" + +#include "usb.h" + +void _Error_Handler(char * file, int line); // FIXME + +void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd) +{ + usb->hpcd = hpcd; + usb->state = USB_STATE_DEFAULT; + usb->ep0_state = USB_EP0_IDLE; + + HAL_PCDEx_PMAConfig(hpcd, 0x00, PCD_SNG_BUF, 0x18); + HAL_PCDEx_PMAConfig(hpcd, 0x80, PCD_SNG_BUF, 0x58); + + HAL_PCD_Start(hpcd); +} + +static inline uint get_u16(byte *p) +{ + return (p[1] << 8) | p[0]; +} + +static inline void put_u16(byte *p, u16 x) +{ + p[0] = x; + p[1] = x >> 8; +} + +#if 0 // FIXME +static struct usb_endpoint *ep_by_addr(struct usb *usb, byte ep_addr) +{ + return ((ep_addr & 0x80) ? usb->ep_in : usb->ep_out) + (ep_addr & 0x7f); +} +#endif + +static void usb_ctl_send_status(struct usb *usb) +{ + usb->ep0_state = USB_EP0_STATUS_IN; + usb_ep_transmit(usb, 0x00, NULL, 0); +} + +#if 0 // FIXME +static void usb_ctl_recv_status(struct usb *usb) +{ + usb->ep0_state = USB_EP0_STATUS_OUT; + usb_ep_receive(usb, 0x00, NULL, 0); +} +#endif + +static void usb_ctl_send_data(struct usb *usb, byte *data, uint len) +{ + usb->ep0_state = USB_EP0_DATA_IN; + usb->ep_in[0].total_length = len; + usb->ep_in[0].remaining_length = len; + usb_ep_transmit(usb, 0x00, data, len); +} + +static void usb_ctl_send_byte(struct usb *usb, byte data) +{ + usb->status_buf[0] = data; + usb_ctl_send_data(usb, usb->status_buf, 1); +} + +static void usb_ctl_send_u16(struct usb *usb, u16 data) +{ + put_u16(usb->status_buf, data); + usb_ctl_send_data(usb, usb->status_buf, 2); +} + +static void usb_ctl_error(struct usb *usb) +{ + usb_ep_stall(usb, 0x00); + usb_ep_stall(usb, 0x80); +} + +struct setup_request { + byte bmRequest; + byte bRequest; + u16 wValue; + u16 wIndex; + u16 wLength; +}; + +static void usb_ctl_setup_error(struct usb *usb, struct setup_request *setup) +{ + usb_ep_stall(usb, setup->bmRequest & USB_REQ_DIRECTION); +} + +static void dev_get_status(struct usb *usb, struct setup_request *setup) +{ + if ((usb->state != USB_STATE_ADDRESSED && usb->state != USB_STATE_CONFIGURED) || + setup->wValue || setup->wIndex || setup->wLength != 2) + return usb_ctl_error(usb); + + uint stat = 0; +#ifdef USB_SELF_POWERED + stat |= USB_DEV_STATUS_SELF_POWERED; +#endif + if (usb->remote_wakeup) + stat |= USB_DEV_STATUS_REMOTE_WAKEUP; + usb_ctl_send_u16(usb, stat); +} + +static void dev_clear_feature(struct usb *usb, struct setup_request *setup) +{ + if (setup->wIndex || setup->wLength) + return usb_ctl_error(usb); + + if (setup->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + usb->remote_wakeup = 0; + usb_ctl_send_status(usb); + } + else + usb_ctl_error(usb); +} + +static void dev_set_feature(struct usb *usb, struct setup_request *setup) +{ + if (setup->wIndex || setup->wLength) + return usb_ctl_error(usb); + + if (setup->wValue == USB_FEATURE_REMOTE_WAKEUP) + { + usb->remote_wakeup = 1; + usb_ctl_send_status(usb); + } + else + usb_ctl_error(usb); +} + +static void dev_set_address(struct usb *usb, struct setup_request *setup) +{ + if (setup->wIndex || setup->wLength) + return usb_ctl_error(usb); + + uint addr = setup->wValue & 0x7f; + if (usb->state == USB_STATE_CONFIGURED) + usb_ctl_error(usb); + else + { + usb->address = addr; + HAL_PCD_SetAddress(usb->hpcd, addr); + usb_ctl_send_status(usb); + usb->state = addr ? USB_STATE_ADDRESSED : USB_STATE_DEFAULT; + } +} + +static void dev_get_descriptor(struct usb *usb, struct setup_request *setup) +{ +} + +static void dev_get_configuration(struct usb *usb, struct setup_request *setup) +{ + if (setup->wValue || setup->wIndex || setup->wLength != 1) + return usb_ctl_error(usb); + + switch (usb->state) + { + case USB_STATE_ADDRESSED: + usb_ctl_send_byte(usb, 0); + break; + case USB_STATE_CONFIGURED: + usb_ctl_send_byte(usb, usb->config); + break; + default: + usb_ctl_error(usb); + } +} + +static void dev_set_configuration(struct usb *usb, struct setup_request *setup) +{ + byte cfg = setup->wValue & 0xff; + + // FIXME: Support more configurations + if (cfg > 1 || setup->wIndex || setup->wLength) + return usb_ctl_error(usb); + + switch (usb->state) + { + case USB_STATE_ADDRESSED: + if (cfg) + { + usb->config = cfg; + usb->state = USB_STATE_CONFIGURED; + // FIXME: Notify that the device was configured + } + usb_ctl_send_status(usb); + break; + case USB_STATE_CONFIGURED: + if (!cfg) + { + // Unconfiguring + usb->config = 0; + usb->state = USB_STATE_ADDRESSED; + // FIXME: Notify that the device was unconfigured + } + else if (cfg != usb->config) + { + usb->config = cfg; + // FIXME: Notify about configuration change + } + usb_ctl_send_status(usb); + break; + default: + usb_ctl_error(usb); + } +} + +static void dev_setup(struct usb *usb, struct setup_request *setup) +{ + switch (setup->bRequest) + { + case USB_REQ_GET_STATUS: + return dev_get_status(usb, setup); + case USB_REQ_CLEAR_FEATURE: + return dev_clear_feature(usb, setup); + case USB_REQ_SET_FEATURE: + return dev_set_feature(usb, setup); + case USB_REQ_SET_ADDRESS: + return dev_set_address(usb, setup); + case USB_REQ_GET_DESCRIPTOR: + return dev_get_descriptor(usb, setup); + case USB_REQ_GET_CONFIGURATION: + return dev_get_configuration(usb, setup); + case USB_REQ_SET_CONFIGURATION: + return dev_set_configuration(usb, setup); + } + + usb_ctl_setup_error(usb, setup); +} + +static void intf_setup(struct usb *usb, struct setup_request *setup) +{ + byte intf = setup->wIndex & 0xff; + + if (!intf) + { + // FIXME: Support more interfaces + usb_ctl_error(usb); + return; + } + + switch (setup->bRequest) + { + case USB_REQ_GET_STATUS: + if (setup->wValue || setup->wLength != 2 || usb->state != USB_STATE_CONFIGURED) + usb_ctl_error(usb); + else + usb_ctl_send_u16(usb, 0); + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + // Interfaces have no standard features + return usb_ctl_error(usb); + } + + usb_ctl_setup_error(usb, setup); +} + +static void ep_setup(struct usb *usb, struct setup_request *setup) +{ + byte ep_addr = setup->wIndex & 0x8f; + + switch (setup->bRequest) + { + case USB_REQ_GET_STATUS: + if (setup->wValue || setup->wLength != 2) + return usb_ctl_error(usb); + switch (usb->state) + { + case USB_STATE_ADDRESSED: + if (ep_addr & 0x7f) + usb_ctl_error(usb); + return; + case USB_STATE_CONFIGURED: + { + if (usb_ep_is_stalled(usb, ep_addr)) + usb_ctl_send_u16(usb, 1); + else + usb_ctl_send_u16(usb, 0); + return; + } + default: + return usb_ctl_error(usb); + } + break; + + case USB_REQ_SET_FEATURE: + if (setup->wLength) + return usb_ctl_error(usb); + switch (usb->state) + { + case USB_STATE_ADDRESSED: + if (ep_addr & 0x7f) + usb_ctl_error(usb); + return; + case USB_STATE_CONFIGURED: + if (setup->wValue == USB_FEATURE_EP_HALT) + { + if (ep_addr & 0x7f) + usb_ep_stall(usb, ep_addr); + } + usb_ctl_send_status(usb); + return; + default: + usb_ctl_error(usb); + } + break; + + case USB_REQ_CLEAR_FEATURE: + if (setup->wLength) + return usb_ctl_error(usb); + switch (usb->state) + { + case USB_STATE_ADDRESSED: + if (ep_addr & 0x7f) + usb_ctl_error(usb); + return; + case USB_STATE_CONFIGURED: + if (setup->wValue == USB_FEATURE_EP_HALT) + { + if (ep_addr & 0x7f) + usb_ep_unstall(usb, ep_addr); + } + usb_ctl_send_status(usb); + return; + default: + usb_ctl_error(usb); + } + break; + } + + usb_ctl_setup_error(usb, setup); +} + +static void usb_handle_setup(struct usb *usb, struct setup_request *setup) +{ + usb->ep0_state = USB_EP0_SETUP; + usb->ep0_data_len = setup->wLength; + + if ((setup->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) + { + // FIXME: Class-specific and vendor-specific setup packets not supported + // FIXME: Check USB_STATE_CONFIGURED here + usb_ctl_setup_error(usb, setup); + } + + switch (setup->bmRequest & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_DEVICE: + return dev_setup(usb, setup); + case USB_REQ_RECIPIENT_INTERFACE: + return intf_setup(usb, setup); + case USB_REQ_RECIPIENT_ENDPOINT: + return ep_setup(usb, setup); + } + + usb_ctl_setup_error(usb, setup); +} + +void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) +{ + struct usb *usb = hpcd->pData; + byte *req = (byte *) hpcd->Setup; + + struct setup_request setup = { + .bmRequest = req[0], + .bRequest = req[1], + .wValue = get_u16(req+2), + .wIndex = get_u16(req+4), + .wLength = get_u16(req+2), + }; + usb_handle_setup(usb, &setup); +} + +void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + struct usb *usb = hpcd->pData; + struct usb_endpoint *ep = &usb->ep_out[epnum]; + byte *data = hpcd->OUT_ep[epnum].xfer_buff; + + if (!epnum) + { + if (usb->ep0_state != USB_EP0_DATA_OUT) + return; + if (ep->remaining_length > ep->max_packet_size) + { + ep->remaining_length -= ep->max_packet_size; + usb_ep_receive(usb, 0x00, data, MIN(ep->remaining_length, ep->max_packet_size)); + } + else + { + if (usb->state == USB_STATE_CONFIGURED) + { + // FIXME: Handle incoming control packet + } + usb_ctl_send_status(usb); + } + } + else + { + if (usb->state == USB_STATE_CONFIGURED) + { + // FIXME: Custom data callback + } + } +} + +void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + struct usb *usb = hpcd->pData; + struct usb_endpoint *ep = &usb->ep_in[epnum]; + byte *data = hpcd->IN_ep[epnum].xfer_buff; + + if (!epnum) + { + if (usb->ep0_state != USB_EP0_DATA_IN) + return; + if (ep->remaining_length > ep->max_packet_size) + { + ep->remaining_length -= ep->max_packet_size; + usb_ep_transmit(usb, 0x00, data, ep->remaining_length); + usb_ep_receive(usb, 0x00, NULL, 0); + } + else if (ep->total_length && ep->total_length % ep->max_packet_size == 0 && ep->total_length < usb->ep0_data_len) + { + // Send an empty packet if total length is divisible by MTU + usb_ep_transmit(usb, 0x00, NULL, 0); + usb->ep0_data_len = 0; + usb_ep_receive(usb, 0x00, NULL, 0); + } + else + { + if (usb->state == USB_STATE_CONFIGURED) + { + // FIXME: Custom data callback + } + } + } + else + { + if (usb->state == USB_STATE_CONFIGURED) + { + // FIXME: Custom data callback + } + } +} + +void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) +{ + // FIXME +} + +void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd) +{ + struct usb *usb = hpcd->pData; + + usb->state = USB_STATE_DEFAULT; + usb->speed = hpcd->Init.speed; + + usb_ep_open(usb, 0x00, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE); + usb->ep_out[0].max_packet_size = USB_MAX_EP0_SIZE; + + usb_ep_open(usb, 0x80, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE); + usb->ep_in[0].max_packet_size = USB_MAX_EP0_SIZE; +} + +void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd) +{ + struct usb *usb = hpcd->pData; + + usb->pre_suspend_state = usb->state; + usb->state = USB_STATE_SUSPENDED; + + if (hpcd->Init.low_power_enable) + SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk)); +} + +void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd) +{ + struct usb *usb = hpcd->pData; + usb->state = usb->pre_suspend_state; +} + +void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + // We do not support isochronous mode +} + +void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum) +{ + // We do not support isochronous mode +} + +void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd) +{ +} + +void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd) +{ + struct usb *usb = hpcd->pData; + usb->state = USB_STATE_DEFAULT; +}