mirror of
https://github.com/hathach/tinyusb.git
synced 2025-04-09 18:44:31 +00:00
add various check for disconncted device, also fix #1511 un-roll recursive hub removal with usbh queue
This commit is contained in:
parent
1c4f22a54c
commit
2c48050993
124
src/host/usbh.c
124
src/host/usbh.c
@ -81,10 +81,12 @@ typedef struct {
|
|||||||
|
|
||||||
// Device State
|
// Device State
|
||||||
struct TU_ATTR_PACKED {
|
struct TU_ATTR_PACKED {
|
||||||
volatile uint8_t connected : 1;
|
volatile uint8_t connected : 1; // After 1st transfer
|
||||||
volatile uint8_t addressed : 1;
|
volatile uint8_t addressed : 1; // After SET_ADDR
|
||||||
volatile uint8_t configured : 1;
|
volatile uint8_t configured : 1; // After SET_CONFIG and all drivers are configured
|
||||||
volatile uint8_t suspended : 1;
|
volatile uint8_t suspended : 1; // Bus suspended
|
||||||
|
|
||||||
|
// volatile uint8_t removing : 1; // Physically disconnected, waiting to be processed by usbh
|
||||||
};
|
};
|
||||||
|
|
||||||
// Device Descriptor
|
// Device Descriptor
|
||||||
@ -248,7 +250,7 @@ static inline usbh_device_t* get_device(uint8_t dev_addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool enum_new_device(hcd_event_t* event);
|
static bool enum_new_device(hcd_event_t* event);
|
||||||
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
||||||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
||||||
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||||
|
|
||||||
@ -420,7 +422,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
|||||||
|
|
||||||
case HCD_EVENT_DEVICE_REMOVE:
|
case HCD_EVENT_DEVICE_REMOVE:
|
||||||
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||||
process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
process_removing_device(event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||||
|
|
||||||
#if CFG_TUH_HUB
|
#if CFG_TUH_HUB
|
||||||
// TODO remove
|
// TODO remove
|
||||||
@ -450,7 +452,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
usbh_device_t* dev = get_device(event.dev_addr);
|
usbh_device_t* dev = get_device(event.dev_addr);
|
||||||
TU_ASSERT(dev, );
|
TU_VERIFY(dev && dev->connected, );
|
||||||
|
|
||||||
dev->ep_status[epnum][ep_dir].busy = 0;
|
dev->ep_status[epnum][ep_dir].busy = 0;
|
||||||
dev->ep_status[epnum][ep_dir].claimed = 0;
|
dev->ep_status[epnum][ep_dir].claimed = 0;
|
||||||
@ -739,29 +741,33 @@ void usbh_int_set(bool enabled)
|
|||||||
// TODO has some duplication code with device, refactor later
|
// TODO has some duplication code with device, refactor later
|
||||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||||
{
|
{
|
||||||
|
// Note: addr0 only use tuh_control_xfer
|
||||||
usbh_device_t* dev = get_device(dev_addr);
|
usbh_device_t* dev = get_device(dev_addr);
|
||||||
|
TU_ASSERT(dev && dev->connected);
|
||||||
// addr0 only use tuh_control_xfer
|
|
||||||
TU_ASSERT(dev);
|
|
||||||
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
return tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex);
|
TU_VERIFY(tu_edpt_claim(&dev->ep_status[epnum][dir], _usbh_mutex));
|
||||||
|
TU_LOG_USBH("[%u] Claimed EP 0x%02x\r\n", dev_addr, ep_addr);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO has some duplication code with device, refactor later
|
// TODO has some duplication code with device, refactor later
|
||||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||||
{
|
{
|
||||||
|
// Note: addr0 only use tuh_control_xfer
|
||||||
usbh_device_t* dev = get_device(dev_addr);
|
usbh_device_t* dev = get_device(dev_addr);
|
||||||
|
TU_VERIFY(dev && dev->connected);
|
||||||
// addr0 only use tuh_control_xfer
|
|
||||||
TU_ASSERT(dev);
|
|
||||||
|
|
||||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||||
|
|
||||||
return tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
|
TU_VERIFY(tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex));
|
||||||
|
TU_LOG_USBH("[%u] Released EP 0x%02x\r\n", dev_addr, ep_addr);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO has some duplication code with device, refactor later
|
// TODO has some duplication code with device, refactor later
|
||||||
@ -870,7 +876,7 @@ TU_ATTR_FAST_FUNC void hcd_event_handler(hcd_event_t const* event, bool in_isr)
|
|||||||
switch (event->event_id)
|
switch (event->event_id)
|
||||||
{
|
{
|
||||||
// case HCD_EVENT_DEVICE_REMOVE:
|
// case HCD_EVENT_DEVICE_REMOVE:
|
||||||
//
|
// // mark device as removing to prevent further xfer before the event is processed in usbh task
|
||||||
// break;
|
// break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1116,7 +1122,7 @@ uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_i
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
//
|
// Detaching
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
TU_ATTR_ALWAYS_INLINE
|
TU_ATTR_ALWAYS_INLINE
|
||||||
@ -1125,45 +1131,79 @@ static inline bool is_hub_addr(uint8_t daddr)
|
|||||||
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
|
return (CFG_TUH_HUB > 0) && (daddr > CFG_TUH_DEVICE_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//static void mark_removing_device_isr(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port) {
|
||||||
|
// for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
|
||||||
|
// usbh_device_t *dev = &_usbh_devices[dev_id];
|
||||||
|
// uint8_t const daddr = dev_id + 1;
|
||||||
|
//
|
||||||
|
// // hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
|
||||||
|
// if (dev->rhport == rhport && dev->connected &&
|
||||||
|
// (hub_addr == 0 || dev->hub_addr == hub_addr) &&
|
||||||
|
// (hub_port == 0 || dev->hub_port == hub_port)) {
|
||||||
|
// if (is_hub_addr(daddr)) {
|
||||||
|
// // If the device itself is a usb hub, mark all downstream devices.
|
||||||
|
// // FIXME recursive calls
|
||||||
|
// mark_removing_device_isr(rhport, daddr, 0);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// dev->removing = 1;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
// a device unplugged from rhport:hub_addr:hub_port
|
// a device unplugged from rhport:hub_addr:hub_port
|
||||||
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
|
static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
|
||||||
{
|
{
|
||||||
//------------- find the all devices (star-network) under port that is unplugged -------------//
|
//------------- find the all devices (star-network) under port that is unplugged -------------//
|
||||||
// TODO mark as disconnected in ISR, also handle dev0
|
// TODO mark as disconnected in ISR, also handle dev0
|
||||||
for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
|
|
||||||
{
|
|
||||||
usbh_device_t* dev = &_usbh_devices[dev_id];
|
|
||||||
uint8_t const dev_addr = dev_id+1;
|
|
||||||
|
|
||||||
if (dev->rhport == rhport &&
|
#if 0
|
||||||
(hub_addr == 0 || dev->hub_addr == hub_addr) && // hub_addr = 0 means roothub
|
// index as hub addr, value is hub port (0xFF for invalid)
|
||||||
(hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub
|
uint8_t removing_hubs[CFG_TUH_HUB];
|
||||||
dev->connected)
|
memset(removing_hubs, TUSB_INDEX_INVALID_8, sizeof(removing_hubs));
|
||||||
{
|
|
||||||
TU_LOG_USBH("Device unplugged address = %u\r\n", dev_addr);
|
|
||||||
|
|
||||||
if (is_hub_addr(dev_addr))
|
removing_hubs[hub_addr-CFG_TUH_DEVICE_MAX] = hub_port;
|
||||||
{
|
|
||||||
TU_LOG(USBH_DEBUG, " is a HUB device\r\n", dev_addr);
|
// consecutive non-removing hub
|
||||||
// If the device itself is a usb hub, unplug downstream devices.
|
uint8_t nop_count = 0;
|
||||||
// FIXME un-roll recursive calls to prevent potential stack overflow
|
#endif
|
||||||
process_device_unplugged(rhport, dev_addr, 0);
|
|
||||||
}else
|
for (uint8_t dev_id = 0; dev_id < TOTAL_DEVICES; dev_id++) {
|
||||||
{
|
usbh_device_t *dev = &_usbh_devices[dev_id];
|
||||||
|
uint8_t const daddr = dev_id + 1;
|
||||||
|
|
||||||
|
// hub_addr = 0 means roothub, hub_port = 0 means all devices of downstream hub
|
||||||
|
if (dev->rhport == rhport && dev->connected &&
|
||||||
|
(hub_addr == 0 || dev->hub_addr == hub_addr) &&
|
||||||
|
(hub_port == 0 || dev->hub_port == hub_port)) {
|
||||||
|
TU_LOG_USBH("Device unplugged address = %u\r\n", daddr);
|
||||||
|
|
||||||
|
if (is_hub_addr(daddr)) {
|
||||||
|
TU_LOG(USBH_DEBUG, " is a HUB device\r\n", daddr);
|
||||||
|
|
||||||
|
// Submit removed event If the device itself is a hub (un-rolled recursive)
|
||||||
|
// TODO a better to unroll recursrive is using array of removing_hubs and mark it here
|
||||||
|
hcd_event_t event;
|
||||||
|
event.rhport = rhport;
|
||||||
|
event.event_id = HCD_EVENT_DEVICE_REMOVE;
|
||||||
|
event.connection.hub_addr = daddr;
|
||||||
|
event.connection.hub_port = 0;
|
||||||
|
|
||||||
|
hcd_event_handler(&event, false);
|
||||||
|
} else {
|
||||||
// Invoke callback before closing driver (maybe call it later ?)
|
// Invoke callback before closing driver (maybe call it later ?)
|
||||||
if (tuh_umount_cb) tuh_umount_cb(dev_addr);
|
if (tuh_umount_cb) tuh_umount_cb(daddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close class driver
|
// Close class driver
|
||||||
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) {
|
||||||
{
|
usbh_class_drivers[drv_id].close(daddr);
|
||||||
usbh_class_drivers[drv_id].close(dev_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hcd_device_close(rhport, dev_addr);
|
hcd_device_close(rhport, daddr);
|
||||||
clear_device(dev);
|
clear_device(dev);
|
||||||
// abort on-going control xfer if any
|
// abort on-going control xfer if any
|
||||||
if (_ctrl_xfer.daddr == dev_addr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
|
if (_ctrl_xfer.daddr == daddr) _set_control_xfer_stage(CONTROL_STAGE_IDLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user