From 6e7e69df17374127d40a5c863ba4bb87e281d0f6 Mon Sep 17 00:00:00 2001 From: Tyrone Ting Date: Fri, 20 Sep 2024 11:09:06 +0800 Subject: [PATCH] drivers: usb: fix for usb rndis 1. Tested with RNDIS and CDC_ACM 2. Credits to CS10 YAChen0 and CS10 YHShih Signed-off-by: Tyrone Ting --- drivers/usb/device/usb_dc_npcm4xx.c | 87 ++++++++++++++++++----------- 1 file changed, 54 insertions(+), 33 deletions(-) diff --git a/drivers/usb/device/usb_dc_npcm4xx.c b/drivers/usb/device/usb_dc_npcm4xx.c index 64d7834823c12c..b2fcb9c85f5e24 100644 --- a/drivers/usb/device/usb_dc_npcm4xx.c +++ b/drivers/usb/device/usb_dc_npcm4xx.c @@ -17,7 +17,7 @@ LOG_MODULE_REGISTER(usb_dc_npcm4xx); /* Timeout for USB PHY clock ready. (Unit:ms) */ #define NPCM4XX_USB_PHY_TIMEOUT (50) /* Timeout for USB Write Data to Host. (Unit:ms) */ -#define NPCM4XX_USB_WRITE_TIMEOUT (50) +#define NPCM4XX_USB_WRITE_TIMEOUT (200) #define NUM_OF_EP_MAX (DT_INST_PROP(0, num_bidir_endpoints)) #define USB_RAM_SIZE (DT_INST_PROP(0, usbd_ram_size)) @@ -62,6 +62,7 @@ struct usb_device_data { volatile uint32_t ram_offset; volatile uint32_t ep_status; volatile uint32_t req_type; + volatile uint32_t req_len; volatile uint32_t set_addr_req; volatile uint32_t new_addr; usb_dc_status_callback status_cb; @@ -143,7 +144,7 @@ static inline void usbd_flush_all_ep(void) uint8_t i; for (i = EPA; i <= EPL; i++) { - USBD->EP[i].USBD_EPRSPCTL = BIT(NPCM4XX_USBD_EPRSPCTL_FLUSH); + USBD->EP[i].USBD_EPRSPCTL = BIT(NPCM4XX_USBD_EPRSPCTL_FLUSH) | BIT(1); } } @@ -188,8 +189,7 @@ static void usb_dc_cep_isr(void) /* Setup Packet */ if (IS_BIT_SET(IrqSt, NPCM4XX_USBD_CEPINTSTS_SETUPPKIF)) { - /* Clear CEP interrupt flag */ - USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); + LOG_DBG("\r\n\r\nSETUP pkt"); @@ -271,8 +271,6 @@ static void usb_dc_cep_isr(void) /* Status Completion */ if (IS_BIT_SET(IrqSt, NPCM4XX_USBD_CEPINTSTS_STSDONEIF)) { - /* Clear CEP interrupt flag */ - USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_STSDONEIF); /* Enable CEP Interrupt */ USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_SETUPPKIEN); @@ -449,6 +447,7 @@ static void usb_dc_isr(void) USB_DC_EP_DATA_IN); } else { LOG_DBG("\r\n\r\nEP_OUT %d", ep_idx); + USBD->EP[ep_idx].USBD_EPINTEN = 0; ep = ep_idx | USB_EP_DIR_OUT; dev_data.ep_data[1 + ep_idx].cb_out(1 + ep, USB_DC_EP_DATA_OUT); @@ -656,7 +655,9 @@ int usb_dc_ep_set_stall(const uint8_t ep) } if (type == USB_DC_EP_CONTROL) { + USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); USBD_SET_CEP_STATE(USBD_CEPCTL_STALL); + USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_SETUPPKIEN); } else { USBD->EP[ep_idx - 1].USBD_EPRSPCTL = (USBD->EP[ep_idx - 1].USBD_EPRSPCTL & 0xf7ul) | BIT(NPCM4XX_USBD_EPRSPCTL_HALT); @@ -680,7 +681,7 @@ int usb_dc_ep_clear_stall(const uint8_t ep) if (type == USB_DC_EP_CONTROL) { USBD_SET_CEP_STATE(USBD_CEPCTL_NAKCLR); } else { - USBD->EP[ep_idx - 1].USBD_EPRSPCTL = BIT(NPCM4XX_USBD_EPRSPCTL_TOGGLE); + USBD->EP[ep_idx - 1].USBD_EPRSPCTL = BIT(NPCM4XX_USBD_EPRSPCTL_TOGGLE) | BIT(1); } LOG_DBG("ep 0x%x", ep); @@ -787,7 +788,7 @@ int usb_dc_ep_flush(const uint8_t ep) if (type == USB_DC_EP_CONTROL) { USBD->USBD_CEPCTL |= BIT(NPCM4XX_USBD_CEPCTL_FLUSH); } else { - USBD->EP[ep_idx - 1].USBD_EPRSPCTL |= BIT(NPCM4XX_USBD_EPRSPCTL_FLUSH); + USBD->EP[ep_idx - 1].USBD_EPRSPCTL |= BIT(NPCM4XX_USBD_EPRSPCTL_FLUSH) | BIT(1); } LOG_DBG("flush ep 0x%x", ep); @@ -850,8 +851,6 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, break; } } - /* Clear NAK */ - USBD_SET_CEP_STATE(USBD_CEPCTL_NAKCLR); /* Has more data to send */ if (data_len > packet_len) { @@ -860,16 +859,20 @@ int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, /* Enable CEP IN Interrupt */ USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_INTKIEN); } else { - /* Clear CEP interrupt flag */ + /* Status Stage */ + USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_STSDONEIF); - /* Enable CEP Interrupt */ - USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_SETUPPKIEN); + USBD_SET_CEP_STATE(USBD_CEPCTL_NAKCLR); + USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_STSDONEIEN); } } else { /* data_len=0 */ - /* Status Stage */ if ((data == NULL) && ret_bytes == NULL) { - USBD_SET_CEP_STATE(USBD_CEPCTL_ZEROLEN); + /* Status Stage */ + USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); + USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_STSDONEIF); + USBD_SET_CEP_STATE(USBD_CEPCTL_ZEROLEN|USBD_CEPCTL_NAKCLR); + USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_STSDONEIEN); LOG_DBG("Zero Len"); } } @@ -914,8 +917,6 @@ int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, const uint32_t max_data_len, uint32_t *const read_bytes) { int ret; - uint8_t ep_idx = USB_EP_GET_IDX(ep); - uint32_t type = dev_data.ep_data[ep_idx].type; ret = usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes); if (ret < 0) { @@ -930,11 +931,9 @@ int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, } /* Clear NAK */ - if (type == USB_DC_EP_CONTROL) { - ret = usb_dc_ep_read_continue(ep); - if (ret < 0) { - return -EINVAL; - } + ret = usb_dc_ep_read_continue(ep); + if (ret < 0) { + return -EINVAL; } LOG_DBG("ep 0x%x", ep); @@ -1027,22 +1026,27 @@ int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, *data++ = (uint8_t)((USBD->USBD_SETUP3_2 >> 8) & 0xfful); *data++ = (uint8_t)(USBD->USBD_SETUP5_4 & 0xfful); *data++ = (uint8_t)((USBD->USBD_SETUP5_4 >> 8) & 0xfful); - *data++ = (uint8_t)(USBD->USBD_SETUP7_6 & 0xfful); - *data++ = (uint8_t)((USBD->USBD_SETUP7_6 >> 8) & 0xfful); + dev_data.req_len = USBD->USBD_SETUP7_6 & 0xfffful; + *data++ = (uint8_t)(dev_data.req_len & 0xfful); + *data++ = (uint8_t)((dev_data.req_len >> 8) & 0xfful); } else { /* CEP OUT */ for (i = 0; i < data_len; i++) { *data++ = USBD->USBD_CEPDAT_BYTE; } + if (dev_data.req_len >= data_len) { + dev_data.req_len -= data_len; + } else { + LOG_WRN("Too more data in buffer!!"); + dev_data.req_len = 0; + } } } else { /* Bulk, Interrupt */ for (i = 0; i < data_len; i++) { *data++ = USBD->EP[ep_idx - 1].USBD_EPDAT_BYTE; } - if (USB_EP_GET_DIR(ep) == USB_EP_DIR_OUT) { - USBD->EP[ep_idx - 1].USBD_EPINTEN = 0; - } + } } @@ -1059,6 +1063,7 @@ int usb_dc_ep_read_continue(uint8_t ep) { uint8_t ep_idx = USB_EP_GET_IDX(ep); uint32_t type = dev_data.ep_data[ep_idx].type; + uint32_t ep_status = dev_data.ep_status; if (ep_idx >= NUM_OF_EP_MAX) { LOG_ERR("wrong endpoint index/address"); @@ -1078,18 +1083,34 @@ int usb_dc_ep_read_continue(uint8_t ep) } if (type == USB_DC_EP_CONTROL) { - /* Check CEP has data or not */ - if (USBD->USBD_CEPDATCNT == 0) { + if (ep_status == USB_DC_EP_SETUP) { if (REQTYPE_GET_DIR(dev_data.req_type) == REQTYPE_DIR_TO_HOST) { - LOG_DBG("get"); + USBD->USBD_CEPINTEN = 0; } else { + /* Check CEP has data or not */ + if (dev_data.req_len == 0) { + /* Status Stage */ + USBD->USBD_CEPINTSTS = + BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); + USBD->USBD_CEPINTSTS = + BIT(NPCM4XX_USBD_CEPINTSTS_STSDONEIF); + USBD_SET_CEP_STATE(USBD_CEPCTL_NAKCLR); + USBD->USBD_CEPINTEN = + BIT(NPCM4XX_USBD_CEPINTEN_STSDONEIEN); + } else { + /* Enable CEP OUT Interrupt and wait Receive CEP OUT data */ + USBD->USBD_CEPINTEN = + BIT(NPCM4XX_USBD_CEPINTEN_RXPKIEN); + } + } + } else { + if (dev_data.req_len == 0) { + /* Status Stage */ + USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_SETUPPKIF); USBD->USBD_CEPINTSTS = BIT(NPCM4XX_USBD_CEPINTSTS_STSDONEIF); USBD_SET_CEP_STATE(USBD_CEPCTL_NAKCLR); USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_STSDONEIEN); } - } else { - /* Enable CEP OUT Interrupt and wait Receive CEP OUT data */ - USBD->USBD_CEPINTEN = BIT(NPCM4XX_USBD_CEPINTEN_RXPKIEN); } } else { /* Enable Interrupt to ack OUT */