/* * Copyright (c) 2022, sakumisu * * SPDX-License-Identifier: Apache-2.0 */ #include "usbd_core.h" #include "usb_musb_reg.h" #define HWREG(x) \ (*((volatile uint32_t *)(x))) #define HWREGH(x) \ (*((volatile uint16_t *)(x))) #define HWREGB(x) \ (*((volatile uint8_t *)(x))) #define USB_BASE (g_usbdev_bus[0].reg_base) #if defined(CONFIG_USB_MUSB_SUNXI) #define MUSB_FADDR_OFFSET 0x98 #define MUSB_POWER_OFFSET 0x40 #define MUSB_TXIS_OFFSET 0x44 #define MUSB_RXIS_OFFSET 0x46 #define MUSB_TXIE_OFFSET 0x48 #define MUSB_RXIE_OFFSET 0x4A #define MUSB_IS_OFFSET 0x4C #define MUSB_IE_OFFSET 0x50 #define MUSB_EPIDX_OFFSET 0x42 #define MUSB_IND_TXMAP_OFFSET 0x80 #define MUSB_IND_TXCSRL_OFFSET 0x82 #define MUSB_IND_TXCSRH_OFFSET 0x83 #define MUSB_IND_RXMAP_OFFSET 0x84 #define MUSB_IND_RXCSRL_OFFSET 0x86 #define MUSB_IND_RXCSRH_OFFSET 0x87 #define MUSB_IND_RXCOUNT_OFFSET 0x88 #define MUSB_FIFO_OFFSET 0x00 #define MUSB_DEVCTL_OFFSET 0x41 #define MUSB_TXFIFOSZ_OFFSET 0x90 #define MUSB_RXFIFOSZ_OFFSET 0x94 #define MUSB_TXFIFOADD_OFFSET 0x92 #define MUSB_RXFIFOADD_OFFSET 0x96 #elif defined(CONFIG_USB_MUSB_CUSTOM) #include "musb_custom.h" #else #define MUSB_FADDR_OFFSET 0x00 #define MUSB_POWER_OFFSET 0x01 #define MUSB_TXIS_OFFSET 0x02 #define MUSB_RXIS_OFFSET 0x04 #define MUSB_TXIE_OFFSET 0x06 #define MUSB_RXIE_OFFSET 0x08 #define MUSB_IS_OFFSET 0x0A #define MUSB_IE_OFFSET 0x0B #define MUSB_EPIDX_OFFSET 0x0E #define MUSB_IND_TXMAP_OFFSET 0x10 #define MUSB_IND_TXCSRL_OFFSET 0x12 #define MUSB_IND_TXCSRH_OFFSET 0x13 #define MUSB_IND_RXMAP_OFFSET 0x14 #define MUSB_IND_RXCSRL_OFFSET 0x16 #define MUSB_IND_RXCSRH_OFFSET 0x17 #define MUSB_IND_RXCOUNT_OFFSET 0x18 #define MUSB_FIFO_OFFSET 0x20 #define MUSB_DEVCTL_OFFSET 0x60 #define MUSB_TXFIFOSZ_OFFSET 0x62 #define MUSB_RXFIFOSZ_OFFSET 0x63 #define MUSB_TXFIFOADD_OFFSET 0x64 #define MUSB_RXFIFOADD_OFFSET 0x66 #endif // CONFIG_USB_MUSB_SUNXI #define USB_FIFO_BASE(ep_idx) (USB_BASE + MUSB_FIFO_OFFSET + 0x4 * ep_idx) typedef enum { USB_EP0_STATE_SETUP = 0x0, /**< SETUP DATA */ USB_EP0_STATE_IN_DATA = 0x1, /**< IN DATA */ USB_EP0_STATE_OUT_DATA = 0x3, /**< OUT DATA */ USB_EP0_STATE_IN_STATUS = 0x4, /**< IN status */ USB_EP0_STATE_OUT_STATUS = 0x5, /**< OUT status */ USB_EP0_STATE_IN_ZLP = 0x6, /**< OUT status */ USB_EP0_STATE_STALL = 0x7, /**< STALL status */ } ep0_state_t; /* Endpoint state */ struct musb_ep_state { uint16_t ep_mps; /* Endpoint max packet size */ uint8_t ep_type; /* Endpoint type */ uint8_t ep_stalled; /* Endpoint stall flag */ uint8_t ep_enable; /* Endpoint enable */ uint8_t *xfer_buf; uint32_t xfer_len; uint32_t actual_xfer_len; }; /* Driver state */ struct musb_udc { volatile uint8_t dev_addr; __attribute__((aligned(32))) struct usb_setup_packet setup; struct musb_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/ struct musb_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */ } g_musb_udc; static volatile uint8_t usb_ep0_state = USB_EP0_STATE_SETUP; /* get current active ep */ static uint8_t musb_get_active_ep(void) { return HWREGB(USB_BASE + MUSB_EPIDX_OFFSET); } /* set the active ep */ static void musb_set_active_ep(uint8_t ep_index) { HWREGB(USB_BASE + MUSB_EPIDX_OFFSET) = ep_index; } static void musb_write_packet(uint8_t ep_idx, uint8_t *buffer, uint16_t len) { uint32_t *buf32; uint8_t *buf8; uint32_t count32; uint32_t count8; int i; if ((uint32_t)buffer & 0x03) { buf8 = buffer; for (i = 0; i < len; i++) { HWREGB(USB_FIFO_BASE(ep_idx)) = *buf8++; } } else { count32 = len >> 2; count8 = len & 0x03; buf32 = (uint32_t *)buffer; while (count32--) { HWREG(USB_FIFO_BASE(ep_idx)) = *buf32++; } buf8 = (uint8_t *)buf32; while (count8--) { HWREGB(USB_FIFO_BASE(ep_idx)) = *buf8++; } } } static void musb_read_packet(uint8_t ep_idx, uint8_t *buffer, uint16_t len) { uint32_t *buf32; uint8_t *buf8; uint32_t count32; uint32_t count8; int i; if ((uint32_t)buffer & 0x03) { buf8 = buffer; for (i = 0; i < len; i++) { *buf8++ = HWREGB(USB_FIFO_BASE(ep_idx)); } } else { count32 = len >> 2; count8 = len & 0x03; buf32 = (uint32_t *)buffer; while (count32--) { *buf32++ = HWREG(USB_FIFO_BASE(ep_idx)); } buf8 = (uint8_t *)buf32; while (count8--) { *buf8++ = HWREGB(USB_FIFO_BASE(ep_idx)); } } } static uint32_t musb_get_fifo_size(uint16_t mps, uint16_t *used) { uint32_t size; for (uint8_t i = USB_TXFIFOSZ_SIZE_8; i <= USB_TXFIFOSZ_SIZE_2048; i++) { size = (8 << i); if (mps <= size) { *used = size; return i; } } *used = 0; return USB_TXFIFOSZ_SIZE_8; } static uint32_t usbd_musb_fifo_config(struct musb_fifo_cfg *cfg, uint32_t offset) { uint16_t fifo_used; uint8_t c_size; uint16_t c_off; c_off = offset >> 3; c_size = musb_get_fifo_size(cfg->maxpacket, &fifo_used); musb_set_active_ep(cfg->ep_num); switch (cfg->style) { case FIFO_TX: HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET) = c_size & 0x0f; HWREGH(USB_BASE + MUSB_TXFIFOADD_OFFSET) = c_off; break; case FIFO_RX: HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET) = c_size & 0x0f; HWREGH(USB_BASE + MUSB_RXFIFOADD_OFFSET) = c_off; break; case FIFO_TXRX: HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET) = c_size & 0x0f; HWREGH(USB_BASE + MUSB_TXFIFOADD_OFFSET) = c_off; HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET) = c_size & 0x0f; HWREGH(USB_BASE + MUSB_RXFIFOADD_OFFSET) = c_off; break; default: break; } return (offset + fifo_used); } __WEAK void usb_dc_low_level_init(void) { } __WEAK void usb_dc_low_level_deinit(void) { } int usb_dc_init(uint8_t busid) { uint16_t offset = 0; uint8_t cfg_num; struct musb_fifo_cfg *cfg; usb_dc_low_level_init(); #ifdef CONFIG_USB_HS HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_HSENAB; #else HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_HSENAB; #endif musb_set_active_ep(0); HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = 0; HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) |= USB_DEVCTL_SESSION; cfg_num = usbd_get_musb_fifo_cfg(&cfg); for (uint8_t i = 0; i < cfg_num; i++) { offset = usbd_musb_fifo_config(&cfg[i], offset); } if (offset > usb_get_musb_ram_size()) { USB_LOG_ERR("offset:%d is overflow, please check your table\r\n", offset); while (1) { } } /* Enable USB interrupts */ HWREGB(USB_BASE + MUSB_IE_OFFSET) = USB_IE_RESET | USB_IE_SUSPND | USB_IE_RESUME; HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = USB_TXIE_EP0; HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0; HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_SOFTCONN; return 0; } int usb_dc_deinit(uint8_t busid) { return 0; } int usbd_set_address(uint8_t busid, const uint8_t addr) { if (addr == 0) { HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = 0; } g_musb_udc.dev_addr = addr; return 0; } int usbd_set_remote_wakeup(uint8_t busid) { HWREGB(USB_BASE + MUSB_POWER_OFFSET) |= USB_POWER_RESUME; usbd_musb_delay_ms(10); HWREGB(USB_BASE + MUSB_POWER_OFFSET) &= ~USB_POWER_RESUME; return 0; } uint8_t usbd_get_port_speed(uint8_t busid) { uint8_t speed = USB_SPEED_UNKNOWN; if (HWREGB(USB_BASE + MUSB_POWER_OFFSET) & USB_POWER_HSMODE) speed = USB_SPEED_HIGH; else if (HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) & USB_DEVCTL_FSDEV) speed = USB_SPEED_FULL; else if (HWREGB(USB_BASE + MUSB_DEVCTL_OFFSET) & USB_DEVCTL_LSDEV) speed = USB_SPEED_LOW; return speed; } int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress); uint8_t old_ep_idx; uint32_t ui32Flags = 0; uint16_t ui32Register = 0; if (ep_idx == 0) { g_musb_udc.out_ep[0].ep_mps = USB_CTRL_EP_MPS; g_musb_udc.out_ep[0].ep_type = 0x00; g_musb_udc.out_ep[0].ep_enable = true; g_musb_udc.in_ep[0].ep_mps = USB_CTRL_EP_MPS; g_musb_udc.in_ep[0].ep_type = 0x00; g_musb_udc.in_ep[0].ep_enable = true; return 0; } if (ep_idx > (CONFIG_USBDEV_EP_NUM - 1)) { USB_LOG_ERR("Ep addr %02x overflow\r\n", ep->bEndpointAddress); return -1; } old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) { g_musb_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize); g_musb_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes); g_musb_udc.out_ep[ep_idx].ep_enable = true; if ((8 << HWREGB(USB_BASE + MUSB_RXFIFOSZ_OFFSET)) < g_musb_udc.out_ep[ep_idx].ep_mps) { USB_LOG_ERR("Ep %02x fifo is overflow\r\n", ep->bEndpointAddress); return -2; } HWREGH(USB_BASE + MUSB_IND_RXMAP_OFFSET) = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize); // // Allow auto clearing of RxPktRdy when packet of size max packet // has been unloaded from the FIFO. // if (ui32Flags & USB_EP_AUTO_CLEAR) { ui32Register = USB_RXCSRH1_AUTOCL; } // // Configure the DMA mode. // if (ui32Flags & USB_EP_DMA_MODE_1) { ui32Register |= USB_RXCSRH1_DMAEN | USB_RXCSRH1_DMAMOD; } else if (ui32Flags & USB_EP_DMA_MODE_0) { ui32Register |= USB_RXCSRH1_DMAEN; } // // If requested, disable NYET responses for high-speed bulk and // interrupt endpoints. // if (ui32Flags & USB_EP_DIS_NYET) { ui32Register |= USB_RXCSRH1_DISNYET; } // // Enable isochronous mode if requested. // if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) == 0x01) { ui32Register |= USB_RXCSRH1_ISO; } HWREGB(USB_BASE + MUSB_IND_RXCSRH_OFFSET) = ui32Register; // Reset the Data toggle to zero. if (HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) & USB_RXCSRL1_RXRDY) HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = (USB_RXCSRL1_CLRDT | USB_RXCSRL1_FLUSH); else HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) = USB_RXCSRL1_CLRDT; } else { g_musb_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize); g_musb_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes); g_musb_udc.in_ep[ep_idx].ep_enable = true; if ((8 << HWREGB(USB_BASE + MUSB_TXFIFOSZ_OFFSET)) < g_musb_udc.in_ep[ep_idx].ep_mps) { USB_LOG_ERR("Ep %02x fifo is overflow\r\n", ep->bEndpointAddress); return -2; } HWREGH(USB_BASE + MUSB_IND_TXMAP_OFFSET) = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize); // // Allow auto setting of TxPktRdy when max packet size has been loaded // into the FIFO. // if (ui32Flags & USB_EP_AUTO_SET) { ui32Register |= USB_TXCSRH1_AUTOSET; } // // Configure the DMA mode. // if (ui32Flags & USB_EP_DMA_MODE_1) { ui32Register |= USB_TXCSRH1_DMAEN | USB_TXCSRH1_DMAMOD; } else if (ui32Flags & USB_EP_DMA_MODE_0) { ui32Register |= USB_TXCSRH1_DMAEN; } // // Enable isochronous mode if requested. // if (USB_GET_ENDPOINT_TYPE(ep->bmAttributes) == 0x01) { ui32Register |= USB_TXCSRH1_ISO; } HWREGB(USB_BASE + MUSB_IND_TXCSRH_OFFSET) = ui32Register; // Reset the Data toggle to zero. if (HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_TXRDY) HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_TXCSRL1_CLRDT | USB_TXCSRL1_FLUSH); else HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_CLRDT; } musb_set_active_ep(old_ep_idx); return 0; } int usbd_ep_close(uint8_t busid, const uint8_t ep) { return 0; } int usbd_ep_set_stall(uint8_t busid, const uint8_t ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t old_ep_idx; old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); if (USB_EP_DIR_IS_OUT(ep)) { if (ep_idx == 0x00) { usb_ep0_state = USB_EP0_STATE_STALL; HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC); } else { HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) |= USB_RXCSRL1_STALL; } } else { if (ep_idx == 0x00) { usb_ep0_state = USB_EP0_STATE_STALL; HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC); } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= USB_TXCSRL1_STALL; } } musb_set_active_ep(old_ep_idx); return 0; } int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t old_ep_idx; old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); if (USB_EP_DIR_IS_OUT(ep)) { if (ep_idx == 0x00) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED; } else { // Clear the stall on an OUT endpoint. HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) &= ~(USB_RXCSRL1_STALL | USB_RXCSRL1_STALLED); // Reset the data toggle. HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) |= USB_RXCSRL1_CLRDT; } } else { if (ep_idx == 0x00) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED; } else { // Clear the stall on an IN endpoint. HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~(USB_TXCSRL1_STALL | USB_TXCSRL1_STALLED); // Reset the data toggle. HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) |= USB_TXCSRL1_CLRDT; } } musb_set_active_ep(old_ep_idx); return 0; } int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t old_ep_idx; old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); if (USB_EP_DIR_IS_OUT(ep)) { if(HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) & USB_RXCSRL1_STALL) { *stalled = 1; } else { *stalled = 0; } } else { if(HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_STALL) { *stalled = 1; } else { *stalled = 0; } } musb_set_active_ep(old_ep_idx); return 0; } int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t old_ep_idx; if (!data && data_len) { return -1; } if (!g_musb_udc.in_ep[ep_idx].ep_enable) { return -2; } old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); if (HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_TXRDY) { musb_set_active_ep(old_ep_idx); return -3; } g_musb_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data; g_musb_udc.in_ep[ep_idx].xfer_len = data_len; g_musb_udc.in_ep[ep_idx].actual_xfer_len = 0; if (data_len == 0) { if (ep_idx == 0x00) { if (g_musb_udc.setup.wLength == 0) { usb_ep0_state = USB_EP0_STATE_IN_STATUS; } else { usb_ep0_state = USB_EP0_STATE_IN_ZLP; } HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND); } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_TXRDY; HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << ep_idx); } musb_set_active_ep(old_ep_idx); return 0; } data_len = MIN(data_len, g_musb_udc.in_ep[ep_idx].ep_mps); musb_write_packet(ep_idx, (uint8_t *)data, data_len); HWREGH(USB_BASE + MUSB_TXIE_OFFSET) |= (1 << ep_idx); if (ep_idx == 0x00) { usb_ep0_state = USB_EP0_STATE_IN_DATA; if (data_len < g_musb_udc.in_ep[ep_idx].ep_mps) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_TXRDY | USB_CSRL0_DATAEND); } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_TXRDY; } } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_TXRDY; } musb_set_active_ep(old_ep_idx); return 0; } int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint8_t old_ep_idx; if (!data && data_len) { return -1; } if (!g_musb_udc.out_ep[ep_idx].ep_enable) { return -2; } old_ep_idx = musb_get_active_ep(); musb_set_active_ep(ep_idx); g_musb_udc.out_ep[ep_idx].xfer_buf = data; g_musb_udc.out_ep[ep_idx].xfer_len = data_len; g_musb_udc.out_ep[ep_idx].actual_xfer_len = 0; if (data_len == 0) { if (ep_idx == 0) { usb_ep0_state = USB_EP0_STATE_SETUP; } musb_set_active_ep(old_ep_idx); return 0; } if (ep_idx == 0) { usb_ep0_state = USB_EP0_STATE_OUT_DATA; } else { HWREGH(USB_BASE + MUSB_RXIE_OFFSET) |= (1 << ep_idx); } musb_set_active_ep(old_ep_idx); return 0; } static void handle_ep0(void) { uint8_t ep0_status = HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET); uint16_t read_count; if (ep0_status & USB_CSRL0_STALLED) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_CSRL0_STALLED; usb_ep0_state = USB_EP0_STATE_SETUP; return; } if (ep0_status & USB_CSRL0_SETEND) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_SETENDC; } if (g_musb_udc.dev_addr > 0) { HWREGB(USB_BASE + MUSB_FADDR_OFFSET) = g_musb_udc.dev_addr; g_musb_udc.dev_addr = 0; } switch (usb_ep0_state) { case USB_EP0_STATE_SETUP: if (ep0_status & USB_CSRL0_RXRDY) { read_count = HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET); if (read_count != 8) { return; } musb_read_packet(0, (uint8_t *)&g_musb_udc.setup, 8); if (g_musb_udc.setup.wLength) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_RXRDYC; } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND); } usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_musb_udc.setup); } break; case USB_EP0_STATE_IN_DATA: if (g_musb_udc.in_ep[0].xfer_len > g_musb_udc.in_ep[0].ep_mps) { g_musb_udc.in_ep[0].actual_xfer_len += g_musb_udc.in_ep[0].ep_mps; g_musb_udc.in_ep[0].xfer_len -= g_musb_udc.in_ep[0].ep_mps; } else { g_musb_udc.in_ep[0].actual_xfer_len += g_musb_udc.in_ep[0].xfer_len; g_musb_udc.in_ep[0].xfer_len = 0; } usbd_event_ep_in_complete_handler(0, 0x80, g_musb_udc.in_ep[0].actual_xfer_len); break; case USB_EP0_STATE_OUT_DATA: if (ep0_status & USB_CSRL0_RXRDY) { read_count = HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET); musb_read_packet(0, g_musb_udc.out_ep[0].xfer_buf, read_count); g_musb_udc.out_ep[0].xfer_buf += read_count; g_musb_udc.out_ep[0].actual_xfer_len += read_count; if (read_count < g_musb_udc.out_ep[0].ep_mps) { usbd_event_ep_out_complete_handler(0, 0x00, g_musb_udc.out_ep[0].actual_xfer_len); HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = (USB_CSRL0_RXRDYC | USB_CSRL0_DATAEND); usb_ep0_state = USB_EP0_STATE_IN_STATUS; } else { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_CSRL0_RXRDYC; } } break; case USB_EP0_STATE_IN_STATUS: case USB_EP0_STATE_IN_ZLP: usb_ep0_state = USB_EP0_STATE_SETUP; usbd_event_ep_in_complete_handler(0, 0x80, 0); break; } } void USBD_IRQHandler(uint8_t busid) { uint32_t is; uint32_t txis; uint32_t rxis; uint8_t old_ep_idx; uint8_t ep_idx; uint16_t write_count, read_count; is = HWREGB(USB_BASE + MUSB_IS_OFFSET); txis = HWREGH(USB_BASE + MUSB_TXIS_OFFSET); rxis = HWREGH(USB_BASE + MUSB_RXIS_OFFSET); HWREGB(USB_BASE + MUSB_IS_OFFSET) = is; old_ep_idx = musb_get_active_ep(); /* Receive a reset signal from the USB bus */ if (is & USB_IS_RESET) { memset(&g_musb_udc, 0, sizeof(struct musb_udc)); usbd_event_reset_handler(0); HWREGH(USB_BASE + MUSB_TXIE_OFFSET) = USB_TXIE_EP0; HWREGH(USB_BASE + MUSB_RXIE_OFFSET) = 0; usb_ep0_state = USB_EP0_STATE_SETUP; } if (is & USB_IS_SOF) { } if (is & USB_IS_RESUME) { usbd_event_resume_handler(0); } if (is & USB_IS_SUSPEND) { usbd_event_suspend_handler(0); } txis &= HWREGH(USB_BASE + MUSB_TXIE_OFFSET); /* Handle EP0 interrupt */ if (txis & USB_TXIE_EP0) { HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = USB_TXIE_EP0; musb_set_active_ep(0); handle_ep0(); txis &= ~USB_TXIE_EP0; } ep_idx = 1; while (txis) { if (txis & (1 << ep_idx)) { musb_set_active_ep(ep_idx); HWREGH(USB_BASE + MUSB_TXIS_OFFSET) = (1 << ep_idx); if (HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) & USB_TXCSRL1_UNDRN) { HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) &= ~USB_TXCSRL1_UNDRN; } if (g_musb_udc.in_ep[ep_idx].xfer_len > g_musb_udc.in_ep[ep_idx].ep_mps) { g_musb_udc.in_ep[ep_idx].xfer_buf += g_musb_udc.in_ep[ep_idx].ep_mps; g_musb_udc.in_ep[ep_idx].actual_xfer_len += g_musb_udc.in_ep[ep_idx].ep_mps; g_musb_udc.in_ep[ep_idx].xfer_len -= g_musb_udc.in_ep[ep_idx].ep_mps; } else { g_musb_udc.in_ep[ep_idx].xfer_buf += g_musb_udc.in_ep[ep_idx].xfer_len; g_musb_udc.in_ep[ep_idx].actual_xfer_len += g_musb_udc.in_ep[ep_idx].xfer_len; g_musb_udc.in_ep[ep_idx].xfer_len = 0; } if (g_musb_udc.in_ep[ep_idx].xfer_len == 0) { HWREGH(USB_BASE + MUSB_TXIE_OFFSET) &= ~(1 << ep_idx); usbd_event_ep_in_complete_handler(0, ep_idx | 0x80, g_musb_udc.in_ep[ep_idx].actual_xfer_len); } else { write_count = MIN(g_musb_udc.in_ep[ep_idx].xfer_len, g_musb_udc.in_ep[ep_idx].ep_mps); musb_write_packet(ep_idx, g_musb_udc.in_ep[ep_idx].xfer_buf, write_count); HWREGB(USB_BASE + MUSB_IND_TXCSRL_OFFSET) = USB_TXCSRL1_TXRDY; } txis &= ~(1 << ep_idx); } ep_idx++; } rxis &= HWREGH(USB_BASE + MUSB_RXIE_OFFSET); ep_idx = 1; while (rxis) { if (rxis & (1 << ep_idx)) { musb_set_active_ep(ep_idx); HWREGH(USB_BASE + MUSB_RXIS_OFFSET) = (1 << ep_idx); if (HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) & USB_RXCSRL1_RXRDY) { read_count = HWREGH(USB_BASE + MUSB_IND_RXCOUNT_OFFSET); musb_read_packet(ep_idx, g_musb_udc.out_ep[ep_idx].xfer_buf, read_count); HWREGB(USB_BASE + MUSB_IND_RXCSRL_OFFSET) &= ~(USB_RXCSRL1_RXRDY); g_musb_udc.out_ep[ep_idx].xfer_buf += read_count; g_musb_udc.out_ep[ep_idx].actual_xfer_len += read_count; g_musb_udc.out_ep[ep_idx].xfer_len -= read_count; if ((read_count < g_musb_udc.out_ep[ep_idx].ep_mps) || (g_musb_udc.out_ep[ep_idx].xfer_len == 0)) { HWREGH(USB_BASE + MUSB_RXIE_OFFSET) &= ~(1 << ep_idx); usbd_event_ep_out_complete_handler(0, ep_idx, g_musb_udc.out_ep[ep_idx].actual_xfer_len); } else { } } rxis &= ~(1 << ep_idx); } ep_idx++; } musb_set_active_ep(old_ep_idx); }