diff --git a/os/hal/include/usb.h b/os/hal/include/usb.h index 82ff59d03..a7b183fe4 100644 --- a/os/hal/include/usb.h +++ b/os/hal/include/usb.h @@ -139,7 +139,8 @@ typedef enum { USB_EP0_TX, /**< Trasmitting. */ USB_EP0_WAITING_STS, /**< Waiting status. */ USB_EP0_RX, /**< Receiving. */ - USB_EP0_SENDING_STS /**< Sending status. */ + USB_EP0_SENDING_STS, /**< Sending status. */ + USB_EP0_ERROR /**< Error, EP0 stalled. */ } usbep0state_t; /** @@ -255,6 +256,37 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, */ #define usbGetReceiveStatusI(usbp, ep) ((usbp)->receiving & (1 << (ep))) +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @iclass + */ +#define usbGetReceiveTransactionSizeI(usbp, ep) \ + usb_lld_get_transaction_size(usbp, ep) + +/** + * @brief Returns the exact size of a received packet. + * @pre The OUT endpoint must have been configured in packet mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @iclass + */ +#define usbGetReceivePacketSizeI(usbp, ep) \ + usb_lld_get_packet_size(usbp, ep) + /** * @brief Request transfer setup. * @details This macro is used by the request handling callbacks in order to @@ -266,9 +298,10 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp, * * @api */ -#define usbSetupTransfer(usbp, buf, n) { \ +#define usbSetupTransfer(usbp, buf, n, endcb) { \ (usbp)->ep0next = (buf); \ (usbp)->ep0n = (n); \ + (usbp)->ep0endcb = (endcb); \ } /*===========================================================================*/ @@ -282,7 +315,7 @@ extern "C" { void usbObjectInit(USBDriver *usbp); void usbStart(USBDriver *usbp, const USBConfig *config); void usbStop(USBDriver *usbp); - void usbInitEndpointI(USBDriver *usbp, usbep_t ep, USBEndpointState *epp, + void usbInitEndpointI(USBDriver *usbp, usbep_t ep, const USBEndpointConfig *epcp); void usbDisableEndpointsI(USBDriver *usbp); size_t usbReadPacketI(USBDriver *usbp, usbep_t ep, diff --git a/os/hal/platforms/STM32/usb_lld.c b/os/hal/platforms/STM32/usb_lld.c index cecbc9934..5125f1cee 100644 --- a/os/hal/platforms/STM32/usb_lld.c +++ b/os/hal/platforms/STM32/usb_lld.c @@ -50,8 +50,19 @@ USBDriver USBD1; /** * @brief EP0 state. + * @note It is an union because IN and OUT endpoints are never used at the + * same time for EP0. */ -static USBEndpointState ep0state; +static union { + /** + * @brief IN EP0 state. + */ + USBInEndpointState in; + /** + * @brief OUT EP0 state. + */ + USBOutEndpointState out; +} ep0_state; /** * @brief EP0 initialization structure. @@ -61,7 +72,9 @@ static const USBEndpointConfig ep0config = { _usb_ep0in, _usb_ep0out, 0x40, - 0x40 + 0x40, + &ep0_state.in, + &ep0_state.out }; /*===========================================================================*/ @@ -191,33 +204,33 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) { while (istr & ISTR_CTR) { uint32_t ep; uint32_t epr = STM32_USB->EPR[ep = istr & ISTR_EP_ID_MASK]; - const USBEndpointConfig *epcp = usbp->ep[ep]->config; + const USBEndpointConfig *epcp = usbp->epc[ep]; if (epr & EPR_CTR_TX) { /* IN endpoint, transmission.*/ EPR_CLEAR_CTR_TX(ep); if (epcp->ep_mode & USB_EP_MODE_PACKET) { /* Packet mode, just invokes the callback.*/ - (usbp)->transmitting &= ~((uint16_t)(1 << ep)); + (usbp)->transmitting &= ~(1 << ep); epcp->in_cb(usbp, ep); } else { /* Transaction mode.*/ n = USB_GET_DESCRIPTOR(ep)->TXCOUNT; - usbp->ep[ep]->txbuf += n; - usbp->ep[ep]->txcnt += n; - usbp->ep[ep]->txsize -= n; - if (usbp->ep[ep]->txsize > 0) { + epcp->in_state->txbuf += n; + epcp->in_state->txcnt += n; + epcp->in_state->txsize -= n; + if (epcp->in_state->txsize > 0) { /* Transfer not completed, there are more packets to send.*/ - if (usbp->ep[ep]->txsize > epcp->in_maxsize) + if (epcp->in_state->txsize > epcp->in_maxsize) n = epcp->in_maxsize; else - n = usbp->ep[ep]->txsize; - write_packet(ep, usbp->ep[ep]->txbuf, n); + n = epcp->in_state->txsize; + write_packet(ep, epcp->in_state->txbuf, n); } else { /* Transfer completed, invokes the callback.*/ - (usbp)->transmitting &= ~((uint16_t)(1 << ep)); + (usbp)->transmitting &= ~(1 << ep); epcp->in_cb(usbp, ep); } } @@ -227,10 +240,11 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) { /* OUT endpoint, receive.*/ if (epcp->ep_mode & USB_EP_MODE_PACKET) { /* Packet mode, just invokes the callback.*/ - (usbp)->receiving &= ~((uint16_t)(1 << ep)); + (usbp)->receiving &= ~(1 << ep); epcp->out_cb(usbp, ep); } else { + /* Transaction mode.*/ if ((epr & EPR_SETUP) && (ep == 0)) { /* Special case, setup packet for EP0, enforcing a reset of the EP0 state machine for robustness.*/ @@ -239,18 +253,18 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) { epcp->out_cb(usbp, ep); } else { - n = read_packet(ep, usbp->ep[ep]->rxbuf, usbp->ep[ep]->rxsize); - usbp->ep[ep]->rxbuf += n; - usbp->ep[ep]->rxcnt += n; - usbp->ep[ep]->rxsize -= n; - usbp->ep[ep]->rxpkts -= 1; - if (usbp->ep[ep]->rxpkts > 0) { + n = read_packet(ep, epcp->out_state->rxbuf, epcp->out_state->rxsize); + epcp->out_state->rxbuf += n; + epcp->out_state->rxcnt += n; + epcp->out_state->rxsize -= n; + epcp->out_state->rxpkts -= 1; + if (epcp->out_state->rxpkts > 0) { /* Transfer not completed, there are more packets to receive.*/ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); } else { /* Transfer completed, invokes the callback.*/ - (usbp)->receiving &= ~((uint16_t)(1 << ep)); + (usbp)->receiving &= ~(1 << ep); epcp->out_cb(usbp, ep); } } @@ -306,10 +320,10 @@ void usb_lld_start(USBDriver *usbp) { NVICEnableVector(USB_LP_CAN1_RX0_IRQn, CORTEX_PRIORITY_MASK(STM32_USB_USB1_LP_IRQ_PRIORITY)); - /* Reset procedure enforced on driver start.*/ - _usb_reset(&USBD1); } #endif + /* Reset procedure enforced on driver start.*/ + _usb_reset(usbp); } /* Configuration.*/ } @@ -329,6 +343,7 @@ void usb_lld_stop(USBDriver *usbp) { if (&USBD1 == usbp) { NVICDisableVector(USB_HP_CAN1_TX_IRQn); NVICDisableVector(USB_LP_CAN1_RX0_IRQn); + STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES; RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; } #endif @@ -364,9 +379,7 @@ void usb_lld_reset(USBDriver *usbp) { pm_reset(usbp); /* EP0 initialization.*/ - memset(&ep0state, 0, sizeof ep0state); - ep0state.config = &ep0config; - usbp->ep[0] = &ep0state; + usbp->epc[0] = &ep0config; usb_lld_init_endpoint(usbp, 0); } @@ -393,7 +406,7 @@ void usb_lld_set_address(USBDriver *usbp) { void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { uint16_t nblocks, epr; stm32_usb_descriptor_t *dp; - const USBEndpointConfig *epcp = usbp->ep[ep]->config; + const USBEndpointConfig *epcp = usbp->epc[ep]; /* Setting the endpoint type.*/ switch (epcp->ep_mode & USB_EP_MODE_TYPE) { @@ -418,7 +431,7 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { start ready to accept data else it must start in NAK mode.*/ if (epcp->out_cb) { if (epcp->ep_mode & USB_EP_MODE_PACKET) { - usbp->receiving |= ((uint16_t)(1 << ep)); + usbp->receiving |= (1 << ep); epr |= EPR_STAT_RX_VALID; } else @@ -585,16 +598,16 @@ void usb_lld_write_packet(USBDriver *usbp, usbep_t ep, */ void usb_lld_start_out(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) { - USBEndpointState *uesp = usbp->ep[ep]; + USBOutEndpointState *osp = usbp->epc[ep]->out_state; - uesp->rxbuf = buf; - uesp->rxsize = n; - uesp->rxcnt = 0; - if (uesp->rxsize == 0) /* Special case for zero sized packets.*/ - uesp->rxpkts = 1; + osp->rxbuf = buf; + osp->rxsize = n; + osp->rxcnt = 0; + if (osp->rxsize == 0) /* Special case for zero sized packets.*/ + osp->rxpkts = 1; else - uesp->rxpkts = (uint16_t)((n + uesp->config->out_maxsize - 1) / - uesp->config->out_maxsize); + osp->rxpkts = (uint16_t)((n + usbp->epc[ep]->out_maxsize - 1) / + usbp->epc[ep]->out_maxsize); EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); } @@ -610,13 +623,13 @@ void usb_lld_start_out(USBDriver *usbp, usbep_t ep, */ void usb_lld_start_in(USBDriver *usbp, usbep_t ep, const uint8_t *buf, size_t n) { - USBEndpointState *uesp = usbp->ep[ep]; + USBInEndpointState *isp = usbp->epc[ep]->in_state; - uesp->txbuf = buf; - uesp->txsize = n; - uesp->txcnt = 0; - if (n > (size_t)uesp->config->in_maxsize) - n = (size_t)uesp->config->in_maxsize; + isp->txbuf = buf; + isp->txsize = n; + isp->txcnt = 0; + if (n > (size_t)usbp->epc[ep]->in_maxsize) + n = (size_t)usbp->epc[ep]->in_maxsize; write_packet(ep, buf, n); } diff --git a/os/hal/platforms/STM32/usb_lld.h b/os/hal/platforms/STM32/usb_lld.h index d82fda644..42f32560e 100644 --- a/os/hal/platforms/STM32/usb_lld.h +++ b/os/hal/platforms/STM32/usb_lld.h @@ -93,6 +93,46 @@ /* Driver data structures and types. */ /*===========================================================================*/ +/** + * @brief Type of an endpoint state structure. + */ +typedef struct { + /** + * @brief Pointer to the transmission buffer. + */ + const uint8_t *txbuf; + /** + * @brief Requested transmit transfer size. + */ + size_t txsize; + /** + * @brief Transmitted bytes so far. + */ + size_t txcnt; +} USBInEndpointState; + +/** + * @brief Type of an endpoint state structure. + */ +typedef struct { + /** + * @brief Number of packets to receive. + */ + uint16_t rxpkts; + /** + * @brief Pointer to the receive buffer. + */ + uint8_t *rxbuf; + /** + * @brief Requested receive transfer size. + */ + size_t rxsize; + /** + * @brief Received bytes so far. + */ + size_t rxcnt; +} USBOutEndpointState; + /** * @brief Type of an USB endpoint configuration structure. * @note Platform specific restrictions may apply to endpoints. @@ -126,48 +166,23 @@ typedef struct { * used. */ uint16_t out_maxsize; + /** + * @brief @p USBEndpointState associated to the IN endpoint. + * @details This structure maintains the state of the IN endpoint when + * the endpoint is not in packet mode. Endpoints configured in + * packet mode must set this field to @p NULL. + */ + USBInEndpointState *in_state; + /** + * @brief @p USBEndpointState associated to the OUT endpoint. + * @details This structure maintains the state of the OUT endpoint when + * the endpoint is not in packet mode. Endpoints configured in + * packet mode must set this field to @p NULL. + */ + USBOutEndpointState *out_state; /* End of the mandatory fields.*/ } USBEndpointConfig; - -/** - * @brief Type of an endpoint state structure. - */ -typedef struct { - /** - * @brief Configuration associated to the endpoint. - */ - const USBEndpointConfig *config; - /** - * @brief Number of packets to receive. - */ - uint16_t rxpkts; - /** - * @brief Pointer to the transmission buffer. - */ - const uint8_t *txbuf; - /** - * @brief Pointer to the receive buffer. - */ - uint8_t *rxbuf; - /** - * @brief Requested transmit transfer size. - */ - size_t txsize; - /** - * @brief Requested receive transfer size. - */ - size_t rxsize; - /** - * @brief Transmitted bytes so far. - */ - size_t txcnt; - /** - * @brief Received bytes so far. - */ - size_t rxcnt; -} USBEndpointState; - /** * @brief Type of an USB driver configuration structure. */ @@ -223,7 +238,7 @@ struct USBDriver { /** * @brief Active endpoints configurations. */ - USBEndpointState *ep[USB_MAX_ENDPOINTS + 1]; + const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1]; /** * @brief Endpoint 0 state. */ @@ -232,14 +247,14 @@ struct USBDriver { * @brief Next position in the buffer to be transferred through endpoint 0. */ uint8_t *ep0next; - /** - * @brief Maximum number of bytes to be transferred through endpoint 0. - */ - size_t ep0max; /** * @brief Number of bytes yet to be transferred through endpoint 0. */ size_t ep0n; + /** + * @brief Endpoint 0 end transaction callback. + */ + usbcallback_t ep0endcb; /** * @brief Setup packet buffer. */ @@ -286,6 +301,37 @@ struct USBDriver { */ #define usb_lld_get_frame_number(usbp) (STM32_USB->FNR & FNR_FN_MASK) +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_transaction_size(usbp, ep) \ + ((usbp)->epc[ep]->out_state->rxcnt) + +/** + * @brief Returns the exact size of a received packet. + * @pre The OUT endpoint must have been configured in packet mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_packet_size(usbp, ep) \ + ((size_t)USB_GET_DESCRIPTOR(ep)->RXCOUNT & RXCOUNT_COUNT_MASK) + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -294,14 +340,6 @@ struct USBDriver { extern USBDriver USBD1; #endif -#if !defined(__DOXYGEN__) -extern const USBEndpointConfig usb_lld_ep0config; -#endif - -#if !defined(__DOXYGEN__) -extern USBEndpointState usb_lld_ep0state; -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/os/hal/src/serial_usb.c b/os/hal/src/serial_usb.c index 430218edb..83f1c93ff 100644 --- a/os/hal/src/serial_usb.c +++ b/os/hal/src/serial_usb.c @@ -250,14 +250,14 @@ bool_t sduRequestsHook(USBDriver *usbp) { if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { switch (usbp->setup[1]) { case CDC_GET_LINE_CODING: - usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding)); + usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); return TRUE; case CDC_SET_LINE_CODING: - usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding)); + usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL); return TRUE; case CDC_SET_CONTROL_LINE_STATE: /* Nothing to do, there are no control lines.*/ - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; default: return FALSE; diff --git a/os/hal/src/usb.c b/os/hal/src/usb.c index cbbe8f5b3..34e9a14fd 100644 --- a/os/hal/src/usb.c +++ b/os/hal/src/usb.c @@ -54,7 +54,7 @@ static const uint8_t halted_status[] = {0x01, 0x00}; * * @param[in] usbp pointer to the @p USBDriver object */ -void set_address(USBDriver *usbp) { +static void set_address(USBDriver *usbp) { usbp->address = usbp->setup[2]; usb_lld_set_address(usbp); @@ -84,14 +84,14 @@ static bool_t default_handler(USBDriver *usbp) { (usbp->setup[1] << 8))) { case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_STATUS << 8): /* Just returns the current status word.*/ - usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2); + usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL); return TRUE; case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_CLEAR_FEATURE << 8): /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature number is handled as an error.*/ if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { usbp->status &= ~2; - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; } return FALSE; @@ -100,7 +100,7 @@ static bool_t default_handler(USBDriver *usbp) { number is handled as an error.*/ if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { usbp->status |= 2; - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; } return FALSE; @@ -112,8 +112,10 @@ static bool_t default_handler(USBDriver *usbp) { if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && (usbp->setup[1] == USB_REQ_SET_ADDRESS)) set_address(usbp); + usbSetupTransfer(usbp, NULL, 0, NULL); +#else + usbSetupTransfer(usbp, NULL, 0, set_address); #endif - usbSetupTransfer(usbp, NULL, 0); return TRUE; case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_DESCRIPTOR << 8): /* Handling descriptor requests from the host.*/ @@ -122,11 +124,11 @@ static bool_t default_handler(USBDriver *usbp) { usb_lld_fetch_word(&usbp->setup[4])); if (dp == NULL) return FALSE; - usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size); + usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); return TRUE; case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_CONFIGURATION << 8): /* Returning the last selected configuration.*/ - usbSetupTransfer(usbp, &usbp->configuration, 1); + usbSetupTransfer(usbp, &usbp->configuration, 1, NULL); return TRUE; case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_CONFIGURATION << 8): /* Handling configuration selection from the host.*/ @@ -137,23 +139,23 @@ static bool_t default_handler(USBDriver *usbp) { usbp->state = USB_ACTIVE; if (usbp->config->event_cb) usbp->config->event_cb(usbp, USB_EVENT_CONFIGURED); - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_STATUS << 8): case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SYNCH_FRAME << 8): /* Just sending two zero bytes, the application can change the behavior using a hook..*/ - usbSetupTransfer(usbp, (uint8_t *)zero_status, 2); + usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL); return TRUE; case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_GET_STATUS << 8): /* Sending the EP status.*/ if (usbp->setup[4] & 0x80) { switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0F)) { case EP_STATUS_STALLED: - usbSetupTransfer(usbp, (uint8_t *)halted_status, 2); + usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); return TRUE; case EP_STATUS_ACTIVE: - usbSetupTransfer(usbp, (uint8_t *)active_status, 2); + usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); return TRUE; default: return FALSE; @@ -162,10 +164,10 @@ static bool_t default_handler(USBDriver *usbp) { else { switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0F)) { case EP_STATUS_STALLED: - usbSetupTransfer(usbp, (uint8_t *)halted_status, 2); + usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL); return TRUE; case EP_STATUS_ACTIVE: - usbSetupTransfer(usbp, (uint8_t *)active_status, 2); + usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL); return TRUE; default: return FALSE; @@ -182,7 +184,7 @@ static bool_t default_handler(USBDriver *usbp) { else usb_lld_clear_out(usbp, usbp->setup[4] & 0x0F); } - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SET_FEATURE << 8): /* Only ENDPOINT_HALT is handled as feature.*/ @@ -195,7 +197,7 @@ static bool_t default_handler(USBDriver *usbp) { else usb_lld_stall_out(usbp, usbp->setup[4] & 0x0F); } - usbSetupTransfer(usbp, NULL, 0); + usbSetupTransfer(usbp, NULL, 0, NULL); return TRUE; case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_DESCRIPTOR << 8): case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_CLEAR_FEATURE << 8): @@ -259,7 +261,7 @@ void usbStart(USBDriver *usbp, const USBConfig *config) { "usbStart(), #1", "invalid state"); usbp->config = config; for (i = 0; i <= USB_MAX_ENDPOINTS; i++) - usbp->ep[i] = NULL; + usbp->epc[i] = NULL; usb_lld_start(usbp); usbp->state = USB_READY; chSysUnlock(); @@ -293,23 +295,24 @@ void usbStop(USBDriver *usbp) { * * @param[in] usbp pointer to the @p USBDriver object * @param[in] ep endpoint number - * @param[out] epp pointer to an endpoint state descriptor structure * @param[in] epcp the endpoint configuration * * @iclass */ -void usbInitEndpointI(USBDriver *usbp, usbep_t ep, USBEndpointState *epp, +void usbInitEndpointI(USBDriver *usbp, usbep_t ep, const USBEndpointConfig *epcp) { chDbgAssert(usbp->state == USB_ACTIVE, "usbEnableEndpointI(), #1", "invalid state"); - chDbgAssert(usbp->ep[ep] != NULL, + chDbgAssert(usbp->epc[ep] != NULL, "usbEnableEndpointI(), #2", "already initialized"); /* Logically enabling the endpoint in the USBDriver structure.*/ - memset(epp, 0, sizeof(USBEndpointState)); - epp->config = epcp; - usbp->ep[ep] = epp; + if (!(epcp->ep_mode & USB_EP_MODE_PACKET)) { + memset(epcp->in_state, 0, sizeof(USBInEndpointState)); + memset(epcp->out_state, 0, sizeof(USBOutEndpointState)); + } + usbp->epc[ep] = epcp; /* Low level endpoint activation.*/ usb_lld_init_endpoint(usbp, ep); @@ -333,7 +336,7 @@ void usbDisableEndpointsI(USBDriver *usbp) { "usbDisableEndpointsI(), #1", "invalid state"); for (i = 1; i <= USB_MAX_ENDPOINTS; i++) - usbp->ep[i] = NULL; + usbp->epc[i] = NULL; /* Low level endpoints deactivation.*/ usb_lld_disable_endpoints(usbp); @@ -493,6 +496,8 @@ bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep) { /** * @brief USB reset routine. + * @details This function must be invoked when an USB bus reset condition is + * detected. * * @param[in] usbp pointer to the @p USBDriver object * @@ -508,7 +513,7 @@ void _usb_reset(USBDriver *usbp) { /* Invalidates all endpoints into the USBDriver structure.*/ for (i = 0; i <= USB_MAX_ENDPOINTS; i++) - usbp->ep[i] = NULL; + usbp->epc[i] = NULL; /* EP0 state machine initialization.*/ usbp->ep0state = USB_EP0_WAITING_SETUP; @@ -538,30 +543,32 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) { multiple of the maximum packet size then a zero size packet must be transmitted.*/ if ((usbp->ep0n < max) && - ((usbp->ep0n % usbp->ep[0]->config->in_maxsize) == 0)) { + ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0)) { usb_lld_start_in(usbp, 0, NULL, 0); return; } + + /* Transmit phase over, receiving the zero sized status packet.*/ usbp->ep0state = USB_EP0_WAITING_STS; usb_lld_start_out(usbp, 0, NULL, 0); return; case USB_EP0_SENDING_STS: -#if USB_SET_ADDRESS_MODE == USB_LATE_SET_ADDRESS - if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && - (usbp->setup[1] == USB_REQ_SET_ADDRESS)) - set_address(usbp); -#endif + /* Status packet sent, invoking the callback if defined.*/ + if (usbp->ep0endcb) + usbp->ep0endcb(usbp); usbp->ep0state = USB_EP0_WAITING_SETUP; return; default: ; } - /* Error response.*/ + /* Error response, the state machine goes into an error state, the low + level layer will have to reset it to USB_EP0_WAITING_SETUP after + receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); if (usbp->config->event_cb) usbp->config->event_cb(usbp, USB_EVENT_STALLED); - usbp->ep0state = USB_EP0_WAITING_SETUP; + usbp->ep0state = USB_EP0_ERROR; } /** @@ -575,13 +582,16 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) { * @notapi */ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { - size_t n, max; + size_t max; (void)ep; switch (usbp->ep0state) { case USB_EP0_WAITING_SETUP: - /* SETUP packet handling. - First verify if the application has an handler installed for this + /* SETUP packet handling. The setup packet is expected to be already + placed into the setup[8] field of the USBDriver structure, the low + level layer has to take care of this.*/ + + /* First verify if the application has an handler installed for this request.*/ if (!(usbp->config->requests_hook_cb) || !(usbp->config->requests_hook_cb(usbp))) { @@ -593,8 +603,8 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { } /* Transfer preparation. The request handler must have populated - correctly the fields ep0next, ep0n and ep0endcb using - the macro usbSetupTransfer().*/ + correctly the fields ep0next, ep0n and ep0endcb using the macro + usbSetupTransfer().*/ max = usb_lld_fetch_word(&usbp->setup[6]); /* The transfer size cannot exceed the specified amount.*/ if (usbp->ep0n > max) @@ -602,12 +612,13 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) { /* IN phase.*/ if (usbp->ep0n > 0) { - /* Starts transmission.*/ + /* Starts the transmit phase.*/ usbp->ep0state = USB_EP0_TX; usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n); } else { - /* Receiving the zero sized status packet.*/ + /* No transmission phase, directly receiving the zero sized status + packet.*/ usbp->ep0state = USB_EP0_WAITING_STS; usb_lld_start_out(usbp, 0, NULL, 0); } @@ -615,37 +626,43 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) { else { /* OUT phase.*/ if (usbp->ep0n > 0) { - /* Starts reception.*/ + /* Starts the receive phase.*/ usbp->ep0state = USB_EP0_RX; usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n); } else { - /* Sending zero sized status packet.*/ + /* No receive phase, directly sending the zero sized status + packet.*/ usbp->ep0state = USB_EP0_SENDING_STS; usb_lld_start_in(usbp, 0, NULL, 0); } } return; case USB_EP0_RX: + /* Receive phase over, sending the zero sized status packet.*/ usbp->ep0state = USB_EP0_SENDING_STS; usb_lld_start_in(usbp, 0, NULL, 0); return; case USB_EP0_WAITING_STS: - /* STATUS received packet handling, it must be zero sized.*/ - n = usbp->ep[0]->rxsize; - if (n != 0) + /* Status packet received, it must be zero sized, invoking the callback + if defined.*/ + if (usbGetReceiveTransactionSizeI(usbp, 0) != 0) break; + if (usbp->ep0endcb) + usbp->ep0endcb(usbp); usbp->ep0state = USB_EP0_WAITING_SETUP; return; default: ; } - /* Error response.*/ + /* Error response, the state machine goes into an error state, the low + level layer will have to reset it to USB_EP0_WAITING_SETUP after + receiving a SETUP packet.*/ usb_lld_stall_in(usbp, 0); usb_lld_stall_out(usbp, 0); if (usbp->config->event_cb) usbp->config->event_cb(usbp, USB_EVENT_STALLED); - usbp->ep0state = USB_EP0_WAITING_SETUP; + usbp->ep0state = USB_EP0_ERROR; } #endif /* HAL_USE_USB */ diff --git a/testhal/STM32/USB_CDC/main.c b/testhal/STM32/USB_CDC/main.c index 00f0d0e66..423a47413 100644 --- a/testhal/STM32/USB_CDC/main.c +++ b/testhal/STM32/USB_CDC/main.c @@ -232,21 +232,6 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp, return NULL; } -/** - * @brief EP1 state. - */ -USBEndpointState ep1state; - -/** - * @brief EP2 state. - */ -USBEndpointState ep2state; - -/** - * @brief EP3 state. - */ -USBEndpointState ep3state; - /** * @brief EP1 initialization structure (IN only). */ @@ -255,7 +240,9 @@ static const USBEndpointConfig ep1config = { sduDataTransmitted, NULL, 0x0040, - 0x0000 + 0x0000, + NULL, + NULL }; /** @@ -266,7 +253,9 @@ static const USBEndpointConfig ep2config = { sduInterruptTransmitted, NULL, 0x0010, - 0x0000 + 0x0000, + NULL, + NULL }; /** @@ -277,7 +266,9 @@ static const USBEndpointConfig ep3config = { NULL, sduDataReceived, 0x0000, - 0x0040 + 0x0040, + NULL, + NULL }; /* @@ -293,9 +284,9 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { case USB_EVENT_CONFIGURED: /* Enables the endpoints specified into the configuration.*/ chSysLock(); - usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1state, &ep1config); - usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2state, &ep2config); - usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3state, &ep3config); + usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1config); + usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2config); + usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3config); chSysUnlock(); return; case USB_EVENT_SUSPEND: