]> mj.ucw.cz Git - home-hw.git/blobdiff - Src/usb.c
Converting I2C to DMA
[home-hw.git] / Src / usb.c
index 434408db3100c2c97b2b35477a00794eec973301..ffac01d0e768ac94c08786519b0dc0bd52d95d6e 100644 (file)
--- a/Src/usb.c
+++ b/Src/usb.c
@@ -1,90 +1,81 @@
 #include "stm32f1xx.h"
 #include "stm32f1xx_hal.h"
 
 #include "stm32f1xx.h"
 #include "stm32f1xx_hal.h"
 
+#include "util.h"
 #include "usb.h"
 
 #include "usb.h"
 
-void _Error_Handler(char * file, int line);    // FIXME
+#include <string.h>
 
 void usb_init(struct usb *usb, PCD_HandleTypeDef *hpcd)
 {
 
 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;
   usb->hpcd = hpcd;
   usb->state = USB_STATE_DEFAULT;
   usb->ep0_state = USB_EP0_IDLE;
-
-  HAL_PCDEx_PMAConfig(hpcd, 0x00, PCD_SNG_BUF, 0x18);
-  HAL_PCDEx_PMAConfig(hpcd, 0x80, PCD_SNG_BUF, 0x58);
-
-  HAL_PCD_Start(hpcd);
+  hpcd->pData = usb;
 }
 
 }
 
-static inline uint get_u16(byte *p)
+void usb_start(struct usb *usb)
 {
 {
-  return (p[1] << 8) | p[0];
-}
+  HAL_PCDEx_PMAConfig(usb->hpcd, 0x00, PCD_SNG_BUF, 0x18);
+  HAL_PCDEx_PMAConfig(usb->hpcd, 0x80, PCD_SNG_BUF, 0x58);
 
 
-static inline void put_u16(byte *p, u16 x)
-{
-  p[0] = x;
-  p[1] = x >> 8;
+  HAL_PCD_Start(usb->hpcd);
 }
 
 }
 
-#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)
+void usb_ctl_send_status(struct usb *usb)
 {
 {
+  usb_debug("Control send: status\n");
   usb->ep0_state = USB_EP0_STATUS_IN;
   usb->ep0_state = USB_EP0_STATUS_IN;
-  usb_ep_transmit(usb, 0x00, NULL, 0);
+  usb_ep_send(usb, 0x00, NULL, 0);
 }
 
 }
 
-#if 0  // FIXME
-static void usb_ctl_recv_status(struct usb *usb)
+void usb_ctl_recv_status(struct usb *usb)
 {
   usb->ep0_state = USB_EP0_STATUS_OUT;
   usb_ep_receive(usb, 0x00, NULL, 0);
 }
 {
   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)
+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->ep0_state = USB_EP0_DATA_IN;
-  usb->ep_in[0].total_length = len;
-  usb->ep_in[0].remaining_length = len;
-  usb_ep_transmit(usb, 0x00, data, len);
+  usb->ep0_total_length = len;
+  usb->ep0_remaining_length = len;
+  usb_ep_send(usb, 0x00, data, len);
+}
+
+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_send(usb, 0x00, data, len);
 }
 
 static void usb_ctl_send_byte(struct usb *usb, byte data)
 {
 }
 
 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)
 {
 }
 
 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_le(usb->ep0_buf, data);
+  usb_ctl_send_data(usb, usb->ep0_buf, 2);
 }
 
 }
 
-static void usb_ctl_error(struct usb *usb)
+void usb_ctl_error(struct usb *usb)
 {
 {
+  usb_debug("Control packet error\n");
   usb_ep_stall(usb, 0x00);
   usb_ep_stall(usb, 0x80);
 }
 
   usb_ep_stall(usb, 0x00);
   usb_ep_stall(usb, 0x80);
 }
 
-struct setup_request {
-  byte bmRequest;
-  byte bRequest;
-  u16 wValue;
-  u16 wIndex;
-  u16 wLength;
-};
-
-static void usb_ctl_setup_error(struct usb *usb, struct setup_request *setup)
+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);
 }
 
   usb_ep_stall(usb, setup->bmRequest & USB_REQ_DIRECTION);
 }
 
@@ -148,8 +139,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)
 {
 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, usb->desc_device, usb->desc_device_len);
+    case USB_DESC_TYPE_CONFIGURATION:
+      return dev_desc_send(usb, setup, usb->desc_config, usb->desc_config_len);
+    case USB_DESC_TYPE_STRING:
+      if (!desc_index)
+       return dev_desc_send(usb, setup, usb->desc_languages, usb->desc_languages_len);
+      if (desc_index < usb->desc_string_items)
+       return dev_desc_send_string(usb, setup, usb->desc_string[desc_index]);
+      break;
+    case USB_DESC_TYPE_DEVICE_QUALIFIER:
+    case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
+      // We do not support high-speed USB
+      break;
+    }
+
+  usb_ctl_error(usb);
 }
 
 static void dev_get_configuration(struct usb *usb, struct setup_request *setup)
 }
 
 static void dev_get_configuration(struct usb *usb, struct setup_request *setup)
@@ -185,7 +223,7 @@ static void dev_set_configuration(struct usb *usb, struct setup_request *setup)
        {
          usb->config = cfg;
          usb->state = USB_STATE_CONFIGURED;
        {
          usb->config = cfg;
          usb->state = USB_STATE_CONFIGURED;
-         // FIXME: Notify that the device was configured
+         usb_dev_configure(usb);
        }
       usb_ctl_send_status(usb);
       break;
        }
       usb_ctl_send_status(usb);
       break;
@@ -193,14 +231,15 @@ static void dev_set_configuration(struct usb *usb, struct setup_request *setup)
       if (!cfg)
        {
          // Unconfiguring
       if (!cfg)
        {
          // Unconfiguring
+         usb_dev_unconfigure(usb);
          usb->config = 0;
          usb->state = USB_STATE_ADDRESSED;
          usb->config = 0;
          usb->state = USB_STATE_ADDRESSED;
-         // FIXME: Notify that the device was unconfigured
        }
       else if (cfg != usb->config)
        {
        }
       else if (cfg != usb->config)
        {
+         usb_dev_unconfigure(usb);
          usb->config = cfg;
          usb->config = cfg;
-         // FIXME: Notify about configuration change
+         usb_dev_configure(usb);
        }
       usb_ctl_send_status(usb);
       break;
        }
       usb_ctl_send_status(usb);
       break;
@@ -238,7 +277,7 @@ static void intf_setup(struct usb *usb, struct setup_request *setup)
 
   if (!intf)
     {
 
   if (!intf)
     {
-      // FIXME: Support more interfaces
+      // FIXME: Currently, we do not support more than 1 interface per configuration
       usb_ctl_error(usb);
       return;
     }
       usb_ctl_error(usb);
       return;
     }
@@ -339,24 +378,24 @@ static void ep_setup(struct usb *usb, struct setup_request *setup)
 
 static void usb_handle_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_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)
-    {
-      // FIXME: Class-specific and vendor-specific setup packets not supported
-      // FIXME: Check USB_STATE_CONFIGURED here
-      usb_ctl_setup_error(usb, setup);
-    }
+  if (usb_dev_setup_hook(usb, setup))
+    return;
 
 
-  switch (setup->bmRequest & USB_REQ_RECIPIENT_MASK)
+  if ((setup->bmRequest & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
     {
     {
-    case USB_REQ_RECIPIENT_DEVICE:
-      return dev_setup(usb, setup);
-    case USB_REQ_RECIPIENT_INTERFACE:
-      return intf_setup(usb, setup);
-    case USB_REQ_RECIPIENT_ENDPOINT:
-      return ep_setup(usb, setup);
+      switch (setup->bmRequest & USB_REQ_RECIPIENT_MASK)
+       {
+       case USB_REQ_RECIPIENT_DEVICE:
+         return dev_setup(usb, setup);
+       case USB_REQ_RECIPIENT_INTERFACE:
+         return intf_setup(usb, setup);
+       case USB_REQ_RECIPIENT_ENDPOINT:
+         return ep_setup(usb, setup);
+       }
     }
 
   usb_ctl_setup_error(usb, setup);
     }
 
   usb_ctl_setup_error(usb, setup);
@@ -370,9 +409,9 @@ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
   struct setup_request setup = {
     .bmRequest = req[0],
     .bRequest = req[1],
   struct setup_request setup = {
     .bmRequest = req[0],
     .bRequest = req[1],
-    .wValue = get_u16(req+2),
-    .wIndex = get_u16(req+4),
-    .wLength = get_u16(req+2),
+    .wValue = get_u16_le(req+2),
+    .wIndex = get_u16_le(req+4),
+    .wLength = get_u16_le(req+6),
   };
   usb_handle_setup(usb, &setup);
 }
   };
   usb_handle_setup(usb, &setup);
 }
@@ -380,93 +419,90 @@ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
 void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
 {
   struct usb *usb = hpcd->pData;
 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)
     {
 
   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 (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
        {
          if (usb->state == USB_STATE_CONFIGURED)
        }
       else
        {
          if (usb->state == USB_STATE_CONFIGURED)
-           {
-             // FIXME: Handle incoming control packet
-           }
+           usb_dev_ctl_recv_done(usb);
          usb_ctl_send_status(usb);
        }
     }
   else
     {
       if (usb->state == USB_STATE_CONFIGURED)
          usb_ctl_send_status(usb);
        }
     }
   else
     {
       if (usb->state == USB_STATE_CONFIGURED)
-       {
-         // FIXME: Custom data callback
-       }
+       usb_dev_recv_done(usb, epnum);
     }
 }
 
 void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
 {
   struct usb *usb = hpcd->pData;
     }
 }
 
 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)
     {
 
   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 (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_send(usb, 0x00, ep->xfer_buff, usb->ep0_remaining_length);
          usb_ep_receive(usb, 0x00, NULL, 0);
        }
          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
-         usb_ep_transmit(usb, 0x00, NULL, 0);
-         usb->ep0_data_len = 0;
+         /*
+          *  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_send(usb, 0x00, NULL, 0);
+         usb->ep0_setup_data_length = 0;
          usb_ep_receive(usb, 0x00, NULL, 0);
        }
       else
        {
          if (usb->state == USB_STATE_CONFIGURED)
          usb_ep_receive(usb, 0x00, NULL, 0);
        }
       else
        {
          if (usb->state == USB_STATE_CONFIGURED)
-           {
-             // FIXME: Custom data callback
-           }
+           usb_dev_ctl_send_done(usb);
+         usb_ctl_recv_status(usb);
        }
     }
   else
     {
       if (usb->state == USB_STATE_CONFIGURED)
        }
     }
   else
     {
       if (usb->state == USB_STATE_CONFIGURED)
-       {
-         // FIXME: Custom data callback
-       }
+       usb_dev_send_done(usb, epnum);
     }
 }
 
 void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
 {
     }
 }
 
 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)
 }
 
 void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
-{ 
+{
   struct usb *usb = hpcd->pData;
 
   usb->state = USB_STATE_DEFAULT;
   struct usb *usb = hpcd->pData;
 
   usb->state = USB_STATE_DEFAULT;
-  usb->speed = hpcd->Init.speed;
+  usb_dev_reset(usb);
 
   usb_ep_open(usb, 0x00, USB_EP_TYPE_CTRL, USB_MAX_EP0_SIZE);
 
   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_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)
 }
 
 void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)