From 1de7d1160ef286ba7ba1c63d7ecab977bdf2362d Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 24 Jun 2018 14:19:33 +0200 Subject: [PATCH] Basic handling of descriptors --- Inc/usb.h | 18 ++++++-- Src/usb.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 141 insertions(+), 8 deletions(-) diff --git a/Inc/usb.h b/Inc/usb.h index 589774d..1d8291f 100644 --- a/Inc/usb.h +++ b/Inc/usb.h @@ -1,4 +1,5 @@ #define USB_SELF_POWERED +#define USB_NUM_CONFIGURATIONS 1 typedef unsigned int uint; typedef uint8_t byte; @@ -12,6 +13,17 @@ typedef int32_t s32; /*** 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 @@ -23,7 +35,7 @@ struct usb { 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); @@ -144,9 +156,9 @@ 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) +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) diff --git a/Src/usb.c b/Src/usb.c index b7604ab..2c366e2 100644 --- a/Src/usb.c +++ b/Src/usb.c @@ -7,6 +7,80 @@ 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)); @@ -52,7 +126,7 @@ static void usb_ctl_recv_status(struct usb *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; @@ -72,14 +146,14 @@ static void usb_ctl_recv_data(struct usb *usb, byte *data, uint 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) @@ -161,8 +235,55 @@ static void dev_set_address(struct usb *usb, struct setup_request *setup) } } +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) -- 2.39.2