#define USB_SELF_POWERED
+#define USB_NUM_CONFIGURATIONS 1
typedef unsigned int uint;
typedef uint8_t byte;
/*** USB state structure ***/
+/*
+ * We have a single buffer for all control transfers.
+ * It must be able to contain:
+ *
+ * - 2-byte status replies
+ * - UTF-16 versions of all string descriptors
+ *
+ * In addition to that, its length must be even.
+ */
+#define USB_EP0_BUF_SIZE 256
+
struct usb {
PCD_HandleTypeDef *hpcd;
byte state; // USB_STATE_xxx
u16 ep0_setup_data_length;
u16 ep0_remaining_length;
u16 ep0_total_length;
- byte status_buf[2];
+ byte ep0_buf[USB_EP0_BUF_SIZE];
};
void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd);
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)
+static inline HAL_StatusTypeDef usb_ep_transmit(struct usb *usb, byte ep_addr, const byte *buf, u32 size)
{
- return HAL_PCD_EP_Transmit(usb->hpcd, ep_addr, buf, size);
+ return HAL_PCD_EP_Transmit(usb->hpcd, ep_addr, (byte *) buf, size);
}
static inline HAL_StatusTypeDef usb_ep_receive(struct usb *usb, byte ep_addr, byte *buf, u32 size)
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
+ 0x01, // 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[] = {
+ "", // 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
+};
+
void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd)
{
memset(usb, 0, sizeof(*usb));
}
#endif
-static void usb_ctl_send_data(struct usb *usb, byte *data, uint len)
+static void usb_ctl_send_data(struct usb *usb, const byte *data, uint len)
{
usb->ep0_state = USB_EP0_DATA_IN;
usb->ep0_total_length = 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);
+ usb->ep0_buf[0] = data;
+ usb_ctl_send_data(usb, usb->ep0_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);
+ put_u16(usb->ep0_buf, data);
+ usb_ctl_send_data(usb, usb->ep0_buf, 2);
}
static void usb_ctl_error(struct usb *usb)
}
}
+static void dev_desc_send(struct usb *usb, struct setup_request *setup, const byte *desc, uint len)
+{
+ len = MIN(len, setup->wLength);
+ if (len)
+ usb_ctl_send_data(usb, desc, len);
+}
+
+static void dev_desc_send_string(struct usb *usb, struct setup_request *setup, const char *str)
+{
+ byte *buf = usb->ep0_buf;
+ uint len = strlen(str);
+ uint i = 0;
+
+ buf[i++] = 2*len + 2;
+ buf[i++] = USB_DESC_TYPE_STRING;
+
+ while (i <= USB_EP0_BUF_SIZE - 2 && *str)
+ {
+ buf[i++] = *str++;
+ buf[i++] = 0;
+ }
+
+ dev_desc_send(usb, setup, buf, i);
+}
+
static void dev_get_descriptor(struct usb *usb, struct setup_request *setup)
{
+ byte desc_type = setup->wValue >> 8;
+ byte desc_index = setup->wValue & 0xff;
+
+ switch (desc_type)
+ {
+ case USB_DESC_TYPE_DEVICE:
+ return dev_desc_send(usb, setup, desc_device, sizeof(desc_device));
+ case USB_DESC_TYPE_CONFIGURATION:
+ return dev_desc_send(usb, setup, desc_config, sizeof(desc_config));
+ case USB_DESC_TYPE_STRING:
+ if (desc_index < sizeof(desc_string) / sizeof(desc_string[0]))
+ return dev_desc_send_string(usb, setup, 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)
+ ;
+ }
+
+ usb_ctl_error(usb);
}
static void dev_get_configuration(struct usb *usb, struct setup_request *setup)