USB improvements.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2815 35acf78f-673a-0410-8e92-d51de3d6d3f4
master
gdisirio 2011-03-10 18:54:58 +00:00
parent 310fd0745e
commit 3d50b5c9e0
8 changed files with 250 additions and 100 deletions

View File

@ -395,6 +395,86 @@ typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
(usbp)->ep0endcb = (endcb); \
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @special
*/
#define usbReadSetup(usbp, ep, buf) usb_lld_read_setup(usbp, ep, buf)
/**
* @brief Common ISR code, usb event callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_event_cb(usbp, evt) { \
if (((usbp)->config->event_cb) != NULL) \
(usbp)->config->event_cb(usbp, evt); \
}
/**
* @brief Common ISR code, SOF callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_sof_cb(usbp) { \
if (((usbp)->config->sof_cb) != NULL) \
(usbp)->config->sof_cb(usbp); \
}
/**
* @brief Common ISR code, setup packet callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_setup_cb(usbp, ep) { \
(usbp)->epc[ep]->setup_cb(usbp, ep); \
}
/**
* @brief Common ISR code, IN endpoint callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_in_cb(usbp, ep) { \
(usbp)->transmitting &= ~(1 << (ep)); \
(usbp)->epc[ep]->in_cb(usbp, ep); \
}
/**
* @brief Common ISR code, OUT endpoint event.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_out_cb(usbp, ep) { \
(usbp)->receiving &= ~(1 << (ep)); \
(usbp)->epc[ep]->out_cb(usbp, ep); \
}
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@ -409,6 +489,7 @@ extern "C" {
void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp);
void usbDisableEndpointsI(USBDriver *usbp);
void usbReadSetupI(USBDriver *usbp, usbep_t ep, uint8_t *buf);
size_t usbReadPacketI(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n);
size_t usbWritePacketI(USBDriver *usbp, usbep_t ep,
@ -420,6 +501,7 @@ extern "C" {
bool_t usbStallReceiveI(USBDriver *usbp, usbep_t ep);
bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep);
void _usb_reset(USBDriver *usbp);
void _usb_ep0setup(USBDriver *usbp, usbep_t ep);
void _usb_ep0in(USBDriver *usbp, usbep_t ep);
void _usb_ep0out(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus

View File

@ -68,6 +68,7 @@ static union {
*/
static const USBEndpointConfig ep0config = {
USB_EP_MODE_TYPE_CTRL | USB_EP_MODE_TRANSACTION,
_usb_ep0setup,
_usb_ep0in,
_usb_ep0out,
0x40,
@ -193,16 +194,14 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
/* USB bus reset condition handling.*/
if (istr & ISTR_RESET) {
_usb_reset(usbp);
if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_RESET);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET);
STM32_USB->ISTR = ~ISTR_RESET;
}
/* USB bus SUSPEND condition handling.*/
if (istr & ISTR_SUSP) {
STM32_USB->CNTR |= CNTR_FSUSP;
if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_SUSPEND);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND);
#if STM32_USB_LOW_POWER_ON_SUSPEND
STM32_USB->CNTR |= CNTR_LP_MODE;
#endif
@ -214,8 +213,7 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
uint32_t fnr = STM32_USB->FNR;
if (!(fnr & FNR_RXDP)) {
STM32_USB->CNTR &= ~CNTR_FSUSP;
if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_WAKEUP);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP);
}
#if STM32_USB_LOW_POWER_ON_SUSPEND
else {
@ -229,8 +227,7 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
/* SOF handling.*/
if (istr & ISTR_SOF) {
if (usbp->config->sof_cb)
usbp->config->sof_cb(usbp);
_usb_isr_invoke_sof_cb(usbp);
STM32_USB->ISTR = ~ISTR_SOF;
}
@ -245,8 +242,7 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
EPR_CLEAR_CTR_TX(ep);
if (epcp->ep_mode & USB_EP_MODE_PACKET) {
/* Packet mode, just invokes the callback.*/
(usbp)->transmitting &= ~(1 << ep);
epcp->in_cb(usbp, ep);
_usb_isr_invoke_in_cb(usbp, ep);
}
else {
/* Transaction mode.*/
@ -264,43 +260,36 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
}
else {
/* Transfer completed, invokes the callback.*/
(usbp)->transmitting &= ~(1 << ep);
epcp->in_cb(usbp, ep);
_usb_isr_invoke_in_cb(usbp, ep);
}
}
}
if (epr & EPR_CTR_RX) {
EPR_CLEAR_CTR_RX(ep);
/* OUT endpoint, receive.*/
if (epcp->ep_mode & USB_EP_MODE_PACKET) {
if (epr & EPR_SETUP) {
/* Setup packets handling, setup packets are handled using a
specific callback.*/
_usb_isr_invoke_setup_cb(usbp, ep);
}
else if (epcp->ep_mode & USB_EP_MODE_PACKET) {
/* Packet mode, just invokes the callback.*/
(usbp)->receiving &= ~(1 << ep);
epcp->out_cb(usbp, ep);
_usb_isr_invoke_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.*/
usbp->ep0state = USB_EP0_WAITING_SETUP;
read_packet(0, usbp->setup, 8);
epcp->out_cb(usbp, ep);
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 {
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 &= ~(1 << ep);
epcp->out_cb(usbp, ep);
}
/* Transfer completed, invokes the callback.*/
_usb_isr_invoke_out_cb(usbp, ep);
}
}
}
@ -452,12 +441,12 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
}
/* IN endpoint settings, always in NAK mode initially.*/
if (epcp->in_cb)
if (epcp->in_cb != NULL)
epr |= EPR_STAT_TX_NAK;
/* OUT endpoint settings. If the endpoint is in packet mode then it must
start ready to accept data else it must start in NAK mode.*/
if (epcp->out_cb) {
if (epcp->out_cb != NULL) {
if (epcp->ep_mode & USB_EP_MODE_PACKET) {
usbp->receiving |= (1 << ep);
epr |= EPR_STAT_RX_VALID;
@ -553,6 +542,35 @@ usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
}
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @notapi
*/
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
uint32_t *pmap;
stm32_usb_descriptor_t *udp;
uint32_t n;
(void)usbp;
udp = USB_GET_DESCRIPTOR(ep);
pmap = USB_ADDR2PTR(udp->RXADDR);
for (n = 0; n < 4; n++) {
*(uint16_t *)buf = (uint16_t)*pmap++;
buf += 2;
}
EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
}
/**
* @brief Reads a packet from the dedicated packet buffer.
* @pre In order to use this function he endpoint must have been

View File

@ -149,6 +149,17 @@ typedef struct {
* @brief Type and mode of the endpoint.
*/
uint32_t ep_mode;
/**
* @brief Setup packet notification callback.
* @details This callback is invoked when a setup packet has been
* received.
* @post The application must immediately call @p usbReadPacket() in
* order to access the received packet.
* @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
* endpoints, it should be set to @p NULL for other endpoint
* types.
*/
usbepcallback_t setup_cb;
/**
* @brief IN endpoint notification callback.
* @details This field must be set to @p NULL if the IN endpoint is not
@ -359,6 +370,7 @@ extern "C" {
void usb_lld_disable_endpoints(USBDriver *usbp);
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n);
void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,

View File

@ -58,8 +58,7 @@ static void set_address(USBDriver *usbp) {
usbp->address = usbp->setup[2];
usb_lld_set_address(usbp);
if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_ADDRESS);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_ADDRESS);
usbp->state = USB_SELECTED;
}
@ -137,8 +136,7 @@ static bool_t default_handler(USBDriver *usbp) {
usbp->state = USB_SELECTED;
else
usbp->state = USB_ACTIVE;
if (usbp->config->event_cb)
usbp->config->event_cb(usbp, USB_EVENT_CONFIGURED);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_CONFIGURED);
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_STATUS << 8):
@ -526,6 +524,77 @@ void _usb_reset(USBDriver *usbp) {
usb_lld_reset(usbp);
}
/**
* @brief Default EP0 SETUP callback.
* @details This function is used by the low level driver as default handler
* for EP0 SETUP events.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number, always zero
*
* @notapi
*/
void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
size_t max;
usbp->ep0state = USB_EP0_WAITING_SETUP;
usbReadSetup(usbp, ep, usbp->setup);
/* First verify if the application has an handler installed for this
request.*/
if (!(usbp->config->requests_hook_cb) ||
!(usbp->config->requests_hook_cb(usbp))) {
/* Invoking the default handler, if this fails then stalls the
endpoint zero as error.*/
if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) ||
!default_handler(usbp)) {
/* 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);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
}
}
/* Transfer preparation. The request handler must have populated
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)
usbp->ep0n = max;
if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
/* IN phase.*/
if (usbp->ep0n > 0) {
/* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX;
usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n);
}
else {
/* No transmission phase, directly receiving the zero sized status
packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
usb_lld_start_out(usbp, 0, NULL, 0);
}
}
else {
/* OUT phase.*/
if (usbp->ep0n > 0) {
/* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX;
usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n);
}
else {
/* No receive phase, directly sending the zero sized status
packet.*/
usbp->ep0state = USB_EP0_SENDING_STS;
usb_lld_start_in(usbp, 0, NULL, 0);
}
}
}
/**
* @brief Default EP0 IN callback.
* @details This function is used by the low level driver as default handler
@ -558,7 +627,7 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
return;
case USB_EP0_SENDING_STS:
/* Status packet sent, invoking the callback if defined.*/
if (usbp->ep0endcb)
if (usbp->ep0endcb != NULL)
usbp->ep0endcb(usbp);
usbp->ep0state = USB_EP0_WAITING_SETUP;
return;
@ -570,8 +639,7 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
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);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
}
@ -586,62 +654,9 @@ void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
* @notapi
*/
void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
size_t max;
(void)ep;
switch (usbp->ep0state) {
case USB_EP0_WAITING_SETUP:
/* 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))) {
/* Invoking the default handler, if this fails then stalls the
endpoint zero as error.*/
if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) ||
!default_handler(usbp))
break;
}
/* Transfer preparation. The request handler must have populated
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)
usbp->ep0n = max;
if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
/* IN phase.*/
if (usbp->ep0n > 0) {
/* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX;
usb_lld_start_in(usbp, 0, usbp->ep0next, usbp->ep0n);
}
else {
/* No transmission phase, directly receiving the zero sized status
packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
usb_lld_start_out(usbp, 0, NULL, 0);
}
}
else {
/* OUT phase.*/
if (usbp->ep0n > 0) {
/* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX;
usb_lld_start_out(usbp, 0, usbp->ep0next, usbp->ep0n);
}
else {
/* 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;
@ -652,7 +667,7 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
if defined.*/
if (usbGetReceiveTransactionSizeI(usbp, 0) != 0)
break;
if (usbp->ep0endcb)
if (usbp->ep0endcb != NULL)
usbp->ep0endcb(usbp);
usbp->ep0state = USB_EP0_WAITING_SETUP;
return;
@ -664,8 +679,7 @@ void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
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);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
}

