Skip to content
Open
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
4 changes: 4 additions & 0 deletions host/class/cdc/usb_host_cdc_acm/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [Unreleased]

- Added global suspend/resume support

## 2.1.1

- Added support for ESP32-H4
Expand Down
76 changes: 74 additions & 2 deletions host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -842,10 +842,35 @@ static void out_xfer_cb(usb_transfer_t *transfer)
xSemaphoreGive((SemaphoreHandle_t)transfer->context);
}

/**
* @brief Resume CDC device
*
* Submit poll for BULK IN and INTR IN transfers
*
* @param cdc_dev
* @return esp_err_t
*/
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
static void cdc_acm_resume(cdc_dev_t *cdc_dev)
{
assert(cdc_dev);

if (cdc_dev->data.in_xfer) {
ESP_LOGD(TAG, "Submitting poll for BULK IN transfer");
ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->data.in_xfer));
}

if (cdc_dev->notif.xfer) {
ESP_LOGD(TAG, "Submitting poll for INTR IN transfer");
ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->notif.xfer));
}
}
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED

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:
case USB_HOST_CLIENT_EVENT_NEW_DEV: {
// Guard p_cdc_acm_obj->new_dev_cb from concurrent access
ESP_LOGD(TAG, "New device connected");
CDC_ACM_ENTER_CRITICAL();
Expand All @@ -861,8 +886,8 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
_new_dev_cb(new_dev);
usb_host_device_close(p_cdc_acm_obj->cdc_acm_client_hdl, new_dev);
}

break;
}
case USB_HOST_CLIENT_EVENT_DEV_GONE: {
ESP_LOGD(TAG, "Device suddenly disconnected");
// Find CDC pseudo-devices associated with this USB device and close them
Expand All @@ -881,7 +906,54 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
}
break;
}
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
case USB_HOST_CLIENT_EVENT_DEV_SUSPENDED: {
ESP_LOGD(TAG, "Device suspended");
// Find CDC pseudo-devices associated with this USB device and deliver suspend event to the user
cdc_dev_t *cdc_dev;
cdc_dev_t *tcdc_dev;
SLIST_FOREACH_SAFE(cdc_dev, &p_cdc_acm_obj->cdc_devices_list, list_entry, tcdc_dev) {
if (cdc_dev->dev_hdl == event_msg->dev_suspend_resume.dev_hdl && cdc_dev->notif.cb) {

// The driver does not have to do anything to suspend the device,
// the usb host lib already halted and flushed all EPs

// The suspended device was opened by this driver: inform user about this
const cdc_acm_host_dev_event_data_t suspend_event = {
.type = CDC_ACM_HOST_DEVICE_SUSPENDED,
.data.cdc_hdl = (cdc_acm_dev_hdl_t) cdc_dev,
};
cdc_dev->notif.cb(&suspend_event, cdc_dev->cb_arg);
}
}
break;
}
case USB_HOST_CLIENT_EVENT_DEV_RESUMED: {
ESP_LOGD(TAG, "Device resumed");
// Find CDC pseudo-devices associated with this USB device and deliver resume event to the user
cdc_dev_t *cdc_dev;
cdc_dev_t *tcdc_dev;
SLIST_FOREACH_SAFE(cdc_dev, &p_cdc_acm_obj->cdc_devices_list, list_entry, tcdc_dev) {
if (cdc_dev->dev_hdl == event_msg->dev_suspend_resume.dev_hdl) {

// Resume the pseudo-device
cdc_acm_resume(cdc_dev);

if (cdc_dev->notif.cb != NULL) {
// The resumed device was opened by this driver: inform user about this
const cdc_acm_host_dev_event_data_t resume_event = {
.type = CDC_ACM_HOST_DEVICE_RESUMED,
.data.cdc_hdl = (cdc_acm_dev_hdl_t) cdc_dev,
};
cdc_dev->notif.cb(&resume_event, cdc_dev->cb_arg);
}
}
}
break;
}
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
default:
ESP_LOGE(TAG, "Unrecognized USB Host client event");
assert(false);
break;
}
Expand Down
7 changes: 6 additions & 1 deletion host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -17,6 +17,11 @@
#define CDC_HOST_ANY_VID (0)
#define CDC_HOST_ANY_PID (0)

// For backward compatibility with IDF versions which do not have suspend/resume api
#ifdef USB_HOST_LIB_EVENT_FLAGS_AUTO_SUSPEND
#define CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
#endif

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
20 changes: 15 additions & 5 deletions host/class/cdc/usb_host_cdc_acm/include/usb/cdc_host_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,27 @@
#include <stdint.h>
#include <stdbool.h>
#include "usb/usb_types_cdc.h"
#include "usb/usb_host.h" // For USB Host suspend/resume API

// For backward compatibility with IDF versions which do not have suspend/resume api
#ifdef USB_HOST_LIB_EVENT_FLAGS_AUTO_SUSPEND
#define CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
#endif

typedef struct cdc_dev_s *cdc_acm_dev_hdl_t;

/**
* @brief CDC-ACM Device Event types to upper layer
*/
typedef enum {
CDC_ACM_HOST_ERROR,
CDC_ACM_HOST_SERIAL_STATE,
CDC_ACM_HOST_NETWORK_CONNECTION,
CDC_ACM_HOST_DEVICE_DISCONNECTED
CDC_ACM_HOST_ERROR, /**< An error occurred on the CDC-ACM device */
CDC_ACM_HOST_SERIAL_STATE, /**< Serial state of the CDC-ACM device has changed */
CDC_ACM_HOST_NETWORK_CONNECTION, /**< CDC-ACM device network connection state has changed */
CDC_ACM_HOST_DEVICE_DISCONNECTED, /**< CDC-ACM device has been disconnected */
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
CDC_ACM_HOST_DEVICE_SUSPENDED, /**< CDC-ACM device has been suspended */
CDC_ACM_HOST_DEVICE_RESUMED, /**< CDC-ACM device has been resumed */
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
} cdc_acm_host_dev_event_t;

/**
Expand Down Expand Up @@ -50,7 +60,7 @@ typedef bool (*cdc_acm_data_callback_t)(const uint8_t *data, size_t data_len, vo
* @brief Device event callback type
*
* @param[in] event Event structure
* @param[in] user_arg User's argument passed to open function
* @param[in] user_ctx User's context passed to open function
*/
typedef void (*cdc_acm_host_dev_callback_t)(const cdc_acm_host_dev_event_data_t *event, void *user_ctx);

Expand Down
Loading
Loading