Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USBUS: Add URB support #17091

Merged
merged 2 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ PSEUDOMODULES += suit_storage_%
PSEUDOMODULES += sys_bus_%
PSEUDOMODULES += tiny_strerror_as_strerror
PSEUDOMODULES += tiny_strerror_minimal
PSEUDOMODULES += usbus_urb
PSEUDOMODULES += vdd_lc_filter_%
## @defgroup pseudomodule_vfs_auto_format vfs_auto_format
## @brief Format mount points at startup unless they can be mounted
Expand Down
1 change: 1 addition & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ ifneq (,$(filter usbus_cdc_ecm,$(USEMODULE)))
USEMODULE += iolist
USEMODULE += fmt
USEMODULE += usbus
USEMODULE += usbus_urb
USEMODULE += netdev_eth
USEMODULE += luid
endif
Expand Down
136 changes: 136 additions & 0 deletions sys/include/usb/usbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,31 @@ extern "C" {
#define USBUS_HANDLER_FLAG_TR_STALL (0x0020) /**< Report transfer stall complete */
/** @} */

/**
* @name USBUS URB flags
*
* @{
*/

/**
* @brief End the URB with a zero length packet if the URB is a full number of
* USB transfers in length
*/
#define USBUS_URB_FLAG_AUTO_ZLP (0x0001)

/**
* @brief URB needs a zero length packet and it is requested
* @internal
*/
#define USBUS_URB_FLAG_NEEDS_ZLP (0x1000)

/**
* @brief URB must be cancelled after the next finished xmit
* @internal
*/
#define USBUS_URB_FLAG_CANCELLED (0x2000)
/** @} */

/**
* @brief USB handler events
*/
Expand Down Expand Up @@ -285,12 +310,26 @@ typedef struct usbus_endpoint {
usbus_descr_gen_t *descr_gen; /**< Linked list of optional additional
descriptor generators */
usbdev_ep_t *ep; /**< ptr to the matching usbdev endpoint */
#ifdef MODULE_USBUS_URB
clist_node_t urb_list; /**< clist of urbs */
#endif
uint16_t maxpacketsize; /**< Max packet size of this endpoint */
uint8_t interval; /**< Poll interval for interrupt endpoints */
bool active; /**< If the endpoint should be activated after
reset */
} usbus_endpoint_t;

/**
* @brief USBUS USB request/response block
*/
typedef struct usbus_urb {
clist_node_t list; /**< clist block in the queue */
uint32_t flags; /**< Transfer flags */
uint8_t *buf; /**< Pointer to the (aligned) buffer */
size_t len; /**< Length of the data */
size_t transferred; /**< amount transferred, only valid for OUT */
} usbus_urb_t;

/**
* @brief USBUS interface alternative setting
*
Expand Down Expand Up @@ -552,6 +591,65 @@ void usbus_init(usbus_t *usbus, usbdev_t *usbdev);
void usbus_create(char *stack, int stacksize, char priority,
const char *name, usbus_t *usbus);

/**
* @brief Initialize a new URB.
*
* Must be called before submitting an URB to an endpoint.
*
* @note When using this for OUT endpoints, the buffer size and the @p len
* argument must allow for a whole number of max length transfers.
*
* @note Requires the `usbus_urb` module.
*
* @param[in] urb URB to submit
* @param[in] buf Buffer to store or transmit the data from
* @param[in] len Length of @p buf in bytes
* @param[in] flags Flags to set for the URB such as @ref USBUS_URB_FLAG_AUTO_ZLP
*/
static inline void usbus_urb_init(usbus_urb_t *urb,
uint8_t *buf,
size_t len,
uint32_t flags)
{
urb->buf = buf;
urb->len = len;
urb->flags = flags;
urb->transferred = 0;
}

/**
* @brief Submit an URB to an endpoint.
*
* @note Requires the `usbus_urb` module.
*
* @param[in] usbus USBUS context
* @param[in] endpoint USBUS endpoint the URB is queued to
* @param[in] urb URB to submit
*/
void usbus_urb_submit(usbus_t *usbus, usbus_endpoint_t *endpoint, usbus_urb_t *urb);

/**
* @brief Cancel and already queued URB.
*
* The URB will be cancelled after the next transmission if the URB is already
* partially completed. It is up to the handler code to gracefully handle the
* partially aborted transfer on the endpoint pipe.
*
* The callback will be called if the URB was already started and cancelled
* while (partially) transferred
*
* @note Requires the `usbus_urb` module.
*
* @param[in] usbus USBUS context
* @param[in] endpoint USBUS endpoint the URB is queued to
* @param[in] urb URB to cancel
*
* @returns 0 if the URB is partially completed
* 1 if the URB was not yet started
* -1 if the URB was not found in the endpoint queue
*/
int usbus_urb_cancel(usbus_t *usbus, usbus_endpoint_t *endpoint, usbus_urb_t *urb);

/**
* @brief Enable an endpoint
*
Expand Down Expand Up @@ -614,6 +712,44 @@ static inline bool usbus_handler_isset_flag(usbus_handler_t *handler,
return handler->flags & flag;
}

/**
* @brief enable an URB flag
*
* @param[in] urb URB to enable the flag for
* @param[in] flag flag to enable
*/
static inline void usbus_urb_set_flag(usbus_urb_t *urb,
uint32_t flag)
{
urb->flags |= flag;
}

/**
* @brief disable an URB flag
*
* @param[in] urb URB to disable the flag for
* @param[in] flag flag to disable
*/
static inline void usbus_urb_remove_flag(usbus_urb_t *urb,
uint32_t flag)
{
urb->flags &= ~flag;
}

/**
* @brief check if an URB flag is set
*
* @param[in] urb URB to check for flag
* @param[in] flag flag to check
*
* @return true if the flag is set for this URB
*/
static inline bool usbus_urb_isset_flag(usbus_urb_t *urb,
uint32_t flag)
{
return urb->flags & flag;
}

#ifdef __cplusplus
}
#endif
Expand Down
13 changes: 11 additions & 2 deletions sys/include/usb/usbus/cdc/ecm.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "usb/descriptor.h"
#include "usb/usbus.h"
#include "usb/usbus/control.h"
#include "macros/math.h"
#include "net/netdev.h"
#include "mutex.h"

