Skip to content

Commit 31ae0b4

Browse files
feat(cdc_acm_host): Add global suspend/resume
- usb_host lib supports global suspend and resume - backward compatibility with older IDF releases - CDC-ACM Host target tests
1 parent 8899063 commit 31ae0b4

File tree

5 files changed

+560
-33
lines changed

5 files changed

+560
-33
lines changed

host/class/cdc/usb_host_cdc_acm/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [unreleased]
2+
3+
- Added global suspend/resume support
4+
15
## 2.1.0
26

37
- Added option to implement custom CDC-ACM like devices with C API

host/class/cdc/usb_host_cdc_acm/cdc_acm_host.c

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -842,10 +842,35 @@ static void out_xfer_cb(usb_transfer_t *transfer)
842842
xSemaphoreGive((SemaphoreHandle_t)transfer->context);
843843
}
844844

845+
/**
846+
* @brief Resume CDC device
847+
*
848+
* Submit poll for BULK IN and INTR IN transfers
849+
*
850+
* @param cdc_dev
851+
* @return esp_err_t
852+
*/
853+
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
854+
static void cdc_acm_resume(cdc_dev_t *cdc_dev)
855+
{
856+
assert(cdc_dev);
857+
858+
if (cdc_dev->data.in_xfer) {
859+
ESP_LOGD(TAG, "Submitting poll for BULK IN transfer");
860+
ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->data.in_xfer));
861+
}
862+
863+
if (cdc_dev->notif.xfer) {
864+
ESP_LOGD(TAG, "Submitting poll for INTR IN transfer");
865+
ESP_ERROR_CHECK(usb_host_transfer_submit(cdc_dev->notif.xfer));
866+
}
867+
}
868+
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
869+
845870
static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg)
846871
{
847872
switch (event_msg->event) {
848-
case USB_HOST_CLIENT_EVENT_NEW_DEV:
873+
case USB_HOST_CLIENT_EVENT_NEW_DEV: {
849874
// Guard p_cdc_acm_obj->new_dev_cb from concurrent access
850875
ESP_LOGD(TAG, "New device connected");
851876
CDC_ACM_ENTER_CRITICAL();
@@ -861,8 +886,8 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
861886
_new_dev_cb(new_dev);
862887
usb_host_device_close(p_cdc_acm_obj->cdc_acm_client_hdl, new_dev);
863888
}
864-
865889
break;
890+
}
866891
case USB_HOST_CLIENT_EVENT_DEV_GONE: {
867892
ESP_LOGD(TAG, "Device suddenly disconnected");
868893
// Find CDC pseudo-devices associated with this USB device and close them
@@ -881,7 +906,50 @@ static void usb_event_cb(const usb_host_client_event_msg_t *event_msg, void *arg
881906
}
882907
break;
883908
}
909+
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
910+
case USB_HOST_CLIENT_EVENT_DEV_SUSPENDED: {
911+
ESP_LOGD(TAG, "Device suspended");
912+
// Find CDC pseudo-devices associated with this USB device and deliver suspend event to the user
913+
cdc_dev_t *cdc_dev;
914+
cdc_dev_t *tcdc_dev;
915+
SLIST_FOREACH_SAFE(cdc_dev, &p_cdc_acm_obj->cdc_devices_list, list_entry, tcdc_dev) {
916+
if (cdc_dev->dev_hdl == event_msg->dev_suspend_resume.dev_hdl && cdc_dev->notif.cb) {
917+
// The suspended device was opened by this driver: inform user about this
918+
const cdc_acm_host_dev_event_data_t disconn_event = {
919+
.type = CDC_ACM_HOST_DEVICE_SUSPENDED,
920+
.data.cdc_hdl = (cdc_acm_dev_hdl_t) cdc_dev,
921+
};
922+
cdc_dev->notif.cb(&disconn_event, cdc_dev->cb_arg);
923+
}
924+
}
925+
break;
926+
}
927+
case USB_HOST_CLIENT_EVENT_DEV_RESUMED: {
928+
ESP_LOGD(TAG, "Device resumed");
929+
// Find CDC pseudo-devices associated with this USB device and deliver resume event to the user
930+
cdc_dev_t *cdc_dev;
931+
cdc_dev_t *tcdc_dev;
932+
SLIST_FOREACH_SAFE(cdc_dev, &p_cdc_acm_obj->cdc_devices_list, list_entry, tcdc_dev) {
933+
if (cdc_dev->dev_hdl == event_msg->dev_suspend_resume.dev_hdl) {
934+
935+
// Resume the pseudo-device
936+
cdc_acm_resume(cdc_dev);
937+
938+
if (cdc_dev->notif.cb != NULL) {
939+
// The resumed device was opened by this driver: inform user about this
940+
const cdc_acm_host_dev_event_data_t disconn_event = {
941+
.type = CDC_ACM_HOST_DEVICE_RESUMED,
942+
.data.cdc_hdl = (cdc_acm_dev_hdl_t) cdc_dev,
943+
};
944+
cdc_dev->notif.cb(&disconn_event, cdc_dev->cb_arg);
945+
}
946+
}
947+
}
948+
break;
949+
}
950+
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
884951
default:
952+
ESP_LOGE(TAG, "Unrecognized USB Host client event");
885953
assert(false);
886954
break;
887955
}

