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
This commit is contained in:
gdisirio 2011-02-14 19:37:40 +00:00
parent dd6a0b3ccd
commit 2c15c4864f
6 changed files with 258 additions and 166 deletions

View File

@ -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,

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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: