chenzhihong007 opened a new issue, #10802:
URL: https://github.com/apache/nuttx/issues/10802

   ## Issue Description
   
   When usb as host to connect cdcacm device, using read() API to get data from 
cdcacm device many times, EHCI driver, such as **sam_transfer() - 
sam_ioc_setup()**, will trigger assert in **sam_ioc_setup()**, because 
**epinfo->iocwait** is true.
   
   ``` c
     DEBUGASSERT(rhport && epinfo && !epinfo->iocwait);
   ```
   
   ## Analysis
   read() API caller as follows:
   
   read() - uart_read() - uart_disablerxint()【usbhost_rxint()】 - 
uart_enablerxint()【usbhost_rxint()】 - usbhost_rxdata_work() - 
DRVR_TRANSFER()【sam_transfer()】.
   
   In **usbhost_rxdata_work()**, while loop call 
**DRVR_TRANSFER()【sam_transfer()】** to excute usb IN transition. 
DRVR_TRANSFER() is a blocking method, this functions will not return until the 
transfer has completed, the comments as follows:
   
   ```
    * Name: sam_transfer
    *
    * Description:
    *   Process a request to handle a transfer descriptor.  This method will
    *   enqueue the transfer request, blocking until the transfer completes.
    *   Only one transfer may be  queued; Neither this method nor the ctrlin or
    *   ctrlout methods can be called again until this function returns.
    *
    *   This is a blocking method; this functions will not return until the
    *   transfer has completed.
   ```
   
   But every read() operation, call uart_disablerxint() first, then call 
uart_enablerxint(). So excute read() one time, call DRVR_TRANSFER() one time, 
even DRVR_TRANSFER() in progress or not finish. Thus will cause usb transfer 
abnormal, such as **epinfo->iocwait** is true.
   
   ## Solution
   I have two sulution ideas.
   
   - fix uart_read() logic,delete serial.c 986 line —— uart_disablerxint(dev).
   - fix usbhost_rxint() logic, cancel disable opertion. When rx is enabled, 
keep **priv->rxena** always enable.
   ```
   static void usbhost_rxint(FAR struct uart_dev_s *uartdev, bool enable)
   {
     FAR struct usbhost_cdcacm_s *priv;
     int ret;
   
     DEBUGASSERT(uartdev && uartdev->priv);
     priv = (FAR struct usbhost_cdcacm_s *)uartdev->priv;
   
     /* Are we enabling or disabling RX reception? */
   
     if (enable && !priv->rxena)
       {
         /* Cancel any pending, delayed RX data reception work */
   
         work_cancel(LPWORK, &priv->rxwork);
   
         /* Restart immediate RX data reception work (unless RX flow control
          * is in effect.
          */
   
   #ifdef CONFIG_SERIAL_IFLOWCONTROL
         if (priv->rts)
   #endif
           {
             ret = work_queue(LPWORK, &priv->rxwork,
                              usbhost_rxdata_work, priv, 0);
             DEBUGASSERT(ret >= 0);
             UNUSED(ret);
           }
   
           /* Save the new RX enable state */
   
           priv->rxena = enable;
       }
   }
   ```
   
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to