Expand Down Expand Up @@ -77,6 +78,11 @@ extern "C" {
*/
#define USBUS_CDCECM_EP_DATA_SIZE 64

/**
* @brief Full ethernet frame rounded up to a whole number of transfers
*/
#define USBUS_ETHERNET_FRAME_BUF MATH_ALIGN(ETHERNET_FRAME_LEN, USBUS_CDCECM_EP_DATA_SIZE)

/**
* @brief notification state, used to track which information must be send to
* the host
Expand Down Expand Up @@ -108,14 +114,13 @@ typedef struct usbus_cdcecm_device {
usbus_t *usbus; /**< Ptr to the USBUS context */
mutex_t out_lock; /**< mutex used for locking netif/USBUS send */
size_t tx_len; /**< Length of the current tx frame */
size_t len; /**< Length of the current rx frame */
usbus_cdcecm_notif_t notif; /**< Startup message notification tracker */
unsigned active_iface; /**< Current active data interface */

/**
* @brief Buffer for received frames from the host
*/
usbdev_ep_buf_t data_out[ETHERNET_FRAME_LEN];
usbdev_ep_buf_t data_out[USBUS_ETHERNET_FRAME_BUF];

/**
* @brief Host in device out data buffer
Expand All @@ -126,6 +131,10 @@ typedef struct usbus_cdcecm_device {
* @brief Host out device in control buffer
*/
usbdev_ep_buf_t control_in[USBUS_CDCECM_EP_CTRL_SIZE];
/**
* @brief Host out device in reception URB
*/
usbus_urb_t out_urb;
} usbus_cdcecm_device_t;

/**
Expand Down
32 changes: 13 additions & 19 deletions sys/usb/usbus/cdc/ecm/cdc_ecm.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ static void _fill_ethernet(usbus_cdcecm_device_t *cdcecm)

}

void _start_urb(usbus_cdcecm_device_t *cdcecm)
{
usbus_urb_init(&cdcecm->out_urb,
cdcecm->data_out,
USBUS_ETHERNET_FRAME_BUF, 0);
usbus_urb_submit(cdcecm->usbus, cdcecm->ep_out, &cdcecm->out_urb);
}

void usbus_cdcecm_init(usbus_t *usbus, usbus_cdcecm_device_t *handler)
{
assert(usbus);
Expand Down Expand Up @@ -251,9 +259,9 @@ static int _control_handler(usbus_t *usbus, usbus_handler_t *handler,
setup->value);
cdcecm->active_iface = (uint8_t)setup->value;
if (cdcecm->active_iface == 1) {
usbdev_ep_xmit(cdcecm->ep_out->ep, cdcecm->data_out,
USBUS_CDCECM_EP_DATA_SIZE);
_notify_link_up(cdcecm);
/* Start URB */
_start_urb(cdcecm);
}
break;

Expand Down Expand Up @@ -298,8 +306,8 @@ static void _handle_rx_flush_ev(event_t *ev)
{
usbus_cdcecm_device_t *cdcecm = container_of(ev, usbus_cdcecm_device_t,
rx_flush);
cdcecm->len = 0; /* Flush packet */
usbdev_ep_xmit(cdcecm->ep_out->ep, cdcecm->data_out, USBUS_CDCECM_EP_DATA_SIZE);
/* Start URB */
_start_urb(cdcecm);
}

static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler,
Expand All @@ -310,20 +318,7 @@ static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler,
usbus_cdcecm_device_t *cdcecm = (usbus_cdcecm_device_t *)handler;
if (ep == cdcecm->ep_out->ep) {
/* Retrieve incoming data */
if (cdcecm->notif == USBUS_CDCECM_NOTIF_NONE) {
_notify_link_up(cdcecm);
}
size_t len = 0;
usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t));
cdcecm->len += len;
if (len == USBUS_CDCECM_EP_DATA_SIZE) {
/* ready next chunk */
usbdev_ep_xmit(ep, cdcecm->data_out + cdcecm->len,
USBUS_CDCECM_EP_DATA_SIZE);
}
else {
netdev_trigger_event_isr(&cdcecm->netdev);
}
netdev_trigger_event_isr(&cdcecm->netdev);
}
else if (ep == cdcecm->ep_in->ep) {
_handle_in_complete(usbus, handler);
Expand All @@ -341,7 +336,6 @@ static void _handle_reset(usbus_t *usbus, usbus_handler_t *handler)
DEBUG("CDC ECM: Reset\n");
_handle_in_complete(usbus, handler);
cdcecm->notif = USBUS_CDCECM_NOTIF_NONE;
cdcecm->len = 0; /* Flush received data */
cdcecm->active_iface = 0;
mutex_unlock(&cdcecm->out_lock);
}
Expand Down
4 changes: 2 additions & 2 deletions sys/usb/usbus/cdc/ecm/cdc_ecm_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t max_len, void *info)
(void)info;
usbus_cdcecm_device_t *cdcecm = _netdev_to_cdcecm(netdev);

size_t pktlen = cdcecm->len;
size_t pktlen = cdcecm->out_urb.transferred;

if (max_len == 0 && buf == NULL) {
return pktlen;
Expand Down Expand Up @@ -198,7 +198,7 @@ static void _isr(netdev_t *dev)
{
usbus_cdcecm_device_t *cdcecm = _netdev_to_cdcecm(dev);

if (cdcecm->len) {
if (cdcecm->out_urb.transferred) {
cdcecm->netdev.event_callback(&cdcecm->netdev,
NETDEV_EVENT_RX_COMPLETE);
}
Expand Down
Loading