usb: disable previously enabled endpoint before re-enabling
When switching between alternate settings of an interface, it is currently possible to call set_endpoint() multiple times on an endpoint without first calling reset_endpoint(). For these situations, it is beneficial to track endpoints for which set_endpoint() has previously been called, and then reset them to properly terminate any transfers, and to return the HAL to the correct state Signed-off-by: Milind Paranjpe <mparanjpe@yahoo.com>
This commit is contained in:
parent
9831b320f2
commit
cf91f1873b
|
@ -135,6 +135,8 @@ static struct usb_dev_priv {
|
|||
uint8_t alt_setting[CONFIG_USB_MAX_ALT_SETTING];
|
||||
/** Remote wakeup feature status */
|
||||
bool remote_wakeup;
|
||||
/** Tracks whether set_endpoint() had been called on an EP */
|
||||
uint32_t ep_bm;
|
||||
} usb_dev;
|
||||
|
||||
/* Setup packet definition used to read raw data from USB line */
|
||||
|
@ -146,6 +148,8 @@ struct usb_setup_packet_packed {
|
|||
uint16_t wLength;
|
||||
} __packed;
|
||||
|
||||
static bool reset_endpoint(const struct usb_ep_descriptor *ep_desc);
|
||||
|
||||
/*
|
||||
* @brief print the contents of a setup packet
|
||||
*
|
||||
|
@ -508,6 +512,37 @@ static bool usb_get_descriptor(struct usb_setup_packet *setup,
|
|||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Get 32-bit endpoint bitmask from index
|
||||
*
|
||||
* In the returned 32-bit word, the bit positions in the lower 16 bits
|
||||
* indicate OUT endpoints, while the upper 16 bits indicate IN
|
||||
* endpoints
|
||||
*
|
||||
* @param [in] ep Endpoint of interest
|
||||
*
|
||||
* @return 32-bit bitmask
|
||||
*/
|
||||
static uint32_t get_ep_bm_from_addr(uint8_t ep)
|
||||
{
|
||||
uint32_t ep_bm = 0;
|
||||
uint8_t ep_idx;
|
||||
|
||||
ep_idx = ep & (~USB_EP_DIR_IN);
|
||||
if (ep_idx > 15) {
|
||||
LOG_ERR("Endpoint 0x%02x is invalid", ep);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ep & USB_EP_DIR_IN) {
|
||||
ep_bm = BIT(ep_idx + 16);
|
||||
} else {
|
||||
ep_bm = BIT(ep_idx);
|
||||
}
|
||||
done:
|
||||
return ep_bm;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief configure and enable endpoint
|
||||
*
|
||||
|
@ -521,6 +556,7 @@ static bool usb_get_descriptor(struct usb_setup_packet *setup,
|
|||
static bool set_endpoint(const struct usb_ep_descriptor *ep_desc)
|
||||
{
|
||||
struct usb_dc_ep_cfg_data ep_cfg;
|
||||
uint32_t ep_bm;
|
||||
int ret;
|
||||
|
||||
ep_cfg.ep_addr = ep_desc->bEndpointAddress;
|
||||
|
@ -530,6 +566,14 @@ static bool set_endpoint(const struct usb_ep_descriptor *ep_desc)
|
|||
LOG_DBG("Set endpoint 0x%x type %u MPS %u",
|
||||
ep_cfg.ep_addr, ep_cfg.ep_type, ep_cfg.ep_mps);
|
||||
|
||||
/* if endpoint is has been set() previously, reset() it first */
|
||||
ep_bm = get_ep_bm_from_addr(ep_desc->bEndpointAddress);
|
||||
if (ep_bm & usb_dev.ep_bm) {
|
||||
reset_endpoint(ep_desc);
|
||||
/* allow any canceled transfers to terminate */
|
||||
k_usleep(150);
|
||||
}
|
||||
|
||||
ret = usb_dc_ep_configure(&ep_cfg);
|
||||
if (ret == -EALREADY) {
|
||||
LOG_WRN("Endpoint 0x%02x already configured", ep_cfg.ep_addr);
|
||||
|
@ -551,6 +595,7 @@ static bool set_endpoint(const struct usb_ep_descriptor *ep_desc)
|
|||
}
|
||||
|
||||
usb_dev.configured = true;
|
||||
usb_dev.ep_bm |= ep_bm;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -568,6 +613,7 @@ static bool set_endpoint(const struct usb_ep_descriptor *ep_desc)
|
|||
static bool reset_endpoint(const struct usb_ep_descriptor *ep_desc)
|
||||
{
|
||||
struct usb_dc_ep_cfg_data ep_cfg;
|
||||
uint32_t ep_bm;
|
||||
int ret;
|
||||
|
||||
ep_cfg.ep_addr = ep_desc->bEndpointAddress;
|
||||
|
@ -588,6 +634,10 @@ static bool reset_endpoint(const struct usb_ep_descriptor *ep_desc)
|
|||
;
|
||||
}
|
||||
|
||||
/* clear endpoint mask */
|
||||
ep_bm = get_ep_bm_from_addr(ep_desc->bEndpointAddress);
|
||||
usb_dev.ep_bm &= ~ep_bm;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1225,16 @@ static int foreach_ep(int (* endpoint_callback)(const struct usb_ep_cfg_data *))
|
|||
|
||||
static int disable_interface_ep(const struct usb_ep_cfg_data *ep_data)
|
||||
{
|
||||
return usb_dc_ep_disable(ep_data->ep_addr);
|
||||
uint32_t ep_bm;
|
||||
int ret;
|
||||
|
||||
ret = usb_dc_ep_disable(ep_data->ep_addr);
|
||||
|
||||
/* clear endpoint mask */
|
||||
ep_bm = get_ep_bm_from_addr(ep_data->ep_addr);
|
||||
usb_dev.ep_bm &= ~ep_bm;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void forward_status_cb(enum usb_dc_status_code status, const uint8_t *param)
|
||||
|
|
Loading…
Reference in a new issue