Esempio n. 1
0
/**
 * @brief   Starts a transmit transaction on an IN endpoint.
 * @note    This function is meant to be called from ISR context outside
 *          critical zones because there is a potentially slow operation
 *          inside.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 * @param[in] buf       buffer where to fetch the data to be transmitted
 * @param[in] n         transaction size
 *
 * @iclass
 */
void usbStartTransmitI(USBDriver *usbp, usbep_t ep,
                       const uint8_t *buf, size_t n) {
  USBInEndpointState *isp;

  osalDbgCheckClassI();
  osalDbgCheck((usbp != NULL) && (ep <= (usbep_t)USB_MAX_ENDPOINTS));
  osalDbgAssert(!usbGetTransmitStatusI(usbp, ep), "already transmitting");

  /* Marking the endpoint as active.*/
  usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep);

  /* Setting up the transfer.*/
  /*lint -save -e661 [18.1] pclint is confused by the check on ep.*/
  isp = usbp->epc[ep]->in_state;
  /*lint -restore*/
  isp->txbuf  = buf;
  isp->txsize = n;
  isp->txcnt  = 0;
#if USB_USE_WAIT == TRUE
  isp->thread = NULL;
#endif

  /* Starting transfer.*/
  usb_lld_start_in(usbp, ep);
}
Esempio n. 2
0
/**
 * @brief   Starts a transmit transaction on an IN endpoint.
 * @post    The endpoint callback is invoked when the transfer has been
 *          completed.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 *
 * @return              The operation status.
 * @retval false        Operation started successfully.
 * @retval true         Endpoint busy, operation not started.
 *
 * @iclass
 */
bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) {

  osalDbgCheckClassI();
  osalDbgCheck(usbp != NULL);

  if (usbGetTransmitStatusI(usbp, ep))
    return true;

  usbp->transmitting |= (1 << ep);
  usb_lld_start_in(usbp, ep);
  return false;
}
Esempio n. 3
0
/**
 * @brief   Starts a transmit transaction on an IN endpoint.
 * @post    The endpoint callback is invoked when the transfer has been
 *          completed.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 *
 * @return              The operation status.
 * @retval FALSE        Operation started successfully.
 * @retval TRUE         Endpoint busy, operation not started.
 *
 * @iclass
 */
bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep) {

  chDbgCheckClassI();
  chDbgCheck(usbp != NULL, "usbStartTransmitI");

  if (usbGetTransmitStatusI(usbp, ep))
    return TRUE;

  usbp->transmitting |= (1 << ep);
  usb_lld_start_in(usbp, ep);
  return FALSE;
}
Esempio n. 4
0
/**
 * @brief   Starts a transmit transaction on an IN endpoint.
 * @post    The endpoint callback is invoked when the transfer has been
 *          completed.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 *
 * @return              The operation status.
 * @retval false        Operation started successfully.
 * @retval true         Endpoint busy, operation not started.
 *
 * @iclass
 */
bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) {

  osalDbgCheckClassI();
  osalDbgCheck(usbp != NULL);

  if (usbGetTransmitStatusI(usbp, ep)) {
    return true;
  }

  usbp->transmitting |= (uint16_t)((unsigned)1U << (unsigned)ep);
  usb_lld_start_in(usbp, ep);
  return false;
}
Esempio n. 5
0
/**
 * @brief   Generic endpoint IN handler.
 *
 * @param[in] usbp      pointer to the @p USBDriver object
 * @param[in] ep        endpoint number
 *
 * @notapi
 */
