aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-02-14 19:37:40 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-02-14 19:37:40 +0000
commit2c15c4864f33c3c71c58e54494561eff1b291a0f (patch)
tree0fe85fb7e1825b67d78cadab18901bc7e6068e1b
parentdd6a0b3ccdd62873e1cb874969741e3fb683db4b (diff)
downloadChibiOS-2c15c4864f33c3c71c58e54494561eff1b291a0f.tar.gz
ChibiOS-2c15c4864f33c3c71c58e54494561eff1b291a0f.tar.bz2
ChibiOS-2c15c4864f33c3c71c58e54494561eff1b291a0f.zip
More improvements in the USB driver model.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2738 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--os/hal/include/usb.h39
-rw-r--r--os/hal/platforms/STM32/usb_lld.c95
-rw-r--r--os/hal/platforms/STM32/usb_lld.h138
-rw-r--r--os/hal/src/serial_usb.c6
-rw-r--r--os/hal/src/usb.c109
-rw-r--r--testhal/STM32/USB_CDC/main.c33
6 files changed, 256 insertions, 164 deletions
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;
/**
@@ -256,6 +257,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
* prepare a transaction over the endpoint zero.
@@ -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
@@ -94,6 +94,46 @@
/*===========================================================================*/
/**
+ * @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,47 +166,22 @@ typedef struct {
* used.
*/
uint16_t out_maxsize;
- /* End of the mandatory fields.*/
-} USBEndpointConfig;
-
-
-/**
- * @brief Type of an endpoint state structure.
- */
-typedef struct {
/**
- * @brief Configuration associated to the endpoint.
+ * @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.
*/
- const USBEndpointConfig *config;
+ USBInEndpointState *in_state;
/**
- * @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.
+ * @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.
*/
- 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;
+ USBOutEndpointState *out_state;
+ /* End of the mandatory fields.*/
+} USBEndpointConfig;
/**
* @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.
*/
@@ -233,14 +248,14 @@ struct USBDriver {
*/
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.
*/
uint8_t setup[8];
@@ -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
@@ -233,21 +233,6 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp,
}
/**
- * @brief EP1 state.
- */
-USBEndpointState ep1state;
-
-/**
- * @brief EP2 state.
- */
-USBEndpointState ep2state;
-
-/**
- * @brief EP3 state.
- */
-USBEndpointState ep3state;
-
-/**
* @brief EP1 initialization structure (IN only).
*/
static const USBEndpointConfig ep1config = {
@@ -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: