#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
+#include "util.h"
#include "usb.h"
-void _Error_Handler(char * file, int line); // FIXME
+#include <string.h>
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;
-
- 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_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);
}
-#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->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)
{
- 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_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);
}
-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);
}
}
}
+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, 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)
{
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;
if (!cfg)
{
// Unconfiguring
+ usb_dev_unconfigure(usb);
usb->config = 0;
usb->state = USB_STATE_ADDRESSED;
- // FIXME: Notify that the device was unconfigured
}
else if (cfg != usb->config)
{
+ usb_dev_unconfigure(usb);
usb->config = cfg;
- // FIXME: Notify about configuration change
+ usb_dev_configure(usb);
}
usb_ctl_send_status(usb);
break;
if (!intf)
{
- // FIXME: Support more interfaces
+ // FIXME: Currently, we do not support more than 1 interface per configuration
usb_ctl_error(usb);
return;
}
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)
- {
- // 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);
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);
}
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
{
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)
- {
- // 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;
- 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_send(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
- 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)
- {
- // FIXME: Custom data callback
- }
+ usb_dev_ctl_send_done(usb);
+ usb_ctl_recv_status(usb);
}
}
else
{
if (usb->state == USB_STATE_CONFIGURED)
- {
- // FIXME: Custom data callback
- }
+ usb_dev_send_done(usb, epnum);
}
}
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)
-{
+{
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_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)