]> mj.ucw.cz Git - home-hw.git/commitdiff
Basic handling of descriptors
authorMartin Mares <mj@ucw.cz>
Sun, 24 Jun 2018 12:19:33 +0000 (14:19 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 24 Jun 2018 12:19:33 +0000 (14:19 +0200)
Inc/usb.h
Src/usb.c

index 589774d6af50e02404e6fa48976edcc392e6f049..1d8291ff61e53a580a8be62fcd66bac1e1d1d86c 100644 (file)
--- 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)
index b7604abd7e28162684719c6483cb37e5893b6239..2c366e2c725780ae192e226571570c8d68953ce7 100644 (file)
--- 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)