123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- /*
- * Copyright (c) 2021-2024 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- /*
- * Copyright (c) 2024, sakumisu
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include "usbd_core.h"
- #include "usb_chipidea_reg.h"
- #define USB_OTG_DEV ((CHIPIDEA_TypeDef *)g_usbdev_bus[busid].reg_base)
- #define CHIPIDEA_BITSMASK(val, offset) ((uint32_t)(val) << (offset))
- #define QTD_COUNT_EACH_ENDPOINT (8U)
- /* ENDPTCTRL */
- enum {
- ENDPTCTRL_STALL = CHIPIDEA_BITSMASK(1, 0),
- ENDPTCTRL_TYPE = CHIPIDEA_BITSMASK(3, 2),
- ENDPTCTRL_TOGGLE_INHIBIT = CHIPIDEA_BITSMASK(1, 5),
- ENDPTCTRL_TOGGLE_RESET = CHIPIDEA_BITSMASK(1, 6),
- ENDPTCTRL_ENABLE = CHIPIDEA_BITSMASK(1, 7),
- };
- /* USBSTS, USBINTR */
- enum {
- intr_usb = CHIPIDEA_BITSMASK(1, 0),
- intr_error = CHIPIDEA_BITSMASK(1, 1),
- intr_port_change = CHIPIDEA_BITSMASK(1, 2),
- intr_reset = CHIPIDEA_BITSMASK(1, 6),
- intr_sof = CHIPIDEA_BITSMASK(1, 7),
- intr_suspend = CHIPIDEA_BITSMASK(1, 8),
- intr_nak = CHIPIDEA_BITSMASK(1, 16)
- };
- /* Queue Transfer Descriptor */
- typedef struct {
- /* Word 0: Next QTD Pointer */
- volatile uint32_t next; /* Next link pointer This field contains the physical memory address of the next dTD to be processed */
- /* Word 1: qTQ Token */
- volatile uint32_t : 3;
- volatile uint32_t xact_err : 1;
- volatile uint32_t : 1;
- volatile uint32_t buffer_err : 1;
- volatile uint32_t halted : 1;
- volatile uint32_t active : 1;
- volatile uint32_t : 2;
- volatile uint32_t iso_mult_override : 2; /* This field can be used for transmit ISOs to override the MULT field in the dQH. This field must be zero for all packet types that are not transmit-ISO. */
- volatile uint32_t : 3;
- volatile uint32_t int_on_complete : 1;
- volatile uint32_t total_bytes : 15;
- volatile uint32_t : 0;
- /* Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page */
- volatile uint32_t buffer[5];
- /*------------- DCD Area -------------*/
- volatile uint16_t expected_bytes;
- volatile uint8_t reserved[2];
- } dcd_qtd_t;
- /* Queue Head */
- typedef struct {
- /* Word 0: Capabilities and Characteristics */
- volatile uint32_t : 15; /* Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed. */
- volatile uint32_t int_on_setup : 1; /* Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received. */
- volatile uint32_t max_packet_size : 11; /* This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize) */
- volatile uint32_t : 2;
- volatile uint32_t zero_length_termination : 1; /* This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length. */
- volatile uint32_t iso_mult : 2;
- volatile uint32_t : 0;
- /* Word 1: Current qTD Pointer */
- volatile uint32_t qtd_addr;
- /* Word 2-9: Transfer Overlay */
- volatile dcd_qtd_t qtd_overlay;
- /* Word 10-11: Setup request (control OUT only) */
- volatile struct usb_setup_packet setup_request;
- /*--------------------------------------------------------------------
- * Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes
- * thus there are 16 bytes padding free that we can make use of.
- *--------------------------------------------------------------------
- */
- volatile uint8_t reserved[16];
- } dcd_qhd_t;
- typedef struct {
- dcd_qhd_t qhd[CONFIG_USBDEV_EP_NUM * 2];
- dcd_qtd_t qtd[CONFIG_USBDEV_EP_NUM * 2 * QTD_COUNT_EACH_ENDPOINT];
- } dcd_data_t;
- /* Endpoint state */
- struct chipidea_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 chipidea_udc {
- dcd_data_t *dcd_data;
- bool is_suspend;
- struct chipidea_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
- struct chipidea_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
- } g_chipidea_udc[CONFIG_USBDEV_MAX_BUS];
- static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data0;
- #if CONFIG_USBDEV_MAX_BUS == 2
- static USB_NOCACHE_RAM_SECTION __attribute__((aligned(2048))) dcd_data_t _dcd_data1;
- #endif
- static dcd_data_t *g_dcd_data[CONFIG_USBDEV_MAX_BUS] = {
- &_dcd_data0,
- #if CONFIG_USBDEV_MAX_BUS == 2
- &_dcd_data1
- #endif
- };
- /* Index to bit position in register */
- static inline uint8_t ep_idx2bit(uint8_t ep_idx)
- {
- return ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
- }
- static void __chipidea_bus_reset(CHIPIDEA_TypeDef *ptr)
- {
- /* The reset value for all endpoint types is the control endpoint. If one endpoint
- * direction is enabled and the paired endpoint of opposite direction is disabled, then the
- * endpoint type of the unused direction must be changed from the control type to any other
- * type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
- * for the data PID tracking on the active endpoint.
- */
- for (uint32_t i = 1; i < CONFIG_USBDEV_EP_NUM; i++) {
- ptr->ENDPTCTRL[i] = USB_ENDPTCTRL_TXT_SET(USB_ENDPOINT_TYPE_BULK) | USB_ENDPTCTRL_RXT_SET(USB_ENDPOINT_TYPE_BULK);
- }
- /* Clear All Registers */
- ptr->ENDPTNAK = ptr->ENDPTNAK;
- ptr->ENDPTNAKEN = 0;
- ptr->USBSTS = ptr->USBSTS;
- ptr->ENDPTSETUPSTAT = ptr->ENDPTSETUPSTAT;
- ptr->ENDPTCOMPLETE = ptr->ENDPTCOMPLETE;
- while (ptr->ENDPTPRIME) {
- }
- ptr->ENDPTFLUSH = 0xFFFFFFFF;
- while (ptr->ENDPTFLUSH) {
- }
- }
- static void chipidea_init(CHIPIDEA_TypeDef *ptr)
- {
- /* Reset controller */
- ptr->USBCMD |= USB_USBCMD_RST_MASK;
- while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
- }
- /* Set mode to device, must be set immediately after reset */
- ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
- ptr->USBMODE |= USB_USBMODE_CM_SET(2);
- /* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */
- ptr->USBMODE &= ~USB_USBMODE_SLOM_MASK;
- /* Set the endian */
- ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
- /* Set parallel interface signal */
- ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
- /* Set parallel transceiver width */
- ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
- /* Set usb forced to full speed mode */
- //ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK;
- /* Not use interrupt threshold. */
- ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
- /* Enable VBUS discharge */
- ptr->OTGSC |= USB_OTGSC_VD_MASK;
- }
- static void chipidea_deinit(CHIPIDEA_TypeDef *ptr)
- {
- /* Stop */
- ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
- /* Reset controller */
- ptr->USBCMD |= USB_USBCMD_RST_MASK;
- while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
- }
- /* Reset endpoint list address register */
- ptr->ENDPTLISTADDR = 0;
- /* Reset status register */
- ptr->USBSTS = ptr->USBSTS;
- /* Reset interrupt enable register */
- ptr->USBINTR = 0;
- }
- /*---------------------------------------------------------------------
- * Endpoint API
- *---------------------------------------------------------------------
- */
- static void __chipidea_edpt_open(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr, uint8_t ep_type)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- /* Enable EP Control */
- uint32_t temp = ptr->ENDPTCTRL[epnum];
- temp &= ~((0x03 << 2) << (dir ? 16 : 0));
- temp |= ((ep_type << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
- ptr->ENDPTCTRL[epnum] = temp;
- }
- static void chipidea_edpt_xfer(CHIPIDEA_TypeDef *ptr, uint8_t ep_idx)
- {
- uint32_t offset = ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
- /* Start transfer */
- ptr->ENDPTPRIME = 1 << offset;
- }
- static void chipidea_edpt_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
- }
- static void chipidea_edpt_clear_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- /* data toggle also need to be reset */
- ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0);
- ptr->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0));
- }
- static bool chipidea_edpt_check_stall(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- return (ptr->ENDPTCTRL[epnum] & (ENDPTCTRL_STALL << (dir ? 16 : 0))) ? true : false;
- }
- static void chipidea_edpt_close(CHIPIDEA_TypeDef *ptr, uint8_t ep_addr)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- uint32_t primebit = CHIPIDEA_BITSMASK(1, epnum) << (dir ? 16 : 0);
- /* Flush the endpoint to stop a transfer. */
- do {
- /* Set the corresponding bit(s) in the ENDPTFLUSH register */
- ptr->ENDPTFLUSH |= primebit;
- /* Wait until all bits in the ENDPTFLUSH register are cleared. */
- while (0U != (ptr->ENDPTFLUSH & primebit)) {
- }
- /*
- * Read the ENDPTSTAT register to ensure that for all endpoints
- * commanded to be flushed, that the corresponding bits
- * are now cleared.
- */
- } while (0U != (ptr->ENDPTSTAT & primebit));
- /* Disable the endpoint */
- ptr->ENDPTCTRL[epnum] &= ~((ENDPTCTRL_TYPE | ENDPTCTRL_ENABLE | ENDPTCTRL_STALL) << (dir ? 16 : 0));
- ptr->ENDPTCTRL[epnum] |= (USB_ENDPOINT_TYPE_BULK << 2) << (dir ? 16 : 0);
- }
- /* Initialize qtd */
- static void usb_qtd_init(dcd_qtd_t *p_qtd, void *data_ptr, uint16_t total_bytes)
- {
- memset(p_qtd, 0, sizeof(dcd_qtd_t));
- p_qtd->next = 1;
- p_qtd->active = 1;
- p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
- if (data_ptr != NULL) {
- p_qtd->buffer[0] = (uint32_t)data_ptr;
- for (uint8_t i = 1; i < 5; i++) {
- p_qtd->buffer[i] |= ((p_qtd->buffer[i - 1]) & 0xFFFFF000UL) + 4096U;
- }
- }
- }
- static dcd_qhd_t *chipidea_qhd_get(uint8_t busid, uint8_t ep_idx)
- {
- dcd_data_t *dcd_data;
- dcd_data = g_chipidea_udc[busid].dcd_data;
- return &dcd_data->qhd[ep_idx];
- }
- static dcd_qtd_t *chipidea_qtd_get(uint8_t busid, uint8_t ep_idx)
- {
- dcd_data_t *dcd_data;
- dcd_data = g_chipidea_udc[busid].dcd_data;
- return &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT];
- }
- static void chipidea_bus_reset(uint8_t busid, uint16_t ep0_max_packet_size)
- {
- dcd_data_t *dcd_data;
- dcd_data = g_chipidea_udc[busid].dcd_data;
- __chipidea_bus_reset(USB_OTG_DEV);
- /* Queue Head & Queue TD */
- memset(dcd_data, 0, sizeof(dcd_data_t));
- /* Set up Control Endpoints (0 OUT, 1 IN) */
- dcd_data->qhd[0].zero_length_termination = dcd_data->qhd[1].zero_length_termination = 1;
- dcd_data->qhd[0].max_packet_size = dcd_data->qhd[1].max_packet_size = ep0_max_packet_size;
- dcd_data->qhd[0].qtd_overlay.next = dcd_data->qhd[1].qtd_overlay.next = 1;
- /* OUT only */
- dcd_data->qhd[0].int_on_setup = 1;
- }
- static void chipidea_edpt_open(uint8_t busid, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- uint8_t const ep_idx = 2 * epnum + dir;
- dcd_data_t *dcd_data;
- dcd_qhd_t *p_qhd;
- /* Prepare Queue Head */
- dcd_data = g_chipidea_udc[busid].dcd_data;
- p_qhd = &dcd_data->qhd[ep_idx];
- memset(p_qhd, 0, sizeof(dcd_qhd_t));
- p_qhd->zero_length_termination = 1;
- p_qhd->max_packet_size = ep_mps & 0x7FFu;
- p_qhd->qtd_overlay.next = 1;
- if (ep_type == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
- p_qhd->iso_mult = ((ep_mps >> 11u) & 0x3u) + 1u;
- }
- __chipidea_edpt_open(USB_OTG_DEV, ep_addr, ep_type);
- }
- static bool chipidea_start_xfer(uint8_t busid, uint8_t ep_addr, uint8_t *buffer, uint32_t total_bytes)
- {
- uint8_t const epnum = ep_addr & 0x0f;
- uint8_t const dir = (ep_addr & 0x80) >> 7;
- uint8_t const ep_idx = 2 * epnum + dir;
- uint8_t qtd_num;
- uint8_t i;
- uint32_t xfer_len;
- dcd_qhd_t *p_qhd;
- dcd_qtd_t *p_qtd;
- dcd_qtd_t *first_p_qtd = NULL;
- dcd_qtd_t *prev_p_qtd = NULL;
- dcd_data_t *dcd_data;
- dcd_data = g_chipidea_udc[busid].dcd_data;
- if (epnum == 0) {
- /* follows UM Setup packet handling using setup lockout mechanism
- * wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
- */
- while (USB_OTG_DEV->ENDPTSETUPSTAT & CHIPIDEA_BITSMASK(1, 0)) {
- }
- }
- qtd_num = (total_bytes + 0x3fff) / 0x4000;
- if (qtd_num > QTD_COUNT_EACH_ENDPOINT) {
- return false;
- }
- if (buffer != NULL) {
- buffer = (uint8_t *)buffer;
- }
- p_qhd = &dcd_data->qhd[ep_idx];
- i = 0;
- do {
- p_qtd = &dcd_data->qtd[ep_idx * QTD_COUNT_EACH_ENDPOINT + i];
- i++;
- if (total_bytes > 0x4000) {
- xfer_len = 0x4000;
- total_bytes -= 0x4000;
- } else {
- xfer_len = total_bytes;
- total_bytes = 0;
- }
- usb_qtd_init(p_qtd, (void *)buffer, xfer_len);
- if (total_bytes == 0) {
- p_qtd->int_on_complete = true;
- }
- buffer += xfer_len;
- if (prev_p_qtd) {
- prev_p_qtd->next = (uint32_t)p_qtd;
- } else {
- first_p_qtd = p_qtd;
- }
- prev_p_qtd = p_qtd;
- } while (total_bytes > 0);
- p_qhd->qtd_overlay.next = (uint32_t)first_p_qtd; /* link qtd to qhd */
- chipidea_edpt_xfer(USB_OTG_DEV, ep_idx);
- return true;
- }
- __WEAK void usb_dc_low_level_init(uint8_t busid)
- {
- }
- __WEAK void usb_dc_low_level_deinit(uint8_t busid)
- {
- }
- int usb_dc_init(uint8_t busid)
- {
- uint32_t int_mask;
- int_mask = (USB_USBINTR_UE_MASK | USB_USBINTR_UEE_MASK | USB_USBINTR_SLE_MASK |
- USB_USBINTR_PCE_MASK | USB_USBINTR_URE_MASK);
- usb_dc_low_level_init(busid);
- memset(&g_chipidea_udc[busid], 0, sizeof(struct chipidea_udc));
- g_chipidea_udc[busid].dcd_data = g_dcd_data[busid];
- memset(g_chipidea_udc[busid].dcd_data, 0, sizeof(dcd_data_t));
- chipidea_init(USB_OTG_DEV);
- /* Set endpoint list address */
- USB_OTG_DEV->ENDPTLISTADDR = ((uint32_t)g_chipidea_udc[busid].dcd_data->qhd) & USB_ENDPTLISTADDR_EPBASE_MASK;
- /* Clear status */
- USB_OTG_DEV->USBSTS = USB_OTG_DEV->USBSTS;
- /* Enable interrupt mask */
- USB_OTG_DEV->USBINTR |= int_mask;
- /* Connect by enabling internal pull-up resistor on D+/D- */
- USB_OTG_DEV->USBCMD |= USB_USBCMD_RS_MASK;
- return 0;
- }
- int usb_dc_deinit(uint8_t busid)
- {
- chipidea_deinit(USB_OTG_DEV);
- for (uint32_t i = 0; i < CONFIG_USBDEV_EP_NUM; i++) {
- chipidea_edpt_close(USB_OTG_DEV, (i | 0x80));
- chipidea_edpt_close(USB_OTG_DEV, (i | 0x00));
- }
- usb_dc_low_level_deinit(busid);
- return 0;
- }
- int usbd_set_address(uint8_t busid, const uint8_t addr)
- {
- USB_OTG_DEV->DEVICEADDR = USB_DEVICEADDR_USBADR_SET(addr) | USB_DEVICEADDR_USBADRA_MASK;
- return 0;
- }
- int usbd_set_remote_wakeup(uint8_t busid)
- {
- if (!USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
- return -1;
- }
- USB_OTG_DEV->PORTSC1 |= USB_PORTSC1_FPR_MASK;
- while (USB_OTG_DEV->PORTSC1 & USB_PORTSC1_FPR_MASK) {
- }
- return 0;
- }
- uint8_t usbd_get_port_speed(uint8_t busid)
- {
- uint8_t speed;
- speed = USB_PORTSC1_PSPD_GET(USB_OTG_DEV->PORTSC1);
- if (speed == 0x00) {
- return USB_SPEED_FULL;
- }
- if (speed == 0x01) {
- return USB_SPEED_LOW;
- }
- if (speed == 0x02) {
- return USB_SPEED_HIGH;
- }
- return 0;
- }
- int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
- {
- uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
- /* Must not exceed max endpoint number */
- if (ep_idx >= CONFIG_USBDEV_EP_NUM) {
- return -1;
- }
- chipidea_edpt_open(busid, ep->bEndpointAddress, USB_GET_ENDPOINT_TYPE(ep->bmAttributes), ep->wMaxPacketSize);
- if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
- g_chipidea_udc[busid].out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_chipidea_udc[busid].out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = true;
- } else {
- g_chipidea_udc[busid].in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
- g_chipidea_udc[busid].in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
- g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = true;
- }
- return 0;
- }
- int usbd_ep_close(uint8_t busid, const uint8_t ep)
- {
- uint8_t ep_idx = USB_EP_GET_IDX(ep);
- if (USB_EP_DIR_IS_OUT(ep)) {
- g_chipidea_udc[busid].out_ep[ep_idx].ep_enable = false;
- } else {
- g_chipidea_udc[busid].in_ep[ep_idx].ep_enable = false;
- }
- chipidea_edpt_close(USB_OTG_DEV, ep);
- return 0;
- }
- int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
- {
- chipidea_edpt_stall(USB_OTG_DEV, ep);
- return 0;
- }
- int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
- {
- chipidea_edpt_clear_stall(USB_OTG_DEV, ep);
- return 0;
- }
- int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
- {
- *stalled = chipidea_edpt_check_stall(USB_OTG_DEV, ep);
- 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);
- if (!data && data_len) {
- return -1;
- }
- if (!g_chipidea_udc[busid].in_ep[ep_idx].ep_enable) {
- return -2;
- }
- g_chipidea_udc[busid].in_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_chipidea_udc[busid].in_ep[ep_idx].xfer_len = data_len;
- g_chipidea_udc[busid].in_ep[ep_idx].actual_xfer_len = 0;
- chipidea_start_xfer(busid, ep, (uint8_t *)data, data_len);
- 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);
- if (!data && data_len) {
- return -1;
- }
- if (!g_chipidea_udc[busid].out_ep[ep_idx].ep_enable) {
- return -2;
- }
- g_chipidea_udc[busid].out_ep[ep_idx].xfer_buf = (uint8_t *)data;
- g_chipidea_udc[busid].out_ep[ep_idx].xfer_len = data_len;
- g_chipidea_udc[busid].out_ep[ep_idx].actual_xfer_len = 0;
- chipidea_start_xfer(busid, ep, data, data_len);
- return 0;
- }
- void USBD_IRQHandler(uint8_t busid)
- {
- uint32_t int_status;
- uint32_t transfer_len;
- bool ep_cb_req;
- /* Acknowledge handled interrupt */
- int_status = USB_OTG_DEV->USBSTS;
- int_status &= USB_OTG_DEV->USBINTR;
- USB_OTG_DEV->USBSTS = int_status;
- if (int_status & intr_error) {
- USB_LOG_ERR("usbd intr error!\r\n");
- }
- if (int_status & intr_reset) {
- g_chipidea_udc[busid].is_suspend = false;
- memset(g_chipidea_udc[busid].in_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
- memset(g_chipidea_udc[busid].out_ep, 0, sizeof(struct chipidea_ep_state) * CONFIG_USBDEV_EP_NUM);
- usbd_event_reset_handler(busid);
- chipidea_bus_reset(busid, 64);
- }
- if (int_status & intr_suspend) {
- if (USB_PORTSC1_SUSP_GET(USB_OTG_DEV->PORTSC1)) {
- /* Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. */
- if (USB_DEVICEADDR_USBADR_GET(USB_OTG_DEV->DEVICEADDR)) {
- g_chipidea_udc[busid].is_suspend = true;
- usbd_event_suspend_handler(busid);
- }
- } else {
- }
- }
- if (int_status & intr_port_change) {
- if (!USB_PORTSC1_CCS_GET(USB_OTG_DEV->PORTSC1)) {
- usbd_event_disconnect_handler(busid);
- } else {
- if (g_chipidea_udc[busid].is_suspend) {
- g_chipidea_udc[busid].is_suspend = false;
- usbd_event_resume_handler(busid);
- }
- usbd_event_connect_handler(busid);
- }
- }
- if (int_status & intr_usb) {
- uint32_t const edpt_complete = USB_OTG_DEV->ENDPTCOMPLETE;
- USB_OTG_DEV->ENDPTCOMPLETE = edpt_complete;
- uint32_t edpt_setup_status = USB_OTG_DEV->ENDPTSETUPSTAT;
- if (edpt_setup_status) {
- /*------------- Set up Received -------------*/
- USB_OTG_DEV->ENDPTSETUPSTAT = edpt_setup_status;
- dcd_qhd_t *qhd0 = chipidea_qhd_get(busid, 0);
- usbd_event_ep0_setup_complete_handler(busid, (uint8_t *)&qhd0->setup_request);
- }
- if (edpt_complete) {
- for (uint8_t ep_idx = 0; ep_idx < (CONFIG_USBDEV_EP_NUM * 2); ep_idx++) {
- if (edpt_complete & (1 << ep_idx2bit(ep_idx))) {
- transfer_len = 0;
- ep_cb_req = true;
- /* Failed QTD also get ENDPTCOMPLETE set */
- dcd_qtd_t *p_qtd = chipidea_qtd_get(busid, ep_idx);
- while (1) {
- if (p_qtd->halted || p_qtd->xact_err || p_qtd->buffer_err) {
- USB_LOG_ERR("usbd transfer error!\r\n");
- ep_cb_req = false;
- break;
- } else if (p_qtd->active) {
- ep_cb_req = false;
- break;
- } else {
- transfer_len += p_qtd->expected_bytes - p_qtd->total_bytes;
- }
- if (p_qtd->next == 1) {
- break;
- } else {
- p_qtd = (dcd_qtd_t *)p_qtd->next;
- }
- }
- if (ep_cb_req) {
- uint8_t const ep_addr = (ep_idx / 2) | ((ep_idx & 0x01) ? 0x80 : 0);
- if (ep_addr & 0x80) {
- usbd_event_ep_in_complete_handler(busid, ep_addr, transfer_len);
- } else {
- usbd_event_ep_out_complete_handler(busid, ep_addr, transfer_len);
- }
- }
- }
- }
- }
- }
- }
|