+/*** Configurable parameters ***/
+
#define USB_SELF_POWERED
#define USB_NUM_CONFIGURATIONS 1
#define USB_DEBUG
u16 ep0_remaining_length;
u16 ep0_total_length;
byte ep0_buf[USB_EP0_BUF_SIZE];
+ // Descriptor data to be filled by the user during usb_dev_reset()
+ const byte *desc_device;
+ const byte *desc_config;
+ const char * const *desc_string;
+ const byte *desc_languages;
+ u16 desc_device_len;
+ u16 desc_config_len;
+ u16 desc_string_items;
+ u16 desc_languages_len;
};
-void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd);
-void usb_start(struct usb *usb);
-
enum usb_device_state {
USB_STATE_DEFAULT,
USB_STATE_ADDRESSED,
{ }
#endif
+// Parsed setup request
+struct setup_request {
+ byte bmRequest;
+ byte bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+};
+
+/*** Functions provided by low-level code ***/
+
+void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd);
+void usb_start(struct usb *usb);
+
+void usb_ctl_send_status(struct usb *usb);
+void usb_ctl_recv_status(struct usb *usb);
+void usb_ctl_send_data(struct usb *usb, const byte *data, uint len);
+void usb_ctl_recv_data(struct usb *usb, byte *data, uint len);
+void usb_ctl_error(struct usb *usb);
+void usb_ctl_setup_error(struct usb *usb, struct setup_request *setup);
+
+/*** Callbacks to user code ***/
+
+// Device was reset
+void usb_dev_reset(struct usb *usb);
+
+// Configure the device (usb->config is the selected configuration)
+void usb_dev_configure(struct usb *usb);
+
+// Un-configure the device (usb->config is the configuration we are leaving)
+void usb_dev_unconfigure(struct usb *usb);
+
+// Intercept a setup packet. Returns true if default processing should be skipped.
+// Remember to check if usb->state == USB_STATE_CONFIGURED for most requests.
+bool usb_dev_setup_hook(struct usb *usb, struct setup_request *setup);
+
+// Finished receiving control packet data requested by usb_ctl_recv_data()
+void usb_dev_ctl_recv_done(struct usb *usb);
+
+// Finished sending control packet data requested by usb_ctl_send_data()
+void usb_dev_ctl_send_done(struct usb *usb);
+
+// Finished receiving data on a non-control endpoint
+void usb_dev_recv_done(struct usb *usb, byte epnum);
+
+// Finished sending data on a non-control endpoint
+void usb_dev_send_done(struct usb *usb, byte epnum);
+
/*** Constants from USB specs ***/
#define USB_REQ_DIRECTION 0x80
#include <string.h>
-void _Error_Handler(char * file, int line); // FIXME
-
-#define DESC_U16(x) ((x) & 0xff), ((x) >> 8)
-
-enum desc_string {
- DESC_STR_NONE = 0,
- DESC_STR_MANUFACTURER,
- DESC_STR_PRODUCT,
- DESC_STR_SERIAL,
- DESC_STR_CONFIGURATION,
- DESC_STR_INTERFACE,
-};
-
-static const byte desc_device[] = {
- 18, // bLength
- USB_DESC_TYPE_DEVICE, // bDescriptorType
- DESC_U16(0x0200), // bcdUSB
- 0x00, // bDeviceClass
- 0x00, // bDeviceSubClass
- 0x00, // bDeviceProtocol
- USB_MAX_EP0_SIZE, // bMaxPacketSize
- DESC_U16(0x4242), // idVendor
- DESC_U16(0x0001), // idProduct
- DESC_U16(0x0200), // bcdDevice
- DESC_STR_MANUFACTURER, // iManufacturer
- DESC_STR_PRODUCT, // iProduct
- DESC_STR_SERIAL, // iSerialNumber
- USB_NUM_CONFIGURATIONS, // bNumConfigurations
-};
-
-static const byte desc_config[] = {
- // Configuration descriptor
- 9, // bLength
- USB_DESC_TYPE_CONFIGURATION, // bDescriptorType
- 32, // wTotalLength
- 0,
- 0x01, // bNumInterfaces
- 0x01, // bConfigurationValue
- DESC_STR_CONFIGURATION, // iConfiguration
- 0xc0, // bmAttributes: bus-powered, supports remote wakeup
- 0x32, // Max power: 100 mA
- // Interface descriptor
- 9, // bLength
- USB_DESC_TYPE_INTERFACE, // bDescriptorType
- 0x00, // bInterfaceNumber
- 0x00, // bAlternateSetting
- 0x02, // bNumEndpoints
- 0xff, // bInterfaceClass: vendor-defined
- 0x00, // bInterfaceSubClass
- 0x00, // nInterfaceProtocol
- DESC_STR_INTERFACE, // iInterface
- // End-point descriptor
- 7, // bLength
- USB_DESC_TYPE_ENDPOINT, // bDescriptorType
- 0x01, // bEndpointAddress
- USB_EP_TYPE_BULK, // bmAttributes
- 0x40, 0x00, // wMaxPacketSize
- 0x00, // bInterval: unused
- // End-point descriptor
- 7, // bLength
- USB_DESC_TYPE_ENDPOINT, // bDescriptorType
- 0x81, // bEndpointAddress
- USB_EP_TYPE_BULK, // bmAttributes
- 0x40, 0x00, // wMaxPacketSize
- 0x00, // bInterval: unused
-};
-
-static const char * const desc_string[] = {
- NULL, // DESC_STR_NONE
- "United Computer Wizards", // DESC_STR_MANUFACTURER
- "Mysterious Gadget", // DESC_STR_PRODUCT
- "00000042", // DESC_STR_SERIAL
- "Default Configuration", // DESC_STR_CONFIGURATION
- "Default Interface", // DESC_STR_INTERFACE
-};
-
-static const byte desc_languages[] = {
- 4, // bLength
- USB_DESC_TYPE_STRING, // bDescriptorType
- DESC_U16(1033), // English
-};
-
void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd)
{
memset(usb, 0, sizeof(*usb));
HAL_PCD_Start(usb->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;
-}
-
-static void usb_ctl_send_status(struct usb *usb)
+void usb_ctl_send_status(struct usb *usb)
{
usb_debug("Control send: status\n");
usb->ep0_state = USB_EP0_STATUS_IN;
usb_ep_transmit(usb, 0x00, NULL, 0);
}
-static void usb_ctl_recv_status(struct usb *usb)
+void usb_ctl_recv_status(struct usb *usb)
{
usb->ep0_state = USB_EP0_STATUS_OUT;
usb_ep_receive(usb, 0x00, NULL, 0);
}
-static void usb_ctl_send_data(struct usb *usb, const byte *data, uint len)
+void usb_ctl_send_data(struct usb *usb, const byte *data, uint len)
{
usb_debug("Control send: %u bytes\n", len);
usb->ep0_state = USB_EP0_DATA_IN;
usb_ep_transmit(usb, 0x00, data, len);
}
-#if 0 // FIXME
-static void usb_ctl_recv_data(struct usb *usb, byte *data, uint len)
+void usb_ctl_recv_data(struct usb *usb, byte *data, uint len)
{
usb_debug("Control recv: %u bytes\n", len);
usb->ep0_state = USB_EP0_DATA_OUT;
usb->ep0_remaining_length = len;
usb_ep_transmit(usb, 0x00, data, len);
}
-#endif
static void usb_ctl_send_byte(struct usb *usb, byte data)
{
static void usb_ctl_send_u16(struct usb *usb, u16 data)
{
- put_u16(usb->ep0_buf, data);
+ put_u16_le(usb->ep0_buf, data);
usb_ctl_send_data(usb, usb->ep0_buf, 2);
}
-static void usb_ctl_error(struct usb *usb)
+void usb_ctl_error(struct usb *usb)
{
usb_debug("Control packet error\n");
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)
+void usb_ctl_setup_error(struct usb *usb, struct setup_request *setup)
{
usb_debug("Setup packet error\n");
usb_ep_stall(usb, setup->bmRequest & USB_REQ_DIRECTION);
switch (desc_type)
{
case USB_DESC_TYPE_DEVICE:
- return dev_desc_send(usb, setup, desc_device, sizeof(desc_device));
+ return dev_desc_send(usb, setup, usb->desc_device, usb->desc_device_len);
case USB_DESC_TYPE_CONFIGURATION:
- return dev_desc_send(usb, setup, desc_config, sizeof(desc_config));
+ return dev_desc_send(usb, setup, usb->desc_config, usb->desc_config_len);
case USB_DESC_TYPE_STRING:
if (!desc_index)
- return dev_desc_send(usb, setup, desc_languages, sizeof(desc_languages));
- if (desc_index < sizeof(desc_string) / sizeof(desc_string[0]))
- return dev_desc_send_string(usb, setup, desc_string[desc_index]);
+ return dev_desc_send(usb, setup, usb->desc_languages, usb->desc_languages_len);
+ if (desc_index < usb->desc_string_items)
+ return dev_desc_send_string(usb, setup, usb->desc_string[desc_index]);
break;
case USB_DESC_TYPE_DEVICE_QUALIFIER:
- // FIXME
case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
- // FIXME
- // if (usb->hpcd->Init.speed == PCD_SPEED_HIGH)
- ;
+ // We do not support high-speed USB
+ break;
}
usb_ctl_error(usb);
{
usb->config = cfg;
usb->state = USB_STATE_CONFIGURED;
- // FIXME: Notify that the device was configured
+ usb_dev_configure(usb);
}
usb_ctl_send_status(usb);
break;
if (!cfg)
{
// Unconfiguring
+ usb_dev_unconfigure(usb);
usb->config = 0;
usb->state = USB_STATE_ADDRESSED;
- // FIXME: Notify that the device was unconfigured
}
else if (cfg != usb->config)
{
+ usb_dev_unconfigure(usb);
usb->config = cfg;
- // FIXME: Notify about configuration change
+ usb_dev_configure(usb);
}
usb_ctl_send_status(usb);
break;
if (!intf)
{
- // FIXME: Support more interfaces
+ // FIXME: Currently, we do not support more than 1 interface per configuration
usb_ctl_error(usb);
return;
}
static void usb_handle_setup(struct usb *usb, struct setup_request *setup)
{
usb_debug("Setup: type=%02x req=%02x val=%04x idx=%04x len=%04x\n", setup->bmRequest, setup->bRequest, setup->wValue, setup->wIndex, setup->wLength);
-
usb->ep0_state = USB_EP0_SETUP;
usb->ep0_setup_data_length = 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);
- }
+ if (usb_dev_setup_hook(usb, setup))
+ return;
- switch (setup->bmRequest & USB_REQ_RECIPIENT_MASK)
+ if ((setup->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
- 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);
+ 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);
struct setup_request setup = {
.bmRequest = req[0],
.bRequest = req[1],
- .wValue = get_u16(req+2),
- .wIndex = get_u16(req+4),
- .wLength = get_u16(req+6),
+ .wValue = get_u16_le(req+2),
+ .wIndex = get_u16_le(req+4),
+ .wLength = get_u16_le(req+6),
};
usb_handle_setup(usb, &setup);
}
else
{
if (usb->state == USB_STATE_CONFIGURED)
- {
- // FIXME: Handle incoming control packet
- }
+ usb_dev_ctl_recv_done(usb);
usb_ctl_send_status(usb);
}
}
else
{
if (usb->state == USB_STATE_CONFIGURED)
- {
- // FIXME: Custom data callback
- }
+ usb_dev_recv_done(usb, epnum);
}
}
else
{
if (usb->state == USB_STATE_CONFIGURED)
- {
- // FIXME: Custom data callback
- // All data have been sent
- }
+ usb_dev_ctl_send_done(usb);
usb_ctl_recv_status(usb);
}
}
else
{
if (usb->state == USB_STATE_CONFIGURED)
- {
- // FIXME: Custom data callback
- // This gets called when a complete message is sent
- }
+ usb_dev_send_done(usb, epnum);
}
}
}
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
-{
+{
struct usb *usb = hpcd->pData;
usb->state = USB_STATE_DEFAULT;
+ usb_dev_reset(usb);
usb_ep_open(usb, 0x00, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
usb_ep_open(usb, 0x80, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
--- /dev/null
+#include "stm32f1xx.h"
+#include "stm32f1xx_hal.h"
+
+#include "util.h"
+#include "usb.h"
+
+/*** Descriptors ***/
+
+#define DESC_U16(x) ((x) & 0xff), ((x) >> 8)
+
+enum desc_string {
+ DESC_STR_NONE = 0,
+ DESC_STR_MANUFACTURER,
+ DESC_STR_PRODUCT,
+ DESC_STR_SERIAL,
+ DESC_STR_CONFIGURATION,
+ DESC_STR_INTERFACE,
+};
+
+static const byte desc_device[] = {
+ 18, // bLength
+ USB_DESC_TYPE_DEVICE, // bDescriptorType
+ DESC_U16(0x0200), // bcdUSB
+ 0x00, // bDeviceClass
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ USB_MAX_EP0_SIZE, // bMaxPacketSize
+ DESC_U16(0x4242), // idVendor
+ DESC_U16(0x0001), // idProduct
+ DESC_U16(0x0200), // bcdDevice
+ DESC_STR_MANUFACTURER, // iManufacturer
+ DESC_STR_PRODUCT, // iProduct
+ DESC_STR_SERIAL, // iSerialNumber
+ USB_NUM_CONFIGURATIONS, // bNumConfigurations
+};
+
+static const byte desc_config[] = {
+ // Configuration descriptor
+ 9, // bLength
+ USB_DESC_TYPE_CONFIGURATION, // bDescriptorType
+ 32, // wTotalLength
+ 0,
+ 0x01, // bNumInterfaces
+ 0x01, // bConfigurationValue
+ DESC_STR_CONFIGURATION, // iConfiguration
+ 0xc0, // bmAttributes: bus-powered, supports remote wakeup
+ 0x32, // Max power: 100 mA
+ // Interface descriptor
+ 9, // bLength
+ USB_DESC_TYPE_INTERFACE, // bDescriptorType
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndpoints
+ 0xff, // bInterfaceClass: vendor-defined
+ 0x00, // bInterfaceSubClass
+ 0x00, // nInterfaceProtocol
+ DESC_STR_INTERFACE, // iInterface
+ // End-point descriptor
+ 7, // bLength
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType
+ 0x01, // bEndpointAddress
+ USB_EP_TYPE_BULK, // bmAttributes
+ 0x40, 0x00, // wMaxPacketSize
+ 0x00, // bInterval: unused
+ // End-point descriptor
+ 7, // bLength
+ USB_DESC_TYPE_ENDPOINT, // bDescriptorType
+ 0x81, // bEndpointAddress
+ USB_EP_TYPE_BULK, // bmAttributes
+ 0x40, 0x00, // wMaxPacketSize
+ 0x00, // bInterval: unused
+};
+
+static const char * const desc_string[] = {
+ NULL, // DESC_STR_NONE
+ "United Computer Wizards", // DESC_STR_MANUFACTURER
+ "Mysterious Gadget", // DESC_STR_PRODUCT
+ "00000042", // DESC_STR_SERIAL
+ "Default Configuration", // DESC_STR_CONFIGURATION
+ "Default Interface", // DESC_STR_INTERFACE
+};
+
+static const byte desc_languages[] = {
+ 4, // bLength
+ USB_DESC_TYPE_STRING, // bDescriptorType
+ DESC_U16(1033), // English
+};
+
+/*** Callbacks ***/
+
+void usb_dev_reset(struct usb *usb)
+{
+ usb->desc_device = desc_device;
+ usb->desc_device_len = sizeof(desc_device);
+ usb->desc_config = desc_config;
+ usb->desc_config_len = sizeof(desc_config);
+ usb->desc_string = desc_string;
+ usb->desc_string_items = sizeof(desc_string) / sizeof(desc_string[0]);
+ usb->desc_languages = desc_languages;
+ usb->desc_languages_len = sizeof(desc_languages);
+}
+
+void usb_dev_configure(struct usb *usb)
+{
+}
+
+void usb_dev_unconfigure(struct usb *usb)
+{
+}
+
+bool usb_dev_setup_hook(struct usb *usb, struct setup_request *setup)
+{
+ return false;
+}
+
+void usb_dev_ctl_recv_done(struct usb *usb)
+{
+}
+
+void usb_dev_ctl_send_done(struct usb *usb)
+{
+}
+
+void usb_dev_recv_done(struct usb *usb, byte epnum)
+{
+}
+
+void usb_dev_send_done(struct usb *usb, byte epnum)
+{
+}