View File

@ -203,6 +203,24 @@ usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @notapi
*/
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
}
/**
* @brief Reads a packet from the dedicated packet buffer.
* @pre In order to use this function he endpoint must have been

View File

@ -282,6 +282,7 @@ extern "C" {
void usb_lld_disable_endpoints(USBDriver *usbp);
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n);
void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,

View File

@ -73,6 +73,8 @@
*** 2.3.1 ***
- FIX: Fixed invalid assertion in adcConvert() (bug 3205410)(backported
to 2.2.3).
- NEW: Improved setup packets handling in the USB driver through a specific
callback.
- OPT: Simplified Serial over USB driver configuration.
- CHANGE: Removed all the prefixes from the structure/union field names
in the HAL subsystem.

View File

@ -224,6 +224,7 @@ static const USBDescriptor *get_descriptor(USBDriver *usbp,
*/
static const USBEndpointConfig ep1config = {
USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
NULL,
sduDataTransmitted,
NULL,
0x0040,
@ -237,6 +238,7 @@ static const USBEndpointConfig ep1config = {
*/
static const USBEndpointConfig ep2config = {
USB_EP_MODE_TYPE_INTR | USB_EP_MODE_PACKET,
NULL,
sduInterruptTransmitted,
NULL,
0x0010,
@ -251,6 +253,7 @@ static const USBEndpointConfig ep2config = {
static const USBEndpointConfig ep3config = {
USB_EP_MODE_TYPE_BULK | USB_EP_MODE_PACKET,
NULL,
NULL,
sduDataReceived,
0x0000,
0x0040,