aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorgdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-10 18:54:58 +0000
committergdisirio <gdisirio@35acf78f-673a-0410-8e92-d51de3d6d3f4>2011-03-10 18:54:58 +0000
commit3d50b5c9e0eee6ca4eb2e9c1114fcd8ff109e984 (patch)
tree0090c63c20385e38b366710798e72769f21775f6 /os
parent310fd0745ef78c90279dcb0004971f26c01bae79 (diff)
downloadChibiOS-3d50b5c9e0eee6ca4eb2e9c1114fcd8ff109e984.tar.gz
ChibiOS-3d50b5c9e0eee6ca4eb2e9c1114fcd8ff109e984.tar.bz2
ChibiOS-3d50b5c9e0eee6ca4eb2e9c1114fcd8ff109e984.zip
USB improvements.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2815 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os')
-rw-r--r--os/hal/include/usb.h82
-rw-r--r--os/hal/platforms/STM32/usb_lld.c92
-rw-r--r--os/hal/platforms/STM32/usb_lld.h12
-rw-r--r--os/hal/src/usb.c140
-rw-r--r--os/hal/templates/usb_lld.c18
-rw-r--r--os/hal/templates/usb_lld.h1
6 files changed, 245 insertions, 100 deletions
diff --git a/os/hal/include/usb.h b/os/hal/include/usb.h
index 24b492e2f..9b8d863b1 100644
--- a/os/hal/include/usb.h
+++ b/os/hal/include/usb.h
@@ -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
diff --git a/os/hal/platforms/STM32/usb_lld.c b/os/hal/platforms/STM32/usb_lld.c
index b2198a806..09a8d7975 100644
--- a/os/hal/platforms/STM32/usb_lld.c
+++ b/os/hal/platforms/STM32/usb_lld.c
@@ -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;
@@ -554,6 +543,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
* initialized in packet mode.
diff --git a/os/hal/platforms/STM32/usb_lld.h b/os/hal/platforms/STM32/usb_lld.h
index 9c4c899b3..0a351f932 100644
--- a/os/hal/platforms/STM32/usb_lld.h
+++ b/os/hal/platforms/STM32/usb_lld.h
@@ -150,6 +150,17 @@ typedef struct {
*/
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
* used.
@@ -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,
diff --git a/os/hal/src/usb.c b/os/hal/src/usb.c
index 0dbe4b39d..b82af84d8 100644
--- a/os/hal/src/usb.c
+++ b/os/hal/src/usb.c
@@ -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):
@@ -527,6 +525,77 @@ void _usb_reset(USBDriver *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
* for EP0 IN events.
@@ -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;
}
diff --git a/os/hal/templates/usb_lld.c b/os/hal/templates/usb_lld.c
index d2750d2e5..823946385 100644
--- a/os/hal/templates/usb_lld.c
+++ b/os/hal/templates/usb_lld.c
@@ -204,6 +204,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
* initialized in packet mode.
diff --git a/os/hal/templates/usb_lld.h b/os/hal/templates/usb_lld.h
index 254f6c5da..5b235eaa4 100644
--- a/os/hal/templates/usb_lld.h
+++ b/os/hal/templates/usb_lld.h
@@ -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,