host/class/cdc/usb_host_cdc_acm/include/usb/cdc_acm_host.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -17,6 +17,11 @@
1717
#define CDC_HOST_ANY_VID (0)
1818
#define CDC_HOST_ANY_PID (0)
1919

20+
// For backward compatibility with IDF versions which do not have suspend/resume api
21+
#ifdef USB_HOST_LIB_EVENT_FLAGS_AUTO_SUSPEND
22+
#define CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
23+
#endif
24+
2025
#ifdef __cplusplus
2126
extern "C" {
2227
#endif

host/class/cdc/usb_host_cdc_acm/include/usb/cdc_host_types.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,27 @@
99
#include <stdint.h>
1010
#include <stdbool.h>
1111
#include "usb/usb_types_cdc.h"
12+
#include "usb/usb_host.h" // For USB Host suspend/resume API
13+
14+
// For backward compatibility with IDF versions which do not have suspend/resume api
15+
#ifdef USB_HOST_LIB_EVENT_FLAGS_AUTO_SUSPEND
16+
#define CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
17+
#endif
1218

1319
typedef struct cdc_dev_s *cdc_acm_dev_hdl_t;
1420

1521
/**
1622
* @brief CDC-ACM Device Event types to upper layer
1723
*/
1824
typedef enum {
19-
CDC_ACM_HOST_ERROR,
20-
CDC_ACM_HOST_SERIAL_STATE,
21-
CDC_ACM_HOST_NETWORK_CONNECTION,
22-
CDC_ACM_HOST_DEVICE_DISCONNECTED
25+
CDC_ACM_HOST_ERROR, /**< An error occurred on the CDC-ACM device */
26+
CDC_ACM_HOST_SERIAL_STATE, /**< Serial state of the CDC-ACM device has changed */
27+
CDC_ACM_HOST_NETWORK_CONNECTION, /**< CDC-ACM device network connection state has changed */
28+
CDC_ACM_HOST_DEVICE_DISCONNECTED, /**< CDC-ACM device has been disconnected */
29+
#ifdef CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
30+
CDC_ACM_HOST_DEVICE_SUSPENDED, /**< CDC-ACM device has been suspended */
31+
CDC_ACM_HOST_DEVICE_RESUMED, /**< CDC-ACM device has been resumed */
32+
#endif // CDC_HOST_SUSPEND_RESUME_API_SUPPORTED
2333
} cdc_acm_host_dev_event_t;
2434

2535
/**
@@ -50,7 +60,7 @@ typedef bool (*cdc_acm_data_callback_t)(const uint8_t *data, size_t data_len, vo
5060
* @brief Device event callback type
5161
*
5262
* @param[in] event Event structure
53-
* @param[in] user_arg User's argument passed to open function
63+
* @param[in] user_ctx User's context passed to open function
5464
*/
5565
typedef void (*cdc_acm_host_dev_callback_t)(const cdc_acm_host_dev_event_data_t *event, void *user_ctx);
5666

0 commit comments

Comments
 (0)