diff --git a/host/class/uvc/usb_host_uvc/CHANGELOG.md b/host/class/uvc/usb_host_uvc/CHANGELOG.md
index de62cddc..933cc4f6 100644
--- a/host/class/uvc/usb_host_uvc/CHANGELOG.md
+++ b/host/class/uvc/usb_host_uvc/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 2.1.0
+
+- support get frame list when device insert
+- support dual camera with hub
+
 ## 2.0.0
 
 - New version of the driver, native to Espressif's USB Host Library
diff --git a/host/class/uvc/usb_host_uvc/Kconfig b/host/class/uvc/usb_host_uvc/Kconfig
new file mode 100644
index 00000000..ff7acc87
--- /dev/null
+++ b/host/class/uvc/usb_host_uvc/Kconfig
@@ -0,0 +1,16 @@
+menu "USB HOST UVC"
+
+    config PRINTF_UVC_CONFIGURATION_DESCRIPTOR
+        bool "Print UVC Configuration Descriptor"
+        default n
+        help
+            Print UVC Configuration Descriptor to console.
+
+    config UVC_INTERVAL_ARRAY_SIZE
+        int "Size of the interval array in uvc_host_frame_info_t"
+        default 3
+        help
+            This option sets the size of the interval array in the `uvc_host_frame_info_t` structure.
+            Increase this value if you need to support more discrete frame intervals.
+
+endmenu
diff --git a/host/class/uvc/usb_host_uvc/idf_component.yml b/host/class/uvc/usb_host_uvc/idf_component.yml
index a282d00b..3fc775d9 100644
--- a/host/class/uvc/usb_host_uvc/idf_component.yml
+++ b/host/class/uvc/usb_host_uvc/idf_component.yml
@@ -1,5 +1,5 @@
 ## IDF Component Manager Manifest File
-version: "2.0.0"
+version: "2.1.0"
 description: USB Host UVC driver
 url: https://github.com/espressif/esp-usb/tree/master/host/class/uvc/usb_host_uvc
 dependencies:
diff --git a/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h b/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h
index 195b7ffe..66ddc734 100644
--- a/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h
+++ b/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h
@@ -14,6 +14,7 @@
 // Use this macros for opening a UVC stream with any VID or PID
 #define UVC_HOST_ANY_VID (0)
 #define UVC_HOST_ANY_PID (0)
+#define UVC_HOST_ANY_DEV_ADDR (0)
 
 #ifdef __cplusplus
 extern "C" {
@@ -21,6 +22,60 @@ extern "C" {
 
 typedef struct uvc_host_stream_s *uvc_host_stream_hdl_t;
 
+enum uvc_host_driver_event {
+    UVC_HOST_DRIVER_EVENT_DEVICE_CONNECTED = 0x0,
+};
+
+/**
+ * @brief Formats supported by this driver
+ */
+enum uvc_host_stream_format {
+    UVC_VS_FORMAT_UNDEFINED = 0, // Invalid format. Do not request this format from the camera.
+    UVC_VS_FORMAT_MJPEG,
+    UVC_VS_FORMAT_YUY2,
+    UVC_VS_FORMAT_H264,
+    UVC_VS_FORMAT_H265,
+};
+
+/**
+ * @brief Frame information
+ *
+ */
+typedef struct {
+    enum uvc_host_stream_format format;       /**< Format of this frame buffer */
+    unsigned h_res;                           /**< Horizontal resolution */
+    unsigned v_res;                           /**< Vertical resolution */
+    uint32_t default_interval;                /**< Default frame interval */
+    uint8_t  interval_type;                   /**< 0: Continuous frame interval, 1..255: The number of discrete frame intervals supported (n) */
+    union {
+        struct {
+            uint32_t interval_min;            /**< Minimum frame interval */
+            uint32_t interval_max;            /**< Maximum frame interval */
+            uint32_t interval_step;           /**< Frame interval step */
+        };
+        uint32_t interval[CONFIG_UVC_INTERVAL_ARRAY_SIZE]; /**< We must put a fixed size here because of the union type. This is flexible size array though */
+    };
+} uvc_host_frame_info_t;
+
+typedef struct {
+    enum uvc_host_driver_event type;      /**< Event type */
+    union {
+        struct {
+            uint8_t dev_addr;             /**< Device address */
+            uint8_t uvc_stream_index;     /**< Index of UVC function for this uvc stream. */
+            size_t frame_info_num;        /**< Number of frame information list */
+        } device_connected;               /**< UVC_HOST_DEVICE_CONNECTED event */
+    };
+} uvc_host_driver_event_data_t;
+
+/**
+ * @brief USB Host UVC driver event callback function
+ *
+ * @param[out] event    Event structure
+ * @param[out] user_ctx User's argument passed to open function
+ */
+typedef void (*uvc_host_driver_event_callback_t)(const uvc_host_driver_event_data_t *event, void *user_ctx);
+
 /**
  * @brief Configuration structure of USB Host UVC driver
  */
@@ -30,6 +85,8 @@ typedef struct {
     int xCoreID;                   /**< Core affinity of the driver's task */
     bool create_background_task;   /**< When set to true, background task handling usb events is created.
                                         Otherwise user has to periodically call uvc_host_handle_events function */
+    uvc_host_driver_event_callback_t event_cb; /**< Callback function to handle events */
+    void *user_ctx;
 } uvc_host_driver_config_t;
 
 /**
@@ -64,17 +121,6 @@ typedef struct {
     };
 } uvc_host_stream_event_data_t;
 
-/**
- * @brief Formats supported by this driver
- */
-enum uvc_host_stream_format {
-    UVC_VS_FORMAT_UNDEFINED = 0, // Invalid format. Do not request this format from the camera.
-    UVC_VS_FORMAT_MJPEG,
-    UVC_VS_FORMAT_YUY2,
-    UVC_VS_FORMAT_H264,
-    UVC_VS_FORMAT_H265,
-};
-
 typedef struct {
     unsigned h_res;                     /**< Horizontal resolution */
     unsigned v_res;                     /**< Vertical resolution */
@@ -122,6 +168,7 @@ typedef struct {
     uvc_host_frame_callback_t frame_cb;   /**< Stream's frame callback function */
     void *user_ctx;                       /**< User's argument that will be passed to the callbacks */
     struct {
+        uint8_t dev_addr;                 /**< USB address of device. Set to 0 for any. */
         uint16_t vid;                     /**< Device's Vendor ID. Set to 0 for any */
         uint16_t pid;                     /**< Device's Product ID. Set to 0 for any */
         uint8_t uvc_stream_index;         /**< Index of UVC function you want to use. Set to 0 to use first available UVC function */
@@ -254,6 +301,27 @@ esp_err_t uvc_host_frame_return(uvc_host_stream_hdl_t stream_hdl, uvc_host_frame
  */
 void uvc_host_desc_print(uvc_host_stream_hdl_t stream_hdl);
 
+/**
+ * @brief Retrieve the list of frame descriptors for a specific streaming interface in a UVC device.
+ *
+ * This function extracts all frame descriptors associated with the given interface number
+ * and organizes them into a list of `uvc_host_frame_info_t` structures.
+ *
+ * If only `list_size` is passed, the length of the frame under uvc_stream_index can be obtained.
+ *
+ * @param[in] dev_addr the usb device address, can get it from uvc_host_driver_event_callback_t
+ * @param[in] uvc_stream_index the uvc stream index, can get it from uvc_host_driver_event_callback_t, Set to 0 to use first available UVC function
+ * @param[out] frame_info_list pointer to array of uvc_host_frame_info_t, must be allocated by the caller
+ * @param[inout] list_size size of the list, to avoid out-of-boundaries array access
+ *
+ * @return
+ *      - ESP_OK: Success.
+ *      - ESP_ERR_INVALID_ARG: One or more invalid arguments.
+ *      - ESP_ERR_NOT_FOUND: Input header descriptor not found.
+ *      - ESP_ERR_NO_MEM: frame_info_list num is smaller than actual frame num.
+ */
+esp_err_t uvc_host_get_frame_list(uint8_t dev_addr, uint8_t uvc_stream_index, uvc_host_frame_info_t (*frame_info_list)[], size_t *list_size);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/host/class/uvc/usb_host_uvc/private_include/uvc_descriptors_priv.h b/host/class/uvc/usb_host_uvc/private_include/uvc_descriptors_priv.h
index b110ff56..91c3af0a 100644
--- a/host/class/uvc/usb_host_uvc/private_include/uvc_descriptors_priv.h
+++ b/host/class/uvc/usb_host_uvc/private_include/uvc_descriptors_priv.h
@@ -15,6 +15,7 @@
 #define UVC_DESC_FPS_TO_DWFRAMEINTERVAL(fps) (((fps) != 0) ? 10000000.0f / (fps) : 0)
 #define UVC_DESC_DWFRAMEINTERVAL_TO_FPS(dwFrameInterval) (((dwFrameInterval) != 0) ? 10000000.0f / ((float)(dwFrameInterval)) : 0)
 
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -75,6 +76,53 @@ esp_err_t uvc_desc_get_frame_format_by_format(
     const uvc_format_desc_t **format_desc_ret,
     const uvc_frame_desc_t **frame_desc_ret);
 
+/**
+ * @brief Check if the given USB configuration descriptor belongs to a UVC (USB Video Class) device.
+ *
+ * This function iterates through the descriptors in the provided configuration descriptor to determine
+ * if there is any interface descriptor indicating the device is a UVC device.
+ *
+ * @param[in] cfg_desc Pointer to the USB configuration descriptor.
+ *
+ * @return
+ *      - true: If the configuration descriptor contains a UVC interface.
+ *      - false: Otherwise.
+ */
+bool uvc_desc_is_uvc_device(const usb_config_desc_t *cfg_desc);
+
+/**
+ * @brief Print UVC specific descriptor in human readable form
+ *
+ * This is a callback function that is called from USB Host library,
+ * when it wants to print full configuration descriptor to stdout.
+ *
+ * @param[in] _desc UVC specific descriptor
+ */
+void uvc_print_desc(const usb_standard_desc_t *_desc);
+
+/**
+ * @brief Retrieve the list of frame descriptors for a specific streaming interface in a UVC device.
+ *
+ * This function extracts all frame descriptors associated with the given interface number
+ * and organizes them into a list of `uvc_host_frame_info_t` structures.
+ *
+ * @param[in] config_desc         Pointer to the USB configuration descriptor.
+ * @param[in] uvc_index           Index of UVC function you want to use.
+ * @param[out] frame_info_list    Pointer to a list of frame info structures (allocated dynamically).
+ * @param[out] list_size          Pointer to store the number of frames in the list.
+ *
+ * @return
+ *      - ESP_OK: Success.
+ *      - ESP_ERR_INVALID_ARG: One or more invalid arguments.
+ *      - ESP_ERR_NOT_FOUND: Input header descriptor not found.
+ *      - ESP_ERR_NO_MEM: Memory allocation failure.
+ */
+esp_err_t uvc_desc_get_frame_list(
+    const usb_config_desc_t *config_desc,
+    uint8_t uvc_index,
+    uvc_host_frame_info_t (*frame_info_list)[],
+    size_t *list_size);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c b/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c
index 2f891609..0da8b531 100644
--- a/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c
+++ b/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c
@@ -7,6 +7,7 @@
 #include <inttypes.h>
 #include <string.h> // strncmp for guid format parsing
 #include <math.h>   // fabs for float comparison
+#include "esp_log.h"
 #include "usb/usb_helpers.h"
 #include "usb/uvc_host.h"
 #include "uvc_check_priv.h"
@@ -303,6 +304,32 @@ static const uvc_vc_header_desc_t *uvc_desc_get_control_interface_header(const u
     return header_desc_ret;
 }
 
+static const uvc_vs_input_header_desc_t *uvc_desc_get_streaming_interface_input_header(const usb_config_desc_t *cfg_desc, unsigned uvc_idx)
+{
+    UVC_CHECK(cfg_desc, NULL);
+
+    // Find IAD UVC descriptor with desired index
+    const uvc_vs_input_header_desc_t *header_desc_ret = NULL;
+    int offset = 0;
+    int uvc_iad_idx = 0;
+    const usb_standard_desc_t *current_desc = (const usb_standard_desc_t *)cfg_desc;
+    while ((current_desc = usb_parse_next_descriptor_of_type(current_desc, cfg_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset))) {
+        const usb_intf_desc_t *iface_desc = (const usb_intf_desc_t *)current_desc;
+        if (USB_CLASS_VIDEO == iface_desc->bInterfaceClass && UVC_SC_VIDEOSTREAMING == iface_desc->bInterfaceSubClass) {
+            if (uvc_idx == uvc_iad_idx) {
+                // // This is the IAD that we are looking for. Find its first Video Control interface header descriptor
+                header_desc_ret = (const uvc_vs_input_header_desc_t *)usb_parse_next_descriptor_of_type(current_desc, cfg_desc->wTotalLength, UVC_CS_INTERFACE, &offset);
+                UVC_CHECK(header_desc_ret->bDescriptorSubType == UVC_VC_DESC_SUBTYPE_HEADER, NULL);
+                break;
+            } else {
+                // The user requires next UVC function
+                uvc_iad_idx++;
+            }
+        }
+    }
+    return header_desc_ret;
+}
+
 esp_err_t uvc_desc_get_frame_format_by_index(
     const usb_config_desc_t *cfg_desc,
     uint8_t bInterfaceNumber,
@@ -375,3 +402,110 @@ esp_err_t uvc_desc_get_streaming_interface_num(
     }
     return ret;
 }
+
+bool uvc_desc_is_uvc_device(const usb_config_desc_t *cfg_desc)
+{
+    assert(cfg_desc);
+    int offset = 0;
+    int total_len = cfg_desc->wTotalLength;
+
+    const usb_standard_desc_t *current_desc = (const usb_standard_desc_t *)cfg_desc;
+    while ((current_desc = usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)current_desc, total_len, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset))) {
+        const usb_intf_desc_t *iface_desc = (const usb_intf_desc_t *)current_desc;
+        if (USB_CLASS_VIDEO == iface_desc->bInterfaceClass) {
+            return true;
+        }
+    }
+    return false;
+}
+
+esp_err_t uvc_desc_get_frame_list(const usb_config_desc_t *config_desc, uint8_t uvc_index, uvc_host_frame_info_t (*frame_info_list)[], size_t *list_size)
+{
+    esp_err_t ret = ESP_OK;
+    UVC_CHECK(config_desc && list_size, ESP_ERR_INVALID_ARG);
+    size_t num_frame = 0;
+    size_t frame_index = 0;
+
+    const uvc_vs_input_header_desc_t *input_header = uvc_desc_get_streaming_interface_input_header(config_desc, uvc_index);
+    UVC_CHECK(input_header, ESP_ERR_NOT_FOUND);
+
+    // Find requested Format descriptors
+    int format_offset = 0;
+    const usb_standard_desc_t *current_desc = (const usb_standard_desc_t *)input_header;
+    while ((current_desc = usb_parse_next_descriptor_of_type(current_desc, input_header->wTotalLength, UVC_CS_INTERFACE, &format_offset))) {
+        if (!uvc_desc_is_format_desc(current_desc)) {
+            continue;
+        }
+
+        const uvc_format_desc_t *this_format = (const uvc_format_desc_t *)(current_desc);
+        enum uvc_host_stream_format format_type = uvc_desc_parse_format(this_format);
+        if (UVC_VS_FORMAT_UNDEFINED == format_type) {
+            continue;
+        }
+
+        num_frame = this_format->bNumFrameDescriptors;
+
+        /*!< Just return the list size */
+        if (!frame_info_list) {
+            *list_size = num_frame;
+            return ESP_OK;
+        }
+
+        if (*list_size < num_frame) {
+            ESP_LOGE("uvc_desc", "list_size(%d) < num_frame(%d)", *list_size, num_frame);
+            return ESP_FAIL;
+        }
+
+        // We found required Format Descriptor
+        // Now we look for correct Frame Descriptors which should be directly after Format
+        while ((current_desc = usb_parse_next_descriptor_of_type(current_desc, input_header->wTotalLength, UVC_CS_INTERFACE, &format_offset))) {
+            if (!uvc_desc_is_frame_desc(current_desc)) {
+                break;
+            }
+            uvc_frame_desc_t *this_frame = (uvc_frame_desc_t *)current_desc;
+
+            if (frame_index > *list_size - 1) {
+                return ESP_ERR_NO_MEM;
+            }
+            uvc_host_frame_info_t *frame_info = &(*frame_info_list)[frame_index];
+            frame_info->format = format_type;
+            frame_info->h_res = this_frame->wWidth;
+            frame_info->v_res = this_frame->wHeight;
+            switch (format_type) {
+                case UVC_VS_FORMAT_MJPEG:
+                    frame_info->default_interval = this_frame->mjpeg_uncompressed.dwDefaultFrameInterval;
+                    frame_info->interval_type = this_frame->mjpeg_uncompressed.bFrameIntervalType;
+                    if (frame_info->interval_type == 0) {
+                        frame_info->interval_min = this_frame->mjpeg_uncompressed.dwMinFrameInterval;
+                        frame_info->interval_max = this_frame->mjpeg_uncompressed.dwMaxFrameInterval;
+                        frame_info->interval_step = this_frame->mjpeg_uncompressed.dwFrameIntervalStep;
+                    } else {
+                        for (int i = 0; i < CONFIG_UVC_INTERVAL_ARRAY_SIZE; i ++) {
+                            frame_info->interval[i] = this_frame->mjpeg_uncompressed.dwFrameInterval[i];
+                        }
+                    }
+                    break;
+                case UVC_VS_FORMAT_H265:
+                case UVC_VS_FORMAT_H264:
+                    frame_info->default_interval = this_frame->frame_based.dwDefaultFrameInterval;
+                    frame_info->interval_type = this_frame->frame_based.bFrameIntervalType;
+                    if (frame_info->interval_type == 0) {
+                        frame_info->interval_min = this_frame->frame_based.dwMinFrameInterval;
+                        frame_info->interval_max = this_frame->frame_based.dwMaxFrameInterval;
+                        frame_info->interval_step = this_frame->frame_based.dwFrameIntervalStep;
+                    } else {
+                        for (int i = 0; i < CONFIG_UVC_INTERVAL_ARRAY_SIZE; i ++) {
+                            frame_info->interval[i] = this_frame->frame_based.dwFrameInterval[i];
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            frame_index++;
+        }
+    }
+    assert(*list_size == num_frame);
+    return ret;
+}
\ No newline at end of file
diff --git a/host/class/uvc/usb_host_uvc/uvc_descriptor_printing.c b/host/class/uvc/usb_host_uvc/uvc_descriptor_printing.c
index e0d54a3d..283c9562 100644
--- a/host/class/uvc/usb_host_uvc/uvc_descriptor_printing.c
+++ b/host/class/uvc/usb_host_uvc/uvc_descriptor_printing.c
@@ -357,15 +357,7 @@ static void print_class_specific_desc(const usb_standard_desc_t *_desc)
     }
 }
 
-/**
- * @brief Print UVC specific descriptor in human readable form
- *
- * This is a callback function that is called from USB Host library,
- * when it wants to print full configuration descriptor to stdout.
- *
- * @param[in] _desc UVC specific descriptor
- */
-static void uvc_print_desc(const usb_standard_desc_t *_desc)
+void uvc_print_desc(const usb_standard_desc_t *_desc)
 {
     switch (_desc->bDescriptorType) {
     case UVC_CS_INTERFACE:
diff --git a/host/class/uvc/usb_host_uvc/uvc_host.c b/host/class/uvc/usb_host_uvc/uvc_host.c
index c9b71303..2ce9a020 100644
--- a/host/class/uvc/usb_host_uvc/uvc_host.c
+++ b/host/class/uvc/usb_host_uvc/uvc_host.c
@@ -48,16 +48,90 @@ void bulk_transfer_callback(usb_transfer_t *transfer);
 
 // UVC driver object
 typedef struct {
-    usb_host_client_handle_t usb_client_hdl; /*!< USB Host handle reused for all UVC devices in the system */
-    SemaphoreHandle_t open_close_mutex;      /*!< Protects list of opened devices from concurrent access */
-    EventGroupHandle_t driver_status;        /*!< Holds status of the driver */
-    usb_transfer_t *ctrl_transfer;           /*!< CTRL (endpoint 0) transfer */
-    SemaphoreHandle_t ctrl_mutex;            /*!< CTRL mutex */
+    usb_host_client_handle_t usb_client_hdl;    /*!< USB Host handle reused for all UVC devices in the system */
+    SemaphoreHandle_t open_close_mutex;         /*!< Protects list of opened devices from concurrent access */
+    EventGroupHandle_t driver_status;           /*!< Holds status of the driver */
+    usb_transfer_t *ctrl_transfer;              /*!< CTRL (endpoint 0) transfer */
+    SemaphoreHandle_t ctrl_mutex;               /*!< CTRL mutex */
+    uvc_host_driver_event_callback_t user_cb;   /*!< Callback function to handle events */
+    void *user_ctx;
     SLIST_HEAD(list_dev, uvc_host_stream_s) uvc_stream_list;   /*!< List of open streams */
 } uvc_host_driver_t;
 
 static uvc_host_driver_t *p_uvc_host_driver = NULL;
 
+static esp_err_t uvc_host_interface_check(uint8_t addr, const usb_config_desc_t *config_desc)
+{
+    assert(config_desc);
+    size_t total_length = config_desc->wTotalLength;
+    int iface_offset = 0;
+    bool is_uvc_interface = false;
+    uint8_t uvc_stream_index = 0;
+
+    // Get first Interface descriptor
+    // Check every uac stream interface
+    const usb_standard_desc_t *current_desc = (const usb_standard_desc_t *)config_desc;
+    while ((current_desc = usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)current_desc, total_length, USB_B_DESCRIPTOR_TYPE_INTERFACE, &iface_offset))) {
+        const usb_intf_desc_t *iface_desc = (const usb_intf_desc_t *)current_desc;
+        if (USB_CLASS_VIDEO == iface_desc->bInterfaceClass && UVC_SC_VIDEOSTREAMING == iface_desc->bInterfaceSubClass) {
+            // notify user about the connected Interfaces
+            is_uvc_interface = true;
+
+            if (p_uvc_host_driver->user_cb) {
+                size_t frame_info_num = 0;
+                if (uvc_desc_get_frame_list(config_desc, uvc_stream_index, NULL, &frame_info_num) != ESP_OK) {
+                    ESP_LOGE(TAG, "Failed to get frame list for interface %d", iface_desc->bInterfaceNumber);
+                    return ESP_FAIL;
+                }
+
+                const uvc_host_driver_event_data_t conn_event = {
+                    .type = UVC_HOST_DRIVER_EVENT_DEVICE_CONNECTED,
+                    .device_connected.dev_addr = addr,
+                    .device_connected.uvc_stream_index = uvc_stream_index,
+                    .device_connected.frame_info_num = frame_info_num
+                };
+                p_uvc_host_driver->user_cb(&conn_event, p_uvc_host_driver->user_ctx);
+            }
+            uvc_stream_index++;
+        }
+    }
+
+    return is_uvc_interface ? ESP_OK : ESP_ERR_NOT_FOUND;
+}
+
+/**
+ * @brief Handler for USB device connected event
+ *
+ * @param[in] addr   USB device physical address
+ * @return esp_err_t
+ */
+static esp_err_t uvc_host_device_connected(uint8_t addr)
+{
+    bool is_uvc_device = false;
+    usb_device_handle_t dev_hdl;
+    const usb_config_desc_t *config_desc = NULL;
+
+    if (usb_host_device_open(p_uvc_host_driver->usb_client_hdl, addr, &dev_hdl) == ESP_OK) {
+        if (usb_host_get_active_config_descriptor(dev_hdl, &config_desc) == ESP_OK) {
+            is_uvc_device = uvc_desc_is_uvc_device(config_desc);
+        }
+        ESP_RETURN_ON_ERROR(usb_host_device_close(p_uvc_host_driver->usb_client_hdl, dev_hdl), TAG, "Unable to close USB device");
+    }
+
+    // Create UAC interfaces list in RAM, connected to the particular USB dev
+    if (is_uvc_device) {
+#ifdef CONFIG_PRINTF_UVC_CONFIGURATION_DESCRIPTOR
+        usb_print_config_descriptor(config_desc, &uvc_print_desc);
+#endif
+        // Create Interfaces list for a possibility to claim Interface
+        ESP_RETURN_ON_ERROR(uvc_host_interface_check(addr, config_desc), TAG, "uvc stream interface not found");
+    } else {
+        ESP_LOGW(TAG, "USB device with addr(%d) is not UVC device", addr);
+    }
+
+    return is_uvc_device ? ESP_OK : ESP_ERR_NOT_FOUND;
+}
+
 /**
  * @brief USB Host Client event callback
  *
@@ -71,6 +145,7 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
     switch (event_msg->event) {
     case USB_HOST_CLIENT_EVENT_NEW_DEV:
         ESP_LOGD(TAG, "New device connected");
+        uvc_host_device_connected(event_msg->new_dev.address);
         break;
     case USB_HOST_CLIENT_EVENT_DEV_GONE: {
         ESP_LOGD(TAG, "Device suddenly disconnected");
@@ -247,10 +322,11 @@ static void uvc_device_remove(uvc_stream_t *uvc_stream)
  * @brief Open USB device with requested VID/PID
  *
  * This function has two regular return paths:
- * 1. USB device with matching VID/PID is already opened by this driver: allocate new UVC device on top of the already opened USB device.
- * 2. USB device with matching VID/PID is NOT opened by this driver yet: poll USB connected devices until it is found.
+ * 1. USB device with matching VID/PID/dev_addr is already opened by this driver: allocate new UVC device on top of the already opened USB device.
+ * 2. USB device with matching VID/PID/dev_addr is NOT opened by this driver yet: poll USB connected devices until it is found.
  *
  * @note This function will block for timeout_ticks, if the device is not enumerated at the moment of calling this function.
+ * @param[in]  dev_addr      Device address
  * @param[in]  vid           Vendor ID
  * @param[in]  pid           Product ID
  * @param[in]  timeout_ticks Connection timeout in FreeRTOS ticks
@@ -259,7 +335,7 @@ static void uvc_device_remove(uvc_stream_t *uvc_stream)
  *     - ESP_OK: Success - device opened
  *     - ESP_ERR_NOT_FOUND: Device not found in given timeout
  */
-static esp_err_t uvc_find_and_open_usb_device(uint16_t vid, uint16_t pid, TickType_t timeout_ticks, uvc_stream_t **dev)
+static esp_err_t uvc_find_and_open_usb_device(uint8_t dev_addr, uint16_t vid, uint16_t pid, TickType_t timeout_ticks, uvc_stream_t **dev)
 {
     assert(p_uvc_host_driver);
     assert(dev);
@@ -274,11 +350,15 @@ static esp_err_t uvc_find_and_open_usb_device(uint16_t vid, uint16_t pid, TickTy
     uvc_stream_t *uvc_stream;
     SLIST_FOREACH(uvc_stream, &p_uvc_host_driver->uvc_stream_list, list_entry) {
         const usb_device_desc_t *device_desc;
+        usb_device_info_t dev_info;
+        ESP_ERROR_CHECK(usb_host_device_info(uvc_stream->constant.dev_hdl, &dev_info));
         ESP_ERROR_CHECK(usb_host_get_device_descriptor(uvc_stream->constant.dev_hdl, &device_desc));
         if ((vid == device_desc->idVendor || vid == UVC_HOST_ANY_VID) &&
-                (pid == device_desc->idProduct || pid == UVC_HOST_ANY_PID)) {
-            // Return path 1:
+            (pid == device_desc->idProduct || pid == UVC_HOST_ANY_PID) &&
+            (dev_addr == dev_info.dev_addr || dev_addr == UVC_HOST_ANY_DEV_ADDR)) {
+            // Return path 1: t
             (*dev)->constant.dev_hdl = uvc_stream->constant.dev_hdl;
+            printf("UVC device already opened by this driver\n");
             return ESP_OK;
         }
     }
@@ -297,18 +377,28 @@ static esp_err_t uvc_find_and_open_usb_device(uint16_t vid, uint16_t pid, TickTy
         // Go through device address list and find the one we are looking for
         for (int i = 0; i < num_of_devices; i++) {
             usb_device_handle_t current_device;
+            bool is_uvc_device = false;
+            const usb_config_desc_t *config_desc = NULL;
+
             // Open USB device
             if (usb_host_device_open(p_uvc_host_driver->usb_client_hdl, dev_addr_list[i], &current_device) != ESP_OK) {
                 continue; // In case we failed to open this device, continue with next one in the list
             }
-            assert(current_device);
-            const usb_device_desc_t *device_desc;
-            ESP_ERROR_CHECK(usb_host_get_device_descriptor(current_device, &device_desc));
-            if ((vid == device_desc->idVendor || vid == UVC_HOST_ANY_VID) &&
-                    (pid == device_desc->idProduct || pid == UVC_HOST_ANY_PID)) {
-                // Return path 2:
-                (*dev)->constant.dev_hdl = current_device;
-                return ESP_OK;
+            // Skip non-UVC devices
+            if (usb_host_get_active_config_descriptor(current_device, &config_desc) == ESP_OK) {
+                is_uvc_device = uvc_desc_is_uvc_device(config_desc);
+            }
+            if (is_uvc_device) {
+                assert(current_device);
+                const usb_device_desc_t *device_desc;
+                ESP_ERROR_CHECK(usb_host_get_device_descriptor(current_device, &device_desc));
+                if ((vid == device_desc->idVendor || vid == UVC_HOST_ANY_VID) &&
+                    (pid == device_desc->idProduct || pid == UVC_HOST_ANY_PID) &&
+                    (dev_addr == dev_addr_list[i] || dev_addr == UVC_HOST_ANY_DEV_ADDR)) {
+                    // Return path 2:
+                    (*dev)->constant.dev_hdl = current_device;
+                    return ESP_OK;
+                }
             }
             usb_host_device_close(p_uvc_host_driver->usb_client_hdl, current_device);
         }
@@ -431,6 +521,8 @@ esp_err_t uvc_host_install(const uvc_host_driver_config_t *driver_config)
     uvc_obj->ctrl_transfer->bEndpointAddress = 0;
     uvc_obj->ctrl_transfer->timeout_ms = 5000;
     uvc_obj->ctrl_transfer->callback = ctrl_xfer_cb;
+    uvc_obj->user_cb = driver_config->event_cb;
+    uvc_obj->user_ctx = driver_config->user_ctx;
 
     // Between 1st call of this function and following section, another task might try to install this driver:
     // Make sure that there is only one instance of this driver in the system
@@ -530,7 +622,7 @@ esp_err_t uvc_host_stream_open(const uvc_host_stream_config_t *stream_config, in
     xSemaphoreTake(p_uvc_host_driver->open_close_mutex, portMAX_DELAY);
 
     // Find underlying USB device
-    ret = uvc_find_and_open_usb_device(stream_config->usb.vid, stream_config->usb.pid, timeout, &uvc_stream);
+    ret = uvc_find_and_open_usb_device(stream_config->usb.dev_addr, stream_config->usb.vid, stream_config->usb.pid, timeout, &uvc_stream);
     if (ESP_OK != ret) {
         goto not_found;
     }
@@ -837,3 +929,17 @@ esp_err_t uvc_host_usb_ctrl(uvc_host_stream_hdl_t stream_hdl, uint8_t bmRequestT
     xSemaphoreGive(p_uvc_host_driver->ctrl_mutex);
     return ret;
 }
+
+esp_err_t uvc_host_get_frame_list(uint8_t dev_addr, uint8_t uvc_stream_index, uvc_host_frame_info_t (*frame_info_list)[], size_t *list_size)
+{
+    UVC_CHECK(list_size, ESP_ERR_INVALID_ARG);
+
+    usb_device_handle_t dev_hdl;
+    const usb_config_desc_t *config_desc = NULL;
+    if (usb_host_device_open(p_uvc_host_driver->usb_client_hdl, dev_addr, &dev_hdl) == ESP_OK) {
+        usb_host_get_active_config_descriptor(dev_hdl, &config_desc);
+        ESP_RETURN_ON_ERROR(usb_host_device_close(p_uvc_host_driver->usb_client_hdl, dev_hdl), TAG, "Unable to close USB device");
+    }
+
+    return uvc_desc_get_frame_list(config_desc, uvc_stream_index, frame_info_list, list_size);
+}