]> mj.ucw.cz Git - home-hw.git/blobdiff - Src/usb.c
More USB debugging
[home-hw.git] / Src / usb.c
index 434408db3100c2c97b2b35477a00794eec973301..b7f731331e89a3b51f7fadb1714db6c80d98d6dc 100644 (file)
--- a/Src/usb.c
+++ b/Src/usb.c
 #include "stm32f1xx.h"
 #include "stm32f1xx_hal.h"
 
+#include "util.h"
 #include "usb.h"
 
+#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));
   usb->hpcd = hpcd;
   usb->state = USB_STATE_DEFAULT;
   usb->ep0_state = USB_EP0_IDLE;
+  hpcd->pData = usb;
+}
 
-  HAL_PCDEx_PMAConfig(hpcd, 0x00, PCD_SNG_BUF, 0x18);
-  HAL_PCDEx_PMAConfig(hpcd, 0x80, PCD_SNG_BUF, 0x58);
+void usb_start(struct usb *usb)
+{
+  HAL_PCDEx_PMAConfig(usb->hpcd, 0x00, PCD_SNG_BUF, 0x18);
+  HAL_PCDEx_PMAConfig(usb->hpcd, 0x80, PCD_SNG_BUF, 0x58);
 
-  HAL_PCD_Start(hpcd);
+  HAL_PCD_Start(usb->hpcd);
 }
 
 static inline uint get_u16(byte *p)
@@ -28,49 +116,54 @@ static inline void put_u16(byte *p, u16 x)
   p[1] = x >> 8;
 }
 
-#if 0  // FIXME
-static struct usb_endpoint *ep_by_addr(struct usb *usb, byte ep_addr)
-{
-  return ((ep_addr & 0x80) ? usb->ep_in : usb->ep_out) + (ep_addr & 0x7f);
-}
-#endif
-
 static 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);
 }
 
-#if 0  // FIXME
 static void usb_ctl_recv_status(struct usb *usb)
 {
   usb->ep0_state = USB_EP0_STATUS_OUT;
   usb_ep_receive(usb, 0x00, NULL, 0);
 }
-#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_debug("Control send: %u bytes\n", len);
   usb->ep0_state = USB_EP0_DATA_IN;
-  usb->ep_in[0].total_length = len;
-  usb->ep_in[0].remaining_length = len;
+  usb->ep0_total_length = len;
+  usb->ep0_remaining_length = len;
   usb_ep_transmit(usb, 0x00, data, len);
 }
 
+#if 0  // FIXME
+static 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_total_length = len;
+  usb->ep0_remaining_length = len;
+  usb_ep_transmit(usb, 0x00, data, len);
+}
+#endif
+
 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)
 {
+  usb_debug("Control packet error\n");
   usb_ep_stall(usb, 0x00);
   usb_ep_stall(usb, 0x80);
 }
@@ -85,6 +178,7 @@ struct setup_request {
 
 static 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);
 }
 
@@ -148,8 +242,57 @@ 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)
+       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]);
+      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)
@@ -339,8 +482,10 @@ static void ep_setup(struct usb *usb, struct setup_request *setup)
 
 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_data_len = setup->wLength;
