From eb0c1ac0c3a3544366b7be5014a23d96ec4e9c9e Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Sat, 26 Dec 2015 13:29:09 +0000 Subject: USB synchronous API, to be completed. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8648 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/include/usb.h | 45 +++++++++++++++++- os/hal/ports/STM32/LLD/OTGv1/usb_lld.c | 8 ++-- os/hal/ports/STM32/LLD/OTGv1/usb_lld.h | 20 ++++++-- os/hal/src/usb.c | 84 +++++++++++++++++++++++++++++----- 4 files changed, 136 insertions(+), 21 deletions(-) diff --git a/os/hal/include/usb.h b/os/hal/include/usb.h index 896aa31cd..4aed90a08 100644 --- a/os/hal/include/usb.h +++ b/os/hal/include/usb.h @@ -236,6 +236,14 @@ /* Driver pre-compile time settings. */ /*===========================================================================*/ +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT TRUE +#endif + /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ @@ -537,10 +545,24 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, * * @notapi */ +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) #define _usb_isr_invoke_in_cb(usbp, ep) { \ (usbp)->transmitting &= ~(1 << (ep)); \ - (usbp)->epc[ep]->in_cb(usbp, ep); \ + if ((usbp)->epc[ep]->in_cb != NULL) { \ + (usbp)->epc[ep]->in_cb(usbp, ep); \ + } \ + osalSysLockFromISR(); \ + osalThreadResumeI(&(usbp)->epc[ep]->in_state->thread, MSG_OK); \ + osalSysUnlockFromISR(); \ +} +#else +#define _usb_isr_invoke_in_cb(usbp, ep) { \ + (usbp)->transmitting &= ~(1 << (ep)); \ + if ((usbp)->epc[ep]->in_cb != NULL) { \ + (usbp)->epc[ep]->in_cb(usbp, ep); \ + } \ } +#endif /** * @brief Common ISR code, OUT endpoint event. @@ -550,10 +572,25 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, * * @notapi */ +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) +#define _usb_isr_invoke_out_cb(usbp, ep) { \ + (usbp)->receiving &= ~(1 << (ep)); \ + if ((usbp)->epc[ep]->out_cb != NULL) { \ + (usbp)->epc[ep]->out_cb(usbp, ep); \ + } \ + osalSysLockFromISR(); \ + osalThreadResumeI(&(usbp)->epc[ep]->out_state->thread, \ + usbGetReceiveTransactionSizeI(usbp, ep)); \ + osalSysUnlockFromISR(); \ +} +#else #define _usb_isr_invoke_out_cb(usbp, ep) { \ (usbp)->receiving &= ~(1 << (ep)); \ - (usbp)->epc[ep]->out_cb(usbp, ep); \ + if ((usbp)->epc[ep]->out_cb != NULL) { \ + (usbp)->epc[ep]->out_cb(usbp, ep); \ + } \ } +#endif /** @} */ /*===========================================================================*/ @@ -577,6 +614,10 @@ extern "C" { const uint8_t *buf, size_t n); bool usbStartReceiveI(USBDriver *usbp, usbep_t ep); bool usbStartTransmitI(USBDriver *usbp, usbep_t ep); +#if USB_USE_WAIT == TRUE + msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n); + msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n); +#endif bool usbStallReceiveI(USBDriver *usbp, usbep_t ep); bool usbStallTransmitI(USBDriver *usbp, usbep_t ep); void _usb_reset(USBDriver *usbp); diff --git a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c index 4ec8fd976..ab735b903 100644 --- a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c +++ b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.c @@ -422,9 +422,9 @@ static void otg_epout_handler(USBDriver *usbp, usbep_t ep) { osp->rxsize = osp->totsize - osp->rxsize; osp->rxcnt = 0; usb_lld_prepare_receive(usbp, ep); - chSysLockFromISR(); + osalSysLockFromISR(); usb_lld_start_out(usbp, ep); - chSysUnlockFromISR(); + osalSysUnlockFromISR(); } else { /* End on OUT transfer.*/ @@ -1005,7 +1005,7 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { /* OUT endpoint activation or deactivation.*/ otgp->oe[ep].DOEPTSIZ = 0; - if (usbp->epc[ep]->out_cb != NULL) { + if (usbp->epc[ep]->out_maxsize != 0) { otgp->oe[ep].DOEPCTL = ctl | DOEPCTL_MPSIZ(usbp->epc[ep]->out_maxsize); otgp->DAINTMSK |= DAINTMSK_OEPM(ep); } @@ -1016,7 +1016,7 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { /* IN endpoint activation or deactivation.*/ otgp->ie[ep].DIEPTSIZ = 0; - if (usbp->epc[ep]->in_cb != NULL) { + if (usbp->epc[ep]->in_maxsize != 0) { /* FIFO allocation for the IN endpoint.*/ fsize = usbp->epc[ep]->in_maxsize / 4; if (usbp->epc[ep]->in_multiplier > 1) diff --git a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h index 544d5aecd..f59685c43 100644 --- a/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h +++ b/os/hal/ports/STM32/LLD/OTGv1/usb_lld.h @@ -226,6 +226,12 @@ typedef struct { * @brief Pointer to the transmission linear buffer. */ const uint8_t *txbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif /* End of the mandatory fields.*/ /** * @brief Total transmit transfer size. @@ -249,6 +255,12 @@ typedef struct { * @brief Pointer to the receive linear buffer. */ uint8_t *rxbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif /* End of the mandatory fields.*/ /** * @brief Total transmit transfer size. @@ -278,14 +290,14 @@ typedef struct { usbepcallback_t setup_cb; /** * @brief IN endpoint notification callback. - * @details This field must be set to @p NULL if the IN endpoint is not - * used. + * @details This field must can be set to @p NULL if callback is not + * required. */ usbepcallback_t in_cb; /** * @brief OUT endpoint notification callback. - * @details This field must be set to @p NULL if the OUT endpoint is not - * used. + * @details This field must can be set to @p NULL if callback is not + * required. */ usbepcallback_t out_cb; /** diff --git a/os/hal/src/usb.c b/os/hal/src/usb.c index cea90b32e..14d345b09 100644 --- a/os/hal/src/usb.c +++ b/os/hal/src/usb.c @@ -345,13 +345,6 @@ void usbInitEndpointI(USBDriver *usbp, usbep_t ep, osalDbgAssert(usbp->epc[ep] == NULL, "already initialized"); /* Logically enabling the endpoint in the USBDriver structure.*/ - if (epcp->in_state != NULL) { - memset(epcp->in_state, 0, sizeof(USBInEndpointState)); - } - if (epcp->out_state != NULL) { - memset(epcp->out_state, 0, sizeof(USBOutEndpointState)); - } - usbp->epc[ep] = epcp; /* Low level endpoint activation.*/ @@ -399,11 +392,17 @@ void usbDisableEndpointsI(USBDriver *usbp) { * @special */ void usbPrepareReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { - USBOutEndpointState *osp = usbp->epc[ep]->out_state; + USBOutEndpointState *osp; + osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); + + osp = usbp->epc[ep]->out_state; osp->rxbuf = buf; osp->rxsize = n; osp->rxcnt = 0; +#if USB_USE_WAIT == TRUE + osp->thread = NULL; +#endif usb_lld_prepare_receive(usbp, ep); } @@ -424,11 +423,17 @@ void usbPrepareReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { */ void usbPrepareTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { - USBInEndpointState *isp = usbp->epc[ep]->in_state; + USBInEndpointState *isp; + + osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); + isp = usbp->epc[ep]->in_state; isp->txbuf = buf; isp->txsize = n; isp->txcnt = 0; +#if USB_USE_WAIT == TRUE + isp->thread = NULL; +#endif usb_lld_prepare_transmit(usbp, ep); } @@ -450,7 +455,7 @@ void usbPrepareTransmit(USBDriver *usbp, usbep_t ep, bool usbStartReceiveI(USBDriver *usbp, usbep_t ep) { osalDbgCheckClassI(); - osalDbgCheck(usbp != NULL); + osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); if (usbGetReceiveStatusI(usbp, ep)) { return true; @@ -478,7 +483,7 @@ bool usbStartReceiveI(USBDriver *usbp, usbep_t ep) { bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) { osalDbgCheckClassI(); - osalDbgCheck(usbp != NULL); + osalDbgCheck((usbp != NULL) && (ep <= USB_MAX_ENDPOINTS)); if (usbGetTransmitStatusI(usbp, ep)) { return true; @@ -489,6 +494,63 @@ bool usbStartTransmitI(USBDriver *usbp, usbep_t ep) { return false; } +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) +/** + * @brief Performs a receive transaction on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the received data + * @param[in] n transaction size. It is recommended a multiple of + * the packet size because the excess is discarded. + * + * @return The received data effective size, it can be less than + * the amount specified. + * @retval MSG_RESET operation aborted by a reset. + * + * @api + */ +msg_t usbReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { + msg_t msg; + + usbPrepareReceive(usbp, ep, buf, n); + + osalSysLock(); + usbStartReceiveI(usbp, ep); + msg = osalThreadSuspendS(&usbp->epc[ep]->out_state->thread); + osalSysUnlock(); + + return msg; +} + +/** + * @brief Performs a transmit transaction on an IN endpoint. + * + * @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 + * + * @return The operation status. + * @retval MSG_OK operation performed successfully. + * @retval MSG_RESET operation aborted by a reset. + * + * @api + */ +msg_t usbTransmit(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { + msg_t msg; + + usbPrepareTransmit(usbp, ep, buf, n); + + osalSysLock(); + usbStartReceiveI(usbp, ep); + msg = osalThreadSuspendS(&usbp->epc[ep]->in_state->thread); + osalSysUnlock(); + + return msg; +} +#endif /* USB_USE_WAIT == TRUE */ + /** * @brief Stalls an OUT endpoint. * -- cgit v1.2.3