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_TX, /**< Trasmitting. */
USB_EP0_WAITING_STS, /**< Waiting status. */ USB_EP0_WAITING_STS, /**< Waiting status. */
USB_EP0_RX, /**< Receiving. */ USB_EP0_RX, /**< Receiving. */
USB_EP0_SENDING_STS /**< Sending status. */ USB_EP0_SENDING_STS, /**< Sending status. */
USB_EP0_ERROR /**< Error, EP0 stalled. */
} usbep0state_t; } usbep0state_t;
/** /**
@ -255,6 +256,37 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
*/ */
#define usbGetReceiveStatusI(usbp, ep) ((usbp)->receiving & (1 << (ep))) #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. * @brief Request transfer setup.
* @details This macro is used by the request handling callbacks in order to * @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 * @api
*/ */
#define usbSetupTransfer(usbp, buf, n) { \ #define usbSetupTransfer(usbp, buf, n, endcb) { \
(usbp)->ep0next = (buf); \ (usbp)->ep0next = (buf); \
(usbp)->ep0n = (n); \ (usbp)->ep0n = (n); \
(usbp)->ep0endcb = (endcb); \
} }
/*===========================================================================*/ /*===========================================================================*/
@ -282,7 +315,7 @@ extern "C" {
void usbObjectInit(USBDriver *usbp); void usbObjectInit(USBDriver *usbp);
void usbStart(USBDriver *usbp, const USBConfig *config); void usbStart(USBDriver *usbp, const USBConfig *config);
void usbStop(USBDriver *usbp); void usbStop(USBDriver *usbp);
void usbInitEndpointI(USBDriver *usbp, usbep_t ep, USBEndpointState *epp, void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp); const USBEndpointConfig *epcp);
void usbDisableEndpointsI(USBDriver *usbp); void usbDisableEndpointsI(USBDriver *usbp);
size_t usbReadPacketI(USBDriver *usbp, usbep_t ep, size_t usbReadPacketI(USBDriver *usbp, usbep_t ep,

View File

@ -50,8 +50,19 @@ USBDriver USBD1;
/** /**
* @brief EP0 state. * @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. * @brief EP0 initialization structure.
@ -61,7 +72,9 @@ static const USBEndpointConfig ep0config = {
_usb_ep0in, _usb_ep0in,
_usb_ep0out, _usb_ep0out,
0x40, 0x40,
0x40 0x40,
&ep0_state.in,
&ep0_state.out
}; };
/*===========================================================================*/ /*===========================================================================*/
@ -191,33 +204,33 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
while (istr & ISTR_CTR) { while (istr & ISTR_CTR) {
uint32_t ep; uint32_t ep;
uint32_t epr = STM32_USB->EPR[ep = istr & ISTR_EP_ID_MASK]; 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) { if (epr & EPR_CTR_TX) {
/* IN endpoint, transmission.*/ /* IN endpoint, transmission.*/
EPR_CLEAR_CTR_TX(ep); EPR_CLEAR_CTR_TX(ep);
if (epcp->ep_mode & USB_EP_MODE_PACKET) { if (epcp->ep_mode & USB_EP_MODE_PACKET) {
/* Packet mode, just invokes the callback.*/ /* Packet mode, just invokes the callback.*/
(usbp)->transmitting &= ~((uint16_t)(1 << ep)); (usbp)->transmitting &= ~(1 << ep);
epcp->in_cb(usbp, ep); epcp->in_cb(usbp, ep);
} }
else { else {
/* Transaction mode.*/ /* Transaction mode.*/
n = USB_GET_DESCRIPTOR(ep)->TXCOUNT; n = USB_GET_DESCRIPTOR(ep)->TXCOUNT;
usbp->ep[ep]->txbuf += n; epcp->in_state->txbuf += n;
usbp->ep[ep]->txcnt += n; epcp->in_state->txcnt += n;
usbp->ep[ep]->txsize -= n; epcp->in_state->txsize -= n;
if (usbp->ep[ep]->txsize > 0) { if (epcp->in_state->txsize > 0) {
/* Transfer not completed, there are more packets to send.*/ /* 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; n = epcp->in_maxsize;
else else
n = usbp->ep[ep]->txsize; n = epcp->in_state->txsize;
write_packet(ep, usbp->ep[ep]->txbuf, n); write_packet(ep, epcp->in_state->txbuf, n);
} }
else { else {
/* Transfer completed, invokes the callback.*/ /* Transfer completed, invokes the callback.*/
(usbp)->transmitting &= ~((uint16_t)(1 << ep)); (usbp)->transmitting &= ~(1 << ep);
epcp->in_cb(usbp, ep); epcp->in_cb(usbp, ep);
} }
} }
@ -227,10 +240,11 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
/* OUT endpoint, receive.*/ /* OUT endpoint, receive.*/
if (epcp->ep_mode & USB_EP_MODE_PACKET) { if (epcp->ep_mode & USB_EP_MODE_PACKET) {
/* Packet mode, just invokes the callback.*/ /* Packet mode, just invokes the callback.*/
(usbp)->receiving &= ~((uint16_t)(1 << ep)); (usbp)->receiving &= ~(1 << ep);
epcp->out_cb(usbp, ep); epcp->out_cb(usbp, ep);
} }
else { else {
/* Transaction mode.*/
if ((epr & EPR_SETUP) && (ep == 0)) { if ((epr & EPR_SETUP) && (ep == 0)) {
/* Special case, setup packet for EP0, enforcing a reset of the /* Special case, setup packet for EP0, enforcing a reset of the
EP0 state machine for robustness.*/ EP0 state machine for robustness.*/
@ -239,18 +253,18 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
epcp->out_cb(usbp, ep); epcp->out_cb(usbp, ep);
} }
else { else {
n = read_packet(ep, usbp->ep[ep]->rxbuf, usbp->ep[ep]->rxsize); n = read_packet(ep, epcp->out_state->rxbuf, epcp->out_state->rxsize);
usbp->ep[ep]->rxbuf += n; epcp->out_state->rxbuf += n;
usbp->ep[ep]->rxcnt += n; epcp->out_state->rxcnt += n;
usbp->ep[ep]->rxsize -= n; epcp->out_state->rxsize -= n;
usbp->ep[ep]->rxpkts -= 1; epcp->out_state->rxpkts -= 1;
if (usbp->ep[ep]->rxpkts > 0) { if (epcp->out_state->rxpkts > 0) {
/* Transfer not completed, there are more packets to receive.*/ /* Transfer not completed, there are more packets to receive.*/
EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
} }
else { else {
/* Transfer completed, invokes the callback.*/ /* Transfer completed, invokes the callback.*/
(usbp)->receiving &= ~((uint16_t)(1 << ep)); (usbp)->receiving &= ~(1 << ep);
epcp->out_cb(usbp, ep); epcp->out_cb(usbp, ep);
} }
} }
@ -306,10 +320,10 @@ void usb_lld_start(USBDriver *usbp) {
NVICEnableVector(USB_LP_CAN1_RX0_IRQn, NVICEnableVector(USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK(STM32_USB_USB1_LP_IRQ_PRIORITY)); CORTEX_PRIORITY_MASK(STM32_USB_USB1_LP_IRQ_PRIORITY));
/* Reset procedure enforced on driver start.*/
_usb_reset(&USBD1);
} }
#endif #endif
/* Reset procedure enforced on driver start.*/
_usb_reset(usbp);
} }
/* Configuration.*/ /* Configuration.*/
} }
@ -329,6 +343,7 @@ void usb_lld_stop(USBDriver *usbp) {
if (&USBD1 == usbp) { if (&USBD1 == usbp) {
NVICDisableVector(USB_HP_CAN1_TX_IRQn); NVICDisableVector(USB_HP_CAN1_TX_IRQn);
NVICDisableVector(USB_LP_CAN1_RX0_IRQn); NVICDisableVector(USB_LP_CAN1_RX0_IRQn);
STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES;
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN; RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
} }
#endif #endif
@ -364,9 +379,7 @@ void usb_lld_reset(USBDriver *usbp) {
pm_reset(usbp); pm_reset(usbp);
/* EP0 initialization.*/ /* EP0 initialization.*/
memset(&ep0state, 0, sizeof ep0state); usbp->epc[0] = &ep0config;
ep0state.config = &ep0config;
usbp->ep[0] = &ep0state;
usb_lld_init_endpoint(usbp, 0); 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) { void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
uint16_t nblocks, epr; uint16_t nblocks, epr;
stm32_usb_descriptor_t *dp; stm32_usb_descriptor_t *dp;
const USBEndpointConfig *epcp = usbp->ep[ep]->config; const USBEndpointConfig *epcp = usbp->epc[ep];
/* Setting the endpoint type.*/ /* Setting the endpoint type.*/
switch (epcp->ep_mode & USB_EP_MODE_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.*/ start ready to accept data else it must start in NAK mode.*/
if (epcp->out_cb) { if (epcp->out_cb) {
if (epcp->ep_mode & USB_EP_MODE_PACKET) { if (epcp->ep_mode & USB_EP_MODE_PACKET) {
usbp->receiving |= ((uint16_t)(1 << ep)); usbp->receiving |= (1 << ep);
epr |= EPR_STAT_RX_VALID; epr |= EPR_STAT_RX_VALID;
} }
else 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, void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n) { uint8_t *buf, size_t n) {
USBEndpointState *uesp = usbp->ep[ep]; USBOutEndpointState *osp = usbp->epc[ep]->out_state;
uesp->rxbuf = buf; osp->rxbuf = buf;
uesp->rxsize = n; osp->rxsize = n;
uesp->rxcnt = 0; osp->rxcnt = 0;
if (uesp->rxsize == 0) /* Special case for zero sized packets.*/ if (osp->rxsize == 0) /* Special case for zero sized packets.*/
uesp->rxpkts = 1; osp->rxpkts = 1;
else else
uesp->rxpkts = (uint16_t)((n + uesp->config->out_maxsize - 1) / osp->rxpkts = (uint16_t)((n + usbp->epc[ep]->out_maxsize - 1) /
uesp->config->out_maxsize); usbp->epc[ep]->out_maxsize);
EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID); 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, void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n) { const uint8_t *buf, size_t n) {
USBEndpointState *uesp = usbp->ep[ep]; USBInEndpointState *isp = usbp->epc[ep]->in_state;
uesp->txbuf = buf; isp->txbuf = buf;
uesp->txsize = n; isp->txsize = n;
uesp->txcnt = 0; isp->txcnt = 0;
if (n > (size_t)uesp->config->in_maxsize) if (n > (size_t)usbp->epc[ep]->in_maxsize)
n = (size_t)uesp->config->in_maxsize; n = (size_t)usbp->epc[ep]->in_maxsize;
write_packet(ep, buf, n); write_packet(ep, buf, n);
} }

View File

@ -93,6 +93,46 @@
/* Driver data structures and types. */ /* 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. * @brief Type of an USB endpoint configuration structure.
* @note Platform specific restrictions may apply to endpoints. * @note Platform specific restrictions may apply to endpoints.
@ -126,48 +166,23 @@ typedef struct {
* used. * used.
*/ */
uint16_t out_maxsize; 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.*/ /* End of the mandatory fields.*/
} USBEndpointConfig; } 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. * @brief Type of an USB driver configuration structure.
*/ */
@ -223,7 +238,7 @@ struct USBDriver {
/** /**
* @brief Active endpoints configurations. * @brief Active endpoints configurations.
*/ */
USBEndpointState *ep[USB_MAX_ENDPOINTS + 1]; const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
/** /**
* @brief Endpoint 0 state. * @brief Endpoint 0 state.
*/ */
@ -232,14 +247,14 @@ struct USBDriver {
* @brief Next position in the buffer to be transferred through endpoint 0. * @brief Next position in the buffer to be transferred through endpoint 0.
*/ */
uint8_t *ep0next; 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. * @brief Number of bytes yet to be transferred through endpoint 0.
*/ */
size_t ep0n; size_t ep0n;
/**
* @brief Endpoint 0 end transaction callback.
*/
usbcallback_t ep0endcb;
/** /**
* @brief Setup packet buffer. * @brief Setup packet buffer.
*/ */
@ -286,6 +301,37 @@ struct USBDriver {
*/ */
#define usb_lld_get_frame_number(usbp) (STM32_USB->FNR & FNR_FN_MASK) #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. */ /* External declarations. */
/*===========================================================================*/ /*===========================================================================*/
@ -294,14 +340,6 @@ struct USBDriver {
extern USBDriver USBD1; extern USBDriver USBD1;
#endif #endif
#if !defined(__DOXYGEN__)
extern const USBEndpointConfig usb_lld_ep0config;
#endif
#if !defined(__DOXYGEN__)
extern USBEndpointState usb_lld_ep0state;
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif

View File

@ -250,14 +250,14 @@ bool_t sduRequestsHook(USBDriver *usbp) {
if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) {
switch (usbp->setup[1]) { switch (usbp->setup[1]) {
case CDC_GET_LINE_CODING: case CDC_GET_LINE_CODING:
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding)); usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
return TRUE; return TRUE;
case CDC_SET_LINE_CODING: case CDC_SET_LINE_CODING:
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding)); usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
return TRUE; return TRUE;
case CDC_SET_CONTROL_LINE_STATE: case CDC_SET_CONTROL_LINE_STATE:
/* Nothing to do, there are no control lines.*/ /* Nothing to do, there are no control lines.*/
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
default: default:
return FALSE; 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 * @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]; usbp->address = usbp->setup[2];
usb_lld_set_address(usbp); usb_lld_set_address(usbp);
@ -84,14 +84,14 @@ static bool_t default_handler(USBDriver *usbp) {
(usbp->setup[1] << 8))) { (usbp->setup[1] << 8))) {
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_STATUS << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_STATUS << 8):
/* Just returns the current status word.*/ /* Just returns the current status word.*/
usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2); usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_CLEAR_FEATURE << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_CLEAR_FEATURE << 8):
/* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature /* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature
number is handled as an error.*/ number is handled as an error.*/
if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
usbp->status &= ~2; usbp->status &= ~2;
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -100,7 +100,7 @@ static bool_t default_handler(USBDriver *usbp) {
number is handled as an error.*/ number is handled as an error.*/
if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) { if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
usbp->status |= 2; usbp->status |= 2;
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
@ -112,8 +112,10 @@ static bool_t default_handler(USBDriver *usbp) {
if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) &&
(usbp->setup[1] == USB_REQ_SET_ADDRESS)) (usbp->setup[1] == USB_REQ_SET_ADDRESS))
set_address(usbp); set_address(usbp);
usbSetupTransfer(usbp, NULL, 0, NULL);
#else
usbSetupTransfer(usbp, NULL, 0, set_address);
#endif #endif
usbSetupTransfer(usbp, NULL, 0);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_DESCRIPTOR << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_DESCRIPTOR << 8):
/* Handling descriptor requests from the host.*/ /* Handling descriptor requests from the host.*/
@ -122,11 +124,11 @@ static bool_t default_handler(USBDriver *usbp) {
usb_lld_fetch_word(&usbp->setup[4])); usb_lld_fetch_word(&usbp->setup[4]));
if (dp == NULL) if (dp == NULL)
return FALSE; 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; return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_CONFIGURATION << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_CONFIGURATION << 8):
/* Returning the last selected configuration.*/ /* Returning the last selected configuration.*/
usbSetupTransfer(usbp, &usbp->configuration, 1); usbSetupTransfer(usbp, &usbp->configuration, 1, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_CONFIGURATION << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_CONFIGURATION << 8):
/* Handling configuration selection from the host.*/ /* Handling configuration selection from the host.*/
@ -137,23 +139,23 @@ static bool_t default_handler(USBDriver *usbp) {
usbp->state = USB_ACTIVE; usbp->state = USB_ACTIVE;
if (usbp->config->event_cb) if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_CONFIGURED); usbp->config->event_cb(usbp, USB_EVENT_CONFIGURED);
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_STATUS << 8): case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_STATUS << 8):
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SYNCH_FRAME << 8): case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SYNCH_FRAME << 8):
/* Just sending two zero bytes, the application can change the behavior /* Just sending two zero bytes, the application can change the behavior
using a hook..*/ using a hook..*/
usbSetupTransfer(usbp, (uint8_t *)zero_status, 2); usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_GET_STATUS << 8): case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_GET_STATUS << 8):
/* Sending the EP status.*/ /* Sending the EP status.*/
if (usbp->setup[4] & 0x80) { if (usbp->setup[4] & 0x80) {
switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0F)) { switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0F)) {
case EP_STATUS_STALLED: case EP_STATUS_STALLED:
usbSetupTransfer(usbp, (uint8_t *)halted_status, 2); usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
return TRUE; return TRUE;
case EP_STATUS_ACTIVE: case EP_STATUS_ACTIVE:
usbSetupTransfer(usbp, (uint8_t *)active_status, 2); usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
return TRUE; return TRUE;
default: default:
return FALSE; return FALSE;
@ -162,10 +164,10 @@ static bool_t default_handler(USBDriver *usbp) {
else { else {
switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0F)) { switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0F)) {
case EP_STATUS_STALLED: case EP_STATUS_STALLED:
usbSetupTransfer(usbp, (uint8_t *)halted_status, 2); usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
return TRUE; return TRUE;
case EP_STATUS_ACTIVE: case EP_STATUS_ACTIVE:
usbSetupTransfer(usbp, (uint8_t *)active_status, 2); usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
return TRUE; return TRUE;
default: default:
return FALSE; return FALSE;
@ -182,7 +184,7 @@ static bool_t default_handler(USBDriver *usbp) {
else else
usb_lld_clear_out(usbp, usbp->setup[4] & 0x0F); usb_lld_clear_out(usbp, usbp->setup[4] & 0x0F);
} }
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SET_FEATURE << 8): case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SET_FEATURE << 8):
/* Only ENDPOINT_HALT is handled as feature.*/ /* Only ENDPOINT_HALT is handled as feature.*/
@ -195,7 +197,7 @@ static bool_t default_handler(USBDriver *usbp) {
else else
usb_lld_stall_out(usbp, usbp->setup[4] & 0x0F); usb_lld_stall_out(usbp, usbp->setup[4] & 0x0F);
} }
usbSetupTransfer(usbp, NULL, 0); usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE; return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_DESCRIPTOR << 8): case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_DESCRIPTOR << 8):
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_CLEAR_FEATURE << 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"); "usbStart(), #1", "invalid state");
usbp->config = config; usbp->config = config;
for (i = 0; i <= USB_MAX_ENDPOINTS; i++) for (i = 0; i <= USB_MAX_ENDPOINTS; i++)
usbp->ep[i] = NULL; usbp->epc[i] = NULL;
usb_lld_start(usbp); usb_lld_start(usbp);
usbp->state = USB_READY; usbp->state = USB_READY;
chSysUnlock(); chSysUnlock();
@ -293,23 +295,24 @@ void usbStop(USBDriver *usbp) {
* *
* @param[in] usbp pointer to the @p USBDriver object * @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number * @param[in] ep endpoint number
* @param[out] epp pointer to an endpoint state descriptor structure
* @param[in] epcp the endpoint configuration * @param[in] epcp the endpoint configuration
* *
* @iclass * @iclass
*/ */
void usbInitEndpointI(USBDriver *usbp, usbep_t ep, USBEndpointState *epp, void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp) { const USBEndpointConfig *epcp) {
chDbgAssert(usbp->state == USB_ACTIVE, chDbgAssert(usbp->state == USB_ACTIVE,
"usbEnableEndpointI(), #1", "invalid state"); "usbEnableEndpointI(), #1", "invalid state");
chDbgAssert(usbp->ep[ep] != NULL, chDbgAssert(usbp->epc[ep] != NULL,
"usbEnableEndpointI(), #2", "already initialized"); "usbEnableEndpointI(), #2", "already initialized");
/* Logically enabling the endpoint in the USBDriver structure.*/ /* Logically enabling the endpoint in the USBDriver structure.*/
memset(epp, 0, sizeof(USBEndpointState)); if (!(epcp->ep_mode & USB_EP_MODE_PACKET)) {
epp->config = epcp; memset(epcp->in_state, 0, sizeof(USBInEndpointState));
usbp->ep[ep] = epp; memset(epcp->out_state, 0, sizeof(USBOutEndpointState));
}
usbp->epc[ep] = epcp;
/* Low level endpoint activation.*/ /* Low level endpoint activation.*/
usb_lld_init_endpoint(usbp, ep); usb_lld_init_endpoint(usbp, ep);
@ -333,7 +336,7 @@ void usbDisableEndpointsI(USBDriver *usbp) {
"usbDisableEndpointsI(), #1", "invalid state"); "usbDisableEndpointsI(), #1", "invalid state");
for (i = 1; i <= USB_MAX_ENDPOINTS; i++) for (i = 1; i <= USB_MAX_ENDPOINTS; i++)
usbp->ep[i] = NULL; usbp->epc[i] = NULL;
/* Low level endpoints deactivation.*/ /* Low level endpoints deactivation.*/
usb_lld_disable_endpoints(usbp); usb_lld_disable_endpoints(usbp);
@ -493,6 +496,8 @@ bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep) {
/** /**
* @brief USB reset routine. * @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 * @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.*/ /* Invalidates all endpoints into the USBDriver structure.*/
for (i = 0; i <= USB_MAX_ENDPOINTS; i++) for (i = 0; i <= USB_MAX_ENDPOINTS; i++)
usbp->ep[i] = NULL; usbp->epc[i] = NULL;
/* EP0 state machine initialization.*/ /* EP0 state machine initialization.*/
usbp->ep0state = USB_EP0_WAITING_SETUP; 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 multiple of the maximum packet size then a zero size packet must be
transmitted.*/ transmitted.*/
if ((usbp->ep0n < max) && 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); usb_lld_start_in(usbp, 0, NULL, 0);
return; return;
} }
/* Transmit phase over, receiving the zero sized status packet.*/
usbp->ep0state = USB_EP0_WAITING_STS; usbp->ep0state = USB_EP0_WAITING_STS;
usb_lld_start_out(usbp, 0, NULL, 0); usb_lld_start_out(usbp, 0, NULL, 0);
return; return;
case USB_EP0_SENDING_STS: case USB_EP0_SENDING_STS:
#if USB_SET_ADDRESS_MODE == USB_LATE_SET_ADDRESS /* Status packet sent, invoking the callback if defined.*/
if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) && if (usbp->ep0endcb)
(usbp->setup[1] == USB_REQ_SET_ADDRESS)) usbp->ep0endcb(usbp);
set_address(usbp);
#endif
usbp->ep0state = USB_EP0_WAITING_SETUP; usbp->ep0state = USB_EP0_WAITING_SETUP;
return; return;
default: 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_in(usbp, 0);
usb_lld_stall_out(usbp, 0); usb_lld_stall_out(usbp, 0);
if (usbp->config->event_cb) if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_STALLED); 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 * @notapi
*/ */
void _usb_ep0out(USBDriver *usbp, usbep_t ep) { void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
size_t n, max; size_t max;
(void)ep; (void)ep;
switch (usbp->ep0state) { switch (usbp->ep0state) {
case USB_EP0_WAITING_SETUP: case USB_EP0_WAITING_SETUP:
/* SETUP packet handling. /* SETUP packet handling. The setup packet is expected to be already
First verify if the application has an handler installed for this 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.*/ request.*/
if (!(usbp->config->requests_hook_cb) || if (!(usbp->config->requests_hook_cb) ||
!(usbp->config->requests_hook_cb(usbp))) { !(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 /* Transfer preparation. The request handler must have populated
correctly the fields ep0next, ep0n and ep0endcb using correctly the fields ep0next, ep0n and ep0endcb using the macro
the macro usbSetupTransfer().*/ usbSetupTransfer().*/
max = usb_lld_fetch_word(&usbp->setup[6]); max = usb_lld_fetch_word(&usbp->setup[6]);
/* The transfer size cannot exceed the specified amount.*/ /* The transfer size cannot exceed the specified amount.*/
if (usbp->ep0n > max) 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) { if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
/* IN phase.*/ /* IN phase.*/
if (usbp->ep0n > 0) { if (usbp->ep0n > 0) {
/* Starts transmission.*/ /* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX; usbp->ep0state = USB_EP0_TX;
usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n); usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n);
} }
else { else {
/* Receiving the zero sized status packet.*/ /* No transmission phase, directly receiving the zero sized status
packet.*/
usbp->ep0state = USB_EP0_WAITING_STS; usbp->ep0state = USB_EP0_WAITING_STS;
usb_lld_start_out(usbp, 0, NULL, 0); usb_lld_start_out(usbp, 0, NULL, 0);
} }
@ -615,37 +626,43 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
else { else {
/* OUT phase.*/ /* OUT phase.*/
if (usbp->ep0n > 0) { if (usbp->ep0n > 0) {
/* Starts reception.*/ /* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX; usbp->ep0state = USB_EP0_RX;
usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n); usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n);
} }
else { else {
/* Sending zero sized status packet.*/ /* No receive phase, directly sending the zero sized status
packet.*/
usbp->ep0state = USB_EP0_SENDING_STS; usbp->ep0state = USB_EP0_SENDING_STS;
usb_lld_start_in(usbp, 0, NULL, 0); usb_lld_start_in(usbp, 0, NULL, 0);
} }
} }
return; return;
case USB_EP0_RX: case USB_EP0_RX:
/* Receive phase over, sending the zero sized status packet.*/
usbp->ep0state = USB_EP0_SENDING_STS; usbp->ep0state = USB_EP0_SENDING_STS;
usb_lld_start_in(usbp, 0, NULL, 0); usb_lld_start_in(usbp, 0, NULL, 0);
return; return;
case USB_EP0_WAITING_STS: case USB_EP0_WAITING_STS:
/* STATUS received packet handling, it must be zero sized.*/ /* Status packet received, it must be zero sized, invoking the callback
n = usbp->ep[0]->rxsize; if defined.*/
if (n != 0) if (usbGetReceiveTransactionSizeI(usbp, 0) != 0)
break; break;
if (usbp->ep0endcb)
usbp->ep0endcb(usbp);
usbp->ep0state = USB_EP0_WAITING_SETUP; usbp->ep0state = USB_EP0_WAITING_SETUP;
return; return;
default: 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_in(usbp, 0);
usb_lld_stall_out(usbp, 0); usb_lld_stall_out(usbp, 0);
if (usbp->config->event_cb) if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_STALLED); usbp->config->event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_WAITING_SETUP; usbp->ep0state = USB_EP0_ERROR;
} }
#endif /* HAL_USE_USB */ #endif /* HAL_USE_USB */

View File

@ -232,21 +232,6 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp,
return NULL; return NULL;
} }
/**
* @brief EP1 state.
*/
USBEndpointState ep1state;
/**
* @brief EP2 state.
*/
USBEndpointState ep2state;
/**
* @brief EP3 state.
*/
USBEndpointState ep3state;
/** /**
* @brief EP1 initialization structure (IN only). * @brief EP1 initialization structure (IN only).
*/ */
@ -255,7 +240,9 @@ static const USBEndpointConfig ep1config = {
sduDataTransmitted, sduDataTransmitted,
NULL, NULL,
0x0040, 0x0040,
0x0000 0x0000,
NULL,
NULL
}; };
/** /**
@ -266,7 +253,9 @@ static const USBEndpointConfig ep2config = {
sduInterruptTransmitted, sduInterruptTransmitted,
NULL, NULL,
0x0010, 0x0010,
0x0000 0x0000,
NULL,
NULL
}; };
/** /**
@ -277,7 +266,9 @@ static const USBEndpointConfig ep3config = {
NULL, NULL,
sduDataReceived, sduDataReceived,
0x0000, 0x0000,
0x0040 0x0040,
NULL,
NULL
}; };
/* /*
@ -293,9 +284,9 @@ static void usb_event(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_CONFIGURED: case USB_EVENT_CONFIGURED:
/* Enables the endpoints specified into the configuration.*/ /* Enables the endpoints specified into the configuration.*/
chSysLock(); chSysLock();
usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1state, &ep1config); usbInitEndpointI(usbp, DATA_REQUEST_EP, &ep1config);
usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2state, &ep2config); usbInitEndpointI(usbp, INTERRUPT_REQUEST_EP, &ep2config);
usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3state, &ep3config); usbInitEndpointI(usbp, DATA_AVAILABLE_EP, &ep3config);
chSysUnlock(); chSysUnlock();
return; return;
case USB_EVENT_SUSPEND: case USB_EVENT_SUSPEND: