X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=Src%2Fusb.c;h=c6867da79b8a7bec04c45e0c1abcf9642d741c57;hb=2fe5a1535ede515a5f2037f9323e7d960358ad96;hp=434408db3100c2c97b2b35477a00794eec973301;hpb=f0a255055982a16d6d0a3f58ef959a2389edbbd7;p=home-hw.git diff --git a/Src/usb.c b/Src/usb.c index 434408d..c6867da 100644 --- a/Src/usb.c +++ b/Src/usb.c @@ -1,90 +1,81 @@ #include "stm32f1xx.h" #include "stm32f1xx_hal.h" +#include "util.h" #include "usb.h" -void _Error_Handler(char * file, int line); // FIXME +#include 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); -} - -static inline uint get_u16(byte *p) -{ - return (p[1] << 8) | p[0]; + hpcd->pData = usb; } -static inline void put_u16(byte *p, u16 x) +void usb_start(struct usb *usb) { - p[0] = x; - p[1] = x >> 8; -} + HAL_PCDEx_PMAConfig(usb->hpcd, 0x00, PCD_SNG_BUF, 0x18); + HAL_PCDEx_PMAConfig(usb->hpcd, 0x80, PCD_SNG_BUF, 0x58); -#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); + HAL_PCD_Start(usb->hpcd); } -#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); } -#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->ep0_total_length = len; + usb->ep0_remaining_length = len; + usb_ep_transmit(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_transmit(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); } @@ -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) { + 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) @@ -185,7 +223,7 @@ static void dev_set_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; @@ -193,14 +231,15 @@ static void dev_set_configuration(struct usb *usb, struct setup_request *setup) 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; @@ -238,7 +277,7 @@ static void intf_setup(struct usb *usb, struct setup_request *setup) if (!intf) { - // FIXME: Support more interfaces + // FIXME: Currently, we do not support more than 1 interface per configuration 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) { + 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); @@ -370,9 +409,9 @@ void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd) 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); } @@ -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; - 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_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 { 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)