static void otg_epin_handler(USBDriver *usbp, usbep_t ep) {
  stm32_otg_t *otgp = usbp->otg;
  uint32_t epint = otgp->ie[ep].DIEPINT;

  otgp->ie[ep].DIEPINT = epint;

  if (epint & DIEPINT_TOC) {
    /* Timeouts not handled yet, not sure how to handle.*/
  }
  if ((epint & DIEPINT_XFRC) && (otgp->DIEPMSK & DIEPMSK_XFRCM)) {
    /* Transmit transfer complete.*/
    USBInEndpointState *isp = usbp->epc[ep]->in_state;

    if (isp->txsize < isp->totsize) {
      /* In case the transaction covered only part of the total transfer
         then another transaction is immediately started in order to
         cover the remaining.*/
      isp->txsize = isp->totsize - isp->txsize;
      isp->txcnt  = 0;
      usb_lld_prepare_transmit(usbp, ep);
      chSysLockFromIsr();
      usb_lld_start_in(usbp, ep);
      chSysUnlockFromIsr();
    }
    else {
      /* End on IN transfer.*/
      _usb_isr_invoke_in_cb(usbp, ep);
    }
  }
  if ((epint & DIEPINT_TXFE) &&
      (otgp->DIEPEMPMSK & DIEPEMPMSK_INEPTXFEM(ep))) {
    /* The thread is made ready, it will be scheduled on ISR exit.*/
    chSysLockFromIsr();
    usbp->txpending |= (1 << ep);
    otgp->DIEPEMPMSK &= ~(1 << ep);
    usb_lld_wakeup_pump(usbp);
    chSysUnlockFromIsr();
  }
}
Esempio n. 6
0
static void ep_isr(USBDriver *usbp, usbep_t ep) {
  const USBEndpointConfig *epcp = usbp->epc[ep];
  size_t n;
  UENUM = ep & 0xf;

  /* TODO: if stalling is needed/expected remove this check */
  osalDbgAssert(!(UEINTX & (1 << STALLEDI)), "Endpoint stalled!");

  if ((UEIENX & (1 << TXINE)) && (UEINTX & (1 << TXINI))) {
    /* Ready to accept more IN data to transmit to host */
    /* Disable TXIN interrupt for now, will be re-enabled below if we
     * send more data */
    UEIENX &= ~(1 << TXINE);

    /* Update transaction counts to reflect newly transmitted bytes */
    epcp->in_state->txcnt += epcp->in_state->last_tx_size;
    n = epcp->in_state->txsize - epcp->in_state->txcnt;
    if (n > 0) {
      /* Transfer not completed, there are more packets to send. */
      usb_fifo_write(usbp, ep, n);

      osalSysLockFromISR();
      usb_lld_start_in(usbp, ep);
      osalSysUnlockFromISR();
    } else {
      UEINTX &= ~(1 << TXINI);
      _usb_isr_invoke_in_cb(usbp, ep);
    }
  }

  if ((UEIENX & (1 << RXSTPE)) && (UEINTX & (1 << RXSTPI))) {
    /* Received SETUP data */
    /* Reset transaction state for endpoint */
    epcp->in_state->txcnt = 0;
    epcp->in_state->txsize = 0;
    epcp->in_state->last_tx_size = 0;
    /* Setup packets handling, setup packets are handled using a
       specific callback.*/
    _usb_isr_invoke_setup_cb(usbp, ep);
  } else if (UEINTX & (1 << RXOUTI)) {
    /* Received OUT data from host */
    if (ep == 0 && usbp->ep0state == USB_EP0_WAITING_STS) {
      /* SETUP/control transaction complete, invoke the callback. */
      n = 0;
      UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON));
      _usb_isr_invoke_out_cb(usbp, ep);
    } else {
      /* Check the FIFO byte count to see how many bytes were received */
      n = UEBCX;
    }
    if (n > 0) {
      usb_fifo_read(usbp, ep, n);

      /* Mark OUT FIFO processed to allow more data to be received */
      UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON));

      /* Transaction state update */
      epcp->out_state->rxcnt += n;
      epcp->out_state->rxsize -= n;
      epcp->out_state->rxpkts -= 1;
      if (n < epcp->out_maxsize || epcp->out_state->rxpkts == 0) {
        /* Transfer complete, invokes the callback.*/
        _usb_isr_invoke_out_cb(usbp, ep);
      }
    }
  }
}