--- /dev/null
+#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);
+}
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_hal.h"
+#include "usb.h"
/* USER CODE BEGIN Includes */
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
-USBD_HandleTypeDef USBD_Device;
+struct usb usb;
/* USER CODE END PV */
/* USER CODE BEGIN 0 */
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+
+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 */
/**
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 */
/* 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;
{
_Error_Handler(__FILE__, __LINE__);
}
-
}
/** Configure pins as
--- /dev/null
+#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;
+}