+#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)
+{
+}