+  usb->ep0_setup_data_length = setup->wLength;
 
   if ((setup->bmRequest & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
     {
@@ -372,7 +517,7 @@ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
     .bRequest = req[1],
     .wValue = get_u16(req+2),
     .wIndex = get_u16(req+4),
-    .wLength = get_u16(req+2),
+    .wLength = get_u16(req+6),
   };
   usb_handle_setup(usb, &setup);
 }
@@ -380,17 +525,18 @@ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
 void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
 {
   struct usb *usb = hpcd->pData;
-  struct usb_endpoint *ep = &usb->ep_out[epnum];
-  byte *data = hpcd->OUT_ep[epnum].xfer_buff;
+  PCD_EPTypeDef *ep = &hpcd->IN_ep[epnum];
 
   if (!epnum)
     {
+      // HAL/LL handle EP0 transfers in a completely different way, we have to do many things ourselves
+      usb_debug("Ep0 OUT: state=%u rem=%u total=%u\n", usb->ep0_state, usb->ep0_remaining_length, usb->ep0_total_length);
       if (usb->ep0_state != USB_EP0_DATA_OUT)
        return;
-      if (ep->remaining_length > ep->max_packet_size)
+      if (usb->ep0_remaining_length > ep->maxpacket)
        {
-         ep->remaining_length -= ep->max_packet_size;
-         usb_ep_receive(usb, 0x00, data, MIN(ep->remaining_length, ep->max_packet_size));
+         usb->ep0_remaining_length -= ep->maxpacket;
+         usb_ep_receive(usb, 0x00, ep->xfer_buff, MIN(usb->ep0_remaining_length, ep->maxpacket));
        }
       else
        {
@@ -413,24 +559,29 @@ void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
 void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
 {
   struct usb *usb = hpcd->pData;
-  struct usb_endpoint *ep = &usb->ep_in[epnum];
-  byte *data = hpcd->IN_ep[epnum].xfer_buff;
+  PCD_EPTypeDef *ep = &hpcd->IN_ep[epnum];
 
   if (!epnum)
     {
+      // HAL/LL handle EP0 transfers in a completely different way, we have to do many things ourselves
+      usb_debug("Ep0 IN: state=%u rem=%u total=%u want=%u\n", usb->ep0_state, usb->ep0_remaining_length, usb->ep0_total_length, usb->ep0_setup_data_length);
       if (usb->ep0_state != USB_EP0_DATA_IN)
        return;
-      if (ep->remaining_length > ep->max_packet_size)
+      if (usb->ep0_remaining_length > ep->maxpacket)
        {
-         ep->remaining_length -= ep->max_packet_size;
-         usb_ep_transmit(usb, 0x00, data, ep->remaining_length);
+         usb->ep0_remaining_length -= ep->maxpacket;
+         usb_ep_transmit(usb, 0x00, ep->xfer_buff, usb->ep0_remaining_length);
          usb_ep_receive(usb, 0x00, NULL, 0);
        }
-      else if (ep->total_length && ep->total_length % ep->max_packet_size == 0 && ep->total_length < usb->ep0_data_len)
+      else if (usb->ep0_total_length && usb->ep0_total_length % ep->maxpacket == 0 && usb->ep0_total_length < usb->ep0_setup_data_length)
        {
-         // Send an empty packet if total length is divisible by MTU
+         /*
+          *  Each data transfer must be terminated by either a small packet (less than maxpacket)
+          *  or by reaching the answer size requested in the setup packet. Send an empty final packet
+          *  if needed.
+          */
          usb_ep_transmit(usb, 0x00, NULL, 0);
-         usb->ep0_data_len = 0;
+         usb->ep0_setup_data_length = 0;
          usb_ep_receive(usb, 0x00, NULL, 0);
        }
       else
@@ -438,7 +589,9 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
          if (usb->state == USB_STATE_CONFIGURED)
            {
              // FIXME: Custom data callback
+             // All data have been sent
            }
+         usb_ctl_recv_status(usb);
        }
     }
   else
@@ -446,13 +599,15 @@ void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
       if (usb->state == USB_STATE_CONFIGURED)
        {
          // FIXME: Custom data callback
+         // This gets called when a complete message is sent
        }
     }
 }
 
 void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
 {
-  // FIXME
+  // We are not interested in Start of frame packets
+  // (neither we set hpcd->Init.Sof_enable, so this callback does not get called)
 }
 
 void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
@@ -460,13 +615,9 @@ void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
   struct usb *usb = hpcd->pData;
 
   usb->state = USB_STATE_DEFAULT;
-  usb->speed = hpcd->Init.speed;
 
   usb_ep_open(usb, 0x00, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
-  usb->ep_out[0].max_packet_size = USB_MAX_EP0_SIZE;
-
   usb_ep_open(usb, 0x80, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
-  usb->ep_in[0].max_packet_size = USB_MAX_EP0_SIZE;
 }
 
 void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)